[launcher-lacros] Add Launcher Search <-> Lacros interface.

This CL adds a new crosapi mojom interface allowing launcher search and
lacros to communicate between each other. It also provides
implementation for the interface.

Bug: 1228587
Change-Id: I4d3a735bbdc7695b65e79c94cc45a352ff0ce7d1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3292782
Reviewed-by: Hidehiko Abe <hidehiko@chromium.org>
Commit-Queue: Rachel Wong <wrong@chromium.org>
Cr-Commit-Position: refs/heads/main@{#963885}
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 75c0d2af..e88b6514 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -5194,6 +5194,8 @@
       "lacros/lacros_startup_infobar_delegate.h",
       "lacros/lacros_url_handling.cc",
       "lacros/lacros_url_handling.h",
+      "lacros/launcher_search/search_controller_lacros.cc",
+      "lacros/launcher_search/search_controller_lacros.h",
       "lacros/metrics_reporting_observer.cc",
       "lacros/metrics_reporting_observer.h",
       "lacros/net/lacros_extension_proxy_tracker.cc",
diff --git a/chrome/browser/ash/crosapi/BUILD.gn b/chrome/browser/ash/crosapi/BUILD.gn
index fb4d75fd..ed3553d 100644
--- a/chrome/browser/ash/crosapi/BUILD.gn
+++ b/chrome/browser/ash/crosapi/BUILD.gn
@@ -133,6 +133,8 @@
     "resource_manager_ash.h",
     "screen_manager_ash.cc",
     "screen_manager_ash.h",
+    "search_provider_ash.cc",
+    "search_provider_ash.h",
     "select_file_ash.cc",
     "select_file_ash.h",
     "structured_metrics_service_ash.cc",
diff --git a/chrome/browser/ash/crosapi/browser_util.cc b/chrome/browser/ash/crosapi/browser_util.cc
index 6af435b..26b126e5 100644
--- a/chrome/browser/ash/crosapi/browser_util.cc
+++ b/chrome/browser/ash/crosapi/browser_util.cc
@@ -253,7 +253,7 @@
 }
 
 static_assert(
-    crosapi::mojom::Crosapi::Version_ == 61,
+    crosapi::mojom::Crosapi::Version_ == 62,
     "if you add a new crosapi, please add it to kInterfaceVersionEntries");
 
 }  // namespace
diff --git a/chrome/browser/ash/crosapi/crosapi_ash.cc b/chrome/browser/ash/crosapi/crosapi_ash.cc
index 3ffcb38..e510fe5c 100644
--- a/chrome/browser/ash/crosapi/crosapi_ash.cc
+++ b/chrome/browser/ash/crosapi/crosapi_ash.cc
@@ -58,6 +58,7 @@
 #include "chrome/browser/ash/crosapi/remoting_ash.h"
 #include "chrome/browser/ash/crosapi/resource_manager_ash.h"
 #include "chrome/browser/ash/crosapi/screen_manager_ash.h"
+#include "chrome/browser/ash/crosapi/search_provider_ash.h"
 #include "chrome/browser/ash/crosapi/select_file_ash.h"
 #include "chrome/browser/ash/crosapi/structured_metrics_service_ash.h"
 #include "chrome/browser/ash/crosapi/system_display_ash.h"
@@ -167,6 +168,7 @@
       remoting_ash_(std::make_unique<RemotingAsh>()),
       resource_manager_ash_(std::make_unique<ResourceManagerAsh>()),
       screen_manager_ash_(std::make_unique<ScreenManagerAsh>()),
+      search_provider_ash_(std::make_unique<SearchProviderAsh>()),
       select_file_ash_(std::make_unique<SelectFileAsh>()),
       stable_video_decoder_factory_ash_(
           std::make_unique<media::StableVideoDecoderFactoryService>()),
@@ -402,6 +404,11 @@
   cert_database_ash_->BindReceiver(std::move(receiver));
 }
 
