chromium/chrome/browser/ash/shimless_rma/chrome_shimless_rma_delegate.cc

// 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.

#include "chrome/browser/ash/shimless_rma/chrome_shimless_rma_delegate.h"

#include <string>
#include <utility>

#include "ash/constants/ash_features.h"
#include "ash/constants/ash_switches.h"
#include "base/check.h"
#include "base/command_line.h"
#include "base/containers/span.h"
#include "base/debug/crash_logging.h"
#include "base/debug/dump_without_crashing.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/ash/accessibility/accessibility_manager.h"
#include "chrome/browser/ash/login/chrome_restart_request.h"
#include "chrome/browser/ash/shimless_rma/diagnostics_app_profile_helper.h"
#include "chrome/browser/ash/system/device_disabling_manager.h"
#include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
#include "chrome/browser/ui/webui/ash/diagnostics_dialog.h"
#include "chrome/common/chromeos/extensions/chromeos_system_extension_info.h"
#include "components/qr_code_generator/bitmap_generator.h"
#include "content/public/browser/web_ui.h"
#include "extensions/common/extension.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/image/image_skia.h"

namespace ash {
namespace shimless_rma {

ChromeShimlessRmaDelegate::ChromeShimlessRmaDelegate(content::WebUI* web_ui) {}
ChromeShimlessRmaDelegate::~ChromeShimlessRmaDelegate() = default;

void ChromeShimlessRmaDelegate::ExitRmaThenRestartChrome() {
  const base::CommandLine& browser_command_line =
      *base::CommandLine::ForCurrentProcess();
  base::CommandLine command_line(browser_command_line);
  command_line.AppendSwitch(::ash::switches::kRmaNotAllowed);
  // Remove any attempts to launch RMA.
  command_line.RemoveSwitch(::ash::switches::kLaunchRma);
  ash::RestartChrome(command_line, ash::RestartChromeReason::kUserless);
}

void ChromeShimlessRmaDelegate::ShowDiagnosticsDialog() {
  // Don't launch Diagnostics if device is disabled.
  if (system::DeviceDisablingManager::IsDeviceDisabledDuringNormalOperation()) {
    return;
  }

  DiagnosticsDialog::ShowDialog();
}

void ChromeShimlessRmaDelegate::RefreshAccessibilityManagerProfile() {
  AccessibilityManager* accessibility_manager = AccessibilityManager::Get();
  DCHECK(accessibility_manager);
  accessibility_manager->OnShimlessRmaLaunched();
}

void ChromeShimlessRmaDelegate::GenerateQrCode(
    const std::string& url,
    base::OnceCallback<void(const std::string& qr_code_image)> callback) {
  // TODO(https://crbug.com/325664342): Audit if `QuietZone::kIncluded`
  // can/should be used instead (this may require testing if the different image
  // size works well with surrounding UI elements).  Note that the absence of a
  // quiet zone may interfere with decoding of QR codes even for small codes
  // (for examples see #comment8, #comment9 and #comment6 in the bug).
  auto response = qr_code_generator::GenerateBitmap(
      base::as_byte_span(url), qr_code_generator::ModuleStyle::kSquares,
      qr_code_generator::LocatorStyle::kSquare,
      qr_code_generator::CenterImage::kDino,
      qr_code_generator::QuietZone::kWillBeAddedByClient);

  // The inputs are controlled/generated by our code - they cannot trigger a QR
  // generation error (e.g. they can't trigger input-too-long error). OTOH we
  // don't want to introduce unnecessary risk into the RMA flow, so let's handle
  // this situation gracefully by returning empty data/string/image.
  DCHECK(response.has_value()) << "url: " << url;
  if (response.has_value()) {
    std::vector<unsigned char> bytes;
    gfx::PNGCodec::EncodeBGRASkBitmap(response.value(), false, &bytes);
    std::move(callback).Run(std::string(bytes.begin(), bytes.end()));
  } else {
    SCOPED_CRASH_KEY_STRING1024("RMA", "QRCodeGeneration", url);
    base::debug::DumpWithoutCrashing();
    std::move(callback).Run(std::string());
  }
}

void ChromeShimlessRmaDelegate::PrepareDiagnosticsAppBrowserContext(
    const base::FilePath& crx_path,
    const base::FilePath& swbn_path,
    PrepareDiagnosticsAppBrowserContextCallback callback) {
  CHECK(::ash::features::IsShimlessRMA3pDiagnosticsEnabled());
  PrepareDiagnosticsAppProfile(diagnostics_app_profile_helper_delegete_ptr_,
                               crx_path, swbn_path, std::move(callback));
}

bool ChromeShimlessRmaDelegate::IsChromeOSSystemExtensionProvider(
    const std::string& manufacturer) {
  return chromeos::IsChromeOSSystemExtensionProvider(manufacturer);
}

void ChromeShimlessRmaDelegate::ProcessMediaAccessRequest(
    content::WebContents* web_contents,
    const content::MediaStreamRequest& request,
    content::MediaResponseCallback callback,
    const extensions::Extension* extension) {
  MediaCaptureDevicesDispatcher::GetInstance()->ProcessMediaAccessRequest(
      web_contents, request, std::move(callback), extension);
}

base::WeakPtr<ShimlessRmaDelegate> ChromeShimlessRmaDelegate::GetWeakPtr() {
  return weak_ptr_factory_.GetWeakPtr();
}

void ChromeShimlessRmaDelegate::
    SetDiagnosticsAppProfileHelperDelegateForTesting(
        DiagnosticsAppProfileHelperDelegate* delegate) {
  diagnostics_app_profile_helper_delegete_ptr_ = delegate;
}

}  // namespace shimless_rma
}  // namespace ash