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

#ifndef CONTENT_PUBLIC_TEST_MOCK_RENDER_PROCESS_HOST_H_
#define CONTENT_PUBLIC_TEST_MOCK_RENDER_PROCESS_HOST_H_

#include <stddef.h>
#include <stdint.h>

#include <map>
#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>

#include "base/containers/flat_set.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/metrics/persistent_memory_allocator.h"
#include "base/observer_list.h"
#include "build/build_config.h"
#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_process_host_factory.h"
#include "content/public/browser/storage_partition_config.h"
#include "media/media_buildflags.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "net/base/network_isolation_key.h"

#if BUILDFLAG(IS_ANDROID)
#include "base/android/child_process_binding_types.h"
#include "content/public/browser/android/child_process_importance.h"
#endif

namespace blink {
class StorageKey;
}  // namespace blink

namespace content {

class MockRenderProcessHostFactory;
class ProcessLock;
class RenderProcessHostPriorityClient;
class SiteInfo;
class SiteInstance;
class StoragePartition;

// A mock render process host that has no corresponding renderer process.  All
// IPC messages are sent into the message sink for inspection by tests.
class MockRenderProcessHost : public RenderProcessHost {
 public:
  using InterfaceBinder =
      base::RepeatingCallback<void(mojo::ScopedMessagePipeHandle)>;

  explicit MockRenderProcessHost(BrowserContext* browser_context,
                                 bool is_for_guests_only = false);
  MockRenderProcessHost(BrowserContext* browser_context,
                        const StoragePartitionConfig& storage_partition_config,
                        bool is_for_guests_only);

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

  ~MockRenderProcessHost() override;

  // Provides test access to how many times a bad message has been received.
  int bad_msg_count() const { return bad_msg_count_; }

  // Provides tests a way to simulate this render process crashing.
  void SimulateCrash();
  void SimulateRenderProcessExit(base::TerminationStatus termination_status,
                                 int exit_code);

  // Simulates async launch happening.
  void SimulateReady();

