1 // Copyright 2013 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef COMPONENTS_NACL_BROWSER_PNACL_HOST_H_ 6 #define COMPONENTS_NACL_BROWSER_PNACL_HOST_H_ 7 8 #include <stddef.h> 9 10 #include <map> 11 #include <memory> 12 13 #include "base/files/file.h" 14 #include "base/functional/callback.h" 15 #include "base/memory/raw_ptr.h" 16 #include "base/task/sequenced_task_runner.h" 17 #include "base/task/thread_pool.h" 18 #include "base/threading/thread_checker.h" 19 #include "components/nacl/browser/nacl_file_host.h" 20 #include "components/nacl/common/pnacl_types.h" 21 #include "ipc/ipc_platform_file.h" 22 23 namespace net { 24 class DrainableIOBuffer; 25 } 26 27 namespace pnacl { 28 29 class PnaclHostTest; 30 class PnaclHostTestDisk; 31 class PnaclTranslationCache; 32 33 // Shared state (translation cache) and common utilities (temp file creation) 34 // for all PNaCl translations. Unless otherwise specified, all methods should be 35 // called on the IO thread. 36 class PnaclHost { 37 public: 38 typedef base::RepeatingCallback<void(base::File)> TempFileCallback; 39 typedef base::RepeatingCallback<void(const base::File&, bool is_hit)> 40 NexeFdCallback; 41 42 // Gets the PnaclHost singleton instance (creating it if necessary). 43 // PnaclHost is a singleton because there is only one translation cache, and 44 // so that the BrowsingDataRemover can clear it even if no translation has 45 // ever been started. 46 static PnaclHost* GetInstance(); 47 48 PnaclHost(const PnaclHost&) = delete; 49 PnaclHost& operator=(const PnaclHost&) = delete; 50 51 // The PnaclHost instance is intentionally leaked on shutdown. DeInitIfSafe() 52 // attempts to cleanup |disk_cache_| earlier, but if it fails to do so in 53 // time, it will be too late when AtExitManager kicks in anway so subscribing 54 // to it is useless. 55 ~PnaclHost() = delete; 56 57 // Initialize cache backend. GetNexeFd will also initialize the backend if 58 // necessary, but calling Init ahead of time will minimize the latency. 59 void Init(); 60 61 // Creates a temporary file that will be deleted when the last handle 62 // is closed, or earlier. Returns a PlatformFile handle. 63 void CreateTemporaryFile(TempFileCallback cb); 64 65 // Create a temporary file, which will be deleted by the time the last 66 // handle is closed (or earlier on POSIX systems), to use for the nexe 67 // with the cache information given in |cache_info|. The specific instance 68 // is identified by the combination of |render_process_id| and |pp_instance|. 69 // Returns by calling |cb| with a PlatformFile handle. 70 // If the nexe is already present 71 // in the cache, |is_hit| is set to true and the contents of the nexe 72 // have been copied into the temporary file. Otherwise |is_hit| is set to 73 // false and the temporary file will be writeable. 74 // Currently the implementation is a stub, which always sets is_hit to false 75 // and calls the implementation of CreateTemporaryFile. 76 // If the cache request was a miss, the caller is expected to call 77 // TranslationFinished after it finishes translation to allow the nexe to be 78 // stored in the cache. 79 // The returned temp fd may be closed at any time by PnaclHost, so it should 80 // be duplicated (e.g. with IPC::GetPlatformFileForTransit) before the 81 // callback returns. 82 // If |is_incognito| is true, the nexe will not be stored 83 // in the cache, but the renderer is still expected to call 84 // TranslationFinished. 85 void GetNexeFd(int render_process_id, 86 int pp_instance, 87 bool is_incognito, 88 const nacl::PnaclCacheInfo& cache_info, 89 const NexeFdCallback& cb); 90 91 // Called after the translation of a pexe instance identified by 92 // |render_process_id| and |pp_instance| finishes. If |success| is true, 93 // store the nexe translated for the instance in the cache. 94 void TranslationFinished(int render_process_id, 95 int pp_instance, 96 bool success); 97 98 // Called when the renderer identified by |render_process_id| is closing. 99 // Clean up any outstanding translations for that renderer. If there are no 100 // more pending translations, the backend is freed, allowing it to flush. 101 void RendererClosing(int render_process_id); 102 103 // Doom all entries between |initial_time| and |end_time|. Like disk_cache_, 104 // PnaclHost supports supports unbounded deletes in either direction by using 105 // null Time values for either argument. |callback| will be called on the UI 106 // thread when finished. 107 void ClearTranslationCacheEntriesBetween(base::Time initial_time, 108 base::Time end_time, 109 base::OnceClosure callback); 110 111 // Return the number of tracked translations or FD requests currently pending. pending_translations()112 size_t pending_translations() { 113 DCHECK(thread_checker_.CalledOnValidThread()); 114 return pending_translations_.size(); 115 } 116 117 private: 118 friend class FileProxy; 119 friend class PnaclHostTest; 120 friend class PnaclHostTestDisk; 121 enum CacheState { 122 CacheUninitialized, 123 CacheInitializing, 124 CacheReady 125 }; 126 class PendingTranslation { 127 public: 128 PendingTranslation(); 129 PendingTranslation(const PendingTranslation& other); 130 ~PendingTranslation(); 131 base::ProcessHandle process_handle; 132 raw_ptr<base::File> nexe_fd; 133 bool got_nexe_fd; 134 bool got_cache_reply; 135 bool got_cache_hit; 136 bool is_incognito; 137 scoped_refptr<net::DrainableIOBuffer> nexe_read_buffer; 138 NexeFdCallback callback; 139 std::string cache_key; 140 nacl::PnaclCacheInfo cache_info; 141 }; 142 143 typedef std::pair<int, int> TranslationID; 144 typedef std::map<TranslationID, PendingTranslation> PendingTranslationMap; 145 146 PnaclHost(); 147 148 static bool TranslationMayBeCached( 149 const PendingTranslationMap::iterator& entry); 150 151 void InitForTest(base::FilePath temp_dir, bool in_memory); 152 void OnCacheInitialized(int net_error); 153 154 static void DoCreateTemporaryFile(base::FilePath temp_dir_, 155 TempFileCallback cb); 156 157 // GetNexeFd common steps 158 void SendCacheQueryAndTempFileRequest(const std::string& key, 159 const TranslationID& id); 160 void OnCacheQueryReturn(const TranslationID& id, 161 int net_error, 162 scoped_refptr<net::DrainableIOBuffer> buffer); 163 void OnTempFileReturn(const TranslationID& id, base::File file); 164 void CheckCacheQueryReady(const PendingTranslationMap::iterator& entry); 165 166 // GetNexeFd miss path 167 void ReturnMiss(const PendingTranslationMap::iterator& entry); 168 static scoped_refptr<net::DrainableIOBuffer> CopyFileToBuffer( 169 std::unique_ptr<base::File> file); 170 void StoreTranslatedNexe(TranslationID id, 171 scoped_refptr<net::DrainableIOBuffer>); 172 void OnTranslatedNexeStored(const TranslationID& id, int net_error); 173 void RequeryMatchingTranslations(const std::string& key); 174 175 // GetNexeFd hit path 176 void OnBufferCopiedToTempFile(const TranslationID& id, 177 std::unique_ptr<base::File> file, 178 int file_error); 179 180 void OnEntriesDoomed(base::OnceClosure callback, int net_error); 181 182 void DeInitIfSafe(); 183 184 scoped_refptr<base::SequencedTaskRunner> file_task_runner_ = 185 base::ThreadPool::CreateSequencedTaskRunner( 186 {base::MayBlock(), base::TaskPriority::USER_VISIBLE}); 187 188 // Operations which are pending with the cache backend, which we should 189 // wait for before destroying it (see comment on DeInitIfSafe). 190 int pending_backend_operations_ = 0; 191 CacheState cache_state_ = CacheUninitialized; 192 base::FilePath temp_dir_; 193 std::unique_ptr<PnaclTranslationCache> disk_cache_; 194 PendingTranslationMap pending_translations_; 195 base::ThreadChecker thread_checker_; 196 }; 197 198 } // namespace pnacl 199 200 #endif // COMPONENTS_NACL_BROWSER_PNACL_HOST_H_ 201