1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker * Copyright (C) 2019 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker *
4*d57664e9SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker *
8*d57664e9SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker *
10*d57664e9SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker */
16*d57664e9SAndroid Build Coastguard Worker
17*d57664e9SAndroid Build Coastguard Worker #define LOG_TAG "IncrementalService"
18*d57664e9SAndroid Build Coastguard Worker
19*d57664e9SAndroid Build Coastguard Worker #include "IncrementalService.h"
20*d57664e9SAndroid Build Coastguard Worker
21*d57664e9SAndroid Build Coastguard Worker #include <android-base/logging.h>
22*d57664e9SAndroid Build Coastguard Worker #include <android-base/no_destructor.h>
23*d57664e9SAndroid Build Coastguard Worker #include <android-base/properties.h>
24*d57664e9SAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
25*d57664e9SAndroid Build Coastguard Worker #include <binder/AppOpsManager.h>
26*d57664e9SAndroid Build Coastguard Worker #include <binder/Status.h>
27*d57664e9SAndroid Build Coastguard Worker #include <sys/stat.h>
28*d57664e9SAndroid Build Coastguard Worker #include <uuid/uuid.h>
29*d57664e9SAndroid Build Coastguard Worker
30*d57664e9SAndroid Build Coastguard Worker #include <charconv>
31*d57664e9SAndroid Build Coastguard Worker #include <ctime>
32*d57664e9SAndroid Build Coastguard Worker #include <iterator>
33*d57664e9SAndroid Build Coastguard Worker #include <span>
34*d57664e9SAndroid Build Coastguard Worker #include <type_traits>
35*d57664e9SAndroid Build Coastguard Worker
36*d57664e9SAndroid Build Coastguard Worker #include "IncrementalServiceValidation.h"
37*d57664e9SAndroid Build Coastguard Worker #include "Metadata.pb.h"
38*d57664e9SAndroid Build Coastguard Worker
39*d57664e9SAndroid Build Coastguard Worker using namespace std::literals;
40*d57664e9SAndroid Build Coastguard Worker
41*d57664e9SAndroid Build Coastguard Worker constexpr const char* kLoaderUsageStats = "android.permission.LOADER_USAGE_STATS";
42*d57664e9SAndroid Build Coastguard Worker constexpr const char* kOpUsage = "android:loader_usage_stats";
43*d57664e9SAndroid Build Coastguard Worker
44*d57664e9SAndroid Build Coastguard Worker constexpr const char* kInteractAcrossUsers = "android.permission.INTERACT_ACROSS_USERS";
45*d57664e9SAndroid Build Coastguard Worker
46*d57664e9SAndroid Build Coastguard Worker namespace android::incremental {
47*d57664e9SAndroid Build Coastguard Worker
48*d57664e9SAndroid Build Coastguard Worker using content::pm::DataLoaderParamsParcel;
49*d57664e9SAndroid Build Coastguard Worker using content::pm::FileSystemControlParcel;
50*d57664e9SAndroid Build Coastguard Worker using content::pm::IDataLoader;
51*d57664e9SAndroid Build Coastguard Worker
52*d57664e9SAndroid Build Coastguard Worker namespace {
53*d57664e9SAndroid Build Coastguard Worker
54*d57664e9SAndroid Build Coastguard Worker using IncrementalFileSystemControlParcel = os::incremental::IncrementalFileSystemControlParcel;
55*d57664e9SAndroid Build Coastguard Worker
56*d57664e9SAndroid Build Coastguard Worker struct Constants {
57*d57664e9SAndroid Build Coastguard Worker static constexpr auto backing = "backing_store"sv;
58*d57664e9SAndroid Build Coastguard Worker static constexpr auto mount = "mount"sv;
59*d57664e9SAndroid Build Coastguard Worker static constexpr auto mountKeyPrefix = "MT_"sv;
60*d57664e9SAndroid Build Coastguard Worker static constexpr auto storagePrefix = "st"sv;
61*d57664e9SAndroid Build Coastguard Worker static constexpr auto mountpointMdPrefix = ".mountpoint."sv;
62*d57664e9SAndroid Build Coastguard Worker static constexpr auto infoMdName = ".info"sv;
63*d57664e9SAndroid Build Coastguard Worker static constexpr auto readLogsDisabledMarkerName = ".readlogs_disabled"sv;
64*d57664e9SAndroid Build Coastguard Worker static constexpr auto libDir = "lib"sv;
65*d57664e9SAndroid Build Coastguard Worker static constexpr auto libSuffix = ".so"sv;
66*d57664e9SAndroid Build Coastguard Worker static constexpr auto blockSize = 4096;
67*d57664e9SAndroid Build Coastguard Worker static constexpr auto systemPackage = "android"sv;
68*d57664e9SAndroid Build Coastguard Worker
69*d57664e9SAndroid Build Coastguard Worker static constexpr auto userStatusDelay = 100ms;
70*d57664e9SAndroid Build Coastguard Worker
71*d57664e9SAndroid Build Coastguard Worker static constexpr auto progressUpdateInterval = 1000ms;
72*d57664e9SAndroid Build Coastguard Worker static constexpr auto perUidTimeoutOffset = progressUpdateInterval * 2;
73*d57664e9SAndroid Build Coastguard Worker static constexpr auto minPerUidTimeout = progressUpdateInterval * 3;
74*d57664e9SAndroid Build Coastguard Worker
75*d57664e9SAndroid Build Coastguard Worker // If DL was up and not crashing for 10mins, we consider it healthy and reset all delays.
76*d57664e9SAndroid Build Coastguard Worker static constexpr auto healthyDataLoaderUptime = 10min;
77*d57664e9SAndroid Build Coastguard Worker
78*d57664e9SAndroid Build Coastguard Worker // For healthy DLs, we'll retry every ~5secs for ~10min
79*d57664e9SAndroid Build Coastguard Worker static constexpr auto bindRetryInterval = 5s;
80*d57664e9SAndroid Build Coastguard Worker static constexpr auto bindGracePeriod = 10min;
81*d57664e9SAndroid Build Coastguard Worker
82*d57664e9SAndroid Build Coastguard Worker static constexpr auto bindingTimeout = 1min;
83*d57664e9SAndroid Build Coastguard Worker
84*d57664e9SAndroid Build Coastguard Worker // 1s, 10s, 100s (~2min), 1000s (~15min), 10000s (~3hrs)
85*d57664e9SAndroid Build Coastguard Worker static constexpr auto minBindDelay = 1s;
86*d57664e9SAndroid Build Coastguard Worker static constexpr auto maxBindDelay = 10000s;
87*d57664e9SAndroid Build Coastguard Worker static constexpr auto bindDelayMultiplier = 10;
88*d57664e9SAndroid Build Coastguard Worker static constexpr auto bindDelayJitterDivider = 10;
89*d57664e9SAndroid Build Coastguard Worker
90*d57664e9SAndroid Build Coastguard Worker // Max interval after system invoked the DL when readlog collection can be enabled.
91*d57664e9SAndroid Build Coastguard Worker static constexpr auto readLogsMaxInterval = 2h;
92*d57664e9SAndroid Build Coastguard Worker
93*d57664e9SAndroid Build Coastguard Worker // How long should we wait till dataLoader reports destroyed.
94*d57664e9SAndroid Build Coastguard Worker static constexpr auto destroyTimeout = 10s;
95*d57664e9SAndroid Build Coastguard Worker
96*d57664e9SAndroid Build Coastguard Worker static constexpr auto anyStatus = INT_MIN;
97*d57664e9SAndroid Build Coastguard Worker };
98*d57664e9SAndroid Build Coastguard Worker
constants()99*d57664e9SAndroid Build Coastguard Worker static const Constants& constants() {
100*d57664e9SAndroid Build Coastguard Worker static constexpr Constants c;
101*d57664e9SAndroid Build Coastguard Worker return c;
102*d57664e9SAndroid Build Coastguard Worker }
103*d57664e9SAndroid Build Coastguard Worker
isPageAligned(IncFsSize s)104*d57664e9SAndroid Build Coastguard Worker static bool isPageAligned(IncFsSize s) {
105*d57664e9SAndroid Build Coastguard Worker return (s & (Constants::blockSize - 1)) == 0;
106*d57664e9SAndroid Build Coastguard Worker }
107*d57664e9SAndroid Build Coastguard Worker
getAlwaysEnableReadTimeoutsForSystemDataLoaders()108*d57664e9SAndroid Build Coastguard Worker static bool getAlwaysEnableReadTimeoutsForSystemDataLoaders() {
109*d57664e9SAndroid Build Coastguard Worker return android::base::
110*d57664e9SAndroid Build Coastguard Worker GetBoolProperty("debug.incremental.always_enable_read_timeouts_for_system_dataloaders",
111*d57664e9SAndroid Build Coastguard Worker true);
112*d57664e9SAndroid Build Coastguard Worker }
113*d57664e9SAndroid Build Coastguard Worker
getEnableReadTimeoutsAfterInstall()114*d57664e9SAndroid Build Coastguard Worker static bool getEnableReadTimeoutsAfterInstall() {
115*d57664e9SAndroid Build Coastguard Worker return android::base::GetBoolProperty("debug.incremental.enable_read_timeouts_after_install",
116*d57664e9SAndroid Build Coastguard Worker true);
117*d57664e9SAndroid Build Coastguard Worker }
118*d57664e9SAndroid Build Coastguard Worker
getEnforceReadLogsMaxIntervalForSystemDataLoaders()119*d57664e9SAndroid Build Coastguard Worker static bool getEnforceReadLogsMaxIntervalForSystemDataLoaders() {
120*d57664e9SAndroid Build Coastguard Worker return android::base::GetBoolProperty("debug.incremental.enforce_readlogs_max_interval_for_"
121*d57664e9SAndroid Build Coastguard Worker "system_dataloaders",
122*d57664e9SAndroid Build Coastguard Worker false);
123*d57664e9SAndroid Build Coastguard Worker }
124*d57664e9SAndroid Build Coastguard Worker
getReadLogsMaxInterval()125*d57664e9SAndroid Build Coastguard Worker static Seconds getReadLogsMaxInterval() {
126*d57664e9SAndroid Build Coastguard Worker constexpr int limit = duration_cast<Seconds>(Constants::readLogsMaxInterval).count();
127*d57664e9SAndroid Build Coastguard Worker int readlogs_max_interval_secs =
128*d57664e9SAndroid Build Coastguard Worker std::min(limit,
129*d57664e9SAndroid Build Coastguard Worker android::base::GetIntProperty<
130*d57664e9SAndroid Build Coastguard Worker int>("debug.incremental.readlogs_max_interval_sec", limit));
131*d57664e9SAndroid Build Coastguard Worker return Seconds{readlogs_max_interval_secs};
132*d57664e9SAndroid Build Coastguard Worker }
133*d57664e9SAndroid Build Coastguard Worker
134*d57664e9SAndroid Build Coastguard Worker template <base::LogSeverity level = base::ERROR>
mkdirOrLog(std::string_view name,int mode=0770,bool allowExisting=true)135*d57664e9SAndroid Build Coastguard Worker bool mkdirOrLog(std::string_view name, int mode = 0770, bool allowExisting = true) {
136*d57664e9SAndroid Build Coastguard Worker auto cstr = path::c_str(name);
137*d57664e9SAndroid Build Coastguard Worker if (::mkdir(cstr, mode)) {
138*d57664e9SAndroid Build Coastguard Worker if (!allowExisting || errno != EEXIST) {
139*d57664e9SAndroid Build Coastguard Worker PLOG(level) << "Can't create directory '" << name << '\'';
140*d57664e9SAndroid Build Coastguard Worker return false;
141*d57664e9SAndroid Build Coastguard Worker }
142*d57664e9SAndroid Build Coastguard Worker struct stat st;
143*d57664e9SAndroid Build Coastguard Worker if (::stat(cstr, &st) || !S_ISDIR(st.st_mode)) {
144*d57664e9SAndroid Build Coastguard Worker PLOG(level) << "Path exists but is not a directory: '" << name << '\'';
145*d57664e9SAndroid Build Coastguard Worker return false;
146*d57664e9SAndroid Build Coastguard Worker }
147*d57664e9SAndroid Build Coastguard Worker }
148*d57664e9SAndroid Build Coastguard Worker if (::chmod(cstr, mode)) {
149*d57664e9SAndroid Build Coastguard Worker PLOG(level) << "Changing permission failed for '" << name << '\'';
150*d57664e9SAndroid Build Coastguard Worker return false;
151*d57664e9SAndroid Build Coastguard Worker }
152*d57664e9SAndroid Build Coastguard Worker
153*d57664e9SAndroid Build Coastguard Worker return true;
154*d57664e9SAndroid Build Coastguard Worker }
155*d57664e9SAndroid Build Coastguard Worker
toMountKey(std::string_view path)156*d57664e9SAndroid Build Coastguard Worker static std::string toMountKey(std::string_view path) {
157*d57664e9SAndroid Build Coastguard Worker if (path.empty()) {
158*d57664e9SAndroid Build Coastguard Worker return "@none";
159*d57664e9SAndroid Build Coastguard Worker }
160*d57664e9SAndroid Build Coastguard Worker if (path == "/"sv) {
161*d57664e9SAndroid Build Coastguard Worker return "@root";
162*d57664e9SAndroid Build Coastguard Worker }
163*d57664e9SAndroid Build Coastguard Worker if (path::isAbsolute(path)) {
164*d57664e9SAndroid Build Coastguard Worker path.remove_prefix(1);
165*d57664e9SAndroid Build Coastguard Worker }
166*d57664e9SAndroid Build Coastguard Worker if (path.size() > 16) {
167*d57664e9SAndroid Build Coastguard Worker path = path.substr(0, 16);
168*d57664e9SAndroid Build Coastguard Worker }
169*d57664e9SAndroid Build Coastguard Worker std::string res(path);
170*d57664e9SAndroid Build Coastguard Worker std::replace_if(
171*d57664e9SAndroid Build Coastguard Worker res.begin(), res.end(), [](char c) { return c == '/' || c == '@'; }, '_');
172*d57664e9SAndroid Build Coastguard Worker return std::string(constants().mountKeyPrefix) += res;
173*d57664e9SAndroid Build Coastguard Worker }
174*d57664e9SAndroid Build Coastguard Worker
makeMountDir(std::string_view incrementalDir,std::string_view path)175*d57664e9SAndroid Build Coastguard Worker static std::pair<std::string, std::string> makeMountDir(std::string_view incrementalDir,
176*d57664e9SAndroid Build Coastguard Worker std::string_view path) {
177*d57664e9SAndroid Build Coastguard Worker auto mountKey = toMountKey(path);
178*d57664e9SAndroid Build Coastguard Worker const auto prefixSize = mountKey.size();
179*d57664e9SAndroid Build Coastguard Worker for (int counter = 0; counter < 1000;
180*d57664e9SAndroid Build Coastguard Worker mountKey.resize(prefixSize), base::StringAppendF(&mountKey, "%d", counter++)) {
181*d57664e9SAndroid Build Coastguard Worker auto mountRoot = path::join(incrementalDir, mountKey);
182*d57664e9SAndroid Build Coastguard Worker if (mkdirOrLog(mountRoot, 0777, false)) {
183*d57664e9SAndroid Build Coastguard Worker return {mountKey, mountRoot};
184*d57664e9SAndroid Build Coastguard Worker }
185*d57664e9SAndroid Build Coastguard Worker }
186*d57664e9SAndroid Build Coastguard Worker return {};
187*d57664e9SAndroid Build Coastguard Worker }
188*d57664e9SAndroid Build Coastguard Worker
189*d57664e9SAndroid Build Coastguard Worker template <class Map>
findParentPath(const Map & map,std::string_view path)190*d57664e9SAndroid Build Coastguard Worker typename Map::const_iterator findParentPath(const Map& map, std::string_view path) {
191*d57664e9SAndroid Build Coastguard Worker const auto nextIt = map.upper_bound(path);
192*d57664e9SAndroid Build Coastguard Worker if (nextIt == map.begin()) {
193*d57664e9SAndroid Build Coastguard Worker return map.end();
194*d57664e9SAndroid Build Coastguard Worker }
195*d57664e9SAndroid Build Coastguard Worker const auto suspectIt = std::prev(nextIt);
196*d57664e9SAndroid Build Coastguard Worker if (!path::startsWith(path, suspectIt->first)) {
197*d57664e9SAndroid Build Coastguard Worker return map.end();
198*d57664e9SAndroid Build Coastguard Worker }
199*d57664e9SAndroid Build Coastguard Worker return suspectIt;
200*d57664e9SAndroid Build Coastguard Worker }
201*d57664e9SAndroid Build Coastguard Worker
dup(base::borrowed_fd fd)202*d57664e9SAndroid Build Coastguard Worker static base::unique_fd dup(base::borrowed_fd fd) {
203*d57664e9SAndroid Build Coastguard Worker const auto res = fcntl(fd.get(), F_DUPFD_CLOEXEC, 0);
204*d57664e9SAndroid Build Coastguard Worker return base::unique_fd(res);
205*d57664e9SAndroid Build Coastguard Worker }
206*d57664e9SAndroid Build Coastguard Worker
207*d57664e9SAndroid Build Coastguard Worker template <class ProtoMessage, class Control>
parseFromIncfs(const IncFsWrapper * incfs,const Control & control,std::string_view path)208*d57664e9SAndroid Build Coastguard Worker static ProtoMessage parseFromIncfs(const IncFsWrapper* incfs, const Control& control,
209*d57664e9SAndroid Build Coastguard Worker std::string_view path) {
210*d57664e9SAndroid Build Coastguard Worker auto md = incfs->getMetadata(control, path);
211*d57664e9SAndroid Build Coastguard Worker ProtoMessage message;
212*d57664e9SAndroid Build Coastguard Worker return message.ParseFromArray(md.data(), md.size()) ? message : ProtoMessage{};
213*d57664e9SAndroid Build Coastguard Worker }
214*d57664e9SAndroid Build Coastguard Worker
isValidMountTarget(std::string_view path)215*d57664e9SAndroid Build Coastguard Worker static bool isValidMountTarget(std::string_view path) {
216*d57664e9SAndroid Build Coastguard Worker return path::isAbsolute(path) && path::isEmptyDir(path).value_or(true);
217*d57664e9SAndroid Build Coastguard Worker }
218*d57664e9SAndroid Build Coastguard Worker
makeUniqueName(std::string_view prefix)219*d57664e9SAndroid Build Coastguard Worker std::string makeUniqueName(std::string_view prefix) {
220*d57664e9SAndroid Build Coastguard Worker static constexpr auto uuidStringSize = 36;
221*d57664e9SAndroid Build Coastguard Worker
222*d57664e9SAndroid Build Coastguard Worker uuid_t guid;
223*d57664e9SAndroid Build Coastguard Worker uuid_generate(guid);
224*d57664e9SAndroid Build Coastguard Worker
225*d57664e9SAndroid Build Coastguard Worker std::string name;
226*d57664e9SAndroid Build Coastguard Worker const auto prefixSize = prefix.size();
227*d57664e9SAndroid Build Coastguard Worker name.reserve(prefixSize + uuidStringSize);
228*d57664e9SAndroid Build Coastguard Worker
229*d57664e9SAndroid Build Coastguard Worker name = prefix;
230*d57664e9SAndroid Build Coastguard Worker name.resize(prefixSize + uuidStringSize);
231*d57664e9SAndroid Build Coastguard Worker uuid_unparse(guid, name.data() + prefixSize);
232*d57664e9SAndroid Build Coastguard Worker
233*d57664e9SAndroid Build Coastguard Worker return name;
234*d57664e9SAndroid Build Coastguard Worker }
235*d57664e9SAndroid Build Coastguard Worker
makeBindMdName()236*d57664e9SAndroid Build Coastguard Worker std::string makeBindMdName() {
237*d57664e9SAndroid Build Coastguard Worker return makeUniqueName(constants().mountpointMdPrefix);
238*d57664e9SAndroid Build Coastguard Worker }
239*d57664e9SAndroid Build Coastguard Worker
checkReadLogsDisabledMarker(std::string_view root)240*d57664e9SAndroid Build Coastguard Worker static bool checkReadLogsDisabledMarker(std::string_view root) {
241*d57664e9SAndroid Build Coastguard Worker const auto markerPath = path::c_str(path::join(root, constants().readLogsDisabledMarkerName));
242*d57664e9SAndroid Build Coastguard Worker struct stat st;
243*d57664e9SAndroid Build Coastguard Worker return (::stat(markerPath, &st) == 0);
244*d57664e9SAndroid Build Coastguard Worker }
245*d57664e9SAndroid Build Coastguard Worker
246*d57664e9SAndroid Build Coastguard Worker } // namespace
247*d57664e9SAndroid Build Coastguard Worker
~IncFsMount()248*d57664e9SAndroid Build Coastguard Worker IncrementalService::IncFsMount::~IncFsMount() {
249*d57664e9SAndroid Build Coastguard Worker if (dataLoaderStub) {
250*d57664e9SAndroid Build Coastguard Worker dataLoaderStub->cleanupResources();
251*d57664e9SAndroid Build Coastguard Worker dataLoaderStub = {};
252*d57664e9SAndroid Build Coastguard Worker }
253*d57664e9SAndroid Build Coastguard Worker control.close();
254*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "Unmounting and cleaning up mount " << mountId << " with root '" << root << '\'';
255*d57664e9SAndroid Build Coastguard Worker for (auto&& [target, _] : bindPoints) {
256*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << " bind: " << target;
257*d57664e9SAndroid Build Coastguard Worker incrementalService.mVold->unmountIncFs(target);
258*d57664e9SAndroid Build Coastguard Worker }
259*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << " root: " << root;
260*d57664e9SAndroid Build Coastguard Worker incrementalService.mVold->unmountIncFs(path::join(root, constants().mount));
261*d57664e9SAndroid Build Coastguard Worker cleanupFilesystem(root);
262*d57664e9SAndroid Build Coastguard Worker }
263*d57664e9SAndroid Build Coastguard Worker
makeStorage(StorageId id)264*d57664e9SAndroid Build Coastguard Worker auto IncrementalService::IncFsMount::makeStorage(StorageId id) -> StorageMap::iterator {
265*d57664e9SAndroid Build Coastguard Worker std::string name;
266*d57664e9SAndroid Build Coastguard Worker for (int no = nextStorageDirNo.fetch_add(1, std::memory_order_relaxed), i = 0;
267*d57664e9SAndroid Build Coastguard Worker i < 1024 && no >= 0; no = nextStorageDirNo.fetch_add(1, std::memory_order_relaxed), ++i) {
268*d57664e9SAndroid Build Coastguard Worker name.clear();
269*d57664e9SAndroid Build Coastguard Worker base::StringAppendF(&name, "%.*s_%d_%d", int(constants().storagePrefix.size()),
270*d57664e9SAndroid Build Coastguard Worker constants().storagePrefix.data(), id, no);
271*d57664e9SAndroid Build Coastguard Worker auto fullName = path::join(root, constants().mount, name);
272*d57664e9SAndroid Build Coastguard Worker if (auto err = incrementalService.mIncFs->makeDir(control, fullName, 0755); !err) {
273*d57664e9SAndroid Build Coastguard Worker std::lock_guard l(lock);
274*d57664e9SAndroid Build Coastguard Worker return storages.insert_or_assign(id, Storage{std::move(fullName)}).first;
275*d57664e9SAndroid Build Coastguard Worker } else if (err != EEXIST) {
276*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << __func__ << "(): failed to create dir |" << fullName << "| " << err;
277*d57664e9SAndroid Build Coastguard Worker break;
278*d57664e9SAndroid Build Coastguard Worker }
279*d57664e9SAndroid Build Coastguard Worker }
280*d57664e9SAndroid Build Coastguard Worker nextStorageDirNo = 0;
281*d57664e9SAndroid Build Coastguard Worker return storages.end();
282*d57664e9SAndroid Build Coastguard Worker }
283*d57664e9SAndroid Build Coastguard Worker
284*d57664e9SAndroid Build Coastguard Worker template <class Func>
makeCleanup(Func && f)285*d57664e9SAndroid Build Coastguard Worker static auto makeCleanup(Func&& f) requires(!std::is_lvalue_reference_v<Func>) {
286*d57664e9SAndroid Build Coastguard Worker // ok to move a 'forwarding' reference here as lvalues are disabled anyway
287*d57664e9SAndroid Build Coastguard Worker auto deleter = [f = std::move(f)](auto) { // NOLINT
288*d57664e9SAndroid Build Coastguard Worker f();
289*d57664e9SAndroid Build Coastguard Worker };
290*d57664e9SAndroid Build Coastguard Worker // &f is a dangling pointer here, but we actually never use it as deleter moves it in.
291*d57664e9SAndroid Build Coastguard Worker return std::unique_ptr<Func, decltype(deleter)>(&f, std::move(deleter));
292*d57664e9SAndroid Build Coastguard Worker }
293*d57664e9SAndroid Build Coastguard Worker
openDir(const char * dir)294*d57664e9SAndroid Build Coastguard Worker static auto openDir(const char* dir) {
295*d57664e9SAndroid Build Coastguard Worker struct DirCloser {
296*d57664e9SAndroid Build Coastguard Worker void operator()(DIR* d) const noexcept { ::closedir(d); }
297*d57664e9SAndroid Build Coastguard Worker };
298*d57664e9SAndroid Build Coastguard Worker return std::unique_ptr<DIR, DirCloser>(::opendir(dir));
299*d57664e9SAndroid Build Coastguard Worker }
300*d57664e9SAndroid Build Coastguard Worker
openDir(std::string_view dir)301*d57664e9SAndroid Build Coastguard Worker static auto openDir(std::string_view dir) {
302*d57664e9SAndroid Build Coastguard Worker return openDir(path::c_str(dir));
303*d57664e9SAndroid Build Coastguard Worker }
304*d57664e9SAndroid Build Coastguard Worker
rmDirContent(const char * path)305*d57664e9SAndroid Build Coastguard Worker static int rmDirContent(const char* path) {
306*d57664e9SAndroid Build Coastguard Worker auto dir = openDir(path);
307*d57664e9SAndroid Build Coastguard Worker if (!dir) {
308*d57664e9SAndroid Build Coastguard Worker return -EINVAL;
309*d57664e9SAndroid Build Coastguard Worker }
310*d57664e9SAndroid Build Coastguard Worker while (auto entry = ::readdir(dir.get())) {
311*d57664e9SAndroid Build Coastguard Worker if (entry->d_name == "."sv || entry->d_name == ".."sv) {
312*d57664e9SAndroid Build Coastguard Worker continue;
313*d57664e9SAndroid Build Coastguard Worker }
314*d57664e9SAndroid Build Coastguard Worker auto fullPath = base::StringPrintf("%s/%s", path, entry->d_name);
315*d57664e9SAndroid Build Coastguard Worker if (entry->d_type == DT_DIR) {
316*d57664e9SAndroid Build Coastguard Worker if (const auto err = rmDirContent(fullPath.c_str()); err != 0) {
317*d57664e9SAndroid Build Coastguard Worker PLOG(WARNING) << "Failed to delete " << fullPath << " content";
318*d57664e9SAndroid Build Coastguard Worker return err;
319*d57664e9SAndroid Build Coastguard Worker }
320*d57664e9SAndroid Build Coastguard Worker if (const auto err = ::rmdir(fullPath.c_str()); err != 0) {
321*d57664e9SAndroid Build Coastguard Worker PLOG(WARNING) << "Failed to rmdir " << fullPath;
322*d57664e9SAndroid Build Coastguard Worker return err;
323*d57664e9SAndroid Build Coastguard Worker }
324*d57664e9SAndroid Build Coastguard Worker } else {
325*d57664e9SAndroid Build Coastguard Worker if (const auto err = ::unlink(fullPath.c_str()); err != 0) {
326*d57664e9SAndroid Build Coastguard Worker PLOG(WARNING) << "Failed to delete " << fullPath;
327*d57664e9SAndroid Build Coastguard Worker return err;
328*d57664e9SAndroid Build Coastguard Worker }
329*d57664e9SAndroid Build Coastguard Worker }
330*d57664e9SAndroid Build Coastguard Worker }
331*d57664e9SAndroid Build Coastguard Worker return 0;
332*d57664e9SAndroid Build Coastguard Worker }
333*d57664e9SAndroid Build Coastguard Worker
cleanupFilesystem(std::string_view root)334*d57664e9SAndroid Build Coastguard Worker void IncrementalService::IncFsMount::cleanupFilesystem(std::string_view root) {
335*d57664e9SAndroid Build Coastguard Worker rmDirContent(path::join(root, constants().backing).c_str());
336*d57664e9SAndroid Build Coastguard Worker ::rmdir(path::join(root, constants().backing).c_str());
337*d57664e9SAndroid Build Coastguard Worker ::rmdir(path::join(root, constants().mount).c_str());
338*d57664e9SAndroid Build Coastguard Worker ::rmdir(path::c_str(root));
339*d57664e9SAndroid Build Coastguard Worker }
340*d57664e9SAndroid Build Coastguard Worker
setFlag(StorageFlags flag,bool value)341*d57664e9SAndroid Build Coastguard Worker void IncrementalService::IncFsMount::setFlag(StorageFlags flag, bool value) {
342*d57664e9SAndroid Build Coastguard Worker if (value) {
343*d57664e9SAndroid Build Coastguard Worker flags |= flag;
344*d57664e9SAndroid Build Coastguard Worker } else {
345*d57664e9SAndroid Build Coastguard Worker flags &= ~flag;
346*d57664e9SAndroid Build Coastguard Worker }
347*d57664e9SAndroid Build Coastguard Worker }
348*d57664e9SAndroid Build Coastguard Worker
IncrementalService(ServiceManagerWrapper && sm,std::string_view rootDir)349*d57664e9SAndroid Build Coastguard Worker IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_view rootDir)
350*d57664e9SAndroid Build Coastguard Worker : mVold(sm.getVoldService()),
351*d57664e9SAndroid Build Coastguard Worker mDataLoaderManager(sm.getDataLoaderManager()),
352*d57664e9SAndroid Build Coastguard Worker mIncFs(sm.getIncFs()),
353*d57664e9SAndroid Build Coastguard Worker mAppOpsManager(sm.getAppOpsManager()),
354*d57664e9SAndroid Build Coastguard Worker mJni(sm.getJni()),
355*d57664e9SAndroid Build Coastguard Worker mLooper(sm.getLooper()),
356*d57664e9SAndroid Build Coastguard Worker mTimedQueue(sm.getTimedQueue()),
357*d57664e9SAndroid Build Coastguard Worker mProgressUpdateJobQueue(sm.getProgressUpdateJobQueue()),
358*d57664e9SAndroid Build Coastguard Worker mFs(sm.getFs()),
359*d57664e9SAndroid Build Coastguard Worker mClock(sm.getClock()),
360*d57664e9SAndroid Build Coastguard Worker mIncrementalDir(rootDir) {
361*d57664e9SAndroid Build Coastguard Worker CHECK(mVold) << "Vold service is unavailable";
362*d57664e9SAndroid Build Coastguard Worker CHECK(mDataLoaderManager) << "DataLoaderManagerService is unavailable";
363*d57664e9SAndroid Build Coastguard Worker CHECK(mAppOpsManager) << "AppOpsManager is unavailable";
364*d57664e9SAndroid Build Coastguard Worker CHECK(mJni) << "JNI is unavailable";
365*d57664e9SAndroid Build Coastguard Worker CHECK(mLooper) << "Looper is unavailable";
366*d57664e9SAndroid Build Coastguard Worker CHECK(mTimedQueue) << "TimedQueue is unavailable";
367*d57664e9SAndroid Build Coastguard Worker CHECK(mProgressUpdateJobQueue) << "mProgressUpdateJobQueue is unavailable";
368*d57664e9SAndroid Build Coastguard Worker CHECK(mFs) << "Fs is unavailable";
369*d57664e9SAndroid Build Coastguard Worker CHECK(mClock) << "Clock is unavailable";
370*d57664e9SAndroid Build Coastguard Worker
371*d57664e9SAndroid Build Coastguard Worker mJobQueue.reserve(16);
372*d57664e9SAndroid Build Coastguard Worker mJobProcessor = std::thread([this]() {
373*d57664e9SAndroid Build Coastguard Worker mJni->initializeForCurrentThread();
374*d57664e9SAndroid Build Coastguard Worker runJobProcessing();
375*d57664e9SAndroid Build Coastguard Worker });
376*d57664e9SAndroid Build Coastguard Worker mCmdLooperThread = std::thread([this]() {
377*d57664e9SAndroid Build Coastguard Worker mJni->initializeForCurrentThread();
378*d57664e9SAndroid Build Coastguard Worker runCmdLooper();
379*d57664e9SAndroid Build Coastguard Worker });
380*d57664e9SAndroid Build Coastguard Worker
381*d57664e9SAndroid Build Coastguard Worker const auto mountedRootNames = adoptMountedInstances();
382*d57664e9SAndroid Build Coastguard Worker mountExistingImages(mountedRootNames);
383*d57664e9SAndroid Build Coastguard Worker }
384*d57664e9SAndroid Build Coastguard Worker
~IncrementalService()385*d57664e9SAndroid Build Coastguard Worker IncrementalService::~IncrementalService() {
386*d57664e9SAndroid Build Coastguard Worker {
387*d57664e9SAndroid Build Coastguard Worker std::lock_guard lock(mJobMutex);
388*d57664e9SAndroid Build Coastguard Worker mRunning = false;
389*d57664e9SAndroid Build Coastguard Worker }
390*d57664e9SAndroid Build Coastguard Worker mJobCondition.notify_all();
391*d57664e9SAndroid Build Coastguard Worker mJobProcessor.join();
392*d57664e9SAndroid Build Coastguard Worker mLooper->wake();
393*d57664e9SAndroid Build Coastguard Worker mCmdLooperThread.join();
394*d57664e9SAndroid Build Coastguard Worker mTimedQueue->stop();
395*d57664e9SAndroid Build Coastguard Worker mProgressUpdateJobQueue->stop();
396*d57664e9SAndroid Build Coastguard Worker // Ensure that mounts are destroyed while the service is still valid.
397*d57664e9SAndroid Build Coastguard Worker mBindsByPath.clear();
398*d57664e9SAndroid Build Coastguard Worker mMounts.clear();
399*d57664e9SAndroid Build Coastguard Worker }
400*d57664e9SAndroid Build Coastguard Worker
toString(IncrementalService::BindKind kind)401*d57664e9SAndroid Build Coastguard Worker static const char* toString(IncrementalService::BindKind kind) {
402*d57664e9SAndroid Build Coastguard Worker switch (kind) {
403*d57664e9SAndroid Build Coastguard Worker case IncrementalService::BindKind::Temporary:
404*d57664e9SAndroid Build Coastguard Worker return "Temporary";
405*d57664e9SAndroid Build Coastguard Worker case IncrementalService::BindKind::Permanent:
406*d57664e9SAndroid Build Coastguard Worker return "Permanent";
407*d57664e9SAndroid Build Coastguard Worker }
408*d57664e9SAndroid Build Coastguard Worker }
409*d57664e9SAndroid Build Coastguard Worker
410*d57664e9SAndroid Build Coastguard Worker template <class Duration>
elapsedMcs(Duration start,Duration end)411*d57664e9SAndroid Build Coastguard Worker static int64_t elapsedMcs(Duration start, Duration end) {
412*d57664e9SAndroid Build Coastguard Worker return std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
413*d57664e9SAndroid Build Coastguard Worker }
414*d57664e9SAndroid Build Coastguard Worker
elapsedUsSinceMonoTs(uint64_t monoTsUs)415*d57664e9SAndroid Build Coastguard Worker int64_t IncrementalService::elapsedUsSinceMonoTs(uint64_t monoTsUs) {
416*d57664e9SAndroid Build Coastguard Worker const auto now = mClock->now();
417*d57664e9SAndroid Build Coastguard Worker const auto nowUs = static_cast<uint64_t>(
418*d57664e9SAndroid Build Coastguard Worker duration_cast<std::chrono::microseconds>(now.time_since_epoch()).count());
419*d57664e9SAndroid Build Coastguard Worker return nowUs - monoTsUs;
420*d57664e9SAndroid Build Coastguard Worker }
421*d57664e9SAndroid Build Coastguard Worker
loadingStateToString(incfs::LoadingState state)422*d57664e9SAndroid Build Coastguard Worker static const char* loadingStateToString(incfs::LoadingState state) {
423*d57664e9SAndroid Build Coastguard Worker switch (state) {
424*d57664e9SAndroid Build Coastguard Worker case (incfs::LoadingState::Full):
425*d57664e9SAndroid Build Coastguard Worker return "Full";
426*d57664e9SAndroid Build Coastguard Worker case (incfs::LoadingState::MissingBlocks):
427*d57664e9SAndroid Build Coastguard Worker return "MissingBlocks";
428*d57664e9SAndroid Build Coastguard Worker default:
429*d57664e9SAndroid Build Coastguard Worker return "error obtaining loading state";
430*d57664e9SAndroid Build Coastguard Worker }
431*d57664e9SAndroid Build Coastguard Worker }
432*d57664e9SAndroid Build Coastguard Worker
onDump(int fd)433*d57664e9SAndroid Build Coastguard Worker void IncrementalService::onDump(int fd) {
434*d57664e9SAndroid Build Coastguard Worker dprintf(fd, "Incremental is %s\n", incfs::enabled() ? "ENABLED" : "DISABLED");
435*d57664e9SAndroid Build Coastguard Worker dprintf(fd, "IncFs features: 0x%x\n", int(mIncFs->features()));
436*d57664e9SAndroid Build Coastguard Worker dprintf(fd, "Incremental dir: %s\n", mIncrementalDir.c_str());
437*d57664e9SAndroid Build Coastguard Worker
438*d57664e9SAndroid Build Coastguard Worker std::unique_lock l(mLock);
439*d57664e9SAndroid Build Coastguard Worker
440*d57664e9SAndroid Build Coastguard Worker dprintf(fd, "Mounts (%d): {\n", int(mMounts.size()));
441*d57664e9SAndroid Build Coastguard Worker for (auto&& [id, ifs] : mMounts) {
442*d57664e9SAndroid Build Coastguard Worker std::unique_lock ll(ifs->lock);
443*d57664e9SAndroid Build Coastguard Worker const IncFsMount& mnt = *ifs;
444*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " [%d]: {\n", id);
445*d57664e9SAndroid Build Coastguard Worker if (id != mnt.mountId) {
446*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " reference to mountId: %d\n", mnt.mountId);
447*d57664e9SAndroid Build Coastguard Worker } else {
448*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " mountId: %d\n", mnt.mountId);
449*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " root: %s\n", mnt.root.c_str());
450*d57664e9SAndroid Build Coastguard Worker const auto& metricsInstanceName = ifs->metricsKey;
451*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " metrics instance name: %s\n", path::c_str(metricsInstanceName).get());
452*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " nextStorageDirNo: %d\n", mnt.nextStorageDirNo.load());
453*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " flags: %d\n", int(mnt.flags));
454*d57664e9SAndroid Build Coastguard Worker if (mnt.startLoadingTs.time_since_epoch() == Clock::duration::zero()) {
455*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " not loading\n");
456*d57664e9SAndroid Build Coastguard Worker } else {
457*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " startLoading: %llds\n",
458*d57664e9SAndroid Build Coastguard Worker (long long)(elapsedMcs(mnt.startLoadingTs, Clock::now()) / 1000000));
459*d57664e9SAndroid Build Coastguard Worker }
460*d57664e9SAndroid Build Coastguard Worker if (mnt.dataLoaderStub) {
461*d57664e9SAndroid Build Coastguard Worker mnt.dataLoaderStub->onDump(fd);
462*d57664e9SAndroid Build Coastguard Worker } else {
463*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " dataLoader: null\n");
464*d57664e9SAndroid Build Coastguard Worker }
465*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " storages (%d): {\n", int(mnt.storages.size()));
466*d57664e9SAndroid Build Coastguard Worker for (auto&& [storageId, storage] : mnt.storages) {
467*d57664e9SAndroid Build Coastguard Worker auto&& ifs = getIfsLocked(storageId);
468*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " [%d] -> [%s] (%d %% loaded)(%s) \n", storageId,
469*d57664e9SAndroid Build Coastguard Worker storage.name.c_str(),
470*d57664e9SAndroid Build Coastguard Worker (int)(getLoadingProgressFromPath(mnt, storage.name.c_str()).getProgress() *
471*d57664e9SAndroid Build Coastguard Worker 100),
472*d57664e9SAndroid Build Coastguard Worker ifs ? loadingStateToString(mIncFs->isEverythingFullyLoaded(ifs->control))
473*d57664e9SAndroid Build Coastguard Worker : "error obtaining ifs");
474*d57664e9SAndroid Build Coastguard Worker }
475*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " }\n");
476*d57664e9SAndroid Build Coastguard Worker
477*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " bindPoints (%d): {\n", int(mnt.bindPoints.size()));
478*d57664e9SAndroid Build Coastguard Worker for (auto&& [target, bind] : mnt.bindPoints) {
479*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " [%s]->[%d]:\n", target.c_str(), bind.storage);
480*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " savedFilename: %s\n", bind.savedFilename.c_str());
481*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " sourceDir: %s\n", bind.sourceDir.c_str());
482*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " kind: %s\n", toString(bind.kind));
483*d57664e9SAndroid Build Coastguard Worker }
484*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " }\n");
485*d57664e9SAndroid Build Coastguard Worker
486*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " incfsMetrics: {\n");
487*d57664e9SAndroid Build Coastguard Worker const auto incfsMetrics = mIncFs->getMetrics(metricsInstanceName);
488*d57664e9SAndroid Build Coastguard Worker if (incfsMetrics) {
489*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " readsDelayedMin: %d\n", incfsMetrics.value().readsDelayedMin);
490*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " readsDelayedMinUs: %lld\n",
491*d57664e9SAndroid Build Coastguard Worker (long long)incfsMetrics.value().readsDelayedMinUs);
492*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " readsDelayedPending: %d\n",
493*d57664e9SAndroid Build Coastguard Worker incfsMetrics.value().readsDelayedPending);
494*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " readsDelayedPendingUs: %lld\n",
495*d57664e9SAndroid Build Coastguard Worker (long long)incfsMetrics.value().readsDelayedPendingUs);
496*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " readsFailedHashVerification: %d\n",
497*d57664e9SAndroid Build Coastguard Worker incfsMetrics.value().readsFailedHashVerification);
498*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " readsFailedOther: %d\n", incfsMetrics.value().readsFailedOther);
499*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " readsFailedTimedOut: %d\n",
500*d57664e9SAndroid Build Coastguard Worker incfsMetrics.value().readsFailedTimedOut);
501*d57664e9SAndroid Build Coastguard Worker } else {
502*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " Metrics not available. Errno: %d\n", errno);
503*d57664e9SAndroid Build Coastguard Worker }
504*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " }\n");
505*d57664e9SAndroid Build Coastguard Worker
506*d57664e9SAndroid Build Coastguard Worker const auto lastReadError = mIncFs->getLastReadError(ifs->control);
507*d57664e9SAndroid Build Coastguard Worker const auto errorNo = errno;
508*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " lastReadError: {\n");
509*d57664e9SAndroid Build Coastguard Worker if (lastReadError) {
510*d57664e9SAndroid Build Coastguard Worker if (lastReadError->timestampUs == 0) {
511*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " No read errors.\n");
512*d57664e9SAndroid Build Coastguard Worker } else {
513*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " fileId: %s\n",
514*d57664e9SAndroid Build Coastguard Worker IncFsWrapper::toString(lastReadError->id).c_str());
515*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " time: %llu microseconds ago\n",
516*d57664e9SAndroid Build Coastguard Worker (unsigned long long)elapsedUsSinceMonoTs(lastReadError->timestampUs));
517*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " blockIndex: %d\n", lastReadError->block);
518*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " errno: %d\n", lastReadError->errorNo);
519*d57664e9SAndroid Build Coastguard Worker }
520*d57664e9SAndroid Build Coastguard Worker } else {
521*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " Info not available. Errno: %d\n", errorNo);
522*d57664e9SAndroid Build Coastguard Worker }
523*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " }\n");
524*d57664e9SAndroid Build Coastguard Worker }
525*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " }\n");
526*d57664e9SAndroid Build Coastguard Worker }
527*d57664e9SAndroid Build Coastguard Worker dprintf(fd, "}\n");
528*d57664e9SAndroid Build Coastguard Worker dprintf(fd, "Sorted binds (%d): {\n", int(mBindsByPath.size()));
529*d57664e9SAndroid Build Coastguard Worker for (auto&& [target, mountPairIt] : mBindsByPath) {
530*d57664e9SAndroid Build Coastguard Worker const auto& bind = mountPairIt->second;
531*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " [%s]->[%d]:\n", target.c_str(), bind.storage);
532*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " savedFilename: %s\n", bind.savedFilename.c_str());
533*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " sourceDir: %s\n", bind.sourceDir.c_str());
534*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " kind: %s\n", toString(bind.kind));
535*d57664e9SAndroid Build Coastguard Worker }
536*d57664e9SAndroid Build Coastguard Worker dprintf(fd, "}\n");
537*d57664e9SAndroid Build Coastguard Worker }
538*d57664e9SAndroid Build Coastguard Worker
needStartDataLoaderLocked(IncFsMount & ifs)539*d57664e9SAndroid Build Coastguard Worker bool IncrementalService::needStartDataLoaderLocked(IncFsMount& ifs) {
540*d57664e9SAndroid Build Coastguard Worker if (!ifs.dataLoaderStub) {
541*d57664e9SAndroid Build Coastguard Worker return false;
542*d57664e9SAndroid Build Coastguard Worker }
543*d57664e9SAndroid Build Coastguard Worker if (ifs.dataLoaderStub->isSystemDataLoader()) {
544*d57664e9SAndroid Build Coastguard Worker return true;
545*d57664e9SAndroid Build Coastguard Worker }
546*d57664e9SAndroid Build Coastguard Worker
547*d57664e9SAndroid Build Coastguard Worker return mIncFs->isEverythingFullyLoaded(ifs.control) == incfs::LoadingState::MissingBlocks;
548*d57664e9SAndroid Build Coastguard Worker }
549*d57664e9SAndroid Build Coastguard Worker
onSystemReady()550*d57664e9SAndroid Build Coastguard Worker void IncrementalService::onSystemReady() {
551*d57664e9SAndroid Build Coastguard Worker if (mSystemReady.exchange(true)) {
552*d57664e9SAndroid Build Coastguard Worker return;
553*d57664e9SAndroid Build Coastguard Worker }
554*d57664e9SAndroid Build Coastguard Worker
555*d57664e9SAndroid Build Coastguard Worker std::vector<IfsMountPtr> mounts;
556*d57664e9SAndroid Build Coastguard Worker {
557*d57664e9SAndroid Build Coastguard Worker std::lock_guard l(mLock);
558*d57664e9SAndroid Build Coastguard Worker mounts.reserve(mMounts.size());
559*d57664e9SAndroid Build Coastguard Worker for (auto&& [id, ifs] : mMounts) {
560*d57664e9SAndroid Build Coastguard Worker std::unique_lock ll(ifs->lock);
561*d57664e9SAndroid Build Coastguard Worker
562*d57664e9SAndroid Build Coastguard Worker if (ifs->mountId != id) {
563*d57664e9SAndroid Build Coastguard Worker continue;
564*d57664e9SAndroid Build Coastguard Worker }
565*d57664e9SAndroid Build Coastguard Worker
566*d57664e9SAndroid Build Coastguard Worker if (needStartDataLoaderLocked(*ifs)) {
567*d57664e9SAndroid Build Coastguard Worker mounts.push_back(ifs);
568*d57664e9SAndroid Build Coastguard Worker }
569*d57664e9SAndroid Build Coastguard Worker }
570*d57664e9SAndroid Build Coastguard Worker }
571*d57664e9SAndroid Build Coastguard Worker
572*d57664e9SAndroid Build Coastguard Worker if (mounts.empty()) {
573*d57664e9SAndroid Build Coastguard Worker return;
574*d57664e9SAndroid Build Coastguard Worker }
575*d57664e9SAndroid Build Coastguard Worker
576*d57664e9SAndroid Build Coastguard Worker std::thread([this, mounts = std::move(mounts)]() {
577*d57664e9SAndroid Build Coastguard Worker mJni->initializeForCurrentThread();
578*d57664e9SAndroid Build Coastguard Worker for (auto&& ifs : mounts) {
579*d57664e9SAndroid Build Coastguard Worker std::unique_lock l(ifs->lock);
580*d57664e9SAndroid Build Coastguard Worker if (ifs->dataLoaderStub) {
581*d57664e9SAndroid Build Coastguard Worker ifs->dataLoaderStub->requestStart();
582*d57664e9SAndroid Build Coastguard Worker }
583*d57664e9SAndroid Build Coastguard Worker }
584*d57664e9SAndroid Build Coastguard Worker }).detach();
585*d57664e9SAndroid Build Coastguard Worker }
586*d57664e9SAndroid Build Coastguard Worker
getStorageSlotLocked()587*d57664e9SAndroid Build Coastguard Worker auto IncrementalService::getStorageSlotLocked() -> MountMap::iterator {
588*d57664e9SAndroid Build Coastguard Worker for (;;) {
589*d57664e9SAndroid Build Coastguard Worker if (mNextId == kMaxStorageId) {
590*d57664e9SAndroid Build Coastguard Worker mNextId = 0;
591*d57664e9SAndroid Build Coastguard Worker }
592*d57664e9SAndroid Build Coastguard Worker auto id = ++mNextId;
593*d57664e9SAndroid Build Coastguard Worker auto [it, inserted] = mMounts.try_emplace(id, nullptr);
594*d57664e9SAndroid Build Coastguard Worker if (inserted) {
595*d57664e9SAndroid Build Coastguard Worker return it;
596*d57664e9SAndroid Build Coastguard Worker }
597*d57664e9SAndroid Build Coastguard Worker }
598*d57664e9SAndroid Build Coastguard Worker }
599*d57664e9SAndroid Build Coastguard Worker
createStorage(std::string_view mountPoint,content::pm::DataLoaderParamsParcel dataLoaderParams,CreateOptions options)600*d57664e9SAndroid Build Coastguard Worker StorageId IncrementalService::createStorage(std::string_view mountPoint,
601*d57664e9SAndroid Build Coastguard Worker content::pm::DataLoaderParamsParcel dataLoaderParams,
602*d57664e9SAndroid Build Coastguard Worker CreateOptions options) {
603*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "createStorage: " << mountPoint << " | " << int(options);
604*d57664e9SAndroid Build Coastguard Worker if (!path::isAbsolute(mountPoint)) {
605*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "path is not absolute: " << mountPoint;
606*d57664e9SAndroid Build Coastguard Worker return kInvalidStorageId;
607*d57664e9SAndroid Build Coastguard Worker }
608*d57664e9SAndroid Build Coastguard Worker
609*d57664e9SAndroid Build Coastguard Worker auto mountNorm = path::normalize(mountPoint);
610*d57664e9SAndroid Build Coastguard Worker {
611*d57664e9SAndroid Build Coastguard Worker const auto id = findStorageId(mountNorm);
612*d57664e9SAndroid Build Coastguard Worker if (id != kInvalidStorageId) {
613*d57664e9SAndroid Build Coastguard Worker if (options & CreateOptions::OpenExisting) {
614*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "Opened existing storage " << id;
615*d57664e9SAndroid Build Coastguard Worker return id;
616*d57664e9SAndroid Build Coastguard Worker }
617*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Directory " << mountPoint << " is already mounted at storage " << id;
618*d57664e9SAndroid Build Coastguard Worker return kInvalidStorageId;
619*d57664e9SAndroid Build Coastguard Worker }
620*d57664e9SAndroid Build Coastguard Worker }
621*d57664e9SAndroid Build Coastguard Worker
622*d57664e9SAndroid Build Coastguard Worker if (!(options & CreateOptions::CreateNew)) {
623*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "not requirested create new storage, and it doesn't exist: " << mountPoint;
624*d57664e9SAndroid Build Coastguard Worker return kInvalidStorageId;
625*d57664e9SAndroid Build Coastguard Worker }
626*d57664e9SAndroid Build Coastguard Worker
627*d57664e9SAndroid Build Coastguard Worker if (!path::isEmptyDir(mountNorm)) {
628*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Mounting over existing non-empty directory is not supported: " << mountNorm;
629*d57664e9SAndroid Build Coastguard Worker return kInvalidStorageId;
630*d57664e9SAndroid Build Coastguard Worker }
631*d57664e9SAndroid Build Coastguard Worker auto [mountKey, mountRoot] = makeMountDir(mIncrementalDir, mountNorm);
632*d57664e9SAndroid Build Coastguard Worker if (mountRoot.empty()) {
633*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Bad mount point";
634*d57664e9SAndroid Build Coastguard Worker return kInvalidStorageId;
635*d57664e9SAndroid Build Coastguard Worker }
636*d57664e9SAndroid Build Coastguard Worker // Make sure the code removes all crap it may create while still failing.
637*d57664e9SAndroid Build Coastguard Worker auto firstCleanup = [](const std::string* ptr) { IncFsMount::cleanupFilesystem(*ptr); };
638*d57664e9SAndroid Build Coastguard Worker auto firstCleanupOnFailure =
639*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<std::string, decltype(firstCleanup)>(&mountRoot, firstCleanup);
640*d57664e9SAndroid Build Coastguard Worker
641*d57664e9SAndroid Build Coastguard Worker auto mountTarget = path::join(mountRoot, constants().mount);
642*d57664e9SAndroid Build Coastguard Worker const auto backing = path::join(mountRoot, constants().backing);
643*d57664e9SAndroid Build Coastguard Worker if (!mkdirOrLog(backing, 0777) || !mkdirOrLog(mountTarget)) {
644*d57664e9SAndroid Build Coastguard Worker return kInvalidStorageId;
645*d57664e9SAndroid Build Coastguard Worker }
646*d57664e9SAndroid Build Coastguard Worker
647*d57664e9SAndroid Build Coastguard Worker std::string metricsKey;
648*d57664e9SAndroid Build Coastguard Worker IncFsMount::Control control;
649*d57664e9SAndroid Build Coastguard Worker {
650*d57664e9SAndroid Build Coastguard Worker std::lock_guard l(mMountOperationLock);
651*d57664e9SAndroid Build Coastguard Worker IncrementalFileSystemControlParcel controlParcel;
652*d57664e9SAndroid Build Coastguard Worker
653*d57664e9SAndroid Build Coastguard Worker if (auto err = rmDirContent(backing.c_str())) {
654*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Coudn't clean the backing directory " << backing << ": " << err;
655*d57664e9SAndroid Build Coastguard Worker return kInvalidStorageId;
656*d57664e9SAndroid Build Coastguard Worker }
657*d57664e9SAndroid Build Coastguard Worker if (!mkdirOrLog(path::join(backing, ".index"), 0777)) {
658*d57664e9SAndroid Build Coastguard Worker return kInvalidStorageId;
659*d57664e9SAndroid Build Coastguard Worker }
660*d57664e9SAndroid Build Coastguard Worker if (!mkdirOrLog(path::join(backing, ".incomplete"), 0777)) {
661*d57664e9SAndroid Build Coastguard Worker return kInvalidStorageId;
662*d57664e9SAndroid Build Coastguard Worker }
663*d57664e9SAndroid Build Coastguard Worker metricsKey = makeUniqueName(mountKey);
664*d57664e9SAndroid Build Coastguard Worker auto status = mVold->mountIncFs(backing, mountTarget, 0, metricsKey, &controlParcel);
665*d57664e9SAndroid Build Coastguard Worker if (!status.isOk()) {
666*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Vold::mountIncFs() failed: " << status.toString8();
667*d57664e9SAndroid Build Coastguard Worker return kInvalidStorageId;
668*d57664e9SAndroid Build Coastguard Worker }
669*d57664e9SAndroid Build Coastguard Worker if (controlParcel.cmd.get() < 0 || controlParcel.pendingReads.get() < 0 ||
670*d57664e9SAndroid Build Coastguard Worker controlParcel.log.get() < 0) {
671*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Vold::mountIncFs() returned invalid control parcel.";
672*d57664e9SAndroid Build Coastguard Worker return kInvalidStorageId;
673*d57664e9SAndroid Build Coastguard Worker }
674*d57664e9SAndroid Build Coastguard Worker int cmd = controlParcel.cmd.release().release();
675*d57664e9SAndroid Build Coastguard Worker int pendingReads = controlParcel.pendingReads.release().release();
676*d57664e9SAndroid Build Coastguard Worker int logs = controlParcel.log.release().release();
677*d57664e9SAndroid Build Coastguard Worker int blocksWritten =
678*d57664e9SAndroid Build Coastguard Worker controlParcel.blocksWritten ? controlParcel.blocksWritten->release().release() : -1;
679*d57664e9SAndroid Build Coastguard Worker control = mIncFs->createControl(cmd, pendingReads, logs, blocksWritten);
680*d57664e9SAndroid Build Coastguard Worker }
681*d57664e9SAndroid Build Coastguard Worker
682*d57664e9SAndroid Build Coastguard Worker std::unique_lock l(mLock);
683*d57664e9SAndroid Build Coastguard Worker const auto mountIt = getStorageSlotLocked();
684*d57664e9SAndroid Build Coastguard Worker const auto mountId = mountIt->first;
685*d57664e9SAndroid Build Coastguard Worker l.unlock();
686*d57664e9SAndroid Build Coastguard Worker
687*d57664e9SAndroid Build Coastguard Worker auto ifs = std::make_shared<IncFsMount>(std::move(mountRoot), std::move(metricsKey), mountId,
688*d57664e9SAndroid Build Coastguard Worker std::move(control), *this);
689*d57664e9SAndroid Build Coastguard Worker // Now it's the |ifs|'s responsibility to clean up after itself, and the only cleanup we need
690*d57664e9SAndroid Build Coastguard Worker // is the removal of the |ifs|.
691*d57664e9SAndroid Build Coastguard Worker (void)firstCleanupOnFailure.release();
692*d57664e9SAndroid Build Coastguard Worker
693*d57664e9SAndroid Build Coastguard Worker auto secondCleanup = [this, &l](auto itPtr) {
694*d57664e9SAndroid Build Coastguard Worker if (!l.owns_lock()) {
695*d57664e9SAndroid Build Coastguard Worker l.lock();
696*d57664e9SAndroid Build Coastguard Worker }
697*d57664e9SAndroid Build Coastguard Worker mMounts.erase(*itPtr);
698*d57664e9SAndroid Build Coastguard Worker };
699*d57664e9SAndroid Build Coastguard Worker auto secondCleanupOnFailure =
700*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<decltype(mountIt), decltype(secondCleanup)>(&mountIt, secondCleanup);
701*d57664e9SAndroid Build Coastguard Worker
702*d57664e9SAndroid Build Coastguard Worker const auto storageIt = ifs->makeStorage(ifs->mountId);
703*d57664e9SAndroid Build Coastguard Worker if (storageIt == ifs->storages.end()) {
704*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Can't create a default storage directory";
705*d57664e9SAndroid Build Coastguard Worker return kInvalidStorageId;
706*d57664e9SAndroid Build Coastguard Worker }
707*d57664e9SAndroid Build Coastguard Worker
708*d57664e9SAndroid Build Coastguard Worker {
709*d57664e9SAndroid Build Coastguard Worker metadata::Mount m;
710*d57664e9SAndroid Build Coastguard Worker m.mutable_storage()->set_id(ifs->mountId);
711*d57664e9SAndroid Build Coastguard Worker m.mutable_loader()->set_type((int)dataLoaderParams.type);
712*d57664e9SAndroid Build Coastguard Worker m.mutable_loader()->set_package_name(std::move(dataLoaderParams.packageName));
713*d57664e9SAndroid Build Coastguard Worker m.mutable_loader()->set_class_name(std::move(dataLoaderParams.className));
714*d57664e9SAndroid Build Coastguard Worker m.mutable_loader()->set_arguments(std::move(dataLoaderParams.arguments));
715*d57664e9SAndroid Build Coastguard Worker const auto metadata = m.SerializeAsString();
716*d57664e9SAndroid Build Coastguard Worker if (auto err =
717*d57664e9SAndroid Build Coastguard Worker mIncFs->makeFile(ifs->control,
718*d57664e9SAndroid Build Coastguard Worker path::join(ifs->root, constants().mount,
719*d57664e9SAndroid Build Coastguard Worker constants().infoMdName),
720*d57664e9SAndroid Build Coastguard Worker 0777, idFromMetadata(metadata),
721*d57664e9SAndroid Build Coastguard Worker {.metadata = {metadata.data(), (IncFsSize)metadata.size()}})) {
722*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Saving mount metadata failed: " << -err;
723*d57664e9SAndroid Build Coastguard Worker return kInvalidStorageId;
724*d57664e9SAndroid Build Coastguard Worker }
725*d57664e9SAndroid Build Coastguard Worker }
726*d57664e9SAndroid Build Coastguard Worker
727*d57664e9SAndroid Build Coastguard Worker const auto bk =
728*d57664e9SAndroid Build Coastguard Worker (options & CreateOptions::PermanentBind) ? BindKind::Permanent : BindKind::Temporary;
729*d57664e9SAndroid Build Coastguard Worker if (auto err = addBindMount(*ifs, storageIt->first, storageIt->second.name,
730*d57664e9SAndroid Build Coastguard Worker std::string(storageIt->second.name), std::move(mountNorm), bk, l);
731*d57664e9SAndroid Build Coastguard Worker err < 0) {
732*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Adding bind mount failed: " << -err;
733*d57664e9SAndroid Build Coastguard Worker return kInvalidStorageId;
734*d57664e9SAndroid Build Coastguard Worker }
735*d57664e9SAndroid Build Coastguard Worker
736*d57664e9SAndroid Build Coastguard Worker // Done here as well, all data structures are in good state.
737*d57664e9SAndroid Build Coastguard Worker (void)secondCleanupOnFailure.release();
738*d57664e9SAndroid Build Coastguard Worker
739*d57664e9SAndroid Build Coastguard Worker mountIt->second = std::move(ifs);
740*d57664e9SAndroid Build Coastguard Worker l.unlock();
741*d57664e9SAndroid Build Coastguard Worker
742*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "created storage " << mountId;
743*d57664e9SAndroid Build Coastguard Worker return mountId;
744*d57664e9SAndroid Build Coastguard Worker }
745*d57664e9SAndroid Build Coastguard Worker
createLinkedStorage(std::string_view mountPoint,StorageId linkedStorage,IncrementalService::CreateOptions options)746*d57664e9SAndroid Build Coastguard Worker StorageId IncrementalService::createLinkedStorage(std::string_view mountPoint,
747*d57664e9SAndroid Build Coastguard Worker StorageId linkedStorage,
748*d57664e9SAndroid Build Coastguard Worker IncrementalService::CreateOptions options) {
749*d57664e9SAndroid Build Coastguard Worker if (!isValidMountTarget(mountPoint)) {
750*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Mount point is invalid or missing";
751*d57664e9SAndroid Build Coastguard Worker return kInvalidStorageId;
752*d57664e9SAndroid Build Coastguard Worker }
753*d57664e9SAndroid Build Coastguard Worker
754*d57664e9SAndroid Build Coastguard Worker std::unique_lock l(mLock);
755*d57664e9SAndroid Build Coastguard Worker auto ifs = getIfsLocked(linkedStorage);
756*d57664e9SAndroid Build Coastguard Worker if (!ifs) {
757*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Ifs unavailable";
758*d57664e9SAndroid Build Coastguard Worker return kInvalidStorageId;
759*d57664e9SAndroid Build Coastguard Worker }
760*d57664e9SAndroid Build Coastguard Worker
761*d57664e9SAndroid Build Coastguard Worker const auto mountIt = getStorageSlotLocked();
762*d57664e9SAndroid Build Coastguard Worker const auto storageId = mountIt->first;
763*d57664e9SAndroid Build Coastguard Worker const auto storageIt = ifs->makeStorage(storageId);
764*d57664e9SAndroid Build Coastguard Worker if (storageIt == ifs->storages.end()) {
765*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Can't create a new storage";
766*d57664e9SAndroid Build Coastguard Worker mMounts.erase(mountIt);
767*d57664e9SAndroid Build Coastguard Worker return kInvalidStorageId;
768*d57664e9SAndroid Build Coastguard Worker }
769*d57664e9SAndroid Build Coastguard Worker
770*d57664e9SAndroid Build Coastguard Worker l.unlock();
771*d57664e9SAndroid Build Coastguard Worker
772*d57664e9SAndroid Build Coastguard Worker const auto bk =
773*d57664e9SAndroid Build Coastguard Worker (options & CreateOptions::PermanentBind) ? BindKind::Permanent : BindKind::Temporary;
774*d57664e9SAndroid Build Coastguard Worker if (auto err = addBindMount(*ifs, storageIt->first, storageIt->second.name,
775*d57664e9SAndroid Build Coastguard Worker std::string(storageIt->second.name), path::normalize(mountPoint),
776*d57664e9SAndroid Build Coastguard Worker bk, l);
777*d57664e9SAndroid Build Coastguard Worker err < 0) {
778*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "bindMount failed with error: " << err;
779*d57664e9SAndroid Build Coastguard Worker (void)mIncFs->unlink(ifs->control, storageIt->second.name);
780*d57664e9SAndroid Build Coastguard Worker ifs->storages.erase(storageIt);
781*d57664e9SAndroid Build Coastguard Worker return kInvalidStorageId;
782*d57664e9SAndroid Build Coastguard Worker }
783*d57664e9SAndroid Build Coastguard Worker
784*d57664e9SAndroid Build Coastguard Worker mountIt->second = ifs;
785*d57664e9SAndroid Build Coastguard Worker return storageId;
786*d57664e9SAndroid Build Coastguard Worker }
787*d57664e9SAndroid Build Coastguard Worker
startLoading(StorageId storageId,content::pm::DataLoaderParamsParcel dataLoaderParams,DataLoaderStatusListener statusListener,const StorageHealthCheckParams & healthCheckParams,StorageHealthListener healthListener,std::vector<PerUidReadTimeouts> perUidReadTimeouts)788*d57664e9SAndroid Build Coastguard Worker bool IncrementalService::startLoading(StorageId storageId,
789*d57664e9SAndroid Build Coastguard Worker content::pm::DataLoaderParamsParcel dataLoaderParams,
790*d57664e9SAndroid Build Coastguard Worker DataLoaderStatusListener statusListener,
791*d57664e9SAndroid Build Coastguard Worker const StorageHealthCheckParams& healthCheckParams,
792*d57664e9SAndroid Build Coastguard Worker StorageHealthListener healthListener,
793*d57664e9SAndroid Build Coastguard Worker std::vector<PerUidReadTimeouts> perUidReadTimeouts) {
794*d57664e9SAndroid Build Coastguard Worker // Per Uid timeouts.
795*d57664e9SAndroid Build Coastguard Worker if (!perUidReadTimeouts.empty()) {
796*d57664e9SAndroid Build Coastguard Worker setUidReadTimeouts(storageId, std::move(perUidReadTimeouts));
797*d57664e9SAndroid Build Coastguard Worker }
798*d57664e9SAndroid Build Coastguard Worker
799*d57664e9SAndroid Build Coastguard Worker IfsMountPtr ifs;
800*d57664e9SAndroid Build Coastguard Worker DataLoaderStubPtr dataLoaderStub;
801*d57664e9SAndroid Build Coastguard Worker
802*d57664e9SAndroid Build Coastguard Worker // Re-initialize DataLoader.
803*d57664e9SAndroid Build Coastguard Worker {
804*d57664e9SAndroid Build Coastguard Worker ifs = getIfs(storageId);
805*d57664e9SAndroid Build Coastguard Worker if (!ifs) {
806*d57664e9SAndroid Build Coastguard Worker return false;
807*d57664e9SAndroid Build Coastguard Worker }
808*d57664e9SAndroid Build Coastguard Worker
809*d57664e9SAndroid Build Coastguard Worker std::unique_lock l(ifs->lock);
810*d57664e9SAndroid Build Coastguard Worker dataLoaderStub = std::exchange(ifs->dataLoaderStub, nullptr);
811*d57664e9SAndroid Build Coastguard Worker }
812*d57664e9SAndroid Build Coastguard Worker
813*d57664e9SAndroid Build Coastguard Worker if (dataLoaderStub) {
814*d57664e9SAndroid Build Coastguard Worker dataLoaderStub->cleanupResources();
815*d57664e9SAndroid Build Coastguard Worker dataLoaderStub = {};
816*d57664e9SAndroid Build Coastguard Worker }
817*d57664e9SAndroid Build Coastguard Worker
818*d57664e9SAndroid Build Coastguard Worker {
819*d57664e9SAndroid Build Coastguard Worker std::unique_lock l(ifs->lock);
820*d57664e9SAndroid Build Coastguard Worker if (ifs->dataLoaderStub) {
821*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "Skipped data loader stub creation because it already exists";
822*d57664e9SAndroid Build Coastguard Worker return false;
823*d57664e9SAndroid Build Coastguard Worker }
824*d57664e9SAndroid Build Coastguard Worker
825*d57664e9SAndroid Build Coastguard Worker prepareDataLoaderLocked(*ifs, std::move(dataLoaderParams), std::move(statusListener),
826*d57664e9SAndroid Build Coastguard Worker healthCheckParams, std::move(healthListener));
827*d57664e9SAndroid Build Coastguard Worker CHECK(ifs->dataLoaderStub);
828*d57664e9SAndroid Build Coastguard Worker dataLoaderStub = ifs->dataLoaderStub;
829*d57664e9SAndroid Build Coastguard Worker
830*d57664e9SAndroid Build Coastguard Worker // Disable long read timeouts for non-system dataloaders.
831*d57664e9SAndroid Build Coastguard Worker // To be re-enabled after installation is complete.
832*d57664e9SAndroid Build Coastguard Worker ifs->setReadTimeoutsRequested(dataLoaderStub->isSystemDataLoader() &&
833*d57664e9SAndroid Build Coastguard Worker getAlwaysEnableReadTimeoutsForSystemDataLoaders());
834*d57664e9SAndroid Build Coastguard Worker applyStorageParamsLocked(*ifs);
835*d57664e9SAndroid Build Coastguard Worker }
836*d57664e9SAndroid Build Coastguard Worker
837*d57664e9SAndroid Build Coastguard Worker if (dataLoaderStub->isSystemDataLoader() &&
838*d57664e9SAndroid Build Coastguard Worker !getEnforceReadLogsMaxIntervalForSystemDataLoaders()) {
839*d57664e9SAndroid Build Coastguard Worker // Readlogs from system dataloader (adb) can always be collected.
840*d57664e9SAndroid Build Coastguard Worker ifs->startLoadingTs = TimePoint::max();
841*d57664e9SAndroid Build Coastguard Worker } else {
842*d57664e9SAndroid Build Coastguard Worker // Assign time when installation wants the DL to start streaming.
843*d57664e9SAndroid Build Coastguard Worker const auto startLoadingTs = mClock->now();
844*d57664e9SAndroid Build Coastguard Worker ifs->startLoadingTs = startLoadingTs;
845*d57664e9SAndroid Build Coastguard Worker // Setup a callback to disable the readlogs after max interval.
846*d57664e9SAndroid Build Coastguard Worker addTimedJob(*mTimedQueue, storageId, getReadLogsMaxInterval(),
847*d57664e9SAndroid Build Coastguard Worker [this, storageId, startLoadingTs]() {
848*d57664e9SAndroid Build Coastguard Worker const auto ifs = getIfs(storageId);
849*d57664e9SAndroid Build Coastguard Worker if (!ifs) {
850*d57664e9SAndroid Build Coastguard Worker LOG(WARNING) << "Can't disable the readlogs, invalid storageId: "
851*d57664e9SAndroid Build Coastguard Worker << storageId;
852*d57664e9SAndroid Build Coastguard Worker return;
853*d57664e9SAndroid Build Coastguard Worker }
854*d57664e9SAndroid Build Coastguard Worker std::unique_lock l(ifs->lock);
855*d57664e9SAndroid Build Coastguard Worker if (ifs->startLoadingTs != startLoadingTs) {
856*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "Can't disable the readlogs, timestamp mismatch (new "
857*d57664e9SAndroid Build Coastguard Worker "installation?): "
858*d57664e9SAndroid Build Coastguard Worker << storageId;
859*d57664e9SAndroid Build Coastguard Worker return;
860*d57664e9SAndroid Build Coastguard Worker }
861*d57664e9SAndroid Build Coastguard Worker disableReadLogsLocked(*ifs);
862*d57664e9SAndroid Build Coastguard Worker });
863*d57664e9SAndroid Build Coastguard Worker }
864*d57664e9SAndroid Build Coastguard Worker
865*d57664e9SAndroid Build Coastguard Worker return dataLoaderStub->requestStart();
866*d57664e9SAndroid Build Coastguard Worker }
867*d57664e9SAndroid Build Coastguard Worker
onInstallationComplete(StorageId storage)868*d57664e9SAndroid Build Coastguard Worker void IncrementalService::onInstallationComplete(StorageId storage) {
869*d57664e9SAndroid Build Coastguard Worker IfsMountPtr ifs = getIfs(storage);
870*d57664e9SAndroid Build Coastguard Worker if (!ifs) {
871*d57664e9SAndroid Build Coastguard Worker return;
872*d57664e9SAndroid Build Coastguard Worker }
873*d57664e9SAndroid Build Coastguard Worker
874*d57664e9SAndroid Build Coastguard Worker // Always enable long read timeouts after installation is complete.
875*d57664e9SAndroid Build Coastguard Worker std::unique_lock l(ifs->lock);
876*d57664e9SAndroid Build Coastguard Worker ifs->setReadTimeoutsRequested(getEnableReadTimeoutsAfterInstall());
877*d57664e9SAndroid Build Coastguard Worker applyStorageParamsLocked(*ifs);
878*d57664e9SAndroid Build Coastguard Worker }
879*d57664e9SAndroid Build Coastguard Worker
findStorageLocked(std::string_view path) const880*d57664e9SAndroid Build Coastguard Worker IncrementalService::BindPathMap::const_iterator IncrementalService::findStorageLocked(
881*d57664e9SAndroid Build Coastguard Worker std::string_view path) const {
882*d57664e9SAndroid Build Coastguard Worker return findParentPath(mBindsByPath, path);
883*d57664e9SAndroid Build Coastguard Worker }
884*d57664e9SAndroid Build Coastguard Worker
findStorageId(std::string_view path) const885*d57664e9SAndroid Build Coastguard Worker StorageId IncrementalService::findStorageId(std::string_view path) const {
886*d57664e9SAndroid Build Coastguard Worker std::lock_guard l(mLock);
887*d57664e9SAndroid Build Coastguard Worker auto it = findStorageLocked(path);
888*d57664e9SAndroid Build Coastguard Worker if (it == mBindsByPath.end()) {
889*d57664e9SAndroid Build Coastguard Worker return kInvalidStorageId;
890*d57664e9SAndroid Build Coastguard Worker }
891*d57664e9SAndroid Build Coastguard Worker return it->second->second.storage;
892*d57664e9SAndroid Build Coastguard Worker }
893*d57664e9SAndroid Build Coastguard Worker
disallowReadLogs(StorageId storageId)894*d57664e9SAndroid Build Coastguard Worker void IncrementalService::disallowReadLogs(StorageId storageId) {
895*d57664e9SAndroid Build Coastguard Worker const auto ifs = getIfs(storageId);
896*d57664e9SAndroid Build Coastguard Worker if (!ifs) {
897*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "disallowReadLogs failed, invalid storageId: " << storageId;
898*d57664e9SAndroid Build Coastguard Worker return;
899*d57664e9SAndroid Build Coastguard Worker }
900*d57664e9SAndroid Build Coastguard Worker
901*d57664e9SAndroid Build Coastguard Worker std::unique_lock l(ifs->lock);
902*d57664e9SAndroid Build Coastguard Worker if (!ifs->readLogsAllowed()) {
903*d57664e9SAndroid Build Coastguard Worker return;
904*d57664e9SAndroid Build Coastguard Worker }
905*d57664e9SAndroid Build Coastguard Worker ifs->disallowReadLogs();
906*d57664e9SAndroid Build Coastguard Worker
907*d57664e9SAndroid Build Coastguard Worker const auto metadata = constants().readLogsDisabledMarkerName;
908*d57664e9SAndroid Build Coastguard Worker if (auto err = mIncFs->makeFile(ifs->control,
909*d57664e9SAndroid Build Coastguard Worker path::join(ifs->root, constants().mount,
910*d57664e9SAndroid Build Coastguard Worker constants().readLogsDisabledMarkerName),
911*d57664e9SAndroid Build Coastguard Worker 0777, idFromMetadata(metadata), {})) {
912*d57664e9SAndroid Build Coastguard Worker //{.metadata = {metadata.data(), (IncFsSize)metadata.size()}})) {
913*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to make marker file for storageId: " << storageId << " err: " << -err;
914*d57664e9SAndroid Build Coastguard Worker return;
915*d57664e9SAndroid Build Coastguard Worker }
916*d57664e9SAndroid Build Coastguard Worker
917*d57664e9SAndroid Build Coastguard Worker disableReadLogsLocked(*ifs);
918*d57664e9SAndroid Build Coastguard Worker }
919*d57664e9SAndroid Build Coastguard Worker
setStorageParams(StorageId storageId,bool enableReadLogs)920*d57664e9SAndroid Build Coastguard Worker int IncrementalService::setStorageParams(StorageId storageId, bool enableReadLogs) {
921*d57664e9SAndroid Build Coastguard Worker const auto ifs = getIfs(storageId);
922*d57664e9SAndroid Build Coastguard Worker if (!ifs) {
923*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "setStorageParams failed, invalid storageId: " << storageId;
924*d57664e9SAndroid Build Coastguard Worker return -EINVAL;
925*d57664e9SAndroid Build Coastguard Worker }
926*d57664e9SAndroid Build Coastguard Worker
927*d57664e9SAndroid Build Coastguard Worker std::string packageName;
928*d57664e9SAndroid Build Coastguard Worker
929*d57664e9SAndroid Build Coastguard Worker {
930*d57664e9SAndroid Build Coastguard Worker std::unique_lock l(ifs->lock);
931*d57664e9SAndroid Build Coastguard Worker if (!enableReadLogs) {
932*d57664e9SAndroid Build Coastguard Worker return disableReadLogsLocked(*ifs);
933*d57664e9SAndroid Build Coastguard Worker }
934*d57664e9SAndroid Build Coastguard Worker
935*d57664e9SAndroid Build Coastguard Worker if (!ifs->readLogsAllowed()) {
936*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "enableReadLogs failed, readlogs disallowed for storageId: " << storageId;
937*d57664e9SAndroid Build Coastguard Worker return -EPERM;
938*d57664e9SAndroid Build Coastguard Worker }
939*d57664e9SAndroid Build Coastguard Worker
940*d57664e9SAndroid Build Coastguard Worker if (!ifs->dataLoaderStub) {
941*d57664e9SAndroid Build Coastguard Worker // This should never happen - only DL can call enableReadLogs.
942*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "enableReadLogs failed: invalid state";
943*d57664e9SAndroid Build Coastguard Worker return -EPERM;
944*d57664e9SAndroid Build Coastguard Worker }
945*d57664e9SAndroid Build Coastguard Worker
946*d57664e9SAndroid Build Coastguard Worker // Check installation time.
947*d57664e9SAndroid Build Coastguard Worker const auto now = mClock->now();
948*d57664e9SAndroid Build Coastguard Worker const auto startLoadingTs = ifs->startLoadingTs;
949*d57664e9SAndroid Build Coastguard Worker if (startLoadingTs <= now && now - startLoadingTs > getReadLogsMaxInterval()) {
950*d57664e9SAndroid Build Coastguard Worker LOG(ERROR)
951*d57664e9SAndroid Build Coastguard Worker << "enableReadLogs failed, readlogs can't be enabled at this time, storageId: "
952*d57664e9SAndroid Build Coastguard Worker << storageId;
953*d57664e9SAndroid Build Coastguard Worker return -EPERM;
954*d57664e9SAndroid Build Coastguard Worker }
955*d57664e9SAndroid Build Coastguard Worker
956*d57664e9SAndroid Build Coastguard Worker packageName = ifs->dataLoaderStub->params().packageName;
957*d57664e9SAndroid Build Coastguard Worker ifs->setReadLogsRequested(true);
958*d57664e9SAndroid Build Coastguard Worker }
959*d57664e9SAndroid Build Coastguard Worker
960*d57664e9SAndroid Build Coastguard Worker // Check loader usage stats permission and apop.
961*d57664e9SAndroid Build Coastguard Worker if (auto status =
962*d57664e9SAndroid Build Coastguard Worker mAppOpsManager->checkPermission(kLoaderUsageStats, kOpUsage, packageName.c_str());
963*d57664e9SAndroid Build Coastguard Worker !status.isOk()) {
964*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << " Permission: " << kLoaderUsageStats
965*d57664e9SAndroid Build Coastguard Worker << " check failed: " << status.toString8();
966*d57664e9SAndroid Build Coastguard Worker return fromBinderStatus(status);
967*d57664e9SAndroid Build Coastguard Worker }
968*d57664e9SAndroid Build Coastguard Worker
969*d57664e9SAndroid Build Coastguard Worker // Check multiuser permission.
970*d57664e9SAndroid Build Coastguard Worker if (auto status =
971*d57664e9SAndroid Build Coastguard Worker mAppOpsManager->checkPermission(kInteractAcrossUsers, nullptr, packageName.c_str());
972*d57664e9SAndroid Build Coastguard Worker !status.isOk()) {
973*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << " Permission: " << kInteractAcrossUsers
974*d57664e9SAndroid Build Coastguard Worker << " check failed: " << status.toString8();
975*d57664e9SAndroid Build Coastguard Worker return fromBinderStatus(status);
976*d57664e9SAndroid Build Coastguard Worker }
977*d57664e9SAndroid Build Coastguard Worker
978*d57664e9SAndroid Build Coastguard Worker {
979*d57664e9SAndroid Build Coastguard Worker std::unique_lock l(ifs->lock);
980*d57664e9SAndroid Build Coastguard Worker if (!ifs->readLogsRequested()) {
981*d57664e9SAndroid Build Coastguard Worker return 0;
982*d57664e9SAndroid Build Coastguard Worker }
983*d57664e9SAndroid Build Coastguard Worker if (auto status = applyStorageParamsLocked(*ifs); status != 0) {
984*d57664e9SAndroid Build Coastguard Worker return status;
985*d57664e9SAndroid Build Coastguard Worker }
986*d57664e9SAndroid Build Coastguard Worker }
987*d57664e9SAndroid Build Coastguard Worker
988*d57664e9SAndroid Build Coastguard Worker registerAppOpsCallback(packageName);
989*d57664e9SAndroid Build Coastguard Worker
990*d57664e9SAndroid Build Coastguard Worker return 0;
991*d57664e9SAndroid Build Coastguard Worker }
992*d57664e9SAndroid Build Coastguard Worker
disableReadLogsLocked(IncFsMount & ifs)993*d57664e9SAndroid Build Coastguard Worker int IncrementalService::disableReadLogsLocked(IncFsMount& ifs) {
994*d57664e9SAndroid Build Coastguard Worker ifs.setReadLogsRequested(false);
995*d57664e9SAndroid Build Coastguard Worker return applyStorageParamsLocked(ifs);
996*d57664e9SAndroid Build Coastguard Worker }
997*d57664e9SAndroid Build Coastguard Worker
applyStorageParamsLocked(IncFsMount & ifs)998*d57664e9SAndroid Build Coastguard Worker int IncrementalService::applyStorageParamsLocked(IncFsMount& ifs) {
999*d57664e9SAndroid Build Coastguard Worker os::incremental::IncrementalFileSystemControlParcel control;
1000*d57664e9SAndroid Build Coastguard Worker control.cmd.reset(dup(ifs.control.cmd()));
1001*d57664e9SAndroid Build Coastguard Worker control.pendingReads.reset(dup(ifs.control.pendingReads()));
1002*d57664e9SAndroid Build Coastguard Worker auto logsFd = ifs.control.logs();
1003*d57664e9SAndroid Build Coastguard Worker if (logsFd >= 0) {
1004*d57664e9SAndroid Build Coastguard Worker control.log.reset(dup(logsFd));
1005*d57664e9SAndroid Build Coastguard Worker }
1006*d57664e9SAndroid Build Coastguard Worker
1007*d57664e9SAndroid Build Coastguard Worker bool enableReadLogs = ifs.readLogsRequested();
1008*d57664e9SAndroid Build Coastguard Worker bool enableReadTimeouts = ifs.readTimeoutsRequested();
1009*d57664e9SAndroid Build Coastguard Worker
1010*d57664e9SAndroid Build Coastguard Worker std::lock_guard l(mMountOperationLock);
1011*d57664e9SAndroid Build Coastguard Worker auto status = mVold->setIncFsMountOptions(control, enableReadLogs, enableReadTimeouts,
1012*d57664e9SAndroid Build Coastguard Worker ifs.metricsKey);
1013*d57664e9SAndroid Build Coastguard Worker if (status.isOk()) {
1014*d57664e9SAndroid Build Coastguard Worker // Store states.
1015*d57664e9SAndroid Build Coastguard Worker ifs.setReadLogsEnabled(enableReadLogs);
1016*d57664e9SAndroid Build Coastguard Worker ifs.setReadTimeoutsEnabled(enableReadTimeouts);
1017*d57664e9SAndroid Build Coastguard Worker } else {
1018*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "applyStorageParams failed: " << status.toString8();
1019*d57664e9SAndroid Build Coastguard Worker }
1020*d57664e9SAndroid Build Coastguard Worker return status.isOk() ? 0 : fromBinderStatus(status);
1021*d57664e9SAndroid Build Coastguard Worker }
1022*d57664e9SAndroid Build Coastguard Worker
deleteStorage(StorageId storageId)1023*d57664e9SAndroid Build Coastguard Worker void IncrementalService::deleteStorage(StorageId storageId) {
1024*d57664e9SAndroid Build Coastguard Worker const auto ifs = getIfs(storageId);
1025*d57664e9SAndroid Build Coastguard Worker if (!ifs) {
1026*d57664e9SAndroid Build Coastguard Worker return;
1027*d57664e9SAndroid Build Coastguard Worker }
1028*d57664e9SAndroid Build Coastguard Worker deleteStorage(*ifs);
1029*d57664e9SAndroid Build Coastguard Worker }
1030*d57664e9SAndroid Build Coastguard Worker
deleteStorage(IncrementalService::IncFsMount & ifs)1031*d57664e9SAndroid Build Coastguard Worker void IncrementalService::deleteStorage(IncrementalService::IncFsMount& ifs) {
1032*d57664e9SAndroid Build Coastguard Worker std::unique_lock l(ifs.lock);
1033*d57664e9SAndroid Build Coastguard Worker deleteStorageLocked(ifs, std::move(l));
1034*d57664e9SAndroid Build Coastguard Worker }
1035*d57664e9SAndroid Build Coastguard Worker
deleteStorageLocked(IncrementalService::IncFsMount & ifs,std::unique_lock<std::mutex> && ifsLock)1036*d57664e9SAndroid Build Coastguard Worker void IncrementalService::deleteStorageLocked(IncrementalService::IncFsMount& ifs,
1037*d57664e9SAndroid Build Coastguard Worker std::unique_lock<std::mutex>&& ifsLock) {
1038*d57664e9SAndroid Build Coastguard Worker const auto storages = std::move(ifs.storages);
1039*d57664e9SAndroid Build Coastguard Worker // Don't move the bind points out: Ifs's dtor will use them to unmount everything.
1040*d57664e9SAndroid Build Coastguard Worker const auto bindPoints = ifs.bindPoints;
1041*d57664e9SAndroid Build Coastguard Worker ifsLock.unlock();
1042*d57664e9SAndroid Build Coastguard Worker
1043*d57664e9SAndroid Build Coastguard Worker std::lock_guard l(mLock);
1044*d57664e9SAndroid Build Coastguard Worker for (auto&& [id, _] : storages) {
1045*d57664e9SAndroid Build Coastguard Worker if (id != ifs.mountId) {
1046*d57664e9SAndroid Build Coastguard Worker mMounts.erase(id);
1047*d57664e9SAndroid Build Coastguard Worker }
1048*d57664e9SAndroid Build Coastguard Worker }
1049*d57664e9SAndroid Build Coastguard Worker for (auto&& [path, _] : bindPoints) {
1050*d57664e9SAndroid Build Coastguard Worker mBindsByPath.erase(path);
1051*d57664e9SAndroid Build Coastguard Worker }
1052*d57664e9SAndroid Build Coastguard Worker mMounts.erase(ifs.mountId);
1053*d57664e9SAndroid Build Coastguard Worker }
1054*d57664e9SAndroid Build Coastguard Worker
openStorage(std::string_view pathInMount)1055*d57664e9SAndroid Build Coastguard Worker StorageId IncrementalService::openStorage(std::string_view pathInMount) {
1056*d57664e9SAndroid Build Coastguard Worker if (!path::isAbsolute(pathInMount)) {
1057*d57664e9SAndroid Build Coastguard Worker return kInvalidStorageId;
1058*d57664e9SAndroid Build Coastguard Worker }
1059*d57664e9SAndroid Build Coastguard Worker
1060*d57664e9SAndroid Build Coastguard Worker return findStorageId(path::normalize(pathInMount));
1061*d57664e9SAndroid Build Coastguard Worker }
1062*d57664e9SAndroid Build Coastguard Worker
getIfs(StorageId storage) const1063*d57664e9SAndroid Build Coastguard Worker IncrementalService::IfsMountPtr IncrementalService::getIfs(StorageId storage) const {
1064*d57664e9SAndroid Build Coastguard Worker std::lock_guard l(mLock);
1065*d57664e9SAndroid Build Coastguard Worker return getIfsLocked(storage);
1066*d57664e9SAndroid Build Coastguard Worker }
1067*d57664e9SAndroid Build Coastguard Worker
getIfsLocked(StorageId storage) const1068*d57664e9SAndroid Build Coastguard Worker const IncrementalService::IfsMountPtr& IncrementalService::getIfsLocked(StorageId storage) const {
1069*d57664e9SAndroid Build Coastguard Worker auto it = mMounts.find(storage);
1070*d57664e9SAndroid Build Coastguard Worker if (it == mMounts.end()) {
1071*d57664e9SAndroid Build Coastguard Worker static const base::NoDestructor<IfsMountPtr> kEmpty{};
1072*d57664e9SAndroid Build Coastguard Worker return *kEmpty;
1073*d57664e9SAndroid Build Coastguard Worker }
1074*d57664e9SAndroid Build Coastguard Worker return it->second;
1075*d57664e9SAndroid Build Coastguard Worker }
1076*d57664e9SAndroid Build Coastguard Worker
bind(StorageId storage,std::string_view source,std::string_view target,BindKind kind)1077*d57664e9SAndroid Build Coastguard Worker int IncrementalService::bind(StorageId storage, std::string_view source, std::string_view target,
1078*d57664e9SAndroid Build Coastguard Worker BindKind kind) {
1079*d57664e9SAndroid Build Coastguard Worker if (!isValidMountTarget(target)) {
1080*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << __func__ << ": not a valid bind target " << target;
1081*d57664e9SAndroid Build Coastguard Worker return -EINVAL;
1082*d57664e9SAndroid Build Coastguard Worker }
1083*d57664e9SAndroid Build Coastguard Worker
1084*d57664e9SAndroid Build Coastguard Worker const auto ifs = getIfs(storage);
1085*d57664e9SAndroid Build Coastguard Worker if (!ifs) {
1086*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << __func__ << ": no ifs object for storage " << storage;
1087*d57664e9SAndroid Build Coastguard Worker return -EINVAL;
1088*d57664e9SAndroid Build Coastguard Worker }
1089*d57664e9SAndroid Build Coastguard Worker
1090*d57664e9SAndroid Build Coastguard Worker std::unique_lock l(ifs->lock);
1091*d57664e9SAndroid Build Coastguard Worker const auto storageInfo = ifs->storages.find(storage);
1092*d57664e9SAndroid Build Coastguard Worker if (storageInfo == ifs->storages.end()) {
1093*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "no storage";
1094*d57664e9SAndroid Build Coastguard Worker return -EINVAL;
1095*d57664e9SAndroid Build Coastguard Worker }
1096*d57664e9SAndroid Build Coastguard Worker std::string normSource = normalizePathToStorageLocked(*ifs, storageInfo, source);
1097*d57664e9SAndroid Build Coastguard Worker if (normSource.empty()) {
1098*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "invalid source path";
1099*d57664e9SAndroid Build Coastguard Worker return -EINVAL;
1100*d57664e9SAndroid Build Coastguard Worker }
1101*d57664e9SAndroid Build Coastguard Worker l.unlock();
1102*d57664e9SAndroid Build Coastguard Worker std::unique_lock l2(mLock, std::defer_lock);
1103*d57664e9SAndroid Build Coastguard Worker return addBindMount(*ifs, storage, storageInfo->second.name, std::move(normSource),
1104*d57664e9SAndroid Build Coastguard Worker path::normalize(target), kind, l2);
1105*d57664e9SAndroid Build Coastguard Worker }
1106*d57664e9SAndroid Build Coastguard Worker
unbind(StorageId storage,std::string_view target)1107*d57664e9SAndroid Build Coastguard Worker int IncrementalService::unbind(StorageId storage, std::string_view target) {
1108*d57664e9SAndroid Build Coastguard Worker if (!path::isAbsolute(target)) {
1109*d57664e9SAndroid Build Coastguard Worker return -EINVAL;
1110*d57664e9SAndroid Build Coastguard Worker }
1111*d57664e9SAndroid Build Coastguard Worker
1112*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "Removing bind point " << target << " for storage " << storage;
1113*d57664e9SAndroid Build Coastguard Worker
1114*d57664e9SAndroid Build Coastguard Worker // Here we should only look up by the exact target, not by a subdirectory of any existing mount,
1115*d57664e9SAndroid Build Coastguard Worker // otherwise there's a chance to unmount something completely unrelated
1116*d57664e9SAndroid Build Coastguard Worker const auto norm = path::normalize(target);
1117*d57664e9SAndroid Build Coastguard Worker std::unique_lock l(mLock);
1118*d57664e9SAndroid Build Coastguard Worker const auto storageIt = mBindsByPath.find(norm);
1119*d57664e9SAndroid Build Coastguard Worker if (storageIt == mBindsByPath.end() || storageIt->second->second.storage != storage) {
1120*d57664e9SAndroid Build Coastguard Worker return -EINVAL;
1121*d57664e9SAndroid Build Coastguard Worker }
1122*d57664e9SAndroid Build Coastguard Worker const auto bindIt = storageIt->second;
1123*d57664e9SAndroid Build Coastguard Worker const auto storageId = bindIt->second.storage;
1124*d57664e9SAndroid Build Coastguard Worker const auto ifs = getIfsLocked(storageId);
1125*d57664e9SAndroid Build Coastguard Worker if (!ifs) {
1126*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Internal error: storageId " << storageId << " for bound path " << target
1127*d57664e9SAndroid Build Coastguard Worker << " is missing";
1128*d57664e9SAndroid Build Coastguard Worker return -EFAULT;
1129*d57664e9SAndroid Build Coastguard Worker }
1130*d57664e9SAndroid Build Coastguard Worker mBindsByPath.erase(storageIt);
1131*d57664e9SAndroid Build Coastguard Worker l.unlock();
1132*d57664e9SAndroid Build Coastguard Worker
1133*d57664e9SAndroid Build Coastguard Worker mVold->unmountIncFs(bindIt->first);
1134*d57664e9SAndroid Build Coastguard Worker std::unique_lock l2(ifs->lock);
1135*d57664e9SAndroid Build Coastguard Worker if (ifs->bindPoints.size() <= 1) {
1136*d57664e9SAndroid Build Coastguard Worker ifs->bindPoints.clear();
1137*d57664e9SAndroid Build Coastguard Worker deleteStorageLocked(*ifs, std::move(l2));
1138*d57664e9SAndroid Build Coastguard Worker } else {
1139*d57664e9SAndroid Build Coastguard Worker const std::string savedFile = std::move(bindIt->second.savedFilename);
1140*d57664e9SAndroid Build Coastguard Worker ifs->bindPoints.erase(bindIt);
1141*d57664e9SAndroid Build Coastguard Worker l2.unlock();
1142*d57664e9SAndroid Build Coastguard Worker if (!savedFile.empty()) {
1143*d57664e9SAndroid Build Coastguard Worker mIncFs->unlink(ifs->control, path::join(ifs->root, constants().mount, savedFile));
1144*d57664e9SAndroid Build Coastguard Worker }
1145*d57664e9SAndroid Build Coastguard Worker }
1146*d57664e9SAndroid Build Coastguard Worker
1147*d57664e9SAndroid Build Coastguard Worker return 0;
1148*d57664e9SAndroid Build Coastguard Worker }
1149*d57664e9SAndroid Build Coastguard Worker
normalizePathToStorageLocked(const IncFsMount & incfs,IncFsMount::StorageMap::const_iterator storageIt,std::string_view path) const1150*d57664e9SAndroid Build Coastguard Worker std::string IncrementalService::normalizePathToStorageLocked(
1151*d57664e9SAndroid Build Coastguard Worker const IncFsMount& incfs, IncFsMount::StorageMap::const_iterator storageIt,
1152*d57664e9SAndroid Build Coastguard Worker std::string_view path) const {
1153*d57664e9SAndroid Build Coastguard Worker if (!path::isAbsolute(path)) {
1154*d57664e9SAndroid Build Coastguard Worker return path::normalize(path::join(storageIt->second.name, path));
1155*d57664e9SAndroid Build Coastguard Worker }
1156*d57664e9SAndroid Build Coastguard Worker auto normPath = path::normalize(path);
1157*d57664e9SAndroid Build Coastguard Worker if (path::startsWith(normPath, storageIt->second.name)) {
1158*d57664e9SAndroid Build Coastguard Worker return normPath;
1159*d57664e9SAndroid Build Coastguard Worker }
1160*d57664e9SAndroid Build Coastguard Worker // not that easy: need to find if any of the bind points match
1161*d57664e9SAndroid Build Coastguard Worker const auto bindIt = findParentPath(incfs.bindPoints, normPath);
1162*d57664e9SAndroid Build Coastguard Worker if (bindIt == incfs.bindPoints.end()) {
1163*d57664e9SAndroid Build Coastguard Worker return {};
1164*d57664e9SAndroid Build Coastguard Worker }
1165*d57664e9SAndroid Build Coastguard Worker return path::join(bindIt->second.sourceDir, path::relativize(bindIt->first, normPath));
1166*d57664e9SAndroid Build Coastguard Worker }
1167*d57664e9SAndroid Build Coastguard Worker
normalizePathToStorage(const IncFsMount & ifs,StorageId storage,std::string_view path) const1168*d57664e9SAndroid Build Coastguard Worker std::string IncrementalService::normalizePathToStorage(const IncFsMount& ifs, StorageId storage,
1169*d57664e9SAndroid Build Coastguard Worker std::string_view path) const {
1170*d57664e9SAndroid Build Coastguard Worker std::unique_lock l(ifs.lock);
1171*d57664e9SAndroid Build Coastguard Worker const auto storageInfo = ifs.storages.find(storage);
1172*d57664e9SAndroid Build Coastguard Worker if (storageInfo == ifs.storages.end()) {
1173*d57664e9SAndroid Build Coastguard Worker return {};
1174*d57664e9SAndroid Build Coastguard Worker }
1175*d57664e9SAndroid Build Coastguard Worker return normalizePathToStorageLocked(ifs, storageInfo, path);
1176*d57664e9SAndroid Build Coastguard Worker }
1177*d57664e9SAndroid Build Coastguard Worker
makeFile(StorageId storage,std::string_view path,int mode,FileId id,incfs::NewFileParams params,std::span<const uint8_t> data)1178*d57664e9SAndroid Build Coastguard Worker int IncrementalService::makeFile(StorageId storage, std::string_view path, int mode, FileId id,
1179*d57664e9SAndroid Build Coastguard Worker incfs::NewFileParams params, std::span<const uint8_t> data) {
1180*d57664e9SAndroid Build Coastguard Worker const auto ifs = getIfs(storage);
1181*d57664e9SAndroid Build Coastguard Worker if (!ifs) {
1182*d57664e9SAndroid Build Coastguard Worker return -EINVAL;
1183*d57664e9SAndroid Build Coastguard Worker }
1184*d57664e9SAndroid Build Coastguard Worker if ((IncFsSize)data.size() > params.size) {
1185*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Bad data size - bigger than file size";
1186*d57664e9SAndroid Build Coastguard Worker return -EINVAL;
1187*d57664e9SAndroid Build Coastguard Worker }
1188*d57664e9SAndroid Build Coastguard Worker if (!data.empty() && (IncFsSize)data.size() != params.size) {
1189*d57664e9SAndroid Build Coastguard Worker // Writing a page is an irreversible operation, and it can't be updated with additional
1190*d57664e9SAndroid Build Coastguard Worker // data later. Check that the last written page is complete, or we may break the file.
1191*d57664e9SAndroid Build Coastguard Worker if (!isPageAligned(data.size())) {
1192*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Bad data size - tried to write half a page?";
1193*d57664e9SAndroid Build Coastguard Worker return -EINVAL;
1194*d57664e9SAndroid Build Coastguard Worker }
1195*d57664e9SAndroid Build Coastguard Worker }
1196*d57664e9SAndroid Build Coastguard Worker const std::string normPath = normalizePathToStorage(*ifs, storage, path);
1197*d57664e9SAndroid Build Coastguard Worker if (normPath.empty()) {
1198*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Internal error: storageId " << storage << " failed to normalize: " << path;
1199*d57664e9SAndroid Build Coastguard Worker return -EINVAL;
1200*d57664e9SAndroid Build Coastguard Worker }
1201*d57664e9SAndroid Build Coastguard Worker if (auto err = mIncFs->makeFile(ifs->control, normPath, mode, id, params); err) {
1202*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Internal error: storageId " << storage << " failed to makeFile [" << normPath
1203*d57664e9SAndroid Build Coastguard Worker << "]: " << err;
1204*d57664e9SAndroid Build Coastguard Worker return err;
1205*d57664e9SAndroid Build Coastguard Worker }
1206*d57664e9SAndroid Build Coastguard Worker if (params.size > 0) {
1207*d57664e9SAndroid Build Coastguard Worker if (auto err = mIncFs->reserveSpace(ifs->control, id, params.size)) {
1208*d57664e9SAndroid Build Coastguard Worker if (err != -EOPNOTSUPP) {
1209*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to reserve space for a new file: " << err;
1210*d57664e9SAndroid Build Coastguard Worker (void)mIncFs->unlink(ifs->control, normPath);
1211*d57664e9SAndroid Build Coastguard Worker return err;
1212*d57664e9SAndroid Build Coastguard Worker } else {
1213*d57664e9SAndroid Build Coastguard Worker LOG(WARNING) << "Reserving space for backing file isn't supported, "
1214*d57664e9SAndroid Build Coastguard Worker "may run out of disk later";
1215*d57664e9SAndroid Build Coastguard Worker }
1216*d57664e9SAndroid Build Coastguard Worker }
1217*d57664e9SAndroid Build Coastguard Worker if (!data.empty()) {
1218*d57664e9SAndroid Build Coastguard Worker if (auto err = setFileContent(ifs, id, path, data); err) {
1219*d57664e9SAndroid Build Coastguard Worker (void)mIncFs->unlink(ifs->control, normPath);
1220*d57664e9SAndroid Build Coastguard Worker return err;
1221*d57664e9SAndroid Build Coastguard Worker }
1222*d57664e9SAndroid Build Coastguard Worker }
1223*d57664e9SAndroid Build Coastguard Worker }
1224*d57664e9SAndroid Build Coastguard Worker return 0;
1225*d57664e9SAndroid Build Coastguard Worker }
1226*d57664e9SAndroid Build Coastguard Worker
makeDir(StorageId storageId,std::string_view path,int mode)1227*d57664e9SAndroid Build Coastguard Worker int IncrementalService::makeDir(StorageId storageId, std::string_view path, int mode) {
1228*d57664e9SAndroid Build Coastguard Worker if (auto ifs = getIfs(storageId)) {
1229*d57664e9SAndroid Build Coastguard Worker std::string normPath = normalizePathToStorage(*ifs, storageId, path);
1230*d57664e9SAndroid Build Coastguard Worker if (normPath.empty()) {
1231*d57664e9SAndroid Build Coastguard Worker return -EINVAL;
1232*d57664e9SAndroid Build Coastguard Worker }
1233*d57664e9SAndroid Build Coastguard Worker return mIncFs->makeDir(ifs->control, normPath, mode);
1234*d57664e9SAndroid Build Coastguard Worker }
1235*d57664e9SAndroid Build Coastguard Worker return -EINVAL;
1236*d57664e9SAndroid Build Coastguard Worker }
1237*d57664e9SAndroid Build Coastguard Worker
makeDirs(StorageId storageId,std::string_view path,int mode)1238*d57664e9SAndroid Build Coastguard Worker int IncrementalService::makeDirs(StorageId storageId, std::string_view path, int mode) {
1239*d57664e9SAndroid Build Coastguard Worker const auto ifs = getIfs(storageId);
1240*d57664e9SAndroid Build Coastguard Worker if (!ifs) {
1241*d57664e9SAndroid Build Coastguard Worker return -EINVAL;
1242*d57664e9SAndroid Build Coastguard Worker }
1243*d57664e9SAndroid Build Coastguard Worker return makeDirs(*ifs, storageId, path, mode);
1244*d57664e9SAndroid Build Coastguard Worker }
1245*d57664e9SAndroid Build Coastguard Worker
makeDirs(const IncFsMount & ifs,StorageId storageId,std::string_view path,int mode)1246*d57664e9SAndroid Build Coastguard Worker int IncrementalService::makeDirs(const IncFsMount& ifs, StorageId storageId, std::string_view path,
1247*d57664e9SAndroid Build Coastguard Worker int mode) {
1248*d57664e9SAndroid Build Coastguard Worker std::string normPath = normalizePathToStorage(ifs, storageId, path);
1249*d57664e9SAndroid Build Coastguard Worker if (normPath.empty()) {
1250*d57664e9SAndroid Build Coastguard Worker return -EINVAL;
1251*d57664e9SAndroid Build Coastguard Worker }
1252*d57664e9SAndroid Build Coastguard Worker return mIncFs->makeDirs(ifs.control, normPath, mode);
1253*d57664e9SAndroid Build Coastguard Worker }
1254*d57664e9SAndroid Build Coastguard Worker
link(StorageId sourceStorageId,std::string_view oldPath,StorageId destStorageId,std::string_view newPath)1255*d57664e9SAndroid Build Coastguard Worker int IncrementalService::link(StorageId sourceStorageId, std::string_view oldPath,
1256*d57664e9SAndroid Build Coastguard Worker StorageId destStorageId, std::string_view newPath) {
1257*d57664e9SAndroid Build Coastguard Worker std::unique_lock l(mLock);
1258*d57664e9SAndroid Build Coastguard Worker auto ifsSrc = getIfsLocked(sourceStorageId);
1259*d57664e9SAndroid Build Coastguard Worker if (!ifsSrc) {
1260*d57664e9SAndroid Build Coastguard Worker return -EINVAL;
1261*d57664e9SAndroid Build Coastguard Worker }
1262*d57664e9SAndroid Build Coastguard Worker if (sourceStorageId != destStorageId && getIfsLocked(destStorageId) != ifsSrc) {
1263*d57664e9SAndroid Build Coastguard Worker return -EINVAL;
1264*d57664e9SAndroid Build Coastguard Worker }
1265*d57664e9SAndroid Build Coastguard Worker l.unlock();
1266*d57664e9SAndroid Build Coastguard Worker std::string normOldPath = normalizePathToStorage(*ifsSrc, sourceStorageId, oldPath);
1267*d57664e9SAndroid Build Coastguard Worker std::string normNewPath = normalizePathToStorage(*ifsSrc, destStorageId, newPath);
1268*d57664e9SAndroid Build Coastguard Worker if (normOldPath.empty() || normNewPath.empty()) {
1269*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Invalid paths in link(): " << normOldPath << " | " << normNewPath;
1270*d57664e9SAndroid Build Coastguard Worker return -EINVAL;
1271*d57664e9SAndroid Build Coastguard Worker }
1272*d57664e9SAndroid Build Coastguard Worker if (auto err = mIncFs->link(ifsSrc->control, normOldPath, normNewPath); err < 0) {
1273*d57664e9SAndroid Build Coastguard Worker PLOG(ERROR) << "Failed to link " << oldPath << "[" << normOldPath << "]"
1274*d57664e9SAndroid Build Coastguard Worker << " to " << newPath << "[" << normNewPath << "]";
1275*d57664e9SAndroid Build Coastguard Worker return err;
1276*d57664e9SAndroid Build Coastguard Worker }
1277*d57664e9SAndroid Build Coastguard Worker return 0;
1278*d57664e9SAndroid Build Coastguard Worker }
1279*d57664e9SAndroid Build Coastguard Worker
unlink(StorageId storage,std::string_view path)1280*d57664e9SAndroid Build Coastguard Worker int IncrementalService::unlink(StorageId storage, std::string_view path) {
1281*d57664e9SAndroid Build Coastguard Worker if (auto ifs = getIfs(storage)) {
1282*d57664e9SAndroid Build Coastguard Worker std::string normOldPath = normalizePathToStorage(*ifs, storage, path);
1283*d57664e9SAndroid Build Coastguard Worker return mIncFs->unlink(ifs->control, normOldPath);
1284*d57664e9SAndroid Build Coastguard Worker }
1285*d57664e9SAndroid Build Coastguard Worker return -EINVAL;
1286*d57664e9SAndroid Build Coastguard Worker }
1287*d57664e9SAndroid Build Coastguard Worker
addBindMount(IncFsMount & ifs,StorageId storage,std::string_view storageRoot,std::string && source,std::string && target,BindKind kind,std::unique_lock<std::mutex> & mainLock)1288*d57664e9SAndroid Build Coastguard Worker int IncrementalService::addBindMount(IncFsMount& ifs, StorageId storage,
1289*d57664e9SAndroid Build Coastguard Worker std::string_view storageRoot, std::string&& source,
1290*d57664e9SAndroid Build Coastguard Worker std::string&& target, BindKind kind,
1291*d57664e9SAndroid Build Coastguard Worker std::unique_lock<std::mutex>& mainLock) {
1292*d57664e9SAndroid Build Coastguard Worker if (!isValidMountTarget(target)) {
1293*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << __func__ << ": invalid mount target " << target;
1294*d57664e9SAndroid Build Coastguard Worker return -EINVAL;
1295*d57664e9SAndroid Build Coastguard Worker }
1296*d57664e9SAndroid Build Coastguard Worker
1297*d57664e9SAndroid Build Coastguard Worker std::string mdFileName;
1298*d57664e9SAndroid Build Coastguard Worker std::string metadataFullPath;
1299*d57664e9SAndroid Build Coastguard Worker if (kind != BindKind::Temporary) {
1300*d57664e9SAndroid Build Coastguard Worker metadata::BindPoint bp;
1301*d57664e9SAndroid Build Coastguard Worker bp.set_storage_id(storage);
1302*d57664e9SAndroid Build Coastguard Worker bp.set_allocated_dest_path(&target);
1303*d57664e9SAndroid Build Coastguard Worker bp.set_allocated_source_subdir(&source);
1304*d57664e9SAndroid Build Coastguard Worker const auto metadata = bp.SerializeAsString();
1305*d57664e9SAndroid Build Coastguard Worker static_cast<void>(bp.release_dest_path());
1306*d57664e9SAndroid Build Coastguard Worker static_cast<void>(bp.release_source_subdir());
1307*d57664e9SAndroid Build Coastguard Worker mdFileName = makeBindMdName();
1308*d57664e9SAndroid Build Coastguard Worker metadataFullPath = path::join(ifs.root, constants().mount, mdFileName);
1309*d57664e9SAndroid Build Coastguard Worker auto node = mIncFs->makeFile(ifs.control, metadataFullPath, 0444, idFromMetadata(metadata),
1310*d57664e9SAndroid Build Coastguard Worker {.metadata = {metadata.data(), (IncFsSize)metadata.size()}});
1311*d57664e9SAndroid Build Coastguard Worker if (node) {
1312*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << __func__ << ": couldn't create a mount node " << mdFileName;
1313*d57664e9SAndroid Build Coastguard Worker return int(node);
1314*d57664e9SAndroid Build Coastguard Worker }
1315*d57664e9SAndroid Build Coastguard Worker }
1316*d57664e9SAndroid Build Coastguard Worker
1317*d57664e9SAndroid Build Coastguard Worker const auto res = addBindMountWithMd(ifs, storage, std::move(mdFileName), std::move(source),
1318*d57664e9SAndroid Build Coastguard Worker std::move(target), kind, mainLock);
1319*d57664e9SAndroid Build Coastguard Worker if (res) {
1320*d57664e9SAndroid Build Coastguard Worker mIncFs->unlink(ifs.control, metadataFullPath);
1321*d57664e9SAndroid Build Coastguard Worker }
1322*d57664e9SAndroid Build Coastguard Worker return res;
1323*d57664e9SAndroid Build Coastguard Worker }
1324*d57664e9SAndroid Build Coastguard Worker
addBindMountWithMd(IncrementalService::IncFsMount & ifs,StorageId storage,std::string && metadataName,std::string && source,std::string && target,BindKind kind,std::unique_lock<std::mutex> & mainLock)1325*d57664e9SAndroid Build Coastguard Worker int IncrementalService::addBindMountWithMd(IncrementalService::IncFsMount& ifs, StorageId storage,
1326*d57664e9SAndroid Build Coastguard Worker std::string&& metadataName, std::string&& source,
1327*d57664e9SAndroid Build Coastguard Worker std::string&& target, BindKind kind,
1328*d57664e9SAndroid Build Coastguard Worker std::unique_lock<std::mutex>& mainLock) {
1329*d57664e9SAndroid Build Coastguard Worker {
1330*d57664e9SAndroid Build Coastguard Worker std::lock_guard l(mMountOperationLock);
1331*d57664e9SAndroid Build Coastguard Worker const auto status = mVold->bindMount(source, target);
1332*d57664e9SAndroid Build Coastguard Worker if (!status.isOk()) {
1333*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Calling Vold::bindMount() failed: " << status.toString8();
1334*d57664e9SAndroid Build Coastguard Worker return status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC
1335*d57664e9SAndroid Build Coastguard Worker ? status.serviceSpecificErrorCode() > 0 ? -status.serviceSpecificErrorCode()
1336*d57664e9SAndroid Build Coastguard Worker : status.serviceSpecificErrorCode() == 0
1337*d57664e9SAndroid Build Coastguard Worker ? -EFAULT
1338*d57664e9SAndroid Build Coastguard Worker : status.serviceSpecificErrorCode()
1339*d57664e9SAndroid Build Coastguard Worker : -EIO;
1340*d57664e9SAndroid Build Coastguard Worker }
1341*d57664e9SAndroid Build Coastguard Worker }
1342*d57664e9SAndroid Build Coastguard Worker
1343*d57664e9SAndroid Build Coastguard Worker if (!mainLock.owns_lock()) {
1344*d57664e9SAndroid Build Coastguard Worker mainLock.lock();
1345*d57664e9SAndroid Build Coastguard Worker }
1346*d57664e9SAndroid Build Coastguard Worker std::lock_guard l(ifs.lock);
1347*d57664e9SAndroid Build Coastguard Worker addBindMountRecordLocked(ifs, storage, std::move(metadataName), std::move(source),
1348*d57664e9SAndroid Build Coastguard Worker std::move(target), kind);
1349*d57664e9SAndroid Build Coastguard Worker return 0;
1350*d57664e9SAndroid Build Coastguard Worker }
1351*d57664e9SAndroid Build Coastguard Worker
addBindMountRecordLocked(IncFsMount & ifs,StorageId storage,std::string && metadataName,std::string && source,std::string && target,BindKind kind)1352*d57664e9SAndroid Build Coastguard Worker void IncrementalService::addBindMountRecordLocked(IncFsMount& ifs, StorageId storage,
1353*d57664e9SAndroid Build Coastguard Worker std::string&& metadataName, std::string&& source,
1354*d57664e9SAndroid Build Coastguard Worker std::string&& target, BindKind kind) {
1355*d57664e9SAndroid Build Coastguard Worker const auto [it, _] =
1356*d57664e9SAndroid Build Coastguard Worker ifs.bindPoints.insert_or_assign(target,
1357*d57664e9SAndroid Build Coastguard Worker IncFsMount::Bind{storage, std::move(metadataName),
1358*d57664e9SAndroid Build Coastguard Worker std::move(source), kind});
1359*d57664e9SAndroid Build Coastguard Worker mBindsByPath[std::move(target)] = it;
1360*d57664e9SAndroid Build Coastguard Worker }
1361*d57664e9SAndroid Build Coastguard Worker
getMetadata(StorageId storage,std::string_view path) const1362*d57664e9SAndroid Build Coastguard Worker RawMetadata IncrementalService::getMetadata(StorageId storage, std::string_view path) const {
1363*d57664e9SAndroid Build Coastguard Worker const auto ifs = getIfs(storage);
1364*d57664e9SAndroid Build Coastguard Worker if (!ifs) {
1365*d57664e9SAndroid Build Coastguard Worker return {};
1366*d57664e9SAndroid Build Coastguard Worker }
1367*d57664e9SAndroid Build Coastguard Worker const auto normPath = normalizePathToStorage(*ifs, storage, path);
1368*d57664e9SAndroid Build Coastguard Worker if (normPath.empty()) {
1369*d57664e9SAndroid Build Coastguard Worker return {};
1370*d57664e9SAndroid Build Coastguard Worker }
1371*d57664e9SAndroid Build Coastguard Worker return mIncFs->getMetadata(ifs->control, normPath);
1372*d57664e9SAndroid Build Coastguard Worker }
1373*d57664e9SAndroid Build Coastguard Worker
getMetadata(StorageId storage,FileId node) const1374*d57664e9SAndroid Build Coastguard Worker RawMetadata IncrementalService::getMetadata(StorageId storage, FileId node) const {
1375*d57664e9SAndroid Build Coastguard Worker const auto ifs = getIfs(storage);
1376*d57664e9SAndroid Build Coastguard Worker if (!ifs) {
1377*d57664e9SAndroid Build Coastguard Worker return {};
1378*d57664e9SAndroid Build Coastguard Worker }
1379*d57664e9SAndroid Build Coastguard Worker return mIncFs->getMetadata(ifs->control, node);
1380*d57664e9SAndroid Build Coastguard Worker }
1381*d57664e9SAndroid Build Coastguard Worker
setUidReadTimeouts(StorageId storage,std::vector<PerUidReadTimeouts> && perUidReadTimeouts)1382*d57664e9SAndroid Build Coastguard Worker void IncrementalService::setUidReadTimeouts(StorageId storage,
1383*d57664e9SAndroid Build Coastguard Worker std::vector<PerUidReadTimeouts>&& perUidReadTimeouts) {
1384*d57664e9SAndroid Build Coastguard Worker using microseconds = std::chrono::microseconds;
1385*d57664e9SAndroid Build Coastguard Worker using milliseconds = std::chrono::milliseconds;
1386*d57664e9SAndroid Build Coastguard Worker
1387*d57664e9SAndroid Build Coastguard Worker auto maxPendingTimeUs = microseconds(0);
1388*d57664e9SAndroid Build Coastguard Worker for (const auto& timeouts : perUidReadTimeouts) {
1389*d57664e9SAndroid Build Coastguard Worker maxPendingTimeUs = std::max(maxPendingTimeUs, microseconds(timeouts.maxPendingTimeUs));
1390*d57664e9SAndroid Build Coastguard Worker }
1391*d57664e9SAndroid Build Coastguard Worker if (maxPendingTimeUs < Constants::minPerUidTimeout) {
1392*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Skip setting read timeouts (maxPendingTime < Constants::minPerUidTimeout): "
1393*d57664e9SAndroid Build Coastguard Worker << duration_cast<milliseconds>(maxPendingTimeUs).count() << "ms < "
1394*d57664e9SAndroid Build Coastguard Worker << Constants::minPerUidTimeout.count() << "ms";
1395*d57664e9SAndroid Build Coastguard Worker return;
1396*d57664e9SAndroid Build Coastguard Worker }
1397*d57664e9SAndroid Build Coastguard Worker
1398*d57664e9SAndroid Build Coastguard Worker const auto ifs = getIfs(storage);
1399*d57664e9SAndroid Build Coastguard Worker if (!ifs) {
1400*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Setting read timeouts failed: invalid storage id: " << storage;
1401*d57664e9SAndroid Build Coastguard Worker return;
1402*d57664e9SAndroid Build Coastguard Worker }
1403*d57664e9SAndroid Build Coastguard Worker
1404*d57664e9SAndroid Build Coastguard Worker if (auto err = mIncFs->setUidReadTimeouts(ifs->control, perUidReadTimeouts); err < 0) {
1405*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Setting read timeouts failed: " << -err;
1406*d57664e9SAndroid Build Coastguard Worker return;
1407*d57664e9SAndroid Build Coastguard Worker }
1408*d57664e9SAndroid Build Coastguard Worker
1409*d57664e9SAndroid Build Coastguard Worker const auto timeout = Clock::now() + maxPendingTimeUs - Constants::perUidTimeoutOffset;
1410*d57664e9SAndroid Build Coastguard Worker addIfsStateCallback(storage, [this, timeout](StorageId storageId, IfsState state) -> bool {
1411*d57664e9SAndroid Build Coastguard Worker if (checkUidReadTimeouts(storageId, state, timeout)) {
1412*d57664e9SAndroid Build Coastguard Worker return true;
1413*d57664e9SAndroid Build Coastguard Worker }
1414*d57664e9SAndroid Build Coastguard Worker clearUidReadTimeouts(storageId);
1415*d57664e9SAndroid Build Coastguard Worker return false;
1416*d57664e9SAndroid Build Coastguard Worker });
1417*d57664e9SAndroid Build Coastguard Worker }
1418*d57664e9SAndroid Build Coastguard Worker
clearUidReadTimeouts(StorageId storage)1419*d57664e9SAndroid Build Coastguard Worker void IncrementalService::clearUidReadTimeouts(StorageId storage) {
1420*d57664e9SAndroid Build Coastguard Worker const auto ifs = getIfs(storage);
1421*d57664e9SAndroid Build Coastguard Worker if (!ifs) {
1422*d57664e9SAndroid Build Coastguard Worker return;
1423*d57664e9SAndroid Build Coastguard Worker }
1424*d57664e9SAndroid Build Coastguard Worker mIncFs->setUidReadTimeouts(ifs->control, {});
1425*d57664e9SAndroid Build Coastguard Worker }
1426*d57664e9SAndroid Build Coastguard Worker
checkUidReadTimeouts(StorageId storage,IfsState state,Clock::time_point timeLimit)1427*d57664e9SAndroid Build Coastguard Worker bool IncrementalService::checkUidReadTimeouts(StorageId storage, IfsState state,
1428*d57664e9SAndroid Build Coastguard Worker Clock::time_point timeLimit) {
1429*d57664e9SAndroid Build Coastguard Worker if (Clock::now() >= timeLimit) {
1430*d57664e9SAndroid Build Coastguard Worker // Reached maximum timeout.
1431*d57664e9SAndroid Build Coastguard Worker return false;
1432*d57664e9SAndroid Build Coastguard Worker }
1433*d57664e9SAndroid Build Coastguard Worker if (state.error) {
1434*d57664e9SAndroid Build Coastguard Worker // Something is wrong, abort.
1435*d57664e9SAndroid Build Coastguard Worker return false;
1436*d57664e9SAndroid Build Coastguard Worker }
1437*d57664e9SAndroid Build Coastguard Worker
1438*d57664e9SAndroid Build Coastguard Worker // Still loading?
1439*d57664e9SAndroid Build Coastguard Worker if (state.fullyLoaded && !state.readLogsEnabled) {
1440*d57664e9SAndroid Build Coastguard Worker return false;
1441*d57664e9SAndroid Build Coastguard Worker }
1442*d57664e9SAndroid Build Coastguard Worker
1443*d57664e9SAndroid Build Coastguard Worker const auto timeLeft = timeLimit - Clock::now();
1444*d57664e9SAndroid Build Coastguard Worker if (timeLeft < Constants::progressUpdateInterval) {
1445*d57664e9SAndroid Build Coastguard Worker // Don't bother.
1446*d57664e9SAndroid Build Coastguard Worker return false;
1447*d57664e9SAndroid Build Coastguard Worker }
1448*d57664e9SAndroid Build Coastguard Worker
1449*d57664e9SAndroid Build Coastguard Worker return true;
1450*d57664e9SAndroid Build Coastguard Worker }
1451*d57664e9SAndroid Build Coastguard Worker
adoptMountedInstances()1452*d57664e9SAndroid Build Coastguard Worker std::unordered_set<std::string_view> IncrementalService::adoptMountedInstances() {
1453*d57664e9SAndroid Build Coastguard Worker std::unordered_set<std::string_view> mountedRootNames;
1454*d57664e9SAndroid Build Coastguard Worker mIncFs->listExistingMounts([this, &mountedRootNames](auto root, auto backingDir, auto binds) {
1455*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "Existing mount: " << backingDir << "->" << root;
1456*d57664e9SAndroid Build Coastguard Worker for (auto [source, target] : binds) {
1457*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << " bind: '" << source << "'->'" << target << "'";
1458*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << " " << path::join(root, source);
1459*d57664e9SAndroid Build Coastguard Worker }
1460*d57664e9SAndroid Build Coastguard Worker
1461*d57664e9SAndroid Build Coastguard Worker // Ensure it's a kind of a mount that's managed by IncrementalService
1462*d57664e9SAndroid Build Coastguard Worker if (path::basename(root) != constants().mount ||
1463*d57664e9SAndroid Build Coastguard Worker path::basename(backingDir) != constants().backing) {
1464*d57664e9SAndroid Build Coastguard Worker return;
1465*d57664e9SAndroid Build Coastguard Worker }
1466*d57664e9SAndroid Build Coastguard Worker const auto expectedRoot = path::dirname(root);
1467*d57664e9SAndroid Build Coastguard Worker if (path::dirname(backingDir) != expectedRoot) {
1468*d57664e9SAndroid Build Coastguard Worker return;
1469*d57664e9SAndroid Build Coastguard Worker }
1470*d57664e9SAndroid Build Coastguard Worker if (path::dirname(expectedRoot) != mIncrementalDir) {
1471*d57664e9SAndroid Build Coastguard Worker return;
1472*d57664e9SAndroid Build Coastguard Worker }
1473*d57664e9SAndroid Build Coastguard Worker if (!path::basename(expectedRoot).starts_with(constants().mountKeyPrefix)) {
1474*d57664e9SAndroid Build Coastguard Worker return;
1475*d57664e9SAndroid Build Coastguard Worker }
1476*d57664e9SAndroid Build Coastguard Worker
1477*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "Looks like an IncrementalService-owned: " << expectedRoot;
1478*d57664e9SAndroid Build Coastguard Worker
1479*d57664e9SAndroid Build Coastguard Worker // make sure we clean up the mount if it happens to be a bad one.
1480*d57664e9SAndroid Build Coastguard Worker // Note: unmounting needs to run first, so the cleanup object is created _last_.
1481*d57664e9SAndroid Build Coastguard Worker auto cleanupFiles = makeCleanup([&]() {
1482*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "Failed to adopt existing mount, deleting files: " << expectedRoot;
1483*d57664e9SAndroid Build Coastguard Worker IncFsMount::cleanupFilesystem(expectedRoot);
1484*d57664e9SAndroid Build Coastguard Worker });
1485*d57664e9SAndroid Build Coastguard Worker auto cleanupMounts = makeCleanup([&]() {
1486*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "Failed to adopt existing mount, cleaning up: " << expectedRoot;
1487*d57664e9SAndroid Build Coastguard Worker for (auto&& [_, target] : binds) {
1488*d57664e9SAndroid Build Coastguard Worker mVold->unmountIncFs(std::string(target));
1489*d57664e9SAndroid Build Coastguard Worker }
1490*d57664e9SAndroid Build Coastguard Worker mVold->unmountIncFs(std::string(root));
1491*d57664e9SAndroid Build Coastguard Worker });
1492*d57664e9SAndroid Build Coastguard Worker
1493*d57664e9SAndroid Build Coastguard Worker auto control = mIncFs->openMount(root);
1494*d57664e9SAndroid Build Coastguard Worker if (!control) {
1495*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "failed to open mount " << root;
1496*d57664e9SAndroid Build Coastguard Worker return;
1497*d57664e9SAndroid Build Coastguard Worker }
1498*d57664e9SAndroid Build Coastguard Worker
1499*d57664e9SAndroid Build Coastguard Worker auto mountRecord =
1500*d57664e9SAndroid Build Coastguard Worker parseFromIncfs<metadata::Mount>(mIncFs.get(), control,
1501*d57664e9SAndroid Build Coastguard Worker path::join(root, constants().infoMdName));
1502*d57664e9SAndroid Build Coastguard Worker if (!mountRecord.has_loader() || !mountRecord.has_storage()) {
1503*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Bad mount metadata in mount at " << expectedRoot;
1504*d57664e9SAndroid Build Coastguard Worker return;
1505*d57664e9SAndroid Build Coastguard Worker }
1506*d57664e9SAndroid Build Coastguard Worker
1507*d57664e9SAndroid Build Coastguard Worker auto mountId = mountRecord.storage().id();
1508*d57664e9SAndroid Build Coastguard Worker mNextId = std::max(mNextId, mountId + 1);
1509*d57664e9SAndroid Build Coastguard Worker
1510*d57664e9SAndroid Build Coastguard Worker DataLoaderParamsParcel dataLoaderParams;
1511*d57664e9SAndroid Build Coastguard Worker {
1512*d57664e9SAndroid Build Coastguard Worker const auto& loader = mountRecord.loader();
1513*d57664e9SAndroid Build Coastguard Worker dataLoaderParams.type = (content::pm::DataLoaderType)loader.type();
1514*d57664e9SAndroid Build Coastguard Worker dataLoaderParams.packageName = loader.package_name();
1515*d57664e9SAndroid Build Coastguard Worker dataLoaderParams.className = loader.class_name();
1516*d57664e9SAndroid Build Coastguard Worker dataLoaderParams.arguments = loader.arguments();
1517*d57664e9SAndroid Build Coastguard Worker }
1518*d57664e9SAndroid Build Coastguard Worker
1519*d57664e9SAndroid Build Coastguard Worker // Not way to obtain a real sysfs key at this point - metrics will stop working after "soft"
1520*d57664e9SAndroid Build Coastguard Worker // reboot.
1521*d57664e9SAndroid Build Coastguard Worker std::string metricsKey{};
1522*d57664e9SAndroid Build Coastguard Worker auto ifs = std::make_shared<IncFsMount>(std::string(expectedRoot), std::move(metricsKey),
1523*d57664e9SAndroid Build Coastguard Worker mountId, std::move(control), *this);
1524*d57664e9SAndroid Build Coastguard Worker (void)cleanupFiles.release(); // ifs will take care of that now
1525*d57664e9SAndroid Build Coastguard Worker
1526*d57664e9SAndroid Build Coastguard Worker // Check if marker file present.
1527*d57664e9SAndroid Build Coastguard Worker if (checkReadLogsDisabledMarker(root)) {
1528*d57664e9SAndroid Build Coastguard Worker ifs->disallowReadLogs();
1529*d57664e9SAndroid Build Coastguard Worker }
1530*d57664e9SAndroid Build Coastguard Worker
1531*d57664e9SAndroid Build Coastguard Worker std::vector<std::pair<std::string, metadata::BindPoint>> permanentBindPoints;
1532*d57664e9SAndroid Build Coastguard Worker auto d = openDir(root);
1533*d57664e9SAndroid Build Coastguard Worker while (auto e = ::readdir(d.get())) {
1534*d57664e9SAndroid Build Coastguard Worker if (e->d_type == DT_REG) {
1535*d57664e9SAndroid Build Coastguard Worker auto name = std::string_view(e->d_name);
1536*d57664e9SAndroid Build Coastguard Worker if (name.starts_with(constants().mountpointMdPrefix)) {
1537*d57664e9SAndroid Build Coastguard Worker permanentBindPoints
1538*d57664e9SAndroid Build Coastguard Worker .emplace_back(name,
1539*d57664e9SAndroid Build Coastguard Worker parseFromIncfs<metadata::BindPoint>(mIncFs.get(),
1540*d57664e9SAndroid Build Coastguard Worker ifs->control,
1541*d57664e9SAndroid Build Coastguard Worker path::join(root,
1542*d57664e9SAndroid Build Coastguard Worker name)));
1543*d57664e9SAndroid Build Coastguard Worker if (permanentBindPoints.back().second.dest_path().empty() ||
1544*d57664e9SAndroid Build Coastguard Worker permanentBindPoints.back().second.source_subdir().empty()) {
1545*d57664e9SAndroid Build Coastguard Worker permanentBindPoints.pop_back();
1546*d57664e9SAndroid Build Coastguard Worker mIncFs->unlink(ifs->control, path::join(root, name));
1547*d57664e9SAndroid Build Coastguard Worker } else {
1548*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "Permanent bind record: '"
1549*d57664e9SAndroid Build Coastguard Worker << permanentBindPoints.back().second.source_subdir() << "'->'"
1550*d57664e9SAndroid Build Coastguard Worker << permanentBindPoints.back().second.dest_path() << "'";
1551*d57664e9SAndroid Build Coastguard Worker }
1552*d57664e9SAndroid Build Coastguard Worker }
1553*d57664e9SAndroid Build Coastguard Worker } else if (e->d_type == DT_DIR) {
1554*d57664e9SAndroid Build Coastguard Worker if (e->d_name == "."sv || e->d_name == ".."sv) {
1555*d57664e9SAndroid Build Coastguard Worker continue;
1556*d57664e9SAndroid Build Coastguard Worker }
1557*d57664e9SAndroid Build Coastguard Worker auto name = std::string_view(e->d_name);
1558*d57664e9SAndroid Build Coastguard Worker if (name.starts_with(constants().storagePrefix)) {
1559*d57664e9SAndroid Build Coastguard Worker int storageId;
1560*d57664e9SAndroid Build Coastguard Worker const auto res =
1561*d57664e9SAndroid Build Coastguard Worker std::from_chars(name.data() + constants().storagePrefix.size() + 1,
1562*d57664e9SAndroid Build Coastguard Worker name.data() + name.size(), storageId);
1563*d57664e9SAndroid Build Coastguard Worker if (res.ec != std::errc{} || *res.ptr != '_') {
1564*d57664e9SAndroid Build Coastguard Worker LOG(WARNING) << "Ignoring storage with invalid name '" << name
1565*d57664e9SAndroid Build Coastguard Worker << "' for mount " << expectedRoot;
1566*d57664e9SAndroid Build Coastguard Worker continue;
1567*d57664e9SAndroid Build Coastguard Worker }
1568*d57664e9SAndroid Build Coastguard Worker auto [_, inserted] = mMounts.try_emplace(storageId, ifs);
1569*d57664e9SAndroid Build Coastguard Worker if (!inserted) {
1570*d57664e9SAndroid Build Coastguard Worker LOG(WARNING) << "Ignoring storage with duplicate id " << storageId
1571*d57664e9SAndroid Build Coastguard Worker << " for mount " << expectedRoot;
1572*d57664e9SAndroid Build Coastguard Worker continue;
1573*d57664e9SAndroid Build Coastguard Worker }
1574*d57664e9SAndroid Build Coastguard Worker ifs->storages.insert_or_assign(storageId,
1575*d57664e9SAndroid Build Coastguard Worker IncFsMount::Storage{path::join(root, name)});
1576*d57664e9SAndroid Build Coastguard Worker mNextId = std::max(mNextId, storageId + 1);
1577*d57664e9SAndroid Build Coastguard Worker }
1578*d57664e9SAndroid Build Coastguard Worker }
1579*d57664e9SAndroid Build Coastguard Worker }
1580*d57664e9SAndroid Build Coastguard Worker
1581*d57664e9SAndroid Build Coastguard Worker if (ifs->storages.empty()) {
1582*d57664e9SAndroid Build Coastguard Worker LOG(WARNING) << "No valid storages in mount " << root;
1583*d57664e9SAndroid Build Coastguard Worker return;
1584*d57664e9SAndroid Build Coastguard Worker }
1585*d57664e9SAndroid Build Coastguard Worker
1586*d57664e9SAndroid Build Coastguard Worker // now match the mounted directories with what we expect to have in the metadata
1587*d57664e9SAndroid Build Coastguard Worker {
1588*d57664e9SAndroid Build Coastguard Worker std::unique_lock l(mLock, std::defer_lock);
1589*d57664e9SAndroid Build Coastguard Worker for (auto&& [metadataFile, bindRecord] : permanentBindPoints) {
1590*d57664e9SAndroid Build Coastguard Worker auto mountedIt = std::find_if(binds.begin(), binds.end(),
1591*d57664e9SAndroid Build Coastguard Worker [&, bindRecord = bindRecord](auto&& bind) {
1592*d57664e9SAndroid Build Coastguard Worker return bind.second == bindRecord.dest_path() &&
1593*d57664e9SAndroid Build Coastguard Worker path::join(root, bind.first) ==
1594*d57664e9SAndroid Build Coastguard Worker bindRecord.source_subdir();
1595*d57664e9SAndroid Build Coastguard Worker });
1596*d57664e9SAndroid Build Coastguard Worker if (mountedIt != binds.end()) {
1597*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "Matched permanent bound " << bindRecord.source_subdir()
1598*d57664e9SAndroid Build Coastguard Worker << " to mount " << mountedIt->first;
1599*d57664e9SAndroid Build Coastguard Worker addBindMountRecordLocked(*ifs, bindRecord.storage_id(), std::move(metadataFile),
1600*d57664e9SAndroid Build Coastguard Worker std::move(*bindRecord.mutable_source_subdir()),
1601*d57664e9SAndroid Build Coastguard Worker std::move(*bindRecord.mutable_dest_path()),
1602*d57664e9SAndroid Build Coastguard Worker BindKind::Permanent);
1603*d57664e9SAndroid Build Coastguard Worker if (mountedIt != binds.end() - 1) {
1604*d57664e9SAndroid Build Coastguard Worker std::iter_swap(mountedIt, binds.end() - 1);
1605*d57664e9SAndroid Build Coastguard Worker }
1606*d57664e9SAndroid Build Coastguard Worker binds = binds.first(binds.size() - 1);
1607*d57664e9SAndroid Build Coastguard Worker } else {
1608*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "Didn't match permanent bound " << bindRecord.source_subdir()
1609*d57664e9SAndroid Build Coastguard Worker << ", mounting";
1610*d57664e9SAndroid Build Coastguard Worker // doesn't exist - try mounting back
1611*d57664e9SAndroid Build Coastguard Worker if (addBindMountWithMd(*ifs, bindRecord.storage_id(), std::move(metadataFile),
1612*d57664e9SAndroid Build Coastguard Worker std::move(*bindRecord.mutable_source_subdir()),
1613*d57664e9SAndroid Build Coastguard Worker std::move(*bindRecord.mutable_dest_path()),
1614*d57664e9SAndroid Build Coastguard Worker BindKind::Permanent, l)) {
1615*d57664e9SAndroid Build Coastguard Worker mIncFs->unlink(ifs->control, metadataFile);
1616*d57664e9SAndroid Build Coastguard Worker }
1617*d57664e9SAndroid Build Coastguard Worker }
1618*d57664e9SAndroid Build Coastguard Worker }
1619*d57664e9SAndroid Build Coastguard Worker }
1620*d57664e9SAndroid Build Coastguard Worker
1621*d57664e9SAndroid Build Coastguard Worker // if anything stays in |binds| those are probably temporary binds; system restarted since
1622*d57664e9SAndroid Build Coastguard Worker // they were mounted - so let's unmount them all.
1623*d57664e9SAndroid Build Coastguard Worker for (auto&& [source, target] : binds) {
1624*d57664e9SAndroid Build Coastguard Worker if (source.empty()) {
1625*d57664e9SAndroid Build Coastguard Worker continue;
1626*d57664e9SAndroid Build Coastguard Worker }
1627*d57664e9SAndroid Build Coastguard Worker mVold->unmountIncFs(std::string(target));
1628*d57664e9SAndroid Build Coastguard Worker }
1629*d57664e9SAndroid Build Coastguard Worker (void)cleanupMounts.release(); // ifs now manages everything
1630*d57664e9SAndroid Build Coastguard Worker
1631*d57664e9SAndroid Build Coastguard Worker if (ifs->bindPoints.empty()) {
1632*d57664e9SAndroid Build Coastguard Worker LOG(WARNING) << "No valid bind points for mount " << expectedRoot;
1633*d57664e9SAndroid Build Coastguard Worker deleteStorage(*ifs);
1634*d57664e9SAndroid Build Coastguard Worker return;
1635*d57664e9SAndroid Build Coastguard Worker }
1636*d57664e9SAndroid Build Coastguard Worker
1637*d57664e9SAndroid Build Coastguard Worker prepareDataLoaderLocked(*ifs, std::move(dataLoaderParams));
1638*d57664e9SAndroid Build Coastguard Worker CHECK(ifs->dataLoaderStub);
1639*d57664e9SAndroid Build Coastguard Worker
1640*d57664e9SAndroid Build Coastguard Worker mountedRootNames.insert(path::basename(ifs->root));
1641*d57664e9SAndroid Build Coastguard Worker
1642*d57664e9SAndroid Build Coastguard Worker // not locking here at all: we're still in the constructor, no other calls can happen
1643*d57664e9SAndroid Build Coastguard Worker mMounts[ifs->mountId] = std::move(ifs);
1644*d57664e9SAndroid Build Coastguard Worker });
1645*d57664e9SAndroid Build Coastguard Worker
1646*d57664e9SAndroid Build Coastguard Worker return mountedRootNames;
1647*d57664e9SAndroid Build Coastguard Worker }
1648*d57664e9SAndroid Build Coastguard Worker
mountExistingImages(const std::unordered_set<std::string_view> & mountedRootNames)1649*d57664e9SAndroid Build Coastguard Worker void IncrementalService::mountExistingImages(
1650*d57664e9SAndroid Build Coastguard Worker const std::unordered_set<std::string_view>& mountedRootNames) {
1651*d57664e9SAndroid Build Coastguard Worker auto dir = openDir(mIncrementalDir);
1652*d57664e9SAndroid Build Coastguard Worker if (!dir) {
1653*d57664e9SAndroid Build Coastguard Worker PLOG(WARNING) << "Couldn't open the root incremental dir " << mIncrementalDir;
1654*d57664e9SAndroid Build Coastguard Worker return;
1655*d57664e9SAndroid Build Coastguard Worker }
1656*d57664e9SAndroid Build Coastguard Worker while (auto entry = ::readdir(dir.get())) {
1657*d57664e9SAndroid Build Coastguard Worker if (entry->d_type != DT_DIR) {
1658*d57664e9SAndroid Build Coastguard Worker continue;
1659*d57664e9SAndroid Build Coastguard Worker }
1660*d57664e9SAndroid Build Coastguard Worker std::string_view name = entry->d_name;
1661*d57664e9SAndroid Build Coastguard Worker if (!name.starts_with(constants().mountKeyPrefix)) {
1662*d57664e9SAndroid Build Coastguard Worker continue;
1663*d57664e9SAndroid Build Coastguard Worker }
1664*d57664e9SAndroid Build Coastguard Worker if (mountedRootNames.find(name) != mountedRootNames.end()) {
1665*d57664e9SAndroid Build Coastguard Worker continue;
1666*d57664e9SAndroid Build Coastguard Worker }
1667*d57664e9SAndroid Build Coastguard Worker const auto root = path::join(mIncrementalDir, name);
1668*d57664e9SAndroid Build Coastguard Worker if (!mountExistingImage(root)) {
1669*d57664e9SAndroid Build Coastguard Worker IncFsMount::cleanupFilesystem(root);
1670*d57664e9SAndroid Build Coastguard Worker }
1671*d57664e9SAndroid Build Coastguard Worker }
1672*d57664e9SAndroid Build Coastguard Worker }
1673*d57664e9SAndroid Build Coastguard Worker
mountExistingImage(std::string_view root)1674*d57664e9SAndroid Build Coastguard Worker bool IncrementalService::mountExistingImage(std::string_view root) {
1675*d57664e9SAndroid Build Coastguard Worker auto mountTarget = path::join(root, constants().mount);
1676*d57664e9SAndroid Build Coastguard Worker const auto backing = path::join(root, constants().backing);
1677*d57664e9SAndroid Build Coastguard Worker std::string mountKey(path::basename(path::dirname(mountTarget)));
1678*d57664e9SAndroid Build Coastguard Worker
1679*d57664e9SAndroid Build Coastguard Worker IncrementalFileSystemControlParcel controlParcel;
1680*d57664e9SAndroid Build Coastguard Worker auto metricsKey = makeUniqueName(mountKey);
1681*d57664e9SAndroid Build Coastguard Worker auto status = mVold->mountIncFs(backing, mountTarget, 0, metricsKey, &controlParcel);
1682*d57664e9SAndroid Build Coastguard Worker if (!status.isOk()) {
1683*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Vold::mountIncFs() failed: " << status.toString8();
1684*d57664e9SAndroid Build Coastguard Worker return false;
1685*d57664e9SAndroid Build Coastguard Worker }
1686*d57664e9SAndroid Build Coastguard Worker
1687*d57664e9SAndroid Build Coastguard Worker int cmd = controlParcel.cmd.release().release();
1688*d57664e9SAndroid Build Coastguard Worker int pendingReads = controlParcel.pendingReads.release().release();
1689*d57664e9SAndroid Build Coastguard Worker int logs = controlParcel.log.release().release();
1690*d57664e9SAndroid Build Coastguard Worker int blocksWritten =
1691*d57664e9SAndroid Build Coastguard Worker controlParcel.blocksWritten ? controlParcel.blocksWritten->release().release() : -1;
1692*d57664e9SAndroid Build Coastguard Worker IncFsMount::Control control = mIncFs->createControl(cmd, pendingReads, logs, blocksWritten);
1693*d57664e9SAndroid Build Coastguard Worker
1694*d57664e9SAndroid Build Coastguard Worker auto ifs = std::make_shared<IncFsMount>(std::string(root), std::move(metricsKey), -1,
1695*d57664e9SAndroid Build Coastguard Worker std::move(control), *this);
1696*d57664e9SAndroid Build Coastguard Worker
1697*d57664e9SAndroid Build Coastguard Worker auto mount = parseFromIncfs<metadata::Mount>(mIncFs.get(), ifs->control,
1698*d57664e9SAndroid Build Coastguard Worker path::join(mountTarget, constants().infoMdName));
1699*d57664e9SAndroid Build Coastguard Worker if (!mount.has_loader() || !mount.has_storage()) {
1700*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Bad mount metadata in mount at " << root;
1701*d57664e9SAndroid Build Coastguard Worker return false;
1702*d57664e9SAndroid Build Coastguard Worker }
1703*d57664e9SAndroid Build Coastguard Worker
1704*d57664e9SAndroid Build Coastguard Worker ifs->mountId = mount.storage().id();
1705*d57664e9SAndroid Build Coastguard Worker mNextId = std::max(mNextId, ifs->mountId + 1);
1706*d57664e9SAndroid Build Coastguard Worker
1707*d57664e9SAndroid Build Coastguard Worker // Check if marker file present.
1708*d57664e9SAndroid Build Coastguard Worker if (checkReadLogsDisabledMarker(mountTarget)) {
1709*d57664e9SAndroid Build Coastguard Worker ifs->disallowReadLogs();
1710*d57664e9SAndroid Build Coastguard Worker }
1711*d57664e9SAndroid Build Coastguard Worker
1712*d57664e9SAndroid Build Coastguard Worker // DataLoader params
1713*d57664e9SAndroid Build Coastguard Worker DataLoaderParamsParcel dataLoaderParams;
1714*d57664e9SAndroid Build Coastguard Worker {
1715*d57664e9SAndroid Build Coastguard Worker const auto& loader = mount.loader();
1716*d57664e9SAndroid Build Coastguard Worker dataLoaderParams.type = (content::pm::DataLoaderType)loader.type();
1717*d57664e9SAndroid Build Coastguard Worker dataLoaderParams.packageName = loader.package_name();
1718*d57664e9SAndroid Build Coastguard Worker dataLoaderParams.className = loader.class_name();
1719*d57664e9SAndroid Build Coastguard Worker dataLoaderParams.arguments = loader.arguments();
1720*d57664e9SAndroid Build Coastguard Worker }
1721*d57664e9SAndroid Build Coastguard Worker
1722*d57664e9SAndroid Build Coastguard Worker prepareDataLoaderLocked(*ifs, std::move(dataLoaderParams));
1723*d57664e9SAndroid Build Coastguard Worker CHECK(ifs->dataLoaderStub);
1724*d57664e9SAndroid Build Coastguard Worker
1725*d57664e9SAndroid Build Coastguard Worker std::vector<std::pair<std::string, metadata::BindPoint>> bindPoints;
1726*d57664e9SAndroid Build Coastguard Worker auto d = openDir(mountTarget);
1727*d57664e9SAndroid Build Coastguard Worker while (auto e = ::readdir(d.get())) {
1728*d57664e9SAndroid Build Coastguard Worker if (e->d_type == DT_REG) {
1729*d57664e9SAndroid Build Coastguard Worker auto name = std::string_view(e->d_name);
1730*d57664e9SAndroid Build Coastguard Worker if (name.starts_with(constants().mountpointMdPrefix)) {
1731*d57664e9SAndroid Build Coastguard Worker bindPoints.emplace_back(name,
1732*d57664e9SAndroid Build Coastguard Worker parseFromIncfs<metadata::BindPoint>(mIncFs.get(),
1733*d57664e9SAndroid Build Coastguard Worker ifs->control,
1734*d57664e9SAndroid Build Coastguard Worker path::join(mountTarget,
1735*d57664e9SAndroid Build Coastguard Worker name)));
1736*d57664e9SAndroid Build Coastguard Worker if (bindPoints.back().second.dest_path().empty() ||
1737*d57664e9SAndroid Build Coastguard Worker bindPoints.back().second.source_subdir().empty()) {
1738*d57664e9SAndroid Build Coastguard Worker bindPoints.pop_back();
1739*d57664e9SAndroid Build Coastguard Worker mIncFs->unlink(ifs->control, path::join(ifs->root, constants().mount, name));
1740*d57664e9SAndroid Build Coastguard Worker }
1741*d57664e9SAndroid Build Coastguard Worker }
1742*d57664e9SAndroid Build Coastguard Worker } else if (e->d_type == DT_DIR) {
1743*d57664e9SAndroid Build Coastguard Worker if (e->d_name == "."sv || e->d_name == ".."sv) {
1744*d57664e9SAndroid Build Coastguard Worker continue;
1745*d57664e9SAndroid Build Coastguard Worker }
1746*d57664e9SAndroid Build Coastguard Worker auto name = std::string_view(e->d_name);
1747*d57664e9SAndroid Build Coastguard Worker if (name.starts_with(constants().storagePrefix)) {
1748*d57664e9SAndroid Build Coastguard Worker int storageId;
1749*d57664e9SAndroid Build Coastguard Worker const auto res = std::from_chars(name.data() + constants().storagePrefix.size() + 1,
1750*d57664e9SAndroid Build Coastguard Worker name.data() + name.size(), storageId);
1751*d57664e9SAndroid Build Coastguard Worker if (res.ec != std::errc{} || *res.ptr != '_') {
1752*d57664e9SAndroid Build Coastguard Worker LOG(WARNING) << "Ignoring storage with invalid name '" << name << "' for mount "
1753*d57664e9SAndroid Build Coastguard Worker << root;
1754*d57664e9SAndroid Build Coastguard Worker continue;
1755*d57664e9SAndroid Build Coastguard Worker }
1756*d57664e9SAndroid Build Coastguard Worker auto [_, inserted] = mMounts.try_emplace(storageId, ifs);
1757*d57664e9SAndroid Build Coastguard Worker if (!inserted) {
1758*d57664e9SAndroid Build Coastguard Worker LOG(WARNING) << "Ignoring storage with duplicate id " << storageId
1759*d57664e9SAndroid Build Coastguard Worker << " for mount " << root;
1760*d57664e9SAndroid Build Coastguard Worker continue;
1761*d57664e9SAndroid Build Coastguard Worker }
1762*d57664e9SAndroid Build Coastguard Worker ifs->storages.insert_or_assign(storageId,
1763*d57664e9SAndroid Build Coastguard Worker IncFsMount::Storage{
1764*d57664e9SAndroid Build Coastguard Worker path::join(root, constants().mount, name)});
1765*d57664e9SAndroid Build Coastguard Worker mNextId = std::max(mNextId, storageId + 1);
1766*d57664e9SAndroid Build Coastguard Worker }
1767*d57664e9SAndroid Build Coastguard Worker }
1768*d57664e9SAndroid Build Coastguard Worker }
1769*d57664e9SAndroid Build Coastguard Worker
1770*d57664e9SAndroid Build Coastguard Worker if (ifs->storages.empty()) {
1771*d57664e9SAndroid Build Coastguard Worker LOG(WARNING) << "No valid storages in mount " << root;
1772*d57664e9SAndroid Build Coastguard Worker return false;
1773*d57664e9SAndroid Build Coastguard Worker }
1774*d57664e9SAndroid Build Coastguard Worker
1775*d57664e9SAndroid Build Coastguard Worker int bindCount = 0;
1776*d57664e9SAndroid Build Coastguard Worker {
1777*d57664e9SAndroid Build Coastguard Worker std::unique_lock l(mLock, std::defer_lock);
1778*d57664e9SAndroid Build Coastguard Worker for (auto&& bp : bindPoints) {
1779*d57664e9SAndroid Build Coastguard Worker bindCount += !addBindMountWithMd(*ifs, bp.second.storage_id(), std::move(bp.first),
1780*d57664e9SAndroid Build Coastguard Worker std::move(*bp.second.mutable_source_subdir()),
1781*d57664e9SAndroid Build Coastguard Worker std::move(*bp.second.mutable_dest_path()),
1782*d57664e9SAndroid Build Coastguard Worker BindKind::Permanent, l);
1783*d57664e9SAndroid Build Coastguard Worker }
1784*d57664e9SAndroid Build Coastguard Worker }
1785*d57664e9SAndroid Build Coastguard Worker
1786*d57664e9SAndroid Build Coastguard Worker if (bindCount == 0) {
1787*d57664e9SAndroid Build Coastguard Worker LOG(WARNING) << "No valid bind points for mount " << root;
1788*d57664e9SAndroid Build Coastguard Worker deleteStorage(*ifs);
1789*d57664e9SAndroid Build Coastguard Worker return false;
1790*d57664e9SAndroid Build Coastguard Worker }
1791*d57664e9SAndroid Build Coastguard Worker
1792*d57664e9SAndroid Build Coastguard Worker // not locking here at all: we're still in the constructor, no other calls can happen
1793*d57664e9SAndroid Build Coastguard Worker mMounts[ifs->mountId] = std::move(ifs);
1794*d57664e9SAndroid Build Coastguard Worker return true;
1795*d57664e9SAndroid Build Coastguard Worker }
1796*d57664e9SAndroid Build Coastguard Worker
runCmdLooper()1797*d57664e9SAndroid Build Coastguard Worker void IncrementalService::runCmdLooper() {
1798*d57664e9SAndroid Build Coastguard Worker constexpr auto kTimeoutMsecs = -1;
1799*d57664e9SAndroid Build Coastguard Worker while (mRunning.load(std::memory_order_relaxed)) {
1800*d57664e9SAndroid Build Coastguard Worker mLooper->pollAll(kTimeoutMsecs);
1801*d57664e9SAndroid Build Coastguard Worker }
1802*d57664e9SAndroid Build Coastguard Worker }
1803*d57664e9SAndroid Build Coastguard Worker
trimReservedSpaceV1(const IncFsMount & ifs)1804*d57664e9SAndroid Build Coastguard Worker void IncrementalService::trimReservedSpaceV1(const IncFsMount& ifs) {
1805*d57664e9SAndroid Build Coastguard Worker mIncFs->forEachFile(ifs.control, [this](auto&& control, auto&& fileId) {
1806*d57664e9SAndroid Build Coastguard Worker if (mIncFs->isFileFullyLoaded(control, fileId) == incfs::LoadingState::Full) {
1807*d57664e9SAndroid Build Coastguard Worker mIncFs->reserveSpace(control, fileId, -1);
1808*d57664e9SAndroid Build Coastguard Worker }
1809*d57664e9SAndroid Build Coastguard Worker return true;
1810*d57664e9SAndroid Build Coastguard Worker });
1811*d57664e9SAndroid Build Coastguard Worker }
1812*d57664e9SAndroid Build Coastguard Worker
prepareDataLoaderLocked(IncFsMount & ifs,DataLoaderParamsParcel && params,DataLoaderStatusListener && statusListener,const StorageHealthCheckParams & healthCheckParams,StorageHealthListener && healthListener)1813*d57664e9SAndroid Build Coastguard Worker void IncrementalService::prepareDataLoaderLocked(IncFsMount& ifs, DataLoaderParamsParcel&& params,
1814*d57664e9SAndroid Build Coastguard Worker DataLoaderStatusListener&& statusListener,
1815*d57664e9SAndroid Build Coastguard Worker const StorageHealthCheckParams& healthCheckParams,
1816*d57664e9SAndroid Build Coastguard Worker StorageHealthListener&& healthListener) {
1817*d57664e9SAndroid Build Coastguard Worker FileSystemControlParcel fsControlParcel;
1818*d57664e9SAndroid Build Coastguard Worker fsControlParcel.incremental = std::make_optional<IncrementalFileSystemControlParcel>();
1819*d57664e9SAndroid Build Coastguard Worker fsControlParcel.incremental->cmd.reset(dup(ifs.control.cmd()));
1820*d57664e9SAndroid Build Coastguard Worker fsControlParcel.incremental->pendingReads.reset(dup(ifs.control.pendingReads()));
1821*d57664e9SAndroid Build Coastguard Worker fsControlParcel.incremental->log.reset(dup(ifs.control.logs()));
1822*d57664e9SAndroid Build Coastguard Worker if (ifs.control.blocksWritten() >= 0) {
1823*d57664e9SAndroid Build Coastguard Worker fsControlParcel.incremental->blocksWritten.emplace(dup(ifs.control.blocksWritten()));
1824*d57664e9SAndroid Build Coastguard Worker }
1825*d57664e9SAndroid Build Coastguard Worker fsControlParcel.service = new IncrementalServiceConnector(*this, ifs.mountId);
1826*d57664e9SAndroid Build Coastguard Worker
1827*d57664e9SAndroid Build Coastguard Worker ifs.dataLoaderStub =
1828*d57664e9SAndroid Build Coastguard Worker new DataLoaderStub(*this, ifs.mountId, std::move(params), std::move(fsControlParcel),
1829*d57664e9SAndroid Build Coastguard Worker std::move(statusListener), healthCheckParams,
1830*d57664e9SAndroid Build Coastguard Worker std::move(healthListener), path::join(ifs.root, constants().mount));
1831*d57664e9SAndroid Build Coastguard Worker
1832*d57664e9SAndroid Build Coastguard Worker // pre-v2 IncFS doesn't do automatic reserved space trimming - need to run it manually
1833*d57664e9SAndroid Build Coastguard Worker if (!(mIncFs->features() & incfs::Features::v2)) {
1834*d57664e9SAndroid Build Coastguard Worker addIfsStateCallback(ifs.mountId, [this](StorageId storageId, IfsState state) -> bool {
1835*d57664e9SAndroid Build Coastguard Worker if (!state.fullyLoaded) {
1836*d57664e9SAndroid Build Coastguard Worker return true;
1837*d57664e9SAndroid Build Coastguard Worker }
1838*d57664e9SAndroid Build Coastguard Worker
1839*d57664e9SAndroid Build Coastguard Worker const auto ifs = getIfs(storageId);
1840*d57664e9SAndroid Build Coastguard Worker if (!ifs) {
1841*d57664e9SAndroid Build Coastguard Worker return false;
1842*d57664e9SAndroid Build Coastguard Worker }
1843*d57664e9SAndroid Build Coastguard Worker trimReservedSpaceV1(*ifs);
1844*d57664e9SAndroid Build Coastguard Worker return false;
1845*d57664e9SAndroid Build Coastguard Worker });
1846*d57664e9SAndroid Build Coastguard Worker }
1847*d57664e9SAndroid Build Coastguard Worker
1848*d57664e9SAndroid Build Coastguard Worker addIfsStateCallback(ifs.mountId, [this](StorageId storageId, IfsState state) -> bool {
1849*d57664e9SAndroid Build Coastguard Worker if (!state.fullyLoaded || state.readLogsEnabled) {
1850*d57664e9SAndroid Build Coastguard Worker return true;
1851*d57664e9SAndroid Build Coastguard Worker }
1852*d57664e9SAndroid Build Coastguard Worker
1853*d57664e9SAndroid Build Coastguard Worker DataLoaderStubPtr dataLoaderStub;
1854*d57664e9SAndroid Build Coastguard Worker {
1855*d57664e9SAndroid Build Coastguard Worker const auto ifs = getIfs(storageId);
1856*d57664e9SAndroid Build Coastguard Worker if (!ifs) {
1857*d57664e9SAndroid Build Coastguard Worker return false;
1858*d57664e9SAndroid Build Coastguard Worker }
1859*d57664e9SAndroid Build Coastguard Worker
1860*d57664e9SAndroid Build Coastguard Worker std::unique_lock l(ifs->lock);
1861*d57664e9SAndroid Build Coastguard Worker dataLoaderStub = std::exchange(ifs->dataLoaderStub, nullptr);
1862*d57664e9SAndroid Build Coastguard Worker }
1863*d57664e9SAndroid Build Coastguard Worker
1864*d57664e9SAndroid Build Coastguard Worker if (dataLoaderStub) {
1865*d57664e9SAndroid Build Coastguard Worker dataLoaderStub->cleanupResources();
1866*d57664e9SAndroid Build Coastguard Worker }
1867*d57664e9SAndroid Build Coastguard Worker
1868*d57664e9SAndroid Build Coastguard Worker return false;
1869*d57664e9SAndroid Build Coastguard Worker });
1870*d57664e9SAndroid Build Coastguard Worker }
1871*d57664e9SAndroid Build Coastguard Worker
1872*d57664e9SAndroid Build Coastguard Worker template <class Duration>
castToMs(Duration d)1873*d57664e9SAndroid Build Coastguard Worker static constexpr auto castToMs(Duration d) {
1874*d57664e9SAndroid Build Coastguard Worker return std::chrono::duration_cast<std::chrono::milliseconds>(d);
1875*d57664e9SAndroid Build Coastguard Worker }
1876*d57664e9SAndroid Build Coastguard Worker
1877*d57664e9SAndroid Build Coastguard Worker // Extract lib files from zip, create new files in incfs and write data to them
1878*d57664e9SAndroid Build Coastguard Worker // Lib files should be placed next to the APK file in the following matter:
1879*d57664e9SAndroid Build Coastguard Worker // Example:
1880*d57664e9SAndroid Build Coastguard Worker // /path/to/base.apk
1881*d57664e9SAndroid Build Coastguard Worker // /path/to/lib/arm/first.so
1882*d57664e9SAndroid Build Coastguard Worker // /path/to/lib/arm/second.so
configureNativeBinaries(StorageId storage,std::string_view apkFullPath,std::string_view libDirRelativePath,std::string_view abi,bool extractNativeLibs)1883*d57664e9SAndroid Build Coastguard Worker bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_view apkFullPath,
1884*d57664e9SAndroid Build Coastguard Worker std::string_view libDirRelativePath,
1885*d57664e9SAndroid Build Coastguard Worker std::string_view abi, bool extractNativeLibs) {
1886*d57664e9SAndroid Build Coastguard Worker auto start = Clock::now();
1887*d57664e9SAndroid Build Coastguard Worker
1888*d57664e9SAndroid Build Coastguard Worker const auto ifs = getIfs(storage);
1889*d57664e9SAndroid Build Coastguard Worker if (!ifs) {
1890*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Invalid storage " << storage;
1891*d57664e9SAndroid Build Coastguard Worker return false;
1892*d57664e9SAndroid Build Coastguard Worker }
1893*d57664e9SAndroid Build Coastguard Worker
1894*d57664e9SAndroid Build Coastguard Worker const auto targetLibPathRelativeToStorage =
1895*d57664e9SAndroid Build Coastguard Worker path::join(path::dirname(normalizePathToStorage(*ifs, storage, apkFullPath)),
1896*d57664e9SAndroid Build Coastguard Worker libDirRelativePath);
1897*d57664e9SAndroid Build Coastguard Worker
1898*d57664e9SAndroid Build Coastguard Worker // First prepare target directories if they don't exist yet
1899*d57664e9SAndroid Build Coastguard Worker if (auto res = makeDirs(*ifs, storage, targetLibPathRelativeToStorage, 0755)) {
1900*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to prepare target lib directory " << targetLibPathRelativeToStorage
1901*d57664e9SAndroid Build Coastguard Worker << " errno: " << res;
1902*d57664e9SAndroid Build Coastguard Worker return false;
1903*d57664e9SAndroid Build Coastguard Worker }
1904*d57664e9SAndroid Build Coastguard Worker
1905*d57664e9SAndroid Build Coastguard Worker auto mkDirsTs = Clock::now();
1906*d57664e9SAndroid Build Coastguard Worker ZipArchiveHandle zipFileHandle;
1907*d57664e9SAndroid Build Coastguard Worker if (OpenArchive(path::c_str(apkFullPath), &zipFileHandle)) {
1908*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to open zip file at " << apkFullPath;
1909*d57664e9SAndroid Build Coastguard Worker return false;
1910*d57664e9SAndroid Build Coastguard Worker }
1911*d57664e9SAndroid Build Coastguard Worker
1912*d57664e9SAndroid Build Coastguard Worker // Need a shared pointer: will be passing it into all unpacking jobs.
1913*d57664e9SAndroid Build Coastguard Worker std::shared_ptr<ZipArchive> zipFile(zipFileHandle, [](ZipArchiveHandle h) { CloseArchive(h); });
1914*d57664e9SAndroid Build Coastguard Worker void* cookie = nullptr;
1915*d57664e9SAndroid Build Coastguard Worker const auto libFilePrefix = path::join(constants().libDir, abi) += "/";
1916*d57664e9SAndroid Build Coastguard Worker if (StartIteration(zipFile.get(), &cookie, libFilePrefix, constants().libSuffix)) {
1917*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to start zip iteration for " << apkFullPath;
1918*d57664e9SAndroid Build Coastguard Worker return false;
1919*d57664e9SAndroid Build Coastguard Worker }
1920*d57664e9SAndroid Build Coastguard Worker auto endIteration = [](void* cookie) { EndIteration(cookie); };
1921*d57664e9SAndroid Build Coastguard Worker auto iterationCleaner = std::unique_ptr<void, decltype(endIteration)>(cookie, endIteration);
1922*d57664e9SAndroid Build Coastguard Worker
1923*d57664e9SAndroid Build Coastguard Worker auto openZipTs = Clock::now();
1924*d57664e9SAndroid Build Coastguard Worker
1925*d57664e9SAndroid Build Coastguard Worker auto mapFiles = (mIncFs->features() & incfs::Features::v2);
1926*d57664e9SAndroid Build Coastguard Worker incfs::FileId sourceId;
1927*d57664e9SAndroid Build Coastguard Worker if (mapFiles) {
1928*d57664e9SAndroid Build Coastguard Worker sourceId = mIncFs->getFileId(ifs->control, apkFullPath);
1929*d57664e9SAndroid Build Coastguard Worker if (!incfs::isValidFileId(sourceId)) {
1930*d57664e9SAndroid Build Coastguard Worker LOG(WARNING) << "Error getting IncFS file ID for apk path '" << apkFullPath
1931*d57664e9SAndroid Build Coastguard Worker << "', mapping disabled";
1932*d57664e9SAndroid Build Coastguard Worker mapFiles = false;
1933*d57664e9SAndroid Build Coastguard Worker }
1934*d57664e9SAndroid Build Coastguard Worker }
1935*d57664e9SAndroid Build Coastguard Worker
1936*d57664e9SAndroid Build Coastguard Worker std::vector<Job> jobQueue;
1937*d57664e9SAndroid Build Coastguard Worker ZipEntry entry;
1938*d57664e9SAndroid Build Coastguard Worker std::string_view fileName;
1939*d57664e9SAndroid Build Coastguard Worker while (!Next(cookie, &entry, &fileName)) {
1940*d57664e9SAndroid Build Coastguard Worker if (fileName.empty()) {
1941*d57664e9SAndroid Build Coastguard Worker continue;
1942*d57664e9SAndroid Build Coastguard Worker }
1943*d57664e9SAndroid Build Coastguard Worker
1944*d57664e9SAndroid Build Coastguard Worker const auto entryUncompressed = entry.method == kCompressStored;
1945*d57664e9SAndroid Build Coastguard Worker const auto entryPageAligned = isPageAligned(entry.offset);
1946*d57664e9SAndroid Build Coastguard Worker
1947*d57664e9SAndroid Build Coastguard Worker if (!extractNativeLibs) {
1948*d57664e9SAndroid Build Coastguard Worker // ensure the file is properly aligned and unpacked
1949*d57664e9SAndroid Build Coastguard Worker if (!entryUncompressed) {
1950*d57664e9SAndroid Build Coastguard Worker LOG(WARNING) << "Library " << fileName << " must be uncompressed to mmap it";
1951*d57664e9SAndroid Build Coastguard Worker return false;
1952*d57664e9SAndroid Build Coastguard Worker }
1953*d57664e9SAndroid Build Coastguard Worker if (!entryPageAligned) {
1954*d57664e9SAndroid Build Coastguard Worker LOG(WARNING) << "Library " << fileName
1955*d57664e9SAndroid Build Coastguard Worker << " must be page-aligned to mmap it, offset = 0x" << std::hex
1956*d57664e9SAndroid Build Coastguard Worker << entry.offset;
1957*d57664e9SAndroid Build Coastguard Worker return false;
1958*d57664e9SAndroid Build Coastguard Worker }
1959*d57664e9SAndroid Build Coastguard Worker continue;
1960*d57664e9SAndroid Build Coastguard Worker }
1961*d57664e9SAndroid Build Coastguard Worker
1962*d57664e9SAndroid Build Coastguard Worker auto startFileTs = Clock::now();
1963*d57664e9SAndroid Build Coastguard Worker
1964*d57664e9SAndroid Build Coastguard Worker const auto libName = path::basename(fileName);
1965*d57664e9SAndroid Build Coastguard Worker auto targetLibPath = path::join(targetLibPathRelativeToStorage, libName);
1966*d57664e9SAndroid Build Coastguard Worker const auto targetLibPathAbsolute = normalizePathToStorage(*ifs, storage, targetLibPath);
1967*d57664e9SAndroid Build Coastguard Worker // If the extract file already exists, skip
1968*d57664e9SAndroid Build Coastguard Worker if (access(targetLibPathAbsolute.c_str(), F_OK) == 0) {
1969*d57664e9SAndroid Build Coastguard Worker if (perfLoggingEnabled()) {
1970*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "incfs: Native lib file already exists: " << targetLibPath
1971*d57664e9SAndroid Build Coastguard Worker << "; skipping extraction, spent "
1972*d57664e9SAndroid Build Coastguard Worker << elapsedMcs(startFileTs, Clock::now()) << "mcs";
1973*d57664e9SAndroid Build Coastguard Worker }
1974*d57664e9SAndroid Build Coastguard Worker continue;
1975*d57664e9SAndroid Build Coastguard Worker }
1976*d57664e9SAndroid Build Coastguard Worker
1977*d57664e9SAndroid Build Coastguard Worker if (mapFiles && entryUncompressed && entryPageAligned && entry.uncompressed_length > 0) {
1978*d57664e9SAndroid Build Coastguard Worker incfs::NewMappedFileParams mappedFileParams = {
1979*d57664e9SAndroid Build Coastguard Worker .sourceId = sourceId,
1980*d57664e9SAndroid Build Coastguard Worker .sourceOffset = entry.offset,
1981*d57664e9SAndroid Build Coastguard Worker .size = entry.uncompressed_length,
1982*d57664e9SAndroid Build Coastguard Worker };
1983*d57664e9SAndroid Build Coastguard Worker
1984*d57664e9SAndroid Build Coastguard Worker if (auto res = mIncFs->makeMappedFile(ifs->control, targetLibPathAbsolute, 0755,
1985*d57664e9SAndroid Build Coastguard Worker mappedFileParams);
1986*d57664e9SAndroid Build Coastguard Worker res == 0) {
1987*d57664e9SAndroid Build Coastguard Worker if (perfLoggingEnabled()) {
1988*d57664e9SAndroid Build Coastguard Worker auto doneTs = Clock::now();
1989*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "incfs: Mapped " << libName << ": "
1990*d57664e9SAndroid Build Coastguard Worker << elapsedMcs(startFileTs, doneTs) << "mcs";
1991*d57664e9SAndroid Build Coastguard Worker }
1992*d57664e9SAndroid Build Coastguard Worker continue;
1993*d57664e9SAndroid Build Coastguard Worker } else {
1994*d57664e9SAndroid Build Coastguard Worker LOG(WARNING) << "Failed to map file for: '" << targetLibPath << "' errno: " << res
1995*d57664e9SAndroid Build Coastguard Worker << "; falling back to full extraction";
1996*d57664e9SAndroid Build Coastguard Worker }
1997*d57664e9SAndroid Build Coastguard Worker }
1998*d57664e9SAndroid Build Coastguard Worker
1999*d57664e9SAndroid Build Coastguard Worker // Create new lib file without signature info
2000*d57664e9SAndroid Build Coastguard Worker incfs::NewFileParams libFileParams = {
2001*d57664e9SAndroid Build Coastguard Worker .size = entry.uncompressed_length,
2002*d57664e9SAndroid Build Coastguard Worker .signature = {},
2003*d57664e9SAndroid Build Coastguard Worker // Metadata of the new lib file is its relative path
2004*d57664e9SAndroid Build Coastguard Worker .metadata = {targetLibPath.c_str(), (IncFsSize)targetLibPath.size()},
2005*d57664e9SAndroid Build Coastguard Worker };
2006*d57664e9SAndroid Build Coastguard Worker incfs::FileId libFileId = idFromMetadata(targetLibPath);
2007*d57664e9SAndroid Build Coastguard Worker if (auto res = mIncFs->makeFile(ifs->control, targetLibPathAbsolute, 0755, libFileId,
2008*d57664e9SAndroid Build Coastguard Worker libFileParams)) {
2009*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to make file for: " << targetLibPath << " errno: " << res;
2010*d57664e9SAndroid Build Coastguard Worker // If one lib file fails to be created, abort others as well
2011*d57664e9SAndroid Build Coastguard Worker return false;
2012*d57664e9SAndroid Build Coastguard Worker }
2013*d57664e9SAndroid Build Coastguard Worker
2014*d57664e9SAndroid Build Coastguard Worker auto makeFileTs = Clock::now();
2015*d57664e9SAndroid Build Coastguard Worker
2016*d57664e9SAndroid Build Coastguard Worker // If it is a zero-byte file, skip data writing
2017*d57664e9SAndroid Build Coastguard Worker if (entry.uncompressed_length == 0) {
2018*d57664e9SAndroid Build Coastguard Worker if (perfLoggingEnabled()) {
2019*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "incfs: Extracted " << libName
2020*d57664e9SAndroid Build Coastguard Worker << "(0 bytes): " << elapsedMcs(startFileTs, makeFileTs) << "mcs";
2021*d57664e9SAndroid Build Coastguard Worker }
2022*d57664e9SAndroid Build Coastguard Worker continue;
2023*d57664e9SAndroid Build Coastguard Worker }
2024*d57664e9SAndroid Build Coastguard Worker
2025*d57664e9SAndroid Build Coastguard Worker jobQueue.emplace_back([this, zipFile, entry, ifs = std::weak_ptr<IncFsMount>(ifs),
2026*d57664e9SAndroid Build Coastguard Worker libFileId, libPath = std::move(targetLibPath),
2027*d57664e9SAndroid Build Coastguard Worker makeFileTs]() mutable {
2028*d57664e9SAndroid Build Coastguard Worker extractZipFile(ifs.lock(), zipFile.get(), entry, libFileId, libPath, makeFileTs);
2029*d57664e9SAndroid Build Coastguard Worker });
2030*d57664e9SAndroid Build Coastguard Worker
2031*d57664e9SAndroid Build Coastguard Worker if (perfLoggingEnabled()) {
2032*d57664e9SAndroid Build Coastguard Worker auto prepareJobTs = Clock::now();
2033*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "incfs: Processed " << libName << ": "
2034*d57664e9SAndroid Build Coastguard Worker << elapsedMcs(startFileTs, prepareJobTs)
2035*d57664e9SAndroid Build Coastguard Worker << "mcs, make file: " << elapsedMcs(startFileTs, makeFileTs)
2036*d57664e9SAndroid Build Coastguard Worker << " prepare job: " << elapsedMcs(makeFileTs, prepareJobTs);
2037*d57664e9SAndroid Build Coastguard Worker }
2038*d57664e9SAndroid Build Coastguard Worker }
2039*d57664e9SAndroid Build Coastguard Worker
2040*d57664e9SAndroid Build Coastguard Worker auto processedTs = Clock::now();
2041*d57664e9SAndroid Build Coastguard Worker
2042*d57664e9SAndroid Build Coastguard Worker if (!jobQueue.empty()) {
2043*d57664e9SAndroid Build Coastguard Worker {
2044*d57664e9SAndroid Build Coastguard Worker std::lock_guard lock(mJobMutex);
2045*d57664e9SAndroid Build Coastguard Worker if (mRunning) {
2046*d57664e9SAndroid Build Coastguard Worker auto& existingJobs = mJobQueue[ifs->mountId];
2047*d57664e9SAndroid Build Coastguard Worker if (existingJobs.empty()) {
2048*d57664e9SAndroid Build Coastguard Worker existingJobs = std::move(jobQueue);
2049*d57664e9SAndroid Build Coastguard Worker } else {
2050*d57664e9SAndroid Build Coastguard Worker existingJobs.insert(existingJobs.end(), std::move_iterator(jobQueue.begin()),
2051*d57664e9SAndroid Build Coastguard Worker std::move_iterator(jobQueue.end()));
2052*d57664e9SAndroid Build Coastguard Worker }
2053*d57664e9SAndroid Build Coastguard Worker }
2054*d57664e9SAndroid Build Coastguard Worker }
2055*d57664e9SAndroid Build Coastguard Worker mJobCondition.notify_all();
2056*d57664e9SAndroid Build Coastguard Worker }
2057*d57664e9SAndroid Build Coastguard Worker
2058*d57664e9SAndroid Build Coastguard Worker if (perfLoggingEnabled()) {
2059*d57664e9SAndroid Build Coastguard Worker auto end = Clock::now();
2060*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "incfs: configureNativeBinaries complete in " << elapsedMcs(start, end)
2061*d57664e9SAndroid Build Coastguard Worker << "mcs, make dirs: " << elapsedMcs(start, mkDirsTs)
2062*d57664e9SAndroid Build Coastguard Worker << " open zip: " << elapsedMcs(mkDirsTs, openZipTs)
2063*d57664e9SAndroid Build Coastguard Worker << " make files: " << elapsedMcs(openZipTs, processedTs)
2064*d57664e9SAndroid Build Coastguard Worker << " schedule jobs: " << elapsedMcs(processedTs, end);
2065*d57664e9SAndroid Build Coastguard Worker }
2066*d57664e9SAndroid Build Coastguard Worker
2067*d57664e9SAndroid Build Coastguard Worker return true;
2068*d57664e9SAndroid Build Coastguard Worker }
2069*d57664e9SAndroid Build Coastguard Worker
extractZipFile(const IfsMountPtr & ifs,ZipArchiveHandle zipFile,ZipEntry & entry,const incfs::FileId & libFileId,std::string_view debugLibPath,Clock::time_point scheduledTs)2070*d57664e9SAndroid Build Coastguard Worker void IncrementalService::extractZipFile(const IfsMountPtr& ifs, ZipArchiveHandle zipFile,
2071*d57664e9SAndroid Build Coastguard Worker ZipEntry& entry, const incfs::FileId& libFileId,
2072*d57664e9SAndroid Build Coastguard Worker std::string_view debugLibPath,
2073*d57664e9SAndroid Build Coastguard Worker Clock::time_point scheduledTs) {
2074*d57664e9SAndroid Build Coastguard Worker if (!ifs) {
2075*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "Skipping zip file " << debugLibPath << " extraction for an expired mount";
2076*d57664e9SAndroid Build Coastguard Worker return;
2077*d57664e9SAndroid Build Coastguard Worker }
2078*d57664e9SAndroid Build Coastguard Worker
2079*d57664e9SAndroid Build Coastguard Worker auto startedTs = Clock::now();
2080*d57664e9SAndroid Build Coastguard Worker
2081*d57664e9SAndroid Build Coastguard Worker // Write extracted data to new file
2082*d57664e9SAndroid Build Coastguard Worker // NOTE: don't zero-initialize memory, it may take a while for nothing
2083*d57664e9SAndroid Build Coastguard Worker auto libData = std::unique_ptr<uint8_t[]>(new uint8_t[entry.uncompressed_length]);
2084*d57664e9SAndroid Build Coastguard Worker if (ExtractToMemory(zipFile, &entry, libData.get(), entry.uncompressed_length)) {
2085*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to extract native lib zip entry: " << path::basename(debugLibPath);
2086*d57664e9SAndroid Build Coastguard Worker return;
2087*d57664e9SAndroid Build Coastguard Worker }
2088*d57664e9SAndroid Build Coastguard Worker
2089*d57664e9SAndroid Build Coastguard Worker auto extractFileTs = Clock::now();
2090*d57664e9SAndroid Build Coastguard Worker
2091*d57664e9SAndroid Build Coastguard Worker if (setFileContent(ifs, libFileId, debugLibPath,
2092*d57664e9SAndroid Build Coastguard Worker std::span(libData.get(), entry.uncompressed_length))) {
2093*d57664e9SAndroid Build Coastguard Worker return;
2094*d57664e9SAndroid Build Coastguard Worker }
2095*d57664e9SAndroid Build Coastguard Worker
2096*d57664e9SAndroid Build Coastguard Worker if (perfLoggingEnabled()) {
2097*d57664e9SAndroid Build Coastguard Worker auto endFileTs = Clock::now();
2098*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "incfs: Extracted " << path::basename(debugLibPath) << "("
2099*d57664e9SAndroid Build Coastguard Worker << entry.compressed_length << " -> " << entry.uncompressed_length
2100*d57664e9SAndroid Build Coastguard Worker << " bytes): " << elapsedMcs(startedTs, endFileTs)
2101*d57664e9SAndroid Build Coastguard Worker << "mcs, scheduling delay: " << elapsedMcs(scheduledTs, startedTs)
2102*d57664e9SAndroid Build Coastguard Worker << " extract: " << elapsedMcs(startedTs, extractFileTs)
2103*d57664e9SAndroid Build Coastguard Worker << " open/prepare/write: " << elapsedMcs(extractFileTs, endFileTs);
2104*d57664e9SAndroid Build Coastguard Worker }
2105*d57664e9SAndroid Build Coastguard Worker }
2106*d57664e9SAndroid Build Coastguard Worker
waitForNativeBinariesExtraction(StorageId storage)2107*d57664e9SAndroid Build Coastguard Worker bool IncrementalService::waitForNativeBinariesExtraction(StorageId storage) {
2108*d57664e9SAndroid Build Coastguard Worker struct WaitPrinter {
2109*d57664e9SAndroid Build Coastguard Worker const Clock::time_point startTs = Clock::now();
2110*d57664e9SAndroid Build Coastguard Worker ~WaitPrinter() noexcept {
2111*d57664e9SAndroid Build Coastguard Worker if (perfLoggingEnabled()) {
2112*d57664e9SAndroid Build Coastguard Worker const auto endTs = Clock::now();
2113*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "incfs: waitForNativeBinariesExtraction() complete in "
2114*d57664e9SAndroid Build Coastguard Worker << elapsedMcs(startTs, endTs) << "mcs";
2115*d57664e9SAndroid Build Coastguard Worker }
2116*d57664e9SAndroid Build Coastguard Worker }
2117*d57664e9SAndroid Build Coastguard Worker } waitPrinter;
2118*d57664e9SAndroid Build Coastguard Worker
2119*d57664e9SAndroid Build Coastguard Worker MountId mount;
2120*d57664e9SAndroid Build Coastguard Worker {
2121*d57664e9SAndroid Build Coastguard Worker auto ifs = getIfs(storage);
2122*d57664e9SAndroid Build Coastguard Worker if (!ifs) {
2123*d57664e9SAndroid Build Coastguard Worker return true;
2124*d57664e9SAndroid Build Coastguard Worker }
2125*d57664e9SAndroid Build Coastguard Worker mount = ifs->mountId;
2126*d57664e9SAndroid Build Coastguard Worker }
2127*d57664e9SAndroid Build Coastguard Worker
2128*d57664e9SAndroid Build Coastguard Worker std::unique_lock lock(mJobMutex);
2129*d57664e9SAndroid Build Coastguard Worker mJobCondition.wait(lock, [this, mount] {
2130*d57664e9SAndroid Build Coastguard Worker return !mRunning ||
2131*d57664e9SAndroid Build Coastguard Worker (mPendingJobsMount != mount && mJobQueue.find(mount) == mJobQueue.end());
2132*d57664e9SAndroid Build Coastguard Worker });
2133*d57664e9SAndroid Build Coastguard Worker return mRunning;
2134*d57664e9SAndroid Build Coastguard Worker }
2135*d57664e9SAndroid Build Coastguard Worker
setFileContent(const IfsMountPtr & ifs,const incfs::FileId & fileId,std::string_view debugFilePath,std::span<const uint8_t> data) const2136*d57664e9SAndroid Build Coastguard Worker int IncrementalService::setFileContent(const IfsMountPtr& ifs, const incfs::FileId& fileId,
2137*d57664e9SAndroid Build Coastguard Worker std::string_view debugFilePath,
2138*d57664e9SAndroid Build Coastguard Worker std::span<const uint8_t> data) const {
2139*d57664e9SAndroid Build Coastguard Worker auto startTs = Clock::now();
2140*d57664e9SAndroid Build Coastguard Worker
2141*d57664e9SAndroid Build Coastguard Worker const auto writeFd = mIncFs->openForSpecialOps(ifs->control, fileId);
2142*d57664e9SAndroid Build Coastguard Worker if (!writeFd.ok()) {
2143*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to open write fd for: " << debugFilePath
2144*d57664e9SAndroid Build Coastguard Worker << " errno: " << writeFd.get();
2145*d57664e9SAndroid Build Coastguard Worker return writeFd.get();
2146*d57664e9SAndroid Build Coastguard Worker }
2147*d57664e9SAndroid Build Coastguard Worker
2148*d57664e9SAndroid Build Coastguard Worker const auto dataLength = data.size();
2149*d57664e9SAndroid Build Coastguard Worker
2150*d57664e9SAndroid Build Coastguard Worker auto openFileTs = Clock::now();
2151*d57664e9SAndroid Build Coastguard Worker const int numBlocks = (data.size() + constants().blockSize - 1) / constants().blockSize;
2152*d57664e9SAndroid Build Coastguard Worker std::vector<IncFsDataBlock> instructions(numBlocks);
2153*d57664e9SAndroid Build Coastguard Worker for (int i = 0; i < numBlocks; i++) {
2154*d57664e9SAndroid Build Coastguard Worker const auto blockSize = std::min<long>(constants().blockSize, data.size());
2155*d57664e9SAndroid Build Coastguard Worker instructions[i] = IncFsDataBlock{
2156*d57664e9SAndroid Build Coastguard Worker .fileFd = writeFd.get(),
2157*d57664e9SAndroid Build Coastguard Worker .pageIndex = static_cast<IncFsBlockIndex>(i),
2158*d57664e9SAndroid Build Coastguard Worker .compression = INCFS_COMPRESSION_KIND_NONE,
2159*d57664e9SAndroid Build Coastguard Worker .kind = INCFS_BLOCK_KIND_DATA,
2160*d57664e9SAndroid Build Coastguard Worker .dataSize = static_cast<uint32_t>(blockSize),
2161*d57664e9SAndroid Build Coastguard Worker .data = reinterpret_cast<const char*>(data.data()),
2162*d57664e9SAndroid Build Coastguard Worker };
2163*d57664e9SAndroid Build Coastguard Worker data = data.subspan(blockSize);
2164*d57664e9SAndroid Build Coastguard Worker }
2165*d57664e9SAndroid Build Coastguard Worker auto prepareInstsTs = Clock::now();
2166*d57664e9SAndroid Build Coastguard Worker
2167*d57664e9SAndroid Build Coastguard Worker size_t res = mIncFs->writeBlocks(instructions);
2168*d57664e9SAndroid Build Coastguard Worker if (res != instructions.size()) {
2169*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to write data into: " << debugFilePath;
2170*d57664e9SAndroid Build Coastguard Worker return res;
2171*d57664e9SAndroid Build Coastguard Worker }
2172*d57664e9SAndroid Build Coastguard Worker
2173*d57664e9SAndroid Build Coastguard Worker if (perfLoggingEnabled()) {
2174*d57664e9SAndroid Build Coastguard Worker auto endTs = Clock::now();
2175*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "incfs: Set file content " << debugFilePath << "(" << dataLength
2176*d57664e9SAndroid Build Coastguard Worker << " bytes): " << elapsedMcs(startTs, endTs)
2177*d57664e9SAndroid Build Coastguard Worker << "mcs, open: " << elapsedMcs(startTs, openFileTs)
2178*d57664e9SAndroid Build Coastguard Worker << " prepare: " << elapsedMcs(openFileTs, prepareInstsTs)
2179*d57664e9SAndroid Build Coastguard Worker << " write: " << elapsedMcs(prepareInstsTs, endTs);
2180*d57664e9SAndroid Build Coastguard Worker }
2181*d57664e9SAndroid Build Coastguard Worker
2182*d57664e9SAndroid Build Coastguard Worker return 0;
2183*d57664e9SAndroid Build Coastguard Worker }
2184*d57664e9SAndroid Build Coastguard Worker
isFileFullyLoaded(StorageId storage,std::string_view filePath) const2185*d57664e9SAndroid Build Coastguard Worker incfs::LoadingState IncrementalService::isFileFullyLoaded(StorageId storage,
2186*d57664e9SAndroid Build Coastguard Worker std::string_view filePath) const {
2187*d57664e9SAndroid Build Coastguard Worker std::unique_lock l(mLock);
2188*d57664e9SAndroid Build Coastguard Worker const auto ifs = getIfsLocked(storage);
2189*d57664e9SAndroid Build Coastguard Worker if (!ifs) {
2190*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "isFileFullyLoaded failed, invalid storageId: " << storage;
2191*d57664e9SAndroid Build Coastguard Worker return incfs::LoadingState(-EINVAL);
2192*d57664e9SAndroid Build Coastguard Worker }
2193*d57664e9SAndroid Build Coastguard Worker const auto storageInfo = ifs->storages.find(storage);
2194*d57664e9SAndroid Build Coastguard Worker if (storageInfo == ifs->storages.end()) {
2195*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "isFileFullyLoaded failed, no storage: " << storage;
2196*d57664e9SAndroid Build Coastguard Worker return incfs::LoadingState(-EINVAL);
2197*d57664e9SAndroid Build Coastguard Worker }
2198*d57664e9SAndroid Build Coastguard Worker l.unlock();
2199*d57664e9SAndroid Build Coastguard Worker return mIncFs->isFileFullyLoaded(ifs->control, filePath);
2200*d57664e9SAndroid Build Coastguard Worker }
2201*d57664e9SAndroid Build Coastguard Worker
isMountFullyLoaded(StorageId storage) const2202*d57664e9SAndroid Build Coastguard Worker incfs::LoadingState IncrementalService::isMountFullyLoaded(StorageId storage) const {
2203*d57664e9SAndroid Build Coastguard Worker const auto ifs = getIfs(storage);
2204*d57664e9SAndroid Build Coastguard Worker if (!ifs) {
2205*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "isMountFullyLoaded failed, invalid storageId: " << storage;
2206*d57664e9SAndroid Build Coastguard Worker return incfs::LoadingState(-EINVAL);
2207*d57664e9SAndroid Build Coastguard Worker }
2208*d57664e9SAndroid Build Coastguard Worker return mIncFs->isEverythingFullyLoaded(ifs->control);
2209*d57664e9SAndroid Build Coastguard Worker }
2210*d57664e9SAndroid Build Coastguard Worker
getLoadingProgress(StorageId storage) const2211*d57664e9SAndroid Build Coastguard Worker IncrementalService::LoadingProgress IncrementalService::getLoadingProgress(
2212*d57664e9SAndroid Build Coastguard Worker StorageId storage) const {
2213*d57664e9SAndroid Build Coastguard Worker std::unique_lock l(mLock);
2214*d57664e9SAndroid Build Coastguard Worker const auto ifs = getIfsLocked(storage);
2215*d57664e9SAndroid Build Coastguard Worker if (!ifs) {
2216*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "getLoadingProgress failed, invalid storageId: " << storage;
2217*d57664e9SAndroid Build Coastguard Worker return {-EINVAL, -EINVAL};
2218*d57664e9SAndroid Build Coastguard Worker }
2219*d57664e9SAndroid Build Coastguard Worker const auto storageInfo = ifs->storages.find(storage);
2220*d57664e9SAndroid Build Coastguard Worker if (storageInfo == ifs->storages.end()) {
2221*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "getLoadingProgress failed, no storage: " << storage;
2222*d57664e9SAndroid Build Coastguard Worker return {-EINVAL, -EINVAL};
2223*d57664e9SAndroid Build Coastguard Worker }
2224*d57664e9SAndroid Build Coastguard Worker l.unlock();
2225*d57664e9SAndroid Build Coastguard Worker return getLoadingProgressFromPath(*ifs, storageInfo->second.name);
2226*d57664e9SAndroid Build Coastguard Worker }
2227*d57664e9SAndroid Build Coastguard Worker
getLoadingProgressFromPath(const IncFsMount & ifs,std::string_view storagePath) const2228*d57664e9SAndroid Build Coastguard Worker IncrementalService::LoadingProgress IncrementalService::getLoadingProgressFromPath(
2229*d57664e9SAndroid Build Coastguard Worker const IncFsMount& ifs, std::string_view storagePath) const {
2230*d57664e9SAndroid Build Coastguard Worker ssize_t totalBlocks = 0, filledBlocks = 0, error = 0;
2231*d57664e9SAndroid Build Coastguard Worker mFs->listFilesRecursive(storagePath, [&, this](auto filePath) {
2232*d57664e9SAndroid Build Coastguard Worker const auto [filledBlocksCount, totalBlocksCount] =
2233*d57664e9SAndroid Build Coastguard Worker mIncFs->countFilledBlocks(ifs.control, filePath);
2234*d57664e9SAndroid Build Coastguard Worker if (filledBlocksCount == -EOPNOTSUPP || filledBlocksCount == -ENOTSUP ||
2235*d57664e9SAndroid Build Coastguard Worker filledBlocksCount == -ENOENT) {
2236*d57664e9SAndroid Build Coastguard Worker // a kind of a file that's not really being loaded, e.g. a mapped range
2237*d57664e9SAndroid Build Coastguard Worker // an older IncFS used to return ENOENT in this case, so handle it the same way
2238*d57664e9SAndroid Build Coastguard Worker return true;
2239*d57664e9SAndroid Build Coastguard Worker }
2240*d57664e9SAndroid Build Coastguard Worker if (filledBlocksCount < 0) {
2241*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "getLoadingProgress failed to get filled blocks count for: " << filePath
2242*d57664e9SAndroid Build Coastguard Worker << ", errno: " << filledBlocksCount;
2243*d57664e9SAndroid Build Coastguard Worker error = filledBlocksCount;
2244*d57664e9SAndroid Build Coastguard Worker return false;
2245*d57664e9SAndroid Build Coastguard Worker }
2246*d57664e9SAndroid Build Coastguard Worker totalBlocks += totalBlocksCount;
2247*d57664e9SAndroid Build Coastguard Worker filledBlocks += filledBlocksCount;
2248*d57664e9SAndroid Build Coastguard Worker return true;
2249*d57664e9SAndroid Build Coastguard Worker });
2250*d57664e9SAndroid Build Coastguard Worker
2251*d57664e9SAndroid Build Coastguard Worker return error ? LoadingProgress{error, error} : LoadingProgress{filledBlocks, totalBlocks};
2252*d57664e9SAndroid Build Coastguard Worker }
2253*d57664e9SAndroid Build Coastguard Worker
updateLoadingProgress(StorageId storage,StorageLoadingProgressListener && progressListener)2254*d57664e9SAndroid Build Coastguard Worker bool IncrementalService::updateLoadingProgress(StorageId storage,
2255*d57664e9SAndroid Build Coastguard Worker StorageLoadingProgressListener&& progressListener) {
2256*d57664e9SAndroid Build Coastguard Worker const auto progress = getLoadingProgress(storage);
2257*d57664e9SAndroid Build Coastguard Worker if (progress.isError()) {
2258*d57664e9SAndroid Build Coastguard Worker // Failed to get progress from incfs, abort.
2259*d57664e9SAndroid Build Coastguard Worker return false;
2260*d57664e9SAndroid Build Coastguard Worker }
2261*d57664e9SAndroid Build Coastguard Worker progressListener->onStorageLoadingProgressChanged(storage, progress.getProgress());
2262*d57664e9SAndroid Build Coastguard Worker if (progress.fullyLoaded()) {
2263*d57664e9SAndroid Build Coastguard Worker // Stop updating progress once it is fully loaded
2264*d57664e9SAndroid Build Coastguard Worker return true;
2265*d57664e9SAndroid Build Coastguard Worker }
2266*d57664e9SAndroid Build Coastguard Worker addTimedJob(*mProgressUpdateJobQueue, storage,
2267*d57664e9SAndroid Build Coastguard Worker Constants::progressUpdateInterval /* repeat after 1s */,
2268*d57664e9SAndroid Build Coastguard Worker [storage, progressListener = std::move(progressListener), this]() mutable {
2269*d57664e9SAndroid Build Coastguard Worker updateLoadingProgress(storage, std::move(progressListener));
2270*d57664e9SAndroid Build Coastguard Worker });
2271*d57664e9SAndroid Build Coastguard Worker return true;
2272*d57664e9SAndroid Build Coastguard Worker }
2273*d57664e9SAndroid Build Coastguard Worker
registerLoadingProgressListener(StorageId storage,StorageLoadingProgressListener progressListener)2274*d57664e9SAndroid Build Coastguard Worker bool IncrementalService::registerLoadingProgressListener(
2275*d57664e9SAndroid Build Coastguard Worker StorageId storage, StorageLoadingProgressListener progressListener) {
2276*d57664e9SAndroid Build Coastguard Worker return updateLoadingProgress(storage, std::move(progressListener));
2277*d57664e9SAndroid Build Coastguard Worker }
2278*d57664e9SAndroid Build Coastguard Worker
unregisterLoadingProgressListener(StorageId storage)2279*d57664e9SAndroid Build Coastguard Worker bool IncrementalService::unregisterLoadingProgressListener(StorageId storage) {
2280*d57664e9SAndroid Build Coastguard Worker return removeTimedJobs(*mProgressUpdateJobQueue, storage);
2281*d57664e9SAndroid Build Coastguard Worker }
2282*d57664e9SAndroid Build Coastguard Worker
perfLoggingEnabled()2283*d57664e9SAndroid Build Coastguard Worker bool IncrementalService::perfLoggingEnabled() {
2284*d57664e9SAndroid Build Coastguard Worker static const bool enabled = base::GetBoolProperty("incremental.perflogging", false);
2285*d57664e9SAndroid Build Coastguard Worker return enabled;
2286*d57664e9SAndroid Build Coastguard Worker }
2287*d57664e9SAndroid Build Coastguard Worker
runJobProcessing()2288*d57664e9SAndroid Build Coastguard Worker void IncrementalService::runJobProcessing() {
2289*d57664e9SAndroid Build Coastguard Worker for (;;) {
2290*d57664e9SAndroid Build Coastguard Worker std::unique_lock lock(mJobMutex);
2291*d57664e9SAndroid Build Coastguard Worker mJobCondition.wait(lock, [this]() { return !mRunning || !mJobQueue.empty(); });
2292*d57664e9SAndroid Build Coastguard Worker if (!mRunning) {
2293*d57664e9SAndroid Build Coastguard Worker return;
2294*d57664e9SAndroid Build Coastguard Worker }
2295*d57664e9SAndroid Build Coastguard Worker
2296*d57664e9SAndroid Build Coastguard Worker auto it = mJobQueue.begin();
2297*d57664e9SAndroid Build Coastguard Worker mPendingJobsMount = it->first;
2298*d57664e9SAndroid Build Coastguard Worker auto queue = std::move(it->second);
2299*d57664e9SAndroid Build Coastguard Worker mJobQueue.erase(it);
2300*d57664e9SAndroid Build Coastguard Worker lock.unlock();
2301*d57664e9SAndroid Build Coastguard Worker
2302*d57664e9SAndroid Build Coastguard Worker for (auto&& job : queue) {
2303*d57664e9SAndroid Build Coastguard Worker job();
2304*d57664e9SAndroid Build Coastguard Worker }
2305*d57664e9SAndroid Build Coastguard Worker
2306*d57664e9SAndroid Build Coastguard Worker lock.lock();
2307*d57664e9SAndroid Build Coastguard Worker mPendingJobsMount = kInvalidStorageId;
2308*d57664e9SAndroid Build Coastguard Worker lock.unlock();
2309*d57664e9SAndroid Build Coastguard Worker mJobCondition.notify_all();
2310*d57664e9SAndroid Build Coastguard Worker }
2311*d57664e9SAndroid Build Coastguard Worker }
2312*d57664e9SAndroid Build Coastguard Worker
registerAppOpsCallback(const std::string & packageName)2313*d57664e9SAndroid Build Coastguard Worker void IncrementalService::registerAppOpsCallback(const std::string& packageName) {
2314*d57664e9SAndroid Build Coastguard Worker sp<IAppOpsCallback> listener;
2315*d57664e9SAndroid Build Coastguard Worker {
2316*d57664e9SAndroid Build Coastguard Worker std::unique_lock lock{mCallbacksLock};
2317*d57664e9SAndroid Build Coastguard Worker auto& cb = mCallbackRegistered[packageName];
2318*d57664e9SAndroid Build Coastguard Worker if (cb) {
2319*d57664e9SAndroid Build Coastguard Worker return;
2320*d57664e9SAndroid Build Coastguard Worker }
2321*d57664e9SAndroid Build Coastguard Worker cb = new AppOpsListener(*this, packageName);
2322*d57664e9SAndroid Build Coastguard Worker listener = cb;
2323*d57664e9SAndroid Build Coastguard Worker }
2324*d57664e9SAndroid Build Coastguard Worker
2325*d57664e9SAndroid Build Coastguard Worker mAppOpsManager->startWatchingMode(AppOpsManager::OP_GET_USAGE_STATS,
2326*d57664e9SAndroid Build Coastguard Worker String16(packageName.c_str()), listener);
2327*d57664e9SAndroid Build Coastguard Worker }
2328*d57664e9SAndroid Build Coastguard Worker
unregisterAppOpsCallback(const std::string & packageName)2329*d57664e9SAndroid Build Coastguard Worker bool IncrementalService::unregisterAppOpsCallback(const std::string& packageName) {
2330*d57664e9SAndroid Build Coastguard Worker sp<IAppOpsCallback> listener;
2331*d57664e9SAndroid Build Coastguard Worker {
2332*d57664e9SAndroid Build Coastguard Worker std::unique_lock lock{mCallbacksLock};
2333*d57664e9SAndroid Build Coastguard Worker auto found = mCallbackRegistered.find(packageName);
2334*d57664e9SAndroid Build Coastguard Worker if (found == mCallbackRegistered.end()) {
2335*d57664e9SAndroid Build Coastguard Worker return false;
2336*d57664e9SAndroid Build Coastguard Worker }
2337*d57664e9SAndroid Build Coastguard Worker listener = found->second;
2338*d57664e9SAndroid Build Coastguard Worker mCallbackRegistered.erase(found);
2339*d57664e9SAndroid Build Coastguard Worker }
2340*d57664e9SAndroid Build Coastguard Worker
2341*d57664e9SAndroid Build Coastguard Worker mAppOpsManager->stopWatchingMode(listener);
2342*d57664e9SAndroid Build Coastguard Worker return true;
2343*d57664e9SAndroid Build Coastguard Worker }
2344*d57664e9SAndroid Build Coastguard Worker
onAppOpChanged(const std::string & packageName)2345*d57664e9SAndroid Build Coastguard Worker void IncrementalService::onAppOpChanged(const std::string& packageName) {
2346*d57664e9SAndroid Build Coastguard Worker if (!unregisterAppOpsCallback(packageName)) {
2347*d57664e9SAndroid Build Coastguard Worker return;
2348*d57664e9SAndroid Build Coastguard Worker }
2349*d57664e9SAndroid Build Coastguard Worker
2350*d57664e9SAndroid Build Coastguard Worker std::vector<IfsMountPtr> affected;
2351*d57664e9SAndroid Build Coastguard Worker {
2352*d57664e9SAndroid Build Coastguard Worker std::lock_guard l(mLock);
2353*d57664e9SAndroid Build Coastguard Worker affected.reserve(mMounts.size());
2354*d57664e9SAndroid Build Coastguard Worker for (auto&& [id, ifs] : mMounts) {
2355*d57664e9SAndroid Build Coastguard Worker std::unique_lock ll(ifs->lock);
2356*d57664e9SAndroid Build Coastguard Worker if (ifs->mountId == id && ifs->dataLoaderStub &&
2357*d57664e9SAndroid Build Coastguard Worker ifs->dataLoaderStub->params().packageName == packageName) {
2358*d57664e9SAndroid Build Coastguard Worker affected.push_back(ifs);
2359*d57664e9SAndroid Build Coastguard Worker }
2360*d57664e9SAndroid Build Coastguard Worker }
2361*d57664e9SAndroid Build Coastguard Worker }
2362*d57664e9SAndroid Build Coastguard Worker for (auto&& ifs : affected) {
2363*d57664e9SAndroid Build Coastguard Worker std::unique_lock ll(ifs->lock);
2364*d57664e9SAndroid Build Coastguard Worker disableReadLogsLocked(*ifs);
2365*d57664e9SAndroid Build Coastguard Worker }
2366*d57664e9SAndroid Build Coastguard Worker }
2367*d57664e9SAndroid Build Coastguard Worker
addTimedJob(TimedQueueWrapper & timedQueue,MountId id,Milliseconds after,Job what)2368*d57664e9SAndroid Build Coastguard Worker bool IncrementalService::addTimedJob(TimedQueueWrapper& timedQueue, MountId id, Milliseconds after,
2369*d57664e9SAndroid Build Coastguard Worker Job what) {
2370*d57664e9SAndroid Build Coastguard Worker if (id == kInvalidStorageId) {
2371*d57664e9SAndroid Build Coastguard Worker return false;
2372*d57664e9SAndroid Build Coastguard Worker }
2373*d57664e9SAndroid Build Coastguard Worker timedQueue.addJob(id, after, std::move(what));
2374*d57664e9SAndroid Build Coastguard Worker return true;
2375*d57664e9SAndroid Build Coastguard Worker }
2376*d57664e9SAndroid Build Coastguard Worker
removeTimedJobs(TimedQueueWrapper & timedQueue,MountId id)2377*d57664e9SAndroid Build Coastguard Worker bool IncrementalService::removeTimedJobs(TimedQueueWrapper& timedQueue, MountId id) {
2378*d57664e9SAndroid Build Coastguard Worker if (id == kInvalidStorageId) {
2379*d57664e9SAndroid Build Coastguard Worker return false;
2380*d57664e9SAndroid Build Coastguard Worker }
2381*d57664e9SAndroid Build Coastguard Worker timedQueue.removeJobs(id);
2382*d57664e9SAndroid Build Coastguard Worker return true;
2383*d57664e9SAndroid Build Coastguard Worker }
2384*d57664e9SAndroid Build Coastguard Worker
addIfsStateCallback(StorageId storageId,IfsStateCallback callback)2385*d57664e9SAndroid Build Coastguard Worker void IncrementalService::addIfsStateCallback(StorageId storageId, IfsStateCallback callback) {
2386*d57664e9SAndroid Build Coastguard Worker bool wasEmpty;
2387*d57664e9SAndroid Build Coastguard Worker {
2388*d57664e9SAndroid Build Coastguard Worker std::lock_guard l(mIfsStateCallbacksLock);
2389*d57664e9SAndroid Build Coastguard Worker wasEmpty = mIfsStateCallbacks.empty();
2390*d57664e9SAndroid Build Coastguard Worker mIfsStateCallbacks[storageId].emplace_back(std::move(callback));
2391*d57664e9SAndroid Build Coastguard Worker }
2392*d57664e9SAndroid Build Coastguard Worker if (wasEmpty) {
2393*d57664e9SAndroid Build Coastguard Worker addTimedJob(*mTimedQueue, kAllStoragesId, Constants::progressUpdateInterval,
2394*d57664e9SAndroid Build Coastguard Worker [this]() { processIfsStateCallbacks(); });
2395*d57664e9SAndroid Build Coastguard Worker }
2396*d57664e9SAndroid Build Coastguard Worker }
2397*d57664e9SAndroid Build Coastguard Worker
processIfsStateCallbacks()2398*d57664e9SAndroid Build Coastguard Worker void IncrementalService::processIfsStateCallbacks() {
2399*d57664e9SAndroid Build Coastguard Worker StorageId storageId = kInvalidStorageId;
2400*d57664e9SAndroid Build Coastguard Worker std::vector<IfsStateCallback> local;
2401*d57664e9SAndroid Build Coastguard Worker while (true) {
2402*d57664e9SAndroid Build Coastguard Worker {
2403*d57664e9SAndroid Build Coastguard Worker std::lock_guard l(mIfsStateCallbacksLock);
2404*d57664e9SAndroid Build Coastguard Worker if (mIfsStateCallbacks.empty()) {
2405*d57664e9SAndroid Build Coastguard Worker return;
2406*d57664e9SAndroid Build Coastguard Worker }
2407*d57664e9SAndroid Build Coastguard Worker IfsStateCallbacks::iterator it;
2408*d57664e9SAndroid Build Coastguard Worker if (storageId == kInvalidStorageId) {
2409*d57664e9SAndroid Build Coastguard Worker // First entry, initialize the |it|.
2410*d57664e9SAndroid Build Coastguard Worker it = mIfsStateCallbacks.begin();
2411*d57664e9SAndroid Build Coastguard Worker } else {
2412*d57664e9SAndroid Build Coastguard Worker // Subsequent entries, update the |storageId|, and shift to the new one (not that
2413*d57664e9SAndroid Build Coastguard Worker // it guarantees much about updated items, but at least the loop will finish).
2414*d57664e9SAndroid Build Coastguard Worker it = mIfsStateCallbacks.lower_bound(storageId);
2415*d57664e9SAndroid Build Coastguard Worker if (it == mIfsStateCallbacks.end()) {
2416*d57664e9SAndroid Build Coastguard Worker // Nothing else left, too bad.
2417*d57664e9SAndroid Build Coastguard Worker break;
2418*d57664e9SAndroid Build Coastguard Worker }
2419*d57664e9SAndroid Build Coastguard Worker if (it->first != storageId) {
2420*d57664e9SAndroid Build Coastguard Worker local.clear(); // Was removed during processing, forget the old callbacks.
2421*d57664e9SAndroid Build Coastguard Worker } else {
2422*d57664e9SAndroid Build Coastguard Worker // Put the 'surviving' callbacks back into the map and advance the position.
2423*d57664e9SAndroid Build Coastguard Worker auto& callbacks = it->second;
2424*d57664e9SAndroid Build Coastguard Worker if (callbacks.empty()) {
2425*d57664e9SAndroid Build Coastguard Worker std::swap(callbacks, local);
2426*d57664e9SAndroid Build Coastguard Worker } else {
2427*d57664e9SAndroid Build Coastguard Worker callbacks.insert(callbacks.end(), std::move_iterator(local.begin()),
2428*d57664e9SAndroid Build Coastguard Worker std::move_iterator(local.end()));
2429*d57664e9SAndroid Build Coastguard Worker local.clear();
2430*d57664e9SAndroid Build Coastguard Worker }
2431*d57664e9SAndroid Build Coastguard Worker if (callbacks.empty()) {
2432*d57664e9SAndroid Build Coastguard Worker it = mIfsStateCallbacks.erase(it);
2433*d57664e9SAndroid Build Coastguard Worker if (mIfsStateCallbacks.empty()) {
2434*d57664e9SAndroid Build Coastguard Worker return;
2435*d57664e9SAndroid Build Coastguard Worker }
2436*d57664e9SAndroid Build Coastguard Worker } else {
2437*d57664e9SAndroid Build Coastguard Worker ++it;
2438*d57664e9SAndroid Build Coastguard Worker }
2439*d57664e9SAndroid Build Coastguard Worker }
2440*d57664e9SAndroid Build Coastguard Worker }
2441*d57664e9SAndroid Build Coastguard Worker
2442*d57664e9SAndroid Build Coastguard Worker if (it == mIfsStateCallbacks.end()) {
2443*d57664e9SAndroid Build Coastguard Worker break;
2444*d57664e9SAndroid Build Coastguard Worker }
2445*d57664e9SAndroid Build Coastguard Worker
2446*d57664e9SAndroid Build Coastguard Worker storageId = it->first;
2447*d57664e9SAndroid Build Coastguard Worker auto& callbacks = it->second;
2448*d57664e9SAndroid Build Coastguard Worker if (callbacks.empty()) {
2449*d57664e9SAndroid Build Coastguard Worker // Invalid case, one extra lookup should be ok.
2450*d57664e9SAndroid Build Coastguard Worker continue;
2451*d57664e9SAndroid Build Coastguard Worker }
2452*d57664e9SAndroid Build Coastguard Worker std::swap(callbacks, local);
2453*d57664e9SAndroid Build Coastguard Worker }
2454*d57664e9SAndroid Build Coastguard Worker
2455*d57664e9SAndroid Build Coastguard Worker processIfsStateCallbacks(storageId, local);
2456*d57664e9SAndroid Build Coastguard Worker }
2457*d57664e9SAndroid Build Coastguard Worker
2458*d57664e9SAndroid Build Coastguard Worker addTimedJob(*mTimedQueue, kAllStoragesId, Constants::progressUpdateInterval,
2459*d57664e9SAndroid Build Coastguard Worker [this]() { processIfsStateCallbacks(); });
2460*d57664e9SAndroid Build Coastguard Worker }
2461*d57664e9SAndroid Build Coastguard Worker
processIfsStateCallbacks(StorageId storageId,std::vector<IfsStateCallback> & callbacks)2462*d57664e9SAndroid Build Coastguard Worker void IncrementalService::processIfsStateCallbacks(StorageId storageId,
2463*d57664e9SAndroid Build Coastguard Worker std::vector<IfsStateCallback>& callbacks) {
2464*d57664e9SAndroid Build Coastguard Worker const auto state = isMountFullyLoaded(storageId);
2465*d57664e9SAndroid Build Coastguard Worker IfsState storageState = {};
2466*d57664e9SAndroid Build Coastguard Worker storageState.error = int(state) < 0;
2467*d57664e9SAndroid Build Coastguard Worker storageState.fullyLoaded = state == incfs::LoadingState::Full;
2468*d57664e9SAndroid Build Coastguard Worker if (storageState.fullyLoaded) {
2469*d57664e9SAndroid Build Coastguard Worker const auto ifs = getIfs(storageId);
2470*d57664e9SAndroid Build Coastguard Worker storageState.readLogsEnabled = ifs && ifs->readLogsEnabled();
2471*d57664e9SAndroid Build Coastguard Worker }
2472*d57664e9SAndroid Build Coastguard Worker
2473*d57664e9SAndroid Build Coastguard Worker for (auto cur = callbacks.begin(); cur != callbacks.end();) {
2474*d57664e9SAndroid Build Coastguard Worker if ((*cur)(storageId, storageState)) {
2475*d57664e9SAndroid Build Coastguard Worker ++cur;
2476*d57664e9SAndroid Build Coastguard Worker } else {
2477*d57664e9SAndroid Build Coastguard Worker cur = callbacks.erase(cur);
2478*d57664e9SAndroid Build Coastguard Worker }
2479*d57664e9SAndroid Build Coastguard Worker }
2480*d57664e9SAndroid Build Coastguard Worker }
2481*d57664e9SAndroid Build Coastguard Worker
removeIfsStateCallbacks(StorageId storageId)2482*d57664e9SAndroid Build Coastguard Worker void IncrementalService::removeIfsStateCallbacks(StorageId storageId) {
2483*d57664e9SAndroid Build Coastguard Worker std::lock_guard l(mIfsStateCallbacksLock);
2484*d57664e9SAndroid Build Coastguard Worker mIfsStateCallbacks.erase(storageId);
2485*d57664e9SAndroid Build Coastguard Worker }
2486*d57664e9SAndroid Build Coastguard Worker
getMetrics(StorageId storageId,android::os::PersistableBundle * result)2487*d57664e9SAndroid Build Coastguard Worker void IncrementalService::getMetrics(StorageId storageId, android::os::PersistableBundle* result) {
2488*d57664e9SAndroid Build Coastguard Worker const auto ifs = getIfs(storageId);
2489*d57664e9SAndroid Build Coastguard Worker if (!ifs) {
2490*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "getMetrics failed, invalid storageId: " << storageId;
2491*d57664e9SAndroid Build Coastguard Worker return;
2492*d57664e9SAndroid Build Coastguard Worker }
2493*d57664e9SAndroid Build Coastguard Worker const auto& kMetricsReadLogsEnabled =
2494*d57664e9SAndroid Build Coastguard Worker os::incremental::BnIncrementalService::METRICS_READ_LOGS_ENABLED();
2495*d57664e9SAndroid Build Coastguard Worker result->putBoolean(String16(kMetricsReadLogsEnabled.c_str()), ifs->readLogsEnabled() != 0);
2496*d57664e9SAndroid Build Coastguard Worker const auto incfsMetrics = mIncFs->getMetrics(ifs->metricsKey);
2497*d57664e9SAndroid Build Coastguard Worker if (incfsMetrics) {
2498*d57664e9SAndroid Build Coastguard Worker const auto& kMetricsTotalDelayedReads =
2499*d57664e9SAndroid Build Coastguard Worker os::incremental::BnIncrementalService::METRICS_TOTAL_DELAYED_READS();
2500*d57664e9SAndroid Build Coastguard Worker const auto totalDelayedReads =
2501*d57664e9SAndroid Build Coastguard Worker incfsMetrics->readsDelayedMin + incfsMetrics->readsDelayedPending;
2502*d57664e9SAndroid Build Coastguard Worker result->putInt(String16(kMetricsTotalDelayedReads.c_str()), totalDelayedReads);
2503*d57664e9SAndroid Build Coastguard Worker const auto& kMetricsTotalFailedReads =
2504*d57664e9SAndroid Build Coastguard Worker os::incremental::BnIncrementalService::METRICS_TOTAL_FAILED_READS();
2505*d57664e9SAndroid Build Coastguard Worker const auto totalFailedReads = incfsMetrics->readsFailedTimedOut +
2506*d57664e9SAndroid Build Coastguard Worker incfsMetrics->readsFailedHashVerification + incfsMetrics->readsFailedOther;
2507*d57664e9SAndroid Build Coastguard Worker result->putInt(String16(kMetricsTotalFailedReads.c_str()), totalFailedReads);
2508*d57664e9SAndroid Build Coastguard Worker const auto& kMetricsTotalDelayedReadsMillis =
2509*d57664e9SAndroid Build Coastguard Worker os::incremental::BnIncrementalService::METRICS_TOTAL_DELAYED_READS_MILLIS();
2510*d57664e9SAndroid Build Coastguard Worker const int64_t totalDelayedReadsMillis =
2511*d57664e9SAndroid Build Coastguard Worker (incfsMetrics->readsDelayedMinUs + incfsMetrics->readsDelayedPendingUs) / 1000;
2512*d57664e9SAndroid Build Coastguard Worker result->putLong(String16(kMetricsTotalDelayedReadsMillis.c_str()), totalDelayedReadsMillis);
2513*d57664e9SAndroid Build Coastguard Worker }
2514*d57664e9SAndroid Build Coastguard Worker const auto lastReadError = mIncFs->getLastReadError(ifs->control);
2515*d57664e9SAndroid Build Coastguard Worker if (lastReadError && lastReadError->timestampUs != 0) {
2516*d57664e9SAndroid Build Coastguard Worker const auto& kMetricsMillisSinceLastReadError =
2517*d57664e9SAndroid Build Coastguard Worker os::incremental::BnIncrementalService::METRICS_MILLIS_SINCE_LAST_READ_ERROR();
2518*d57664e9SAndroid Build Coastguard Worker result->putLong(String16(kMetricsMillisSinceLastReadError.c_str()),
2519*d57664e9SAndroid Build Coastguard Worker (int64_t)elapsedUsSinceMonoTs(lastReadError->timestampUs) / 1000);
2520*d57664e9SAndroid Build Coastguard Worker const auto& kMetricsLastReadErrorNo =
2521*d57664e9SAndroid Build Coastguard Worker os::incremental::BnIncrementalService::METRICS_LAST_READ_ERROR_NUMBER();
2522*d57664e9SAndroid Build Coastguard Worker result->putInt(String16(kMetricsLastReadErrorNo.c_str()), lastReadError->errorNo);
2523*d57664e9SAndroid Build Coastguard Worker const auto& kMetricsLastReadUid =
2524*d57664e9SAndroid Build Coastguard Worker os::incremental::BnIncrementalService::METRICS_LAST_READ_ERROR_UID();
2525*d57664e9SAndroid Build Coastguard Worker result->putInt(String16(kMetricsLastReadUid.c_str()), lastReadError->uid);
2526*d57664e9SAndroid Build Coastguard Worker }
2527*d57664e9SAndroid Build Coastguard Worker std::unique_lock l(ifs->lock);
2528*d57664e9SAndroid Build Coastguard Worker if (!ifs->dataLoaderStub) {
2529*d57664e9SAndroid Build Coastguard Worker return;
2530*d57664e9SAndroid Build Coastguard Worker }
2531*d57664e9SAndroid Build Coastguard Worker ifs->dataLoaderStub->getMetrics(result);
2532*d57664e9SAndroid Build Coastguard Worker }
2533*d57664e9SAndroid Build Coastguard Worker
DataLoaderStub(IncrementalService & service,MountId id,DataLoaderParamsParcel && params,FileSystemControlParcel && control,DataLoaderStatusListener && statusListener,const StorageHealthCheckParams & healthCheckParams,StorageHealthListener && healthListener,std::string && healthPath)2534*d57664e9SAndroid Build Coastguard Worker IncrementalService::DataLoaderStub::DataLoaderStub(
2535*d57664e9SAndroid Build Coastguard Worker IncrementalService& service, MountId id, DataLoaderParamsParcel&& params,
2536*d57664e9SAndroid Build Coastguard Worker FileSystemControlParcel&& control, DataLoaderStatusListener&& statusListener,
2537*d57664e9SAndroid Build Coastguard Worker const StorageHealthCheckParams& healthCheckParams, StorageHealthListener&& healthListener,
2538*d57664e9SAndroid Build Coastguard Worker std::string&& healthPath)
2539*d57664e9SAndroid Build Coastguard Worker : mService(service),
2540*d57664e9SAndroid Build Coastguard Worker mId(id),
2541*d57664e9SAndroid Build Coastguard Worker mParams(std::move(params)),
2542*d57664e9SAndroid Build Coastguard Worker mControl(std::move(control)),
2543*d57664e9SAndroid Build Coastguard Worker mStatusListener(std::move(statusListener)),
2544*d57664e9SAndroid Build Coastguard Worker mHealthListener(std::move(healthListener)),
2545*d57664e9SAndroid Build Coastguard Worker mHealthPath(std::move(healthPath)),
2546*d57664e9SAndroid Build Coastguard Worker mHealthCheckParams(healthCheckParams) {
2547*d57664e9SAndroid Build Coastguard Worker if (mHealthListener && !isHealthParamsValid()) {
2548*d57664e9SAndroid Build Coastguard Worker mHealthListener = {};
2549*d57664e9SAndroid Build Coastguard Worker }
2550*d57664e9SAndroid Build Coastguard Worker if (!mHealthListener) {
2551*d57664e9SAndroid Build Coastguard Worker // Disable advanced health check statuses.
2552*d57664e9SAndroid Build Coastguard Worker mHealthCheckParams.blockedTimeoutMs = -1;
2553*d57664e9SAndroid Build Coastguard Worker }
2554*d57664e9SAndroid Build Coastguard Worker updateHealthStatus();
2555*d57664e9SAndroid Build Coastguard Worker }
2556*d57664e9SAndroid Build Coastguard Worker
~DataLoaderStub()2557*d57664e9SAndroid Build Coastguard Worker IncrementalService::DataLoaderStub::~DataLoaderStub() {
2558*d57664e9SAndroid Build Coastguard Worker if (isValid()) {
2559*d57664e9SAndroid Build Coastguard Worker cleanupResources();
2560*d57664e9SAndroid Build Coastguard Worker }
2561*d57664e9SAndroid Build Coastguard Worker }
2562*d57664e9SAndroid Build Coastguard Worker
cleanupResources()2563*d57664e9SAndroid Build Coastguard Worker void IncrementalService::DataLoaderStub::cleanupResources() {
2564*d57664e9SAndroid Build Coastguard Worker auto now = Clock::now();
2565*d57664e9SAndroid Build Coastguard Worker {
2566*d57664e9SAndroid Build Coastguard Worker std::unique_lock lock(mMutex);
2567*d57664e9SAndroid Build Coastguard Worker mHealthPath.clear();
2568*d57664e9SAndroid Build Coastguard Worker unregisterFromPendingReads();
2569*d57664e9SAndroid Build Coastguard Worker resetHealthControl();
2570*d57664e9SAndroid Build Coastguard Worker mService.removeTimedJobs(*mService.mTimedQueue, mId);
2571*d57664e9SAndroid Build Coastguard Worker }
2572*d57664e9SAndroid Build Coastguard Worker mService.removeIfsStateCallbacks(mId);
2573*d57664e9SAndroid Build Coastguard Worker
2574*d57664e9SAndroid Build Coastguard Worker requestDestroy();
2575*d57664e9SAndroid Build Coastguard Worker
2576*d57664e9SAndroid Build Coastguard Worker {
2577*d57664e9SAndroid Build Coastguard Worker std::unique_lock lock(mMutex);
2578*d57664e9SAndroid Build Coastguard Worker mParams = {};
2579*d57664e9SAndroid Build Coastguard Worker mControl = {};
2580*d57664e9SAndroid Build Coastguard Worker mHealthControl = {};
2581*d57664e9SAndroid Build Coastguard Worker mHealthListener = {};
2582*d57664e9SAndroid Build Coastguard Worker mStatusCondition.wait_until(lock, now + Constants::destroyTimeout, [this] {
2583*d57664e9SAndroid Build Coastguard Worker return mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_DESTROYED;
2584*d57664e9SAndroid Build Coastguard Worker });
2585*d57664e9SAndroid Build Coastguard Worker mStatusListener = {};
2586*d57664e9SAndroid Build Coastguard Worker mId = kInvalidStorageId;
2587*d57664e9SAndroid Build Coastguard Worker }
2588*d57664e9SAndroid Build Coastguard Worker }
2589*d57664e9SAndroid Build Coastguard Worker
getDataLoader()2590*d57664e9SAndroid Build Coastguard Worker sp<content::pm::IDataLoader> IncrementalService::DataLoaderStub::getDataLoader() {
2591*d57664e9SAndroid Build Coastguard Worker sp<IDataLoader> dataloader;
2592*d57664e9SAndroid Build Coastguard Worker auto status = mService.mDataLoaderManager->getDataLoader(id(), &dataloader);
2593*d57664e9SAndroid Build Coastguard Worker if (!status.isOk()) {
2594*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to get dataloader: " << status.toString8();
2595*d57664e9SAndroid Build Coastguard Worker return {};
2596*d57664e9SAndroid Build Coastguard Worker }
2597*d57664e9SAndroid Build Coastguard Worker if (!dataloader) {
2598*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "DataLoader is null: " << status.toString8();
2599*d57664e9SAndroid Build Coastguard Worker return {};
2600*d57664e9SAndroid Build Coastguard Worker }
2601*d57664e9SAndroid Build Coastguard Worker return dataloader;
2602*d57664e9SAndroid Build Coastguard Worker }
2603*d57664e9SAndroid Build Coastguard Worker
isSystemDataLoader() const2604*d57664e9SAndroid Build Coastguard Worker bool IncrementalService::DataLoaderStub::isSystemDataLoader() const {
2605*d57664e9SAndroid Build Coastguard Worker return (params().packageName == Constants::systemPackage);
2606*d57664e9SAndroid Build Coastguard Worker }
2607*d57664e9SAndroid Build Coastguard Worker
requestCreate()2608*d57664e9SAndroid Build Coastguard Worker bool IncrementalService::DataLoaderStub::requestCreate() {
2609*d57664e9SAndroid Build Coastguard Worker return setTargetStatus(IDataLoaderStatusListener::DATA_LOADER_CREATED);
2610*d57664e9SAndroid Build Coastguard Worker }
2611*d57664e9SAndroid Build Coastguard Worker
requestStart()2612*d57664e9SAndroid Build Coastguard Worker bool IncrementalService::DataLoaderStub::requestStart() {
2613*d57664e9SAndroid Build Coastguard Worker return setTargetStatus(IDataLoaderStatusListener::DATA_LOADER_STARTED);
2614*d57664e9SAndroid Build Coastguard Worker }
2615*d57664e9SAndroid Build Coastguard Worker
requestDestroy()2616*d57664e9SAndroid Build Coastguard Worker bool IncrementalService::DataLoaderStub::requestDestroy() {
2617*d57664e9SAndroid Build Coastguard Worker return setTargetStatus(IDataLoaderStatusListener::DATA_LOADER_DESTROYED);
2618*d57664e9SAndroid Build Coastguard Worker }
2619*d57664e9SAndroid Build Coastguard Worker
setTargetStatus(int newStatus)2620*d57664e9SAndroid Build Coastguard Worker bool IncrementalService::DataLoaderStub::setTargetStatus(int newStatus) {
2621*d57664e9SAndroid Build Coastguard Worker {
2622*d57664e9SAndroid Build Coastguard Worker std::unique_lock lock(mMutex);
2623*d57664e9SAndroid Build Coastguard Worker setTargetStatusLocked(newStatus);
2624*d57664e9SAndroid Build Coastguard Worker }
2625*d57664e9SAndroid Build Coastguard Worker return fsmStep();
2626*d57664e9SAndroid Build Coastguard Worker }
2627*d57664e9SAndroid Build Coastguard Worker
setTargetStatusLocked(int status)2628*d57664e9SAndroid Build Coastguard Worker void IncrementalService::DataLoaderStub::setTargetStatusLocked(int status) {
2629*d57664e9SAndroid Build Coastguard Worker auto oldStatus = mTargetStatus;
2630*d57664e9SAndroid Build Coastguard Worker mTargetStatus = status;
2631*d57664e9SAndroid Build Coastguard Worker mTargetStatusTs = Clock::now();
2632*d57664e9SAndroid Build Coastguard Worker LOG(DEBUG) << "Target status update for DataLoader " << id() << ": " << oldStatus << " -> "
2633*d57664e9SAndroid Build Coastguard Worker << status << " (current " << mCurrentStatus << ")";
2634*d57664e9SAndroid Build Coastguard Worker }
2635*d57664e9SAndroid Build Coastguard Worker
needToBind()2636*d57664e9SAndroid Build Coastguard Worker std::optional<Milliseconds> IncrementalService::DataLoaderStub::needToBind() {
2637*d57664e9SAndroid Build Coastguard Worker std::unique_lock lock(mMutex);
2638*d57664e9SAndroid Build Coastguard Worker
2639*d57664e9SAndroid Build Coastguard Worker const auto now = mService.mClock->now();
2640*d57664e9SAndroid Build Coastguard Worker const bool healthy = (mPreviousBindDelay == 0ms);
2641*d57664e9SAndroid Build Coastguard Worker
2642*d57664e9SAndroid Build Coastguard Worker if (mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_BINDING &&
2643*d57664e9SAndroid Build Coastguard Worker now - mCurrentStatusTs <= Constants::bindingTimeout) {
2644*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "Binding still in progress. "
2645*d57664e9SAndroid Build Coastguard Worker << (healthy ? "The DL is healthy/freshly bound, ok to retry for a few times."
2646*d57664e9SAndroid Build Coastguard Worker : "Already unhealthy, don't do anything.")
2647*d57664e9SAndroid Build Coastguard Worker << " for storage " << mId;
2648*d57664e9SAndroid Build Coastguard Worker // Binding still in progress.
2649*d57664e9SAndroid Build Coastguard Worker if (!healthy) {
2650*d57664e9SAndroid Build Coastguard Worker // Already unhealthy, don't do anything.
2651*d57664e9SAndroid Build Coastguard Worker return {};
2652*d57664e9SAndroid Build Coastguard Worker }
2653*d57664e9SAndroid Build Coastguard Worker // The DL is healthy/freshly bound, ok to retry for a few times.
2654*d57664e9SAndroid Build Coastguard Worker if (now - mPreviousBindTs <= Constants::bindGracePeriod) {
2655*d57664e9SAndroid Build Coastguard Worker // Still within grace period.
2656*d57664e9SAndroid Build Coastguard Worker if (now - mCurrentStatusTs >= Constants::bindRetryInterval) {
2657*d57664e9SAndroid Build Coastguard Worker // Retry interval passed, retrying.
2658*d57664e9SAndroid Build Coastguard Worker mCurrentStatusTs = now;
2659*d57664e9SAndroid Build Coastguard Worker mPreviousBindDelay = 0ms;
2660*d57664e9SAndroid Build Coastguard Worker return 0ms;
2661*d57664e9SAndroid Build Coastguard Worker }
2662*d57664e9SAndroid Build Coastguard Worker return {};
2663*d57664e9SAndroid Build Coastguard Worker }
2664*d57664e9SAndroid Build Coastguard Worker // fallthrough, mark as unhealthy, and retry with delay
2665*d57664e9SAndroid Build Coastguard Worker }
2666*d57664e9SAndroid Build Coastguard Worker
2667*d57664e9SAndroid Build Coastguard Worker const auto previousBindTs = mPreviousBindTs;
2668*d57664e9SAndroid Build Coastguard Worker mPreviousBindTs = now;
2669*d57664e9SAndroid Build Coastguard Worker
2670*d57664e9SAndroid Build Coastguard Worker const auto nonCrashingInterval =
2671*d57664e9SAndroid Build Coastguard Worker std::max(castToMs(now - previousBindTs - mPreviousBindDelay), 100ms);
2672*d57664e9SAndroid Build Coastguard Worker if (previousBindTs.time_since_epoch() == Clock::duration::zero() ||
2673*d57664e9SAndroid Build Coastguard Worker nonCrashingInterval > Constants::healthyDataLoaderUptime) {
2674*d57664e9SAndroid Build Coastguard Worker mPreviousBindDelay = 0ms;
2675*d57664e9SAndroid Build Coastguard Worker return 0ms;
2676*d57664e9SAndroid Build Coastguard Worker }
2677*d57664e9SAndroid Build Coastguard Worker
2678*d57664e9SAndroid Build Coastguard Worker constexpr auto minBindDelayMs = castToMs(Constants::minBindDelay);
2679*d57664e9SAndroid Build Coastguard Worker constexpr auto maxBindDelayMs = castToMs(Constants::maxBindDelay);
2680*d57664e9SAndroid Build Coastguard Worker
2681*d57664e9SAndroid Build Coastguard Worker const auto bindDelayMs =
2682*d57664e9SAndroid Build Coastguard Worker std::min(std::max(mPreviousBindDelay * Constants::bindDelayMultiplier, minBindDelayMs),
2683*d57664e9SAndroid Build Coastguard Worker maxBindDelayMs)
2684*d57664e9SAndroid Build Coastguard Worker .count();
2685*d57664e9SAndroid Build Coastguard Worker const auto bindDelayJitterRangeMs = bindDelayMs / Constants::bindDelayJitterDivider;
2686*d57664e9SAndroid Build Coastguard Worker // rand() is enough, not worth maintaining a full-blown <rand> object for delay jitter
2687*d57664e9SAndroid Build Coastguard Worker const auto bindDelayJitterMs = rand() % (bindDelayJitterRangeMs * 2) - // NOLINT
2688*d57664e9SAndroid Build Coastguard Worker bindDelayJitterRangeMs;
2689*d57664e9SAndroid Build Coastguard Worker mPreviousBindDelay = std::chrono::milliseconds(bindDelayMs + bindDelayJitterMs);
2690*d57664e9SAndroid Build Coastguard Worker return mPreviousBindDelay;
2691*d57664e9SAndroid Build Coastguard Worker }
2692*d57664e9SAndroid Build Coastguard Worker
bind()2693*d57664e9SAndroid Build Coastguard Worker bool IncrementalService::DataLoaderStub::bind() {
2694*d57664e9SAndroid Build Coastguard Worker const auto maybeBindDelay = needToBind();
2695*d57664e9SAndroid Build Coastguard Worker if (!maybeBindDelay) {
2696*d57664e9SAndroid Build Coastguard Worker LOG(DEBUG) << "Skipping bind to " << mParams.packageName << " because of pending bind.";
2697*d57664e9SAndroid Build Coastguard Worker return true;
2698*d57664e9SAndroid Build Coastguard Worker }
2699*d57664e9SAndroid Build Coastguard Worker const auto bindDelay = *maybeBindDelay;
2700*d57664e9SAndroid Build Coastguard Worker if (bindDelay > 1s) {
2701*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "Delaying bind to " << mParams.packageName << " by "
2702*d57664e9SAndroid Build Coastguard Worker << bindDelay.count() / 1000 << "s"
2703*d57664e9SAndroid Build Coastguard Worker << " for storage " << mId;
2704*d57664e9SAndroid Build Coastguard Worker }
2705*d57664e9SAndroid Build Coastguard Worker
2706*d57664e9SAndroid Build Coastguard Worker bool result = false;
2707*d57664e9SAndroid Build Coastguard Worker auto status = mService.mDataLoaderManager->bindToDataLoader(id(), mParams, bindDelay.count(),
2708*d57664e9SAndroid Build Coastguard Worker this, &result);
2709*d57664e9SAndroid Build Coastguard Worker if (!status.isOk() || !result) {
2710*d57664e9SAndroid Build Coastguard Worker const bool healthy = (bindDelay == 0ms);
2711*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to bind a data loader for mount " << id()
2712*d57664e9SAndroid Build Coastguard Worker << (healthy ? ", retrying." : "");
2713*d57664e9SAndroid Build Coastguard Worker
2714*d57664e9SAndroid Build Coastguard Worker // Internal error, retry for healthy/new DLs.
2715*d57664e9SAndroid Build Coastguard Worker // Let needToBind migrate it to unhealthy after too many retries.
2716*d57664e9SAndroid Build Coastguard Worker if (healthy) {
2717*d57664e9SAndroid Build Coastguard Worker if (mService.addTimedJob(*mService.mTimedQueue, id(), Constants::bindRetryInterval,
2718*d57664e9SAndroid Build Coastguard Worker [this]() { fsmStep(); })) {
2719*d57664e9SAndroid Build Coastguard Worker // Mark as binding so that we know it's not the DL's fault.
2720*d57664e9SAndroid Build Coastguard Worker setCurrentStatus(IDataLoaderStatusListener::DATA_LOADER_BINDING);
2721*d57664e9SAndroid Build Coastguard Worker return true;
2722*d57664e9SAndroid Build Coastguard Worker }
2723*d57664e9SAndroid Build Coastguard Worker }
2724*d57664e9SAndroid Build Coastguard Worker
2725*d57664e9SAndroid Build Coastguard Worker return false;
2726*d57664e9SAndroid Build Coastguard Worker }
2727*d57664e9SAndroid Build Coastguard Worker return true;
2728*d57664e9SAndroid Build Coastguard Worker }
2729*d57664e9SAndroid Build Coastguard Worker
create()2730*d57664e9SAndroid Build Coastguard Worker bool IncrementalService::DataLoaderStub::create() {
2731*d57664e9SAndroid Build Coastguard Worker auto dataloader = getDataLoader();
2732*d57664e9SAndroid Build Coastguard Worker if (!dataloader) {
2733*d57664e9SAndroid Build Coastguard Worker return false;
2734*d57664e9SAndroid Build Coastguard Worker }
2735*d57664e9SAndroid Build Coastguard Worker auto status = dataloader->create(id(), mParams, mControl, this);
2736*d57664e9SAndroid Build Coastguard Worker if (!status.isOk()) {
2737*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to create DataLoader: " << status.toString8();
2738*d57664e9SAndroid Build Coastguard Worker return false;
2739*d57664e9SAndroid Build Coastguard Worker }
2740*d57664e9SAndroid Build Coastguard Worker return true;
2741*d57664e9SAndroid Build Coastguard Worker }
2742*d57664e9SAndroid Build Coastguard Worker
start()2743*d57664e9SAndroid Build Coastguard Worker bool IncrementalService::DataLoaderStub::start() {
2744*d57664e9SAndroid Build Coastguard Worker auto dataloader = getDataLoader();
2745*d57664e9SAndroid Build Coastguard Worker if (!dataloader) {
2746*d57664e9SAndroid Build Coastguard Worker return false;
2747*d57664e9SAndroid Build Coastguard Worker }
2748*d57664e9SAndroid Build Coastguard Worker auto status = dataloader->start(id());
2749*d57664e9SAndroid Build Coastguard Worker if (!status.isOk()) {
2750*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to start DataLoader: " << status.toString8();
2751*d57664e9SAndroid Build Coastguard Worker return false;
2752*d57664e9SAndroid Build Coastguard Worker }
2753*d57664e9SAndroid Build Coastguard Worker return true;
2754*d57664e9SAndroid Build Coastguard Worker }
2755*d57664e9SAndroid Build Coastguard Worker
destroy()2756*d57664e9SAndroid Build Coastguard Worker bool IncrementalService::DataLoaderStub::destroy() {
2757*d57664e9SAndroid Build Coastguard Worker return mService.mDataLoaderManager->unbindFromDataLoader(id()).isOk();
2758*d57664e9SAndroid Build Coastguard Worker }
2759*d57664e9SAndroid Build Coastguard Worker
fsmStep()2760*d57664e9SAndroid Build Coastguard Worker bool IncrementalService::DataLoaderStub::fsmStep() {
2761*d57664e9SAndroid Build Coastguard Worker if (!isValid()) {
2762*d57664e9SAndroid Build Coastguard Worker return false;
2763*d57664e9SAndroid Build Coastguard Worker }
2764*d57664e9SAndroid Build Coastguard Worker
2765*d57664e9SAndroid Build Coastguard Worker int currentStatus;
2766*d57664e9SAndroid Build Coastguard Worker int targetStatus;
2767*d57664e9SAndroid Build Coastguard Worker {
2768*d57664e9SAndroid Build Coastguard Worker std::unique_lock lock(mMutex);
2769*d57664e9SAndroid Build Coastguard Worker currentStatus = mCurrentStatus;
2770*d57664e9SAndroid Build Coastguard Worker targetStatus = mTargetStatus;
2771*d57664e9SAndroid Build Coastguard Worker }
2772*d57664e9SAndroid Build Coastguard Worker
2773*d57664e9SAndroid Build Coastguard Worker LOG(DEBUG) << "fsmStep: " << id() << ": " << currentStatus << " -> " << targetStatus;
2774*d57664e9SAndroid Build Coastguard Worker
2775*d57664e9SAndroid Build Coastguard Worker if (currentStatus == targetStatus) {
2776*d57664e9SAndroid Build Coastguard Worker return true;
2777*d57664e9SAndroid Build Coastguard Worker }
2778*d57664e9SAndroid Build Coastguard Worker
2779*d57664e9SAndroid Build Coastguard Worker switch (targetStatus) {
2780*d57664e9SAndroid Build Coastguard Worker case IDataLoaderStatusListener::DATA_LOADER_DESTROYED: {
2781*d57664e9SAndroid Build Coastguard Worker switch (currentStatus) {
2782*d57664e9SAndroid Build Coastguard Worker case IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE:
2783*d57664e9SAndroid Build Coastguard Worker case IDataLoaderStatusListener::DATA_LOADER_UNRECOVERABLE:
2784*d57664e9SAndroid Build Coastguard Worker destroy();
2785*d57664e9SAndroid Build Coastguard Worker // DataLoader is broken, just assume it's destroyed.
2786*d57664e9SAndroid Build Coastguard Worker compareAndSetCurrentStatus(currentStatus,
2787*d57664e9SAndroid Build Coastguard Worker IDataLoaderStatusListener::DATA_LOADER_DESTROYED);
2788*d57664e9SAndroid Build Coastguard Worker return true;
2789*d57664e9SAndroid Build Coastguard Worker case IDataLoaderStatusListener::DATA_LOADER_BINDING:
2790*d57664e9SAndroid Build Coastguard Worker compareAndSetCurrentStatus(currentStatus,
2791*d57664e9SAndroid Build Coastguard Worker IDataLoaderStatusListener::DATA_LOADER_DESTROYED);
2792*d57664e9SAndroid Build Coastguard Worker return true;
2793*d57664e9SAndroid Build Coastguard Worker default:
2794*d57664e9SAndroid Build Coastguard Worker return destroy();
2795*d57664e9SAndroid Build Coastguard Worker }
2796*d57664e9SAndroid Build Coastguard Worker break;
2797*d57664e9SAndroid Build Coastguard Worker }
2798*d57664e9SAndroid Build Coastguard Worker case IDataLoaderStatusListener::DATA_LOADER_STARTED: {
2799*d57664e9SAndroid Build Coastguard Worker switch (currentStatus) {
2800*d57664e9SAndroid Build Coastguard Worker case IDataLoaderStatusListener::DATA_LOADER_CREATED:
2801*d57664e9SAndroid Build Coastguard Worker case IDataLoaderStatusListener::DATA_LOADER_STOPPED:
2802*d57664e9SAndroid Build Coastguard Worker return start();
2803*d57664e9SAndroid Build Coastguard Worker }
2804*d57664e9SAndroid Build Coastguard Worker [[fallthrough]];
2805*d57664e9SAndroid Build Coastguard Worker }
2806*d57664e9SAndroid Build Coastguard Worker case IDataLoaderStatusListener::DATA_LOADER_CREATED:
2807*d57664e9SAndroid Build Coastguard Worker switch (currentStatus) {
2808*d57664e9SAndroid Build Coastguard Worker case IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE:
2809*d57664e9SAndroid Build Coastguard Worker case IDataLoaderStatusListener::DATA_LOADER_UNRECOVERABLE:
2810*d57664e9SAndroid Build Coastguard Worker // Before binding need to make sure we are unbound.
2811*d57664e9SAndroid Build Coastguard Worker // Otherwise we'll get stuck binding.
2812*d57664e9SAndroid Build Coastguard Worker destroy();
2813*d57664e9SAndroid Build Coastguard Worker // DataLoader is broken, just assume it's destroyed.
2814*d57664e9SAndroid Build Coastguard Worker compareAndSetCurrentStatus(currentStatus,
2815*d57664e9SAndroid Build Coastguard Worker IDataLoaderStatusListener::DATA_LOADER_DESTROYED);
2816*d57664e9SAndroid Build Coastguard Worker return true;
2817*d57664e9SAndroid Build Coastguard Worker case IDataLoaderStatusListener::DATA_LOADER_DESTROYED:
2818*d57664e9SAndroid Build Coastguard Worker case IDataLoaderStatusListener::DATA_LOADER_BINDING:
2819*d57664e9SAndroid Build Coastguard Worker return bind();
2820*d57664e9SAndroid Build Coastguard Worker case IDataLoaderStatusListener::DATA_LOADER_BOUND:
2821*d57664e9SAndroid Build Coastguard Worker return create();
2822*d57664e9SAndroid Build Coastguard Worker }
2823*d57664e9SAndroid Build Coastguard Worker break;
2824*d57664e9SAndroid Build Coastguard Worker default:
2825*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Invalid target status: " << targetStatus
2826*d57664e9SAndroid Build Coastguard Worker << ", current status: " << currentStatus;
2827*d57664e9SAndroid Build Coastguard Worker break;
2828*d57664e9SAndroid Build Coastguard Worker }
2829*d57664e9SAndroid Build Coastguard Worker return false;
2830*d57664e9SAndroid Build Coastguard Worker }
2831*d57664e9SAndroid Build Coastguard Worker
onStatusChanged(MountId mountId,int newStatus)2832*d57664e9SAndroid Build Coastguard Worker binder::Status IncrementalService::DataLoaderStub::onStatusChanged(MountId mountId, int newStatus) {
2833*d57664e9SAndroid Build Coastguard Worker if (!isValid()) {
2834*d57664e9SAndroid Build Coastguard Worker if (newStatus == IDataLoaderStatusListener::DATA_LOADER_BOUND) {
2835*d57664e9SAndroid Build Coastguard Worker // Async "bound" came to already destroyed stub.
2836*d57664e9SAndroid Build Coastguard Worker // Unbind immediately to avoid invalid stub sitting around in DataLoaderManagerService.
2837*d57664e9SAndroid Build Coastguard Worker mService.mDataLoaderManager->unbindFromDataLoader(mountId);
2838*d57664e9SAndroid Build Coastguard Worker return binder::Status::ok();
2839*d57664e9SAndroid Build Coastguard Worker }
2840*d57664e9SAndroid Build Coastguard Worker return binder::Status::
2841*d57664e9SAndroid Build Coastguard Worker fromServiceSpecificError(-EINVAL, "onStatusChange came to invalid DataLoaderStub");
2842*d57664e9SAndroid Build Coastguard Worker }
2843*d57664e9SAndroid Build Coastguard Worker if (id() != mountId) {
2844*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "onStatusChanged: mount ID mismatch: expected " << id()
2845*d57664e9SAndroid Build Coastguard Worker << ", but got: " << mountId;
2846*d57664e9SAndroid Build Coastguard Worker return binder::Status::fromServiceSpecificError(-EPERM, "Mount ID mismatch.");
2847*d57664e9SAndroid Build Coastguard Worker }
2848*d57664e9SAndroid Build Coastguard Worker if (newStatus == IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE ||
2849*d57664e9SAndroid Build Coastguard Worker newStatus == IDataLoaderStatusListener::DATA_LOADER_UNRECOVERABLE) {
2850*d57664e9SAndroid Build Coastguard Worker // User-provided status, let's postpone the handling to avoid possible deadlocks.
2851*d57664e9SAndroid Build Coastguard Worker mService.addTimedJob(*mService.mTimedQueue, id(), Constants::userStatusDelay,
2852*d57664e9SAndroid Build Coastguard Worker [this, newStatus]() { setCurrentStatus(newStatus); });
2853*d57664e9SAndroid Build Coastguard Worker return binder::Status::ok();
2854*d57664e9SAndroid Build Coastguard Worker }
2855*d57664e9SAndroid Build Coastguard Worker
2856*d57664e9SAndroid Build Coastguard Worker setCurrentStatus(newStatus);
2857*d57664e9SAndroid Build Coastguard Worker return binder::Status::ok();
2858*d57664e9SAndroid Build Coastguard Worker }
2859*d57664e9SAndroid Build Coastguard Worker
setCurrentStatus(int newStatus)2860*d57664e9SAndroid Build Coastguard Worker void IncrementalService::DataLoaderStub::setCurrentStatus(int newStatus) {
2861*d57664e9SAndroid Build Coastguard Worker compareAndSetCurrentStatus(Constants::anyStatus, newStatus);
2862*d57664e9SAndroid Build Coastguard Worker }
2863*d57664e9SAndroid Build Coastguard Worker
compareAndSetCurrentStatus(int expectedStatus,int newStatus)2864*d57664e9SAndroid Build Coastguard Worker void IncrementalService::DataLoaderStub::compareAndSetCurrentStatus(int expectedStatus,
2865*d57664e9SAndroid Build Coastguard Worker int newStatus) {
2866*d57664e9SAndroid Build Coastguard Worker int oldStatus, oldTargetStatus, newTargetStatus;
2867*d57664e9SAndroid Build Coastguard Worker DataLoaderStatusListener listener;
2868*d57664e9SAndroid Build Coastguard Worker {
2869*d57664e9SAndroid Build Coastguard Worker std::unique_lock lock(mMutex);
2870*d57664e9SAndroid Build Coastguard Worker if (mCurrentStatus == newStatus) {
2871*d57664e9SAndroid Build Coastguard Worker return;
2872*d57664e9SAndroid Build Coastguard Worker }
2873*d57664e9SAndroid Build Coastguard Worker if (expectedStatus != Constants::anyStatus && expectedStatus != mCurrentStatus) {
2874*d57664e9SAndroid Build Coastguard Worker return;
2875*d57664e9SAndroid Build Coastguard Worker }
2876*d57664e9SAndroid Build Coastguard Worker
2877*d57664e9SAndroid Build Coastguard Worker oldStatus = mCurrentStatus;
2878*d57664e9SAndroid Build Coastguard Worker oldTargetStatus = mTargetStatus;
2879*d57664e9SAndroid Build Coastguard Worker listener = mStatusListener;
2880*d57664e9SAndroid Build Coastguard Worker
2881*d57664e9SAndroid Build Coastguard Worker // Change the status.
2882*d57664e9SAndroid Build Coastguard Worker mCurrentStatus = newStatus;
2883*d57664e9SAndroid Build Coastguard Worker mCurrentStatusTs = mService.mClock->now();
2884*d57664e9SAndroid Build Coastguard Worker
2885*d57664e9SAndroid Build Coastguard Worker switch (mCurrentStatus) {
2886*d57664e9SAndroid Build Coastguard Worker case IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE:
2887*d57664e9SAndroid Build Coastguard Worker // Unavailable, retry.
2888*d57664e9SAndroid Build Coastguard Worker setTargetStatusLocked(IDataLoaderStatusListener::DATA_LOADER_STARTED);
2889*d57664e9SAndroid Build Coastguard Worker break;
2890*d57664e9SAndroid Build Coastguard Worker case IDataLoaderStatusListener::DATA_LOADER_UNRECOVERABLE:
2891*d57664e9SAndroid Build Coastguard Worker // Unrecoverable, just unbind.
2892*d57664e9SAndroid Build Coastguard Worker setTargetStatusLocked(IDataLoaderStatusListener::DATA_LOADER_DESTROYED);
2893*d57664e9SAndroid Build Coastguard Worker break;
2894*d57664e9SAndroid Build Coastguard Worker default:
2895*d57664e9SAndroid Build Coastguard Worker break;
2896*d57664e9SAndroid Build Coastguard Worker }
2897*d57664e9SAndroid Build Coastguard Worker
2898*d57664e9SAndroid Build Coastguard Worker newTargetStatus = mTargetStatus;
2899*d57664e9SAndroid Build Coastguard Worker }
2900*d57664e9SAndroid Build Coastguard Worker
2901*d57664e9SAndroid Build Coastguard Worker LOG(DEBUG) << "Current status update for DataLoader " << id() << ": " << oldStatus << " -> "
2902*d57664e9SAndroid Build Coastguard Worker << newStatus << " (target " << oldTargetStatus << " -> " << newTargetStatus << ")";
2903*d57664e9SAndroid Build Coastguard Worker
2904*d57664e9SAndroid Build Coastguard Worker if (listener) {
2905*d57664e9SAndroid Build Coastguard Worker listener->onStatusChanged(id(), newStatus);
2906*d57664e9SAndroid Build Coastguard Worker }
2907*d57664e9SAndroid Build Coastguard Worker
2908*d57664e9SAndroid Build Coastguard Worker fsmStep();
2909*d57664e9SAndroid Build Coastguard Worker
2910*d57664e9SAndroid Build Coastguard Worker mStatusCondition.notify_all();
2911*d57664e9SAndroid Build Coastguard Worker }
2912*d57664e9SAndroid Build Coastguard Worker
isHealthParamsValid() const2913*d57664e9SAndroid Build Coastguard Worker bool IncrementalService::DataLoaderStub::isHealthParamsValid() const {
2914*d57664e9SAndroid Build Coastguard Worker return mHealthCheckParams.blockedTimeoutMs > 0 &&
2915*d57664e9SAndroid Build Coastguard Worker mHealthCheckParams.blockedTimeoutMs < mHealthCheckParams.unhealthyTimeoutMs;
2916*d57664e9SAndroid Build Coastguard Worker }
2917*d57664e9SAndroid Build Coastguard Worker
onHealthStatus(const StorageHealthListener & healthListener,int healthStatus)2918*d57664e9SAndroid Build Coastguard Worker void IncrementalService::DataLoaderStub::onHealthStatus(const StorageHealthListener& healthListener,
2919*d57664e9SAndroid Build Coastguard Worker int healthStatus) {
2920*d57664e9SAndroid Build Coastguard Worker LOG(DEBUG) << id() << ": healthStatus: " << healthStatus;
2921*d57664e9SAndroid Build Coastguard Worker if (healthListener) {
2922*d57664e9SAndroid Build Coastguard Worker healthListener->onHealthStatus(id(), healthStatus);
2923*d57664e9SAndroid Build Coastguard Worker }
2924*d57664e9SAndroid Build Coastguard Worker mHealthStatus = healthStatus;
2925*d57664e9SAndroid Build Coastguard Worker }
2926*d57664e9SAndroid Build Coastguard Worker
updateHealthStatus(bool baseline)2927*d57664e9SAndroid Build Coastguard Worker void IncrementalService::DataLoaderStub::updateHealthStatus(bool baseline) {
2928*d57664e9SAndroid Build Coastguard Worker LOG(DEBUG) << id() << ": updateHealthStatus" << (baseline ? " (baseline)" : "");
2929*d57664e9SAndroid Build Coastguard Worker
2930*d57664e9SAndroid Build Coastguard Worker int healthStatusToReport = -1;
2931*d57664e9SAndroid Build Coastguard Worker StorageHealthListener healthListener;
2932*d57664e9SAndroid Build Coastguard Worker
2933*d57664e9SAndroid Build Coastguard Worker {
2934*d57664e9SAndroid Build Coastguard Worker std::unique_lock lock(mMutex);
2935*d57664e9SAndroid Build Coastguard Worker unregisterFromPendingReads();
2936*d57664e9SAndroid Build Coastguard Worker
2937*d57664e9SAndroid Build Coastguard Worker healthListener = mHealthListener;
2938*d57664e9SAndroid Build Coastguard Worker
2939*d57664e9SAndroid Build Coastguard Worker // Healthcheck depends on timestamp of the oldest pending read.
2940*d57664e9SAndroid Build Coastguard Worker // To get it, we need to re-open a pendingReads FD to get a full list of reads.
2941*d57664e9SAndroid Build Coastguard Worker // Additionally we need to re-register for epoll with fresh FDs in case there are no
2942*d57664e9SAndroid Build Coastguard Worker // reads.
2943*d57664e9SAndroid Build Coastguard Worker const auto now = Clock::now();
2944*d57664e9SAndroid Build Coastguard Worker const auto kernelTsUs = getOldestPendingReadTs();
2945*d57664e9SAndroid Build Coastguard Worker if (baseline) {
2946*d57664e9SAndroid Build Coastguard Worker // Updating baseline only on looper/epoll callback, i.e. on new set of pending
2947*d57664e9SAndroid Build Coastguard Worker // reads.
2948*d57664e9SAndroid Build Coastguard Worker mHealthBase = {now, kernelTsUs};
2949*d57664e9SAndroid Build Coastguard Worker }
2950*d57664e9SAndroid Build Coastguard Worker
2951*d57664e9SAndroid Build Coastguard Worker if (kernelTsUs == kMaxBootClockTsUs || mHealthBase.kernelTsUs == kMaxBootClockTsUs ||
2952*d57664e9SAndroid Build Coastguard Worker mHealthBase.userTs > now) {
2953*d57664e9SAndroid Build Coastguard Worker LOG(DEBUG) << id() << ": No pending reads or invalid base, report Ok and wait.";
2954*d57664e9SAndroid Build Coastguard Worker registerForPendingReads();
2955*d57664e9SAndroid Build Coastguard Worker healthStatusToReport = IStorageHealthListener::HEALTH_STATUS_OK;
2956*d57664e9SAndroid Build Coastguard Worker lock.unlock();
2957*d57664e9SAndroid Build Coastguard Worker onHealthStatus(healthListener, healthStatusToReport);
2958*d57664e9SAndroid Build Coastguard Worker return;
2959*d57664e9SAndroid Build Coastguard Worker }
2960*d57664e9SAndroid Build Coastguard Worker
2961*d57664e9SAndroid Build Coastguard Worker resetHealthControl();
2962*d57664e9SAndroid Build Coastguard Worker
2963*d57664e9SAndroid Build Coastguard Worker // Always make sure the data loader is started.
2964*d57664e9SAndroid Build Coastguard Worker setTargetStatusLocked(IDataLoaderStatusListener::DATA_LOADER_STARTED);
2965*d57664e9SAndroid Build Coastguard Worker
2966*d57664e9SAndroid Build Coastguard Worker // Skip any further processing if health check params are invalid.
2967*d57664e9SAndroid Build Coastguard Worker if (!isHealthParamsValid()) {
2968*d57664e9SAndroid Build Coastguard Worker LOG(DEBUG) << id()
2969*d57664e9SAndroid Build Coastguard Worker << ": Skip any further processing if health check params are invalid.";
2970*d57664e9SAndroid Build Coastguard Worker healthStatusToReport = IStorageHealthListener::HEALTH_STATUS_READS_PENDING;
2971*d57664e9SAndroid Build Coastguard Worker lock.unlock();
2972*d57664e9SAndroid Build Coastguard Worker onHealthStatus(healthListener, healthStatusToReport);
2973*d57664e9SAndroid Build Coastguard Worker // Triggering data loader start. This is a one-time action.
2974*d57664e9SAndroid Build Coastguard Worker fsmStep();
2975*d57664e9SAndroid Build Coastguard Worker return;
2976*d57664e9SAndroid Build Coastguard Worker }
2977*d57664e9SAndroid Build Coastguard Worker
2978*d57664e9SAndroid Build Coastguard Worker // Don't schedule timer job less than 500ms in advance.
2979*d57664e9SAndroid Build Coastguard Worker static constexpr auto kTolerance = 500ms;
2980*d57664e9SAndroid Build Coastguard Worker
2981*d57664e9SAndroid Build Coastguard Worker const auto blockedTimeout = std::chrono::milliseconds(mHealthCheckParams.blockedTimeoutMs);
2982*d57664e9SAndroid Build Coastguard Worker const auto unhealthyTimeout =
2983*d57664e9SAndroid Build Coastguard Worker std::chrono::milliseconds(mHealthCheckParams.unhealthyTimeoutMs);
2984*d57664e9SAndroid Build Coastguard Worker const auto unhealthyMonitoring =
2985*d57664e9SAndroid Build Coastguard Worker std::max(1000ms,
2986*d57664e9SAndroid Build Coastguard Worker std::chrono::milliseconds(mHealthCheckParams.unhealthyMonitoringMs));
2987*d57664e9SAndroid Build Coastguard Worker
2988*d57664e9SAndroid Build Coastguard Worker const auto delta = elapsedMsSinceKernelTs(now, kernelTsUs);
2989*d57664e9SAndroid Build Coastguard Worker
2990*d57664e9SAndroid Build Coastguard Worker Milliseconds checkBackAfter;
2991*d57664e9SAndroid Build Coastguard Worker if (delta + kTolerance < blockedTimeout) {
2992*d57664e9SAndroid Build Coastguard Worker LOG(DEBUG) << id() << ": Report reads pending and wait for blocked status.";
2993*d57664e9SAndroid Build Coastguard Worker checkBackAfter = blockedTimeout - delta;
2994*d57664e9SAndroid Build Coastguard Worker healthStatusToReport = IStorageHealthListener::HEALTH_STATUS_READS_PENDING;
2995*d57664e9SAndroid Build Coastguard Worker } else if (delta + kTolerance < unhealthyTimeout) {
2996*d57664e9SAndroid Build Coastguard Worker LOG(DEBUG) << id() << ": Report blocked and wait for unhealthy.";
2997*d57664e9SAndroid Build Coastguard Worker checkBackAfter = unhealthyTimeout - delta;
2998*d57664e9SAndroid Build Coastguard Worker healthStatusToReport = IStorageHealthListener::HEALTH_STATUS_BLOCKED;
2999*d57664e9SAndroid Build Coastguard Worker } else {
3000*d57664e9SAndroid Build Coastguard Worker LOG(DEBUG) << id() << ": Report unhealthy and continue monitoring.";
3001*d57664e9SAndroid Build Coastguard Worker checkBackAfter = unhealthyMonitoring;
3002*d57664e9SAndroid Build Coastguard Worker healthStatusToReport = IStorageHealthListener::HEALTH_STATUS_UNHEALTHY;
3003*d57664e9SAndroid Build Coastguard Worker }
3004*d57664e9SAndroid Build Coastguard Worker LOG(DEBUG) << id() << ": updateHealthStatus in " << double(checkBackAfter.count()) / 1000.0
3005*d57664e9SAndroid Build Coastguard Worker << "secs";
3006*d57664e9SAndroid Build Coastguard Worker mService.addTimedJob(*mService.mTimedQueue, id(), checkBackAfter,
3007*d57664e9SAndroid Build Coastguard Worker [this]() { updateHealthStatus(); });
3008*d57664e9SAndroid Build Coastguard Worker }
3009*d57664e9SAndroid Build Coastguard Worker
3010*d57664e9SAndroid Build Coastguard Worker // With kTolerance we are expecting these to execute before the next update.
3011*d57664e9SAndroid Build Coastguard Worker if (healthStatusToReport != -1) {
3012*d57664e9SAndroid Build Coastguard Worker onHealthStatus(healthListener, healthStatusToReport);
3013*d57664e9SAndroid Build Coastguard Worker }
3014*d57664e9SAndroid Build Coastguard Worker
3015*d57664e9SAndroid Build Coastguard Worker fsmStep();
3016*d57664e9SAndroid Build Coastguard Worker }
3017*d57664e9SAndroid Build Coastguard Worker
elapsedMsSinceKernelTs(TimePoint now,BootClockTsUs kernelTsUs)3018*d57664e9SAndroid Build Coastguard Worker Milliseconds IncrementalService::DataLoaderStub::elapsedMsSinceKernelTs(TimePoint now,
3019*d57664e9SAndroid Build Coastguard Worker BootClockTsUs kernelTsUs) {
3020*d57664e9SAndroid Build Coastguard Worker const auto kernelDeltaUs = kernelTsUs - mHealthBase.kernelTsUs;
3021*d57664e9SAndroid Build Coastguard Worker const auto userTs = mHealthBase.userTs + std::chrono::microseconds(kernelDeltaUs);
3022*d57664e9SAndroid Build Coastguard Worker return std::chrono::duration_cast<Milliseconds>(now - userTs);
3023*d57664e9SAndroid Build Coastguard Worker }
3024*d57664e9SAndroid Build Coastguard Worker
initializeHealthControl()3025*d57664e9SAndroid Build Coastguard Worker const incfs::UniqueControl& IncrementalService::DataLoaderStub::initializeHealthControl() {
3026*d57664e9SAndroid Build Coastguard Worker if (mHealthPath.empty()) {
3027*d57664e9SAndroid Build Coastguard Worker resetHealthControl();
3028*d57664e9SAndroid Build Coastguard Worker return mHealthControl;
3029*d57664e9SAndroid Build Coastguard Worker }
3030*d57664e9SAndroid Build Coastguard Worker if (mHealthControl.pendingReads() < 0) {
3031*d57664e9SAndroid Build Coastguard Worker mHealthControl = mService.mIncFs->openMount(mHealthPath);
3032*d57664e9SAndroid Build Coastguard Worker }
3033*d57664e9SAndroid Build Coastguard Worker if (mHealthControl.pendingReads() < 0) {
3034*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Failed to open health control for: " << id() << ", path: " << mHealthPath
3035*d57664e9SAndroid Build Coastguard Worker << "(" << mHealthControl.cmd() << ":" << mHealthControl.pendingReads() << ":"
3036*d57664e9SAndroid Build Coastguard Worker << mHealthControl.logs() << ")";
3037*d57664e9SAndroid Build Coastguard Worker }
3038*d57664e9SAndroid Build Coastguard Worker return mHealthControl;
3039*d57664e9SAndroid Build Coastguard Worker }
3040*d57664e9SAndroid Build Coastguard Worker
resetHealthControl()3041*d57664e9SAndroid Build Coastguard Worker void IncrementalService::DataLoaderStub::resetHealthControl() {
3042*d57664e9SAndroid Build Coastguard Worker mHealthControl = {};
3043*d57664e9SAndroid Build Coastguard Worker }
3044*d57664e9SAndroid Build Coastguard Worker
getOldestPendingReadTs()3045*d57664e9SAndroid Build Coastguard Worker BootClockTsUs IncrementalService::DataLoaderStub::getOldestPendingReadTs() {
3046*d57664e9SAndroid Build Coastguard Worker auto result = kMaxBootClockTsUs;
3047*d57664e9SAndroid Build Coastguard Worker
3048*d57664e9SAndroid Build Coastguard Worker const auto& control = initializeHealthControl();
3049*d57664e9SAndroid Build Coastguard Worker if (control.pendingReads() < 0) {
3050*d57664e9SAndroid Build Coastguard Worker return result;
3051*d57664e9SAndroid Build Coastguard Worker }
3052*d57664e9SAndroid Build Coastguard Worker
3053*d57664e9SAndroid Build Coastguard Worker if (mService.mIncFs->waitForPendingReads(control, 0ms, &mLastPendingReads) !=
3054*d57664e9SAndroid Build Coastguard Worker android::incfs::WaitResult::HaveData ||
3055*d57664e9SAndroid Build Coastguard Worker mLastPendingReads.empty()) {
3056*d57664e9SAndroid Build Coastguard Worker // Clear previous pending reads
3057*d57664e9SAndroid Build Coastguard Worker mLastPendingReads.clear();
3058*d57664e9SAndroid Build Coastguard Worker return result;
3059*d57664e9SAndroid Build Coastguard Worker }
3060*d57664e9SAndroid Build Coastguard Worker
3061*d57664e9SAndroid Build Coastguard Worker LOG(DEBUG) << id() << ": pendingReads: fd(" << control.pendingReads() << "), count("
3062*d57664e9SAndroid Build Coastguard Worker << mLastPendingReads.size() << "), block: " << mLastPendingReads.front().block
3063*d57664e9SAndroid Build Coastguard Worker << ", time: " << mLastPendingReads.front().bootClockTsUs
3064*d57664e9SAndroid Build Coastguard Worker << ", uid: " << mLastPendingReads.front().uid;
3065*d57664e9SAndroid Build Coastguard Worker
3066*d57664e9SAndroid Build Coastguard Worker return getOldestTsFromLastPendingReads();
3067*d57664e9SAndroid Build Coastguard Worker }
3068*d57664e9SAndroid Build Coastguard Worker
registerForPendingReads()3069*d57664e9SAndroid Build Coastguard Worker void IncrementalService::DataLoaderStub::registerForPendingReads() {
3070*d57664e9SAndroid Build Coastguard Worker const auto pendingReadsFd = mHealthControl.pendingReads();
3071*d57664e9SAndroid Build Coastguard Worker if (pendingReadsFd < 0) {
3072*d57664e9SAndroid Build Coastguard Worker return;
3073*d57664e9SAndroid Build Coastguard Worker }
3074*d57664e9SAndroid Build Coastguard Worker
3075*d57664e9SAndroid Build Coastguard Worker LOG(DEBUG) << id() << ": addFd(pendingReadsFd): " << pendingReadsFd;
3076*d57664e9SAndroid Build Coastguard Worker
3077*d57664e9SAndroid Build Coastguard Worker mService.mLooper->addFd(
3078*d57664e9SAndroid Build Coastguard Worker pendingReadsFd, android::Looper::POLL_CALLBACK, android::Looper::EVENT_INPUT,
3079*d57664e9SAndroid Build Coastguard Worker [](int, int, void* data) -> int {
3080*d57664e9SAndroid Build Coastguard Worker auto self = (DataLoaderStub*)data;
3081*d57664e9SAndroid Build Coastguard Worker self->updateHealthStatus(/*baseline=*/true);
3082*d57664e9SAndroid Build Coastguard Worker return 0;
3083*d57664e9SAndroid Build Coastguard Worker },
3084*d57664e9SAndroid Build Coastguard Worker this);
3085*d57664e9SAndroid Build Coastguard Worker mService.mLooper->wake();
3086*d57664e9SAndroid Build Coastguard Worker }
3087*d57664e9SAndroid Build Coastguard Worker
getOldestTsFromLastPendingReads()3088*d57664e9SAndroid Build Coastguard Worker BootClockTsUs IncrementalService::DataLoaderStub::getOldestTsFromLastPendingReads() {
3089*d57664e9SAndroid Build Coastguard Worker auto result = kMaxBootClockTsUs;
3090*d57664e9SAndroid Build Coastguard Worker for (auto&& pendingRead : mLastPendingReads) {
3091*d57664e9SAndroid Build Coastguard Worker result = std::min(result, pendingRead.bootClockTsUs);
3092*d57664e9SAndroid Build Coastguard Worker }
3093*d57664e9SAndroid Build Coastguard Worker return result;
3094*d57664e9SAndroid Build Coastguard Worker }
3095*d57664e9SAndroid Build Coastguard Worker
getMetrics(android::os::PersistableBundle * result)3096*d57664e9SAndroid Build Coastguard Worker void IncrementalService::DataLoaderStub::getMetrics(android::os::PersistableBundle* result) {
3097*d57664e9SAndroid Build Coastguard Worker const auto duration = elapsedMsSinceOldestPendingRead();
3098*d57664e9SAndroid Build Coastguard Worker if (duration >= 0) {
3099*d57664e9SAndroid Build Coastguard Worker const auto& kMetricsMillisSinceOldestPendingRead =
3100*d57664e9SAndroid Build Coastguard Worker os::incremental::BnIncrementalService::METRICS_MILLIS_SINCE_OLDEST_PENDING_READ();
3101*d57664e9SAndroid Build Coastguard Worker result->putLong(String16(kMetricsMillisSinceOldestPendingRead.c_str()), duration);
3102*d57664e9SAndroid Build Coastguard Worker }
3103*d57664e9SAndroid Build Coastguard Worker const auto& kMetricsStorageHealthStatusCode =
3104*d57664e9SAndroid Build Coastguard Worker os::incremental::BnIncrementalService::METRICS_STORAGE_HEALTH_STATUS_CODE();
3105*d57664e9SAndroid Build Coastguard Worker result->putInt(String16(kMetricsStorageHealthStatusCode.c_str()), mHealthStatus);
3106*d57664e9SAndroid Build Coastguard Worker const auto& kMetricsDataLoaderStatusCode =
3107*d57664e9SAndroid Build Coastguard Worker os::incremental::BnIncrementalService::METRICS_DATA_LOADER_STATUS_CODE();
3108*d57664e9SAndroid Build Coastguard Worker result->putInt(String16(kMetricsDataLoaderStatusCode.c_str()), mCurrentStatus);
3109*d57664e9SAndroid Build Coastguard Worker const auto& kMetricsMillisSinceLastDataLoaderBind =
3110*d57664e9SAndroid Build Coastguard Worker os::incremental::BnIncrementalService::METRICS_MILLIS_SINCE_LAST_DATA_LOADER_BIND();
3111*d57664e9SAndroid Build Coastguard Worker result->putLong(String16(kMetricsMillisSinceLastDataLoaderBind.c_str()),
3112*d57664e9SAndroid Build Coastguard Worker elapsedMcs(mPreviousBindTs, mService.mClock->now()) / 1000);
3113*d57664e9SAndroid Build Coastguard Worker const auto& kMetricsDataLoaderBindDelayMillis =
3114*d57664e9SAndroid Build Coastguard Worker os::incremental::BnIncrementalService::METRICS_DATA_LOADER_BIND_DELAY_MILLIS();
3115*d57664e9SAndroid Build Coastguard Worker result->putLong(String16(kMetricsDataLoaderBindDelayMillis.c_str()),
3116*d57664e9SAndroid Build Coastguard Worker mPreviousBindDelay.count());
3117*d57664e9SAndroid Build Coastguard Worker }
3118*d57664e9SAndroid Build Coastguard Worker
elapsedMsSinceOldestPendingRead()3119*d57664e9SAndroid Build Coastguard Worker long IncrementalService::DataLoaderStub::elapsedMsSinceOldestPendingRead() {
3120*d57664e9SAndroid Build Coastguard Worker const auto oldestPendingReadKernelTs = getOldestTsFromLastPendingReads();
3121*d57664e9SAndroid Build Coastguard Worker if (oldestPendingReadKernelTs == kMaxBootClockTsUs) {
3122*d57664e9SAndroid Build Coastguard Worker return 0;
3123*d57664e9SAndroid Build Coastguard Worker }
3124*d57664e9SAndroid Build Coastguard Worker return elapsedMsSinceKernelTs(Clock::now(), oldestPendingReadKernelTs).count();
3125*d57664e9SAndroid Build Coastguard Worker }
3126*d57664e9SAndroid Build Coastguard Worker
unregisterFromPendingReads()3127*d57664e9SAndroid Build Coastguard Worker void IncrementalService::DataLoaderStub::unregisterFromPendingReads() {
3128*d57664e9SAndroid Build Coastguard Worker const auto pendingReadsFd = mHealthControl.pendingReads();
3129*d57664e9SAndroid Build Coastguard Worker if (pendingReadsFd < 0) {
3130*d57664e9SAndroid Build Coastguard Worker return;
3131*d57664e9SAndroid Build Coastguard Worker }
3132*d57664e9SAndroid Build Coastguard Worker
3133*d57664e9SAndroid Build Coastguard Worker LOG(DEBUG) << id() << ": removeFd(pendingReadsFd): " << pendingReadsFd;
3134*d57664e9SAndroid Build Coastguard Worker
3135*d57664e9SAndroid Build Coastguard Worker mService.mLooper->removeFd(pendingReadsFd);
3136*d57664e9SAndroid Build Coastguard Worker mService.mLooper->wake();
3137*d57664e9SAndroid Build Coastguard Worker }
3138*d57664e9SAndroid Build Coastguard Worker
setHealthListener(const StorageHealthCheckParams & healthCheckParams,StorageHealthListener && healthListener)3139*d57664e9SAndroid Build Coastguard Worker void IncrementalService::DataLoaderStub::setHealthListener(
3140*d57664e9SAndroid Build Coastguard Worker const StorageHealthCheckParams& healthCheckParams, StorageHealthListener&& healthListener) {
3141*d57664e9SAndroid Build Coastguard Worker std::lock_guard lock(mMutex);
3142*d57664e9SAndroid Build Coastguard Worker mHealthCheckParams = healthCheckParams;
3143*d57664e9SAndroid Build Coastguard Worker mHealthListener = std::move(healthListener);
3144*d57664e9SAndroid Build Coastguard Worker if (!mHealthListener) {
3145*d57664e9SAndroid Build Coastguard Worker mHealthCheckParams.blockedTimeoutMs = -1;
3146*d57664e9SAndroid Build Coastguard Worker }
3147*d57664e9SAndroid Build Coastguard Worker }
3148*d57664e9SAndroid Build Coastguard Worker
toHexString(const RawMetadata & metadata)3149*d57664e9SAndroid Build Coastguard Worker static std::string toHexString(const RawMetadata& metadata) {
3150*d57664e9SAndroid Build Coastguard Worker int n = metadata.size();
3151*d57664e9SAndroid Build Coastguard Worker std::string res(n * 2, '\0');
3152*d57664e9SAndroid Build Coastguard Worker // Same as incfs::toString(fileId)
3153*d57664e9SAndroid Build Coastguard Worker static constexpr char kHexChar[] = "0123456789abcdef";
3154*d57664e9SAndroid Build Coastguard Worker for (int i = 0; i < n; ++i) {
3155*d57664e9SAndroid Build Coastguard Worker res[i * 2] = kHexChar[(metadata[i] & 0xf0) >> 4];
3156*d57664e9SAndroid Build Coastguard Worker res[i * 2 + 1] = kHexChar[(metadata[i] & 0x0f)];
3157*d57664e9SAndroid Build Coastguard Worker }
3158*d57664e9SAndroid Build Coastguard Worker return res;
3159*d57664e9SAndroid Build Coastguard Worker }
3160*d57664e9SAndroid Build Coastguard Worker
onDump(int fd)3161*d57664e9SAndroid Build Coastguard Worker void IncrementalService::DataLoaderStub::onDump(int fd) {
3162*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " dataLoader: {\n");
3163*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " currentStatus: %d\n", mCurrentStatus);
3164*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " currentStatusTs: %lldmcs\n",
3165*d57664e9SAndroid Build Coastguard Worker (long long)(elapsedMcs(mCurrentStatusTs, Clock::now())));
3166*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " targetStatus: %d\n", mTargetStatus);
3167*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " targetStatusTs: %lldmcs\n",
3168*d57664e9SAndroid Build Coastguard Worker (long long)(elapsedMcs(mTargetStatusTs, Clock::now())));
3169*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " health: {\n");
3170*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " path: %s\n", mHealthPath.c_str());
3171*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " base: %lldmcs (%lld)\n",
3172*d57664e9SAndroid Build Coastguard Worker (long long)(elapsedMcs(mHealthBase.userTs, Clock::now())),
3173*d57664e9SAndroid Build Coastguard Worker (long long)mHealthBase.kernelTsUs);
3174*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " blockedTimeoutMs: %d\n", int(mHealthCheckParams.blockedTimeoutMs));
3175*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " unhealthyTimeoutMs: %d\n", int(mHealthCheckParams.unhealthyTimeoutMs));
3176*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " unhealthyMonitoringMs: %d\n",
3177*d57664e9SAndroid Build Coastguard Worker int(mHealthCheckParams.unhealthyMonitoringMs));
3178*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " lastPendingReads: \n");
3179*d57664e9SAndroid Build Coastguard Worker const auto control = mService.mIncFs->openMount(mHealthPath);
3180*d57664e9SAndroid Build Coastguard Worker for (auto&& pendingRead : mLastPendingReads) {
3181*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " fileId: %s\n", IncFsWrapper::toString(pendingRead.id).c_str());
3182*d57664e9SAndroid Build Coastguard Worker const auto metadata = mService.mIncFs->getMetadata(control, pendingRead.id);
3183*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " metadataHex: %s\n", toHexString(metadata).c_str());
3184*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " blockIndex: %d\n", pendingRead.block);
3185*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " bootClockTsUs: %lld\n", (long long)pendingRead.bootClockTsUs);
3186*d57664e9SAndroid Build Coastguard Worker }
3187*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " bind: %llds ago (delay: %llds)\n",
3188*d57664e9SAndroid Build Coastguard Worker (long long)(elapsedMcs(mPreviousBindTs, mService.mClock->now()) / 1000000),
3189*d57664e9SAndroid Build Coastguard Worker (long long)(mPreviousBindDelay.count() / 1000));
3190*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " }\n");
3191*d57664e9SAndroid Build Coastguard Worker const auto& params = mParams;
3192*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " dataLoaderParams: {\n");
3193*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " type: %s\n", toString(params.type).c_str());
3194*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " packageName: %s\n", params.packageName.c_str());
3195*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " className: %s\n", params.className.c_str());
3196*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " arguments: %s\n", params.arguments.c_str());
3197*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " }\n");
3198*d57664e9SAndroid Build Coastguard Worker dprintf(fd, " }\n");
3199*d57664e9SAndroid Build Coastguard Worker }
3200*d57664e9SAndroid Build Coastguard Worker
opChanged(int32_t,const String16 &)3201*d57664e9SAndroid Build Coastguard Worker void IncrementalService::AppOpsListener::opChanged(int32_t, const String16&) {
3202*d57664e9SAndroid Build Coastguard Worker incrementalService.onAppOpChanged(packageName);
3203*d57664e9SAndroid Build Coastguard Worker }
3204*d57664e9SAndroid Build Coastguard Worker
setStorageParams(bool enableReadLogs,int32_t * _aidl_return)3205*d57664e9SAndroid Build Coastguard Worker binder::Status IncrementalService::IncrementalServiceConnector::setStorageParams(
3206*d57664e9SAndroid Build Coastguard Worker bool enableReadLogs, int32_t* _aidl_return) {
3207*d57664e9SAndroid Build Coastguard Worker *_aidl_return = incrementalService.setStorageParams(storage, enableReadLogs);
3208*d57664e9SAndroid Build Coastguard Worker return binder::Status::ok();
3209*d57664e9SAndroid Build Coastguard Worker }
3210*d57664e9SAndroid Build Coastguard Worker
idFromMetadata(std::span<const uint8_t> metadata)3211*d57664e9SAndroid Build Coastguard Worker FileId IncrementalService::idFromMetadata(std::span<const uint8_t> metadata) {
3212*d57664e9SAndroid Build Coastguard Worker return IncFs_FileIdFromMetadata({(const char*)metadata.data(), (IncFsSize)metadata.size()});
3213*d57664e9SAndroid Build Coastguard Worker }
3214*d57664e9SAndroid Build Coastguard Worker
3215*d57664e9SAndroid Build Coastguard Worker } // namespace android::incremental
3216