chromium/chrome/browser/win/conflicts/module_load_attempt_log_listener.h

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_WIN_CONFLICTS_MODULE_LOAD_ATTEMPT_LOG_LISTENER_H_
#define CHROME_BROWSER_WIN_CONFLICTS_MODULE_LOAD_ATTEMPT_LOG_LISTENER_H_

#include <string_view>
#include <tuple>
#include <utility>
#include <vector>

#include "base/files/file_path.h"
#include "base/functional/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/synchronization/waitable_event.h"
#include "base/win/object_watcher.h"
#include "base/win/windows_types.h"
#include "chrome/chrome_elf/third_party_dlls/packed_list_format.h"

namespace base {
class SequencedTaskRunner;
}

// This class drains the log of module load attempt from Chrome ELF, and
// notifies its delegate for all modules that were blocked.
class ModuleLoadAttemptLogListener : public base::win::ObjectWatcher::Delegate {
 public:
  using OnModuleBlockedCallback =
      base::RepeatingCallback<void(const base::FilePath& module_path,
                                   uint32_t module_size,
                                   uint32_t module_time_date_stamp)>;

  explicit ModuleLoadAttemptLogListener(
      OnModuleBlockedCallback on_module_blocked_callback);

  ModuleLoadAttemptLogListener(const ModuleLoadAttemptLogListener&) = delete;
  ModuleLoadAttemptLogListener& operator=(const ModuleLoadAttemptLogListener&) =
      delete;

  ~ModuleLoadAttemptLogListener() override;

  // base::win::ObjectWatcher::Delegate:
  void OnObjectSignaled(HANDLE object) override;

  static std::vector<std::wstring_view> SplitLogicalDriveStringsForTesting(
      std::wstring_view logical_drive_strings) {
    return SplitLogicalDriveStringsImpl(logical_drive_strings);
  }

 private:
  void StartDrainingLogs();

  void OnLogDrained(
      std::vector<std::tuple<base::FilePath, uint32_t, uint32_t>>&&
          blocked_modules);

  // Translates a path of the form "\Device\HarddiskVolumeXX\..." into its
  // equivalent that starts with a drive letter ("C:\..."). Returns false on
  // failure.
  bool GetDriveLetterPath(const base::FilePath& device_path,
                          base::FilePath* drive_letter_path);

  // Update the |device_to_letter_path_mapping_|.
  void UpdateDeviceToLetterPathMapping();

  // Splits the result of calling GetLogicalDriveStrings() into its components.
  static std::vector<std::wstring_view> SplitLogicalDriveStringsImpl(
      std::wstring_view logical_drive_strings);

  // Invoked once per blocked module every time the log is drained.
  OnModuleBlockedCallback on_module_blocked_callback_;

  // The sequence in which the log is drained.
  scoped_refptr<base::SequencedTaskRunner> background_task_runner_;

  // Must be before |object_watcher_|.
  base::WaitableEvent waitable_event_;

  // Watches |waitable_event_|.
  base::win::ObjectWatcher object_watcher_;

  // A cache of the mapping of device path roots to their drive letter root
  // equivalent.
  std::vector<std::pair<base::FilePath, std::wstring>>
      device_to_letter_path_mapping_;

  base::WeakPtrFactory<ModuleLoadAttemptLogListener> weak_ptr_factory_;
};

#endif  // CHROME_BROWSER_WIN_CONFLICTS_MODULE_LOAD_ATTEMPT_LOG_LISTENER_H_