#pragma once #include #include #include #include #include class ApexUpdateListener { private: struct Sigil {}; public: // Information extracted from updated /apex/apex-info-list.xml struct Info { std::string module_name; std::string module_path; std::string preinstalled_module_path; int64_t version_code; std::string version_name; bool is_factory; bool is_active; auto AsTuple() const { return std::make_tuple(is_active, is_factory, version_code, version_name, module_path, preinstalled_module_path, module_name); } bool operator<(const Info& other) const { return AsTuple() < other.AsTuple(); } bool operator==(const ApexUpdateListener::Info& other) const { return !(other < *this) && !(*this < other); } bool operator!=(const ApexUpdateListener::Info& other) const { return !(*this == other); } template friend auto& operator<<(T& stream, const ApexUpdateListener::Info& i) { return stream << "{ moduleName: " << i.module_name << ", modulePath: " << i.module_path << ", preinstalledModulePath: " << i.preinstalled_module_path << ", versionCode: " << i.version_code << ", versionName: " << i.version_name << ", i.isFactory: " << i.is_factory << ", i.isActive: " << i.is_active << " }"; } template friend auto& operator<<(T& stream, const std::set& s) { stream << "{"; std::string sep = ""; for (auto& i : s) { stream << sep << i; sep = ", "; } return stream << "}"; } }; using CallbackFunction = std::function& last_versions, const std::set& current_versions)>; ApexUpdateListener(Sigil, const std::string& apex_name, const std::string& apex_info_list_file_name, CallbackFunction callback, int fd, int wd, const std::set& last_info); static std::unique_ptr Make( const std::string& apex_name, CallbackFunction callback, bool invoke_with_initial_version = false, const std::string& apex_info_list_file_name = "/apex/apex-info-list.xml"); // We need some cleanup handling ~ApexUpdateListener(); private: const std::string apex_name_; const std::string apex_info_list_file_name_; const CallbackFunction callback_function_; std::atomic running_ = true; int file_descriptor_ = -1; int watch_descriptor_ = -1; std::set last_info_; std::thread thread_; void ThreadFunction(); static std::optional> TrySlurpInfo( const std::string& apex_name, const std::string& apex_info_list_file_name); };