root/chrome/browser/pepper_flash_settings_manager.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. max_age
  2. plugin_prefs_
  3. Initialize
  4. Detach
  5. DeauthorizeContentLicenses
  6. GetPermissionSettings
  7. SetDefaultPermission
  8. SetSitePermission
  9. GetSitesWithData
  10. ClearSiteData
  11. OnMessageReceived
  12. OnChannelError
  13. ConnectToChannel
  14. InitializeOnIOThread
  15. DeauthorizeContentLicensesOnIOThread
  16. DeauthorizeContentLicensesOnBlockingPool
  17. DeauthorizeContentLicensesInPlugin
  18. GetPermissionSettingsOnIOThread
  19. SetDefaultPermissionOnIOThread
  20. SetSitePermissionOnIOThread
  21. GetSitesWithDataOnIOThread
  22. ClearSiteDataOnIOThread
  23. DetachOnIOThread
  24. NotifyErrorFromIOThread
  25. NotifyDeauthorizeContentLicensesCompleted
  26. NotifyGetPermissionSettingsCompleted
  27. NotifySetDefaultPermissionCompleted
  28. NotifySetSitePermissionCompleted
  29. NotifyGetSitesWithDataCompleted
  30. NotifyClearSiteDataCompleted
  31. NotifyError
  32. OnDeauthorizeContentLicensesResult
  33. OnGetPermissionSettingsResult
  34. OnSetDefaultPermissionResult
  35. OnSetSitePermissionResult
  36. OnGetSitesWithDataResult
  37. OnClearSiteDataResult
  38. weak_ptr_factory_
  39. IsPepperFlashInUse
  40. RegisterProfilePrefs
  41. DeauthorizeContentLicenses
  42. GetPermissionSettings
  43. SetDefaultPermission
  44. SetSitePermission
  45. GetSitesWithData
  46. ClearSiteData
  47. GetNextRequestId
  48. EnsureCoreExists
  49. OnError

// Copyright (c) 2012 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.

#include "chrome/browser/pepper_flash_settings_manager.h"

#include <map>
#include <utility>
#include <vector>

#include "base/bind.h"
#include "base/compiler_specific.h"
#include "base/file_util.h"
#include "base/prefs/pref_service.h"
#include "base/sequenced_task_runner_helpers.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/plugins/plugin_prefs.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/pepper/device_id_fetcher.h"
#include "chrome/common/pref_names.h"
#include "components/user_prefs/pref_registry_syncable.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/pepper_flash_settings_helper.h"
#include "content/public/browser/plugin_service.h"
#include "content/public/common/content_constants.h"
#include "content/public/common/webplugininfo.h"
#include "ipc/ipc_channel.h"
#include "ipc/ipc_listener.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "url/gurl.h"

using content::BrowserThread;

