C++程序  |  179行  |  7 KB

// 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_