910e62b5创建于 1月15日历史提交
// 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.

#include "content/public/browser/device_service.h"

#include "base/memory/scoped_refptr.h"
#include "base/task/single_thread_task_runner.h"
#include "base/task/thread_pool.h"
#include "base/threading/sequence_local_storage_slot.h"
#include "build/build_config.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/network_service_instance.h"
#include "content/public/common/content_client.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/device/device_service.h"
#include "services/device/public/cpp/geolocation/geolocation_system_permission_manager.h"
#include "services/network/public/cpp/cross_thread_pending_shared_url_loader_factory.h"
#include "services/network/public/mojom/network_service_test.mojom.h"
#include "services/network/public/mojom/url_loader.mojom.h"

#if BUILDFLAG(IS_ANDROID)
#include "base/android/jni_android.h"
#include "base/android/scoped_java_ref.h"
#include "content/browser/wake_lock/wake_lock_context_host.h"
#include "content/public/android/content_jni_headers/ContentNfcDelegate_jni.h"
#endif

namespace content {

namespace {

// SharedURLLoaderFactory for device service, backed by
// GetContentClient()->browser()->GetSystemSharedURLLoaderFactory().
class DeviceServiceURLLoaderFactory : public network::SharedURLLoaderFactory {
 public:
  DeviceServiceURLLoaderFactory() = default;

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

  // mojom::URLLoaderFactory implementation:
  void CreateLoaderAndStart(
      mojo::PendingReceiver<network::mojom::URLLoader> receiver,
      int32_t request_id,
      uint32_t options,
      const network::ResourceRequest& url_request,
      mojo::PendingRemote<network::mojom::URLLoaderClient> client,
      const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
      override {
    auto factory =
        GetContentClient()->browser()->GetSystemSharedURLLoaderFactory();
    if (!factory)
      return;

    factory->CreateLoaderAndStart(std::move(receiver), request_id, options,
                                  url_request, std::move(client),
                                  traffic_annotation);
  }

  // SharedURLLoaderFactory implementation:
  void Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver)
      override {
    GetContentClient()->browser()->GetSystemSharedURLLoaderFactory()->Clone(
        std::move(receiver));
  }

  std::unique_ptr<network::PendingSharedURLLoaderFactory> Clone() override {
    return std::make_unique<network::CrossThreadPendingSharedURLLoaderFactory>(
        this);
  }

 private:
  friend class base::RefCounted<DeviceServiceURLLoaderFactory>;
  ~DeviceServiceURLLoaderFactory() override = default;
};

void BindDeviceServiceReceiver(
    mojo::PendingReceiver<device::mojom::DeviceService> receiver) {
  // Bind the lifetime of the service instance to that of the sequence it's
  // running on.
  static base::SequenceLocalStorageSlot<std::unique_ptr<device::DeviceService>>
      service_slot;
  auto& service = service_slot.GetOrCreateValue();

  if (service) {
    service->AddReceiver(std::move(receiver));
    return;
  }

  auto params = std::make_unique<device::DeviceServiceParams>();

  // This task runner may be used by some device service implementation bits
  // to interface with dbus client code, which in turn imposes some subtle
  // thread affinity on the clients. We therefore require a single-thread
  // runner.
  params->file_task_runner = base::ThreadPool::CreateSingleThreadTaskRunner(
      {base::MayBlock(), base::TaskPriority::BEST_EFFORT});

  params->io_task_runner = GetIOThreadTaskRunner({});
  params->url_loader_factory =
      base::MakeRefCounted<DeviceServiceURLLoaderFactory>();
  params->network_connection_tracker = content::GetNetworkConnectionTracker();
  params->geolocation_api_key =
      GetContentClient()->browser()->GetGeolocationApiKey();
  params->custom_location_provider_callback =
      base::BindRepeating(&ContentBrowserClient::OverrideSystemLocationProvider,
                          base::Unretained(GetContentClient()->browser()));
  params->geolocation_system_permission_manager =
      GetContentClient()->browser()->GetGeolocationSystemPermissionManager();

#if BUILDFLAG(IS_ANDROID)
  JNIEnv* env = base::android::AttachCurrentThread();
  params->java_nfc_delegate = Java_ContentNfcDelegate_create(env);
  DCHECK(!params->java_nfc_delegate.is_null());

  params->wake_lock_context_callback =
      base::BindRepeating(&WakeLockContextHost::GetNativeViewForContext);
  params->use_gms_core_location_provider =
      GetContentClient()->browser()->ShouldUseGmsCoreGeolocationProvider();
#endif

  service = device::CreateDeviceService(std::move(params), std::move(receiver));
}

}  // namespace

device::mojom::DeviceService& GetDeviceService() {
  static base::SequenceLocalStorageSlot<
      mojo::Remote<device::mojom::DeviceService>>
      remote_slot;
  mojo::Remote<device::mojom::DeviceService>& remote =
      remote_slot.GetOrCreateValue();
  if (!remote) {
    // This may be called very early in startup, too early for some Device
    // Service initialization steps (for example, in browser test environments,
    // the Device Service's connection to the Network Service could deadlock).
    // We post a task to defer until the main message loop has started, when
    // initialization is reliably safe.
    GetUIThreadTaskRunner({})->PostTask(
        FROM_HERE, base::BindOnce(&BindDeviceServiceReceiver,
                                  remote.BindNewPipeAndPassReceiver()));
  }
  return *remote.get();
}

}  // namespace content

#if BUILDFLAG(IS_ANDROID)
DEFINE_JNI(ContentNfcDelegate)
#endif