chromium/ios/chrome/browser/sessions/model/web_session_state_cache_factory.mm

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "ios/chrome/browser/sessions/model/web_session_state_cache_factory.h"

#import "base/functional/bind.h"
#import "base/logging.h"
#import "base/memory/ptr_util.h"
#import "base/no_destructor.h"
#import "components/keyed_service/core/keyed_service.h"
#import "components/keyed_service/ios/browser_state_dependency_manager.h"
#import "ios/chrome/browser/sessions/model/web_session_state_cache.h"
#import "ios/chrome/browser/sessions/model/web_session_state_cache_web_state_list_observer.h"
#import "ios/chrome/browser/shared/model/browser/all_web_state_list_observation_registrar.h"
#import "ios/chrome/browser/shared/model/browser/browser_list_factory.h"
#import "ios/chrome/browser/shared/model/browser_state/browser_state_otr_helper.h"
#import "ios/chrome/browser/shared/model/profile/profile_ios.h"

namespace {
// C++ wrapper around WebSessionStateCache, owning the WebSessionStateCache and
// allowing it bind it to an ChromeBrowserState as a KeyedService.
class WebSessionStateCacheWrapper : public KeyedService {
 public:
  WebSessionStateCacheWrapper(BrowserList* browser_list,
                              WebSessionStateCache* web_session_state_cache);

  WebSessionStateCacheWrapper(const WebSessionStateCacheWrapper&) = delete;
  WebSessionStateCacheWrapper& operator=(const WebSessionStateCacheWrapper&) =
      delete;

  ~WebSessionStateCacheWrapper() override;

  WebSessionStateCache* web_session_state_cache() {
    return web_session_state_cache_;
  }

  // KeyedService implementation.
  void Shutdown() override;

 private:
  __strong WebSessionStateCache* web_session_state_cache_;
  std::unique_ptr<AllWebStateListObservationRegistrar> registrar_;
};

WebSessionStateCacheWrapper::WebSessionStateCacheWrapper(
    BrowserList* browser_list,
    WebSessionStateCache* web_session_state_cache)
    : web_session_state_cache_(web_session_state_cache) {
  DCHECK(web_session_state_cache);
  registrar_ = std::make_unique<AllWebStateListObservationRegistrar>(
      browser_list, std::make_unique<WebSessionStateCacheWebStateListObserver>(
                        web_session_state_cache));
}

WebSessionStateCacheWrapper::~WebSessionStateCacheWrapper() {
  DCHECK(!web_session_state_cache_);
}

void WebSessionStateCacheWrapper::Shutdown() {
  registrar_.reset();
  [web_session_state_cache_ shutdown];
  web_session_state_cache_ = nil;
}

std::unique_ptr<KeyedService> BuildWebSessionStateCacheWrapper(
    web::BrowserState* context) {
  ChromeBrowserState* chrome_browser_state =
      ChromeBrowserState::FromBrowserState(context);
  return std::make_unique<WebSessionStateCacheWrapper>(
      BrowserListFactory::GetForBrowserState(chrome_browser_state),
      [[WebSessionStateCache alloc] initWithBrowserState:chrome_browser_state]);
}
}  // namespace

// static
WebSessionStateCache* WebSessionStateCacheFactory::GetForBrowserState(
    ChromeBrowserState* browser_state) {
  WebSessionStateCacheWrapper* wrapper =
      static_cast<WebSessionStateCacheWrapper*>(
          GetInstance()->GetServiceForBrowserState(browser_state, true));
  return wrapper ? wrapper->web_session_state_cache() : nil;
}

// static
WebSessionStateCacheFactory* WebSessionStateCacheFactory::GetInstance() {
  static base::NoDestructor<WebSessionStateCacheFactory> instance;
  return instance.get();
}

WebSessionStateCacheFactory::WebSessionStateCacheFactory()
    : BrowserStateKeyedServiceFactory(
          "WebSessionStateCache",
          BrowserStateDependencyManager::GetInstance()) {}

WebSessionStateCacheFactory::~WebSessionStateCacheFactory() = default;

std::unique_ptr<KeyedService>
WebSessionStateCacheFactory::BuildServiceInstanceFor(
    web::BrowserState* context) const {
  return BuildWebSessionStateCacheWrapper(context);
}

web::BrowserState* WebSessionStateCacheFactory::GetBrowserStateToUse(
    web::BrowserState* context) const {
  return GetBrowserStateRedirectedInIncognito(context);
}