+void CrosapiAsh::BindSearchControllerRegistry(
+    mojo::PendingReceiver<mojom::SearchControllerRegistry> receiver) {
+  search_provider_ash_->BindReceiver(std::move(receiver));
+}
+
 void CrosapiAsh::BindSystemDisplay(
     mojo::PendingReceiver<mojom::SystemDisplay> receiver) {
   system_display_ash_->BindReceiver(std::move(receiver));
diff --git a/chrome/browser/ash/crosapi/crosapi_ash.h b/chrome/browser/ash/crosapi/crosapi_ash.h
index f27b1c5..b1bfa052 100644
--- a/chrome/browser/ash/crosapi/crosapi_ash.h
+++ b/chrome/browser/ash/crosapi/crosapi_ash.h
@@ -60,6 +60,7 @@
 class RemotingAsh;
 class ResourceManagerAsh;
 class ScreenManagerAsh;
+class SearchProviderAsh;
 class SelectFileAsh;
 class StructuredMetricsServiceAsh;
 class SystemDisplayAsh;
@@ -172,6 +173,8 @@
       mojo::PendingReceiver<mojom::ResourceManager> receiver) override;
   void BindScreenManager(
       mojo::PendingReceiver<mojom::ScreenManager> receiver) override;
+  void BindSearchControllerRegistry(
+      mojo::PendingReceiver<mojom::SearchControllerRegistry> receiver) override;
   void BindSelectFile(
       mojo::PendingReceiver<mojom::SelectFile> receiver) override;
   void BindSensorHalClient(
@@ -239,6 +242,10 @@
     return kiosk_session_service_ash_.get();
   }
 
+  SearchProviderAsh* search_provider_ash() {
+    return search_provider_ash_.get();
+  }
+
   WebPageInfoFactoryAsh* web_page_info_factory_ash() {
     return web_page_info_factory_ash_.get();
   }
@@ -310,6 +317,7 @@
   std::unique_ptr<RemotingAsh> remoting_ash_;
   std::unique_ptr<ResourceManagerAsh> resource_manager_ash_;
   std::unique_ptr<ScreenManagerAsh> screen_manager_ash_;
+  std::unique_ptr<SearchProviderAsh> search_provider_ash_;
   std::unique_ptr<SelectFileAsh> select_file_ash_;
   std::unique_ptr<media::StableVideoDecoderFactoryService>
       stable_video_decoder_factory_ash_;
diff --git a/chrome/browser/ash/crosapi/crosapi_util.cc b/chrome/browser/ash/crosapi/crosapi_util.cc
index 2032d79c..2b2873a 100644
--- a/chrome/browser/ash/crosapi/crosapi_util.cc
+++ b/chrome/browser/ash/crosapi/crosapi_util.cc
@@ -52,6 +52,7 @@
 #include "chromeos/crosapi/mojom/image_writer.mojom.h"
 #include "chromeos/crosapi/mojom/keystore_service.mojom.h"
 #include "chromeos/crosapi/mojom/kiosk_session_service.mojom.h"
+#include "chromeos/crosapi/mojom/launcher_search.mojom.h"
 #include "chromeos/crosapi/mojom/local_printer.mojom.h"
 #include "chromeos/crosapi/mojom/login_state.mojom.h"
 #include "chromeos/crosapi/mojom/message_center.mojom.h"
@@ -195,6 +196,7 @@
     MakeInterfaceVersionEntry<crosapi::mojom::Remoting>(),
     MakeInterfaceVersionEntry<crosapi::mojom::ResourceManager>(),
     MakeInterfaceVersionEntry<crosapi::mojom::ScreenManager>(),
+    MakeInterfaceVersionEntry<crosapi::mojom::SearchControllerRegistry>(),
     MakeInterfaceVersionEntry<crosapi::mojom::StructuredMetricsService>(),
     MakeInterfaceVersionEntry<crosapi::mojom::SnapshotCapturer>(),
     MakeInterfaceVersionEntry<crosapi::mojom::SystemDisplay>(),
