| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // 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/callback.h" |
| #include "base/files/file.h" |
| #include "base/macros.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::Callback<void(base::File)> TempFileCallback; |
| typedef base::Callback<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(); |
| |
| // 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 render_view_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, |
| const base::Closure& 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; |
| int render_view_id; |
| 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(const base::Closure& callback, int net_error); |
| |
| void DeInitIfSafe(); |
| |
| // 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_; |
| DISALLOW_COPY_AND_ASSIGN(PnaclHost); |
| }; |
| |
| } // namespace pnacl |
| |
| #endif // COMPONENTS_NACL_BROWSER_PNACL_HOST_H_ |