1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139

content / browser / code_cache / generated_code_cache_context.cc [blame]

// Copyright 2018 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/code_cache/generated_code_cache_context.h"

#include <memory>

#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/metrics/histogram_macros.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/thread_pool.h"
#include "content/browser/code_cache/generated_code_cache.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_features.h"

namespace content {

// static
void GeneratedCodeCacheContext::RunOrPostTask(
    scoped_refptr<GeneratedCodeCacheContext> context,
    const base::Location& location,
    base::OnceClosure task) {
  if (!context || context->task_runner_->RunsTasksInCurrentSequence()) {
    std::move(task).Run();
    return;
  }

  context->task_runner_->PostTask(location, std::move(task));
}

// static
scoped_refptr<base::SequencedTaskRunner>
GeneratedCodeCacheContext::GetTaskRunner(
    scoped_refptr<GeneratedCodeCacheContext> context) {
  if (!context)
    return base::SequencedTaskRunner::GetCurrentDefault();
  return context->task_runner_;
}

GeneratedCodeCacheContext::GeneratedCodeCacheContext() {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  DETACH_FROM_SEQUENCE(sequence_checker_);
  task_runner_ = base::ThreadPool::CreateSingleThreadTaskRunner(
      {base::TaskPriority::USER_BLOCKING});
}

void GeneratedCodeCacheContext::Initialize(const base::FilePath& path,
                                           int max_bytes) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  RunOrPostTask(this, FROM_HERE,
                base::BindOnce(&GeneratedCodeCacheContext::InitializeOnThread,
                               this, path, max_bytes));
}

void GeneratedCodeCacheContext::InitializeOnThread(const base::FilePath& path,
                                                   int max_bytes) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  int max_bytes_js = max_bytes;

  if (base::FeatureList::IsEnabled(features::kWebUICodeCache)) {
    int max_bytes_webui_js = max_bytes;
    if (max_bytes > 0) {
      // If a maximum was specified, then we should limit the total JS bytecode,
      // both from WebUI and from open web sites, to max_bytes. The larger
      // portion by far should be reserved for open web sites.
      const int kMaxWebUIPercent = 2;
      max_bytes_webui_js = std::min(max_bytes * kMaxWebUIPercent / 100,
                                    disk_cache::kMaxWebUICodeCacheSize);

      // The rest is left over for open web JS.
      max_bytes_js = max_bytes - max_bytes_webui_js;
      DCHECK_GT(max_bytes_js, max_bytes_webui_js);

      // Specifying a maximum size of zero means to use heuristics based on
      // available disk size, which would be the opposite of our intent if the
      // specified number was so small that the division above truncated to
      // zero.
      if (max_bytes_webui_js == 0) {
        max_bytes_webui_js = 1;
      }
    }

    generated_webui_js_code_cache_ = {
        new GeneratedCodeCache(
            path.AppendASCII("webui_js"), max_bytes_webui_js,
            GeneratedCodeCache::CodeCacheType::kWebUIJavaScript),
        base::OnTaskRunnerDeleter(task_runner_)};

    UMA_HISTOGRAM_BOOLEAN("WebUICodeCache.FeatureEnabled", true);
  }

  generated_js_code_cache_ = {
      new GeneratedCodeCache(path.AppendASCII("js"), max_bytes_js,
                             GeneratedCodeCache::CodeCacheType::kJavaScript),
      base::OnTaskRunnerDeleter(task_runner_)};

  generated_wasm_code_cache_ = {
      new GeneratedCodeCache(path.AppendASCII("wasm"), max_bytes,
                             GeneratedCodeCache::CodeCacheType::kWebAssembly),
      base::OnTaskRunnerDeleter(task_runner_)};
}

void GeneratedCodeCacheContext::Shutdown() {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  RunOrPostTask(
      this, FROM_HERE,
      base::BindOnce(&GeneratedCodeCacheContext::ShutdownOnThread, this));
}

void GeneratedCodeCacheContext::ShutdownOnThread() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  generated_js_code_cache_.reset();
  generated_wasm_code_cache_.reset();
  generated_webui_js_code_cache_.reset();
}

GeneratedCodeCache* GeneratedCodeCacheContext::generated_js_code_cache() const {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  return generated_js_code_cache_.get();
}

GeneratedCodeCache* GeneratedCodeCacheContext::generated_wasm_code_cache()
    const {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  return generated_wasm_code_cache_.get();
}

GeneratedCodeCache* GeneratedCodeCacheContext::generated_webui_js_code_cache()
    const {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  return generated_webui_js_code_cache_.get();
}

GeneratedCodeCacheContext::~GeneratedCodeCacheContext() = default;

}  // namespace content