// Copyright 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//    * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//    * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//    * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef CHROME_BROWSER_RENDER_PROCESS_HOST_H__
#define CHROME_BROWSER_RENDER_PROCESS_HOST_H__

#include <vector>
#include <windows.h>

#include "base/id_map.h"
#include "base/message_loop.h"
#include "base/process.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "chrome/common/ipc_channel_proxy.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/rand_util.h"
#include "chrome/common/render_messages.h"

class PrefService;
class Profile;
class RenderWidgetHelper;
class Thread;
class WebContents;

// Represents the browser side of the browser <--> renderer communication
// channel. There will be one RenderProcessHost per renderer process.
//
// This object is refcounted so that it can release its resources when all
// hosts using it go away.
//
// This object communicates back and forth with the RenderProcess object
// running in the renderer process. Each RenderProcessHost and RenderProcess
// keeps a list of RenderView (renderer) and WebContents (browser) which
// are correlated with IDs. This way, the Views and the corresponding ViewHosts
// communicate through the two process objects.
class RenderProcessHost : public IPC::Channel::Listener,
                          public MessageLoop::Watcher,
                          public IPC::Channel::Sender,
                          public NotificationObserver {
 public:
  // Returns the RenderProcessHost given its ID.  Returns NULL if the ID does
  // not correspond to a live RenderProcessHost.
  static RenderProcessHost* FromID(int render_process_id);

  explicit RenderProcessHost(Profile* profile);
  ~RenderProcessHost();

  // Flag to run the renderer in process.  This is primarily
  // for debugging purposes.  When running "in process", the
  // browser maintains a single RenderProcessHost which communicates
  // to a RenderProcess which is instantiated in the same process
  // with the Browser.  All IPC between the Browser and the
  // Renderer is the same, it's just not crossing a process boundary.
  static bool run_renderer_in_process() {
    return run_renderer_in_process_;
  }
  static void set_run_renderer_in_process(bool value) {
    run_renderer_in_process_ = value;
  }

  static void RegisterPrefs(PrefService* prefs);

  // If the a process has sent a message that cannot be decoded, it is deemed
  // corrupted and thus needs to be terminated using this call. This function
  // can be safely called from any thread.
  static void BadMessageTerminateProcess(uint16 msg_type, HANDLE renderer);

  // Called when a received message cannot be decoded.
  void ReceivedBadMessage(uint16 msg_type) {
    BadMessageTerminateProcess(msg_type, process_.handle());
  }

  // Initialize the new renderer process, returning true on success. This must
  // be called once before the object can be used, but can be called after
  // that with no effect. Therefore, if the caller isn't sure about whether
  // the process has been created, it should just call Init().
  bool Init();

  // Used for refcounting, each holder of this object must Attach and Release
  // just like it would for a COM object. This object should be allocated on
  // the heap; when no listeners own it any more, it will delete itself.
  void Attach(IPC::Channel::Listener* listener, int routing_id);

  // See Attach()
  void Release(int listener_id);

  // Listeners should call this when they've sent a "Close" message and
  // they're waiting for a "Close_ACK", so that if the renderer process
  // goes away we'll know that it was intentional rather than a crash.
  void ReportExpectingClose(int32 listener_id);

  // getters, these may return NULL if there is no connection
  IPC::ChannelProxy* channel() {
    return channel_.get();
  }
  HANDLE process() {
    return process_.handle();
  }

  // Get the process id of this renderer.
  int pid() const {
    return process_.pid();
  }

  // Try to shutdown the associated renderer process as fast as possible.
  // If this renderer has any RenderViews with unload handlers, then this
  // function does nothing.  The current implementation uses TerminateProcess.
  // Returns True if it was able to do fast shutdown.
  bool FastShutdownIfPossible();

  IPC::Channel::Listener* GetListenerByID(int routing_id) {
    return listeners_.Lookup(routing_id);
  }

  // Called to inform the render process host of a new "max page id" for a
  // render view host.  The render process host computes the largest page id
  // across all render view hosts and uses the value when it needs to
  // initialize a new renderer in place of the current one.
  void UpdateMaxPageID(int32 page_id);

  // Called to simulate a ClosePage_ACK message to the ResourceDispatcherHost.
  // Necessary for a cross-site request, in the case that the original
  // RenderViewHost is not live and thus cannot run an onunload handler.
  void CrossSiteClosePageACK(int new_render_process_host_id,
                             int new_request_id);

  // IPC channel listener
  virtual void OnMessageReceived(const IPC::Message& msg);
  virtual void OnChannelConnected(int32 peer_pid);

  // MessageLoop watcher callback
  virtual void OnObjectSignaled(HANDLE object);

  // IPC::Channel::Sender callback
  virtual bool Send(IPC::Message* msg);

  // Allows iteration over all the RenderProcessHosts in the browser. Note
  // that each host may not be active, and therefore may have NULL channels.
  // This is just a standard STL iterator, so it is not valid if the list
  // of RenderProcessHosts changes between iterations.
  typedef IDMap<RenderProcessHost>::const_iterator iterator;
  static iterator begin();
  static iterator end();
  static size_t size();

  // Allows iteration over this RenderProcessHost's RenderViewHost listeners.
  // Use from UI thread only.
  typedef IDMap<IPC::Channel::Listener>::const_iterator listeners_iterator;
  listeners_iterator listeners_begin() {
    return listeners_.begin();
  }
  listeners_iterator listeners_end() {
    return listeners_.end();
  }

  // Returns true if the caller should attempt to use an existing
  // RenderProcessHost rather than creating a new one.
  static bool ShouldTryToUseExistingProcessHost();

  // Get an existing RenderProcessHost associated with the given profile, if
  // possible.  The renderer process is chosen randomly from the
  // processes associated with the given profile.
  // Returns NULL if no suitable renderer process is available.
  static RenderProcessHost* GetExistingProcessHost(Profile* profile);

  int host_id() const { return host_id_; }

  // Returns the user profile associated with this renderer process.
  Profile* profile() const { return profile_; }

  RenderWidgetHelper* widget_helper() const { return widget_helper_; }

  // Track the count of visible widgets.  Called by listeners
  // to register/unregister visibility.
  void WidgetRestored();
  void WidgetHidden();

  // NotificationObserver implementation.
  virtual void Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details);

 private:
  // control message handlers
  void OnPageContents(const GURL& url, int32 page_id,
                      const std::wstring& contents);
  // Clipboard messages
  void OnClipboardWriteHTML(const std::wstring& markup, const GURL& src_url);
  void OnClipboardWriteBookmark(const std::wstring& title, const GURL& url);
  void OnClipboardWriteBitmap(SharedMemoryHandle bitmap, gfx::Size size);
  void OnClipboardIsFormatAvailable(unsigned int format, bool* result);
  void OnClipboardReadText(std::wstring* result);
  void OnClipboardReadAsciiText(std::string* result);
  void OnClipboardReadHTML(std::wstring* markup, GURL* src_url);
  void OnUpdatedCacheStats(const CacheManager::UsageStats& stats);

  // Callers can reduce the RenderProcess' priority.
  // Returns true if the priority is backgrounded; false otherwise.
  void SetBackgrounded(bool boost);

  // Unregister this object from all globals that reference it.
  // This would naturally be part of the destructor, but we destruct
  // asynchronously.
  void Unregister();

  // the registered listeners. When this list is empty or all NULL, we should
  // delete ourselves
  IDMap<IPC::Channel::Listener> listeners_;

  // set of listeners that expect the renderer process to close
  std::set<int> listeners_expecting_close_;

  // A proxy for our IPC::Channel that lives on the IO thread (see
  // browser_process.h)
  scoped_ptr<IPC::ChannelProxy> channel_;

  // Our renderer process.
  Process process_;

  // The profile associated with this renderer process.
  Profile* profile_;

  // Our ID into the IDMap.
  int host_id_;

  // The maximum page ID we've ever seen from the renderer process.
  int32 max_page_id_;

  // The count of currently visible widgets.  Since the host can be a container
  // for multiple widgets, it uses this count to determine when it should be
  // backgrounded.
  int32 visible_widgets_;

  // Does this process have backgrounded priority.
  bool backgrounded_;

  // Used to allow a RenderWidgetHost to intercept various messages on the
  // IO thread.
  scoped_refptr<RenderWidgetHelper> widget_helper_;

  // Whether we have notified that the process has terminated.
  bool notified_termination_;

  static bool run_renderer_in_process_;

  DISALLOW_EVIL_CONSTRUCTORS(RenderProcessHost);
};

// Generates a unique channel name for a child renderer/plugin process.
// The "instance" pointer value is baked into the channel id.
inline std::wstring GenerateRandomChannelID(void* instance) {
  // Note: the string must start with the current process id, this is how
  // child processes determine the pid of the parent.
  // Build the channel ID.  This is composed of a unique identifier for the
  // parent browser process, an identifier for the renderer/plugin instance,
  // and a random component. We use a random component so that a hacked child
  // process can't cause denial of service by causing future named pipe creation
  // to fail.
  return StringPrintf(L"%d.%x.%d",
                      GetCurrentProcessId(), instance,
                      rand_util::RandIntSecure(0, kint32max));
}


#endif  // CHROME_BROWSER_RENDER_PROCESS_HOST_H__