| // Copyright 2018 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef DLCSERVICE_DLC_SERVICE_H_ |
| #define DLCSERVICE_DLC_SERVICE_H_ |
| |
| #include <memory> |
| #include <optional> |
| #include <set> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include <base/files/file_path.h> |
| #include <base/memory/weak_ptr.h> |
| #include <brillo/dbus/dbus_method_response.h> |
| #include <brillo/errors/error.h> |
| #include <brillo/message_loops/message_loop.h> |
| #include <dlcservice/proto_bindings/dlcservice.pb.h> |
| #include <gtest/gtest_prod.h> // for FRIEND_TEST |
| #include <imageloader/proto_bindings/imageloader.pb.h> |
| #include <imageloader/dbus-proxies.h> |
| |
| #include "dlcservice/dlc_base.h" |
| #include "dlcservice/dlc_creator_interface.h" |
| #include "dlcservice/installer.h" |
| #include "dlcservice/system_state.h" |
| #include "dlcservice/types.h" |
| #include "dlcservice/utils/utils_interface.h" |
| |
| namespace dlcservice { |
| |
| class DlcServiceInterface { |
| public: |
| virtual ~DlcServiceInterface() = default; |
| |
| // Initializes the state of dlcservice. |
| virtual void Initialize() = 0; |
| |
| // DLC Installation Flow |
| // |
| // To start an install, the initial requirement is to call this function. |
| // During this phase, all necessary setup for installer to successfully |
| // install DLC(s) and other files that require creation are handled. |
| // Args: |
| // install_request: The DLC install request. |
| // response: The DBus method response to respond on. |
| virtual void Install( |
| const InstallRequest& install_request, |
| std::unique_ptr<brillo::dbus_utils::DBusMethodResponse<>> response) = 0; |
| |
| // DLC Uninstall/Purge Flow |
| // |
| // To delete the DLC this can be invoked, no prior step is required. |
| // Args: |
| // id: The DLC ID that is to be uninstalled. |
| // err: The error that's set when returned false. |
| // Return: |
| // True if the DLC with the ID passed in is successfully uninstalled, |
| // otherwise false. Deleting a valid DLC that's not installed is considered |
| // successfully uninstalled, however uninstalling a DLC that's not supported |
| // is a failure. Uninstalling a DLC that is installing is also a failure. |
| virtual bool Uninstall(const std::string& id, brillo::ErrorPtr* err) = 0; |
| |
| // Create DLC slots and load deployed DLC image into the slots. |
| // Args: |
| // id: The DLC ID that is to be deployed. |
| // err: The error that's set when returned false. |
| // Return: |
| // True on success, otherwise false. |
| virtual bool Deploy(const DlcId& id, brillo::ErrorPtr* err) = 0; |
| |
| // Returns a reference to a DLC object given a DLC ID. If the ID is not |
| // supported, it will set the error and return |nullptr|. |
| virtual DlcInterface* GetDlc(const DlcId& id, brillo::ErrorPtr* err) = 0; |
| |
| // Returns the list of installed DLCs. |
| virtual DlcIdList GetInstalled(const ListRequest& list_request) = 0; |
| |
| // Returns the list of DLCs with installed content. |
| virtual DlcIdList GetExistingDlcs() = 0; |
| |
| // Unmount DLCs and change their states to `NOT_INSTALLED`. |
| virtual bool Unload(const std::string& id, brillo::ErrorPtr* err) = 0; |
| virtual bool Unload(const SelectDlc& select, |
| const base::FilePath& mount_base, |
| brillo::ErrorPtr* err) = 0; |
| |
| // Returns the list of DLCs that need to be updated. |
| virtual DlcIdList GetDlcsToUpdate() = 0; |
| |
| // Persists the verified pref for given DLC(s) on install completion. |
| virtual bool InstallCompleted(const DlcIdList& ids, |
| brillo::ErrorPtr* err) = 0; |
| |
| // Persists the verified pref for given DLC(s) on update completion. |
| virtual bool UpdateCompleted(const DlcIdList& ids, brillo::ErrorPtr* err) = 0; |
| }; |
| |
| // DlcService manages life-cycles of DLCs (Downloadable Content) and provides an |
| // API for the rest of the system to install/uninstall DLCs. |
| class DlcService : public DlcServiceInterface, |
| public InstallerInterface::Observer { |
| public: |
| static constexpr base::TimeDelta kUECheckTimeout = base::Seconds(5); |
| |
| DlcService(std::unique_ptr<DlcCreatorInterface> dlc_creator, |
| std::shared_ptr<UtilsInterface> utils); |
| ~DlcService() override; |
| |
| void Initialize() override; |
| void Install(const InstallRequest& install_request, |
| std::unique_ptr<brillo::dbus_utils::DBusMethodResponse<>> |
| response) override; |
| bool Uninstall(const std::string& id, brillo::ErrorPtr* err) override; |
| bool Deploy(const DlcId& id, brillo::ErrorPtr* err) override; |
| DlcIdList GetInstalled(const ListRequest& list_request) override; |
| DlcIdList GetExistingDlcs() override; |
| bool Unload(const std::string& id, brillo::ErrorPtr* err) override; |
| bool Unload(const SelectDlc& select, |
| const base::FilePath& mount_base, |
| brillo::ErrorPtr* err) override; |
| DlcInterface* GetDlc(const DlcId& id, brillo::ErrorPtr* err) override; |
| DlcIdList GetDlcsToUpdate() override; |
| bool InstallCompleted(const DlcIdList& ids, brillo::ErrorPtr* err) override; |
| bool UpdateCompleted(const DlcIdList& ids, brillo::ErrorPtr* err) override; |
| |
| // Overrides for `InstallerInterface::Observer`. |
| void OnStatusSync(const InstallerInterface::Status& status) override; |
| |
| // For testing only. |
| void SetSupportedForTesting(DlcMap supported) { |
| supported_ = std::move(supported); |
| } |
| |
| private: |
| friend class DlcServiceTest; |
| friend class DlcServiceTestLegacy; |
| FRIEND_TEST(DlcServiceTestLegacy, InstallCannotSetDlcActiveValue); |
| FRIEND_TEST(DlcServiceTestLegacy, OnStatusUpdateSignalTest); |
| FRIEND_TEST(DlcServiceTestLegacy, MountFailureTest); |
| FRIEND_TEST(DlcServiceTestLegacy, OnStatusUpdateSignalDlcRootTest); |
| FRIEND_TEST(DlcServiceTestLegacy, OnStatusUpdateSignalNoRemountTest); |
| FRIEND_TEST(DlcServiceTestLegacy, ReportingFailureCleanupTest); |
| FRIEND_TEST(DlcServiceTestLegacy, ReportingFailureSignalTest); |
| FRIEND_TEST(DlcServiceTestLegacy, SignalToleranceCapTest); |
| FRIEND_TEST(DlcServiceTestLegacy, SignalToleranceCapResetTest); |
| FRIEND_TEST(DlcServiceTestLegacy, OnStatusUpdateSignalDownloadProgressTest); |
| FRIEND_TEST( |
| DlcServiceTestLegacy, |
| OnStatusUpdateSignalSubsequentialBadOrNonInstalledDlcsNonBlocking); |
| FRIEND_TEST(DlcServiceTestLegacy, PeriodicInstallCheck); |
| FRIEND_TEST(DlcServiceTestLegacy, InstallSchedulesPeriodicInstallCheck); |
| |
| // Install the DLC with installer. |
| void InstallViaInstaller( |
| const InstallRequest& install_request, |
| std::unique_ptr<brillo::dbus_utils::DBusMethodResponse<>> response); |
| |
| // Finishes the currently running installation. Returns true if the |
| // installation finished successfully, false otherwise. |
| bool FinishInstall(brillo::ErrorPtr* err); |
| FRIEND_TEST(DlcServiceTest, FinishInstallTestNothingInstalling); |
| FRIEND_TEST(DlcServiceTest, FinishInstallTestUnsupported); |
| FRIEND_TEST(DlcServiceTest, FinishInstallTestNotInstalling); |
| FRIEND_TEST(DlcServiceTest, FinishInstallTestSuccess); |
| |
| // Cancels the currently running installation. |
| // The |err_in| argument is the error that causes the install to be cancelled. |
| void CancelInstall(const brillo::ErrorPtr& err_in); |
| FRIEND_TEST(DlcServiceTest, CancelInstallNoOpTest); |
| FRIEND_TEST(DlcServiceTest, CancelInstallNotInstallingResetsTest); |
| FRIEND_TEST(DlcServiceTest, CancelInstallDlcCancelFailureResetsTest); |
| FRIEND_TEST(DlcServiceTest, CancelInstallResetsTest); |
| |
| // Handles status from installer. Returns true if the installation is going |
| // fine, false otherwise. |
| bool HandleStatus(brillo::ErrorPtr* err); |
| |
| // The periodic check that runs as a delayed task that checks installer |
| // status during an install to make sure installer is active. This is |
| // basically a fallback mechanism in case we miss some of the installer's |
| // signals so we don't block forever. |
| void PeriodicInstallCheck(); |
| |
| // Schedules the method |PeriodicInstallCheck()| to be ran at a later time, |
| void SchedulePeriodicInstallCheck(); |
| |
| // Callback when interacting with installer. |
| void OnInstallSuccess( |
| base::OnceCallback<void(brillo::ErrorPtr)> response_func); |
| void OnInstallFailure( |
| base::OnceCallback<void(brillo::ErrorPtr)> response_func, |
| brillo::Error* err); |
| |
| FRIEND_TEST(DlcServiceTest, OnInstallFailure); |
| |
| FRIEND_TEST(DlcServiceTest, |
| OnStatusUpdateAdvancedSignalConnectedTestVerifyFailureAlert); |
| |
| // Called on when installer service becomes available. |
| void OnReadyInstaller(bool available); |
| |
| // Perform an action on mounted DLCs, optionally only on selected ones. |
| // Returns the number of DLCs that failed to perform the action. |
| int MountedDlcsAction(const base::FilePath& mount_base, |
| std::optional<SelectDlc> select, |
| const std::function<bool(DlcInterface*)>& action); |
| |
| // Get the sanitized ID from DLC if it exists, otherwise return unchanged ID. |
| std::string SanitizeId(DlcId id); |
| |
| // Removes all unsupported/deprecated DLCs. |
| void CleanupUnsupported(); |
| FRIEND_TEST(DlcServiceTest, CleanupUnsupportedTest); |
| |
| #if USE_LVM_STATEFUL_PARTITION |
| void CleanupUnsupportedLvs(); |
| FRIEND_TEST(DlcServiceTest, CleanupUnsupportedLvsLvmFailure); |
| FRIEND_TEST(DlcServiceTest, CleanupUnsupportedLvsNoDlcs); |
| FRIEND_TEST(DlcServiceTest, CleanupUnsupportedLvsAllSupportedDlcs); |
| FRIEND_TEST(DlcServiceTest, CleanupUnsupportedLvs); |
| #endif // USE_LVM_STATEFUL_PARTITION |
| |
| // Report DLC packages storage usage metrics. |
| void ReportTotalUsedBytesOnDisk(); |
| |
| // Sends metrics daily. |
| void CheckAndReportDailyMetrics(); |
| |
| // Schedules the method |CheckAndReportDailyMetrics()| to be ran periodically. |
| void ScheduleReportDailyMetrics(); |
| |
| // Holds the DLC that is being installed by installer. |
| std::optional<DlcId> installing_dlc_id_; |
| |
| // Holds the tolerance signal count during an installation. |
| size_t tolerance_count_ = 0; |
| |
| // Holds the ML task id of the delayed |PeriodicInstallCheck()| if an install |
| // is in progress. |
| brillo::MessageLoop::TaskId periodic_install_check_id_; |
| |
| // Holds the list of supported DLCs. |
| DlcMap supported_; |
| |
| // Holds the DLC creator. |
| std::unique_ptr<DlcCreatorInterface> dlc_creator_; |
| |
| // Holds utils. |
| std::shared_ptr<UtilsInterface> utils_; |
| |
| // Holds the task id of periodic metrics reporting |
| brillo::MessageLoop::TaskId periodic_metrics_reporting_id_; |
| |
| base::WeakPtrFactory<DlcService> weak_ptr_factory_; |
| |
| DlcService(const DlcService&) = delete; |
| DlcService& operator=(const DlcService&) = delete; |
| }; |
| |
| } // namespace dlcservice |
| |
| #endif // DLCSERVICE_DLC_SERVICE_H_ |