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 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
|
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_NACL_BROWSER_PNACL_HOST_H_
#define COMPONENTS_NACL_BROWSER_PNACL_HOST_H_
#include <stddef.h>
#include <map>
#include <memory>
#include "base/files/file.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/thread_pool.h"
#include "base/threading/thread_checker.h"
#include "components/nacl/browser/nacl_file_host.h"
#include "components/nacl/common/pnacl_types.h"
#include "ipc/ipc_platform_file.h"
namespace net {
class DrainableIOBuffer;
}
namespace pnacl {
class PnaclHostTest;
class PnaclHostTestDisk;
class PnaclTranslationCache;
// Shared state (translation cache) and common utilities (temp file creation)
// for all PNaCl translations. Unless otherwise specified, all methods should be
// called on the IO thread.
class PnaclHost {
public:
typedef base::RepeatingCallback<void(base::File)> TempFileCallback;
typedef base::RepeatingCallback<void(const base::File&, bool is_hit)>
NexeFdCallback;
// Gets the PnaclHost singleton instance (creating it if necessary).
// PnaclHost is a singleton because there is only one translation cache, and
// so that the BrowsingDataRemover can clear it even if no translation has
// ever been started.
static PnaclHost* GetInstance();
PnaclHost(const PnaclHost&) = delete;
PnaclHost& operator=(const PnaclHost&) = delete;
// The PnaclHost instance is intentionally leaked on shutdown. DeInitIfSafe()
// attempts to cleanup |disk_cache_| earlier, but if it fails to do so in
// time, it will be too late when AtExitManager kicks in anway so subscribing
// to it is useless.
~PnaclHost() = delete;
// Initialize cache backend. GetNexeFd will also initialize the backend if
// necessary, but calling Init ahead of time will minimize the latency.
void Init();
// Creates a temporary file that will be deleted when the last handle
// is closed, or earlier. Returns a PlatformFile handle.
void CreateTemporaryFile(TempFileCallback cb);
// Create a temporary file, which will be deleted by the time the last
// handle is closed (or earlier on POSIX systems), to use for the nexe
// with the cache information given in |cache_info|. The specific instance
// is identified by the combination of |render_process_id| and |pp_instance|.
// Returns by calling |cb| with a PlatformFile handle.
// If the nexe is already present
// in the cache, |is_hit| is set to true and the contents of the nexe
// have been copied into the temporary file. Otherwise |is_hit| is set to
// false and the temporary file will be writeable.
// Currently the implementation is a stub, which always sets is_hit to false
// and calls the implementation of CreateTemporaryFile.
// If the cache request was a miss, the caller is expected to call
// TranslationFinished after it finishes translation to allow the nexe to be
// stored in the cache.
// The returned temp fd may be closed at any time by PnaclHost, so it should
// be duplicated (e.g. with IPC::GetPlatformFileForTransit) before the
// callback returns.
// If |is_incognito| is true, the nexe will not be stored
// in the cache, but the renderer is still expected to call
// TranslationFinished.
void GetNexeFd(int render_process_id,
int pp_instance,
bool is_incognito,
const nacl::PnaclCacheInfo& cache_info,
const NexeFdCallback& cb);
// Called after the translation of a pexe instance identified by
// |render_process_id| and |pp_instance| finishes. If |success| is true,
// store the nexe translated for the instance in the cache.
void TranslationFinished(int render_process_id,
int pp_instance,
bool success);
// Called when the renderer identified by |render_process_id| is closing.
// Clean up any outstanding translations for that renderer. If there are no
// more pending translations, the backend is freed, allowing it to flush.
void RendererClosing(int render_process_id);
// Doom all entries between |initial_time| and |end_time|. Like disk_cache_,
// PnaclHost supports supports unbounded deletes in either direction by using
// null Time values for either argument. |callback| will be called on the UI
// thread when finished.
void ClearTranslationCacheEntriesBetween(base::Time initial_time,
base::Time end_time,
base::OnceClosure callback);
// Return the number of tracked translations or FD requests currently pending.
size_t pending_translations() {
DCHECK(thread_checker_.CalledOnValidThread());
return pending_translations_.size();
}
private:
friend class FileProxy;
friend class PnaclHostTest;
friend class PnaclHostTestDisk;
enum CacheState {
CacheUninitialized,
CacheInitializing,
CacheReady
};
class PendingTranslation {
public:
PendingTranslation();
PendingTranslation(const PendingTranslation& other);
~PendingTranslation();
base::ProcessHandle process_handle;
raw_ptr<base::File> nexe_fd;
bool got_nexe_fd;
bool got_cache_reply;
bool got_cache_hit;
bool is_incognito;
scoped_refptr<net::DrainableIOBuffer> nexe_read_buffer;
NexeFdCallback callback;
std::string cache_key;
nacl::PnaclCacheInfo cache_info;
};
typedef std::pair<int, int> TranslationID;
typedef std::map<TranslationID, PendingTranslation> PendingTranslationMap;
PnaclHost();
static bool TranslationMayBeCached(
const PendingTranslationMap::iterator& entry);
void InitForTest(base::FilePath temp_dir, bool in_memory);
void OnCacheInitialized(int net_error);
static void DoCreateTemporaryFile(base::FilePath temp_dir_,
TempFileCallback cb);
// GetNexeFd common steps
void SendCacheQueryAndTempFileRequest(const std::string& key,
const TranslationID& id);
void OnCacheQueryReturn(const TranslationID& id,
int net_error,
scoped_refptr<net::DrainableIOBuffer> buffer);
void OnTempFileReturn(const TranslationID& id, base::File file);
void CheckCacheQueryReady(const PendingTranslationMap::iterator& entry);
// GetNexeFd miss path
void ReturnMiss(const PendingTranslationMap::iterator& entry);
static scoped_refptr<net::DrainableIOBuffer> CopyFileToBuffer(
std::unique_ptr<base::File> file);
void StoreTranslatedNexe(TranslationID id,
scoped_refptr<net::DrainableIOBuffer>);
void OnTranslatedNexeStored(const TranslationID& id, int net_error);
void RequeryMatchingTranslations(const std::string& key);
// GetNexeFd hit path
void OnBufferCopiedToTempFile(const TranslationID& id,
std::unique_ptr<base::File> file,
int file_error);
void OnEntriesDoomed(base::OnceClosure callback, int net_error);
void DeInitIfSafe();
scoped_refptr<base::SequencedTaskRunner> file_task_runner_ =
base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE});
// Operations which are pending with the cache backend, which we should
// wait for before destroying it (see comment on DeInitIfSafe).
int pending_backend_operations_ = 0;
CacheState cache_state_ = CacheUninitialized;
base::FilePath temp_dir_;
std::unique_ptr<PnaclTranslationCache> disk_cache_;
PendingTranslationMap pending_translations_;
base::ThreadChecker thread_checker_;
};
} // namespace pnacl
#endif // COMPONENTS_NACL_BROWSER_PNACL_HOST_H_
|