Loading services/incremental/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ cc_defaults { "libbinder", "libcrypto", "libcutils", "libdataloader", "libincfs", "liblog", "libz", Loading services/incremental/IncrementalService.cpp +98 −47 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #define LOG_TAG "IncrementalService" #include "IncrementalService.h" #include "IncrementalServiceValidation.h" #include <android-base/file.h> #include <android-base/logging.h> Loading Loading @@ -50,6 +51,9 @@ using namespace std::literals; using namespace android::content::pm; namespace fs = std::filesystem; constexpr const char* kDataUsageStats = "android.permission.LOADER_USAGE_STATS"; constexpr const char* kOpUsage = "android:get_usage_stats"; namespace android::incremental { namespace { Loading Loading @@ -232,6 +236,7 @@ IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_v : mVold(sm.getVoldService()), mDataLoaderManager(sm.getDataLoaderManager()), mIncFs(sm.getIncFs()), mAppOpsManager(sm.getAppOpsManager()), mIncrementalDir(rootDir) { if (!mVold) { LOG(FATAL) << "Vold service is unavailable"; Loading @@ -239,6 +244,9 @@ IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_v if (!mDataLoaderManager) { LOG(FATAL) << "DataLoaderManagerService is unavailable"; } if (!mAppOpsManager) { LOG(FATAL) << "AppOpsManager is unavailable"; } mountExistingImages(); } Loading Loading @@ -279,12 +287,9 @@ void IncrementalService::onDump(int fd) { dprintf(fd, "\t\troot: %s\n", mnt.root.c_str()); dprintf(fd, "\t\tnextStorageDirNo: %d\n", mnt.nextStorageDirNo.load()); dprintf(fd, "\t\tdataLoaderStatus: %d\n", mnt.dataLoaderStatus.load()); dprintf(fd, "\t\tconnectionLostTime: %s\n", toString(mnt.connectionLostTime)); dprintf(fd, "\t\tsavedDataLoaderParams:\n"); if (!mnt.savedDataLoaderParams) { dprintf(fd, "\t\t\tnone\n"); } else { const auto& params = mnt.savedDataLoaderParams.value(); { const auto& params = mnt.dataLoaderParams; dprintf(fd, "\t\tdataLoaderParams:\n"); dprintf(fd, "\t\t\ttype: %s\n", toString(params.type).c_str()); dprintf(fd, "\t\t\tpackageName: %s\n", params.packageName.c_str()); dprintf(fd, "\t\t\tclassName: %s\n", params.className.c_str()); Loading Loading @@ -332,6 +337,7 @@ std::optional<std::future<void>> IncrementalService::onSystemReady() { } std::thread([this, mounts = std::move(mounts)]() { /* TODO(b/151241369): restore data loaders on reboot. for (auto&& ifs : mounts) { if (prepareDataLoader(*ifs)) { LOG(INFO) << "Successfully started data loader for mount " << ifs->mountId; Loading @@ -340,6 +346,7 @@ std::optional<std::future<void>> IncrementalService::onSystemReady() { LOG(WARNING) << "Failed to start data loader for mount " << ifs->mountId; } } */ mPrepareDataLoaders.set_value_at_thread_exit(); }).detach(); return mPrepareDataLoaders.get_future(); Loading Loading @@ -459,13 +466,15 @@ StorageId IncrementalService::createStorage( return kInvalidStorageId; } ifs->dataLoaderParams = std::move(dataLoaderParams); { metadata::Mount m; m.mutable_storage()->set_id(ifs->mountId); m.mutable_loader()->set_type((int)dataLoaderParams.type); m.mutable_loader()->set_package_name(dataLoaderParams.packageName); m.mutable_loader()->set_class_name(dataLoaderParams.className); m.mutable_loader()->set_arguments(dataLoaderParams.arguments); m.mutable_loader()->set_type((int)ifs->dataLoaderParams.type); m.mutable_loader()->set_package_name(ifs->dataLoaderParams.packageName); m.mutable_loader()->set_class_name(ifs->dataLoaderParams.className); m.mutable_loader()->set_arguments(ifs->dataLoaderParams.arguments); const auto metadata = m.SerializeAsString(); m.mutable_loader()->release_arguments(); m.mutable_loader()->release_class_name(); Loading Loading @@ -493,7 +502,7 @@ StorageId IncrementalService::createStorage( // Done here as well, all data structures are in good state. secondCleanupOnFailure.release(); if (!prepareDataLoader(*ifs, &dataLoaderParams, &dataLoaderStatusListener)) { if (!prepareDataLoader(*ifs, &dataLoaderStatusListener)) { LOG(ERROR) << "prepareDataLoader() failed"; deleteStorageLocked(*ifs, std::move(l)); return kInvalidStorageId; Loading Loading @@ -573,11 +582,30 @@ int IncrementalService::setStorageParams(StorageId storageId, bool enableReadLog return -EINVAL; } ifs->dataLoaderFilesystemParams.readLogsEnabled = enableReadLogs; if (enableReadLogs) { // We never unregister the callbacks, but given a restricted number of data loaders and even fewer asking for read log access, should be ok. registerAppOpsCallback(ifs->dataLoaderParams.packageName); } return applyStorageParams(*ifs); } int IncrementalService::applyStorageParams(IncFsMount& ifs) { const bool enableReadLogs = ifs.dataLoaderFilesystemParams.readLogsEnabled; if (enableReadLogs) { if (auto status = CheckPermissionForDataDelivery(kDataUsageStats, kOpUsage); !status.isOk()) { LOG(ERROR) << "CheckPermissionForDataDelivery failed: " << status.toString8(); return fromBinderStatus(status); } } using unique_fd = ::android::base::unique_fd; ::android::os::incremental::IncrementalFileSystemControlParcel control; control.cmd.reset(unique_fd(dup(ifs->control.cmd()))); control.pendingReads.reset(unique_fd(dup(ifs->control.pendingReads()))); auto logsFd = ifs->control.logs(); control.cmd.reset(unique_fd(dup(ifs.control.cmd()))); control.pendingReads.reset(unique_fd(dup(ifs.control.pendingReads()))); auto logsFd = ifs.control.logs(); if (logsFd >= 0) { control.log.reset(unique_fd(dup(logsFd))); } Loading @@ -586,12 +614,7 @@ int IncrementalService::setStorageParams(StorageId storageId, bool enableReadLog const auto status = mVold->setIncFsMountOptions(control, enableReadLogs); if (!status.isOk()) { LOG(ERROR) << "Calling Vold::setIncFsMountOptions() failed: " << status.toString8(); return status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC ? status.serviceSpecificErrorCode() > 0 ? -status.serviceSpecificErrorCode() : status.serviceSpecificErrorCode() == 0 ? -EFAULT : status.serviceSpecificErrorCode() : -EIO; return fromBinderStatus(status); } return 0; Loading Loading @@ -1015,16 +1038,26 @@ bool IncrementalService::mountExistingImage(std::string_view root) { auto ifs = std::make_shared<IncFsMount>(std::string(root), -1, std::move(control), *this); auto m = parseFromIncfs<metadata::Mount>(mIncFs.get(), ifs->control, auto mount = parseFromIncfs<metadata::Mount>(mIncFs.get(), ifs->control, path::join(mountTarget, constants().infoMdName)); if (!m.has_loader() || !m.has_storage()) { if (!mount.has_loader() || !mount.has_storage()) { LOG(ERROR) << "Bad mount metadata in mount at " << root; return false; } ifs->mountId = m.storage().id(); ifs->mountId = mount.storage().id(); mNextId = std::max(mNextId, ifs->mountId + 1); // DataLoader params { auto& dlp = ifs->dataLoaderParams; const auto& loader = mount.loader(); dlp.type = (android::content::pm::DataLoaderType)loader.type(); dlp.packageName = loader.package_name(); dlp.className = loader.class_name(); dlp.arguments = loader.arguments(); } std::vector<std::pair<std::string, metadata::BindPoint>> bindPoints; auto d = openDir(path::c_str(mountTarget)); while (auto e = ::readdir(d.get())) { Loading Loading @@ -1095,23 +1128,9 @@ bool IncrementalService::mountExistingImage(std::string_view root) { } bool IncrementalService::prepareDataLoader(IncrementalService::IncFsMount& ifs, DataLoaderParamsParcel* params, const DataLoaderStatusListener* externalListener) { if (!mSystemReady.load(std::memory_order_relaxed)) { std::unique_lock l(ifs.lock); if (params) { if (ifs.savedDataLoaderParams) { LOG(WARNING) << "Trying to pass second set of data loader parameters, ignored it"; } else { ifs.savedDataLoaderParams = std::move(*params); } } else { if (!ifs.savedDataLoaderParams) { LOG(ERROR) << "Mount " << ifs.mountId << " is broken: no data loader params (system is not ready yet)"; return false; } } return true; // eventually... } Loading @@ -1121,12 +1140,6 @@ bool IncrementalService::prepareDataLoader(IncrementalService::IncFsMount& ifs, return true; } auto* dlp = params ? params : ifs.savedDataLoaderParams ? &ifs.savedDataLoaderParams.value() : nullptr; if (!dlp) { LOG(ERROR) << "Mount " << ifs.mountId << " is broken: no data loader params"; return false; } FileSystemControlParcel fsControlParcel; fsControlParcel.incremental = aidl::make_nullable<IncrementalFileSystemControlParcel>(); fsControlParcel.incremental->cmd.reset(base::unique_fd(::dup(ifs.control.cmd()))); Loading @@ -1138,13 +1151,11 @@ bool IncrementalService::prepareDataLoader(IncrementalService::IncFsMount& ifs, externalListener ? *externalListener : DataLoaderStatusListener()); bool created = false; auto status = mDataLoaderManager->initializeDataLoader(ifs.mountId, *dlp, fsControlParcel, listener, &created); auto status = mDataLoaderManager->initializeDataLoader(ifs.mountId, ifs.dataLoaderParams, fsControlParcel, listener, &created); if (!status.isOk() || !created) { LOG(ERROR) << "Failed to create a data loader for mount " << ifs.mountId; return false; } ifs.savedDataLoaderParams.reset(); return true; } Loading Loading @@ -1268,6 +1279,42 @@ bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_ return success; } void IncrementalService::registerAppOpsCallback(const std::string& packageName) { if (packageName.empty()) { return; } { std::unique_lock lock{mCallbacksLock}; if (!mCallbackRegistered.insert(packageName).second) { return; } } /* TODO(b/152633648): restore callback after it's not crashing Binder anymore. sp<AppOpsListener> listener = new AppOpsListener(*this, packageName); mAppOpsManager->startWatchingMode(AppOpsManager::OP_GET_USAGE_STATS, String16(packageName.c_str()), listener); */ } void IncrementalService::onAppOppChanged(const std::string& packageName) { std::vector<IfsMountPtr> affected; { std::lock_guard l(mLock); affected.reserve(mMounts.size()); for (auto&& [id, ifs] : mMounts) { if (ifs->dataLoaderFilesystemParams.readLogsEnabled && ifs->dataLoaderParams.packageName == packageName) { affected.push_back(ifs); } } } /* TODO(b/152633648): restore callback after it's not crashing Kernel anymore. for (auto&& ifs : affected) { applyStorageParams(*ifs); } */ } binder::Status IncrementalService::IncrementalDataLoaderListener::onStatusChanged(MountId mountId, int newStatus) { if (externalListener) { Loading Loading @@ -1331,4 +1378,8 @@ binder::Status IncrementalService::IncrementalDataLoaderListener::onStatusChange return binder::Status::ok(); } void IncrementalService::AppOpsListener::opChanged(int32_t op, const String16&) { incrementalService.onAppOppChanged(packageName); } } // namespace android::incremental services/incremental/IncrementalService.h +30 −8 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ #include "ServiceWrappers.h" #include "android/content/pm/BnDataLoaderStatusListener.h" #include "incfs.h" #include "dataloader_ndk.h" #include "path.h" using namespace android::os::incremental; Loading Loading @@ -132,6 +133,7 @@ public: bool startLoading(StorageId storage) const; bool configureNativeBinaries(StorageId storage, std::string_view apkFullPath, std::string_view libDirRelativePath, std::string_view abi); class IncrementalDataLoaderListener : public android::content::pm::BnDataLoaderStatusListener { public: IncrementalDataLoaderListener(IncrementalService& incrementalService, Loading @@ -145,6 +147,16 @@ public: DataLoaderStatusListener externalListener; }; class AppOpsListener : public android::BnAppOpsCallback { public: AppOpsListener(IncrementalService& incrementalService, std::string packageName) : incrementalService(incrementalService), packageName(std::move(packageName)) {} void opChanged(int32_t op, const String16& packageName) override; private: IncrementalService& incrementalService; const std::string packageName; }; private: struct IncFsMount { struct Bind { Loading @@ -169,11 +181,11 @@ private: /*const*/ MountId mountId; StorageMap storages; BindMap bindPoints; std::optional<DataLoaderParamsParcel> savedDataLoaderParams; DataLoaderParamsParcel dataLoaderParams; DataLoaderFilesystemParams dataLoaderFilesystemParams; std::atomic<int> nextStorageDirNo{0}; std::atomic<int> dataLoaderStatus = -1; bool dataLoaderStartRequested = false; TimePoint connectionLostTime = TimePoint(); const IncrementalService& incrementalService; IncFsMount(std::string root, MountId mountId, Control control, Loading @@ -181,7 +193,9 @@ private: : root(std::move(root)), control(std::move(control)), mountId(mountId), incrementalService(incrementalService) {} incrementalService(incrementalService) { dataLoaderFilesystemParams.readLogsEnabled = false; } IncFsMount(IncFsMount&&) = delete; IncFsMount& operator=(IncFsMount&&) = delete; ~IncFsMount(); Loading @@ -208,8 +222,7 @@ private: std::string&& source, std::string&& target, BindKind kind, std::unique_lock<std::mutex>& mainLock); bool prepareDataLoader(IncFsMount& ifs, DataLoaderParamsParcel* params = nullptr, const DataLoaderStatusListener* externalListener = nullptr); bool prepareDataLoader(IncFsMount& ifs, const DataLoaderStatusListener* externalListener = nullptr); bool startDataLoader(MountId mountId) const; BindPathMap::const_iterator findStorageLocked(std::string_view path) const; Loading @@ -221,10 +234,16 @@ private: std::string normalizePathToStorage(const IfsMountPtr incfs, StorageId storage, std::string_view path); int applyStorageParams(IncFsMount& ifs); void registerAppOpsCallback(const std::string& packageName); void onAppOppChanged(const std::string& packageName); // Member variables std::unique_ptr<VoldServiceWrapper> mVold; std::unique_ptr<DataLoaderManagerWrapper> mDataLoaderManager; std::unique_ptr<IncFsWrapper> mIncFs; std::unique_ptr<VoldServiceWrapper> const mVold; std::unique_ptr<DataLoaderManagerWrapper> const mDataLoaderManager; std::unique_ptr<IncFsWrapper> const mIncFs; std::unique_ptr<AppOpsManagerWrapper> const mAppOpsManager; const std::string mIncrementalDir; mutable std::mutex mLock; Loading @@ -232,6 +251,9 @@ private: MountMap mMounts; BindPathMap mBindsByPath; std::mutex mCallbacksLock; std::set<std::string> mCallbackRegistered; std::atomic_bool mSystemReady = false; StorageId mNextId = 0; std::promise<void> mPrepareDataLoaders; Loading services/incremental/IncrementalServiceValidation.h 0 → 100644 +75 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <android-base/stringprintf.h> #include <binder/IPCThreadState.h> #include <binder/PermissionCache.h> #include <binder/PermissionController.h> #include <binder/Status.h> namespace android::incremental { inline binder::Status Ok() { return binder::Status::ok(); } inline binder::Status Exception(uint32_t code, const std::string& msg) { return binder::Status::fromExceptionCode(code, String8(msg.c_str())); } inline int fromBinderStatus(const binder::Status& status) { return status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC ? status.serviceSpecificErrorCode() > 0 ? -status.serviceSpecificErrorCode() : status.serviceSpecificErrorCode() == 0 ? -EFAULT : status.serviceSpecificErrorCode() : -EIO; } inline binder::Status CheckPermissionForDataDelivery(const char* permission, const char* operation) { using android::base::StringPrintf; int32_t pid; int32_t uid; if (!PermissionCache::checkCallingPermission(String16(permission), &pid, &uid)) { return Exception(binder::Status::EX_SECURITY, StringPrintf("UID %d / PID %d lacks permission %s", uid, pid, permission)); } // Caller must also have op granted. PermissionController pc; // Package is a required parameter. Need to obtain one. Vector<String16> packages; pc.getPackagesForUid(uid, packages); if (packages.empty()) { return Exception(binder::Status::EX_SECURITY, StringPrintf("UID %d / PID %d has no packages", uid, pid)); } switch (auto result = pc.noteOp(String16(operation), uid, packages[0]); result) { case PermissionController::MODE_ALLOWED: case PermissionController::MODE_DEFAULT: return binder::Status::ok(); default: return Exception(binder::Status::EX_SECURITY, StringPrintf("UID %d / PID %d lacks app-op %s, error %d", uid, pid, operation, result)); } } } // namespace android::incremental services/incremental/ServiceWrappers.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -59,4 +59,8 @@ std::unique_ptr<IncFsWrapper> RealServiceManager::getIncFs() { return std::make_unique<RealIncFs>(); } std::unique_ptr<AppOpsManagerWrapper> RealServiceManager::getAppOpsManager() { return std::make_unique<RealAppOpsManager>(); } } // namespace android::os::incremental Loading
services/incremental/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ cc_defaults { "libbinder", "libcrypto", "libcutils", "libdataloader", "libincfs", "liblog", "libz", Loading
services/incremental/IncrementalService.cpp +98 −47 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #define LOG_TAG "IncrementalService" #include "IncrementalService.h" #include "IncrementalServiceValidation.h" #include <android-base/file.h> #include <android-base/logging.h> Loading Loading @@ -50,6 +51,9 @@ using namespace std::literals; using namespace android::content::pm; namespace fs = std::filesystem; constexpr const char* kDataUsageStats = "android.permission.LOADER_USAGE_STATS"; constexpr const char* kOpUsage = "android:get_usage_stats"; namespace android::incremental { namespace { Loading Loading @@ -232,6 +236,7 @@ IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_v : mVold(sm.getVoldService()), mDataLoaderManager(sm.getDataLoaderManager()), mIncFs(sm.getIncFs()), mAppOpsManager(sm.getAppOpsManager()), mIncrementalDir(rootDir) { if (!mVold) { LOG(FATAL) << "Vold service is unavailable"; Loading @@ -239,6 +244,9 @@ IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_v if (!mDataLoaderManager) { LOG(FATAL) << "DataLoaderManagerService is unavailable"; } if (!mAppOpsManager) { LOG(FATAL) << "AppOpsManager is unavailable"; } mountExistingImages(); } Loading Loading @@ -279,12 +287,9 @@ void IncrementalService::onDump(int fd) { dprintf(fd, "\t\troot: %s\n", mnt.root.c_str()); dprintf(fd, "\t\tnextStorageDirNo: %d\n", mnt.nextStorageDirNo.load()); dprintf(fd, "\t\tdataLoaderStatus: %d\n", mnt.dataLoaderStatus.load()); dprintf(fd, "\t\tconnectionLostTime: %s\n", toString(mnt.connectionLostTime)); dprintf(fd, "\t\tsavedDataLoaderParams:\n"); if (!mnt.savedDataLoaderParams) { dprintf(fd, "\t\t\tnone\n"); } else { const auto& params = mnt.savedDataLoaderParams.value(); { const auto& params = mnt.dataLoaderParams; dprintf(fd, "\t\tdataLoaderParams:\n"); dprintf(fd, "\t\t\ttype: %s\n", toString(params.type).c_str()); dprintf(fd, "\t\t\tpackageName: %s\n", params.packageName.c_str()); dprintf(fd, "\t\t\tclassName: %s\n", params.className.c_str()); Loading Loading @@ -332,6 +337,7 @@ std::optional<std::future<void>> IncrementalService::onSystemReady() { } std::thread([this, mounts = std::move(mounts)]() { /* TODO(b/151241369): restore data loaders on reboot. for (auto&& ifs : mounts) { if (prepareDataLoader(*ifs)) { LOG(INFO) << "Successfully started data loader for mount " << ifs->mountId; Loading @@ -340,6 +346,7 @@ std::optional<std::future<void>> IncrementalService::onSystemReady() { LOG(WARNING) << "Failed to start data loader for mount " << ifs->mountId; } } */ mPrepareDataLoaders.set_value_at_thread_exit(); }).detach(); return mPrepareDataLoaders.get_future(); Loading Loading @@ -459,13 +466,15 @@ StorageId IncrementalService::createStorage( return kInvalidStorageId; } ifs->dataLoaderParams = std::move(dataLoaderParams); { metadata::Mount m; m.mutable_storage()->set_id(ifs->mountId); m.mutable_loader()->set_type((int)dataLoaderParams.type); m.mutable_loader()->set_package_name(dataLoaderParams.packageName); m.mutable_loader()->set_class_name(dataLoaderParams.className); m.mutable_loader()->set_arguments(dataLoaderParams.arguments); m.mutable_loader()->set_type((int)ifs->dataLoaderParams.type); m.mutable_loader()->set_package_name(ifs->dataLoaderParams.packageName); m.mutable_loader()->set_class_name(ifs->dataLoaderParams.className); m.mutable_loader()->set_arguments(ifs->dataLoaderParams.arguments); const auto metadata = m.SerializeAsString(); m.mutable_loader()->release_arguments(); m.mutable_loader()->release_class_name(); Loading Loading @@ -493,7 +502,7 @@ StorageId IncrementalService::createStorage( // Done here as well, all data structures are in good state. secondCleanupOnFailure.release(); if (!prepareDataLoader(*ifs, &dataLoaderParams, &dataLoaderStatusListener)) { if (!prepareDataLoader(*ifs, &dataLoaderStatusListener)) { LOG(ERROR) << "prepareDataLoader() failed"; deleteStorageLocked(*ifs, std::move(l)); return kInvalidStorageId; Loading Loading @@ -573,11 +582,30 @@ int IncrementalService::setStorageParams(StorageId storageId, bool enableReadLog return -EINVAL; } ifs->dataLoaderFilesystemParams.readLogsEnabled = enableReadLogs; if (enableReadLogs) { // We never unregister the callbacks, but given a restricted number of data loaders and even fewer asking for read log access, should be ok. registerAppOpsCallback(ifs->dataLoaderParams.packageName); } return applyStorageParams(*ifs); } int IncrementalService::applyStorageParams(IncFsMount& ifs) { const bool enableReadLogs = ifs.dataLoaderFilesystemParams.readLogsEnabled; if (enableReadLogs) { if (auto status = CheckPermissionForDataDelivery(kDataUsageStats, kOpUsage); !status.isOk()) { LOG(ERROR) << "CheckPermissionForDataDelivery failed: " << status.toString8(); return fromBinderStatus(status); } } using unique_fd = ::android::base::unique_fd; ::android::os::incremental::IncrementalFileSystemControlParcel control; control.cmd.reset(unique_fd(dup(ifs->control.cmd()))); control.pendingReads.reset(unique_fd(dup(ifs->control.pendingReads()))); auto logsFd = ifs->control.logs(); control.cmd.reset(unique_fd(dup(ifs.control.cmd()))); control.pendingReads.reset(unique_fd(dup(ifs.control.pendingReads()))); auto logsFd = ifs.control.logs(); if (logsFd >= 0) { control.log.reset(unique_fd(dup(logsFd))); } Loading @@ -586,12 +614,7 @@ int IncrementalService::setStorageParams(StorageId storageId, bool enableReadLog const auto status = mVold->setIncFsMountOptions(control, enableReadLogs); if (!status.isOk()) { LOG(ERROR) << "Calling Vold::setIncFsMountOptions() failed: " << status.toString8(); return status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC ? status.serviceSpecificErrorCode() > 0 ? -status.serviceSpecificErrorCode() : status.serviceSpecificErrorCode() == 0 ? -EFAULT : status.serviceSpecificErrorCode() : -EIO; return fromBinderStatus(status); } return 0; Loading Loading @@ -1015,16 +1038,26 @@ bool IncrementalService::mountExistingImage(std::string_view root) { auto ifs = std::make_shared<IncFsMount>(std::string(root), -1, std::move(control), *this); auto m = parseFromIncfs<metadata::Mount>(mIncFs.get(), ifs->control, auto mount = parseFromIncfs<metadata::Mount>(mIncFs.get(), ifs->control, path::join(mountTarget, constants().infoMdName)); if (!m.has_loader() || !m.has_storage()) { if (!mount.has_loader() || !mount.has_storage()) { LOG(ERROR) << "Bad mount metadata in mount at " << root; return false; } ifs->mountId = m.storage().id(); ifs->mountId = mount.storage().id(); mNextId = std::max(mNextId, ifs->mountId + 1); // DataLoader params { auto& dlp = ifs->dataLoaderParams; const auto& loader = mount.loader(); dlp.type = (android::content::pm::DataLoaderType)loader.type(); dlp.packageName = loader.package_name(); dlp.className = loader.class_name(); dlp.arguments = loader.arguments(); } std::vector<std::pair<std::string, metadata::BindPoint>> bindPoints; auto d = openDir(path::c_str(mountTarget)); while (auto e = ::readdir(d.get())) { Loading Loading @@ -1095,23 +1128,9 @@ bool IncrementalService::mountExistingImage(std::string_view root) { } bool IncrementalService::prepareDataLoader(IncrementalService::IncFsMount& ifs, DataLoaderParamsParcel* params, const DataLoaderStatusListener* externalListener) { if (!mSystemReady.load(std::memory_order_relaxed)) { std::unique_lock l(ifs.lock); if (params) { if (ifs.savedDataLoaderParams) { LOG(WARNING) << "Trying to pass second set of data loader parameters, ignored it"; } else { ifs.savedDataLoaderParams = std::move(*params); } } else { if (!ifs.savedDataLoaderParams) { LOG(ERROR) << "Mount " << ifs.mountId << " is broken: no data loader params (system is not ready yet)"; return false; } } return true; // eventually... } Loading @@ -1121,12 +1140,6 @@ bool IncrementalService::prepareDataLoader(IncrementalService::IncFsMount& ifs, return true; } auto* dlp = params ? params : ifs.savedDataLoaderParams ? &ifs.savedDataLoaderParams.value() : nullptr; if (!dlp) { LOG(ERROR) << "Mount " << ifs.mountId << " is broken: no data loader params"; return false; } FileSystemControlParcel fsControlParcel; fsControlParcel.incremental = aidl::make_nullable<IncrementalFileSystemControlParcel>(); fsControlParcel.incremental->cmd.reset(base::unique_fd(::dup(ifs.control.cmd()))); Loading @@ -1138,13 +1151,11 @@ bool IncrementalService::prepareDataLoader(IncrementalService::IncFsMount& ifs, externalListener ? *externalListener : DataLoaderStatusListener()); bool created = false; auto status = mDataLoaderManager->initializeDataLoader(ifs.mountId, *dlp, fsControlParcel, listener, &created); auto status = mDataLoaderManager->initializeDataLoader(ifs.mountId, ifs.dataLoaderParams, fsControlParcel, listener, &created); if (!status.isOk() || !created) { LOG(ERROR) << "Failed to create a data loader for mount " << ifs.mountId; return false; } ifs.savedDataLoaderParams.reset(); return true; } Loading Loading @@ -1268,6 +1279,42 @@ bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_ return success; } void IncrementalService::registerAppOpsCallback(const std::string& packageName) { if (packageName.empty()) { return; } { std::unique_lock lock{mCallbacksLock}; if (!mCallbackRegistered.insert(packageName).second) { return; } } /* TODO(b/152633648): restore callback after it's not crashing Binder anymore. sp<AppOpsListener> listener = new AppOpsListener(*this, packageName); mAppOpsManager->startWatchingMode(AppOpsManager::OP_GET_USAGE_STATS, String16(packageName.c_str()), listener); */ } void IncrementalService::onAppOppChanged(const std::string& packageName) { std::vector<IfsMountPtr> affected; { std::lock_guard l(mLock); affected.reserve(mMounts.size()); for (auto&& [id, ifs] : mMounts) { if (ifs->dataLoaderFilesystemParams.readLogsEnabled && ifs->dataLoaderParams.packageName == packageName) { affected.push_back(ifs); } } } /* TODO(b/152633648): restore callback after it's not crashing Kernel anymore. for (auto&& ifs : affected) { applyStorageParams(*ifs); } */ } binder::Status IncrementalService::IncrementalDataLoaderListener::onStatusChanged(MountId mountId, int newStatus) { if (externalListener) { Loading Loading @@ -1331,4 +1378,8 @@ binder::Status IncrementalService::IncrementalDataLoaderListener::onStatusChange return binder::Status::ok(); } void IncrementalService::AppOpsListener::opChanged(int32_t op, const String16&) { incrementalService.onAppOppChanged(packageName); } } // namespace android::incremental
services/incremental/IncrementalService.h +30 −8 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ #include "ServiceWrappers.h" #include "android/content/pm/BnDataLoaderStatusListener.h" #include "incfs.h" #include "dataloader_ndk.h" #include "path.h" using namespace android::os::incremental; Loading Loading @@ -132,6 +133,7 @@ public: bool startLoading(StorageId storage) const; bool configureNativeBinaries(StorageId storage, std::string_view apkFullPath, std::string_view libDirRelativePath, std::string_view abi); class IncrementalDataLoaderListener : public android::content::pm::BnDataLoaderStatusListener { public: IncrementalDataLoaderListener(IncrementalService& incrementalService, Loading @@ -145,6 +147,16 @@ public: DataLoaderStatusListener externalListener; }; class AppOpsListener : public android::BnAppOpsCallback { public: AppOpsListener(IncrementalService& incrementalService, std::string packageName) : incrementalService(incrementalService), packageName(std::move(packageName)) {} void opChanged(int32_t op, const String16& packageName) override; private: IncrementalService& incrementalService; const std::string packageName; }; private: struct IncFsMount { struct Bind { Loading @@ -169,11 +181,11 @@ private: /*const*/ MountId mountId; StorageMap storages; BindMap bindPoints; std::optional<DataLoaderParamsParcel> savedDataLoaderParams; DataLoaderParamsParcel dataLoaderParams; DataLoaderFilesystemParams dataLoaderFilesystemParams; std::atomic<int> nextStorageDirNo{0}; std::atomic<int> dataLoaderStatus = -1; bool dataLoaderStartRequested = false; TimePoint connectionLostTime = TimePoint(); const IncrementalService& incrementalService; IncFsMount(std::string root, MountId mountId, Control control, Loading @@ -181,7 +193,9 @@ private: : root(std::move(root)), control(std::move(control)), mountId(mountId), incrementalService(incrementalService) {} incrementalService(incrementalService) { dataLoaderFilesystemParams.readLogsEnabled = false; } IncFsMount(IncFsMount&&) = delete; IncFsMount& operator=(IncFsMount&&) = delete; ~IncFsMount(); Loading @@ -208,8 +222,7 @@ private: std::string&& source, std::string&& target, BindKind kind, std::unique_lock<std::mutex>& mainLock); bool prepareDataLoader(IncFsMount& ifs, DataLoaderParamsParcel* params = nullptr, const DataLoaderStatusListener* externalListener = nullptr); bool prepareDataLoader(IncFsMount& ifs, const DataLoaderStatusListener* externalListener = nullptr); bool startDataLoader(MountId mountId) const; BindPathMap::const_iterator findStorageLocked(std::string_view path) const; Loading @@ -221,10 +234,16 @@ private: std::string normalizePathToStorage(const IfsMountPtr incfs, StorageId storage, std::string_view path); int applyStorageParams(IncFsMount& ifs); void registerAppOpsCallback(const std::string& packageName); void onAppOppChanged(const std::string& packageName); // Member variables std::unique_ptr<VoldServiceWrapper> mVold; std::unique_ptr<DataLoaderManagerWrapper> mDataLoaderManager; std::unique_ptr<IncFsWrapper> mIncFs; std::unique_ptr<VoldServiceWrapper> const mVold; std::unique_ptr<DataLoaderManagerWrapper> const mDataLoaderManager; std::unique_ptr<IncFsWrapper> const mIncFs; std::unique_ptr<AppOpsManagerWrapper> const mAppOpsManager; const std::string mIncrementalDir; mutable std::mutex mLock; Loading @@ -232,6 +251,9 @@ private: MountMap mMounts; BindPathMap mBindsByPath; std::mutex mCallbacksLock; std::set<std::string> mCallbackRegistered; std::atomic_bool mSystemReady = false; StorageId mNextId = 0; std::promise<void> mPrepareDataLoaders; Loading
services/incremental/IncrementalServiceValidation.h 0 → 100644 +75 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <android-base/stringprintf.h> #include <binder/IPCThreadState.h> #include <binder/PermissionCache.h> #include <binder/PermissionController.h> #include <binder/Status.h> namespace android::incremental { inline binder::Status Ok() { return binder::Status::ok(); } inline binder::Status Exception(uint32_t code, const std::string& msg) { return binder::Status::fromExceptionCode(code, String8(msg.c_str())); } inline int fromBinderStatus(const binder::Status& status) { return status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC ? status.serviceSpecificErrorCode() > 0 ? -status.serviceSpecificErrorCode() : status.serviceSpecificErrorCode() == 0 ? -EFAULT : status.serviceSpecificErrorCode() : -EIO; } inline binder::Status CheckPermissionForDataDelivery(const char* permission, const char* operation) { using android::base::StringPrintf; int32_t pid; int32_t uid; if (!PermissionCache::checkCallingPermission(String16(permission), &pid, &uid)) { return Exception(binder::Status::EX_SECURITY, StringPrintf("UID %d / PID %d lacks permission %s", uid, pid, permission)); } // Caller must also have op granted. PermissionController pc; // Package is a required parameter. Need to obtain one. Vector<String16> packages; pc.getPackagesForUid(uid, packages); if (packages.empty()) { return Exception(binder::Status::EX_SECURITY, StringPrintf("UID %d / PID %d has no packages", uid, pid)); } switch (auto result = pc.noteOp(String16(operation), uid, packages[0]); result) { case PermissionController::MODE_ALLOWED: case PermissionController::MODE_DEFAULT: return binder::Status::ok(); default: return Exception(binder::Status::EX_SECURITY, StringPrintf("UID %d / PID %d lacks app-op %s, error %d", uid, pid, operation, result)); } } } // namespace android::incremental
services/incremental/ServiceWrappers.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -59,4 +59,8 @@ std::unique_ptr<IncFsWrapper> RealServiceManager::getIncFs() { return std::make_unique<RealIncFs>(); } std::unique_ptr<AppOpsManagerWrapper> RealServiceManager::getAppOpsManager() { return std::make_unique<RealAppOpsManager>(); } } // namespace android::os::incremental