  // RenderProcessHost implementation (public portion).
  bool Init() override;
  void EnableSendQueue() override;
  int GetNextRoutingID() override;
  void AddRoute(int32_t routing_id, IPC::Listener* listener) override;
  void RemoveRoute(int32_t routing_id) override;
  void AddObserver(RenderProcessHostObserver* observer) override;
  void RemoveObserver(RenderProcessHostObserver* observer) override;
  void ShutdownForBadMessage(CrashReportMode crash_report_mode) override;
  void UpdateClientPriority(RenderProcessHostPriorityClient* client) override;
  int VisibleClientCount() override;
  unsigned int GetFrameDepth() override;
  bool GetIntersectsViewport() override;
  bool IsForTopChromeWebUI() const override;
  bool ShouldSendGpuChannelEarly() const override;
  bool IsForGuestsOnly() override;
  bool IsPrivileged() override;
  bool IsJitDisabled() override;
  bool AreV8OptimizationsDisabled() override;
  void SetAreV8OptimizationsDisabled(bool disabled);
  bool DisallowV8FeatureFlagOverrides() override;
  bool IsPdf() override;
  void SetIsPdf(bool is_pdf);
  void OnMediaStreamAdded() override;
  void OnMediaStreamRemoved() override;
  void OnForegroundServiceWorkerAdded() override;
  void OnForegroundServiceWorkerRemoved() override;
  void OnBoostForLoadingAdded() override;
  void OnBoostForLoadingRemoved() override;
  void OnImmersiveXrSessionStarted() override;
  void OnImmersiveXrSessionStopped() override;
  bool HasImmersiveXrSessionForTesting() const override;
  StoragePartition* GetStoragePartition() override;
  virtual void AddWord(const std::u16string& word);
  bool Shutdown(int exit_code) override;
  bool ShutdownRequested() override;
  bool FastShutdownIfPossible(size_t page_count,
                              bool skip_unload_handlers,
                              bool ignore_workers,
                              bool ignore_keep_alive,
                              bool ignore_pending_reuse,
                              bool use_outermost_main_frame_check) override;
  bool FastShutdownStarted() override;
  const base::Process& GetProcess() override;
  bool IsReady() override;
  ChildProcessId GetID() const override;
  int GetDeprecatedID() const override;
  base::SafeRef<RenderProcessHost> GetSafeRef() const override;
  bool IsInitializedAndNotDead() override;
  bool IsDeletingSoon() override;
  void SetBlocked(bool blocked) override;
  bool IsBlocked() override;
  base::CallbackListSubscription RegisterBlockStateChangedCallback(
      const BlockStateChangedCallback& cb) override;
  void Cleanup() override;
  void AddPendingView() override;
  void RemovePendingView() override;
  void AddPriorityClient(
      RenderProcessHostPriorityClient* priority_client) override;
  void RemovePriorityClient(
      RenderProcessHostPriorityClient* priority_client) override;
  void SetPriorityOverride(base::Process::Priority priority) override;
  bool HasPriorityOverride() override;
  void ClearPriorityOverride() override;
#if BUILDFLAG(IS_ANDROID)
  void GraduateSpareToNormalRendererPriority() override;
  bool ShouldThrottleNavigationForSpareRendererGraduation() override;
  ChildProcessImportance GetEffectiveImportance() override;
  base::android::ChildBindingState GetEffectiveChildBindingState() override;
  void DumpProcessStack() override;
#endif
  void SetSuddenTerminationAllowed(bool allowed) override;
  BrowserContext* GetBrowserContext() override;
  bool InSameStoragePartition(StoragePartition* partition) override;
  IPC::ChannelProxy* GetChannel() override;
  base::TimeDelta GetChildProcessIdleTime() override;
  FilterURLResult FilterURL(bool empty_allowed, GURL* url) override;
  void EnableAudioDebugRecordings(const base::FilePath& file) override;
  void DisableAudioDebugRecordings() override;
  WebRtcStopRtpDumpCallback StartRtpDump(
      bool incoming,
      bool outgoing,
      WebRtcRtpPacketCallback packet_callback) override;
  void BindReceiver(mojo::GenericPendingReceiver receiver) override;
  std::unique_ptr<base::PersistentMemoryAllocator> TakeMetricsAllocator()
      override;
  const base::TimeTicks& GetLastInitTime() override;
  base::TimeTicks GetProcessLaunchedTime() const override;
  base::Process::Priority GetPriority() const override;
  size_t GetWorkerRefCount() const;
  std::string GetKeepAliveDurations() const override;
  size_t GetShutdownDelayRefCount() const override;
  int GetRenderFrameHostCount() const override;
  void DisableRefCounts() override;
  void ForEachRenderFrameHost(
      base::FunctionRef<void(RenderFrameHost*)> on_render_frame_host) override;
  void RegisterRenderFrameHost(
      const GlobalRenderFrameHostId& render_frame_host_id,
      bool is_outermost_main_frame) override;
  void UnregisterRenderFrameHost(
      const GlobalRenderFrameHostId& render_frame_host_id,
      bool is_outermost_main_frame) override;
  void IncrementWorkerRefCount() override;
  void DecrementWorkerRefCount() override;
  void IncrementPendingReuseRefCount() override;
  void DecrementPendingReuseRefCount() override;
  int GetPendingReuseRefCountForTesting() const override;
  bool AreRefCountsDisabled() override;
  mojom::Renderer* GetRendererInterface() override;

  bool MayReuseHost() override;
  bool IsUnused() override;
  void SetIsUsed() override;

