// 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 <map> #include "base/callback_forward.h" #include "base/memory/singleton.h" #include "base/memory/weak_ptr.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 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::PlatformFile)> TempFileCallback; typedef base::Callback<void(base::PlatformFile, bool is_hit)> NexeFdCallback; static PnaclHost* GetInstance(); PnaclHost(); ~PnaclHost(); // 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::GetFileHandleForProcess) 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() { return pending_translations_.size(); } private: // 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. friend struct DefaultSingletonTraits<PnaclHost>; friend class pnacl::PnaclHostTest; enum CacheState { CacheUninitialized, CacheInitializing, CacheReady }; class PendingTranslation { public: PendingTranslation(); ~PendingTranslation(); base::ProcessHandle process_handle; int render_view_id; base::PlatformFile 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; static bool TranslationMayBeCached( const PendingTranslationMap::iterator& entry); void InitForTest(base::FilePath temp_dir); 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::PlatformFile fd); void CheckCacheQueryReady(const PendingTranslationMap::iterator& entry); // GetNexeFd miss path void ReturnMiss(const PendingTranslationMap::iterator& entry); static scoped_refptr<net::DrainableIOBuffer> CopyFileToBuffer( base::PlatformFile fd); 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 static int CopyBufferToFile(base::PlatformFile fd, scoped_refptr<net::DrainableIOBuffer> buffer); void OnBufferCopiedToTempFile(const TranslationID& id, 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_; CacheState cache_state_; base::FilePath temp_dir_; scoped_ptr<pnacl::PnaclTranslationCache> disk_cache_; PendingTranslationMap pending_translations_; base::ThreadChecker thread_checker_; base::WeakPtrFactory<PnaclHost> weak_factory_; DISALLOW_COPY_AND_ASSIGN(PnaclHost); }; } // namespace pnacl #endif // COMPONENTS_NACL_BROWSER_PNACL_HOST_H_