1 #pragma once 2 3 #include <set> 4 #include <sstream> 5 #include <string> 6 #include <string_view> 7 #include <thread> 8 9 class ApexUpdateListener { 10 private: 11 struct Sigil {}; 12 13 public: 14 // Information extracted from updated /apex/apex-info-list.xml 15 struct Info { 16 std::string module_name; 17 std::string module_path; 18 std::string preinstalled_module_path; 19 int64_t version_code; 20 std::string version_name; 21 bool is_factory; 22 bool is_active; 23 AsTupleInfo24 auto AsTuple() const { 25 return std::make_tuple(is_active, is_factory, version_code, version_name, 26 module_path, preinstalled_module_path, module_name); 27 } 28 29 bool operator<(const Info& other) const { 30 return AsTuple() < other.AsTuple(); 31 } 32 33 bool operator==(const ApexUpdateListener::Info& other) const { 34 return !(other < *this) && !(*this < other); 35 } 36 bool operator!=(const ApexUpdateListener::Info& other) const { 37 return !(*this == other); 38 } 39 template <typename T> 40 friend auto& operator<<(T& stream, const ApexUpdateListener::Info& i) { 41 return stream << "{ moduleName: " << i.module_name 42 << ", modulePath: " << i.module_path 43 << ", preinstalledModulePath: " << i.preinstalled_module_path 44 << ", versionCode: " << i.version_code 45 << ", versionName: " << i.version_name 46 << ", i.isFactory: " << i.is_factory 47 << ", i.isActive: " << i.is_active << " }"; 48 } 49 template <typename T> 50 friend auto& operator<<(T& stream, 51 const std::set<ApexUpdateListener::Info>& s) { 52 stream << "{"; 53 std::string sep = ""; 54 for (auto& i : s) { 55 stream << sep << i; 56 sep = ", "; 57 } 58 return stream << "}"; 59 } 60 }; 61 62 using CallbackFunction = 63 std::function<void(const std::set<Info>& last_versions, 64 const std::set<Info>& current_versions)>; 65 66 ApexUpdateListener(Sigil, const std::string& apex_name, 67 const std::string& apex_info_list_file_name, 68 CallbackFunction callback, int fd, int wd, 69 std::set<Info> last_info); 70 71 static std::unique_ptr<ApexUpdateListener> Make( 72 const std::string& apex_name, CallbackFunction callback, 73 bool invoke_with_initial_version = false, 74 const std::string& apex_info_list_file_name = "/apex/apex-info-list.xml"); 75 76 // We need some cleanup handling 77 ~ApexUpdateListener(); 78 79 private: 80 const std::string apex_name_; 81 const std::string apex_info_list_file_name_; 82 const CallbackFunction callback_function_; 83 std::atomic<bool> running_ = true; 84 int file_descriptor_ = -1; 85 int watch_descriptor_ = -1; 86 std::set<Info> last_info_; 87 std::thread thread_; 88 89 void ThreadFunction(); 90 static std::optional<std::set<Info>> TrySlurpInfo( 91 const std::string& apex_name, const std::string& apex_info_list_file_name); 92 }; 93