root/chrome/browser/chromeos/policy/app_pack_updater.cc

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

DEFINITIONS

This source file includes following definitions.
  1. SetCurrentAppPackExtensions
  2. StartLoading
  3. external_cache_
  4. CreateExternalLoader
  5. SetScreenSaverUpdateCallback
  6. AppPackChanged
  7. LoadPolicy
  8. OnExtensionListsUpdated
  9. UpdateExtensionLoader
  10. OnDamagedFileDetected
  11. SetScreenSaverPath

// 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/chromeos/policy/app_pack_updater.h"

#include "base/bind.h"
#include "base/memory/ref_counted.h"
#include "base/sequenced_task_runner.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/values.h"
#include "chrome/browser/chromeos/policy/enterprise_install_attributes.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/extensions/external_loader.h"
#include "chrome/browser/extensions/external_provider_impl.h"
#include "chromeos/settings/cros_settings_names.h"
#include "content/public/browser/browser_thread.h"

using content::BrowserThread;

namespace policy {

namespace {

// Directory where the AppPack extensions are cached.
const char kAppPackCacheDir[] = "/var/cache/app_pack";

}  // namespace

// A custom extensions::ExternalLoader that the AppPackUpdater creates and uses
// to publish AppPack updates to the extensions system.
class AppPackExternalLoader
    : public extensions::ExternalLoader,
      public base::SupportsWeakPtr<AppPackExternalLoader> {
 public:
  AppPackExternalLoader() {}

  // Used by the AppPackUpdater to update the current list of extensions.
  // The format of |prefs| is detailed in the extensions::ExternalLoader/
  // Provider headers.
  void SetCurrentAppPackExtensions(scoped_ptr<base::DictionaryValue> prefs) {
    app_pack_prefs_.Swap(prefs.get());
    StartLoading();
  }

  // Implementation of extensions::ExternalLoader:
  virtual void StartLoading() OVERRIDE {
    prefs_.reset(app_pack_prefs_.DeepCopy());
    VLOG(1) << "AppPack extension loader publishing "
            << app_pack_prefs_.size() << " crx files.";
    LoadFinished();
  }

 protected:
  virtual ~AppPackExternalLoader() {}

 private:
  base::DictionaryValue app_pack_prefs_;

  DISALLOW_COPY_AND_ASSIGN(AppPackExternalLoader);
};

AppPackUpdater::AppPackUpdater(net::URLRequestContextGetter* request_context,
                               EnterpriseInstallAttributes* install_attributes)
    : weak_ptr_factory_(this),
      created_extension_loader_(false),
      install_attributes_(install_attributes),
      external_cache_(base::FilePath(kAppPackCacheDir),
                      request_context,
                      content::BrowserThread::GetBlockingPool()->
                          GetSequencedTaskRunnerWithShutdownBehavior(
                              content::BrowserThread::GetBlockingPool()->
                                  GetSequenceToken(),
                              base::SequencedWorkerPool::SKIP_ON_SHUTDOWN),
                      this,
                      false,
                      false) {
  app_pack_subscription_ = chromeos::CrosSettings::Get()->AddSettingsObserver(
      chromeos::kAppPack,
      base::Bind(&AppPackUpdater::AppPackChanged, base::Unretained(this)));

  if (install_attributes_->GetMode() == DEVICE_MODE_RETAIL_KIOSK) {
    // Already in Kiosk mode, start loading.
    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
                            base::Bind(&AppPackUpdater::LoadPolicy,
                                       weak_ptr_factory_.GetWeakPtr()));
  } else {
    // Linger until the device switches to DEVICE_MODE_RETAIL_KIOSK and the
    // app pack device setting appears.
  }
}

AppPackUpdater::~AppPackUpdater() {
}

extensions::ExternalLoader* AppPackUpdater::CreateExternalLoader() {
  if (created_extension_loader_) {
    NOTREACHED();
    return NULL;
  }
  created_extension_loader_ = true;
  AppPackExternalLoader* loader = new AppPackExternalLoader();
  extension_loader_ = loader->AsWeakPtr();

  // The cache may have been already checked. In that case, load the current
  // extensions into the loader immediately.
  UpdateExtensionLoader();

  return loader;
}

