chromium/chrome/browser/ash/accessibility/accessibility_extension_loader.cc

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

#include "chrome/browser/ash/accessibility/accessibility_extension_loader.h"

#include <utility>

#include "base/functional/callback.h"
#include "chrome/browser/extensions/component_loader.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chromeos/ash/components/browser_context_helper/browser_context_helper.h"
#include "components/user_manager/user.h"
#include "extensions/browser/extension_system.h"

namespace ash {

AccessibilityExtensionLoader::AccessibilityExtensionLoader(
    const std::string& extension_id,
    const base::FilePath& extension_path,
    const base::FilePath::CharType* manifest_filename,
    const base::FilePath::CharType* guest_manifest_filename,
    base::RepeatingClosure unload_callback)
    : extension_id_(extension_id),
      extension_path_(extension_path),
      manifest_filename_(manifest_filename),
      guest_manifest_filename_(guest_manifest_filename),
      unload_callback_(unload_callback) {}

AccessibilityExtensionLoader::~AccessibilityExtensionLoader() = default;

void AccessibilityExtensionLoader::SetBrowserContext(
    content::BrowserContext* browser_context,
    base::OnceClosure done_callback) {
  content::BrowserContext* prev_browser_context = browser_context_;
  browser_context_ = browser_context;

  if (!loaded_)
    return;

  // If the extension was loaded on the previous browser context (which isn't
  // the current browser context), unload it there.
  if (prev_browser_context && prev_browser_context != browser_context) {
    UnloadExtension(prev_browser_context);
  }

  // If the extension was already enabled, but not for this profile, add it
  // to this profile.
  auto* extension_service =
      extensions::ExtensionSystem::Get(browser_context_)->extension_service();
  auto* component_loader = extension_service->component_loader();
  if (!component_loader->Exists(extension_id_)) {
    LoadExtension(browser_context_, std::move(done_callback));
  }
}

void AccessibilityExtensionLoader::Load(
    content::BrowserContext* browser_context,
    base::OnceClosure done_cb) {
  browser_context_ = browser_context;

  if (loaded_)
    return;

  loaded_ = true;
  LoadExtension(browser_context_, std::move(done_cb));
}

void AccessibilityExtensionLoader::Unload() {
  if (loaded_) {
    UnloadExtension(browser_context_);
    UnloadExtension(BrowserContextHelper::Get()->GetSigninBrowserContext());
    loaded_ = false;
  }

  browser_context_ = nullptr;

  if (unload_callback_) {
    unload_callback_.Run();
  }
}

//
// private
//

void AccessibilityExtensionLoader::LoadExtension(
    content::BrowserContext* browser_context,
    base::OnceClosure done_cb) {
  DCHECK(manifest_filename_);
  DCHECK(guest_manifest_filename_);

  extensions::ExtensionService* extension_service =
      extensions::ExtensionSystem::Get(browser_context)->extension_service();

  // In Kiosk mode, we should reinstall the extension upon first load. This way,
  // no state from the previous session is preserved.
  const user_manager::User* user =
      BrowserContextHelper::Get()->GetUserByBrowserContext(browser_context);
  if (user && user->IsKioskType() && !was_reset_for_kiosk_) {
    was_reset_for_kiosk_ = true;
    extension_service->DisableExtension(
        extension_id_, extensions::disable_reason::DISABLE_REINSTALL);
    done_cb = base::BindOnce(
        &AccessibilityExtensionLoader::ReinstallExtensionForKiosk,
        weak_ptr_factory_.GetWeakPtr(), browser_context, std::move(done_cb));
  }

  extension_service->component_loader()
      ->AddComponentFromDirWithManifestFilename(
          extension_path_, extension_id_.c_str(), manifest_filename_,
          guest_manifest_filename_, std::move(done_cb));
}

void AccessibilityExtensionLoader::ReinstallExtensionForKiosk(
    content::BrowserContext* browser_context,
    base::OnceClosure done_cb) {
  DCHECK(was_reset_for_kiosk_);

  auto* extension_service =
      extensions::ExtensionSystem::Get(browser_context)->extension_service();
  std::u16string error;
  extension_service->UninstallExtension(
      extension_id_, extensions::UninstallReason::UNINSTALL_REASON_REINSTALL,
      &error);
  extension_service->component_loader()->Reload(extension_id_);

  if (done_cb)
    std::move(done_cb).Run();
}

void AccessibilityExtensionLoader::UnloadExtension(
    content::BrowserContext* browser_context) {
  auto* extension_service =
      extensions::ExtensionSystem::Get(browser_context)->extension_service();
  extension_service->component_loader()->Remove(extension_id_);
}

}  // namespace ash