class PepperFlashSettingsManager::Core
    : public IPC::Listener,
      public base::RefCountedThreadSafe<Core, BrowserThread::DeleteOnIOThread> {
 public:
  Core(base::WeakPtr<PepperFlashSettingsManager> manager,
       content::BrowserContext* browser_context);

  void Initialize();

  // Notifies the core that it has been detached. Afterwards, no method should
  // be called any more.
  void Detach();

  void DeauthorizeContentLicenses(uint32 request_id);
  void GetPermissionSettings(
      uint32 request_id,
      PP_Flash_BrowserOperations_SettingType setting_type);
  void SetDefaultPermission(
      uint32 request_id,
      PP_Flash_BrowserOperations_SettingType setting_type,
      PP_Flash_BrowserOperations_Permission permission,
      bool clear_site_specific);
  void SetSitePermission(uint32 request_id,
                         PP_Flash_BrowserOperations_SettingType setting_type,
                         const ppapi::FlashSiteSettings& sites);
  void GetSitesWithData(uint32 request_id);
  void ClearSiteData(uint32 request_id,
                     const std::string& site,
                     uint64 flags,
                     uint64 max_age);

  // IPC::Listener implementation.
  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
  virtual void OnChannelError() OVERRIDE;

 private:
  friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>;
  friend class base::DeleteHelper<Core>;

  enum RequestType {
    INVALID_REQUEST_TYPE = 0,
    DEAUTHORIZE_CONTENT_LICENSES,
    GET_PERMISSION_SETTINGS,
    SET_DEFAULT_PERMISSION,
    SET_SITE_PERMISSION,
    GET_SITES_WITH_DATA,
    CLEAR_SITE_DATA,
  };

  enum State {
    STATE_UNINITIALIZED = 0,
    STATE_INITIALIZED,
    STATE_ERROR,
    STATE_DETACHED,
  };

  struct PendingRequest {
    PendingRequest()
        : id(0),
          type(INVALID_REQUEST_TYPE),
          setting_type(PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_CAMERAMIC),
          permission(PP_FLASH_BROWSEROPERATIONS_PERMISSION_DEFAULT),
          clear_site_specific(false),
          flags(0),
          max_age(0) {
    }

    uint32 id;
    RequestType type;

    // Used by GET_PERMISSION_SETTINGS, SET_DEFAULT_PERMISSION and
    // SET_SITE_PERMISSION.
    PP_Flash_BrowserOperations_SettingType setting_type;

    // Used by SET_DEFAULT_PERMISSION.
    PP_Flash_BrowserOperations_Permission permission;
    bool clear_site_specific;

    // Used by SET_SITE_PERMISSION.
    ppapi::FlashSiteSettings sites;

    // Used by CLEAR_SITE_DATA
    std::string site;
    uint64 flags;
    uint64 max_age;
  };

  virtual ~Core();

  void ConnectToChannel(bool success, const IPC::ChannelHandle& handle);

  void InitializeOnIOThread();
  void DeauthorizeContentLicensesOnIOThread(uint32 request_id);
  void DeauthorizeContentLicensesOnBlockingPool(
      uint32 request_id,
      const base::FilePath& profile_path);
  void DeauthorizeContentLicensesInPlugin(uint32 request_id, bool success);
  void GetPermissionSettingsOnIOThread(
      uint32 request_id,
      PP_Flash_BrowserOperations_SettingType setting_type);
  void SetDefaultPermissionOnIOThread(
      uint32 request_id,
      PP_Flash_BrowserOperations_SettingType setting_type,
      PP_Flash_BrowserOperations_Permission permission,
      bool clear_site_specific);
  void SetSitePermissionOnIOThread(
      uint32 request_id,
      PP_Flash_BrowserOperations_SettingType setting_type,
      const ppapi::FlashSiteSettings& sites);
  void GetSitesWithDataOnIOThread(uint32 request_id);
  void ClearSiteDataOnIOThread(uint32 request_id,
                               const std::string& site,
                               uint64 flags,
                               uint64 max_age);
  void DetachOnIOThread();

  void NotifyErrorFromIOThread();

  void NotifyDeauthorizeContentLicensesCompleted(uint32 request_id,
                                                 bool success);
  void NotifyGetPermissionSettingsCompleted(
      uint32 request_id,
      bool success,
      PP_Flash_BrowserOperations_Permission default_permission,
      const ppapi::FlashSiteSettings& sites);
  void NotifySetDefaultPermissionCompleted(uint32 request_id, bool success);
  void NotifySetSitePermissionCompleted(uint32 request_id, bool success);
  void NotifyGetSitesWithDataCompleted(uint32 request_id,
                                       const std::vector<std::string>& sites);
  void NotifyClearSiteDataCompleted(uint32 request_id, bool success);

  void NotifyError(
      const std::vector<std::pair<uint32, RequestType> >& notifications);

  // Message handlers.
  void OnDeauthorizeContentLicensesResult(uint32 request_id, bool success);
  void OnGetPermissionSettingsResult(
      uint32 request_id,
      bool success,
      PP_Flash_BrowserOperations_Permission default_permission,
      const ppapi::FlashSiteSettings& sites);
  void OnSetDefaultPermissionResult(uint32 request_id, bool success);
  void OnSetSitePermissionResult(uint32 request_id, bool success);
  void OnGetSitesWithDataResult(uint32 request_id,
                                const std::vector<std::string>& sites);
  void OnClearSiteDataResult(uint32 request_id, bool success);

  // Used only on the UI thread.
  base::WeakPtr<PepperFlashSettingsManager> manager_;

  // Used only on the I/O thread.
  base::FilePath plugin_data_path_;

  // The channel is NULL until we have opened a connection to the broker
  // process. Used only on the I/O thread.
  scoped_ptr<IPC::Channel> channel_;

  // Used only on the I/O thread.
  State state_;

  // Requests that need to be sent once the channel to the broker process is
  // established. Used only on the I/O thread.
  std::vector<PendingRequest> pending_requests_;
  // Requests that have been sent but haven't got replied. Used only on the
  // I/O thread.
  std::map<uint32, RequestType> pending_responses_;

  // Used only on the I/O thread.
  scoped_refptr<content::PepperFlashSettingsHelper> helper_;

  // Path for the current profile. Must be retrieved on the UI thread from the
  // browser context when we start so we can use it later on the I/O thread.
  base::FilePath browser_context_path_;

  scoped_refptr<PluginPrefs> plugin_prefs_;
};

