1 // Copyright 2017 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CHROME_BROWSER_WIN_CONFLICTS_MODULE_DATABASE_H_ 6 #define CHROME_BROWSER_WIN_CONFLICTS_MODULE_DATABASE_H_ 7 8 #include <map> 9 #include <memory> 10 11 #include "base/memory/scoped_refptr.h" 12 #include "base/observer_list.h" 13 #include "base/sequence_checker.h" 14 #include "base/time/time.h" 15 #include "base/timer/timer.h" 16 #include "chrome/browser/win/conflicts/module_info.h" 17 #include "chrome/browser/win/conflicts/module_inspector.h" 18 #include "chrome/browser/win/conflicts/third_party_metrics_recorder.h" 19 #include "content/public/common/process_type.h" 20 21 class ModuleDatabaseObserver; 22 23 namespace base { 24 class FilePath; 25 class SequencedTaskRunner; 26 } // namespace base 27 28 #if defined(GOOGLE_CHROME_BUILD) 29 class ModuleLoadAttemptLogListener; 30 class PrefChangeRegistrar; 31 class PrefRegistrySimple; 32 class ThirdPartyConflictsManager; 33 34 namespace base { 35 struct OnTaskRunnerDeleter; 36 } 37 #endif // defined(GOOGLE_CHROME_BUILD) 38 39 // A class that keeps track of all modules loaded across Chrome processes. 40 // 41 // It is also the main class behind third-party modules tracking, and owns the 42 // different classes that required to identify incompatible applications and 43 // record metrics. 44 // 45 // This is effectively a singleton, but doesn't use base::Singleton. The intent 46 // is for the object to be created when Chrome is single-threaded, and for it 47 // be set as the process-wide singleton via SetInstance. 48 class ModuleDatabase : public ModuleDatabaseEventSource { 49 public: 50 // Structures for maintaining information about modules. 51 using ModuleMap = std::map<ModuleInfoKey, ModuleInfoData>; 52 using ModuleInfo = ModuleMap::value_type; 53 54 // The Module Database becomes idle after this timeout expires without any 55 // module events. 56 static constexpr base::TimeDelta kIdleTimeout = 57 base::TimeDelta::FromSeconds(10); 58 59 // Creates the ModuleDatabase. Must be created and set on the sequence 60 // returned by GetTaskRunner(). 61 explicit ModuleDatabase(bool third_party_blocking_policy_enabled); 62 ~ModuleDatabase() override; 63 64 // Returns the SequencedTaskRunner on which the ModuleDatabase lives. Can be 65 // called on any thread. 66 static scoped_refptr<base::SequencedTaskRunner> GetTaskRunner(); 67 68 // Retrieves the singleton global instance of the ModuleDatabase. Must only be 69 // called on the sequence returned by GetTaskRunner(). 70 static ModuleDatabase* GetInstance(); 71 72 // Sets the global instance of the ModuleDatabase. Ownership is passed to the 73 // global instance and deliberately leaked, unless manually cleaned up. This 74 // has no locking and should be called when Chrome is single threaded. 75 static void SetInstance(std::unique_ptr<ModuleDatabase> module_database); 76 77 // Initializes the ModuleLoadAttemptLogListener instance. This function is a 78 // noop on non-GOOGLE_CHROME_BUILD configurations because it is used only for 79 // third-party software blocking, which is only enabled in Google Chrome 80 // builds. 81 void StartDrainingModuleLoadAttemptsLog(); 82 83 // Returns true if the ModuleDatabase is idle. This means that no modules are 84 // currently being inspected, and no new module events have been observed in 85 // the last 10 seconds. 86 bool IsIdle(); 87 88 // Indicates that a new registered shell extension was found. 89 void OnShellExtensionEnumerated(const base::FilePath& path, 90 uint32_t size_of_image, 91 uint32_t time_date_stamp); 92 93 // Indicates that all shell extensions have been enumerated. 94 void OnShellExtensionEnumerationFinished(); 95 96 // Indicates that a new registered input method editor was found. 97 void OnImeEnumerated(const base::FilePath& path, 98 uint32_t size_of_image, 99 uint32_t time_date_stamp); 100 101 // Indicates that all input method editors have been enumerated. 102 void OnImeEnumerationFinished(); 103 104 // Indicates that a module has been loaded. The data passed to this function 105 // is taken as gospel, so if it originates from a remote process it should be 106 // independently validated first. (In practice, see ModuleEventSinkImpl for 107 // details of where this happens.) 108 void OnModuleLoad(content::ProcessType process_type, 109 const base::FilePath& module_path, 110 uint32_t module_size, 111 uint32_t module_time_date_stamp); 112 113 // Forwards the module load event to the ModuleDatabase global instance via 114 // OnModuleLoad() on the ModuleDatabase task runner. Can be called on any 115 // threads. Provided for convenience. 116 static void HandleModuleLoadEvent(content::ProcessType process_type, 117 const base::FilePath& module_path, 118 uint32_t module_size, 119 uint32_t module_time_date_stamp); 120 121 void OnModuleBlocked(const base::FilePath& module_path, 122 uint32_t module_size, 123 uint32_t module_time_date_stamp); 124 125 // Marks the module as added to the module blacklist cache, which means it 126 // will be blocked on the next browser launch. 127 void OnModuleAddedToBlacklist(const base::FilePath& module_path, 128 uint32_t module_size, 129 uint32_t module_time_date_stamp); 130 131 // TODO(chrisha): Module analysis code, and various accessors for use by 132 // chrome://conflicts. 133 134 // Adds or removes an observer. 135 // Note that when adding an observer, OnNewModuleFound() will immediately be 136 // called once for all modules that are already loaded before returning to the 137 // caller. In addition, if the ModuleDatabase is currently idle, 138 // OnModuleDatabaseIdle() will also be invoked. 139 // 140 // ModuleDatabaseEventSource: 141 void AddObserver(ModuleDatabaseObserver* observer) override; 142 void RemoveObserver(ModuleDatabaseObserver* observer) override; 143 144 // Raises the priority of module inspection tasks to ensure the 145 // ModuleDatabase becomes idle ASAP. 146 void IncreaseInspectionPriority(); 147 148 #if defined(GOOGLE_CHROME_BUILD) 149 static void RegisterLocalStatePrefs(PrefRegistrySimple* registry); 150 151 // Returns false if third-party modules blocking is disabled via 152 // administrative policy. 153 static bool IsThirdPartyBlockingPolicyEnabled(); 154 155 // Disables the blocking of third-party modules in the browser process. It is 156 // safe to invoke this function from any thread. 157 // This function is meant to be used only as a workaround for the in-process 158 // printing code that may require that third-party DLLs be successfully 159 // loaded into the process to work correctly. 160 // TODO(pmonette): Remove this workaround when printing is moved to a utility 161 // process. See https://crbug.com/892294. 162 static void DisableThirdPartyBlocking(); 163 164 // Destroys the |third_party_conflicts_manager_| instance. Invoked by 165 // the |pref_change_registrar_| when it detects that the policy was disabled. 166 // Note: This is distinct from OnThirdPartyBlockingDisabled(). When the policy 167 // is disabled, the |third_party_conflicts_manager_| is destroyed as if 168 // it was never initialized. 169 void OnThirdPartyBlockingPolicyDisabled(); 170 171 // Accessor for the third party conflicts manager. 172 // Returns null if both the tracking of incompatible applications and the 173 // blocking of third-party modules are disabled. 174 // Do not hold a pointer to the manager because it can be destroyed if the 175 // ThirdPartyBlocking policy is later disabled. third_party_conflicts_manager()176 ThirdPartyConflictsManager* third_party_conflicts_manager() { 177 return third_party_conflicts_manager_.get(); 178 } 179 #endif 180 181 private: 182 friend class TestModuleDatabase; 183 friend class ModuleDatabaseTest; 184 friend class ModuleEventSinkImplTest; 185 186 ModuleInfo* CreateModuleInfo(const base::FilePath& module_path, 187 uint32_t module_size, 188 uint32_t module_time_date_stamp); 189 190 // Finds or creates a mutable ModuleInfo entry. Returns true if the module 191 // info was created. 192 bool FindOrCreateModuleInfo(const base::FilePath& module_path, 193 uint32_t module_size, 194 uint32_t module_time_date_stamp, 195 ModuleInfo** module_info); 196 197 // Returns true if the enumeration of the IMEs and the shell extensions is 198 // finished. 199 // 200 // To avoid sending an improperly tagged module to an observer (in case a race 201 // condition happens and the module is loaded before the enumeration is done), 202 // it's important that this function returns true before any calls to 203 // OnNewModuleFound() is made. 204 bool RegisteredModulesEnumerated(); 205 206 // Called when RegisteredModulesEnumerated() becomes true. Notifies the 207 // observers of each already inspected modules and checks if the idle state 208 // should be entered. 209 void OnRegisteredModulesEnumerated(); 210 211 // Callback for ModuleInspector. 212 void OnModuleInspected(const ModuleInfoKey& module_key, 213 ModuleInspectionResult inspection_result); 214 215 // If the ModuleDatabase is truly idle, calls EnterIdleState(). 216 void OnDelayExpired(); 217 218 // Notifies the observers that ModuleDatabase is now idle. 219 void EnterIdleState(); 220 221 // Notifies the |observer| of already found and inspected modules via 222 // OnNewModuleFound(). 223 void NotifyLoadedModules(ModuleDatabaseObserver* observer); 224 225 #if defined(GOOGLE_CHROME_BUILD) 226 // Called by DisableThirdPartyBlocking() to disable the analysis of loaded 227 // modules. 228 // Note: This is distinct from OnThirdPartyBlockingPolicyDisabled() because 229 // they have a different effect. OnThirdPartyBlockingDisabled() keeps 230 // the |third_party_conflicts_manager_| instance alive. 231 // TODO(pmonette): Remove this workaround when printing is moved to a utility 232 // process. See https://crbug.com/892294. 233 void OnThirdPartyBlockingDisabled(); 234 235 // Initializes the ThirdPartyConflictsManager, which controls showing warnings 236 // for incompatible applications that inject into Chrome and the blocking of 237 // third-party modules. The manager is only initialized if either or both of 238 // the ThirdPartyModulesBlocking and IncompatibleApplicationsWarning features 239 // are enabled. 240 void MaybeInitializeThirdPartyConflictsManager( 241 bool third_party_blocking_policy_enabled); 242 #endif 243 244 // A map of all known modules. 245 ModuleMap modules_; 246 247 base::RetainingOneShotTimer idle_timer_; 248 249 // Indicates if the ModuleDatabase has started processing module load events. 250 bool has_started_processing_; 251 252 // Indicates if all shell extensions have been enumerated. 253 bool shell_extensions_enumerated_; 254 255 // Indicates if all input method editors have been enumerated. 256 bool ime_enumerated_; 257 258 #if defined(GOOGLE_CHROME_BUILD) 259 std::unique_ptr<ModuleLoadAttemptLogListener> 260 module_load_attempt_log_listener_; 261 262 // Observes the ThirdPartyBlockingEnabled group policy on the UI thread. 263 std::unique_ptr<PrefChangeRegistrar, base::OnTaskRunnerDeleter> 264 pref_change_registrar_; 265 #endif 266 267 // Inspects new modules on a blocking task runner. 268 ModuleInspector module_inspector_; 269 270 // Holds observers. 271 base::ObserverList<ModuleDatabaseObserver>::Unchecked observer_list_; 272 273 #if defined(GOOGLE_CHROME_BUILD) 274 std::unique_ptr<ThirdPartyConflictsManager> third_party_conflicts_manager_; 275 #endif 276 277 // Records metrics on third-party modules. 278 ThirdPartyMetricsRecorder third_party_metrics_; 279 280 SEQUENCE_CHECKER(sequence_checker_); 281 282 DISALLOW_COPY_AND_ASSIGN(ModuleDatabase); 283 }; 284 285 #endif // CHROME_BROWSER_WIN_CONFLICTS_MODULE_DATABASE_H_ 286