diff --git a/chrome/browser/ash/crosapi/search_provider_ash.cc b/chrome/browser/ash/crosapi/search_provider_ash.cc
new file mode 100644
index 0000000..fbaf456
--- /dev/null
+++ b/chrome/browser/ash/crosapi/search_provider_ash.cc
@@ -0,0 +1,66 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ash/crosapi/search_provider_ash.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/logging.h"
+
+namespace crosapi {
+
+SearchProviderAsh::SearchProviderAsh() = default;
+SearchProviderAsh::~SearchProviderAsh() = default;
+
+void SearchProviderAsh::BindReceiver(
+    mojo::PendingReceiver<mojom::SearchControllerRegistry> pending_receiver) {
+  registry_receivers_.Add(this, std::move(pending_receiver));
+}
+
+void SearchProviderAsh::Search(const std::u16string& query,
+                               SearchResultsReceivedCallback callback) {
+  if (search_controller_.is_bound() && search_controller_.is_connected()) {
+    search_controller_->Search(
+        query, base::BindOnce(&SearchProviderAsh::BindPublisher,
+                              weak_factory_.GetWeakPtr(), std::move(callback)));
+  }
+}
+
+void SearchProviderAsh::RegisterSearchController(
+    mojo::PendingRemote<mojom::SearchController> search_controller) {
+  if (search_controller_.is_bound() && search_controller_.is_connected()) {
+    LOG(ERROR) << "Search Controller is already connected.";
+    return;
+  }
+
+  search_controller_.reset();
+  search_controller_.Bind(std::move(search_controller));
+}
+
+void SearchProviderAsh::OnSearchResultsReceived(
+    mojom::SearchStatus status,
+    absl::optional<std::vector<mojom::SearchResultPtr>> results) {
+  const bool result_expected = status == mojom::SearchStatus::kInProgress ||
+                               status == mojom::SearchStatus::kDone;
+  const auto& callback = publisher_receivers_.current_context();
+  if (result_expected && results.has_value() && !callback.is_null()) {
+    callback.Run(std::move(results.value()));
+    return;
+  }
+
+  if (status == mojom::SearchStatus::kError) {
+    LOG(ERROR) << "Search failed.";
+    publisher_receivers_.Remove(publisher_receivers_.current_receiver());
+  }
+}
+
+void SearchProviderAsh::BindPublisher(
+    SearchResultsReceivedCallback callback,
+    mojo::PendingAssociatedReceiver<mojom::SearchResultsPublisher> publisher) {
+  publisher_receivers_.Add(this, std::move(publisher), std::move(callback));
+}
+
+}  // namespace crosapi
diff --git a/chrome/browser/ash/crosapi/search_provider_ash.h b/chrome/browser/ash/crosapi/search_provider_ash.h
new file mode 100644
index 0000000..37b3af4
--- /dev/null
+++ b/chrome/browser/ash/crosapi/search_provider_ash.h
@@ -0,0 +1,75 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ASH_CROSAPI_SEARCH_PROVIDER_ASH_H_
+#define CHROME_BROWSER_ASH_CROSAPI_SEARCH_PROVIDER_ASH_H_
+
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "chromeos/crosapi/mojom/launcher_search.mojom.h"
+#include "mojo/public/cpp/bindings/associated_receiver_set.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+
+namespace crosapi {
+
+// Implements the crosapi interface for launcher search. Lives ash-chrome on UI
+// thread.
+// IMPORTANT: This search API should only be used by the launcher, because
+// in-flight queries will be cancelled whenever a new query is issued.
+class SearchProviderAsh : public mojom::SearchResultsPublisher,
+                          public mojom::SearchControllerRegistry {
+ public:
+  SearchProviderAsh();
+  SearchProviderAsh(const SearchProviderAsh&) = delete;
+  SearchProviderAsh& operator=(const SearchProviderAsh&) = delete;
+  ~SearchProviderAsh() override;
+
+  void BindReceiver(
+      mojo::PendingReceiver<mojom::SearchControllerRegistry> receiver);
+
+  using SearchResultsReceivedCallback =
+      base::RepeatingCallback<void(std::vector<mojom::SearchResultPtr>)>;
+  // Sends search query to lacros. The callback will be called each time results
+  // are received from lacros via OnSearchResultsReceived().
+  // If a search query is called while there is an in-flight search query, the
+  // in-flight search query will be cancelled (from lacros side) before the new
+  // search query is executed.
+  // When lacros finishes the search, it'll terminate the connection and no more
+  // results will be sent.
+  void Search(const std::u16string& query,
+              SearchResultsReceivedCallback callback);
+
+  // mojom::SearchControllerRegistry overrides:
+  void RegisterSearchController(
+      mojo::PendingRemote<mojom::SearchController> search_controller) override;
+
+  // mojom::SearchResultsPublisher overrides:
+  void OnSearchResultsReceived(
+      mojom::SearchStatus status,
+      absl::optional<std::vector<mojom::SearchResultPtr>> results) override;
+
+ private:
+  void BindPublisher(
+      SearchResultsReceivedCallback callback,
+      mojo::PendingAssociatedReceiver<mojom::SearchResultsPublisher> publisher);
+
+  // Since we only need one connection to fetch the results, we'll only support
+  // one crosapi connection here.
+  mojo::Remote<mojom::SearchController> search_controller_;
+
+  mojo::ReceiverSet<mojom::SearchControllerRegistry> registry_receivers_;
+  mojo::AssociatedReceiverSet<mojom::SearchResultsPublisher,
+                              SearchResultsReceivedCallback>
+      publisher_receivers_;
+
+  base::WeakPtrFactory<SearchProviderAsh> weak_factory_{this};
+};
+
+}  // namespace crosapi
+
+#endif  // CHROME_BROWSER_ASH_CROSAPI_SEARCH_PROVIDER_ASH_H_
diff --git a/chrome/browser/lacros/chrome_browser_main_extra_parts_lacros.cc b/chrome/browser/lacros/chrome_browser_main_extra_parts_lacros.cc
index 487bdbb..8dca009 100644
--- a/chrome/browser/lacros/chrome_browser_main_extra_parts_lacros.cc
+++ b/chrome/browser/lacros/chrome_browser_main_extra_parts_lacros.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/lacros/lacros_extension_apps_controller.h"
 #include "chrome/browser/lacros/lacros_extension_apps_publisher.h"
 #include "chrome/browser/lacros/lacros_memory_pressure_evaluator.h"