  bool HostHasNotBeenUsed() override;
  bool IsSpare() const override;
  void SetProcessLock(const IsolationContext& isolation_context,
                      const ProcessLock& process_lock) override;
  ProcessLock GetProcessLock() const override;
  bool IsProcessLockedToSiteForTesting() override;
  base::ScopedClosureRunner DelayProcessShutdown(
      const base::TimeDelta& subframe_shutdown_timeout,
      const base::TimeDelta& unload_handler_timeout,
      const SiteInfo& site_info) override;
  void StopTrackingProcessForShutdownDelay() override;
  void BindCacheStorage(
      const network::CrossOriginEmbedderPolicy&,
      mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>,
      const network::DocumentIsolationPolicy& document_isolation_policy,
      mojo::PendingRemote<network::mojom::DocumentIsolationPolicyReporter>,
      const storage::BucketLocator& bucket,
      mojo::PendingReceiver<blink::mojom::CacheStorage> receiver) override;
  void BindFileSystemManager(
      const blink::StorageKey& storage_key,
      mojo::PendingReceiver<blink::mojom::FileSystemManager> receiver)
      override {}
  void BindFileSystemAccessManager(
      const blink::StorageKey& storage_key,
      mojo::PendingReceiver<blink::mojom::FileSystemAccessManager> receiver)
      override {}
  void GetSandboxedFileSystemForBucket(
      const storage::BucketLocator& bucket,
      const std::vector<std::string>& directory_path_components,
      blink::mojom::FileSystemAccessManager::GetSandboxedFileSystemCallback
          callback) override;
  void BindIndexedDB(
      const blink::StorageKey& storage_key,
      BucketContext& bucket_context,
      mojo::PendingReceiver<blink::mojom::IDBFactory> receiver) override;
  void BindBucketManagerHost(
      base::WeakPtr<BucketContext> bucket_context,
      mojo::PendingReceiver<blink::mojom::BucketManagerHost> receiver)
      override {}
  void BindRestrictedCookieManagerForServiceWorker(
      const blink::StorageKey& storage_key,
      mojo::PendingReceiver<network::mojom::RestrictedCookieManager> receiver)
      override {}
  void BindVideoDecodePerfHistory(
      mojo::PendingReceiver<media::mojom::VideoDecodePerfHistory> receiver)
      override {}
  void BindQuotaManagerHost(
      const blink::StorageKey& storage_key,
      mojo::PendingReceiver<blink::mojom::QuotaManagerHost> receiver) override {
  }
#if BUILDFLAG(IS_FUCHSIA)
  void BindMediaCodecProvider(
      mojo::PendingReceiver<media::mojom::FuchsiaMediaCodecProvider> receiver)
      override {}
#endif
  void CreateLockManager(
      const blink::StorageKey& storage_key,
      mojo::PendingReceiver<blink::mojom::LockManager> receiver) override {}
  void CreateOneShotSyncService(
      const url::Origin& origin,
      mojo::PendingReceiver<blink::mojom::OneShotBackgroundSyncService>
          receiver) override {}
  void CreatePeriodicSyncService(
      const url::Origin& origin,
      mojo::PendingReceiver<blink::mojom::PeriodicBackgroundSyncService>
          receiver) override {}
  void CreatePermissionService(
      const url::Origin& origin,
      mojo::PendingReceiver<blink::mojom::PermissionService> receiver)
      override {}
  void CreatePaymentManagerForOrigin(
      const url::Origin& origin,
      mojo::PendingReceiver<payments::mojom::PaymentManager> receiver)
      override {}
  void CreateNotificationService(
      GlobalRenderFrameHostId rfh_id,
      RenderProcessHost::NotificationServiceCreatorType creator_type,
      const blink::StorageKey& storage_key,
      mojo::PendingReceiver<blink::mojom::NotificationService> receiver)
      override {}
#if BUILDFLAG(ALLOW_OOP_VIDEO_DECODER)
  void CreateOOPVideoDecoder(
      mojo::PendingReceiver<media::mojom::VideoDecoder> receiver) override {}
#endif  // BUILDFLAG(ALLOW_OOP_VIDEO_DECODER)

  std::string GetInfoForBrowserContextDestructionCrashReporting() override;
  void WriteIntoTrace(perfetto::TracedProto<TraceProto> proto) const override;

#if BUILDFLAG(IS_CHROMEOS)
  void ReinitializeLogging(uint32_t logging_dest,
                           base::ScopedFD log_file_descriptor) override;
#endif

  void SetBatterySaverMode(bool battery_saver_mode_enabled) override {}
  uint64_t GetPrivateMemoryFootprint() override;

  void PauseSocketManagerForRenderFrameHost(
      const GlobalRenderFrameHostId& render_frame_host_id) override {}
  void ResumeSocketManagerForRenderFrameHost(
      const GlobalRenderFrameHostId& render_frame_host_id) override {}

  bool IsOnlyHostingPrerenderedFramesOrEmpty() override;

  // IPC::Listener via RenderProcessHost.
  void OnChannelConnected(int32_t peer_pid) override;

  void set_priority(base::Process::Priority priority) { priority_ = priority; }