void AppPackUpdater::SetScreenSaverUpdateCallback(
    const AppPackUpdater::ScreenSaverUpdateCallback& callback) {
  screen_saver_update_callback_ = callback;
  if (!screen_saver_update_callback_.is_null() && !screen_saver_path_.empty()) {
    BrowserThread::PostTask(
        BrowserThread::UI, FROM_HERE,
        base::Bind(screen_saver_update_callback_, screen_saver_path_));
  }
}

void AppPackUpdater::AppPackChanged() {
  if (install_attributes_->GetMode() == DEVICE_MODE_RETAIL_KIOSK)
    LoadPolicy();
}

void AppPackUpdater::LoadPolicy() {
  chromeos::CrosSettings* settings = chromeos::CrosSettings::Get();
  if (chromeos::CrosSettingsProvider::TRUSTED != settings->PrepareTrustedValues(
          base::Bind(&AppPackUpdater::LoadPolicy,
                     weak_ptr_factory_.GetWeakPtr()))) {
    return;
  }

  scoped_ptr<base::DictionaryValue> prefs(new base::DictionaryValue());
  const base::Value* value = settings->GetPref(chromeos::kAppPack);
  const base::ListValue* list = NULL;
  if (value && value->GetAsList(&list)) {
    for (base::ListValue::const_iterator it = list->begin();
         it != list->end(); ++it) {
      base::DictionaryValue* dict = NULL;
      if (!(*it)->GetAsDictionary(&dict)) {
        LOG(WARNING) << "AppPack entry is not a dictionary, ignoring.";
        continue;
      }
      std::string id;
      std::string update_url;
      if (dict->GetString(chromeos::kAppPackKeyExtensionId, &id) &&
          dict->GetString(chromeos::kAppPackKeyUpdateUrl, &update_url)) {
        base::DictionaryValue* entry = new base::DictionaryValue();
        entry->SetString(extensions::ExternalProviderImpl::kExternalUpdateUrl,
                         update_url);
        prefs->Set(id, entry);
      } else {
        LOG(WARNING) << "Failed to read required fields for an AppPack entry, "
                     << "ignoring.";
      }
    }
  }

  VLOG(1) << "Refreshed AppPack policy, got " << prefs->size()
          << " entries.";

  value = settings->GetPref(chromeos::kScreenSaverExtensionId);
  if (!value || !value->GetAsString(&screen_saver_id_)) {
    screen_saver_id_.clear();
    SetScreenSaverPath(base::FilePath());
  }

  external_cache_.UpdateExtensionsList(prefs.Pass());
}

void AppPackUpdater::OnExtensionListsUpdated(
    const base::DictionaryValue* prefs) {
  std::string crx_path;
  const base::DictionaryValue* screen_saver = NULL;
  if (prefs->GetDictionary(screen_saver_id_, &screen_saver)) {
    screen_saver->GetString(extensions::ExternalProviderImpl::kExternalCrx,
                            &crx_path);
  }
  if (!crx_path.empty())
    SetScreenSaverPath(base::FilePath(crx_path));
  else
    SetScreenSaverPath(base::FilePath());

  UpdateExtensionLoader();
}

void AppPackUpdater::UpdateExtensionLoader() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  if (!extension_loader_) {
    VLOG(1) << "No AppPack loader created yet, not pushing extensions.";
    return;
  }

  scoped_ptr<base::DictionaryValue> prefs(
      external_cache_.cached_extensions()->DeepCopy());

  // The screensaver isn't installed into the Profile.
  prefs->Remove(screen_saver_id_, NULL);

  extension_loader_->SetCurrentAppPackExtensions(prefs.Pass());
}

void AppPackUpdater::OnDamagedFileDetected(const base::FilePath& path) {
  external_cache_.OnDamagedFileDetected(path);
}

void AppPackUpdater::SetScreenSaverPath(const base::FilePath& path) {
  // Don't invoke the callback if the path isn't changing.
  if (path != screen_saver_path_) {
    screen_saver_path_ = path;
    if (!screen_saver_update_callback_.is_null())
      screen_saver_update_callback_.Run(screen_saver_path_);
  }
}

}  // namespace policy

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