#ifndef CHROME_BROWSER_ACTOR_EXECUTION_ENGINE_H_
#define CHROME_BROWSER_ACTOR_EXECUTION_ENGINE_H_
#include <memory>
#include <optional>
#include <vector>
#include "base/callback_list.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/safe_ref.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/types/id_type.h"
#include "chrome/browser/actor/actor_task.h"
#include "chrome/browser/actor/aggregated_journal.h"
#include "chrome/browser/actor/site_policy.h"
#include "chrome/browser/actor/tools/tool_controller.h"
#include "chrome/browser/actor/tools/tool_delegate.h"
#include "chrome/browser/password_manager/actor_login/actor_login_service.h"
#include "chrome/common/actor.mojom-forward.h"
#include "chrome/common/actor/task_id.h"
#include "components/autofill/core/browser/integrators/glic/actor_form_filling_types.h"
#include "components/tabs/public/tab_interface.h"
#include "content/public/browser/web_contents_observer.h"
#include "third_party/abseil-cpp/absl/container/flat_hash_set.h"
class Profile;
namespace affiliations {
struct Facet;
}
namespace content {
class NavigationHandle;
}
namespace url {
class Origin;
}
namespace actor {
class ActorTask;
class ToolRequest;
namespace ui {
class UiEventDispatcher;
}
class ExecutionEngine : public ToolDelegate {
public:
enum class State {
kInit = 0,
kStartAction,
kToolCreateAndVerify,
kUiPreInvoke,
kToolInvoke,
kUiPostInvoke,
kComplete,
};
enum class GatingDecision {
kAllowSameOrigin = 0,
kAllowByStaticList = 1,
kBlockByStaticList = 2,
kNeedsAsyncCheck = 3,
kMaxValue = kNeedsAsyncCheck,
};
class StateObserver : public base::CheckedObserver {
public:
~StateObserver() override = default;
virtual void OnStateChanged(State old_state, State new_state) = 0;
};
explicit ExecutionEngine(Profile* profile);
ExecutionEngine(const ExecutionEngine&) = delete;
ExecutionEngine& operator=(const ExecutionEngine&) = delete;
~ExecutionEngine() override;
static std::unique_ptr<ExecutionEngine> CreateForTesting(
Profile* profile,
std::unique_ptr<ui::UiEventDispatcher> ui_event_dispatcher);
void SetOwner(ActorTask* task);
void CancelOngoingActions(mojom::ActionResultCode reason);
void FailCurrentTool(mojom::ActionResultCode reason);
void Act(std::vector<std::unique_ptr<ToolRequest>>&& actions,
ActorTask::ActCallback callback);
base::WeakPtr<ExecutionEngine> GetWeakPtr();
bool HasActionSequence() const;
Profile& GetProfile() override;
AggregatedJournal& GetJournal() override;
favicon::FaviconService* GetFaviconService() override;
void IsAcceptableNavigationDestination(
const GURL& url,
DecisionCallbackWithReason callback) override;
actor_login::ActorLoginService& GetActorLoginService() override;
autofill::ActorFormFillingService& GetActorFormFillingService() override;
void PromptToSelectCredential(
const std::vector<actor_login::Credential>& credentials,
const base::flat_map<std::string, gfx::Image>& icons,
ToolDelegate::CredentialSelectedCallback callback) override;
void SetUserSelectedCredential(
const CredentialWithPermission& credential,
base::OnceClosure affiliations_fetched) override;
const std::optional<CredentialWithPermission> GetUserSelectedCredential(
const url::Origin& request_origin) const override;
void RequestToShowAutofillSuggestions(
std::vector<autofill::ActorFormFillingRequest> requests,
AutofillSuggestionSelectedCallback callback) override;
void InterruptFromTool() override;
void UninterruptFromTool() override;
using AllowedOriginSet = absl::flat_hash_set<url::Origin>;
void AddWritableMainframeOrigins(
const AllowedOriginSet& added_writable_mainframe_origins);
using NavigationDecisionCallback =
base::OnceCallback<void(bool may_continue)>;
bool ShouldGateNavigation(content::NavigationHandle& navigation_handle,
NavigationDecisionCallback callback);
static std::string StateToString(State state);
void OnMayActOnTabDecision(const url::Origin& evaluated_origin,
MayActOnUrlBlockReason block_reason);
void UserTakeover(mojom::ActionResultCode takeover_response_code,
base::OnceCallback<void(bool)> callback);
void RunUserTakeoverCallbackIfExists(bool should_cancel);
void set_user_take_over_result(
std::optional<mojom::ActionResultCode> user_takeover_result) {
user_takeover_result_ = user_takeover_result;
}
std::optional<mojom::ActionResultCode> user_take_over_result() const {
return user_takeover_result_;
}
const base::flat_map<url::Origin, url::Origin>&
GetAffiliatedOriginMapForTesting() const {
return affiliated_origin_map_;
}
void AddObserver(StateObserver* observer);
void RemoveObserver(StateObserver* observer);
private:
class NewTabWebContentsObserver;
ExecutionEngine(Profile* profile,
std::unique_ptr<ui::UiEventDispatcher> ui_event_dispatcher);
void SetState(State state);
void KickOffNextAction();
void SafetyChecksForNextAction();
void DidFinishAsyncSafetyChecks(const url::Origin& evaluated_origin,
bool may_act);
void FailedOnTabBeforeToolCreation();
void ExecuteNextAction();
void PostToolCreate(mojom::ActionResultPtr result);
void FinishedUiPreInvoke(mojom::ActionResultPtr result);
void FinishedToolInvoke(mojom::ActionResultPtr result);
void FinishedUiPostInvoke(mojom::ActionResultPtr result);
void CompleteActions(mojom::ActionResultPtr result,
std::optional<size_t> action_index);
const ToolRequest& GetNextAction() const;
void OnAffiliationsReceived(const url::Origin& source_origin,
base::OnceClosure affiliations_fetched,
const std::vector<affiliations::Facet>& results,
bool success);
size_t InProgressActionIndex() const;
const ToolRequest& GetInProgressAction() const;
GatingDecision ShouldGateNavigationInternal(
content::NavigationHandle& navigation_handle,
NavigationDecisionCallback callback);
void LogNavigationGating(const std::optional<url::Origin>& initiator_origin,
const GURL& navigation_url,
bool applied_gate);
GatingDecision DetermineGatingDecision(const GURL& source_url,
const GURL& destination_url) const;
void CheckNavigationBlocklist(
const std::optional<url::Origin>& initiator_origin,
const GURL& navigation_url,
bool skip_prompt,
NavigationDecisionCallback callback);
void OnNavigationBlocklistDecision(
const std::optional<url::Origin> initiator_origin,
const GURL navigation_url,
bool skip_prompt,
NavigationDecisionCallback callback,
bool not_on_blocklist);
void HandleNavigationToNewOrigin(
const url::Origin& navigation_origin,
ExecutionEngine::NavigationDecisionCallback callback);
void SendNavigationConfirmationRequest(const url::Origin& navigation_origin,
NavigationDecisionCallback callback);
void OnNavigationConfirmationDecision(
url::Origin navigation_origin,
NavigationDecisionCallback callback,
webui::mojom::NavigationConfirmationResponsePtr response);
void SendUserConfirmationDialogRequest(const url::Origin& navigation_origin,
bool for_blocklisted_origin,
NavigationDecisionCallback callback);
void OnPromptUserToConfirmNavigationDecision(
url::Origin navigation_origin,
bool for_blocklisted_origin,
NavigationDecisionCallback callback,
webui::mojom::UserConfirmationDialogResponsePtr response);
State state_ = State::kInit;
static std::optional<base::TimeDelta> action_observation_delay_for_testing_;
raw_ptr<Profile> profile_;
base::SafeRef<AggregatedJournal> journal_;
raw_ptr<ActorTask> task_;
std::unique_ptr<ToolController> tool_controller_;
std::unique_ptr<actor_login::ActorLoginService> actor_login_service_;
std::unique_ptr<autofill::ActorFormFillingService>
actor_form_filling_service_;
std::unique_ptr<ui::UiEventDispatcher> ui_event_dispatcher_;
base::flat_map<url::Origin, url::Origin> affiliated_origin_map_;
std::vector<std::unique_ptr<ToolRequest>> action_sequence_;
ActorTask::ActCallback act_callback_;
size_t next_action_index_ = 0;
base::TimeTicks action_start_time_;
std::optional<mojom::ActionResultCode> external_tool_failure_reason_;
std::vector<ActionResultWithLatencyInfo> action_results_;
AllowedOriginSet allowed_navigation_origins_;
AllowedOriginSet user_confirmed_blocklisted_origins_;
base::flat_map<url::Origin, CredentialWithPermission>
user_selected_credentials_;
base::OnceCallback<void(bool )> user_takeover_callback_;
std::optional<mojom::ActionResultCode> user_takeover_result_;
base::ObserverList<StateObserver> observers_;
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<ExecutionEngine> actions_weak_ptr_factory_{this};
};
std::ostream& operator<<(std::ostream& o, const ExecutionEngine::State& s);
}
#endif