  void SetIsForTopChromeWebUI(bool is_for_top_chrome_web_ui) {
    is_for_top_chrome_web_ui_ = is_for_top_chrome_web_ui;
  }

  // Makes GetProcess() report an invalid Process, as RenderProcessHostImpl
  // does between Init() and OnProcessLaunched(). Lets tests cover the window
  // in which a host is initialized but its renderer has not launched yet.
  void SimulateProcessStillLaunchingForTesting(bool still_launching) {
    process_still_launching_ = still_launching;
  }

  void SetProcessLaunchedTime(base::TimeTicks time) {
    process_launched_time_ = time;
  }

  void OverrideBinderForTesting(const std::string& interface_name,
                                const InterfaceBinder& binder);

  void OverrideRendererInterfaceForTesting(
      std::unique_ptr<mojo::AssociatedRemote<mojom::Renderer>>
          renderer_interface);

  bool is_renderer_locked_to_site() const {
    return is_renderer_locked_to_site_;
  }

  int foreground_service_worker_count() const {
    return foreground_service_worker_count_;
  }

 private:
  // Stores IPC messages that would have been sent to the renderer.
  int bad_msg_count_;
  ChildProcessId id_;
  bool has_connection_;
  raw_ptr<BrowserContext, DanglingUntriaged> browser_context_;
  base::ObserverList<RenderProcessHostObserver> observers_;

  StoragePartitionConfig storage_partition_config_;
  base::flat_set<raw_ptr<RenderProcessHostPriorityClient, CtnExperimental>>
      priority_clients_;
  int prev_routing_id_;
  base::IDMap<IPC::Listener*> listeners_;
  bool shutdown_requested_;
  bool fast_shutdown_started_;
  bool within_process_died_observer_ = false;
  bool delayed_cleanup_ = false;
  bool deletion_callback_called_;
  bool is_for_guests_only_;
  bool is_pdf_ = false;
  base::Process::Priority priority_;
  bool is_unused_;
  bool are_v8_optimizations_disabled_ = false;
  bool is_for_top_chrome_web_ui_ = false;
  bool has_immersive_xr_session_ = false;
  bool is_ready_ = false;
  bool process_still_launching_ = false;
  base::TimeTicks process_launched_time_;
  int pending_view_count_;
  int worker_ref_count_;
  int pending_reuse_ref_count_;
  int foreground_service_worker_count_;
  std::unique_ptr<mojo::AssociatedRemote<mojom::Renderer>> renderer_interface_;
  std::map<std::string, InterfaceBinder> binder_overrides_;
  bool is_renderer_locked_to_site_ = false;
  std::set<GlobalRenderFrameHostId> render_frame_host_id_set_;
  mojo::PendingReceiver<blink::mojom::CacheStorage> cache_storage_receiver_;
  mojo::PendingReceiver<blink::mojom::IDBFactory> idb_factory_receiver_;
  base::WeakPtrFactory<MockRenderProcessHost> weak_ptr_factory_{this};
};

class MockRenderProcessHostFactory : public RenderProcessHostFactory {
 public:
  MockRenderProcessHostFactory();

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

  ~MockRenderProcessHostFactory() override;

  // Builds MockRenderProcessHost and stores it in `processes_`.
  RenderProcessHost* CreateRenderProcessHost(BrowserContext* browser_context,
                                             SiteInstance* site_instance) final;

  // Removes the given MockRenderProcessHost from the MockRenderProcessHost
  // list.
  void Remove(MockRenderProcessHost* host) const;

  // Retrieve the current list of mock processes.
  std::vector<std::unique_ptr<MockRenderProcessHost>>* GetProcesses() {
    return &processes_;
  }

 protected:
  // Builds MockRenderProcessHost.
  virtual std::unique_ptr<MockRenderProcessHost> BuildRenderProcessHost(
      BrowserContext* browser_context,
      SiteInstance* site_instance);

  // A list of MockRenderProcessHosts created by this object. This list is used
  // for deleting all MockRenderProcessHosts that have not deleted by a test in
  // the destructor and prevent them from being leaked.
  mutable std::vector<std::unique_ptr<MockRenderProcessHost>> processes_;
};

}  // namespace content

#endif  // CONTENT_PUBLIC_TEST_MOCK_RENDER_PROCESS_HOST_H_
