1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "extensions/browser/extension_registrar.h"
6 
7 #include <memory>
8 
9 #include "base/location.h"
10 #include "base/macros.h"
11 #include "base/optional.h"
12 #include "base/threading/sequenced_task_runner_handle.h"
13 #include "content/public/browser/browser_context.h"
14 #include "content/public/test/test_notification_tracker.h"
15 #include "extensions/browser/extension_prefs.h"
16 #include "extensions/browser/extension_registry.h"
17 #include "extensions/browser/extensions_test.h"
18 #include "extensions/browser/notification_types.h"
19 #include "extensions/browser/runtime_data.h"
20 #include "extensions/browser/test_extension_registry_observer.h"
21 #include "extensions/browser/test_extensions_browser_client.h"
22 #include "extensions/common/extension.h"
23 #include "extensions/common/extension_builder.h"
24 #include "testing/gmock/include/gmock/gmock.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26 
27 namespace extensions {
28 
29 namespace {
30 
31 using testing::Return;
32 using testing::_;
33 
34 using LoadErrorBehavior = ExtensionRegistrar::LoadErrorBehavior;
35 
36 class TestExtensionSystem : public MockExtensionSystem {
37  public:
TestExtensionSystem(content::BrowserContext * context)38   explicit TestExtensionSystem(content::BrowserContext* context)
39       : MockExtensionSystem(context),
40         runtime_data_(ExtensionRegistry::Get(context)) {}
41 
~TestExtensionSystem()42   ~TestExtensionSystem() override {}
43 
44   // MockExtensionSystem:
RegisterExtensionWithRequestContexts(const Extension * extension,base::OnceClosure callback)45   void RegisterExtensionWithRequestContexts(
46       const Extension* extension,
47       base::OnceClosure callback) override {
48     base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
49                                                      std::move(callback));
50   }
runtime_data()51   RuntimeData* runtime_data() override { return &runtime_data_; }
52 
53  private:
54   RuntimeData runtime_data_;
55   DISALLOW_COPY_AND_ASSIGN(TestExtensionSystem);
56 };
57 
58 class TestExtensionRegistrarDelegate : public ExtensionRegistrar::Delegate {
59  public:
60   TestExtensionRegistrarDelegate() = default;
61   ~TestExtensionRegistrarDelegate() override = default;
62 
63   // ExtensionRegistrar::Delegate:
64   MOCK_METHOD2(PreAddExtension,
65                void(const Extension* extension,
66                     const Extension* old_extension));
67   MOCK_METHOD1(PostActivateExtension,
68                void(scoped_refptr<const Extension> extension));
69   MOCK_METHOD1(PostDeactivateExtension,
70                void(scoped_refptr<const Extension> extension));
71   MOCK_METHOD3(LoadExtensionForReload,
72                void(const ExtensionId& extension_id,
73                     const base::FilePath& path,
74                     LoadErrorBehavior load_error_behavior));
75   MOCK_METHOD1(CanEnableExtension, bool(const Extension* extension));
76   MOCK_METHOD1(CanDisableExtension, bool(const Extension* extension));
77   MOCK_METHOD1(ShouldBlockExtension, bool(const Extension* extension));
78 
79  private:
80   DISALLOW_COPY_AND_ASSIGN(TestExtensionRegistrarDelegate);
81 };
82 
83 }  // namespace
84 
85 class ExtensionRegistrarTest : public ExtensionsTest {
86  public:
87   ExtensionRegistrarTest() = default;
88   ~ExtensionRegistrarTest() override = default;
89 
SetUp()90   void SetUp() override {
91     ExtensionsTest::SetUp();
92     extensions_browser_client()->set_extension_system_factory(&factory_);
93     extension_ = ExtensionBuilder("extension").Build();
94     registrar_.emplace(browser_context(), delegate());
95 
96     notification_tracker_.ListenFor(
97         extensions::NOTIFICATION_EXTENSION_UPDATE_DISABLED,
98         content::Source<content::BrowserContext>(browser_context()));
99     notification_tracker_.ListenFor(
100         extensions::NOTIFICATION_EXTENSION_REMOVED,
101         content::Source<content::BrowserContext>(browser_context()));
102 
103     // Mock defaults.
104     ON_CALL(delegate_, CanEnableExtension(extension_.get()))
105         .WillByDefault(Return(true));
106     ON_CALL(delegate_, CanDisableExtension(extension_.get()))
107         .WillByDefault(Return(true));
108     ON_CALL(delegate_, ShouldBlockExtension(extension_.get()))
109         .WillByDefault(Return(false));
110     EXPECT_CALL(delegate_, PostActivateExtension(_)).Times(0);
111     EXPECT_CALL(delegate_, PostDeactivateExtension(_)).Times(0);
112   }
113 
114  protected:
115   // Boilerplate to verify the mock's expected calls. With a SCOPED_TRACE at the
116   // call site, this includes the caller's function in the Gtest trace on
117   // failure. Otherwise, the failures are unhelpfully listed at the end of the
118   // test.
VerifyMock()119   void VerifyMock() {
120     EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(&delegate_));
121 
122     // Re-add the expectations for functions that must not be called.
123     EXPECT_CALL(delegate_, PostActivateExtension(_)).Times(0);
124     EXPECT_CALL(delegate_, PostDeactivateExtension(_)).Times(0);
125   }
126 
127   // Adds the extension as enabled and verifies the result.
AddEnabledExtension()128   void AddEnabledExtension() {
129     SCOPED_TRACE("AddEnabledExtension");
130     ExtensionRegistry* extension_registry =
131         ExtensionRegistry::Get(browser_context());
132 
133     EXPECT_CALL(delegate_, PostActivateExtension(extension_));
134     registrar_->AddExtension(extension_);
135     ExpectInSet(ExtensionRegistry::ENABLED);
136     EXPECT_FALSE(IsExtensionReady());
137 
138     TestExtensionRegistryObserver(extension_registry).WaitForExtensionReady();
139     EXPECT_TRUE(IsExtensionReady());
140 
141     EXPECT_EQ(disable_reason::DISABLE_NONE,
142               ExtensionPrefs::Get(browser_context())
143                   ->GetDisableReasons(extension()->id()));
144 
145     VerifyMock();
146   }
147 
148   // Adds the extension as disabled and verifies the result.
AddDisabledExtension()149   void AddDisabledExtension() {
150     SCOPED_TRACE("AddDisabledExtension");
151     ExtensionPrefs::Get(browser_context())
152         ->SetExtensionDisabled(extension_->id(),
153                                disable_reason::DISABLE_USER_ACTION);
154     registrar_->AddExtension(extension_);
155     ExpectInSet(ExtensionRegistry::DISABLED);
156     EXPECT_FALSE(IsExtensionReady());
157     EXPECT_TRUE(notification_tracker_.Check1AndReset(
158         extensions::NOTIFICATION_EXTENSION_UPDATE_DISABLED));
159   }
160 
161   // Adds the extension as blacklisted and verifies the result.
AddBlacklistedExtension()162   void AddBlacklistedExtension() {
163     SCOPED_TRACE("AddBlacklistedExtension");
164     ExtensionPrefs::Get(browser_context())
165         ->SetExtensionBlacklistState(extension_->id(), BLACKLISTED_MALWARE);
166     registrar_->AddExtension(extension_);
167     ExpectInSet(ExtensionRegistry::BLACKLISTED);
168     EXPECT_FALSE(IsExtensionReady());
169     EXPECT_EQ(0u, notification_tracker_.size());
170   }
171 
172   // Adds the extension as blocked and verifies the result.
AddBlockedExtension()173   void AddBlockedExtension() {
174     SCOPED_TRACE("AddBlockedExtension");
175     registrar_->AddExtension(extension_);
176     ExpectInSet(ExtensionRegistry::BLOCKED);
177     EXPECT_FALSE(IsExtensionReady());
178     EXPECT_EQ(0u, notification_tracker_.size());
179   }
180 
181   // Removes an enabled extension and verifies the result.
RemoveEnabledExtension()182   void RemoveEnabledExtension() {
183     SCOPED_TRACE("RemoveEnabledExtension");
184     // Calling RemoveExtension removes its entry from the enabled list and
185     // removes the extension.
186     EXPECT_CALL(delegate_, PostDeactivateExtension(extension_));
187     registrar_->RemoveExtension(extension_->id(),
188                                 UnloadedExtensionReason::UNINSTALL);
189     ExpectInSet(ExtensionRegistry::NONE);
190 
191     // Removing an enabled extension should trigger a notification.
192     EXPECT_TRUE(notification_tracker_.Check1AndReset(
193         extensions::NOTIFICATION_EXTENSION_REMOVED));
194 
195     VerifyMock();
196   }
197 
198   // Removes a disabled extension and verifies the result.
RemoveDisabledExtension()199   void RemoveDisabledExtension() {
200     SCOPED_TRACE("RemoveDisabledExtension");
201     // Calling RemoveExtension removes its entry from the disabled list and
202     // removes the extension.
203     registrar_->RemoveExtension(extension_->id(),
204                                 UnloadedExtensionReason::UNINSTALL);
205     ExpectInSet(ExtensionRegistry::NONE);
206 
207     // Removing a disabled extension should trigger a notification.
208     EXPECT_TRUE(notification_tracker_.Check1AndReset(
209         extensions::NOTIFICATION_EXTENSION_REMOVED));
210   }
211 
212   // Removes a blacklisted extension and verifies the result.
RemoveBlacklistedExtension()213   void RemoveBlacklistedExtension() {
214     SCOPED_TRACE("RemoveBlacklistedExtension");
215     // Calling RemoveExtension removes the extension.
216     // TODO(michaelpg): Blacklisted extensions shouldn't need to be
217     // "deactivated". See crbug.com/708230.
218     EXPECT_CALL(delegate_, PostDeactivateExtension(extension_));
219     registrar_->RemoveExtension(extension_->id(),
220                                 UnloadedExtensionReason::UNINSTALL);
221 
222     // RemoveExtension does not un-blacklist the extension.
223     ExpectInSet(ExtensionRegistry::BLACKLISTED);
224 
225     // Removing a blacklisted extension should trigger a notification.
226     EXPECT_TRUE(notification_tracker_.Check1AndReset(
227         extensions::NOTIFICATION_EXTENSION_REMOVED));
228 
229     VerifyMock();
230   }
231 
232   // Removes a blocked extension and verifies the result.
RemoveBlockedExtension()233   void RemoveBlockedExtension() {
234     SCOPED_TRACE("RemoveBlockedExtension");
235     // Calling RemoveExtension removes the extension.
236     // TODO(michaelpg): Blocked extensions shouldn't need to be
237     // "deactivated". See crbug.com/708230.
238     EXPECT_CALL(delegate_, PostDeactivateExtension(extension_));
239     registrar_->RemoveExtension(extension_->id(),
240                                 UnloadedExtensionReason::UNINSTALL);
241 
242     // RemoveExtension does not un-block the extension.
243     ExpectInSet(ExtensionRegistry::BLOCKED);
244 
245     // Removing a blocked extension should trigger a notification.
246     EXPECT_TRUE(notification_tracker_.Check1AndReset(
247         extensions::NOTIFICATION_EXTENSION_REMOVED));
248 
249     VerifyMock();
250   }
251 
EnableExtension()252   void EnableExtension() {
253     SCOPED_TRACE("EnableExtension");
254     ExtensionRegistry* extension_registry =
255         ExtensionRegistry::Get(browser_context());
256 
257     EXPECT_CALL(delegate_, PostActivateExtension(extension_));
258     registrar_->EnableExtension(extension_->id());
259     ExpectInSet(ExtensionRegistry::ENABLED);
260     EXPECT_FALSE(IsExtensionReady());
261 
262     TestExtensionRegistryObserver(extension_registry).WaitForExtensionReady();
263     ExpectInSet(ExtensionRegistry::ENABLED);
264     EXPECT_TRUE(IsExtensionReady());
265 
266     VerifyMock();
267   }
268 
DisableEnabledExtension()269   void DisableEnabledExtension() {
270     SCOPED_TRACE("DisableEnabledExtension");
271     EXPECT_CALL(delegate_, PostDeactivateExtension(extension_));
272     registrar_->DisableExtension(extension_->id(),
273                                  disable_reason::DISABLE_USER_ACTION);
274     ExpectInSet(ExtensionRegistry::DISABLED);
275     EXPECT_FALSE(IsExtensionReady());
276 
277     VerifyMock();
278   }
279 
DisableTerminatedExtension()280   void DisableTerminatedExtension() {
281     SCOPED_TRACE("DisableTerminatedExtension");
282     // PostDeactivateExtension should not be called.
283     registrar_->DisableExtension(extension_->id(),
284                                  disable_reason::DISABLE_USER_ACTION);
285     ExpectInSet(ExtensionRegistry::DISABLED);
286     EXPECT_FALSE(IsExtensionReady());
287   }
288 
TerminateExtension()289   void TerminateExtension() {
290     SCOPED_TRACE("TerminateExtension");
291     EXPECT_CALL(delegate_, PostDeactivateExtension(extension_));
292     registrar_->TerminateExtension(extension_->id());
293     ExpectInSet(ExtensionRegistry::TERMINATED);
294     EXPECT_FALSE(IsExtensionReady());
295     VerifyMock();
296   }
297 
UntrackTerminatedExtension()298   void UntrackTerminatedExtension() {
299     SCOPED_TRACE("UntrackTerminatedExtension");
300     registrar()->UntrackTerminatedExtension(extension()->id());
301     ExpectInSet(ExtensionRegistry::NONE);
302     EXPECT_TRUE(notification_tracker_.Check1AndReset(
303         extensions::NOTIFICATION_EXTENSION_REMOVED));
304   }
305 
306   // Directs ExtensionRegistrar to reload the extension and verifies the
307   // delegate is invoked correctly.
ReloadEnabledExtension()308   void ReloadEnabledExtension() {
309     SCOPED_TRACE("ReloadEnabledExtension");
310     EXPECT_CALL(delegate_, PostDeactivateExtension(extension()));
311     EXPECT_CALL(delegate_,
312                 LoadExtensionForReload(extension()->id(), extension()->path(),
313                                        LoadErrorBehavior::kNoisy));
314     registrar()->ReloadExtension(extension()->id(), LoadErrorBehavior::kNoisy);
315     VerifyMock();
316 
317     // ExtensionRegistrar should have disabled the extension in preparation for
318     // a reload.
319     ExpectInSet(ExtensionRegistry::DISABLED);
320     EXPECT_EQ(disable_reason::DISABLE_RELOAD,
321               ExtensionPrefs::Get(browser_context())
322                   ->GetDisableReasons(extension()->id()));
323   }
324 
325   // Directs ExtensionRegistrar to reload the terminated extension and verifies
326   // the delegate is invoked correctly.
ReloadTerminatedExtension()327   void ReloadTerminatedExtension() {
328     SCOPED_TRACE("ReloadTerminatedExtension");
329     EXPECT_CALL(delegate_,
330                 LoadExtensionForReload(extension()->id(), extension()->path(),
331                                        LoadErrorBehavior::kNoisy));
332     registrar()->ReloadExtension(extension()->id(), LoadErrorBehavior::kNoisy);
333     VerifyMock();
334 
335     // The extension should remain in the terminated set until the reload
336     // completes successfully.
337     ExpectInSet(ExtensionRegistry::TERMINATED);
338     // Unlike when reloading an enabled extension, the extension hasn't been
339     // disabled and shouldn't have the DISABLE_RELOAD disable reason.
340     EXPECT_EQ(disable_reason::DISABLE_NONE,
341               ExtensionPrefs::Get(browser_context())
342                   ->GetDisableReasons(extension()->id()));
343   }
344 
345   // Verifies that the extension is in the given set in the ExtensionRegistry
346   // and not in other sets.
ExpectInSet(ExtensionRegistry::IncludeFlag set_id)347   void ExpectInSet(ExtensionRegistry::IncludeFlag set_id) {
348     ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context());
349 
350     EXPECT_EQ(set_id == ExtensionRegistry::ENABLED,
351               registry->enabled_extensions().Contains(extension_->id()));
352 
353     EXPECT_EQ(set_id == ExtensionRegistry::DISABLED,
354               registry->disabled_extensions().Contains(extension_->id()));
355 
356     EXPECT_EQ(set_id == ExtensionRegistry::TERMINATED,
357               registry->terminated_extensions().Contains(extension_->id()));
358 
359     EXPECT_EQ(set_id == ExtensionRegistry::BLACKLISTED,
360               registry->blacklisted_extensions().Contains(extension_->id()));
361 
362     EXPECT_EQ(set_id == ExtensionRegistry::BLOCKED,
363               registry->blocked_extensions().Contains(extension_->id()));
364   }
365 
IsExtensionReady()366   bool IsExtensionReady() {
367     return ExtensionRegistry::Get(browser_context())
368         ->ready_extensions()
369         .Contains(extension_->id());
370   }
371 
registrar()372   ExtensionRegistrar* registrar() { return &registrar_.value(); }
delegate()373   TestExtensionRegistrarDelegate* delegate() { return &delegate_; }
374 
extension() const375   scoped_refptr<const Extension> extension() const { return extension_; }
376 
377  private:
378   MockExtensionSystemFactory<TestExtensionSystem> factory_;
379   // Use NiceMock to allow uninteresting calls, so the delegate can be queried
380   // any number of times. We will explicitly disallow unexpected calls to
381   // PostActivateExtension/PostDeactivateExtension with EXPECT_CALL statements.
382   testing::NiceMock<TestExtensionRegistrarDelegate> delegate_;
383   scoped_refptr<const Extension> extension_;
384 
385   content::TestNotificationTracker notification_tracker_;
386 
387   // Initialized in SetUp().
388   base::Optional<ExtensionRegistrar> registrar_;
389 
390   DISALLOW_COPY_AND_ASSIGN(ExtensionRegistrarTest);
391 };
392 
TEST_F(ExtensionRegistrarTest,Basic)393 TEST_F(ExtensionRegistrarTest, Basic) {
394   AddEnabledExtension();
395   RemoveEnabledExtension();
396 }
397 
TEST_F(ExtensionRegistrarTest,AlreadyEnabled)398 TEST_F(ExtensionRegistrarTest, AlreadyEnabled) {
399   AddEnabledExtension();
400 
401   // As the extension is already enabled, this is a no-op.
402   registrar()->EnableExtension(extension()->id());
403   ExpectInSet(ExtensionRegistry::ENABLED);
404   EXPECT_TRUE(IsExtensionReady());
405 
406   RemoveEnabledExtension();
407 }
408 
TEST_F(ExtensionRegistrarTest,Disable)409 TEST_F(ExtensionRegistrarTest, Disable) {
410   AddEnabledExtension();
411 
412   // Disable the extension before removing it.
413   DisableEnabledExtension();
414   RemoveDisabledExtension();
415 }
416 
TEST_F(ExtensionRegistrarTest,DisableAndEnable)417 TEST_F(ExtensionRegistrarTest, DisableAndEnable) {
418   AddEnabledExtension();
419 
420   // Disable then enable the extension.
421   DisableEnabledExtension();
422   EnableExtension();
423 
424   RemoveEnabledExtension();
425 }
426 
TEST_F(ExtensionRegistrarTest,AddDisabled)427 TEST_F(ExtensionRegistrarTest, AddDisabled) {
428   // An extension can be added as disabled, then removed.
429   AddDisabledExtension();
430   RemoveDisabledExtension();
431 
432   // An extension can be added as disabled, then enabled.
433   AddDisabledExtension();
434   EnableExtension();
435   RemoveEnabledExtension();
436 }
437 
TEST_F(ExtensionRegistrarTest,AddForceEnabled)438 TEST_F(ExtensionRegistrarTest, AddForceEnabled) {
439   // Prevent the extension from being disabled.
440   ON_CALL(*delegate(), CanDisableExtension(extension().get()))
441       .WillByDefault(Return(false));
442   AddEnabledExtension();
443 
444   // Extension cannot be disabled.
445   registrar()->DisableExtension(extension()->id(),
446                                 disable_reason::DISABLE_USER_ACTION);
447   ExpectInSet(ExtensionRegistry::ENABLED);
448 }
449 
TEST_F(ExtensionRegistrarTest,AddForceDisabled)450 TEST_F(ExtensionRegistrarTest, AddForceDisabled) {
451   // Prevent the extension from being enabled.
452   ON_CALL(*delegate(), CanEnableExtension(extension().get()))
453       .WillByDefault(Return(false));
454   AddDisabledExtension();
455 
456   // Extension cannot be enabled.
457   registrar()->EnableExtension(extension()->id());
458   ExpectInSet(ExtensionRegistry::DISABLED);
459 }
460 
TEST_F(ExtensionRegistrarTest,AddBlacklisted)461 TEST_F(ExtensionRegistrarTest, AddBlacklisted) {
462   AddBlacklistedExtension();
463 
464   // A blacklisted extension cannot be enabled/disabled/reloaded.
465   registrar()->EnableExtension(extension()->id());
466   ExpectInSet(ExtensionRegistry::BLACKLISTED);
467   registrar()->DisableExtension(extension()->id(),
468                                 disable_reason::DISABLE_USER_ACTION);
469   ExpectInSet(ExtensionRegistry::BLACKLISTED);
470   registrar()->ReloadExtension(extension()->id(), LoadErrorBehavior::kQuiet);
471   ExpectInSet(ExtensionRegistry::BLACKLISTED);
472 
473   RemoveBlacklistedExtension();
474 }
475 
TEST_F(ExtensionRegistrarTest,AddBlocked)476 TEST_F(ExtensionRegistrarTest, AddBlocked) {
477   // Block extensions.
478   ON_CALL(*delegate(), ShouldBlockExtension(extension().get()))
479       .WillByDefault(Return(true));
480 
481   // A blocked extension can be added.
482   AddBlockedExtension();
483 
484   // Extension cannot be enabled/disabled.
485   registrar()->EnableExtension(extension()->id());
486   ExpectInSet(ExtensionRegistry::BLOCKED);
487   registrar()->DisableExtension(extension()->id(),
488                                 disable_reason::DISABLE_USER_ACTION);
489   ExpectInSet(ExtensionRegistry::BLOCKED);
490 
491   RemoveBlockedExtension();
492 }
493 
TEST_F(ExtensionRegistrarTest,TerminateExtension)494 TEST_F(ExtensionRegistrarTest, TerminateExtension) {
495   AddEnabledExtension();
496   TerminateExtension();
497 
498   // RemoveExtension only handles enabled or disabled extensions.
499   registrar()->RemoveExtension(extension()->id(),
500                                UnloadedExtensionReason::UNINSTALL);
501   ExpectInSet(ExtensionRegistry::TERMINATED);
502 
503   UntrackTerminatedExtension();
504 }
505 
TEST_F(ExtensionRegistrarTest,DisableTerminatedExtension)506 TEST_F(ExtensionRegistrarTest, DisableTerminatedExtension) {
507   AddEnabledExtension();
508   TerminateExtension();
509   DisableTerminatedExtension();
510   RemoveDisabledExtension();
511 }
512 
TEST_F(ExtensionRegistrarTest,EnableTerminatedExtension)513 TEST_F(ExtensionRegistrarTest, EnableTerminatedExtension) {
514   AddEnabledExtension();
515   TerminateExtension();
516 
517   // Enable the terminated extension.
518   UntrackTerminatedExtension();
519   AddEnabledExtension();
520 
521   RemoveEnabledExtension();
522 }
523 
TEST_F(ExtensionRegistrarTest,ReloadExtension)524 TEST_F(ExtensionRegistrarTest, ReloadExtension) {
525   AddEnabledExtension();
526   ReloadEnabledExtension();
527 
528   // Add the now-reloaded extension back into the registrar.
529   AddEnabledExtension();
530 }
531 
TEST_F(ExtensionRegistrarTest,RemoveReloadedExtension)532 TEST_F(ExtensionRegistrarTest, RemoveReloadedExtension) {
533   AddEnabledExtension();
534   ReloadEnabledExtension();
535 
536   // Simulate the delegate failing to load the extension and removing it
537   // instead.
538   RemoveDisabledExtension();
539 
540   // Attempting to reload it silently fails.
541   registrar()->ReloadExtension(extension()->id(), LoadErrorBehavior::kQuiet);
542   ExpectInSet(ExtensionRegistry::NONE);
543 }
544 
TEST_F(ExtensionRegistrarTest,ReloadTerminatedExtension)545 TEST_F(ExtensionRegistrarTest, ReloadTerminatedExtension) {
546   AddEnabledExtension();
547   TerminateExtension();
548 
549   // Reload the terminated extension.
550   ReloadTerminatedExtension();
551 
552   // Complete the reload by adding the extension. Expect the extension to be
553   // enabled once re-added to the registrar, since ExtensionPrefs shouldn't say
554   // it's disabled.
555   AddEnabledExtension();
556 }
557 
558 }  // namespace extensions
559