// 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 CHROME_BROWSER_APPS_APP_SHIM_APP_SHIM_HOST_MAC_H_
#define CHROME_BROWSER_APPS_APP_SHIM_APP_SHIM_HOST_MAC_H_
#include <memory>
#include <string>
#include <vector>
#include "base/files/file_path.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/process/process.h"
#include "base/threading/thread_checker.h"
#include "chrome/browser/web_applications/os_integration/mac/app_shim_launch.h"
#include "chrome/common/mac/app_shim.mojom.h"
#include "components/metrics/histogram_child_process.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
namespace apps {
using ShimLaunchedCallback = base::OnceCallback<void(base::Process)>;
using ShimTerminatedCallback = base::OnceClosure;
} // namespace apps
namespace remote_cocoa {
class ApplicationHost;
} // namespace remote_cocoa
class AppShimHostBootstrap;
// This is the counterpart to AppShimController in
// chrome/app/chrome_main_app_mode_mac.mm. The AppShimHost is owned by the
// AppShimManager, which implements its client interface.
class AppShimHost : public chrome::mojom::AppShimHost,
public metrics::HistogramChildProcess {
public:
// The interface through which the AppShimHost interacts with
// AppShimManager.
class Client {
public:
// Request that the handler launch the app shim process.
virtual void OnShimLaunchRequested(
AppShimHost* host,
web_app::LaunchShimUpdateBehavior update_behavior,
web_app::ShimLaunchMode launch_mode,
apps::ShimLaunchedCallback launched_callback,
apps::ShimTerminatedCallback terminated_callback) = 0;
// Invoked by the shim host when the connection to the shim process is
// closed. This is also called when we give up on trying to get a shim to
// connect.
virtual void OnShimProcessDisconnected(AppShimHost* host) = 0;
// Invoked by the shim host when the shim process receives a focus event.
virtual void OnShimFocus(AppShimHost* host) = 0;
// Invoked by the shim host when the shim process should reopen if needed.
virtual void OnShimReopen(AppShimHost* host) = 0;
// Invoked by the shim host when the shim opens a file, e.g, by dragging
// a file onto the dock icon.
virtual void OnShimOpenedFiles(
AppShimHost* host,
const std::vector<base::FilePath>& files) = 0;
// Invoked when a profile is selected from the menu bar.
virtual void OnShimSelectedProfile(AppShimHost* host,
const base::FilePath& profile_path) = 0;
//
virtual void OnShimOpenedAppSettings(AppShimHost* host) = 0;
// Invoked by the shim host when the shim opens a url, e.g, clicking a link
// in mail.
virtual void OnShimOpenedUrls(AppShimHost* host,
const std::vector<GURL>& urls) = 0;
// Invoked by the shim host when the app should be opened with an override
// url (e.g. user clicks on an item in the application dock menu).
virtual void OnShimOpenAppWithOverrideUrl(AppShimHost* host,
const GURL& override_url) = 0;
// Invoked by the shim host when the app is about to terminate (for example
// because the user quit it).
virtual void OnShimWillTerminate(AppShimHost* host) = 0;
// Invoked by the shim host when a change to the system level notification
// permission status has been detected.
virtual void OnNotificationPermissionStatusChanged(
AppShimHost* host,
mac_notifications::mojom::PermissionStatus status) = 0;
};
AppShimHost(Client* client,
const std::string& app_id,
const base::FilePath& profile_path,
bool uses_remote_views);
AppShimHost(const AppShimHost&) = delete;
AppShimHost& operator=(const AppShimHost&) = delete;
~AppShimHost() override;
bool UsesRemoteViews() const { return uses_remote_views_; }
// Returns true if an AppShimHostBootstrap has already connected to this
// host.
bool HasBootstrapConnected() const;
// Invoked to request that the shim be launched (if it has not been launched
// already).
void LaunchShim(
web_app::ShimLaunchMode launch_mode = web_app::ShimLaunchMode::kNormal);
// Invoked when the app shim has launched and connected to the browser.
virtual void OnBootstrapConnected(
std::unique_ptr<AppShimHostBootstrap> bootstrap);
// Functions to allow the handler to determine which app this host corresponds
// to.
base::FilePath GetProfilePath() const;
std::string GetAppId() const;
// Return the factory to use to create new widgets in the same process.
remote_cocoa::ApplicationHost* GetRemoteCocoaApplicationHost() const;
// Return the app shim interface. Virtual for tests.
virtual chrome::mojom::AppShim* GetAppShim() const;
void SetOnShimConnectedForTesting(base::OnceClosure closure);
// Returns kNullProcessId if no process has connected to this host yet.
base::ProcessId GetAppShimPid() const;
protected:
void ChannelError(uint32_t custom_reason, const std::string& description);
// Helper function to launch the app shim process.
void LaunchShimInternal(web_app::LaunchShimUpdateBehavior update_behavior,
web_app::ShimLaunchMode launch_mode);
// Called when LaunchShim has launched (or failed to launch) a process.
void OnShimProcessLaunched(web_app::LaunchShimUpdateBehavior update_behavior,
web_app::ShimLaunchMode launch_mode,
base::Process shim_process);
// Called when a shim process returned via OnShimLaunchCompleted has
// terminated.
void OnShimProcessTerminated(
web_app::LaunchShimUpdateBehavior update_behavior,
web_app::ShimLaunchMode launch_mode);
// chrome::mojom::AppShimHost.
void FocusApp() override;
void ReopenApp() override;
void FilesOpened(const std::vector<base::FilePath>& files) override;
void ProfileSelectedFromMenu(const base::FilePath& profile_path) override;
void OpenAppSettings() override;
void UrlsOpened(const std::vector<GURL>& urls) override;
void OpenAppWithOverrideUrl(const GURL& override_url) override;
void EnableAccessibilitySupport(
chrome::mojom::AppShimScreenReaderSupportMode mode) override;
void ApplicationWillTerminate() override;
void NotificationPermissionStatusChanged(
mac_notifications::mojom::PermissionStatus status) override;
// content::HistogramChildProcess:
void BindChildHistogramFetcherFactory(
mojo::PendingReceiver<metrics::mojom::ChildHistogramFetcherFactory>
factory) override;
// Weak, owns |this|.
const raw_ptr<Client> client_;
mojo::Receiver<chrome::mojom::AppShimHost> host_receiver_{this};
mojo::Remote<chrome::mojom::AppShim> app_shim_;
mojo::PendingReceiver<chrome::mojom::AppShim> app_shim_receiver_;
// Only allow LaunchShim to have any effect on the first time it is called. If
// that launch fails, it will re-launch (requesting that the shim be
// re-created).
bool launch_shim_has_been_called_ = false;
std::unique_ptr<AppShimHostBootstrap> bootstrap_;
std::unique_ptr<remote_cocoa::ApplicationHost> remote_cocoa_application_host_;
std::string app_id_;
base::OnceClosure on_shim_connected_for_testing_;
base::FilePath profile_path_;
const bool uses_remote_views_;
// Not a system-level PID, rather an ID assigned by content::ChildProcessHost
// used to identify this process when registering with
// metrics::SubprocessMetricsProvider.
const int child_process_host_id_;
// This holds the histogram allocator to be used for this app shim before it
// gets passed to the remote host when it finished launching.
std::unique_ptr<base::PersistentMemoryAllocator> histogram_allocator_;
// This class is only ever to be used on the UI thread.
THREAD_CHECKER(thread_checker_);
// This weak factory is used for launch callbacks only.
base::WeakPtrFactory<AppShimHost> launch_weak_factory_;
};
#endif // CHROME_BROWSER_APPS_APP_SHIM_APP_SHIM_HOST_MAC_H_