PepperFlashSettingsManager::Core::Core(
    base::WeakPtr<PepperFlashSettingsManager> manager,
    content::BrowserContext* browser_context)
    : manager_(manager),
      state_(STATE_UNINITIALIZED),
      browser_context_path_(browser_context->GetPath()),
      plugin_prefs_(PluginPrefs::GetForProfile(
          Profile::FromBrowserContext(browser_context))) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}

PepperFlashSettingsManager::Core::~Core() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
}

void PepperFlashSettingsManager::Core::Initialize() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
                          base::Bind(&Core::InitializeOnIOThread, this));
}

void PepperFlashSettingsManager::Core::Detach() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  // This call guarantees that one ref is retained until we get to the DETACHED
  // state. This is important. Otherwise, if the ref count drops to zero on the
  // UI thread (which posts a task to delete this object on the I/O thread)
  // while the I/O thread doesn't know about it, methods on the I/O thread might
  // increase the ref count again and cause double deletion.
  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE, base::Bind(&Core::DetachOnIOThread, this));
}

void PepperFlashSettingsManager::Core::DeauthorizeContentLicenses(
    uint32 request_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      base::Bind(&Core::DeauthorizeContentLicensesOnIOThread, this,
                 request_id));
}

void PepperFlashSettingsManager::Core::GetPermissionSettings(
    uint32 request_id,
    PP_Flash_BrowserOperations_SettingType setting_type) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      base::Bind(&Core::GetPermissionSettingsOnIOThread, this, request_id,
                 setting_type));
}

void PepperFlashSettingsManager::Core::SetDefaultPermission(
    uint32 request_id,
    PP_Flash_BrowserOperations_SettingType setting_type,
    PP_Flash_BrowserOperations_Permission permission,
    bool clear_site_specific) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      base::Bind(&Core::SetDefaultPermissionOnIOThread, this, request_id,
                 setting_type, permission, clear_site_specific));
}

void PepperFlashSettingsManager::Core::SetSitePermission(
    uint32 request_id,
    PP_Flash_BrowserOperations_SettingType setting_type,
    const ppapi::FlashSiteSettings& sites) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      base::Bind(&Core::SetSitePermissionOnIOThread, this, request_id,
                 setting_type, sites));
}

void PepperFlashSettingsManager::Core::GetSitesWithData(uint32 request_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      base::Bind(&Core::GetSitesWithDataOnIOThread, this, request_id));
}

void PepperFlashSettingsManager::Core::ClearSiteData(uint32 request_id,
                                                     const std::string& site,
                                                     uint64 flags,
                                                     uint64 max_age) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      base::Bind(&Core::ClearSiteDataOnIOThread, this, request_id,
                 site, flags, max_age));
}

bool PepperFlashSettingsManager::Core::OnMessageReceived(
    const IPC::Message& message) {
  IPC_BEGIN_MESSAGE_MAP(Core, message)
    IPC_MESSAGE_HANDLER(PpapiHostMsg_DeauthorizeContentLicensesResult,
                        OnDeauthorizeContentLicensesResult)
    IPC_MESSAGE_HANDLER(PpapiHostMsg_GetPermissionSettingsResult,
                        OnGetPermissionSettingsResult)
    IPC_MESSAGE_HANDLER(PpapiHostMsg_SetDefaultPermissionResult,
                        OnSetDefaultPermissionResult)
    IPC_MESSAGE_HANDLER(PpapiHostMsg_SetSitePermissionResult,
                        OnSetSitePermissionResult)
    IPC_MESSAGE_HANDLER(PpapiHostMsg_GetSitesWithDataResult,
                        OnGetSitesWithDataResult)
    IPC_MESSAGE_HANDLER(PpapiHostMsg_ClearSiteDataResult,
                        OnClearSiteDataResult)
    IPC_MESSAGE_UNHANDLED_ERROR()
  IPC_END_MESSAGE_MAP()

  return true;
}

void PepperFlashSettingsManager::Core::OnChannelError() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  if (state_ == STATE_DETACHED)
    return;

  NotifyErrorFromIOThread();
}

