1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "IncrementalService"
18
19 #include "ServiceWrappers.h"
20
21 #include <MountRegistry.h>
22 #include <android-base/logging.h>
23 #include <android/content/pm/IDataLoaderManager.h>
24 #include <android/os/IVold.h>
25 #include <binder/AppOpsManager.h>
26 #include <utils/String16.h>
27
28 #include <filesystem>
29 #include <thread>
30
31 #include "IncrementalServiceValidation.h"
32
33 using namespace std::literals;
34
35 namespace android::incremental {
36
37 static constexpr auto kVoldServiceName = "vold"sv;
38 static constexpr auto kDataLoaderManagerName = "dataloader_manager"sv;
39
40 class RealVoldService : public VoldServiceWrapper {
41 public:
RealVoldService(sp<os::IVold> vold)42 RealVoldService(sp<os::IVold> vold) : mInterface(std::move(vold)) {}
43 ~RealVoldService() = default;
mountIncFs(const std::string & backingPath,const std::string & targetDir,int32_t flags,const std::string & sysfsName,os::incremental::IncrementalFileSystemControlParcel * _aidl_return) const44 binder::Status mountIncFs(
45 const std::string& backingPath, const std::string& targetDir, int32_t flags,
46 const std::string& sysfsName,
47 os::incremental::IncrementalFileSystemControlParcel* _aidl_return) const final {
48 return mInterface->mountIncFs(backingPath, targetDir, flags, sysfsName, _aidl_return);
49 }
unmountIncFs(const std::string & dir) const50 binder::Status unmountIncFs(const std::string& dir) const final {
51 return mInterface->unmountIncFs(dir);
52 }
bindMount(const std::string & sourceDir,const std::string & targetDir) const53 binder::Status bindMount(const std::string& sourceDir,
54 const std::string& targetDir) const final {
55 return mInterface->bindMount(sourceDir, targetDir);
56 }
setIncFsMountOptions(const::android::os::incremental::IncrementalFileSystemControlParcel & control,bool enableReadLogs,bool enableReadTimeouts,const std::string & sysfsName) const57 binder::Status setIncFsMountOptions(
58 const ::android::os::incremental::IncrementalFileSystemControlParcel& control,
59 bool enableReadLogs, bool enableReadTimeouts,
60 const std::string& sysfsName) const final {
61 return mInterface->setIncFsMountOptions(control, enableReadLogs, enableReadTimeouts,
62 sysfsName);
63 }
64
65 private:
66 sp<os::IVold> mInterface;
67 };
68
69 class RealDataLoaderManager : public DataLoaderManagerWrapper {
70 public:
RealDataLoaderManager(sp<content::pm::IDataLoaderManager> manager)71 RealDataLoaderManager(sp<content::pm::IDataLoaderManager> manager)
72 : mInterface(std::move(manager)) {}
73 ~RealDataLoaderManager() = default;
bindToDataLoader(MountId mountId,const content::pm::DataLoaderParamsParcel & params,int bindDelayMs,const sp<content::pm::IDataLoaderStatusListener> & listener,bool * _aidl_return) const74 binder::Status bindToDataLoader(MountId mountId,
75 const content::pm::DataLoaderParamsParcel& params,
76 int bindDelayMs,
77 const sp<content::pm::IDataLoaderStatusListener>& listener,
78 bool* _aidl_return) const final {
79 return mInterface->bindToDataLoader(mountId, params, bindDelayMs, listener, _aidl_return);
80 }
getDataLoader(MountId mountId,sp<content::pm::IDataLoader> * _aidl_return) const81 binder::Status getDataLoader(MountId mountId,
82 sp<content::pm::IDataLoader>* _aidl_return) const final {
83 return mInterface->getDataLoader(mountId, _aidl_return);
84 }
unbindFromDataLoader(MountId mountId) const85 binder::Status unbindFromDataLoader(MountId mountId) const final {
86 return mInterface->unbindFromDataLoader(mountId);
87 }
88
89 private:
90 sp<content::pm::IDataLoaderManager> mInterface;
91 };
92
93 class RealAppOpsManager : public AppOpsManagerWrapper {
94 public:
95 ~RealAppOpsManager() = default;
checkPermission(const char * permission,const char * operation,const char * package) const96 binder::Status checkPermission(const char* permission, const char* operation,
97 const char* package) const final {
98 return android::incremental::CheckPermissionForDataDelivery(permission, operation, package);
99 }
startWatchingMode(int32_t op,const String16 & packageName,const sp<IAppOpsCallback> & callback)100 void startWatchingMode(int32_t op, const String16& packageName,
101 const sp<IAppOpsCallback>& callback) final {
102 mAppOpsManager.startWatchingMode(op, packageName, callback);
103 }
stopWatchingMode(const sp<IAppOpsCallback> & callback)104 void stopWatchingMode(const sp<IAppOpsCallback>& callback) final {
105 mAppOpsManager.stopWatchingMode(callback);
106 }
107
108 private:
109 android::AppOpsManager mAppOpsManager;
110 };
111
112 class RealJniWrapper final : public JniWrapper {
113 public:
114 RealJniWrapper(JavaVM* jvm);
115 void initializeForCurrentThread() const final;
116
117 static JavaVM* getJvm(JNIEnv* env);
118
119 private:
120 JavaVM* const mJvm;
121 };
122
123 class RealLooperWrapper final : public LooperWrapper {
124 public:
addFd(int fd,int ident,int events,android::Looper_callbackFunc callback,void * data)125 int addFd(int fd, int ident, int events, android::Looper_callbackFunc callback,
126 void* data) final {
127 return mLooper.addFd(fd, ident, events, callback, data);
128 }
removeFd(int fd)129 int removeFd(int fd) final { return mLooper.removeFd(fd); }
wake()130 void wake() final { return mLooper.wake(); }
pollAll(int timeoutMillis)131 int pollAll(int timeoutMillis) final { return mLooper.pollAll(timeoutMillis); }
132
133 private:
134 struct Looper : public android::Looper {
Looperandroid::incremental::RealLooperWrapper::Looper135 Looper() : android::Looper(/*allowNonCallbacks=*/false) {}
~Looperandroid::incremental::RealLooperWrapper::Looper136 ~Looper() {}
137 } mLooper;
138 };
139
toString(FileId fileId)140 std::string IncFsWrapper::toString(FileId fileId) {
141 return incfs::toString(fileId);
142 }
143
144 class RealIncFs final : public IncFsWrapper {
145 public:
146 RealIncFs() = default;
147 ~RealIncFs() final = default;
features() const148 Features features() const final { return incfs::features(); }
listExistingMounts(const ExistingMountCallback & cb) const149 void listExistingMounts(const ExistingMountCallback& cb) const final {
150 for (auto mount : incfs::defaultMountRegistry().copyMounts()) {
151 auto binds = mount.binds(); // span() doesn't like rvalue containers, needs to save it.
152 cb(mount.root(), mount.backingDir(), binds);
153 }
154 }
openMount(std::string_view path) const155 Control openMount(std::string_view path) const final { return incfs::open(path); }
createControl(IncFsFd cmd,IncFsFd pendingReads,IncFsFd logs,IncFsFd blocksWritten) const156 Control createControl(IncFsFd cmd, IncFsFd pendingReads, IncFsFd logs,
157 IncFsFd blocksWritten) const final {
158 return incfs::createControl(cmd, pendingReads, logs, blocksWritten);
159 }
makeFile(const Control & control,std::string_view path,int mode,FileId id,incfs::NewFileParams params) const160 ErrorCode makeFile(const Control& control, std::string_view path, int mode, FileId id,
161 incfs::NewFileParams params) const final {
162 return incfs::makeFile(control, path, mode, id, params);
163 }
makeMappedFile(const Control & control,std::string_view path,int mode,incfs::NewMappedFileParams params) const164 ErrorCode makeMappedFile(const Control& control, std::string_view path, int mode,
165 incfs::NewMappedFileParams params) const final {
166 return incfs::makeMappedFile(control, path, mode, params);
167 }
makeDir(const Control & control,std::string_view path,int mode) const168 ErrorCode makeDir(const Control& control, std::string_view path, int mode) const final {
169 return incfs::makeDir(control, path, mode);
170 }
makeDirs(const Control & control,std::string_view path,int mode) const171 ErrorCode makeDirs(const Control& control, std::string_view path, int mode) const final {
172 return incfs::makeDirs(control, path, mode);
173 }
getMetadata(const Control & control,FileId fileid) const174 incfs::RawMetadata getMetadata(const Control& control, FileId fileid) const final {
175 return incfs::getMetadata(control, fileid);
176 }
getMetadata(const Control & control,std::string_view path) const177 incfs::RawMetadata getMetadata(const Control& control, std::string_view path) const final {
178 return incfs::getMetadata(control, path);
179 }
getFileId(const Control & control,std::string_view path) const180 FileId getFileId(const Control& control, std::string_view path) const final {
181 return incfs::getFileId(control, path);
182 }
countFilledBlocks(const Control & control,std::string_view path) const183 std::pair<IncFsBlockIndex, IncFsBlockIndex> countFilledBlocks(
184 const Control& control, std::string_view path) const final {
185 if (incfs::features() & Features::v2) {
186 const auto counts = incfs::getBlockCount(control, path);
187 if (!counts) {
188 return {-errno, -errno};
189 }
190 return {counts->filledDataBlocks + counts->filledHashBlocks,
191 counts->totalDataBlocks + counts->totalHashBlocks};
192 }
193 const auto fileId = incfs::getFileId(control, path);
194 const auto fd = incfs::openForSpecialOps(control, fileId);
195 int res = fd.get();
196 if (!fd.ok()) {
197 return {res, res};
198 }
199 const auto ranges = incfs::getFilledRanges(res);
200 res = ranges.first;
201 if (res) {
202 return {res, res};
203 }
204 const auto totalBlocksCount = ranges.second.internalRawRanges().endIndex;
205 int filledBlockCount = 0;
206 for (const auto& dataRange : ranges.second.dataRanges()) {
207 filledBlockCount += dataRange.size();
208 }
209 for (const auto& hashRange : ranges.second.hashRanges()) {
210 filledBlockCount += hashRange.size();
211 }
212 return {filledBlockCount, totalBlocksCount};
213 }
isFileFullyLoaded(const Control & control,std::string_view path) const214 incfs::LoadingState isFileFullyLoaded(const Control& control,
215 std::string_view path) const final {
216 return incfs::isFullyLoaded(control, path);
217 }
isFileFullyLoaded(const Control & control,FileId id) const218 incfs::LoadingState isFileFullyLoaded(const Control& control, FileId id) const final {
219 return incfs::isFullyLoaded(control, id);
220 }
isEverythingFullyLoaded(const Control & control) const221 incfs::LoadingState isEverythingFullyLoaded(const Control& control) const final {
222 return incfs::isEverythingFullyLoaded(control);
223 }
link(const Control & control,std::string_view from,std::string_view to) const224 ErrorCode link(const Control& control, std::string_view from, std::string_view to) const final {
225 return incfs::link(control, from, to);
226 }
unlink(const Control & control,std::string_view path) const227 ErrorCode unlink(const Control& control, std::string_view path) const final {
228 return incfs::unlink(control, path);
229 }
openForSpecialOps(const Control & control,FileId id) const230 incfs::UniqueFd openForSpecialOps(const Control& control, FileId id) const final {
231 return incfs::openForSpecialOps(control, id);
232 }
writeBlocks(std::span<const incfs::DataBlock> blocks) const233 ErrorCode writeBlocks(std::span<const incfs::DataBlock> blocks) const final {
234 return incfs::writeBlocks({blocks.data(), size_t(blocks.size())});
235 }
reserveSpace(const Control & control,FileId id,IncFsSize size) const236 ErrorCode reserveSpace(const Control& control, FileId id, IncFsSize size) const final {
237 return incfs::reserveSpace(control, id, size);
238 }
waitForPendingReads(const Control & control,std::chrono::milliseconds timeout,std::vector<incfs::ReadInfoWithUid> * pendingReadsBuffer) const239 WaitResult waitForPendingReads(
240 const Control& control, std::chrono::milliseconds timeout,
241 std::vector<incfs::ReadInfoWithUid>* pendingReadsBuffer) const final {
242 return incfs::waitForPendingReads(control, timeout, pendingReadsBuffer);
243 }
setUidReadTimeouts(const Control & control,const std::vector<android::os::incremental::PerUidReadTimeouts> & perUidReadTimeouts) const244 ErrorCode setUidReadTimeouts(const Control& control,
245 const std::vector<android::os::incremental::PerUidReadTimeouts>&
246 perUidReadTimeouts) const final {
247 std::vector<incfs::UidReadTimeouts> timeouts(perUidReadTimeouts.size());
248 for (int i = 0, size = perUidReadTimeouts.size(); i < size; ++i) {
249 auto& timeout = timeouts[i];
250 const auto& perUidTimeout = perUidReadTimeouts[i];
251 timeout.uid = perUidTimeout.uid;
252 timeout.minTimeUs = perUidTimeout.minTimeUs;
253 timeout.minPendingTimeUs = perUidTimeout.minPendingTimeUs;
254 timeout.maxPendingTimeUs = perUidTimeout.maxPendingTimeUs;
255 }
256 return incfs::setUidReadTimeouts(control, timeouts);
257 }
forEachFile(const Control & control,FileCallback cb) const258 ErrorCode forEachFile(const Control& control, FileCallback cb) const final {
259 return incfs::forEachFile(control,
260 [&](auto& control, FileId id) { return cb(control, id); });
261 }
forEachIncompleteFile(const Control & control,FileCallback cb) const262 ErrorCode forEachIncompleteFile(const Control& control, FileCallback cb) const final {
263 return incfs::forEachIncompleteFile(control, [&](auto& control, FileId id) {
264 return cb(control, id);
265 });
266 }
getMetrics(std::string_view sysfsName) const267 std::optional<Metrics> getMetrics(std::string_view sysfsName) const final {
268 return incfs::getMetrics(sysfsName);
269 }
getLastReadError(const Control & control) const270 std::optional<LastReadError> getLastReadError(const Control& control) const final {
271 return incfs::getLastReadError(control);
272 }
273 };
274
275 static JNIEnv* getOrAttachJniEnv(JavaVM* jvm);
276
277 class RealTimedQueueWrapper final : public TimedQueueWrapper {
278 public:
RealTimedQueueWrapper(JavaVM * jvm)279 RealTimedQueueWrapper(JavaVM* jvm) {
280 mThread = std::thread([this, jvm]() {
281 (void)getOrAttachJniEnv(jvm);
282 runTimers();
283 });
284 }
~RealTimedQueueWrapper()285 ~RealTimedQueueWrapper() final {
286 CHECK(!mRunning) << "call stop first";
287 CHECK(!mThread.joinable()) << "call stop first";
288 }
289
addJob(MountId id,Milliseconds timeout,Job what)290 void addJob(MountId id, Milliseconds timeout, Job what) final {
291 const auto now = Clock::now();
292 {
293 std::unique_lock lock(mMutex);
294 mJobs.insert(TimedJob{id, now + timeout, std::move(what)});
295 }
296 mCondition.notify_all();
297 }
removeJobs(MountId id)298 void removeJobs(MountId id) final {
299 std::unique_lock lock(mMutex);
300 std::erase_if(mJobs, [id](auto&& item) { return item.id == id; });
301 }
stop()302 void stop() final {
303 {
304 std::unique_lock lock(mMutex);
305 mRunning = false;
306 }
307 mCondition.notify_all();
308 mThread.join();
309 mJobs.clear();
310 }
311
312 private:
runTimers()313 void runTimers() {
314 static constexpr TimePoint kInfinityTs{Clock::duration::max()};
315 std::unique_lock lock(mMutex);
316 for (;;) {
317 const TimePoint nextJobTs = mJobs.empty() ? kInfinityTs : mJobs.begin()->when;
318 auto conditionPredicate = [this, oldNextJobTs = nextJobTs]() {
319 const auto now = Clock::now();
320 const auto newFirstJobTs = !mJobs.empty() ? mJobs.begin()->when : kInfinityTs;
321 return newFirstJobTs <= now || newFirstJobTs < oldNextJobTs || !mRunning;
322 };
323 // libcxx's implementation of wait_until() recalculates the 'until' time into
324 // the wait duration and then goes back to the absolute timestamp when calling
325 // pthread_cond_timedwait(); this back-and-forth calculation sometimes loses
326 // the 'infinity' value because enough time passes in between, and instead
327 // passes incorrect timestamp into the syscall, causing a crash.
328 // Mitigating it by explicitly calling the non-timed wait here.
329 if (mJobs.empty()) {
330 mCondition.wait(lock, conditionPredicate);
331 } else {
332 mCondition.wait_until(lock, nextJobTs, conditionPredicate);
333 }
334 if (!mRunning) {
335 return;
336 }
337
338 const auto now = Clock::now();
339 // Always re-acquire begin(). We can't use it after unlock as mTimedJobs can change.
340 for (auto it = mJobs.begin(); it != mJobs.end() && it->when <= now;
341 it = mJobs.begin()) {
342 auto jobNode = mJobs.extract(it);
343
344 lock.unlock();
345 jobNode.value().what();
346 lock.lock();
347 }
348 }
349 }
350
351 struct TimedJob {
352 MountId id;
353 TimePoint when;
354 Job what;
operator <(const TimedJob & lhs,const TimedJob & rhs)355 friend bool operator<(const TimedJob& lhs, const TimedJob& rhs) {
356 return lhs.when < rhs.when;
357 }
358 };
359 bool mRunning = true;
360 std::multiset<TimedJob> mJobs;
361 std::condition_variable mCondition;
362 std::mutex mMutex;
363 std::thread mThread;
364 };
365
366 class RealFsWrapper final : public FsWrapper {
367 public:
368 RealFsWrapper() = default;
369 ~RealFsWrapper() = default;
370
listFilesRecursive(std::string_view directoryPath,FileCallback onFile) const371 void listFilesRecursive(std::string_view directoryPath, FileCallback onFile) const final {
372 for (const auto& entry : std::filesystem::recursive_directory_iterator(directoryPath)) {
373 if (!entry.is_regular_file()) {
374 continue;
375 }
376 if (!onFile(entry.path().native())) {
377 break;
378 }
379 }
380 }
381 };
382
383 class RealClockWrapper final : public ClockWrapper {
384 public:
385 RealClockWrapper() = default;
386 ~RealClockWrapper() = default;
387
now() const388 TimePoint now() const final { return Clock::now(); }
389 };
390
RealServiceManager(sp<IServiceManager> serviceManager,JNIEnv * env)391 RealServiceManager::RealServiceManager(sp<IServiceManager> serviceManager, JNIEnv* env)
392 : mServiceManager(std::move(serviceManager)), mJvm(RealJniWrapper::getJvm(env)) {}
393
394 template <class INTERFACE>
getRealService(std::string_view serviceName) const395 sp<INTERFACE> RealServiceManager::getRealService(std::string_view serviceName) const {
396 sp<IBinder> binder =
397 mServiceManager->getService(String16(serviceName.data(), serviceName.size()));
398 if (!binder) {
399 return nullptr;
400 }
401 return interface_cast<INTERFACE>(binder);
402 }
403
getVoldService()404 std::unique_ptr<VoldServiceWrapper> RealServiceManager::getVoldService() {
405 sp<os::IVold> vold = RealServiceManager::getRealService<os::IVold>(kVoldServiceName);
406 if (vold != 0) {
407 return std::make_unique<RealVoldService>(vold);
408 }
409 return nullptr;
410 }
411
getDataLoaderManager()412 std::unique_ptr<DataLoaderManagerWrapper> RealServiceManager::getDataLoaderManager() {
413 sp<content::pm::IDataLoaderManager> manager =
414 RealServiceManager::getRealService<content::pm::IDataLoaderManager>(
415 kDataLoaderManagerName);
416 if (manager) {
417 return std::make_unique<RealDataLoaderManager>(manager);
418 }
419 return nullptr;
420 }
421
getIncFs()422 std::unique_ptr<IncFsWrapper> RealServiceManager::getIncFs() {
423 return std::make_unique<RealIncFs>();
424 }
425
getAppOpsManager()426 std::unique_ptr<AppOpsManagerWrapper> RealServiceManager::getAppOpsManager() {
427 return std::make_unique<RealAppOpsManager>();
428 }
429
getJni()430 std::unique_ptr<JniWrapper> RealServiceManager::getJni() {
431 return std::make_unique<RealJniWrapper>(mJvm);
432 }
433
getLooper()434 std::unique_ptr<LooperWrapper> RealServiceManager::getLooper() {
435 return std::make_unique<RealLooperWrapper>();
436 }
437
getTimedQueue()438 std::unique_ptr<TimedQueueWrapper> RealServiceManager::getTimedQueue() {
439 return std::make_unique<RealTimedQueueWrapper>(mJvm);
440 }
441
getProgressUpdateJobQueue()442 std::unique_ptr<TimedQueueWrapper> RealServiceManager::getProgressUpdateJobQueue() {
443 return std::make_unique<RealTimedQueueWrapper>(mJvm);
444 }
445
getFs()446 std::unique_ptr<FsWrapper> RealServiceManager::getFs() {
447 return std::make_unique<RealFsWrapper>();
448 }
449
getClock()450 std::unique_ptr<ClockWrapper> RealServiceManager::getClock() {
451 return std::make_unique<RealClockWrapper>();
452 }
453
getJavaVm(JNIEnv * env)454 static JavaVM* getJavaVm(JNIEnv* env) {
455 CHECK(env);
456 JavaVM* jvm = nullptr;
457 env->GetJavaVM(&jvm);
458 CHECK(jvm);
459 return jvm;
460 }
461
getJniEnv(JavaVM * vm)462 static JNIEnv* getJniEnv(JavaVM* vm) {
463 JNIEnv* env;
464 if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
465 return nullptr;
466 }
467 return env;
468 }
469
getOrAttachJniEnv(JavaVM * jvm)470 static JNIEnv* getOrAttachJniEnv(JavaVM* jvm) {
471 if (!jvm) {
472 LOG(ERROR) << "No JVM instance";
473 return nullptr;
474 }
475
476 JNIEnv* env = getJniEnv(jvm);
477 if (!env) {
478 int result = jvm->AttachCurrentThread(&env, nullptr);
479 if (result != JNI_OK) {
480 LOG(ERROR) << "JVM thread attach failed: " << result;
481 return nullptr;
482 }
483 struct VmDetacher {
484 VmDetacher(JavaVM* vm) : mVm(vm) {}
485 ~VmDetacher() { mVm->DetachCurrentThread(); }
486
487 private:
488 JavaVM* const mVm;
489 };
490 static thread_local VmDetacher detacher(jvm);
491 }
492
493 return env;
494 }
495
RealJniWrapper(JavaVM * jvm)496 RealJniWrapper::RealJniWrapper(JavaVM* jvm) : mJvm(jvm) {
497 CHECK(!!mJvm) << "JVM is unavailable";
498 }
499
initializeForCurrentThread() const500 void RealJniWrapper::initializeForCurrentThread() const {
501 (void)getOrAttachJniEnv(mJvm);
502 }
503
getJvm(JNIEnv * env)504 JavaVM* RealJniWrapper::getJvm(JNIEnv* env) {
505 return getJavaVm(env);
506 }
507
508 } // namespace android::incremental
509