+#include "chrome/browser/lacros/launcher_search/search_controller_lacros.h"
 #include "chrome/browser/lacros/screen_orientation_delegate_lacros.h"
 #include "chrome/browser/lacros/standalone_browser_test_controller.h"
 #include "chrome/browser/lacros/task_manager_lacros.h"
@@ -40,6 +41,7 @@
       std::make_unique<crosapi::WebPageInfoProviderLacros>();
   screen_orientation_delegate_ =
       std::make_unique<ScreenOrientationDelegateLacros>();
+  search_controller_ = std::make_unique<crosapi::SearchControllerLacros>();
 
   memory_pressure::MultiSourceMemoryPressureMonitor* monitor =
       static_cast<memory_pressure::MultiSourceMemoryPressureMonitor*>(
diff --git a/chrome/browser/lacros/chrome_browser_main_extra_parts_lacros.h b/chrome/browser/lacros/chrome_browser_main_extra_parts_lacros.h
index 7a56eac7..ac4dbe7 100644
--- a/chrome/browser/lacros/chrome_browser_main_extra_parts_lacros.h
+++ b/chrome/browser/lacros/chrome_browser_main_extra_parts_lacros.h
@@ -23,6 +23,7 @@
 class StandaloneBrowserTestController;
 
 namespace crosapi {
+class SearchControllerLacros;
 class TaskManagerLacros;
 class WebPageInfoProviderLacros;
 }  // namespace crosapi
@@ -53,6 +54,9 @@
   // Handles browser action requests from ash-chrome.
   std::unique_ptr<BrowserServiceLacros> browser_service_;
 
+  // Handles search queries from ash-chrome.
+  std::unique_ptr<crosapi::SearchControllerLacros> search_controller_;
+
   // Handles task manager crosapi from ash for sending lacros tasks to ash.
   std::unique_ptr<crosapi::TaskManagerLacros> task_manager_provider_;
 
diff --git a/chrome/browser/lacros/launcher_search/OWNERS b/chrome/browser/lacros/launcher_search/OWNERS
new file mode 100644
index 0000000..5b86ca73
--- /dev/null
+++ b/chrome/browser/lacros/launcher_search/OWNERS
@@ -0,0 +1,3 @@
+tby@chromium.org
+thanhdng@chromium.org
+wrong@chromium.org
diff --git a/chrome/browser/lacros/launcher_search/search_controller_lacros.cc b/chrome/browser/lacros/launcher_search/search_controller_lacros.cc
new file mode 100644
index 0000000..c5caefb
--- /dev/null
+++ b/chrome/browser/lacros/launcher_search/search_controller_lacros.cc
@@ -0,0 +1,32 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/lacros/launcher_search/search_controller_lacros.h"
+
+#include <utility>
+
+#include "chromeos/lacros/lacros_service.h"
+
+namespace crosapi {
+
+SearchControllerLacros::SearchControllerLacros() {
+  chromeos::LacrosService* service = chromeos::LacrosService::Get();
+  if (!service->IsAvailable<mojom::SearchControllerRegistry>())
+    return;
+  service->GetRemote<mojom::SearchControllerRegistry>()
+      ->RegisterSearchController(receiver_.BindNewPipeAndPassRemote());
+}
+
+SearchControllerLacros::~SearchControllerLacros() = default;
+
+void SearchControllerLacros::Search(const std::u16string& query,
+                                    SearchCallback callback) {
+  // Reset the remote and send a new pending receiver to ash.
+  publisher_.reset();
+  std::move(callback).Run(publisher_.BindNewEndpointAndPassReceiver());
+
+  // TODO(crbug/1228587): Fill the results here.
+}
+
+}  // namespace crosapi
diff --git a/chrome/browser/lacros/launcher_search/search_controller_lacros.h b/chrome/browser/lacros/launcher_search/search_controller_lacros.h
new file mode 100644
index 0000000..f808429
--- /dev/null
+++ b/chrome/browser/lacros/launcher_search/search_controller_lacros.h
@@ -0,0 +1,37 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_LACROS_LAUNCHER_SEARCH_SEARCH_CONTROLLER_LACROS_H_
+#define CHROME_BROWSER_LACROS_LAUNCHER_SEARCH_SEARCH_CONTROLLER_LACROS_H_
+
+#include <string>
+
+#include "base/memory/weak_ptr.h"
+#include "chromeos/crosapi/mojom/launcher_search.mojom.h"
+#include "mojo/public/cpp/bindings/associated_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+
+namespace crosapi {
+
+// Implements crosapi interface for launcher search controller.
+class SearchControllerLacros : public mojom::SearchController {
+ public:
+  SearchControllerLacros();
+  SearchControllerLacros(const SearchControllerLacros&) = delete;
+  SearchControllerLacros& operator=(const SearchControllerLacros&) = delete;
+  ~SearchControllerLacros() override;
+
+ private:
+  // mojom::SearchController:
+  void Search(const std::u16string& query, SearchCallback callback) override;
+
+  mojo::AssociatedRemote<mojom::SearchResultsPublisher> publisher_;
+  mojo::Receiver<mojom::SearchController> receiver_{this};
+
+  base::WeakPtrFactory<SearchControllerLacros> weak_ptr_factory_{this};
+};
+
+}  // namespace crosapi
+
+#endif  // CHROME_BROWSER_LACROS_LAUNCHER_SEARCH_SEARCH_CONTROLLER_LACROS_H_
diff --git a/chromeos/crosapi/mojom/BUILD.gn b/chromeos/crosapi/mojom/BUILD.gn
index d0bc556..095fe31f 100644
--- a/chromeos/crosapi/mojom/BUILD.gn
+++ b/chromeos/crosapi/mojom/BUILD.gn
@@ -39,6 +39,7 @@
     "keystore_error.mojom",
     "keystore_service.mojom",
     "kiosk_session_service.mojom",
+    "launcher_search.mojom",
     "local_printer.mojom",
     "login_state.mojom",
     "message_center.mojom",
diff --git a/chromeos/crosapi/mojom/crosapi.mojom b/chromeos/crosapi/mojom/crosapi.mojom
index ecb0c74..82120d3 100644
--- a/chromeos/crosapi/mojom/crosapi.mojom
+++ b/chromeos/crosapi/mojom/crosapi.mojom
@@ -32,6 +32,7 @@
 import "chromeos/crosapi/mojom/idle_service.mojom";
 import "chromeos/crosapi/mojom/image_writer.mojom";
 import "chromeos/crosapi/mojom/keystore_service.mojom";
+import "chromeos/crosapi/mojom/launcher_search.mojom";
 import "chromeos/crosapi/mojom/local_printer.mojom";
 import "chromeos/crosapi/mojom/login_state.mojom";
 import "chromeos/crosapi/mojom/policy_service.mojom";
@@ -93,8 +94,8 @@
 // please note the milestone when you added it, to help us reason about
 // compatibility between the client applications and older ash-chrome binaries.
 //
-// Next version: 62
-// Next method id: 66
+// Next version: 63
+// Next method id: 67
 [Stable, Uuid="8b79c34f-2bf8-4499-979a-b17cac522c1e",
  RenamedFrom="crosapi.mojom.AshChromeService"]
 interface Crosapi {
@@ -385,6 +386,11 @@
   [MinVersion=36] BindResourceManager@41(
       pending_receiver<ResourceManager> receiver);
 
+  // Binds the search controller which send queries from ash to lacros.
+  // Added in M99.
+  [MinVersion=62] BindSearchControllerRegistry@66(
+      pending_receiver<SearchControllerRegistry> receiver);
+
   // Binds the System Display interface for querying display info.
   // Added in M92.
   [MinVersion=24] BindSystemDisplay@29(
diff --git a/chromeos/crosapi/mojom/launcher_search.mojom b/chromeos/crosapi/mojom/launcher_search.mojom
new file mode 100644
index 0000000..6571d4bb
--- /dev/null
+++ b/chromeos/crosapi/mojom/launcher_search.mojom
@@ -0,0 +1,152 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module crosapi.mojom;
+
+import "mojo/public/mojom/base/string16.mojom";
+import "ui/gfx/image/mojom/image.mojom";
+import "url/mojom/url.mojom";
+
+[Stable, Extensible]
+enum SearchStatus {
+  // Indicates an error with the search. No results will be sent with this
+  // status, and there may or may not be further results sent.
+  [Default] kError = 0,
+  // Search session is complete and no more results will be sent. This
+  // accompanies the final set of results.
+  kDone = 1,
+  // Search session is still in progress and further results may be sent. This
+  // accompanies a set of results.
+  kInProgress = 2,
+  // Search session has been cancelled due to a newer query. No more results
+  // will be sent.
+  kCancelled = 3,
+};
+
+// Enum represents the result type.
+[Stable, Extensible]
+enum SearchResultType {
+  [Default] kUnknown = 0,
+  // This represents the results come from Omnibox's AutocompleteController
+  // of the browser.
+  kOmniboxResult = 1,
+};
+
+// Struct represents search result.
+// Next min ID: 14
+[Stable]
+struct SearchResult {
+  // Type of the result. Used to distinguish between different types of result.
+  SearchResultType type@0;
+  // Relevance of the result. Used for scoring/ranking.
+  double relevance@1;
+  // Destination URL of the result. Used for opening the result.
+  url.mojom.Url? destination_url@2;
+
+  // The following fields represent additional information about search
+  // results. These are optional and will be filled depending on the result.
+
+  // Whether the result is an omnibox search result or not. Used for
+  // kOmniboxResult type results.
+  OptionalBool is_omnibox_search@3;
+  // Whether the result is an answer result or not. Used for kOmniboxResult
+  // type results.
+  OptionalBool is_answer@4;
+  // The Omnibox subtype of the result, used for kOmniboxResult type results.
+  // This defaults to kUnset.
+  OmniboxType omnibox_type@5;
+  // The Omnibox answer subtype of the result, used for Omnibox answer results.
+  // This defaults to kUnset.
+  AnswerType answer_type@6;
+
+  // The image url of the result, if any. Used to download the result image.
+  url.mojom.Url? image_url@7;
+  // Favicon of the result.
+  gfx.mojom.ImageSkia? favicon@8;
+
+  // The contents of the result. Used to display the result.
+  mojo_base.mojom.String16? contents@9;
+  // Additional contents for the result. Used to display the result.
+  mojo_base.mojom.String16? additional_contents@10;
+  // Description of the result. Used to display the result.
+  mojo_base.mojom.String16? description@11;
+  // Additional description for the result. Used to display the result.
+  mojo_base.mojom.String16? additional_description@12;
+  // Text type of the additional description, if any. Defaults to kUnset.
+  TextType additional_description_type@13;
+
+  [Stable, Extensible]
+  enum OptionalBool {
+    kUnset,
+    kFalse,
+    kTrue,
+  };
+
+  // Enum representing the Omnibox result subtype.
+  [Stable, Extensible]
+  enum OmniboxType {
+    [Default] kUnset = 0,
+    kRichImage = 1,
+    kFavicon = 2,
+    kBookmark = 3,
+    kDomain = 4,
+    kSearch = 5,
+    kHistory = 6,
+    kCalculator = 7,
+  };
+
+  // Enum representing the Omnibox answer subtype.
+  [Stable, Extensible]
+  enum AnswerType {
+    [Default] kUnset = 0,
+    kDefaultAnswer = 1,
+    kWeather = 2,
+    kCurrency = 3,
+    kDictionary = 4,
+    kFinance = 5,
+    kSunrise = 6,
+    kTranslation = 7,
+    kWhenIs = 8,
+  };
+
+  // Enum representing special text types.
+  [Stable, Extensible]
+  enum TextType {
+    [Default] kUnset = 0,
+    kPositive = 1,
+    kNegative = 2,
+  };
+};
+
+// Interface to send results from lacros to ash. Implemented in ash.
+// Next min method ID: 1
+[Stable, Uuid="ce797aae-286e-4b63-b7b3-090bf5040818"]
+interface SearchResultsPublisher {
+  // Sends search result from lacros to ash. For each query, this will be called
+  // multiple times, each time it will overwrite the existing results. When all
+  // results for a query are already sent, the connection will be reset and no
+  // more results will be sent.
+  OnSearchResultsReceived@0(SearchStatus status, array<SearchResult>? result);
+};
+
+// Interface to send query from ash to lacros. Implemented in lacros.
+// Next min method ID: 2
+[Stable, Uuid="c2d77467-b04d-4b10-8f54-de52c3cbe30d"]
+interface SearchController {
+  // Sends search queries from ash to lacros. If a search query is called while
+  // there is an in-flight search query, the in-flight search query will be
+  // cancelled before the new search query being executed.
+  Search@0(mojo_base.mojom.String16 query) =>
+      (pending_associated_receiver<SearchResultsPublisher> publisher);
+};
+
+// Interface to register the search controller. Implemented in ash.
+// Next min method ID: 1
+[Stable, Uuid="1dc4306b-50af-4b43-a1f0-552e7010971e"]
+interface SearchControllerRegistry {
+  // Lacros can register the search controller to ash so that ash can
+  // start making calls.
+  RegisterSearchController@0(
+      pending_remote<SearchController> search_controller);
+};
diff --git a/chromeos/lacros/lacros_service.cc b/chromeos/lacros/lacros_service.cc
index 2cbc415..7e4fa9b5 100644
--- a/chromeos/lacros/lacros_service.cc
+++ b/chromeos/lacros/lacros_service.cc
@@ -41,6 +41,7 @@
 #include "chromeos/crosapi/mojom/image_writer.mojom.h"
 #include "chromeos/crosapi/mojom/keystore_service.mojom.h"
 #include "chromeos/crosapi/mojom/kiosk_session_service.mojom.h"
+#include "chromeos/crosapi/mojom/launcher_search.mojom.h"
 #include "chromeos/crosapi/mojom/local_printer.mojom.h"
 #include "chromeos/crosapi/mojom/login_state.mojom.h"
 #include "chromeos/crosapi/mojom/message_center.mojom.h"
@@ -330,6 +331,10 @@
                   &crosapi::mojom::Crosapi::BindSelectFile,
                   Crosapi::MethodMinVersions::kBindSelectFileMinVersion>();
   ConstructRemote<
+      crosapi::mojom::SearchControllerRegistry,
+      &crosapi::mojom::Crosapi::BindSearchControllerRegistry,
+      Crosapi::MethodMinVersions::kBindSearchControllerRegistryMinVersion>();
+  ConstructRemote<
       crosapi::mojom::StructuredMetricsService,
       &crosapi::mojom::Crosapi::BindStructuredMetricsService,
       Crosapi::MethodMinVersions::kBindStructuredMetricsServiceMinVersion>();