blob: 28d3c5c6e944eeb9a6cc696ae0376b87e0b0fd82 [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_ICON_CACHE_H_
#define COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_ICON_CACHE_H_
#include <map>
#include <memory>
#include <string>
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "components/services/app_service/public/cpp/app_types.h"
#include "components/services/app_service/public/cpp/icon_loader.h"
#include "ui/gfx/image/image_skia.h"
namespace apps {
// This is used for logging, so do not remove or reorder existing entries.
enum class IconLoadingMethod {
kFromCache = 0,
kViaMojomCall = 1,
kViaNonMojomCall = 2,
// Add any new values above this one, and update kMaxValue to the highest
// enumerator value.
kMaxValue = kViaNonMojomCall,
};
// Records metrics when loading icons.
void RecordIconLoadMethodMetrics(IconLoadingMethod icon_loading_method);
// An IconLoader that caches the apps::mojom::IconType::kUncompressed
// results of another (wrapped) IconLoader.
class IconCache : public IconLoader {
public:
// What triggers dropping no-longer-used icons from the cache.
//
// If unsure of which one to use, kEager is a safe choice, with little
// overhead above not having an icon cache at all.
enum class GarbageCollectionPolicy {
// kEager means that we drop icons as soon as their ref-count hits zero
// (i.e. all the IconLoader::Releaser's returned by LoadIconFromIconKey
// have been destroyed).
//
// This minimizes the overall memory cost of the cache. Only icons that are
// still actively used stay alive in the cache.
//
// On the other hand, this can result in more cache misses than other
// policies. For example, suppose that some UI starts with a widget showing
// the "foo" app icon. In response to user input, the UI destroys that
// widget and then creates a new widget to show the same "foo" app icon.
// With a kEager garbage collection policy, that freshly created widget
// might not get a cache hit, if the icon's ref-count hits zero in between
// the two widgets' destruction and creation.
kEager,
// kExplicit means that icons can remain in the cache, even if their
// ref-count hits zero. Instead, explicit calls to SweepReleasedIcons are
// needed to clear cache entries.
//
// This can use more memory than kEager, but it can also provide a cache
// hit in the "destroy and then create" example described above.
//
// On the other hand, it requires more effort and more thought from the
// programmer. They need to make additional calls (to SweepReleasedIcons),
// so they can't just drop an IconCache in transparently. The programmer
// also needs to think about when is a good time to make those calls. Too
// frequent, and you get extra complexity for not much more benefit than
// using kEager. Too infrequent, and you have the memory cost of keeping
// unused icons around.
//
// All together, kExplicit might not be the best policy for e.g. a
// process-wide icon cache with many clients, each with different usage
// patterns.
kExplicit,
};
IconCache(IconLoader* wrapped_loader, GarbageCollectionPolicy gc_policy);
IconCache(const IconCache&) = delete;
IconCache& operator=(const IconCache&) = delete;
~IconCache() override;
// IconLoader overrides.
absl::optional<IconKey> GetIconKey(const std::string& app_id) override;
std::unique_ptr<Releaser> LoadIconFromIconKey(
AppType app_type,
const std::string& app_id,
const IconKey& icon_key,
IconType icon_type,
int32_t size_hint_in_dip,
bool allow_placeholder_icon,
apps::LoadIconCallback callback) override;
// A hint that now is a good time to garbage-collect any icons that are not
// actively held.
void SweepReleasedIcons();
void RemoveIcon(AppType app_type, const std::string& app_id);
private:
class Value {
public:
gfx::ImageSkia image_;
bool is_placeholder_icon_;
uint64_t ref_count_;
Value();
IconValuePtr AsIconValue(IconType icon_type);
};
void Update(const IconLoader::Key& key, const IconValue& icon_value);
void OnLoadIcon(const IconLoader::Key& key,
apps::LoadIconCallback callback,
IconValuePtr icon_value);
void OnRelease(IconLoader::Key);
std::map<IconLoader::Key, Value> map_;
raw_ptr<IconLoader> wrapped_loader_;
GarbageCollectionPolicy gc_policy_;
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<IconCache> weak_ptr_factory_{this};
};
} // namespace apps
#endif // COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_ICON_CACHE_H_