1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
|
// Copyright 2018 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_ASH_GUEST_OS_GUEST_OS_REGISTRY_SERVICE_H_
#define CHROME_BROWSER_ASH_GUEST_OS_GUEST_OS_REGISTRY_SERVICE_H_
#include <map>
#include <set>
#include <string>
#include <string_view>
#include <vector>
#include "base/files/file_path.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/values.h"
#include "chrome/browser/apps/app_service/app_icon/app_icon_factory.h"
#include "chrome/browser/ash/crostini/crostini_simple_types.h"
#include "chrome/browser/ash/guest_os/guest_id.h"
#include "chrome/browser/ash/guest_os/guest_os_external_protocol_handler.h"
#include "chrome/browser/ash/guest_os/public/types.h"
#include "chromeos/ash/components/dbus/vm_applications/apps.pb.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/services/app_service/public/cpp/icon_types.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/base/resource/resource_scale_factor.h"
class Profile;
class PrefService;
namespace base {
class Clock;
class Time;
} // namespace base
namespace apps {
class SvgIconTranscoder;
} // namespace apps
namespace vm_tools {
namespace apps {
class ApplicationList;
} // namespace apps
} // namespace vm_tools
namespace guest_os {
using IconContentCallback = base::OnceCallback<void(std::string)>;
using CanHandleUrlCallback = base::RepeatingCallback<bool(const GURL&)>;
// The GuestOsRegistryService stores information about Desktop Entries (apps)
// in Crostini. We store this in prefs so that it is readily available even when
// the VM isn't running. The registrations here correspond to .desktop files,
// which are detailed in the spec:
// https://www.freedesktop.org/wiki/Specifications/desktop-entry-spec/
// This class deals with several types of IDs, including:
// 1) Desktop File IDs (desktop_file_id):
// - As per the desktop entry spec.
// 2) Crostini App List Ids (app_id):
// - Valid extensions ids for apps stored in the registry, derived from the
// desktop file id, vm name, and container name.
// - The Terminal is a special case, using kCrostiniTerminalId (see below).
// 3) Exo Window App Ids (window_app_id):
// - Retrieved from exo::GetShellApplicationId()
// - For Wayland apps, this is the surface class of the app
// - For X apps, this is of the form org.chromium.termina.wmclass.foo when
// WM_CLASS is set to foo, or otherwise some string prefixed by
// "org.chromium.termina." when WM_CLASS is not set.
// 4) Shelf App Ids (shelf_app_id):
// - Used in ash::ShelfID::app_id
// - Either a Window App Id prefixed by "crostini:" or a Crostini App Id.
// - For pinned apps, this is a Crostini App Id.
// The default Terminal app does not correspond to a desktop file, but users
// of the registry can treat it as a regular app that is always installed.
// Internal to the registry, the pref entry only contains the last launch time
// so some care is required.
class GuestOsRegistryService : public KeyedService {
public:
class Registration {
public:
Registration(std::string app_id, base::Value pref);
Registration(Registration&& registration) = default;
Registration& operator=(Registration&& registration) = default;
Registration(const Registration&) = delete;
Registration& operator=(const Registration&) = delete;
~Registration();
std::string app_id() const { return app_id_; }
std::string DesktopFileId() const;
VmType VmType() const;
std::string VmName() const;
std::string ContainerName() const;
std::string Name() const;
std::string Exec() const;
std::string ExecutableFileName() const;
std::set<std::string> Extensions() const;
std::set<std::string> MimeTypes() const;
std::set<std::string> Keywords() const;
bool NoDisplay() const;
bool Terminal() const;
std::string PackageId() const;
base::Time InstallTime() const;
base::Time LastLaunchTime() const;
// Whether this app should scale up when displayed.
bool IsScaled() const;
bool CanUninstall() const;
guest_os::GuestId ToGuestId() const;
std::string StartupWmClass() const;
bool StartupNotify() const;
private:
std::string GetString(std::string_view key) const;
bool GetBool(std::string_view key) const;
base::Time GetTime(std::string_view key) const;
std::string GetLocalizedString(std::string_view key) const;
std::set<std::string> GetLocalizedList(std::string_view key) const;
std::string app_id_;
base::Value pref_;
};
class Observer {
public:
// Called at the end of UpdateApplicationList() with lists of app_ids for
// apps which have been updated, removed, and inserted. Not called when the
// last_launch_time field is updated.
virtual void OnRegistryUpdated(
guest_os::GuestOsRegistryService* registry_service,
VmType vm_type,
const std::vector<std::string>& updated_apps,
const std::vector<std::string>& removed_apps,
const std::vector<std::string>& inserted_apps) {}
// Called at the end of AppLaunched().
virtual void OnAppLastLaunchTimeUpdated(
VmType vm_type,
const std::string& app_id,
const base::Time& last_launch_time) {}
protected:
virtual ~Observer() = default;
};
explicit GuestOsRegistryService(Profile* profile);
GuestOsRegistryService(const GuestOsRegistryService&) = delete;
GuestOsRegistryService& operator=(const GuestOsRegistryService&) = delete;
~GuestOsRegistryService() override;
base::WeakPtr<GuestOsRegistryService> GetWeakPtr();
// Return all installed apps. This always includes the Terminal app.
std::map<std::string, GuestOsRegistryService::Registration>
GetAllRegisteredApps() const;
// Return all installed apps where the VM is enabled.
std::map<std::string, GuestOsRegistryService::Registration> GetEnabledApps()
const;
// Return all installed apps for a given vm.
// If |vm_type == TERMINA_VM| then this includes the Terminal app.
std::map<std::string, GuestOsRegistryService::Registration> GetRegisteredApps(
VmType vm_type) const;
// Return null if `app_id` is not found in the registry.
std::optional<GuestOsRegistryService::Registration> GetRegistration(
const std::string& app_id) const;
// Return the preferred handler for the given URL, if any.
std::optional<GuestOsUrlHandler> GetHandler(const GURL& url) const;
// Register a non-app handler of URLs.
// Handlers registered here take priority over apps (since they come from
// the OS, rather than VMs), and are not persisted to prefs.
// `canHandleCallback` should return true when passed a URL that should be
// handled by `handler`.
void RegisterTransientUrlHandler(GuestOsUrlHandler handler,
CanHandleUrlCallback canHandleCallback);
// Constructs path to app icon for specific scale factor.
base::FilePath GetIconPath(const std::string& app_id,
ui::ResourceScaleFactor scale_factor) const;
// Attempts to load icon in the following order:
// 1/ Loads from resource if |icon_key->resource_id| is valid (non-zero).
// 2/ Looks up file cache.
// 3/ Fetches from VM.
// 4/ Uses |fallback_icon_resource_id| if it is valid (non-zero).
// 5/ Returns empty.
void LoadIcon(const std::string& app_id,
const apps::IconKey& icon_key,
apps::IconType icon_type,
int32_t size_hint_in_dip,
bool allow_placeholder_icon,
int fallback_icon_resource_id,
apps::LoadIconCallback callback);
void LoadIconFromVM(const std::string& app_id,
apps::IconType icon_type,
int32_t size_hint_in_dip,
ui::ResourceScaleFactor scale_factor,
apps::IconEffects icon_effects,
int fallback_icon_resource_id,
apps::LoadIconCallback callback);
void OnLoadIconFromVM(const std::string& app_id,
apps::IconType icon_type,
int32_t size_hint_in_dip,
apps::IconEffects icon_effects,
int fallback_icon_resource_id,
apps::LoadIconCallback callback,
std::string compressed_icon_data);
// Fetches icons from container.
void RequestIcon(const std::string& app_id,
ui::ResourceScaleFactor scale_factor,
IconContentCallback callback);
// Remove all apps from the named VM and container. If |container_name| is an
// empty string, this function removes all apps associated with the VM,
// regardless of container. Used in the uninstall process.
void ClearApplicationList(VmType vm_type,
const std::string& vm_name,
const std::string& container_name);
// Remove all apps from the named container. Used when deleting a container
// without deleting the whole VM.
void ClearApplicationListForContainer(VmType vm_type,
const std::string& vm_name,
const std::string& container_name);
// The existing list of apps is replaced by |application_list|.
void UpdateApplicationList(const vm_tools::apps::ApplicationList& app_list);
// Inform the registry that the badge color for `container_id` has changed. In
// practice, this sends an update notification for all apps associated with
// this container, which will prompt the icons to be regenerated.
void ContainerBadgeColorChanged(const guest_os::GuestId& container_id);
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
// Notify the registry to update the last_launched field.
void AppLaunched(const std::string& app_id);
// Serializes the current time and stores it in |dictionary|.
void SetCurrentTime(base::Value::Dict& dictionary, const char* key) const;
// Set the display scaled setting of the |app_id| to |scaled|.
void SetAppScaled(const std::string& app_id, bool scaled);
void SetClockForTesting(base::Clock* clock) { clock_ = clock; }
// Apply a coloured badge to the app icon if Crostini multi-container
// feature is enabled.
void ApplyContainerBadge(const std::optional<std::string>& app_id,
gfx::ImageSkia* image_skia);
// Returns the AppId that will be used to refer to the given GuestOs
// application.
static std::string GenerateAppId(const std::string& desktop_file_id,
const std::string& vm_name,
const std::string& container_name);
private:
// Construct path to app local data.
base::FilePath GetAppPath(const std::string& app_id) const;
// Called to request an icon from the container.
void RequestContainerAppIcon(const std::string& app_id,
ui::ResourceScaleFactor scale_factor);
// Callback for when we request an icon from the container.
void OnContainerAppIcon(const std::string& app_id,
ui::ResourceScaleFactor scale_factor,
bool success,
const std::vector<crostini::Icon>& icons);
// Removes all the icons installed for an application.
void RemoveAppData(const std::string& app_id);
// Apply container-specific badging to `icon_out`. This is used by
// ApplyContainerBadge.
void ApplyContainerBadgeForImageSkiaIcon(SkColor badge_color,
gfx::ImageSkia* icon_out);
// Apply container-specific badging to `icon` before running the callback.
// This is run after the generic icon loading code.
void ApplyContainerBadgeWithCallback(SkColor badge_color,
apps::LoadIconCallback callback,
apps::IconValuePtr icon);
// Call the callbacks |active_icon_requests_| for |app_id|.
void InvokeActiveIconCallbacks(std::string app_id,
ui::ResourceScaleFactor scale_factor,
std::string icon_content);
// If a valid .svg file is found at |svg_path|, transcode it to png and save
// it to |png_path| and invoke |callback|, otherwise invoke |fallback|.
void TranscodeIconFromSvg(
base::FilePath svg_path,
base::FilePath png_path,
apps::IconType icon_type,
int32_t size_hint_in_dip,
apps::IconEffects icon_effects,
base::OnceCallback<void(apps::LoadIconCallback)> fallback,
apps::LoadIconCallback callback);
// Callback for when a saved container icon is svg and was transcoded.
void OnSvgIconTranscoded(std::string app_id,
ui::ResourceScaleFactor scale_factor,
std::string svg_icon_content,
std::string png_icon_content);
// Owned by the Profile.
const raw_ptr<Profile, DanglingUntriaged> profile_;
const raw_ptr<PrefService, DanglingUntriaged> prefs_;
// Keeps root folder where Crostini app icons for different scale factors are
// stored.
base::FilePath base_icon_path_;
base::ObserverList<Observer>::Unchecked observers_;
raw_ptr<const base::Clock> clock_;
std::vector<std::pair<GuestOsUrlHandler, CanHandleUrlCallback>> url_handlers_;
// Keeps record for icon request to avoid duplication. Each app may contain
// several requests for different scale factors. Scale factor is defined by
// specific bit position. The |active_icon_requests_| holds icon request that
// are in flight. |retry_icon_requests| holds failed requests which we
// should attempt again when we get an app list refresh from the container
// which means there's a good chance the container is online and the request
// will then succeed.
std::map<std::pair<std::string, ui::ResourceScaleFactor>,
std::vector<IconContentCallback>>
active_icon_requests_;
std::map<std::string, uint32_t> retry_icon_requests_;
std::unique_ptr<apps::SvgIconTranscoder> svg_icon_transcoder_;
base::WeakPtrFactory<GuestOsRegistryService> weak_ptr_factory_{this};
};
} // namespace guest_os
#endif // CHROME_BROWSER_ASH_GUEST_OS_GUEST_OS_REGISTRY_SERVICE_H_
|