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