OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
| 5 #include "chrome/browser/extensions/updater/extension_updater.h" |
| 6 |
5 #include <stddef.h> | 7 #include <stddef.h> |
6 #include <stdint.h> | 8 #include <stdint.h> |
7 | |
8 #include <list> | 9 #include <list> |
9 #include <map> | 10 #include <map> |
10 #include <set> | 11 #include <set> |
| 12 #include <utility> |
11 #include <vector> | 13 #include <vector> |
12 | 14 |
13 #include "base/bind.h" | 15 #include "base/bind.h" |
14 #include "base/bind_helpers.h" | 16 #include "base/bind_helpers.h" |
15 #include "base/command_line.h" | 17 #include "base/command_line.h" |
16 #include "base/compiler_specific.h" | 18 #include "base/compiler_specific.h" |
17 #include "base/macros.h" | 19 #include "base/macros.h" |
18 #include "base/memory/scoped_ptr.h" | 20 #include "base/memory/scoped_ptr.h" |
19 #include "base/memory/weak_ptr.h" | 21 #include "base/memory/weak_ptr.h" |
20 #include "base/message_loop/message_loop.h" | 22 #include "base/message_loop/message_loop.h" |
21 #include "base/run_loop.h" | 23 #include "base/run_loop.h" |
22 #include "base/sequenced_task_runner.h" | 24 #include "base/sequenced_task_runner.h" |
23 #include "base/stl_util.h" | 25 #include "base/stl_util.h" |
24 #include "base/strings/string_number_conversions.h" | 26 #include "base/strings/string_number_conversions.h" |
25 #include "base/strings/string_split.h" | 27 #include "base/strings/string_split.h" |
26 #include "base/strings/string_util.h" | 28 #include "base/strings/string_util.h" |
27 #include "base/strings/stringprintf.h" | 29 #include "base/strings/stringprintf.h" |
28 #include "base/thread_task_runner_handle.h" | 30 #include "base/thread_task_runner_handle.h" |
29 #include "base/threading/thread.h" | 31 #include "base/threading/thread.h" |
30 #include "base/version.h" | 32 #include "base/version.h" |
31 #include "build/build_config.h" | 33 #include "build/build_config.h" |
32 #include "chrome/browser/chrome_notification_types.h" | 34 #include "chrome/browser/chrome_notification_types.h" |
33 #include "chrome/browser/extensions/crx_installer.h" | 35 #include "chrome/browser/extensions/crx_installer.h" |
34 #include "chrome/browser/extensions/extension_error_reporter.h" | 36 #include "chrome/browser/extensions/extension_error_reporter.h" |
35 #include "chrome/browser/extensions/extension_sync_data.h" | 37 #include "chrome/browser/extensions/extension_sync_data.h" |
36 #include "chrome/browser/extensions/test_extension_prefs.h" | 38 #include "chrome/browser/extensions/test_extension_prefs.h" |
37 #include "chrome/browser/extensions/test_extension_service.h" | 39 #include "chrome/browser/extensions/test_extension_service.h" |
38 #include "chrome/browser/extensions/test_extension_system.h" | 40 #include "chrome/browser/extensions/test_extension_system.h" |
39 #include "chrome/browser/extensions/updater/chrome_extension_downloader_factory.
h" | 41 #include "chrome/browser/extensions/updater/chrome_extension_downloader_factory.
h" |
40 #include "chrome/browser/extensions/updater/extension_updater.h" | |
41 #include "chrome/browser/google/google_brand.h" | 42 #include "chrome/browser/google/google_brand.h" |
42 #include "chrome/test/base/scoped_testing_local_state.h" | 43 #include "chrome/test/base/scoped_testing_local_state.h" |
43 #include "chrome/test/base/testing_browser_process.h" | 44 #include "chrome/test/base/testing_browser_process.h" |
44 #include "chrome/test/base/testing_profile.h" | 45 #include "chrome/test/base/testing_profile.h" |
45 #include "components/crx_file/id_util.h" | 46 #include "components/crx_file/id_util.h" |
46 #include "components/syncable_prefs/pref_service_syncable.h" | 47 #include "components/syncable_prefs/pref_service_syncable.h" |
47 #include "components/update_client/update_query_params.h" | 48 #include "components/update_client/update_query_params.h" |
48 #include "content/public/browser/notification_details.h" | 49 #include "content/public/browser/notification_details.h" |
49 #include "content/public/browser/notification_observer.h" | 50 #include "content/public/browser/notification_observer.h" |
50 #include "content/public/browser/notification_registrar.h" | 51 #include "content/public/browser/notification_registrar.h" |
(...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
374 private: | 375 private: |
375 scoped_ptr<ExtensionDownloader> CreateExtensionDownloader( | 376 scoped_ptr<ExtensionDownloader> CreateExtensionDownloader( |
376 ExtensionDownloaderDelegate* delegate) { | 377 ExtensionDownloaderDelegate* delegate) { |
377 scoped_ptr<ExtensionDownloader> downloader = | 378 scoped_ptr<ExtensionDownloader> downloader = |
378 ChromeExtensionDownloaderFactory::CreateForRequestContext( | 379 ChromeExtensionDownloaderFactory::CreateForRequestContext( |
379 request_context(), | 380 request_context(), |
380 downloader_delegate_override_ ? downloader_delegate_override_ | 381 downloader_delegate_override_ ? downloader_delegate_override_ |
381 : delegate); | 382 : delegate); |
382 if (enable_metrics_) | 383 if (enable_metrics_) |
383 downloader->set_enable_extra_update_metrics(true); | 384 downloader->set_enable_extra_update_metrics(true); |
384 return downloader.Pass(); | 385 return downloader; |
385 } | 386 } |
386 | 387 |
387 scoped_ptr<ExtensionDownloader> CreateExtensionDownloaderWithIdentity( | 388 scoped_ptr<ExtensionDownloader> CreateExtensionDownloaderWithIdentity( |
388 ExtensionDownloaderDelegate* delegate) { | 389 ExtensionDownloaderDelegate* delegate) { |
389 scoped_ptr<FakeIdentityProvider> fake_identity_provider; | 390 scoped_ptr<FakeIdentityProvider> fake_identity_provider; |
390 fake_token_service_.reset(new FakeOAuth2TokenService()); | 391 fake_token_service_.reset(new FakeOAuth2TokenService()); |
391 fake_identity_provider.reset(new FakeIdentityProvider( | 392 fake_identity_provider.reset(new FakeIdentityProvider( |
392 fake_token_service_.get())); | 393 fake_token_service_.get())); |
393 fake_identity_provider->LogIn(kFakeAccountId); | 394 fake_identity_provider->LogIn(kFakeAccountId); |
394 fake_token_service_->AddAccount(kFakeAccountId); | 395 fake_token_service_->AddAccount(kFakeAccountId); |
395 | 396 |
396 scoped_ptr<ExtensionDownloader> downloader( | 397 scoped_ptr<ExtensionDownloader> downloader( |
397 CreateExtensionDownloader(delegate)); | 398 CreateExtensionDownloader(delegate)); |
398 downloader->SetWebstoreIdentityProvider(fake_identity_provider.Pass()); | 399 downloader->SetWebstoreIdentityProvider(std::move(fake_identity_provider)); |
399 return downloader.Pass(); | 400 return downloader; |
400 } | 401 } |
401 | 402 |
402 scoped_ptr<FakeOAuth2TokenService> fake_token_service_; | 403 scoped_ptr<FakeOAuth2TokenService> fake_token_service_; |
403 | 404 |
404 ExtensionDownloaderDelegate* downloader_delegate_override_; | 405 ExtensionDownloaderDelegate* downloader_delegate_override_; |
405 | 406 |
406 bool enable_metrics_; | 407 bool enable_metrics_; |
407 | 408 |
408 DISALLOW_COPY_AND_ASSIGN(MockService); | 409 DISALLOW_COPY_AND_ASSIGN(MockService); |
409 }; | 410 }; |
(...skipping 543 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
953 fetch4->AddExtension("4444", "4.0", &zeroDays, kEmptyUpdateUrlData, | 954 fetch4->AddExtension("4444", "4.0", &zeroDays, kEmptyUpdateUrlData, |
954 std::string()); | 955 std::string()); |
955 | 956 |
956 // This will start the first fetcher and queue the others. The next in queue | 957 // This will start the first fetcher and queue the others. The next in queue |
957 // is started as each fetcher receives its response. Note that the fetchers | 958 // is started as each fetcher receives its response. Note that the fetchers |
958 // don't necessarily run in the order that they are started from here. | 959 // don't necessarily run in the order that they are started from here. |
959 GURL fetch1_url = fetch1->full_url(); | 960 GURL fetch1_url = fetch1->full_url(); |
960 GURL fetch2_url = fetch2->full_url(); | 961 GURL fetch2_url = fetch2->full_url(); |
961 GURL fetch3_url = fetch3->full_url(); | 962 GURL fetch3_url = fetch3->full_url(); |
962 GURL fetch4_url = fetch4->full_url(); | 963 GURL fetch4_url = fetch4->full_url(); |
963 downloader.StartUpdateCheck(fetch1.Pass()); | 964 downloader.StartUpdateCheck(std::move(fetch1)); |
964 downloader.StartUpdateCheck(fetch2.Pass()); | 965 downloader.StartUpdateCheck(std::move(fetch2)); |
965 downloader.StartUpdateCheck(fetch3.Pass()); | 966 downloader.StartUpdateCheck(std::move(fetch3)); |
966 downloader.StartUpdateCheck(fetch4.Pass()); | 967 downloader.StartUpdateCheck(std::move(fetch4)); |
967 RunUntilIdle(); | 968 RunUntilIdle(); |
968 | 969 |
969 for (int i = 0; i < 4; ++i) { | 970 for (int i = 0; i < 4; ++i) { |
970 fetcher = factory.GetFetcherByID(ExtensionDownloader::kManifestFetcherId); | 971 fetcher = factory.GetFetcherByID(ExtensionDownloader::kManifestFetcherId); |
971 ASSERT_TRUE(fetcher); | 972 ASSERT_TRUE(fetcher); |
972 ASSERT_TRUE(fetcher->delegate()); | 973 ASSERT_TRUE(fetcher->delegate()); |
973 EXPECT_TRUE(fetcher->GetLoadFlags() == kExpectedLoadFlags); | 974 EXPECT_TRUE(fetcher->GetLoadFlags() == kExpectedLoadFlags); |
974 EXPECT_FALSE(fetcher->GetOriginalURL().is_empty()); | 975 EXPECT_FALSE(fetcher->GetOriginalURL().is_empty()); |
975 | 976 |
976 if (fetcher->GetOriginalURL() == fetch1_url) { | 977 if (fetcher->GetOriginalURL() == fetch1_url) { |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1078 downloader.manifests_queue_.set_backoff_policy(&kNoBackoffPolicy); | 1079 downloader.manifests_queue_.set_backoff_policy(&kNoBackoffPolicy); |
1079 | 1080 |
1080 GURL kUpdateUrl("http://localhost/manifest1"); | 1081 GURL kUpdateUrl("http://localhost/manifest1"); |
1081 | 1082 |
1082 scoped_ptr<ManifestFetchData> fetch(CreateManifestFetchData(kUpdateUrl)); | 1083 scoped_ptr<ManifestFetchData> fetch(CreateManifestFetchData(kUpdateUrl)); |
1083 ManifestFetchData::PingData zeroDays(0, 0, true, 0); | 1084 ManifestFetchData::PingData zeroDays(0, 0, true, 0); |
1084 fetch->AddExtension("1111", "1.0", &zeroDays, kEmptyUpdateUrlData, | 1085 fetch->AddExtension("1111", "1.0", &zeroDays, kEmptyUpdateUrlData, |
1085 std::string()); | 1086 std::string()); |
1086 | 1087 |
1087 // This will start the first fetcher. | 1088 // This will start the first fetcher. |
1088 downloader.StartUpdateCheck(fetch.Pass()); | 1089 downloader.StartUpdateCheck(std::move(fetch)); |
1089 RunUntilIdle(); | 1090 RunUntilIdle(); |
1090 | 1091 |
1091 // ExtensionDownloader should retry kMaxRetries times and then fail. | 1092 // ExtensionDownloader should retry kMaxRetries times and then fail. |
1092 EXPECT_CALL(delegate, OnExtensionDownloadFailed( | 1093 EXPECT_CALL(delegate, OnExtensionDownloadFailed( |
1093 "1111", ExtensionDownloaderDelegate::MANIFEST_FETCH_FAILED, _, _)); | 1094 "1111", ExtensionDownloaderDelegate::MANIFEST_FETCH_FAILED, _, _)); |
1094 for (int i = 0; i <= ExtensionDownloader::kMaxRetries; ++i) { | 1095 for (int i = 0; i <= ExtensionDownloader::kMaxRetries; ++i) { |
1095 // All fetches will fail. | 1096 // All fetches will fail. |
1096 fetcher = factory.GetFetcherByID(ExtensionDownloader::kManifestFetcherId); | 1097 fetcher = factory.GetFetcherByID(ExtensionDownloader::kManifestFetcherId); |
1097 EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL); | 1098 EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL); |
1098 EXPECT_TRUE(fetcher->GetLoadFlags() == kExpectedLoadFlags); | 1099 EXPECT_TRUE(fetcher->GetLoadFlags() == kExpectedLoadFlags); |
1099 fetcher->set_url(kUpdateUrl); | 1100 fetcher->set_url(kUpdateUrl); |
1100 fetcher->set_status(net::URLRequestStatus()); | 1101 fetcher->set_status(net::URLRequestStatus()); |
1101 // Code 5xx causes ExtensionDownloader to retry. | 1102 // Code 5xx causes ExtensionDownloader to retry. |
1102 fetcher->set_response_code(500); | 1103 fetcher->set_response_code(500); |
1103 fetcher->delegate()->OnURLFetchComplete(fetcher); | 1104 fetcher->delegate()->OnURLFetchComplete(fetcher); |
1104 RunUntilIdle(); | 1105 RunUntilIdle(); |
1105 } | 1106 } |
1106 Mock::VerifyAndClearExpectations(&delegate); | 1107 Mock::VerifyAndClearExpectations(&delegate); |
1107 | 1108 |
1108 | 1109 |
1109 // For response codes that are not in the 5xx range ExtensionDownloader | 1110 // For response codes that are not in the 5xx range ExtensionDownloader |
1110 // should not retry. | 1111 // should not retry. |
1111 fetch.reset(CreateManifestFetchData(kUpdateUrl)); | 1112 fetch.reset(CreateManifestFetchData(kUpdateUrl)); |
1112 fetch->AddExtension("1111", "1.0", &zeroDays, kEmptyUpdateUrlData, | 1113 fetch->AddExtension("1111", "1.0", &zeroDays, kEmptyUpdateUrlData, |
1113 std::string()); | 1114 std::string()); |
1114 | 1115 |
1115 // This will start the first fetcher. | 1116 // This will start the first fetcher. |
1116 downloader.StartUpdateCheck(fetch.Pass()); | 1117 downloader.StartUpdateCheck(std::move(fetch)); |
1117 RunUntilIdle(); | 1118 RunUntilIdle(); |
1118 | 1119 |
1119 EXPECT_CALL(delegate, OnExtensionDownloadFailed( | 1120 EXPECT_CALL(delegate, OnExtensionDownloadFailed( |
1120 "1111", ExtensionDownloaderDelegate::MANIFEST_FETCH_FAILED, _, _)); | 1121 "1111", ExtensionDownloaderDelegate::MANIFEST_FETCH_FAILED, _, _)); |
1121 // The first fetch will fail, and require retrying. | 1122 // The first fetch will fail, and require retrying. |
1122 fetcher = factory.GetFetcherByID(ExtensionDownloader::kManifestFetcherId); | 1123 fetcher = factory.GetFetcherByID(ExtensionDownloader::kManifestFetcherId); |
1123 EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL); | 1124 EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL); |
1124 EXPECT_TRUE(fetcher->GetLoadFlags() == kExpectedLoadFlags); | 1125 EXPECT_TRUE(fetcher->GetLoadFlags() == kExpectedLoadFlags); |
1125 fetcher->set_url(kUpdateUrl); | 1126 fetcher->set_url(kUpdateUrl); |
1126 fetcher->set_status(net::URLRequestStatus()); | 1127 fetcher->set_status(net::URLRequestStatus()); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1165 GURL test_url("http://localhost/extension.crx"); | 1166 GURL test_url("http://localhost/extension.crx"); |
1166 | 1167 |
1167 std::string id = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; | 1168 std::string id = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; |
1168 std::string hash; | 1169 std::string hash; |
1169 Version version("0.0.1"); | 1170 Version version("0.0.1"); |
1170 std::set<int> requests; | 1171 std::set<int> requests; |
1171 requests.insert(0); | 1172 requests.insert(0); |
1172 scoped_ptr<ExtensionDownloader::ExtensionFetch> fetch( | 1173 scoped_ptr<ExtensionDownloader::ExtensionFetch> fetch( |
1173 new ExtensionDownloader::ExtensionFetch( | 1174 new ExtensionDownloader::ExtensionFetch( |
1174 id, test_url, hash, version.GetString(), requests)); | 1175 id, test_url, hash, version.GetString(), requests)); |
1175 updater.downloader_->FetchUpdatedExtension(fetch.Pass()); | 1176 updater.downloader_->FetchUpdatedExtension(std::move(fetch)); |
1176 | 1177 |
1177 if (pending) { | 1178 if (pending) { |
1178 const bool kIsFromSync = true; | 1179 const bool kIsFromSync = true; |
1179 const bool kMarkAcknowledged = false; | 1180 const bool kMarkAcknowledged = false; |
1180 const bool kRemoteInstall = false; | 1181 const bool kRemoteInstall = false; |
1181 PendingExtensionManager* pending_extension_manager = | 1182 PendingExtensionManager* pending_extension_manager = |
1182 service->pending_extension_manager(); | 1183 service->pending_extension_manager(); |
1183 pending_extension_manager->AddForTesting( | 1184 pending_extension_manager->AddForTesting( |
1184 PendingExtensionInfo(id, | 1185 PendingExtensionInfo(id, |
1185 std::string(), | 1186 std::string(), |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1275 | 1276 |
1276 GURL test_url(base::StringPrintf("%s/extension.crx", url_prefix.c_str())); | 1277 GURL test_url(base::StringPrintf("%s/extension.crx", url_prefix.c_str())); |
1277 std::string id = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; | 1278 std::string id = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; |
1278 std::string hash; | 1279 std::string hash; |
1279 Version version("0.0.1"); | 1280 Version version("0.0.1"); |
1280 std::set<int> requests; | 1281 std::set<int> requests; |
1281 requests.insert(0); | 1282 requests.insert(0); |
1282 scoped_ptr<ExtensionDownloader::ExtensionFetch> fetch( | 1283 scoped_ptr<ExtensionDownloader::ExtensionFetch> fetch( |
1283 new ExtensionDownloader::ExtensionFetch( | 1284 new ExtensionDownloader::ExtensionFetch( |
1284 id, test_url, hash, version.GetString(), requests)); | 1285 id, test_url, hash, version.GetString(), requests)); |
1285 updater.downloader_->FetchUpdatedExtension(fetch.Pass()); | 1286 updater.downloader_->FetchUpdatedExtension(std::move(fetch)); |
1286 | 1287 |
1287 fetcher = factory.GetFetcherByID(ExtensionDownloader::kExtensionFetcherId); | 1288 fetcher = factory.GetFetcherByID(ExtensionDownloader::kExtensionFetcherId); |
1288 EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL); | 1289 EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL); |
1289 EXPECT_EQ(kExpectedLoadFlags, fetcher->GetLoadFlags()); | 1290 EXPECT_EQ(kExpectedLoadFlags, fetcher->GetLoadFlags()); |
1290 | 1291 |
1291 // Fake a 403 response. | 1292 // Fake a 403 response. |
1292 fetcher->set_url(test_url); | 1293 fetcher->set_url(test_url); |
1293 fetcher->set_status(net::URLRequestStatus()); | 1294 fetcher->set_status(net::URLRequestStatus()); |
1294 fetcher->set_response_code(403); | 1295 fetcher->set_response_code(403); |
1295 fetcher->delegate()->OnURLFetchComplete(fetcher); | 1296 fetcher->delegate()->OnURLFetchComplete(fetcher); |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1468 std::string version2 = "0.1"; | 1469 std::string version2 = "0.1"; |
1469 std::set<int> requests; | 1470 std::set<int> requests; |
1470 requests.insert(0); | 1471 requests.insert(0); |
1471 // Start two fetches | 1472 // Start two fetches |
1472 scoped_ptr<ExtensionDownloader::ExtensionFetch> fetch1( | 1473 scoped_ptr<ExtensionDownloader::ExtensionFetch> fetch1( |
1473 new ExtensionDownloader::ExtensionFetch( | 1474 new ExtensionDownloader::ExtensionFetch( |
1474 id1, url1, hash1, version1, requests)); | 1475 id1, url1, hash1, version1, requests)); |
1475 scoped_ptr<ExtensionDownloader::ExtensionFetch> fetch2( | 1476 scoped_ptr<ExtensionDownloader::ExtensionFetch> fetch2( |
1476 new ExtensionDownloader::ExtensionFetch( | 1477 new ExtensionDownloader::ExtensionFetch( |
1477 id2, url2, hash2, version2, requests)); | 1478 id2, url2, hash2, version2, requests)); |
1478 updater.downloader_->FetchUpdatedExtension(fetch1.Pass()); | 1479 updater.downloader_->FetchUpdatedExtension(std::move(fetch1)); |
1479 updater.downloader_->FetchUpdatedExtension(fetch2.Pass()); | 1480 updater.downloader_->FetchUpdatedExtension(std::move(fetch2)); |
1480 | 1481 |
1481 // Make the first fetch complete. | 1482 // Make the first fetch complete. |
1482 base::FilePath extension_file_path(FILE_PATH_LITERAL("/whatever")); | 1483 base::FilePath extension_file_path(FILE_PATH_LITERAL("/whatever")); |
1483 | 1484 |
1484 fetcher = factory.GetFetcherByID(ExtensionDownloader::kExtensionFetcherId); | 1485 fetcher = factory.GetFetcherByID(ExtensionDownloader::kExtensionFetcherId); |
1485 EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL); | 1486 EXPECT_TRUE(fetcher != NULL && fetcher->delegate() != NULL); |
1486 EXPECT_TRUE(fetcher->GetLoadFlags() == kExpectedLoadFlags); | 1487 EXPECT_TRUE(fetcher->GetLoadFlags() == kExpectedLoadFlags); |
1487 | 1488 |
1488 // We need some CrxInstallers, and CrxInstallers require a real | 1489 // We need some CrxInstallers, and CrxInstallers require a real |
1489 // ExtensionService. Create one on the testing profile. Any action | 1490 // ExtensionService. Create one on the testing profile. Any action |
(...skipping 767 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2257 // -prodversionmin (shouldn't update if browser version too old) | 2258 // -prodversionmin (shouldn't update if browser version too old) |
2258 // -manifests & updates arriving out of order / interleaved | 2259 // -manifests & updates arriving out of order / interleaved |
2259 // -malformed update url (empty, file://, has query, has a # fragment, etc.) | 2260 // -malformed update url (empty, file://, has query, has a # fragment, etc.) |
2260 // -An extension gets uninstalled while updates are in progress (so it doesn't | 2261 // -An extension gets uninstalled while updates are in progress (so it doesn't |
2261 // "come back from the dead") | 2262 // "come back from the dead") |
2262 // -An extension gets manually updated to v3 while we're downloading v2 (ie | 2263 // -An extension gets manually updated to v3 while we're downloading v2 (ie |
2263 // you don't get downgraded accidentally) | 2264 // you don't get downgraded accidentally) |
2264 // -An update manifest mentions multiple updates | 2265 // -An update manifest mentions multiple updates |
2265 | 2266 |
2266 } // namespace extensions | 2267 } // namespace extensions |
OLD | NEW |