void PepperFlashSettingsManager::Core::ConnectToChannel(
    bool success,
    const IPC::ChannelHandle& handle) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  if (state_ == STATE_DETACHED)
    return;

  DCHECK(state_ == STATE_UNINITIALIZED);
  DCHECK(!channel_.get());

  if (!success) {
    DLOG(ERROR) << "Couldn't open plugin channel";
    NotifyErrorFromIOThread();
    return;
  }

  channel_.reset(new IPC::Channel(handle, IPC::Channel::MODE_CLIENT, this));
  if (!channel_->Connect()) {
    DLOG(ERROR) << "Couldn't connect to plugin";
    NotifyErrorFromIOThread();
    return;
  }

  state_ = STATE_INITIALIZED;

  std::vector<PendingRequest> temp_pending_requests;
  temp_pending_requests.swap(pending_requests_);
  for (std::vector<PendingRequest>::iterator iter =
           temp_pending_requests.begin();
       iter != temp_pending_requests.end(); ++iter) {
    switch (iter->type) {
      case INVALID_REQUEST_TYPE:
        NOTREACHED();
        break;
      case DEAUTHORIZE_CONTENT_LICENSES:
        DeauthorizeContentLicensesOnIOThread(iter->id);
        break;
      case GET_PERMISSION_SETTINGS:
        GetPermissionSettingsOnIOThread(iter->id, iter->setting_type);
        break;
      case SET_DEFAULT_PERMISSION:
        SetDefaultPermissionOnIOThread(
            iter->id, iter->setting_type, iter->permission,
            iter->clear_site_specific);
        break;
      case SET_SITE_PERMISSION:
        SetSitePermissionOnIOThread(iter->id, iter->setting_type, iter->sites);
        break;
      case GET_SITES_WITH_DATA:
        GetSitesWithDataOnIOThread(iter->id);
        break;
      case CLEAR_SITE_DATA:
        ClearSiteDataOnIOThread(iter->id, iter->site, iter->flags,
                                iter->max_age);
        break;
    }
  }
}

void PepperFlashSettingsManager::Core::InitializeOnIOThread() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  DCHECK_EQ(STATE_UNINITIALIZED, state_);

  content::WebPluginInfo plugin_info;
  if (!PepperFlashSettingsManager::IsPepperFlashInUse(plugin_prefs_.get(),
                                                      &plugin_info)) {
    NotifyErrorFromIOThread();
    return;
  }

  base::FilePath profile_path =
      browser_context_path_.Append(content::kPepperDataDirname);
#if defined(OS_WIN)
  plugin_data_path_ = profile_path.Append(plugin_info.name);
#else
  plugin_data_path_ = profile_path.Append(base::UTF16ToUTF8(plugin_info.name));
#endif

  helper_ = content::PepperFlashSettingsHelper::Create();
  content::PepperFlashSettingsHelper::OpenChannelCallback callback =
      base::Bind(&Core::ConnectToChannel, this);
  helper_->OpenChannelToBroker(plugin_info.path, callback);
}

void PepperFlashSettingsManager::Core::DeauthorizeContentLicensesOnIOThread(
    uint32 request_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  DCHECK_NE(STATE_DETACHED, state_);

  if (state_ == STATE_UNINITIALIZED) {
    PendingRequest request;
    request.id = request_id;
    request.type = DEAUTHORIZE_CONTENT_LICENSES;
    pending_requests_.push_back(request);
    return;
  }

  pending_responses_.insert(
      std::make_pair(request_id, DEAUTHORIZE_CONTENT_LICENSES));
  if (state_ == STATE_ERROR) {
    NotifyErrorFromIOThread();
    return;
  }

#if defined(OS_CHROMEOS)
  BrowserThread::PostBlockingPoolTask(FROM_HERE,
      base::Bind(&Core::DeauthorizeContentLicensesOnBlockingPool, this,
                 request_id, browser_context_path_));
#else
  DeauthorizeContentLicensesInPlugin(request_id, true);
#endif
}

// TODO(raymes): This is temporary code to migrate ChromeOS devices to the new
// scheme for generating device IDs. Delete this once we are sure most ChromeOS
// devices have been migrated.
void PepperFlashSettingsManager::Core::DeauthorizeContentLicensesOnBlockingPool(
    uint32 request_id,
    const base::FilePath& profile_path) {
  // ChromeOS used to store the device ID in a file but this is no longer used.
  // Wipe that file.
  const base::FilePath& device_id_path =
      chrome::DeviceIDFetcher::GetLegacyDeviceIDPath(profile_path);
  bool success = base::DeleteFile(device_id_path, false);

  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      base::Bind(&Core::DeauthorizeContentLicensesInPlugin, this, request_id,
                 success));
}

