• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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