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

#ifndef EXTENSIONS_BROWSER_EXTENSION_FUNCTION_H_
#define EXTENSIONS_BROWSER_EXTENSION_FUNCTION_H_

#include <stddef.h>

#include <memory>
#include <optional>
#include <string>
#include <vector>

#include "base/callback_list.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/process/process.h"
#include "base/task/sequenced_task_runner_helpers.h"
#include "base/timer/elapsed_timer.h"
#include "base/types/pass_key.h"
#include "content/public/browser/browser_thread.h"
#include "extensions/browser/extension_function_histogram_value.h"
#include "extensions/browser/quota_service.h"
#include "extensions/browser/service_worker/service_worker_keepalive.h"
#include "extensions/browser/service_worker/worker_id.h"
#include "extensions/common/constants.h"
#include "extensions/common/context_data.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_id.h"
#include "extensions/common/features/feature.h"
#include "extensions/common/mojom/context_type.mojom.h"
#include "extensions/common/mojom/extra_response_data.mojom.h"
#include "extensions/common/stack_frame.h"
#include "third_party/blink/public/mojom/devtools/console_message.mojom-forward.h"
#include "third_party/blink/public/mojom/devtools/inspector_issue.mojom-forward.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_database.mojom-forward.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom-forward.h"

namespace base {
class ListValue;
}

namespace content {
class BrowserContext;
class RenderFrameHost;
class WebContents;
}

namespace extensions {
class ExtensionFunctionDispatcher;
}

#ifdef NDEBUG
#define EXTENSION_FUNCTION_VALIDATE(test) \
  do {                                    \
    if (!(test)) {                        \
      this->SetBadMessage();              \
      return ValidationFailure(this);     \
    }                                     \
  } while (0)
#else   // NDEBUG
// TODO(pbos): This works around that CHECK(false) is [[noreturn]]. Instead we
// should try to not build any functions that should never be called. See
// ChromeOS-only LanguageSettingsPrivateGetInputMethodListsFunction and other
// instances of EXTENSION_FUNCTION_VALIDATE(false).
namespace extensions {
inline bool FunctionValidateInternalReturnParam(bool param) {
  return param;
}
}  // namespace extensions
#define EXTENSION_FUNCTION_VALIDATE(test) \
  CHECK(extensions::FunctionValidateInternalReturnParam((test) ? true : false))
#endif  // NDEBUG

#ifdef NDEBUG
#define EXTENSION_FUNCTION_PRERUN_VALIDATE(test) \
  do {                                           \
    if (!(test)) {                               \
      this->SetBadMessage();                     \
      return false;                              \
    }                                            \
  } while (0)
#else  // NDEBUG
#define EXTENSION_FUNCTION_PRERUN_VALIDATE(test) CHECK(test)
#endif  // NDEBUG

// Declares a callable extension function with the given `name`. You must also
// supply a unique `histogramvalue` used for histograms of extension function
// invocation (add new ones at the end of the enum in
// extension_function_histogram_value.h).
// TODO(devlin): This would be nicer if instead we defined the constructor
// for the ExtensionFunction since the histogram value and name should never
// change. Then, we could get rid of the set_ methods for those values on
// ExtensionFunction, and there'd be no possibility of having them be
// "wrong" for a given function. Unfortunately, that would require updating
// each ExtensionFunction and construction site, which, while possible, is
// quite costly.
#define DECLARE_EXTENSION_FUNCTION(name, histogramvalue)               \
 public:                                                               \
  static constexpr const char* static_function_name() { return name; } \
                                                                       \
 public:                                                               \
  static constexpr extensions::functions::HistogramValue               \
  static_histogram_value() {                                           \
    return extensions::functions::histogramvalue;                      \
  }

