diff options
author | dimich@chromium.org <dimich@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-28 21:58:53 +0000 |
---|---|---|
committer | dimich@chromium.org <dimich@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-28 21:58:53 +0000 |
commit | 0d784792f432a058824d332d3cd7f4f2617f2092 (patch) | |
tree | 0af48586dfa3bf9eeccb8baac06b6d53722bb4f5 /chrome/browser/background | |
parent | 0f79893bfd2a3c5bcc20bd32ad9b509f0e157115 (diff) | |
download | chromium_src-0d784792f432a058824d332d3cd7f4f2617f2092.zip chromium_src-0d784792f432a058824d332d3cd7f4f2617f2092.tar.gz chromium_src-0d784792f432a058824d332d3cd7f4f2617f2092.tar.bz2 |
Enable apps that use Push Messaging to not request background mode.
The use case: the app is using Push Messaging for not real-time event that happens rarely. There is no great reason to keep Chrome running just for that.
Implemented as a whitelist for now since we believe this is a temporary solution. A better solution, which would allow push to work all the time but not keep Chrome running can take longer time. See bug for more info.
BUG=311268
Review URL: https://codereview.chromium.org/45863002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@231419 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/background')
3 files changed, 158 insertions, 14 deletions
diff --git a/chrome/browser/background/background_application_list_model.cc b/chrome/browser/background/background_application_list_model.cc index 1661b39..11c4406 100644 --- a/chrome/browser/background/background_application_list_model.cc +++ b/chrome/browser/background/background_application_list_model.cc @@ -7,7 +7,9 @@ #include <algorithm> #include <set> +#include "base/sha1.h" #include "base/stl_util.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "chrome/app/chrome_command_ids.h" #include "chrome/browser/background/background_contents_service.h" @@ -267,6 +269,28 @@ int BackgroundApplicationListModel::GetPosition( } // static +bool BackgroundApplicationListModel::RequiresBackgroundModeForPushMessaging( + const Extension& extension) { + // No PushMessaging permission - does not require the background mode. + if (!extension.HasAPIPermission(APIPermission::kPushMessaging)) + return false; + + // If in the whitelist, then does not require background mode even if + // uses push messaging. + // TODO(dimich): remove this whitelist once we have a better way to keep + // listening for GCM. http://crbug.com/311268 + std::string id_hash = base::SHA1HashString(extension.id()); + std::string hexencoded_id_hash = base::HexEncode(id_hash.c_str(), + id_hash.length()); + // The id starting from "9A04..." is a one from unit test. + if (hexencoded_id_hash == "C41AD9DCD670210295614257EF8C9945AD68D86E" || + hexencoded_id_hash == "9A0417016F345C934A1A88F55CA17C05014EEEBA") + return false; + + return true; + } + +// static bool BackgroundApplicationListModel::IsBackgroundApp( const Extension& extension, Profile* profile) { // An extension is a "background app" if it has the "background API" @@ -278,7 +302,7 @@ bool BackgroundApplicationListModel::IsBackgroundApp( // Not a background app if we don't have the background permission or // the push messaging permission if (!extension.HasAPIPermission(APIPermission::kBackground) && - !extension.HasAPIPermission(APIPermission::kPushMessaging) ) + !RequiresBackgroundModeForPushMessaging(extension)) return false; // Extensions and packaged apps with background permission are always treated diff --git a/chrome/browser/background/background_application_list_model.h b/chrome/browser/background/background_application_list_model.h index e9be88a..1bc7d2d 100644 --- a/chrome/browser/background/background_application_list_model.h +++ b/chrome/browser/background/background_application_list_model.h @@ -139,6 +139,13 @@ class BackgroundApplicationListModel : public content::NotificationObserver { // Refresh the list of background applications and generate notifications. void Update(); + // Determines if the given extension has to be considered a "background app" + // due to its use of PushMessaging. Normally every extension that expectes + // push messages is classified as "background app", however there are some + // rare exceptions, so this function implements a whitelist. + static bool RequiresBackgroundModeForPushMessaging( + const extensions::Extension& extension); + ApplicationMap applications_; extensions::ExtensionList extensions_; ObserverList<Observer> observers_; diff --git a/chrome/browser/background/background_application_list_model_unittest.cc b/chrome/browser/background/background_application_list_model_unittest.cc index 0c35c59..62aa6c2 100644 --- a/chrome/browser/background/background_application_list_model_unittest.cc +++ b/chrome/browser/background/background_application_list_model_unittest.cc @@ -35,8 +35,9 @@ using extensions::APIPermission; using extensions::Extension; // For ExtensionService interface when it requires a path that is not used. -base::FilePath bogus_file_path() { - return base::FilePath(FILE_PATH_LITERAL("//foobar_nonexistent")); +base::FilePath bogus_file_pathname(const std::string& name) { + return base::FilePath(FILE_PATH_LITERAL("//foobar_nonexistent")) + .AppendASCII(name); } class BackgroundApplicationListModelTest : public ExtensionServiceTestBase { @@ -56,32 +57,69 @@ class BackgroundApplicationListModelTest : public ExtensionServiceTestBase { } }; +enum PushMessagingOption { + NO_PUSH_MESSAGING, + PUSH_MESSAGING_PERMISSION, + PUSH_MESSAGING_BUT_NOT_BACKGROUND +}; + // Returns a barebones test Extension object with the specified |name|. The // returned extension will include background permission iff -// |background_permission| is true. -static scoped_refptr<Extension> CreateExtension(const std::string& name, - bool background_permission) { +// |background_permission| is true and pushMessaging permission if requested +// by |push_messaging| value. Also the extension may have a specific id set +// to test the case when it has a pushMessaging permission but is not +// considered a background app based on a whitelist. +static scoped_refptr<Extension> CreateExtensionBase( + const std::string& name, + bool background_permission, + PushMessagingOption push_messaging) { DictionaryValue manifest; manifest.SetString(extensions::manifest_keys::kVersion, "1.0.0.0"); manifest.SetString(extensions::manifest_keys::kName, name); + ListValue* permissions = new ListValue(); + manifest.Set(extensions::manifest_keys::kPermissions, permissions); if (background_permission) { - ListValue* permissions = new ListValue(); - manifest.Set(extensions::manifest_keys::kPermissions, permissions); permissions->Append(Value::CreateStringValue("background")); } + if (push_messaging == PUSH_MESSAGING_PERMISSION || + push_messaging == PUSH_MESSAGING_BUT_NOT_BACKGROUND) { + permissions->Append(Value::CreateStringValue("pushMessaging")); + } + std::string error; - scoped_refptr<Extension> extension = Extension::Create( - bogus_file_path().AppendASCII(name), - extensions::Manifest::INVALID_LOCATION, - manifest, - Extension::NO_FLAGS, - &error); + scoped_refptr<Extension> extension; + + // There is a whitelist for extensions that have pushMessaging permission but + // are not considered a background app. Create a test extension with a known + // test id if needed. + if (push_messaging == PUSH_MESSAGING_BUT_NOT_BACKGROUND) { + extension = Extension::Create( + bogus_file_pathname(name), + extensions::Manifest::INVALID_LOCATION, + manifest, + Extension::NO_FLAGS, + "aaaabbbbccccddddeeeeffffgggghhhh", + &error); + } else { + extension = Extension::Create( + bogus_file_pathname(name), + extensions::Manifest::INVALID_LOCATION, + manifest, + Extension::NO_FLAGS, + &error); + } + // Cannot ASSERT_* here because that attempts an illegitimate return. // Cannot EXPECT_NE here because that assumes non-pointers unlike EXPECT_EQ EXPECT_TRUE(extension.get() != NULL) << error; return extension; } +static scoped_refptr<Extension> CreateExtension(const std::string& name, + bool background_permission) { + return CreateExtensionBase(name, background_permission, NO_PUSH_MESSAGING); +} + namespace { std::string GenerateUniqueExtensionName() { static int uniqueness = 0; @@ -192,6 +230,81 @@ TEST_F(BackgroundApplicationListModelTest, MAYBE_ExplicitTest) { ASSERT_EQ(0U, model->size()); } +// Verifies that pushMessaging also triggers background detection, except +// when extension is in a whitelist. +TEST_F(BackgroundApplicationListModelTest, PushMessagingTest) { + InitializeAndLoadEmptyExtensionService(); + ExtensionService* service = extensions::ExtensionSystem::Get(profile_.get())-> + extension_service(); + ASSERT_TRUE(service); + ASSERT_TRUE(service->is_ready()); + ASSERT_TRUE(service->extensions()); + ASSERT_TRUE(service->extensions()->is_empty()); + scoped_ptr<BackgroundApplicationListModel> model( + new BackgroundApplicationListModel(profile_.get())); + ASSERT_EQ(0U, model->size()); + + scoped_refptr<Extension> ext1 = CreateExtension("alpha", false); + scoped_refptr<Extension> ext2 = + CreateExtensionBase("charlie", false, PUSH_MESSAGING_BUT_NOT_BACKGROUND); + scoped_refptr<Extension> bgapp1 = + CreateExtensionBase("bravo", false, PUSH_MESSAGING_PERMISSION); + scoped_refptr<Extension> bgapp2 = + CreateExtensionBase("delta", true, PUSH_MESSAGING_PERMISSION); + scoped_refptr<Extension> bgapp3 = + CreateExtensionBase("echo", true, PUSH_MESSAGING_BUT_NOT_BACKGROUND); + ASSERT_TRUE(service->extensions() != NULL); + ASSERT_EQ(0U, service->extensions()->size()); + ASSERT_EQ(0U, model->size()); + + // Add alternating Extensions and Background Apps + ASSERT_FALSE(IsBackgroundApp(*ext1.get())); + service->AddExtension(ext1.get()); + ASSERT_EQ(1U, service->extensions()->size()); + ASSERT_EQ(0U, model->size()); + ASSERT_TRUE(IsBackgroundApp(*bgapp1.get())); + service->AddExtension(bgapp1.get()); + ASSERT_EQ(2U, service->extensions()->size()); + ASSERT_EQ(1U, model->size()); + ASSERT_FALSE(IsBackgroundApp(*ext2.get())); + service->AddExtension(ext2.get()); + ASSERT_EQ(3U, service->extensions()->size()); + ASSERT_EQ(1U, model->size()); + ASSERT_TRUE(IsBackgroundApp(*bgapp2.get())); + service->AddExtension(bgapp2.get()); + ASSERT_EQ(4U, service->extensions()->size()); + ASSERT_EQ(2U, model->size()); + // Need to remove ext2 because it uses same id as bgapp3. + ASSERT_FALSE(IsBackgroundApp(*ext2.get())); + service->UninstallExtension(ext2->id(), false, NULL); + ASSERT_EQ(3U, service->extensions()->size()); + ASSERT_EQ(2U, model->size()); + ASSERT_TRUE(IsBackgroundApp(*bgapp3.get())); + service->AddExtension(bgapp3.get()); + ASSERT_EQ(4U, service->extensions()->size()); + ASSERT_EQ(3U, model->size()); + + // Remove in FIFO order. + ASSERT_FALSE(IsBackgroundApp(*ext1.get())); + service->UninstallExtension(ext1->id(), false, NULL); + ASSERT_EQ(3U, service->extensions()->size()); + ASSERT_EQ(3U, model->size()); + ASSERT_TRUE(IsBackgroundApp(*bgapp1.get())); + service->UninstallExtension(bgapp1->id(), false, NULL); + ASSERT_EQ(2U, service->extensions()->size()); + ASSERT_EQ(2U, model->size()); + ASSERT_TRUE(IsBackgroundApp(*bgapp2.get())); + service->UninstallExtension(bgapp2->id(), false, NULL); + ASSERT_EQ(1U, service->extensions()->size()); + ASSERT_EQ(1U, model->size()); + ASSERT_TRUE(IsBackgroundApp(*bgapp3.get())); + service->UninstallExtension(bgapp3->id(), false, NULL); + ASSERT_EQ(0U, service->extensions()->size()); + ASSERT_EQ(0U, model->size()); +} + + + // With minimal test logic, verifies behavior with dynamic permissions. TEST_F(BackgroundApplicationListModelTest, AddRemovePermissionsTest) { InitializeAndLoadEmptyExtensionService(); |