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