void PepperFlashSettingsManager::Core::DeauthorizeContentLicensesInPlugin(
    uint32 request_id,
    bool success) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  if (!success) {
    NotifyErrorFromIOThread();
    return;
  }
  IPC::Message* msg =
      new PpapiMsg_DeauthorizeContentLicenses(request_id, plugin_data_path_);
  if (!channel_->Send(msg)) {
    DLOG(ERROR) << "Couldn't send DeauthorizeContentLicenses message";
    // A failure notification for the current request will be sent since
    // |pending_responses_| has been updated.
    NotifyErrorFromIOThread();
  }
}

void PepperFlashSettingsManager::Core::GetPermissionSettingsOnIOThread(
    uint32 request_id,
    PP_Flash_BrowserOperations_SettingType setting_type) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  DCHECK_NE(STATE_DETACHED, state_);

  if (state_ == STATE_UNINITIALIZED) {
    PendingRequest request;
    request.id = request_id;
    request.type = GET_PERMISSION_SETTINGS;
    request.setting_type = setting_type;
    pending_requests_.push_back(request);
    return;
  }

  pending_responses_.insert(
      std::make_pair(request_id, GET_PERMISSION_SETTINGS));
  if (state_ == STATE_ERROR) {
    NotifyErrorFromIOThread();
    return;
  }

  IPC::Message* msg = new PpapiMsg_GetPermissionSettings(
      request_id, plugin_data_path_, setting_type);
  if (!channel_->Send(msg)) {
    DLOG(ERROR) << "Couldn't send GetPermissionSettings message";
    // A failure notification for the current request will be sent since
    // |pending_responses_| has been updated.
    NotifyErrorFromIOThread();
  }
}

void PepperFlashSettingsManager::Core::SetDefaultPermissionOnIOThread(
    uint32 request_id,
    PP_Flash_BrowserOperations_SettingType setting_type,
    PP_Flash_BrowserOperations_Permission permission,
    bool clear_site_specific) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  DCHECK_NE(STATE_DETACHED, state_);

  if (state_ == STATE_UNINITIALIZED) {
    PendingRequest request;
    request.id = request_id;
    request.type = SET_DEFAULT_PERMISSION;
    request.setting_type = setting_type;
    request.permission = permission;
    request.clear_site_specific = clear_site_specific;
    pending_requests_.push_back(request);
    return;
  }

  pending_responses_.insert(std::make_pair(request_id, SET_DEFAULT_PERMISSION));
  if (state_ == STATE_ERROR) {
    NotifyErrorFromIOThread();
    return;
  }

  IPC::Message* msg = new PpapiMsg_SetDefaultPermission(
      request_id, plugin_data_path_, setting_type, permission,
      clear_site_specific);
  if (!channel_->Send(msg)) {
    DLOG(ERROR) << "Couldn't send SetDefaultPermission message";
    // A failure notification for the current request will be sent since
    // |pending_responses_| has been updated.
    NotifyErrorFromIOThread();
  }
}

void PepperFlashSettingsManager::Core::SetSitePermissionOnIOThread(
    uint32 request_id,
    PP_Flash_BrowserOperations_SettingType setting_type,
    const ppapi::FlashSiteSettings& sites) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  DCHECK_NE(STATE_DETACHED, state_);

  if (state_ == STATE_UNINITIALIZED) {
    pending_requests_.push_back(PendingRequest());
    PendingRequest& request = pending_requests_.back();
    request.id = request_id;
    request.type = SET_SITE_PERMISSION;
    request.setting_type = setting_type;
    request.sites = sites;
    return;
  }

  pending_responses_.insert(std::make_pair(request_id, SET_SITE_PERMISSION));
  if (state_ == STATE_ERROR) {
    NotifyErrorFromIOThread();
    return;
  }

  IPC::Message* msg = new PpapiMsg_SetSitePermission(
      request_id, plugin_data_path_, setting_type, sites);
  if (!channel_->Send(msg)) {
    DLOG(ERROR) << "Couldn't send SetSitePermission message";
    // A failure notification for the current request will be sent since
    // |pending_responses_| has been updated.
    NotifyErrorFromIOThread();
  }
}

void PepperFlashSettingsManager::Core::GetSitesWithDataOnIOThread(
    uint32 request_id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  DCHECK_NE(STATE_DETACHED, state_);

  if (state_ == STATE_UNINITIALIZED) {
    pending_requests_.push_back(PendingRequest());
    PendingRequest& request = pending_requests_.back();
    request.id = request_id;
    request.type = GET_SITES_WITH_DATA;
    return;
  }

  pending_responses_.insert(std::make_pair(request_id, GET_SITES_WITH_DATA));
  if (state_ == STATE_ERROR) {
    NotifyErrorFromIOThread();
    return;
  }

  IPC::Message* msg = new PpapiMsg_GetSitesWithData(
      request_id, plugin_data_path_);
  if (!channel_->Send(msg)) {
    DLOG(ERROR) << "Couldn't send GetSitesWithData message";
    // A failure notification for the current request will be sent since
    // |pending_responses_| has been updated.
    NotifyErrorFromIOThread();
  }
}