// Declares/defines an empty extension function. This is useful for APIs that
// are not yet implemented, but are defined in the IDL/JSON schema.
#define DECLARE_UNIMPLEMENTED_EXTENSION_FUNCTION(class_name,     \
                                                 api_name,       \
                                                 histogramvalue) \
  class class_name : public ExtensionFunction {                  \
   public:                                                       \
    DECLARE_EXTENSION_FUNCTION(api_name, histogramvalue)         \
   protected:                                                    \
    ~class_name() override;                                      \
    ResponseAction Run() override;                               \
  }
#define DEFINE_UNIMPLEMENTED_EXTENSION_FUNCTION(class_name, api_name) \
  class_name::~class_name() = default;                                \
  ExtensionFunction::ResponseAction class_name::Run() {               \
    return RespondNow(Error(api_name " not implemented"));            \
  }

// Abstract base class for extension functions the ExtensionFunctionDispatcher
// knows how to dispatch to.
// NOTE: If you see a crash in an ExtensionFunction implementation and want to
// know which extension triggered the crash, look for crash keys
// extension-function-caller-1, 2, and 3.
class ExtensionFunction : public base::RefCountedThreadSafe<
                              ExtensionFunction,
                              content::BrowserThread::DeleteOnUIThread> {
 public:
  enum class ResponseType {
    // The function has succeeded.
    kSucceeded,
    // The function has failed.
    kFailed,
    // The input message is malformed.
    kBadMessage,
  };

  using ResponseCallback = base::OnceCallback<void(
      ResponseType type,
      base::ListValue results,
      const std::string& error,
      extensions::mojom::ExtraResponseDataPtr response_data)>;

  ExtensionFunction();

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

  static void EnsureShutdownNotifierFactoryBuilt();

  // Returns true if the function has permission to run.
  //
  // This checks the Extension's permissions against the features declared in
  // the *_features.json files. Note that some functions may perform additional
  // checks in Run(), such as for specific host permissions or user gestures.
  bool HasPermission() const;

  // Sends `error` as an error response.
  void RespondWithError(std::string error);

  using PassKey = base::PassKey<ExtensionFunction>;

  // The result of a function call.
  //
  // Use NoArguments(), WithArguments(), ArgumentList(), or Error()
  // rather than this class directly.
  class ResponseValue {
   public:
    ResponseValue(bool success, PassKey);
    ResponseValue(ResponseValue&& other);
    ResponseValue& operator=(ResponseValue&& other) = delete;
    ResponseValue(const ResponseValue&) = delete;
    ResponseValue& operator=(const ResponseValue&) = delete;
    ~ResponseValue();

    // Returns true for success, false for failure.
    bool success() const { return success_; }

   private:
    const bool success_;
  };

  // The action type used to hold a callback to be used by ResponseAction, when
  // returning from RunAsync.
  class RespondNowAction {
   public:
    using SendResponseCallback = base::OnceCallback<void(bool)>;
    RespondNowAction(ResponseValue result, SendResponseCallback send_response);
    RespondNowAction(RespondNowAction&& other);
    RespondNowAction& operator=(RespondNowAction&& other) = delete;
    ~RespondNowAction();

    // Executes the send response callback.
    void Execute();

   private:
    ResponseValue result_;
    SendResponseCallback send_response_;
  };

  // The action to use when returning from RunAsync.
  //
  // Use RespondNow() or RespondLater() or AlreadyResponded() rather than this
  // class directly.

  class ResponseAction {
   public:
    explicit ResponseAction(PassKey);
    ResponseAction(RespondNowAction action, PassKey);
    ResponseAction(ResponseAction&& other);
    ResponseAction& operator=(ResponseAction&& other) = delete;
    ~ResponseAction();

    // Executes whatever respond action it may be holding.
    void Execute();

   private:
    // An action object responsible for handling the sending of the response.
    std::optional<RespondNowAction> action_;
  };

  // Helper class for tests to force all ExtensionFunction::user_gesture()
  // calls to return true as long as at least one instance of this class
  // exists.
  class ScopedUserGestureForTests {
   public:
    ScopedUserGestureForTests();
    ~ScopedUserGestureForTests();
  };

  // A string used in the case of an unknown error being detected.
  // DON'T USE THIS. It's only here during conversion to flag cases where errors
  // aren't already set.
  // TODO(devlin): Remove this if/when all functions are updated to return real
  // errors.
  static const char kUnknownErrorDoNotUse[];

  // Called before Run() in order to perform a common verification check so that
  // APIs subclassing this don't have to roll their own RunSafe() variants.
  // If this returns false, then Run() is never called, and the function
  // responds immediately with an error (note that error must be non-empty in
  // this case). If this returns true, execution continues on to Run().
  virtual bool PreRunValidation(std::string* error);

  // Runs the extension function if PreRunValidation() succeeds. This should be
  // called at most once over the lifetime of an ExtensionFunction.
  ResponseAction RunWithValidation();

  // Runs the function and returns the action to take when the caller is ready
  // to respond. Callers can expect this is called at most once for the lifetime
  // of an ExtensionFunction.
  //
  // Typical return values might be:
  //   * RespondNow(NoArguments())
  //   * RespondNow(ArgumentList(my_result.ToValue()))
  //   * RespondNow(WithArguments(42))
  //   * RespondNow(WithArguments(42, "value", false))
  //   * RespondNow(Error("Warp core breach"))
  //   * RespondNow(Error("Warp core breach on *", GetURL()))
  //   * RespondLater(), then later,
  //     * Respond(NoArguments())
  //     * ... etc.
  //
  //
  // Callers must call Execute() on the return ResponseAction at some point,
  // exactly once.
  //
  // ExtensionFunction implementations are encouraged to just implement Run.
  [[nodiscard]] virtual ResponseAction Run() = 0;

  // Gets whether quota should be applied to this individual function
  // invocation. This is different to GetQuotaLimitHeuristics which is only
  // invoked once and then cached.
  //
  // Returns false by default.
  virtual bool ShouldSkipQuotaLimiting() const;

  // Optionally adds one or multiple QuotaLimitHeuristic instances suitable for
  // this function to `heuristics`. The ownership of the new QuotaLimitHeuristic
  // instances is passed to the owner of `heuristics`.
  // No quota limiting by default.
  //
  // Only called once per lifetime of the QuotaService.
  virtual void GetQuotaLimitHeuristics(
      extensions::QuotaLimitHeuristics* heuristics) const {}

  // Called when the quota limit has been exceeded. The default implementation
  // returns an error.
  virtual void OnQuotaExceeded(std::string violation_error);

  // Specifies the raw arguments to the function, as a JSON value.
  void SetArgs(base::ListValue args);

  // Retrieves the results of the function as a base::ListValue for testing
  // purposes.
  const base::ListValue* GetResultListForTest() const;

  std::unique_ptr<extensions::ContextData> GetContextData() const;

  // Retrieves any error string from the function.
  virtual const std::string& GetError() const;

  void SetBadMessage();

  // Specifies the name of the function. A long-lived string (such as a string
  // literal) must be provided.
  void SetName(const char* name);
  const char* name() const { return name_; }

  int context_id() const { return context_id_; }

  void set_extension(
      const scoped_refptr<const extensions::Extension>& extension) {
    extension_ = extension;
  }
  const extensions::Extension* extension() const { return extension_.get(); }
  const extensions::ExtensionId& extension_id() const {
    DCHECK(extension())
        << "extension_id() called without an Extension. If " << name()
        << " is allowed to be called without any Extension then you should "
        << "check extension() first. If not, there is a bug in the Extension "
        << "platform, so page somebody in extensions/OWNERS";
    return extension_->id();
  }

  void set_request_uuid(base::Uuid uuid) { request_uuid_ = std::move(uuid); }
  const base::Uuid& request_uuid() const { return request_uuid_; }

  void set_source_url(const GURL& source_url) { source_url_ = source_url; }
  const GURL& source_url() const { return source_url_; }

  void set_has_callback(bool has_callback) { has_callback_ = has_callback; }
  bool has_callback() const { return has_callback_; }

  void set_include_incognito_information(bool include) {
    include_incognito_information_ = include;
  }
  bool include_incognito_information() const {
    return include_incognito_information_;
  }

  // Note: consider using ScopedUserGestureForTests instead of calling
  // set_user_gesture directly.
  void set_user_gesture(bool user_gesture) { user_gesture_ = user_gesture; }
  bool user_gesture() const;

  void set_histogram_value(
      extensions::functions::HistogramValue histogram_value) {
    histogram_value_ = histogram_value; }
  extensions::functions::HistogramValue histogram_value() const {
    return histogram_value_; }

  void set_response_callback(ResponseCallback callback) {
    response_callback_ = std::move(callback);
  }

  bool response_callback_is_null() { return response_callback_.is_null(); }

  void set_source_context_type(extensions::mojom::ContextType type) {
    source_context_type_ = type;
  }
  extensions::mojom::ContextType source_context_type() const {
    return source_context_type_;
  }

  void set_source_process_id(int source_process_id) {
    source_process_id_ = source_process_id;
  }
  int source_process_id() const {
    return source_process_id_;
  }

  void set_worker_id(extensions::WorkerId worker_id) {
    worker_id_ = std::move(worker_id);
  }
  const std::optional<extensions::WorkerId>& worker_id() const {
    return worker_id_;
  }

  int64_t service_worker_version_id() const {
    return worker_id_ ? worker_id_->version_id
                      : blink::mojom::kInvalidServiceWorkerVersionId;
  }

  void set_service_worker_keepalive(
      std::unique_ptr<extensions::ServiceWorkerKeepalive> keepalive) {
    service_worker_keepalive_ = std::move(keepalive);
  }
  // Out-of-line because the release of the keepalive can invoke significant
  // work.
  void ResetServiceWorkerKeepalive();

  bool is_from_service_worker() const { return worker_id_.has_value(); }

  bool did_initialize() const { return did_initialize_; }
  void set_did_initialize() { did_initialize_ = true; }

  ResponseType* response_type() const { return response_type_.get(); }

  // Whether this function has responded.
  bool did_respond() const {
    return response_type_ != nullptr || should_ignore_did_respond_for_testing;
  }

  // Set the browser context which contains the extension that has originated
  // this function call. Only meant for testing; if unset, uses the
  // BrowserContext from dispatcher().
  void SetBrowserContextForTesting(content::BrowserContext* context);
  content::BrowserContext* browser_context() const;

  void SetRenderFrameHost(content::RenderFrameHost* render_frame_host);
  content::RenderFrameHost* render_frame_host() const {
    return render_frame_host_;
  }

  void SetDispatcher(
      const base::WeakPtr<extensions::ExtensionFunctionDispatcher>& dispatcher);
  extensions::ExtensionFunctionDispatcher* dispatcher() const {
    return dispatcher_.get();
  }

  int worker_thread_id() const {
    return worker_id_ ? worker_id_->thread_id : extensions::kMainThreadId;
  }

  // Returns the web contents associated with the sending `render_frame_host_`.
  // This can be null.
  content::WebContents* GetSenderWebContents();

  // Returns whether this API call should allow the extension service worker (if
  // any) to stay alive beyond the typical 5 minute-per-task limit (i.e.,
  // indicates this API is expected to potentially take longer than 5 minutes
  // to execute).
  // The default implementation returns false. In general, this should only
  // return true for APIs that trigger some sort of user prompt. If you are
  // unsure, please consult the extensions team.
  virtual bool ShouldKeepWorkerAliveIndefinitely();

  // Notifies the function that the renderer received the reply from the
  // browser. The function will only receive this notification if it registers
  // via `AddResponseTarget()`.
  virtual void OnResponseAck();

  // Returns original args, as they were set by SetArgs() (doesn't include
  // modifications via GetMutableArgs()).
  const base::ListValue& GetOriginalArgs() const;

  // Sets did_respond_ to true so that the function won't DCHECK if it never
  // sends a response. Typically, this shouldn't be used, even in testing. It's
  // only for when you want to test functionality that doesn't exercise the
  // Run() aspect of an extension function.
  void ignore_did_respond_for_testing() {
    should_ignore_did_respond_for_testing = true;
  }
  bool should_ignore_did_respond_for_testing = false;

  void preserve_results_for_testing() { preserve_results_for_testing_ = true; }

  // Same as above, but global. Yuck. Do not add any more uses of this.
  static bool ignore_all_did_respond_for_testing_do_not_use;

  void set_js_callstack(extensions::StackTrace js_callstack) {
    js_callstack_ = std::move(js_callstack);
  }

  const std::optional<extensions::StackTrace>& js_callstack() const {
    return js_callstack_;
  }

 protected:
  // ResponseValues.
  //
  // Success, no arguments to pass to caller.
  ResponseValue NoArguments();
  // Success, a list of arguments `results` to pass to caller.
  ResponseValue ArgumentList(base::ListValue results);

  // Success, a variadic list of arguments to pass to the caller.
  template <typename... Args>
  ResponseValue WithArguments(Args&&... args) {
    static_assert(sizeof...(Args) > 0,
                  "Use NoArguments(), as there are no arguments in this call.");

    base::ListValue params;
    params.reserve(sizeof...(Args));
    (params.Append(std::forward<Args&&>(args)), ...);
    return ArgumentList(std::move(params));
  }

  // Error. chrome.runtime.lastError.message will be set to `error`.
  ResponseValue Error(std::string error);
  // Error with formatting. Args are processed using
  // ErrorUtils::FormatErrorMessage, that is, each occurrence of * is replaced
  // by the corresponding |s*|:
  // Error("Error in *: *", "foo", "bar") <--> Error("Error in foo: bar").
  template <typename... Args>
  ResponseValue Error(const std::string& format, const Args&... args) {
    return CreateErrorResponseValue(
        extensions::ErrorUtils::FormatErrorMessage(format, args...));
  }
  // Error with a list of arguments `args` to pass to caller.
  // Using this ResponseValue is incompatible with promise based returns and
  // indicates something is wrong with the API. If you are trying to use this,
  // you likely instead want to be returning a value indicating if the API call
  // was a "success" and/or an enum indicating what may have gone wrong.
  // Some legacy APIs do still rely on this though.
  ResponseValue ErrorWithArgumentsDoNotUse(base::ListValue args,
                                           const std::string& error);
  // Bad message. A ResponseValue equivalent to EXTENSION_FUNCTION_VALIDATE(),
  // so this will actually kill the renderer and not respond at all.
  ResponseValue BadMessage();

  // ResponseActions.
  //
  // These are exclusively used as return values from Run(). Call Respond(...)
  // to respond at any other time - but as described below, only after Run()
  // has already executed, and only if it returned RespondLater().
  //
  // Respond to the extension immediately with `result`.
  [[nodiscard]] ResponseAction RespondNow(ResponseValue result);
  // Don't respond now, but promise to call Respond(...) later.
  [[nodiscard]] ResponseAction RespondLater();
  // Respond() was already called before Run() finished executing.
  //
  // Assume Run() uses some helper system that accepts callback that Respond()s.
  // If that helper system calls the synchronously in some cases, then use
  // this return value in those cases.
  //
  // FooExtensionFunction::Run() {
  //   Helper::FetchResults(..., base::BindOnce(&Success));
  //   if (did_respond()) return AlreadyResponded();
  //   return RespondLater();
  // }
  // FooExtensionFunction::Success() {
  //   Respond(...);
  // }
  //
  // Helper::FetchResults(..., base::OnceCallback callback) {
  //   if (...)
  //     std::move(callback).Run(..);  // Synchronously call `callback`.
  //   else
  //     // Asynchronously call `callback`.
  // }
  [[nodiscard]] ResponseAction AlreadyResponded();

  // This is the return value of the EXTENSION_FUNCTION_VALIDATE macro, which
  // needs to work from Run(), RunAsync(), and RunSync(). The former of those
  // has a different return type (ResponseAction) than the latter two (bool).
  [[nodiscard]] static ResponseAction ValidationFailure(
      ExtensionFunction* function);

  // If RespondLater() was returned from Run(), functions must at some point
  // call Respond() with `result` as their result.
  //
  // More specifically: call this iff Run() has already executed, it returned
  // RespondLater(), and Respond(...) hasn't already been called.
  void Respond(ResponseValue result);

  // Adds this instance to the set of targets waiting for an ACK from the
  // renderer.
  void AddResponseTarget();

  virtual ~ExtensionFunction();

  // Called after the response is sent, allowing the function to perform any
  // additional work or cleanup.
  virtual void OnResponded();

  // Called when the `browser_context_` associated with this ExtensionFunction
  // is shutting down. Immediately after this call, `browser_context_` will be
  // set to null. Subclasses should override this method to perform any cleanup
  // that needs to happen before the context shuts down, such as removing
  // observers of KeyedServices.
  virtual void OnBrowserContextShutdown() {}

  // Return true if the argument to this function at `index` was provided and
  // is non-null.
  bool HasOptionalArgument(size_t index);

  // Emits a message to the extension's devtools console.
  void WriteToConsole(blink::mojom::ConsoleMessageLevel level,
                      const std::string& message);

  // Reports an inspector issue to the issues tab in Chrome DevTools
  void ReportInspectorIssue(blink::mojom::InspectorIssueInfoPtr info);

  // Sets the Blobs whose ownership is being transferred to the renderer.
  void SetTransferredBlobs(std::vector<blink::mojom::SerializedBlobPtr> blobs);

  bool has_args() const { return args_.has_value(); }

  // Returns args. They may have been modified via GetMutableArgs() since they
  // were set with SetArgs().
  const base::ListValue& args() const {
    DCHECK(args_);
    return *args_;
  }

  base::ListValue& GetMutableArgs();

  // The extension that called this function.
  scoped_refptr<const extensions::Extension> extension_;

 private:
  ResponseValue CreateArgumentListResponse(base::ListValue result);
  ResponseValue CreateErrorWithArgumentsResponse(base::ListValue result,
                                                 const std::string& error);
  ResponseValue CreateErrorResponseValue(std::string error);
  ResponseValue CreateBadMessageResponse();

  void SetFunctionResults(base::ListValue results);
  void SetFunctionError(std::string error);

  friend struct content::BrowserThread::DeleteOnThread<
      content::BrowserThread::UI>;
  friend class base::DeleteHelper<ExtensionFunction>;
  friend class ResponseValueObject;
  class RenderFrameHostTracker;

  // Called on BrowserContext shutdown.
  void Shutdown();

  // Call with true to indicate success, false to indicate failure. If this
  // failed, `error_` should be set.
  void SendResponseImpl(bool success);

  // The arguments to the API. Populated by SetArgs(). May be modified via
  // GetMutableArgs().
  std::optional<base::ListValue> args_;

  // Original arguments to the API. Populated from `args_` when GetMutableArgs()
  // is first invoked, otherwise nullopt. This exists because an extension
  // function may modify its args via GetMutableArgs(), but the owner of this
  // object may need to access the original args via GetOriginalArgs() (the
  // owner could also copy the args before passing them to the extension
  // function, but that would result in an unnecessary copy when the extension
  // function doesn't modify its args).
  std::optional<base::ListValue> original_args_;

  base::ElapsedTimer timer_;

  // The results of the API. This should be populated through the Respond()/
  // RespondNow() methods. In legacy implementations, this is set directly, and
  // should be set before calling SendResponse().
  std::optional<base::ListValue> results_;

  // Any detailed error from the API. This should be populated by the derived
  // class before Run() returns.
  std::string error_;

  // The callback to run once the function has done execution.
  ResponseCallback response_callback_;

  // UUID for this request.
  base::Uuid request_uuid_;

  // The name of this function.
  const char* name_ = nullptr;

  // The URL of the frame which is making this request
  GURL source_url_;

  // True if the js caller provides a callback function to receive the response
  // of this call.
  bool has_callback_ = false;

  // True if this callback should include information from incognito contexts
  // even if our profile_ is non-incognito. Note that in the case of a "split"
  // mode extension, this will always be false, and we will limit access to
  // data from within the same profile_ (either incognito or not).
  bool include_incognito_information_ = false;

  // True if the call was made in response of user gesture.
  bool user_gesture_ = false;

  // Any class that gets a malformed message should set this to true before
  // returning.  Usually we want to kill the message sending process.
  bool bad_message_ = false;

  // Set to true when an extension function is created successfully without
  // error. This implies all setup state should be valid on the function for
  // some assertions made during destruction.
  bool did_initialize_ = false;

  // Set to true when RunWithValidation() is called, to look for callers using
  // the method more than once on a single ExtensionFunction. Note that some
  // ExtensionFunction objects may be created but not run, for example due to
  // quota limits.
  bool did_run_ = false;

  // The sample value to record with the histogram API when the function
  // is invoked.
  extensions::functions::HistogramValue histogram_value_ =
      extensions::functions::UNKNOWN;

  // The type of the JavaScript context where this call originated.
  extensions::mojom::ContextType source_context_type_ =
      extensions::mojom::ContextType::kUnspecified;

  // The context ID of the browser context where this call originated.
  int context_id_ = extensions::kUnspecifiedContextId;

  // The process ID of the page that triggered this function call, or -1
  // if unknown.
  int source_process_id_ = -1;

  // Set to the ID of the calling worker if this function was invoked by an
  // extension service worker context.
  std::optional<extensions::WorkerId> worker_id_;

  // A keepalive for the associated service worker. Only populated if this was
  // triggered by an extension service worker. In a unique_ptr instead of an
  // optional because it's unclear if the pre-allocated memory overhead is
  // worthwhile (given the number of calls from e.g. webui).
  std::unique_ptr<extensions::ServiceWorkerKeepalive> service_worker_keepalive_;

  // The response type of the function, if the response has been sent.
  std::unique_ptr<ResponseType> response_type_;

  // If set to true, preserves `results_`, even after SendResponseImpl() was
  // called.
  //
  // SendResponseImpl() moves the results out of `this` through
  // ResponseCallback, and calling this method avoids that. This is necessary
  // for tests that use test_utils::RunFunction*(), as those tests typically
  // retrieve the result afterwards through GetResultListForTest().
  // TODO(crbug.com/40803310): Remove this once GetResultListForTest() is
  // removed after ensuring consumers only use RunFunctionAndReturnResult() to
  // retrieve the results.
  bool preserve_results_for_testing_ = false;

  // The dispatcher that will service this extension function call.
  base::WeakPtr<extensions::ExtensionFunctionDispatcher> dispatcher_;

  // Obtained via `dispatcher_` when it is set. It automatically resets to
  // nullptr when the BrowserContext is shutdown (much like a WeakPtr).
  raw_ptr<content::BrowserContext> browser_context_ = nullptr;
  raw_ptr<content::BrowserContext> browser_context_for_testing_ = nullptr;

  // Subscription for a callback that runs when the BrowserContext* is
  // destroyed.
  base::CallbackListSubscription shutdown_subscription_;

  // The RenderFrameHost we will send responses to.
  raw_ptr<content::RenderFrameHost> render_frame_host_ = nullptr;

  std::unique_ptr<RenderFrameHostTracker> tracker_;

  // The blobs transferred to the renderer process.
  std::vector<blink::mojom::SerializedBlobPtr> transferred_blobs_;

  // The JS call stack snapshot captured at function invocation time.
  std::optional<extensions::StackTrace> js_callstack_;
};

#endif  // EXTENSIONS_BROWSER_EXTENSION_FUNCTION_H_
