910e62b5创建于 1月15日历史提交
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/installedapp/installed_app_provider_impl.h"

#include <algorithm>

#include "base/check_is_test.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/functional/concurrent_callbacks.h"
#include "base/task/task_traits.h"
#include "build/build_config.h"
#include "content/browser/browser_thread_impl.h"
#if !BUILDFLAG(IS_ANDROID)
#include "content/browser/installedapp/fetch_related_web_apps_task.h"
#endif  // !BUILDFLAG(IS_ANDROID)
#include "content/common/features.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/common/content_features.h"
#include "mojo/public/cpp/bindings/clone_traits.h"
#include "third_party/blink/public/mojom/installedapp/related_application.mojom.h"

#if BUILDFLAG(IS_WIN)
#include "content/browser/installedapp/fetch_related_win_apps_task.h"
#include "content/browser/installedapp/native_win_app_fetcher.h"
#include "content/browser/installedapp/native_win_app_fetcher_impl.h"
#endif

namespace content {

namespace {
constexpr int kMaxNumberOfQueriedApps = 10;

#if BUILDFLAG(IS_WIN)
std::unique_ptr<NativeWinAppFetcher> CreateNativeWinAppFetcher() {
  return std::make_unique<NativeWinAppFetcherImpl>();
}
#endif  // BUILDFLAG(IS_WIN)
}

InstalledAppProviderImpl::InstalledAppProviderImpl(
    RenderFrameHost& render_frame_host,
    mojo::PendingReceiver<blink::mojom::InstalledAppProvider> pending_receiver)
    : DocumentService(render_frame_host, std::move(pending_receiver)) {
#if BUILDFLAG(IS_WIN)
  native_win_app_fetcher_factory_ =
      base::BindRepeating(&CreateNativeWinAppFetcher);
#endif  // BUILDFLAG(IS_WIN)
}

InstalledAppProviderImpl::~InstalledAppProviderImpl() = default;

void InstalledAppProviderImpl::FilterInstalledApps(
    std::vector<blink::mojom::RelatedApplicationPtr> related_apps,
    const GURL& manifest_url,
    bool add_saved_related_applications,
    FilterInstalledAppsCallback callback) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  if (!base::FeatureList::IsEnabled(features::kInstalledAppProvider)) {
    base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
        FROM_HERE,
        base::BindOnce(std::move(callback),
                       std::vector<blink::mojom::RelatedApplicationPtr>()));
    return;
  }

  // If we failed to retrieve the manifest, fall back to the saved
  // related_apps.
  if (add_saved_related_applications) {
    WebContents* web_contents =
        WebContents::FromRenderFrameHost(&render_frame_host());
    WebContentsDelegate* delegate = web_contents->GetDelegate();
    if (delegate) {
      std::vector<blink::mojom::RelatedApplicationPtr> saved_related_apps =
          delegate->GetSavedRelatedApplications(web_contents);
      related_apps.insert(related_apps.end(),
                          std::make_move_iterator(saved_related_apps.begin()),
                          std::make_move_iterator(saved_related_apps.end()));
    }
  }

  if (related_apps.size() > kMaxNumberOfQueriedApps) {
    related_apps.resize(kMaxNumberOfQueriedApps);
  }

  base::ConcurrentCallbacks<FetchRelatedAppsTaskResult> concurrent;

#if BUILDFLAG(IS_WIN)
  if (base::FeatureList::IsEnabled(features::kFilterInstalledAppsWinMatching)) {
    StartTask(std::make_unique<FetchRelatedWinAppsTask>(
                  native_win_app_fetcher_factory_.Run()),
              related_apps, concurrent.CreateCallback());
  }
#endif

#if !BUILDFLAG(IS_ANDROID)
  if (base::FeatureList::IsEnabled(
          features::kFilterInstalledAppsWebAppMatching)) {
    StartTask(std::make_unique<FetchRelatedWebAppsTask>(
                  render_frame_host().GetBrowserContext()),
              related_apps, concurrent.CreateCallback());
  }
#endif  // !BUILDFLAG(IS_ANDROID)

  std::move(concurrent)
      .Done(base::BindOnce(&InstalledAppProviderImpl::AggregateTaskResults,
                           weak_ptr_factory_.GetWeakPtr(),
                           std::move(callback)));
}

void InstalledAppProviderImpl::StartTask(
    std::unique_ptr<FetchRelatedAppsTask> task,
    std::vector<blink::mojom::RelatedApplicationPtr>& related_apps,
    FetchRelatedAppsTaskCallback callback) {
  auto* task_ptr = task.get();
  tasks_.insert({task_ptr, std::move(task)});
  auto erase_task_cb = base::BindOnce(&InstalledAppProviderImpl::EraseTask,
                                      weak_ptr_factory_.GetWeakPtr(), task_ptr);
  task_ptr->Start(render_frame_host().GetLastCommittedURL(),
                  mojo::Clone(related_apps),
                  std::move(callback).Then(std::move(erase_task_cb)));
}

void InstalledAppProviderImpl::EraseTask(FetchRelatedAppsTask* task) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  int num_removed = tasks_.erase(task);
  CHECK(num_removed != 0);
}

void InstalledAppProviderImpl::AggregateTaskResults(
    FilterInstalledAppsCallback callback,
    std::vector<FetchRelatedAppsTaskResult> task_result_list) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  std::vector<blink::mojom::RelatedApplicationPtr> matched_apps;

  for (FetchRelatedAppsTaskResult& result : task_result_list) {
    for (blink::mojom::RelatedApplicationPtr& app : result) {
      matched_apps.push_back(std::move(app));
    }
  }

  // |is_off_the_record| should be checked at the end to prevent clients from
  // using timing functions to test if the user is in private.
  bool is_off_the_record =
      render_frame_host().GetProcess()->GetBrowserContext()->IsOffTheRecord();

  if (is_off_the_record) {
    return std::move(callback).Run(
        std::vector<blink::mojom::RelatedApplicationPtr>());
  }

  return std::move(callback).Run(mojo::Clone(matched_apps));
}

#if BUILDFLAG(IS_WIN)
void InstalledAppProviderImpl::SetNativeWinAppFetcherFactoryForTesting(
    base::RepeatingCallback<std::unique_ptr<NativeWinAppFetcher>()> factory) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  CHECK_IS_TEST();
  native_win_app_fetcher_factory_ = std::move(factory);
}
#endif  // BUILDFLAG(IS_WIN)

// static
void InstalledAppProviderImpl::Create(
    RenderFrameHost& host,
    mojo::PendingReceiver<blink::mojom::InstalledAppProvider> receiver) {
  if (host.GetParentOrOuterDocument()) {
    // The renderer is supposed to disallow this and we shouldn't end up here.
    mojo::ReportBadMessage(
        "InstalledAppProvider only allowed for outermost main frame.");
    return;
  }

  // The object is bound to the lifetime of |host|'s current document and the
  // mojo connection. See DocumentService for details.
  new InstalledAppProviderImpl(host, std::move(receiver));
}

// static
InstalledAppProviderImpl* InstalledAppProviderImpl::CreateForTesting(
    RenderFrameHost& render_frame_host,
    mojo::PendingReceiver<blink::mojom::InstalledAppProvider> receiver) {
  CHECK_IS_TEST();
  return new InstalledAppProviderImpl(render_frame_host, std::move(receiver));
}

}  // namespace content