void PepperFlashSettingsManager::Core::ClearSiteDataOnIOThread(
    uint32 request_id,
    const std::string& site,
    uint64 flags,
    uint64 max_age) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  DCHECK_NE(STATE_DETACHED, state_);

  if (state_ == STATE_UNINITIALIZED) {
    pending_requests_.push_back(PendingRequest());
    PendingRequest& request = pending_requests_.back();
    request.id = request_id;
    request.type = CLEAR_SITE_DATA;
    request.site = site;
    request.flags = flags;
    request.max_age = max_age;
    return;
  }

  pending_responses_.insert(std::make_pair(request_id, CLEAR_SITE_DATA));
  if (state_ == STATE_ERROR) {
    NotifyErrorFromIOThread();
    return;
  }

  IPC::Message* msg = new PpapiMsg_ClearSiteData(
      request_id, plugin_data_path_, site, flags, max_age);
  if (!channel_->Send(msg)) {
    DLOG(ERROR) << "Couldn't send ClearSiteData message";
    // A failure notification for the current request will be sent since
    // |pending_responses_| has been updated.
    NotifyErrorFromIOThread();
  }
}

void PepperFlashSettingsManager::Core::DetachOnIOThread() {
  state_ = STATE_DETACHED;
}

void PepperFlashSettingsManager::Core::NotifyErrorFromIOThread() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  if (state_ == STATE_DETACHED)
    return;

  state_ = STATE_ERROR;
  std::vector<std::pair<uint32, RequestType> > notifications;
  for (std::vector<PendingRequest>::iterator iter = pending_requests_.begin();
       iter != pending_requests_.end(); ++iter) {
    notifications.push_back(std::make_pair(iter->id, iter->type));
  }
  pending_requests_.clear();
  notifications.insert(notifications.end(), pending_responses_.begin(),
                       pending_responses_.end());
  pending_responses_.clear();

  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      base::Bind(&Core::NotifyError, this, notifications));
}

void
PepperFlashSettingsManager::Core::NotifyDeauthorizeContentLicensesCompleted(
    uint32 request_id,
    bool success) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  if (manager_.get()) {
    manager_->client_->OnDeauthorizeContentLicensesCompleted(
        request_id, success);
  }
}

void PepperFlashSettingsManager::Core::NotifyGetPermissionSettingsCompleted(
    uint32 request_id,
    bool success,
    PP_Flash_BrowserOperations_Permission default_permission,
    const ppapi::FlashSiteSettings& sites) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  if (manager_.get()) {
    manager_->client_->OnGetPermissionSettingsCompleted(
        request_id, success, default_permission, sites);
  }
}

void PepperFlashSettingsManager::Core::NotifySetDefaultPermissionCompleted(
    uint32 request_id,
    bool success) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  if (manager_.get()) {
    manager_->client_->OnSetDefaultPermissionCompleted(
        request_id, success);
  }
}

void PepperFlashSettingsManager::Core::NotifySetSitePermissionCompleted(
    uint32 request_id,
    bool success) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  if (manager_.get()) {
    manager_->client_->OnSetSitePermissionCompleted(
        request_id, success);
  }
}

void PepperFlashSettingsManager::Core::NotifyGetSitesWithDataCompleted(
    uint32 request_id,
    const std::vector<std::string>& sites) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  if (manager_.get()) {
    manager_->client_->OnGetSitesWithDataCompleted(
        request_id, sites);
  }
}

void PepperFlashSettingsManager::Core::NotifyClearSiteDataCompleted(
    uint32 request_id,
    bool success) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  if (manager_.get())
    manager_->client_->OnClearSiteDataCompleted(request_id, success);
}

