diff options
16 files changed, 426 insertions, 148 deletions
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_data.cc b/chrome/browser/chromeos/app_mode/kiosk_app_data.cc index 1c5a874..85da09c 100644 --- a/chrome/browser/chromeos/app_mode/kiosk_app_data.cc +++ b/chrome/browser/chromeos/app_mode/kiosk_app_data.cc @@ -33,6 +33,7 @@ #include "extensions/common/manifest.h" #include "extensions/common/manifest_constants.h" #include "extensions/common/manifest_handlers/icons_handler.h" +#include "extensions/common/manifest_handlers/kiosk_mode_info.h" #include "ui/gfx/codec/png_codec.h" #include "ui/gfx/image/image.h" @@ -45,6 +46,7 @@ namespace { // Keys for local state data. See sample layout in KioskAppManager. const char kKeyName[] = "name"; const char kKeyIcon[] = "icon"; +const char kKeyRequiredPlatformVersion[] = "required_platform_version"; const char kInvalidWebstoreResponseError[] = "Invalid Chrome Web Store reponse"; @@ -113,6 +115,9 @@ class KioskAppData::CrxLoader : public extensions::SandboxedUnpackerClient { const base::FilePath& crx_file() const { return crx_file_; } const std::string& name() const { return name_; } const SkBitmap& icon() const { return icon_; } + const std::string& required_platform_version() const { + return required_platform_version_; + } private: ~CrxLoader() override {}; @@ -128,6 +133,8 @@ class KioskAppData::CrxLoader : public extensions::SandboxedUnpackerClient { success_ = true; name_ = extension->name(); icon_ = install_icon; + required_platform_version_ = + extensions::KioskModeInfo::Get(extension)->required_platform_version; NotifyFinishedOnBlockingPool(); } void OnUnpackFailure(const extensions::CrxInstallError& error) override { @@ -183,6 +190,7 @@ class KioskAppData::CrxLoader : public extensions::SandboxedUnpackerClient { // Extracted meta data. std::string name_; SkBitmap icon_; + std::string required_platform_version_; DISALLOW_COPY_AND_ASSIGN(CrxLoader); }; @@ -349,8 +357,20 @@ class KioskAppData::WebstoreDataParser return; } + std::string required_platform_version; + if (manifest.HasPath( + extensions::manifest_keys::kKioskRequiredPlatformVersion) && + (!manifest.GetString( + extensions::manifest_keys::kKioskRequiredPlatformVersion, + &required_platform_version) || + !extensions::KioskModeInfo::IsValidPlatformVersion( + required_platform_version))) { + ReportFailure(); + return; + } + if (client_) - client_->OnWebstoreParseSuccess(icon); + client_->OnWebstoreParseSuccess(icon, required_platform_version); delete this; } void OnWebstoreParseFailure(const std::string& id, @@ -418,6 +438,8 @@ void KioskAppData::LoadFromInstalledApp(Profile* profile, DCHECK_EQ(app_id_, app->id()); name_ = app->name(); + required_platform_version_ = + extensions::KioskModeInfo::Get(app)->required_platform_version; const int kIconSize = extension_misc::EXTENSION_ICON_LARGE; extensions::ExtensionResource image = extensions::IconsInfo::GetIconResource( @@ -444,6 +466,10 @@ bool KioskAppData::IsFromWebStore() const { extension_urls::IsWebstoreUpdateUrl(update_url_); } +void KioskAppData::SetStatusForTest(Status status) { + SetStatus(status); +} + void KioskAppData::SetStatus(Status status) { if (status_ == status) return; @@ -471,9 +497,12 @@ net::URLRequestContextGetter* KioskAppData::GetRequestContextGetter() { } bool KioskAppData::LoadFromCache() { - std::string app_key = std::string(KioskAppManager::kKeyApps) + '.' + app_id_; - std::string name_key = app_key + '.' + kKeyName; - std::string icon_path_key = app_key + '.' + kKeyIcon; + const std::string app_key = + std::string(KioskAppManager::kKeyApps) + '.' + app_id_; + const std::string name_key = app_key + '.' + kKeyName; + const std::string icon_path_key = app_key + '.' + kKeyIcon; + const std::string required_platform_version_key = + app_key + '.' + kKeyRequiredPlatformVersion; PrefService* local_state = g_browser_process->local_state(); const base::DictionaryValue* dict = @@ -482,7 +511,9 @@ bool KioskAppData::LoadFromCache() { icon_path_.clear(); std::string icon_path_string; if (!dict->GetString(name_key, &name_) || - !dict->GetString(icon_path_key, &icon_path_string)) { + !dict->GetString(icon_path_key, &icon_path_string) || + !dict->GetString(required_platform_version_key, + &required_platform_version_)) { return false; } icon_path_ = base::FilePath(icon_path_string); @@ -493,22 +524,31 @@ bool KioskAppData::LoadFromCache() { } void KioskAppData::SetCache(const std::string& name, - const base::FilePath& icon_path) { - std::string app_key = std::string(KioskAppManager::kKeyApps) + '.' + app_id_; - std::string name_key = app_key + '.' + kKeyName; - std::string icon_path_key = app_key + '.' + kKeyIcon; + const base::FilePath& icon_path, + const std::string& required_platform_version) { + name_ = name; + icon_path_ = icon_path; + required_platform_version_ = required_platform_version; + + const std::string app_key = + std::string(KioskAppManager::kKeyApps) + '.' + app_id_; + const std::string name_key = app_key + '.' + kKeyName; + const std::string icon_path_key = app_key + '.' + kKeyIcon; + const std::string required_platform_version_key = + app_key + '.' + kKeyRequiredPlatformVersion; PrefService* local_state = g_browser_process->local_state(); DictionaryPrefUpdate dict_update(local_state, KioskAppManager::kKioskDictionaryName); dict_update->SetString(name_key, name); dict_update->SetString(icon_path_key, icon_path.value()); - icon_path_ = icon_path; + dict_update->SetString(required_platform_version_key, + required_platform_version); } -void KioskAppData::SetCache(const std::string& name, const SkBitmap& icon) { - name_ = name; - +void KioskAppData::SetCache(const std::string& name, + const SkBitmap& icon, + const std::string& required_platform_version) { icon_ = gfx::ImageSkia::CreateFrom1xBitmap(icon); icon_.MakeThreadSafe(); @@ -527,16 +567,17 @@ void KioskAppData::SetCache(const std::string& name, const SkBitmap& icon) { FROM_HERE, base::Bind(&SaveIconToLocalOnBlockingPool, icon_path, raw_icon)); - SetCache(name, icon_path); + SetCache(name, icon_path, required_platform_version); } void KioskAppData::OnExtensionIconLoaded(const gfx::Image& icon) { if (icon.IsEmpty()) { LOG(WARNING) << "Failed to load icon from installed app" << ", id=" << app_id_; - SetCache(name_, *extensions::util::GetDefaultAppIcon().bitmap()); + SetCache(name_, *extensions::util::GetDefaultAppIcon().bitmap(), + required_platform_version_); } else { - SetCache(name_, icon.AsBitmap()); + SetCache(name_, icon.AsBitmap(), required_platform_version_); } SetStatus(STATUS_LOADED); @@ -553,8 +594,10 @@ void KioskAppData::OnIconLoadFailure() { StartFetch(); } -void KioskAppData::OnWebstoreParseSuccess(const SkBitmap& icon) { - SetCache(name_, icon); +void KioskAppData::OnWebstoreParseSuccess( + const SkBitmap& icon, + const std::string& required_platform_version) { + SetCache(name_, icon, required_platform_version); SetStatus(STATUS_LOADED); } @@ -655,7 +698,7 @@ void KioskAppData::OnCrxLoadFinished(const CrxLoader* crx_loader) { SkBitmap icon = crx_loader->icon(); if (icon.empty()) icon = *extensions::util::GetDefaultAppIcon().bitmap(); - SetCache(crx_loader->name(), icon); + SetCache(crx_loader->name(), icon, crx_loader->required_platform_version()); SetStatus(STATUS_LOADED); } diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_data.h b/chrome/browser/chromeos/app_mode/kiosk_app_data.h index 57509e6..c50fec8 100644 --- a/chrome/browser/chromeos/app_mode/kiosk_app_data.h +++ b/chrome/browser/chromeos/app_mode/kiosk_app_data.h @@ -77,8 +77,13 @@ class KioskAppData : public base::SupportsWeakPtr<KioskAppData>, const std::string& name() const { return name_; } const GURL& update_url() const { return update_url_; } const gfx::ImageSkia& icon() const { return icon_; } + const std::string& required_platform_version() const { + return required_platform_version_; + } Status status() const { return status_; } + void SetStatusForTest(Status status); + private: class CrxLoader; class IconLoader; @@ -93,10 +98,14 @@ class KioskAppData : public base::SupportsWeakPtr<KioskAppData>, bool LoadFromCache(); // Sets the cached data. - void SetCache(const std::string& name, const base::FilePath& icon_path); + void SetCache(const std::string& name, + const base::FilePath& icon_path, + const std::string& required_platform_version); // Helper to set the cached data using a SkBitmap icon. - void SetCache(const std::string& name, const SkBitmap& icon); + void SetCache(const std::string& name, + const SkBitmap& icon, + const std::string& required_platform_version); // Callback for extensions::ImageLoader. void OnExtensionIconLoaded(const gfx::Image& icon); @@ -106,7 +115,8 @@ class KioskAppData : public base::SupportsWeakPtr<KioskAppData>, void OnIconLoadFailure(); // Callbacks for WebstoreDataParser - void OnWebstoreParseSuccess(const SkBitmap& icon); + void OnWebstoreParseSuccess(const SkBitmap& icon, + const std::string& required_platform_version); void OnWebstoreParseFailure(); // Starts to fetch data from web store. @@ -139,6 +149,7 @@ class KioskAppData : public base::SupportsWeakPtr<KioskAppData>, std::string name_; GURL update_url_; gfx::ImageSkia icon_; + std::string required_platform_version_; scoped_ptr<extensions::WebstoreDataFetcher> webstore_fetcher_; base::FilePath icon_path_; diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc b/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc index f20e31c..84b3eb2 100644 --- a/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc +++ b/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc @@ -72,7 +72,7 @@ void ScheduleDelayedCryptohomeRemoval(const std::string& user_id, void CancelDelayedCryptohomeRemoval(const std::string& user_id) { PrefService* local_state = g_browser_process->local_state(); DictionaryPrefUpdate dict_update(local_state, kKioskUsersToRemove); - dict_update->RemoveWithoutPathExpansion(user_id, NULL); + dict_update->RemoveWithoutPathExpansion(user_id, nullptr); local_state->CommitPendingWrite(); } @@ -147,7 +147,7 @@ KioskAppManager* KioskAppManager::Get() { // static void KioskAppManager::Shutdown() { - if (instance == NULL) + if (instance == nullptr) return; instance.Pointer()->CleanUp(); @@ -167,17 +167,16 @@ void KioskAppManager::RemoveObsoleteCryptohomes() { base::Bind(&PerformDelayedCryptohomeRemovals)); } -KioskAppManager::App::App( - const KioskAppData& data, - bool is_extension_pending, - bool auto_launched_with_zero_delay) +KioskAppManager::App::App(const KioskAppData& data, + bool is_extension_pending, + bool auto_launched_with_zero_delay) : app_id(data.app_id()), user_id(data.user_id()), name(data.name()), icon(data.icon()), + required_platform_version(data.required_platform_version()), is_loading(data.IsLoading() || is_extension_pending), - was_auto_launched_with_zero_delay(auto_launched_with_zero_delay) { -} + was_auto_launched_with_zero_delay(auto_launched_with_zero_delay) {} KioskAppManager::App::App() : is_loading(false), was_auto_launched_with_zero_delay(false) {} @@ -345,6 +344,14 @@ bool KioskAppManager::IsAutoLaunchEnabled() const { return GetAutoLoginState() == AUTOLOGIN_APPROVED; } +std::string KioskAppManager::GetAutoLaunchAppRequiredPlatformVersion() const { + if (!IsAutoLaunchEnabled()) + return std::string(); + + const KioskAppData* data = GetAppData(GetAutoLaunchApp()); + return data == nullptr ? std::string() : data->required_platform_version(); +} + void KioskAppManager::AddApp(const std::string& app_id, OwnerSettingsServiceChromeOS* service) { std::vector<policy::DeviceLocalAccount> device_local_accounts = @@ -500,7 +507,7 @@ KioskAppManager::CreateSecondaryAppExternalLoader() { } void KioskAppManager::InstallFromCache(const std::string& id) { - const base::DictionaryValue* extension = NULL; + const base::DictionaryValue* extension = nullptr; if (external_cache_->cached_extensions()->GetDictionary(id, &extension)) { scoped_ptr<base::DictionaryValue> prefs(new base::DictionaryValue); base::DictionaryValue* extension_copy = extension->DeepCopy(); @@ -603,7 +610,7 @@ const KioskAppData* KioskAppManager::GetAppData( return data; } - return NULL; + return nullptr; } KioskAppData* KioskAppManager::GetAppDataMutable(const std::string& app_id) { diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_manager.h b/chrome/browser/chromeos/app_mode/kiosk_app_manager.h index ee80b49..85cb345 100644 --- a/chrome/browser/chromeos/app_mode/kiosk_app_manager.h +++ b/chrome/browser/chromeos/app_mode/kiosk_app_manager.h @@ -72,6 +72,7 @@ class KioskAppManager : public KioskAppDataDelegate, std::string user_id; std::string name; gfx::ImageSkia icon; + std::string required_platform_version; bool is_loading; bool was_auto_launched_with_zero_delay; }; @@ -136,6 +137,9 @@ class KioskAppManager : public KioskAppDataDelegate, // Enable auto launch setter. void SetEnableAutoLaunch(bool value); + // Returns the cached required platform version of the auto launch kiosk app. + std::string GetAutoLaunchAppRequiredPlatformVersion() const; + // Adds/removes a kiosk app by id. When removed, all locally cached data // will be removed as well. void AddApp(const std::string& app_id, OwnerSettingsServiceChromeOS* service); diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_manager_browsertest.cc b/chrome/browser/chromeos/app_mode/kiosk_app_manager_browsertest.cc index 545646b..418b0b7 100644 --- a/chrome/browser/chromeos/app_mode/kiosk_app_manager_browsertest.cc +++ b/chrome/browser/chromeos/app_mode/kiosk_app_manager_browsertest.cc @@ -5,18 +5,19 @@ #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" #include <stddef.h> +#include <utility> #include "base/command_line.h" #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/macros.h" #include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" #include "base/path_service.h" #include "base/strings/stringprintf.h" #include "base/values.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/app_mode/fake_cws.h" +#include "chrome/browser/chromeos/app_mode/kiosk_app_data.h" #include "chrome/browser/chromeos/app_mode/kiosk_app_manager_observer.h" #include "chrome/browser/chromeos/ownership/fake_owner_settings_service.h" #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" @@ -85,15 +86,21 @@ void OnEnterpriseDeviceLock( runner_quit_task.Run(); } -scoped_refptr<extensions::Extension> MakeApp(const std::string& name, - const std::string& version, - const std::string& url, - const std::string& id) { - std::string err; +scoped_refptr<extensions::Extension> MakeKioskApp( + const std::string& name, + const std::string& version, + const std::string& id, + const std::string& required_platform_version) { base::DictionaryValue value; value.SetString("name", name); value.SetString("version", version); - value.SetString("app.launch.web_url", url); + scoped_ptr<base::ListValue> scripts(new base::ListValue); + scripts->AppendString("main.js"); + value.Set("app.background.scripts", std::move(scripts)); + value.SetBoolean("kiosk_enabled", true); + value.SetString("kiosk.required_platform_version", required_platform_version); + + std::string err; scoped_refptr<extensions::Extension> app = extensions::Extension::Create( base::FilePath(), @@ -108,13 +115,8 @@ scoped_refptr<extensions::Extension> MakeApp(const std::string& name, class AppDataLoadWaiter : public KioskAppManagerObserver { public: - AppDataLoadWaiter(KioskAppManager* manager, int data_loaded_threshold) - : runner_(NULL), - manager_(manager), - loaded_(false), - quit_(false), - data_change_count_(0), - data_loaded_threshold_(data_loaded_threshold) { + AppDataLoadWaiter(KioskAppManager* manager, int expected_data_change) + : manager_(manager), expected_data_change_(expected_data_change) { manager_->AddObserver(this); } @@ -127,13 +129,20 @@ class AppDataLoadWaiter : public KioskAppManagerObserver { runner_->Run(); } + void Reset() { + quit_ = false; + data_change_count_ = 0; + data_load_failure_count_ = 0; + } + bool loaded() const { return loaded_; } + int data_load_failure_count() const { return data_load_failure_count_; } private: // KioskAppManagerObserver overrides: void OnKioskAppDataChanged(const std::string& app_id) override { ++data_change_count_; - if (data_change_count_ < data_loaded_threshold_) + if (data_change_count_ < expected_data_change_) return; loaded_ = true; quit_ = true; @@ -142,6 +151,7 @@ class AppDataLoadWaiter : public KioskAppManagerObserver { } void OnKioskAppDataLoadFailure(const std::string& app_id) override { + ++data_load_failure_count_; loaded_ = false; quit_ = true; if (runner_.get()) @@ -158,14 +168,45 @@ class AppDataLoadWaiter : public KioskAppManagerObserver { scoped_refptr<content::MessageLoopRunner> runner_; KioskAppManager* manager_; - bool loaded_; - bool quit_; - int data_change_count_; - int data_loaded_threshold_; + bool loaded_ = false; + bool quit_ = false; + int data_change_count_ = 0; + int expected_data_change_; + int data_load_failure_count_ = 0; DISALLOW_COPY_AND_ASSIGN(AppDataLoadWaiter); }; +// A class to wait for ExternalCache to finish putting the extension crx. +class ExternalCachePutWaiter { + public: + ExternalCachePutWaiter() {} + ~ExternalCachePutWaiter() {} + + void Wait() { + if (quit_) + return; + runner_ = new content::MessageLoopRunner; + runner_->Run(); + } + + void OnPutExtension(const std::string& id, bool success) { + success_ = success; + quit_ = true; + if (runner_.get()) + runner_->Quit(); + } + + bool success() const { return success_; } + + private: + scoped_refptr<content::MessageLoopRunner> runner_; + bool quit_ = false; + bool success_ = false; + + DISALLOW_COPY_AND_ASSIGN(ExternalCachePutWaiter); +}; + } // namespace class KioskAppManagerTest : public InProcessBrowserTest { @@ -250,19 +291,22 @@ class KioskAppManagerTest : public InProcessBrowserTest { void SetExistingApp(const std::string& app_id, const std::string& app_name, - const std::string& icon_file_name) { + const std::string& icon_file_name, + const std::string& required_platform_version) { base::FilePath test_dir; ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); base::FilePath data_dir = test_dir.AppendASCII("chromeos/app_mode/"); // Copy the icon file to temp dir for using because ClearAppData test // deletes it. - base::FilePath icon_path = temp_dir_.path().AppendASCII(icon_file_name); - base::CopyFile(data_dir.AppendASCII(icon_file_name), icon_path); + base::FilePath icon_path = + CopyFileToTempDir(data_dir.AppendASCII(icon_file_name)); scoped_ptr<base::DictionaryValue> apps_dict(new base::DictionaryValue); apps_dict->SetString(app_id + ".name", app_name); apps_dict->SetString(app_id + ".icon", icon_path.MaybeAsASCII()); + apps_dict->SetString(app_id + ".required_platform_version", + required_platform_version); PrefService* local_state = g_browser_process->local_state(); DictionaryPrefUpdate dict_update(local_state, @@ -272,16 +316,18 @@ class KioskAppManagerTest : public InProcessBrowserTest { // Make the app appear in device settings. base::ListValue device_local_accounts; scoped_ptr<base::DictionaryValue> entry(new base::DictionaryValue); - entry->SetStringWithoutPathExpansion( - kAccountsPrefDeviceLocalAccountsKeyId, - app_id + "_id"); + // Fake an account id. Note this needs to match GenerateKioskAppAccountId + // in kiosk_app_manager.cc to make SetAutoLaunchApp work with the + // existing app entry created here. + entry->SetStringWithoutPathExpansion(kAccountsPrefDeviceLocalAccountsKeyId, + app_id + "@kiosk-apps"); entry->SetIntegerWithoutPathExpansion( kAccountsPrefDeviceLocalAccountsKeyType, policy::DeviceLocalAccount::TYPE_KIOSK_APP); entry->SetStringWithoutPathExpansion( kAccountsPrefDeviceLocalAccountsKeyKioskAppId, app_id); - device_local_accounts.Append(entry.release()); + device_local_accounts.Append(std::move(entry)); owner_settings_service_->Set(kAccountsPrefDeviceLocalAccounts, device_local_accounts); } @@ -294,11 +340,62 @@ class KioskAppManagerTest : public InProcessBrowserTest { void UpdateAppData() { manager()->UpdateAppData(); } + void CheckAppData(const std::string& app_id, + const std::string& expected_app_name, + const std::string& expected_required_platform_version) { + // Check manifest data is cached correctly. + KioskAppManager::Apps apps; + manager()->GetApps(&apps); + ASSERT_EQ(1u, apps.size()); + EXPECT_EQ(app_id, apps[0].app_id); + EXPECT_EQ(expected_app_name, apps[0].name); + EXPECT_FALSE(apps[0].icon.size().IsEmpty()); + EXPECT_EQ(expected_required_platform_version, + apps[0].required_platform_version); + } + + void CheckAppDataAndCache( + const std::string& app_id, + const std::string& expected_app_name, + const std::string& expected_required_platform_version) { + CheckAppData(app_id, expected_app_name, expected_required_platform_version); + + // Check data is cached in local state correctly. + PrefService* local_state = g_browser_process->local_state(); + const base::DictionaryValue* dict = + local_state->GetDictionary(KioskAppManager::kKioskDictionaryName); + + std::string name; + const std::string name_key = "apps." + app_id + ".name"; + EXPECT_TRUE(dict->GetString(name_key, &name)); + EXPECT_EQ(expected_app_name, name); + + std::string icon_path_string; + const std::string icon_path_key = "apps." + app_id + ".icon"; + EXPECT_TRUE(dict->GetString(icon_path_key, &icon_path_string)); + + std::string required_platform_version; + const std::string required_platform_version_key = + "apps." + app_id + ".required_platform_version"; + EXPECT_TRUE(dict->GetString(required_platform_version_key, + &required_platform_version)); + EXPECT_EQ(expected_required_platform_version, required_platform_version); + + base::FilePath expected_icon_path; + ASSERT_TRUE(PathService::Get(chrome::DIR_USER_DATA, &expected_icon_path)); + expected_icon_path = + expected_icon_path.AppendASCII(KioskAppManager::kIconCacheDir) + .AppendASCII(app_id) + .AddExtension(".png"); + EXPECT_EQ(expected_icon_path.value(), icon_path_string); + } + void RunAddNewAppTest(const std::string& id, - const std::string& version, - const std::string& app_name) { + const std::string& expected_version, + const std::string& expected_app_name, + const std::string& expected_required_platform_version) { std::string crx_file_name = id + ".crx"; - fake_cws_->SetUpdateCrx(id, crx_file_name, version); + fake_cws_->SetUpdateCrx(id, crx_file_name, expected_version); AppDataLoadWaiter waiter(manager(), 3); manager()->AddApp(id, owner_settings_service_.get()); @@ -310,7 +407,7 @@ class KioskAppManagerTest : public InProcessBrowserTest { std::string crx_version; EXPECT_TRUE(GetCachedCrx(id, &crx_path, &crx_version)); EXPECT_TRUE(base::PathExists(crx_path)); - EXPECT_EQ(version, crx_version); + EXPECT_EQ(expected_version, crx_version); // Verify the original crx file is identical to the cached file. base::FilePath test_data_dir; PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir); @@ -320,35 +417,20 @@ class KioskAppManagerTest : public InProcessBrowserTest { EXPECT_TRUE(base::PathExists(src_file_path)); EXPECT_TRUE(base::ContentsEqual(src_file_path, crx_path)); - // Check manifest data is cached correctly. - KioskAppManager::Apps apps; - manager()->GetApps(&apps); - ASSERT_EQ(1u, apps.size()); - EXPECT_EQ(id, apps[0].app_id); - EXPECT_EQ(app_name, apps[0].name); - EXPECT_EQ(gfx::Size(16, 16), apps[0].icon.size()); - - // Check data is cached in local state. - PrefService* local_state = g_browser_process->local_state(); - const base::DictionaryValue* dict = - local_state->GetDictionary(KioskAppManager::kKioskDictionaryName); - - std::string name; - std::string name_key = "apps." + id + ".name"; - EXPECT_TRUE(dict->GetString(name_key, &name)); - EXPECT_EQ(apps[0].name, name); + CheckAppDataAndCache(id, expected_app_name, + expected_required_platform_version); + } - std::string icon_path_string; - std::string icon_path_key = "apps." + id + ".icon"; - EXPECT_TRUE(dict->GetString(icon_path_key, &icon_path_string)); + // Copies the given file into temp dir and returns the full path + // of the copied file. + base::FilePath CopyFileToTempDir(const base::FilePath& file) { + base::FilePath target_file = temp_dir_.path().Append(file.BaseName()); + CHECK(base::CopyFile(file, target_file)); + return target_file; + } - base::FilePath expected_icon_path; - ASSERT_TRUE(PathService::Get(chrome::DIR_USER_DATA, &expected_icon_path)); - expected_icon_path = - expected_icon_path.AppendASCII(KioskAppManager::kIconCacheDir) - .AppendASCII(apps[0].app_id) - .AddExtension(".png"); - EXPECT_EQ(expected_icon_path.value(), icon_path_string); + KioskAppData* GetAppDataMutable(const std::string& app_id) { + return manager()->GetAppDataMutable(app_id); } KioskAppManager* manager() const { return KioskAppManager::Get(); } @@ -429,23 +511,18 @@ IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, Basic) { } IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, LoadCached) { - SetExistingApp("app_1", "Cached App1 Name", "red16x16.png"); + SetExistingApp("app_1", "Cached App1 Name", "red16x16.png", "1234"); fake_cws()->SetNoUpdate("app_1"); AppDataLoadWaiter waiter(manager(), 1); waiter.Wait(); EXPECT_TRUE(waiter.loaded()); - KioskAppManager::Apps apps; - manager()->GetApps(&apps); - EXPECT_EQ(1u, apps.size()); - EXPECT_EQ("app_1", apps[0].app_id); - EXPECT_EQ("Cached App1 Name", apps[0].name); - EXPECT_EQ(gfx::Size(16, 16), apps[0].icon.size()); + CheckAppData("app_1", "Cached App1 Name", "1234"); } IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, ClearAppData) { - SetExistingApp("app_1", "Cached App1 Name", "red16x16.png"); + SetExistingApp("app_1", "Cached App1 Name", "red16x16.png", ""); PrefService* local_state = g_browser_process->local_state(); const base::DictionaryValue* dict = @@ -460,31 +537,73 @@ IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, ClearAppData) { } IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, UpdateAppDataFromProfile) { - SetExistingApp("app_1", "Cached App1 Name", "red16x16.png"); + SetExistingApp("app_1", "Cached App1 Name", "red16x16.png", ""); fake_cws()->SetNoUpdate("app_1"); AppDataLoadWaiter waiter(manager(), 1); waiter.Wait(); EXPECT_TRUE(waiter.loaded()); - KioskAppManager::Apps apps; - manager()->GetApps(&apps); - EXPECT_EQ(1u, apps.size()); - EXPECT_EQ("app_1", apps[0].app_id); - EXPECT_EQ("Cached App1 Name", apps[0].name); + CheckAppData("app_1", "Cached App1 Name", ""); scoped_refptr<extensions::Extension> updated_app = - MakeApp("Updated App1 Name", "2.0", "http://localhost/", "app_1"); + MakeKioskApp("Updated App1 Name", "2.0", "app_1", "1234"); manager()->UpdateAppDataFromProfile( "app_1", browser()->profile(), updated_app.get()); + waiter.Reset(); waiter.Wait(); EXPECT_TRUE(waiter.loaded()); - manager()->GetApps(&apps); - EXPECT_EQ(1u, apps.size()); - EXPECT_EQ("app_1", apps[0].app_id); - EXPECT_EQ("Updated App1 Name", apps[0].name); + CheckAppData("app_1", "Updated App1 Name", "1234"); +} + +IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, UpdateAppDataFromCrx) { + const char kAppId[] = "ajoggoflpgplnnjkjamcmbepjdjdnpdp"; + const char kAppName[] = "Test Kiosk App"; + + SetExistingApp(kAppId, kAppName, "red16x16.png", ""); + fake_cws()->SetNoUpdate(kAppId); + AppDataLoadWaiter waiter(manager(), 1); + waiter.Wait(); + EXPECT_TRUE(waiter.loaded()); + + CheckAppData(kAppId, kAppName, ""); + + // Fake app data load failure so that the manager will attempt to + // load it from crx. + KioskAppData* app_data = GetAppDataMutable(kAppId); + app_data->SetStatusForTest(KioskAppData::STATUS_ERROR); + + // Copy test crx file to temp dir because the cache moves the file. + base::FilePath test_dir; + ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); + base::FilePath data_dir = + test_dir.AppendASCII("chromeos/app_mode/offline_enabled_kiosk_app"); + base::FilePath crx_file = + data_dir.AppendASCII("v2_required_platform_version_added.crx"); + crx_file = CopyFileToTempDir(crx_file); + + ExternalCachePutWaiter put_waiter; + manager()->PutValidatedExternalExtension( + kAppId, crx_file, "2.0.0", + base::Bind(&ExternalCachePutWaiter::OnPutExtension, + base::Unretained(&put_waiter))); + put_waiter.Wait(); + ASSERT_TRUE(put_waiter.success()); + + // Wait for 3 data loaded events at the most. One for crx putting into cache, + // one for update check and one for app data is updated from crx. + const size_t kMaxDataChange = 3; + for (size_t i = 0; + i < kMaxDataChange && app_data->status() != KioskAppData::STATUS_LOADED; + ++i) { + waiter.Reset(); + waiter.Wait(); + } + ASSERT_EQ(KioskAppData::STATUS_LOADED, app_data->status()); + + CheckAppData(kAppId, kAppName, "1234"); } IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, BadApp) { @@ -498,47 +617,52 @@ IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, BadApp) { IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, GoodApp) { // Webstore data json is in // chrome/test/data/chromeos/app_mode/webstore/inlineinstall/detail/app_1 - fake_cws()->SetNoUpdate("app_1"); + const char kAppId[] = "app_1"; + fake_cws()->SetNoUpdate(kAppId); AppDataLoadWaiter waiter(manager(), 2); - manager()->AddApp("app_1", owner_settings_service_.get()); + manager()->AddApp(kAppId, owner_settings_service_.get()); waiter.Wait(); EXPECT_TRUE(waiter.loaded()); - // Check data is correct. - KioskAppManager::Apps apps; - manager()->GetApps(&apps); - ASSERT_EQ(1u, apps.size()); - EXPECT_EQ("app_1", apps[0].app_id); - EXPECT_EQ("Name of App 1", apps[0].name); - EXPECT_EQ(gfx::Size(16, 16), apps[0].icon.size()); + CheckAppDataAndCache(kAppId, "Name of App 1", ""); +} - // Check data is cached in local state. - PrefService* local_state = g_browser_process->local_state(); - const base::DictionaryValue* dict = - local_state->GetDictionary(KioskAppManager::kKioskDictionaryName); +IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, AppWithRequiredPlatformVersion) { + // Webstore data json is in + // chrome/test/data/chromeos/app_mode/webstore/inlineinstall/detail/ + // app_with_required_platform_version + const char kAppId[] = "app_with_required_platform_version"; + fake_cws()->SetNoUpdate(kAppId); + AppDataLoadWaiter waiter(manager(), 2); + manager()->AddApp(kAppId, owner_settings_service_.get()); + waiter.Wait(); + EXPECT_TRUE(waiter.loaded()); - std::string name; - EXPECT_TRUE(dict->GetString("apps.app_1.name", &name)); - EXPECT_EQ(apps[0].name, name); + CheckAppDataAndCache(kAppId, "App with required platform version", "1234"); +} - std::string icon_path_string; - EXPECT_TRUE(dict->GetString("apps.app_1.icon", &icon_path_string)); +IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, AppWithBadRequiredPlatformVersion) { + // Webstore data json is in + // chrome/test/data/chromeos/app_mode/webstore/inlineinstall/detail/ + // app_with_bad_required_platform_version + const char kAppId[] = "app_with_bad_required_platform_version"; + fake_cws()->SetNoUpdate(kAppId); + AppDataLoadWaiter waiter(manager(), 2); + manager()->AddApp(kAppId, owner_settings_service_.get()); + waiter.Wait(); + EXPECT_FALSE(waiter.loaded()); + EXPECT_EQ(1, waiter.data_load_failure_count()); - base::FilePath expected_icon_path; - ASSERT_TRUE(PathService::Get(chrome::DIR_USER_DATA, &expected_icon_path)); - expected_icon_path = expected_icon_path. - AppendASCII(KioskAppManager::kIconCacheDir). - AppendASCII(apps[0].app_id).AddExtension(".png"); - EXPECT_EQ(expected_icon_path.value(), icon_path_string); + EXPECT_EQ("", GetAppIds()); } IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, DownloadNewApp) { - RunAddNewAppTest(kTestLocalFsKioskApp, "1.0.0", kTestLocalFsKioskAppName); + RunAddNewAppTest(kTestLocalFsKioskApp, "1.0.0", kTestLocalFsKioskAppName, ""); } IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, RemoveApp) { // Add a new app. - RunAddNewAppTest(kTestLocalFsKioskApp, "1.0.0", kTestLocalFsKioskAppName); + RunAddNewAppTest(kTestLocalFsKioskApp, "1.0.0", kTestLocalFsKioskAppName, ""); KioskAppManager::Apps apps; manager()->GetApps(&apps); ASSERT_EQ(1u, apps.size()); @@ -559,7 +683,7 @@ IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, RemoveApp) { IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, UpdateApp) { // Add a version 1 app first. - RunAddNewAppTest(kTestLocalFsKioskApp, "1.0.0", kTestLocalFsKioskAppName); + RunAddNewAppTest(kTestLocalFsKioskApp, "1.0.0", kTestLocalFsKioskAppName, ""); KioskAppManager::Apps apps; manager()->GetApps(&apps); ASSERT_EQ(1u, apps.size()); @@ -599,7 +723,7 @@ IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, UpdateApp) { IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, UpdateAndRemoveApp) { // Add a version 1 app first. - RunAddNewAppTest(kTestLocalFsKioskApp, "1.0.0", kTestLocalFsKioskAppName); + RunAddNewAppTest(kTestLocalFsKioskApp, "1.0.0", kTestLocalFsKioskAppName, ""); KioskAppManager::Apps apps; manager()->GetApps(&apps); ASSERT_EQ(1u, apps.size()); @@ -718,4 +842,27 @@ IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, KioskAppManager::CONSUMER_KIOSK_AUTO_LAUNCH_DISABLED); } +IN_PROC_BROWSER_TEST_F(KioskAppManagerTest, + GetAutoLaunchAppRequiredPlatformVersion) { + const char kAppId[] = "app_with_required_platform_version"; + const char kRequiredPlatformVersion[] = "1234"; + SetExistingApp(kAppId, "App Name", "red16x16.png", kRequiredPlatformVersion); + + fake_cws()->SetNoUpdate(kAppId); + AppDataLoadWaiter waiter(manager(), 1); + waiter.Wait(); + EXPECT_TRUE(waiter.loaded()); + + EXPECT_FALSE(manager()->IsAutoLaunchEnabled()); + EXPECT_EQ("", manager()->GetAutoLaunchAppRequiredPlatformVersion()); + + manager()->SetAutoLaunchApp(kAppId, owner_settings_service_.get()); + EXPECT_EQ("", manager()->GetAutoLaunchAppRequiredPlatformVersion()); + + manager()->SetEnableAutoLaunch(true); + EXPECT_TRUE(manager()->IsAutoLaunchEnabled()); + EXPECT_EQ(kRequiredPlatformVersion, + manager()->GetAutoLaunchAppRequiredPlatformVersion()); +} + } // namespace chromeos diff --git a/chrome/test/data/chromeos/app_mode/offline_enabled_kiosk_app/v2_required_platform_version_added.crx b/chrome/test/data/chromeos/app_mode/offline_enabled_kiosk_app/v2_required_platform_version_added.crx Binary files differnew file mode 100644 index 0000000..d4e8674 --- /dev/null +++ b/chrome/test/data/chromeos/app_mode/offline_enabled_kiosk_app/v2_required_platform_version_added.crx diff --git a/chrome/test/data/chromeos/app_mode/offline_enabled_kiosk_app/v2_required_platform_version_added/app_main.html b/chrome/test/data/chromeos/app_mode/offline_enabled_kiosk_app/v2_required_platform_version_added/app_main.html new file mode 100644 index 0000000..e0aa0f6 --- /dev/null +++ b/chrome/test/data/chromeos/app_mode/offline_enabled_kiosk_app/v2_required_platform_version_added/app_main.html @@ -0,0 +1,6 @@ +<html> +<script src="app_main.js"></script> +<body> +<h1>Test Kiosk App!!!</h1> +</body> +<hmtl> diff --git a/chrome/test/data/chromeos/app_mode/offline_enabled_kiosk_app/v2_required_platform_version_added/app_main.js b/chrome/test/data/chromeos/app_mode/offline_enabled_kiosk_app/v2_required_platform_version_added/app_main.js new file mode 100644 index 0000000..6201556 --- /dev/null +++ b/chrome/test/data/chromeos/app_mode/offline_enabled_kiosk_app/v2_required_platform_version_added/app_main.js @@ -0,0 +1,8 @@ +// Copyright (c) 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. + +window.addEventListener('load', function onload() { + window.close(); +}); + diff --git a/chrome/test/data/chromeos/app_mode/offline_enabled_kiosk_app/v2_required_platform_version_added/icon-128.png b/chrome/test/data/chromeos/app_mode/offline_enabled_kiosk_app/v2_required_platform_version_added/icon-128.png Binary files differnew file mode 100644 index 0000000..5c226f3 --- /dev/null +++ b/chrome/test/data/chromeos/app_mode/offline_enabled_kiosk_app/v2_required_platform_version_added/icon-128.png diff --git a/chrome/test/data/chromeos/app_mode/offline_enabled_kiosk_app/v2_required_platform_version_added/icon-16.png b/chrome/test/data/chromeos/app_mode/offline_enabled_kiosk_app/v2_required_platform_version_added/icon-16.png Binary files differnew file mode 100644 index 0000000..c7510d38 --- /dev/null +++ b/chrome/test/data/chromeos/app_mode/offline_enabled_kiosk_app/v2_required_platform_version_added/icon-16.png diff --git a/chrome/test/data/chromeos/app_mode/offline_enabled_kiosk_app/v2_required_platform_version_added/main.js b/chrome/test/data/chromeos/app_mode/offline_enabled_kiosk_app/v2_required_platform_version_added/main.js new file mode 100644 index 0000000..842ca23 --- /dev/null +++ b/chrome/test/data/chromeos/app_mode/offline_enabled_kiosk_app/v2_required_platform_version_added/main.js @@ -0,0 +1,12 @@ +// Copyright (c) 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. + +chrome.app.runtime.onLaunched.addListener(function(launchData) { + if (launchData.isKioskSession) + chrome.test.sendMessage('launchData.isKioskSession = true'); + + chrome.app.window.create('app_main.html', + { 'width': 1920, + 'height': 1080 }); +}); diff --git a/chrome/test/data/chromeos/app_mode/offline_enabled_kiosk_app/v2_required_platform_version_added/manifest.json b/chrome/test/data/chromeos/app_mode/offline_enabled_kiosk_app/v2_required_platform_version_added/manifest.json new file mode 100644 index 0000000..4a9789a --- /dev/null +++ b/chrome/test/data/chromeos/app_mode/offline_enabled_kiosk_app/v2_required_platform_version_added/manifest.json @@ -0,0 +1,20 @@ +{ + "manifest_version": 2, + "name": "Test Kiosk App", + "minimum_chrome_version": "24.0.1307.0", + "version": "2.0.0", + "icons": { + "128": "icon-128.png", + "16": "icon-16.png" + }, + "app": { + "background": { + "scripts": ["main.js"] + } + }, + "kiosk_enabled": true, + "kiosk": { + "required_platform_version": "1234" + }, + "offline_enabled": true +} diff --git a/chrome/test/data/chromeos/app_mode/webstore/inlineinstall/detail/app_with_bad_required_platform_version b/chrome/test/data/chromeos/app_mode/webstore/inlineinstall/detail/app_with_bad_required_platform_version new file mode 100644 index 0000000..0af85ac --- /dev/null +++ b/chrome/test/data/chromeos/app_mode/webstore/inlineinstall/detail/app_with_bad_required_platform_version @@ -0,0 +1,10 @@ +{ + "id": "app_with_bad_required_platform_version", + "users": "1234", + "average_rating": 1.0, + "rating_count": 999, + "verified_site": "chrome.google.com", + "localized_name": "App with bad required platform version", + "localized_description": "Description of app with bad required_platform_version", + "icon_url": "webstore/inlineinstall/detail/app_1_green16x16.png", "manifest":"{\n \"name\": \"__MSG_appName__\",\n \"version\": \"1\",\n \"manifest_version\": 2,\n \"description\": \"__MSG_appDesc__\",\n \"default_locale\": \"en\",\n \"app\": {\n \"background\": {\n \"scripts\": [\"background.js\"]\n },\n \"launch\": {\n \"local_path\": \"index.html\"\n }\n },\n \"icons\": {\n \"16\": \"favicon.png\",\n \"128\": \"128.png\"\n },\n \"kiosk_enabled\": true,\n \"kiosk\": {\"required_platform_version\": \"bad\"},\n \"permissions\": [] }" +} diff --git a/chrome/test/data/chromeos/app_mode/webstore/inlineinstall/detail/app_with_required_platform_version b/chrome/test/data/chromeos/app_mode/webstore/inlineinstall/detail/app_with_required_platform_version new file mode 100644 index 0000000..e76a63470d --- /dev/null +++ b/chrome/test/data/chromeos/app_mode/webstore/inlineinstall/detail/app_with_required_platform_version @@ -0,0 +1,11 @@ +{ + "id": "app_with_required_platform_version", + "users": "1234", + "average_rating": 1.0, + "rating_count": 999, + "verified_site": "chrome.google.com", + "localized_name": "App with required platform version", + "localized_description": "Description of app with required_platform_version", + "icon_url": "webstore/inlineinstall/detail/app_1_green16x16.png", + "manifest":"{\n \"name\": \"__MSG_appName__\",\n \"version\": \"1\",\n \"manifest_version\": 2,\n \"description\": \"__MSG_appDesc__\",\n \"default_locale\": \"en\",\n \"app\": {\n \"background\": {\n \"scripts\": [\"background.js\"]\n },\n \"launch\": {\n \"local_path\": \"index.html\"\n }\n },\n \"icons\": {\n \"16\": \"favicon.png\",\n \"128\": \"128.png\"\n },\n \"kiosk_enabled\": true,\n \"kiosk\": {\"required_platform_version\": \"1234\"},\n \"permissions\": [] }" +} diff --git a/extensions/common/manifest_handlers/kiosk_mode_info.cc b/extensions/common/manifest_handlers/kiosk_mode_info.cc index 5ab5656..d625bfd 100644 --- a/extensions/common/manifest_handlers/kiosk_mode_info.cc +++ b/extensions/common/manifest_handlers/kiosk_mode_info.cc @@ -13,17 +13,6 @@ #include "extensions/common/api/extensions_manifest_types.h" #include "extensions/common/manifest_constants.h" -namespace { - -// Whether the given |version_string| is a valid ChromeOS platform version. -// The acceptable format is major[.minor[.micro]]. -bool IsValidPlatformVersion(const std::string& version_string) { - const base::Version version(version_string); - return version.IsValid() && version.components().size() <= 3u; -} - -} // namespace - namespace extensions { namespace keys = manifest_keys; @@ -64,6 +53,12 @@ bool KioskModeInfo::HasSecondaryApps(const Extension* extension) { return info && !info->secondary_app_ids.empty(); } +// static +bool KioskModeInfo::IsValidPlatformVersion(const std::string& version_string) { + const base::Version version(version_string); + return version.IsValid() && version.components().size() <= 3u; +} + KioskModeHandler::KioskModeHandler() { supported_keys_.push_back(keys::kKiosk); supported_keys_.push_back(keys::kKioskEnabled); @@ -135,7 +130,7 @@ bool KioskModeHandler::Parse(Extension* extension, base::string16* error) { if (manifest->HasPath(keys::kKioskRequiredPlatformVersion) && (!manifest->GetString(keys::kKioskRequiredPlatformVersion, &required_platform_version) || - !IsValidPlatformVersion(required_platform_version))) { + !KioskModeInfo::IsValidPlatformVersion(required_platform_version))) { *error = base::ASCIIToUTF16( manifest_errors::kInvalidKioskRequiredPlatformVersion); return false; diff --git a/extensions/common/manifest_handlers/kiosk_mode_info.h b/extensions/common/manifest_handlers/kiosk_mode_info.h index 514e78e..bd37f96 100644 --- a/extensions/common/manifest_handlers/kiosk_mode_info.h +++ b/extensions/common/manifest_handlers/kiosk_mode_info.h @@ -41,6 +41,10 @@ struct KioskModeInfo : public Extension::ManifestData { // Returns true if |extension| declares kiosk secondary apps. static bool HasSecondaryApps(const Extension* extension); + // Whether the given |version_string| is a valid ChromeOS platform version. + // The acceptable format is major[.minor[.micro]]. + static bool IsValidPlatformVersion(const std::string& version_string); + KioskStatus kiosk_status; // The IDs of the kiosk secondary apps. |