blob: 9ddf0389d7a4487678115067facff8ecb2046989 [file] [log] [blame]
// Copyright 2018 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_APPS_APP_SERVICE_APP_SERVICE_PROXY_H_
#define CHROME_BROWSER_APPS_APP_SERVICE_APP_SERVICE_PROXY_H_
#include <memory>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "chrome/services/app_service/public/cpp/app_registry_cache.h"
#include "chrome/services/app_service/public/cpp/icon_cache.h"
#include "chrome/services/app_service/public/cpp/icon_coalescer.h"
#include "components/keyed_service/core/keyed_service.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/apps/app_service/built_in_chromeos_apps.h"
#include "chrome/browser/apps/app_service/crostini_apps.h"
#include "chrome/browser/apps/app_service/extension_apps.h"
#endif // OS_CHROMEOS
class Profile;
namespace service_manager {
class Connector;
}
namespace apps {
// Singleton (per Profile) proxy and cache of an App Service's apps.
//
// Singleton-ness means that //chrome/browser code (e.g UI code) can find *the*
// proxy for a given Profile, and therefore share its caches.
//
// See chrome/services/app_service/README.md.
class AppServiceProxy : public KeyedService,
public apps::IconLoader,
public apps::mojom::Subscriber {
public:
static AppServiceProxy* CreateForTesting(
Profile* profile,
service_manager::Connector* connector);
explicit AppServiceProxy(Profile* profile);
~AppServiceProxy() override;
void ReInitializeForTesting(Profile* profile,
service_manager::Connector* connector);
apps::mojom::AppServicePtr& AppService();
apps::AppRegistryCache& AppRegistryCache();
// apps::IconLoader overrides.
apps::mojom::IconKeyPtr GetIconKey(const std::string& app_id) override;
std::unique_ptr<IconLoader::Releaser> LoadIconFromIconKey(
apps::mojom::AppType app_type,
const std::string& app_id,
apps::mojom::IconKeyPtr icon_key,
apps::mojom::IconCompression icon_compression,
int32_t size_hint_in_dip,
bool allow_placeholder_icon,
apps::mojom::Publisher::LoadIconCallback callback) override;
// TODO: Provide comments for public API methods.
void Launch(const std::string& app_id,
int32_t event_flags,
apps::mojom::LaunchSource launch_source,
int64_t display_id);
void SetPermission(const std::string& app_id,
apps::mojom::PermissionPtr permission);
void Uninstall(const std::string& app_id);
void OpenNativeSettings(const std::string& app_id);
void FlushMojoCallsForTesting();
apps::IconLoader* OverrideInnerIconLoaderForTesting(
apps::IconLoader* icon_loader);
void ReInitializeCrostiniForTesting(Profile* profile);
private:
// An adapter, presenting an IconLoader interface based on the underlying
// Mojo service (or on a fake implementation for testing).
//
// Conceptually, the ASP (the AppServiceProxy) is itself such an adapter:
// UI clients call the IconLoader::LoadIconFromIconKey method (which the ASP
// implements) and the ASP translates (i.e. adapts) these to Mojo calls (or
// C++ calls to the Fake). This diagram shows control flow going left to
// right (with "=c=>" and "=m=>" denoting C++ and Mojo calls), and the
// responses (callbacks) then run right to left in LIFO order:
//
// UI =c=> ASP =+=m=> MojoService
// | or
// +=c=> Fake
//
// It is more complicated in practice, as we want to insert IconLoader
// decorators (as in the classic "decorator" or "wrapper" design pattern) to
// provide optimizations like proxy-wide icon caching and IPC coalescing
// (de-duplication). Nonetheless, from a UI client's point of view, we would
// still like to present a simple API: that the ASP implements the IconLoader
// interface. We therefore split the "ASP" component into multiple
// sub-components. Once again, control flow runs from left to right, and
// inside the ASP, outer layers (wrappers) call into inner layers (wrappees):
//
// +------------------ ASP ------------------+
// | |
// UI =c=> | Outer =c=> MoreDecorators... =c=> Inner | =+=m=> MojoService
// | | | or
// +-----------------------------------------+ +=c=> Fake
//
// The inner_icon_loader_ field (of type InnerIconLoader) is the "Inner"
// component: the one that ultimately talks to the Mojo service.
//
// The outer_icon_loader_ field (of type IconCache) is the "Outer" component:
// the entry point for calls into the AppServiceProxy.
//
// Note that even if the ASP provides some icon caching, upstream UI clients
// may want to introduce further icon caching. See the commentary where
// IconCache::GarbageCollectionPolicy is defined.
//
// IPC coalescing would be one of the "MoreDecorators".
class InnerIconLoader : public apps::IconLoader {
public:
explicit InnerIconLoader(AppServiceProxy* host);
// apps::IconLoader overrides.
apps::mojom::IconKeyPtr GetIconKey(const std::string& app_id) override;
std::unique_ptr<IconLoader::Releaser> LoadIconFromIconKey(
apps::mojom::AppType app_type,
const std::string& app_id,
apps::mojom::IconKeyPtr icon_key,
apps::mojom::IconCompression icon_compression,
int32_t size_hint_in_dip,
bool allow_placeholder_icon,
apps::mojom::Publisher::LoadIconCallback callback) override;
// |host_| owns |this|, as the InnerIconLoader is an AppServiceProxy
// field.
AppServiceProxy* host_;
apps::IconLoader* overriding_icon_loader_for_testing_;
};
AppServiceProxy(Profile* profile, service_manager::Connector* connector);
void Initialize(Profile* profile, service_manager::Connector* connector);
void AddAppIconSource(Profile* profile);
// KeyedService overrides.
void Shutdown() override;
// apps::mojom::Subscriber overrides.
void OnApps(std::vector<apps::mojom::AppPtr> deltas) override;
void Clone(apps::mojom::SubscriberRequest request) override;
apps::mojom::AppServicePtr app_service_;
apps::AppRegistryCache cache_;
mojo::BindingSet<apps::mojom::Subscriber> bindings_;
// The LoadIconFromIconKey implementation sends a chained series of requests
// through each icon loader, starting from the outer and working back to the
// inner. Fields are listed from inner to outer, the opposite of call order,
// as each one depends on the previous one, and in the constructor,
// initialization happens in field order.
InnerIconLoader inner_icon_loader_;
IconCoalescer icon_coalescer_;
IconCache outer_icon_loader_;
#if defined(OS_CHROMEOS)
BuiltInChromeOsApps built_in_chrome_os_apps_;
CrostiniApps crostini_apps_;
ExtensionApps extension_apps_;
ExtensionApps extension_web_apps_;
#endif // OS_CHROMEOS
base::WeakPtrFactory<AppServiceProxy> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(AppServiceProxy);
};
} // namespace apps
#endif // CHROME_BROWSER_APPS_APP_SERVICE_APP_SERVICE_PROXY_H_