void PepperFlashSettingsManager::Core::NotifyError(
    const std::vector<std::pair<uint32, RequestType> >& notifications) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  scoped_refptr<Core> protector(this);
  for (std::vector<std::pair<uint32, RequestType> >::const_iterator iter =
      notifications.begin(); iter != notifications.end(); ++iter) {
    // Check |manager_| for each iteration in case it is destroyed in one of
    // the callbacks.
    if (!manager_.get())
      return;

    switch (iter->second) {
      case INVALID_REQUEST_TYPE:
        NOTREACHED();
        break;
      case DEAUTHORIZE_CONTENT_LICENSES:
        manager_->client_->OnDeauthorizeContentLicensesCompleted(
            iter->first, false);
        break;
      case GET_PERMISSION_SETTINGS:
        manager_->client_->OnGetPermissionSettingsCompleted(
            iter->first, false, PP_FLASH_BROWSEROPERATIONS_PERMISSION_DEFAULT,
            ppapi::FlashSiteSettings());
        break;
      case SET_DEFAULT_PERMISSION:
        manager_->client_->OnSetDefaultPermissionCompleted(
            iter->first, false);
        break;
      case SET_SITE_PERMISSION:
        manager_->client_->OnSetSitePermissionCompleted(iter->first, false);
        break;
      case GET_SITES_WITH_DATA:
        manager_->client_->OnGetSitesWithDataCompleted(
            iter->first, std::vector<std::string>());
        break;
      case CLEAR_SITE_DATA:
        manager_->client_->OnClearSiteDataCompleted(iter->first, false);
        break;
    }
  }

  if (manager_.get())
    manager_->OnError(this);
}

void PepperFlashSettingsManager::Core::OnDeauthorizeContentLicensesResult(
    uint32 request_id,
    bool success) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  if (state_ == STATE_DETACHED)
    return;

  DLOG_IF(ERROR, !success) << "DeauthorizeContentLicenses returned error";

  std::map<uint32, RequestType>::iterator iter =
      pending_responses_.find(request_id);
  if (iter == pending_responses_.end())
    return;

  DCHECK_EQ(iter->second, DEAUTHORIZE_CONTENT_LICENSES);

  pending_responses_.erase(iter);
  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      base::Bind(&Core::NotifyDeauthorizeContentLicensesCompleted, this,
                 request_id, success));
}

void PepperFlashSettingsManager::Core::OnGetPermissionSettingsResult(
    uint32 request_id,
    bool success,
    PP_Flash_BrowserOperations_Permission default_permission,
    const ppapi::FlashSiteSettings& sites) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  if (state_ == STATE_DETACHED)
    return;

  DLOG_IF(ERROR, !success) << "GetPermissionSettings returned error";

  std::map<uint32, RequestType>::iterator iter =
      pending_responses_.find(request_id);
  if (iter == pending_responses_.end())
    return;

  DCHECK_EQ(iter->second, GET_PERMISSION_SETTINGS);

  pending_responses_.erase(iter);
  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      base::Bind(&Core::NotifyGetPermissionSettingsCompleted, this,
                 request_id, success, default_permission, sites));
}

void PepperFlashSettingsManager::Core::OnSetDefaultPermissionResult(
    uint32 request_id,
    bool success) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  if (state_ == STATE_DETACHED)
    return;

  DLOG_IF(ERROR, !success) << "SetDefaultPermission returned error";

  std::map<uint32, RequestType>::iterator iter =
      pending_responses_.find(request_id);
  if (iter == pending_responses_.end())
    return;

  DCHECK_EQ(iter->second, SET_DEFAULT_PERMISSION);

  pending_responses_.erase(iter);
  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      base::Bind(&Core::NotifySetDefaultPermissionCompleted, this,
                 request_id, success));
}

void PepperFlashSettingsManager::Core::OnSetSitePermissionResult(
    uint32 request_id,
    bool success) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  if (state_ == STATE_DETACHED)
    return;

  DLOG_IF(ERROR, !success) << "SetSitePermission returned error";

  std::map<uint32, RequestType>::iterator iter =
      pending_responses_.find(request_id);
  if (iter == pending_responses_.end())
    return;

  DCHECK_EQ(iter->second, SET_SITE_PERMISSION);

  pending_responses_.erase(iter);
  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      base::Bind(&Core::NotifySetSitePermissionCompleted, this, request_id,
      success));
}

void PepperFlashSettingsManager::Core::OnGetSitesWithDataResult(
    uint32 request_id,
    const std::vector<std::string>& sites) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  if (state_ == STATE_DETACHED)
    return;

  std::map<uint32, RequestType>::iterator iter =
      pending_responses_.find(request_id);
  if (iter == pending_responses_.end())
    return;

  DCHECK_EQ(iter->second, GET_SITES_WITH_DATA);

  pending_responses_.erase(iter);
  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      base::Bind(&Core::NotifyGetSitesWithDataCompleted, this, request_id,
      sites));
}

void PepperFlashSettingsManager::Core::OnClearSiteDataResult(
    uint32 request_id,
    bool success) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  if (state_ == STATE_DETACHED)
    return;

  DLOG_IF(ERROR, !success) << "ClearSiteData returned error";

  std::map<uint32, RequestType>::iterator iter =
      pending_responses_.find(request_id);
  if (iter == pending_responses_.end())
    return;

  DCHECK_EQ(iter->second, CLEAR_SITE_DATA);

  pending_responses_.erase(iter);
  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      base::Bind(&Core::NotifyClearSiteDataCompleted, this, request_id,
      success));
}

PepperFlashSettingsManager::PepperFlashSettingsManager(
    Client* client,
    content::BrowserContext* browser_context)
    : client_(client),
      browser_context_(browser_context),
      next_request_id_(1),
      weak_ptr_factory_(this) {
  DCHECK(client);
  DCHECK(browser_context);
}

PepperFlashSettingsManager::~PepperFlashSettingsManager() {
  if (core_.get())
    core_->Detach();
}

// static
bool PepperFlashSettingsManager::IsPepperFlashInUse(
    PluginPrefs* plugin_prefs,
    content::WebPluginInfo* plugin_info) {
  if (!plugin_prefs)
    return false;

  content::PluginService* plugin_service =
      content::PluginService::GetInstance();
  std::vector<content::WebPluginInfo> plugins;
  plugin_service->GetPluginInfoArray(
      GURL(), content::kFlashPluginSwfMimeType, false, &plugins, NULL);

  for (std::vector<content::WebPluginInfo>::iterator iter = plugins.begin();
       iter != plugins.end(); ++iter) {
    if (iter->is_pepper_plugin() && plugin_prefs->IsPluginEnabled(*iter)) {
      if (plugin_info)
        *plugin_info = *iter;
      return true;
    }
  }
  return false;
}

// static
void PepperFlashSettingsManager::RegisterProfilePrefs(
    user_prefs::PrefRegistrySyncable* registry) {
  registry->RegisterBooleanPref(
      prefs::kDeauthorizeContentLicenses,
      false,
      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);

  registry->RegisterBooleanPref(
      prefs::kPepperFlashSettingsEnabled,
      true,
      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
}

uint32 PepperFlashSettingsManager::DeauthorizeContentLicenses(
    PrefService* prefs) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  // Clear the device ID salt which has the effect of regenerating a device
  // ID. Since this happens synchronously (and on the UI thread), we don't have
  // to add it to a pending request.
  prefs->ClearPref(prefs::kDRMSalt);

  EnsureCoreExists();
  uint32 id = GetNextRequestId();
  core_->DeauthorizeContentLicenses(id);
  return id;
}

uint32 PepperFlashSettingsManager::GetPermissionSettings(
    PP_Flash_BrowserOperations_SettingType setting_type) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  EnsureCoreExists();
  uint32 id = GetNextRequestId();
  core_->GetPermissionSettings(id, setting_type);
  return id;
}

uint32 PepperFlashSettingsManager::SetDefaultPermission(
    PP_Flash_BrowserOperations_SettingType setting_type,
    PP_Flash_BrowserOperations_Permission permission,
    bool clear_site_specific) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  EnsureCoreExists();
  uint32 id = GetNextRequestId();
  core_->SetDefaultPermission(id, setting_type, permission,
                              clear_site_specific);
  return id;
}

uint32 PepperFlashSettingsManager::SetSitePermission(
    PP_Flash_BrowserOperations_SettingType setting_type,
    const ppapi::FlashSiteSettings& sites) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  EnsureCoreExists();
  uint32 id = GetNextRequestId();
  core_->SetSitePermission(id, setting_type, sites);
  return id;
}

uint32 PepperFlashSettingsManager::GetSitesWithData() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  EnsureCoreExists();
  uint32 id = GetNextRequestId();
  core_->GetSitesWithData(id);
  return id;
}

uint32 PepperFlashSettingsManager::ClearSiteData(const std::string& site,
                                                 uint64 flags,
                                                 uint64 max_age) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  EnsureCoreExists();
  uint32 id = GetNextRequestId();
  core_->ClearSiteData(id, site, flags, max_age);
  return id;
}

uint32 PepperFlashSettingsManager::GetNextRequestId() {
  return next_request_id_++;
}

void PepperFlashSettingsManager::EnsureCoreExists() {
  if (!core_.get()) {
    core_ = new Core(weak_ptr_factory_.GetWeakPtr(), browser_context_);
    core_->Initialize();
  }
}

void PepperFlashSettingsManager::OnError(Core* core) {
  DCHECK(core);
  if (core != core_.get())
    return;

  core_->Detach();
  core_ = NULL;
}

/* [<][>][^][v][top][bottom][index][help] */