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
3 // found in the LICENSE file.
4
5 #include "extensions/browser/api/management/management_api.h"
6
7 #include <memory>
8 #include <string>
9 #include <utility>
10 #include <vector>
11
12 #include "base/bind.h"
13 #include "base/json/json_writer.h"
14 #include "base/lazy_instance.h"
15 #include "base/location.h"
16 #include "base/logging.h"
17 #include "base/metrics/histogram.h"
18 #include "base/single_thread_task_runner.h"
19 #include "base/stl_util.h"
20 #include "base/strings/string_util.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "base/threading/thread_task_runner_handle.h"
23 #include "build/build_config.h"
24 #include "build/chromeos_buildflags.h"
25 #include "content/public/browser/browser_context.h"
26 #include "extensions/browser/api/extensions_api_client.h"
27 #include "extensions/browser/api/management/management_api_constants.h"
28 #include "extensions/browser/disable_reason.h"
29 #include "extensions/browser/event_router.h"
30 #include "extensions/browser/extension_prefs.h"
31 #include "extensions/browser/extension_registry.h"
32 #include "extensions/browser/extension_system.h"
33 #include "extensions/browser/management_policy.h"
34 #include "extensions/browser/requirements_checker.h"
35 #include "extensions/browser/uninstall_reason.h"
36 #include "extensions/common/api/management.h"
37 #include "extensions/common/error_utils.h"
38 #include "extensions/common/extension.h"
39 #include "extensions/common/extension_icon_set.h"
40 #include "extensions/common/manifest.h"
41 #include "extensions/common/manifest_handlers/icons_handler.h"
42 #include "extensions/common/manifest_handlers/offline_enabled_info.h"
43 #include "extensions/common/manifest_handlers/options_page_info.h"
44 #include "extensions/common/manifest_handlers/replacement_apps.h"
45 #include "extensions/common/manifest_url_handlers.h"
46 #include "extensions/common/permissions/permission_message.h"
47 #include "extensions/common/permissions/permissions_data.h"
48 #include "extensions/common/url_pattern.h"
49 #include "url/gurl.h"
50 #include "url/url_constants.h"
51
52 using content::BrowserThread;
53
54 namespace keys = extension_management_api_constants;
55
56 namespace extensions {
57
58 namespace management = api::management;
59
60 namespace {
61
62 typedef std::vector<management::ExtensionInfo> ExtensionInfoList;
63 typedef std::vector<management::IconInfo> IconInfoList;
64
65 enum AutoConfirmForTest { DO_NOT_SKIP = 0, PROCEED, ABORT };
66
67 AutoConfirmForTest auto_confirm_for_test = DO_NOT_SKIP;
68
CreateWarningsList(const Extension * extension)69 std::vector<std::string> CreateWarningsList(const Extension* extension) {
70 std::vector<std::string> warnings_list;
71 for (const PermissionMessage& msg :
72 extension->permissions_data()->GetPermissionMessages()) {
73 warnings_list.push_back(base::UTF16ToUTF8(msg.message()));
74 }
75
76 return warnings_list;
77 }
78
GetAvailableLaunchTypes(const Extension & extension,const ManagementAPIDelegate * delegate)79 std::vector<management::LaunchType> GetAvailableLaunchTypes(
80 const Extension& extension,
81 const ManagementAPIDelegate* delegate) {
82 std::vector<management::LaunchType> launch_type_list;
83 if (extension.is_platform_app()) {
84 launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_WINDOW);
85 return launch_type_list;
86 }
87
88 launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_REGULAR_TAB);
89 launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_WINDOW);
90 return launch_type_list;
91 }
92
CreateExtensionInfo(const Extension * source_extension,const Extension & extension,content::BrowserContext * context)93 management::ExtensionInfo CreateExtensionInfo(
94 const Extension* source_extension,
95 const Extension& extension,
96 content::BrowserContext* context) {
97 ExtensionSystem* system = ExtensionSystem::Get(context);
98 ExtensionRegistry* registry = ExtensionRegistry::Get(context);
99 const ManagementAPIDelegate* delegate =
100 ManagementAPI::GetFactoryInstance()->Get(context)->GetDelegate();
101 management::ExtensionInfo info;
102
103 info.id = extension.id();
104 info.name = extension.name();
105 info.short_name = extension.short_name();
106 info.enabled = registry->enabled_extensions().Contains(info.id);
107 info.offline_enabled = OfflineEnabledInfo::IsOfflineEnabled(&extension);
108 info.version = extension.VersionString();
109 if (!extension.version_name().empty())
110 info.version_name.reset(new std::string(extension.version_name()));
111 info.description = extension.description();
112 info.options_url = OptionsPageInfo::GetOptionsPage(&extension).spec();
113 info.homepage_url.reset(
114 new std::string(ManifestURL::GetHomepageURL(&extension).spec()));
115 info.may_disable =
116 !system->management_policy()->MustRemainEnabled(&extension, nullptr);
117 info.is_app = extension.is_app();
118 if (info.is_app) {
119 if (extension.is_legacy_packaged_app())
120 info.type = management::EXTENSION_TYPE_LEGACY_PACKAGED_APP;
121 else if (extension.is_hosted_app())
122 info.type = management::EXTENSION_TYPE_HOSTED_APP;
123 else
124 info.type = management::EXTENSION_TYPE_PACKAGED_APP;
125 } else if (extension.is_theme()) {
126 info.type = management::EXTENSION_TYPE_THEME;
127 } else if (extension.is_login_screen_extension()) {
128 info.type = management::EXTENSION_TYPE_LOGIN_SCREEN_EXTENSION;
129 } else {
130 info.type = management::EXTENSION_TYPE_EXTENSION;
131 }
132
133 if (info.enabled) {
134 info.disabled_reason = management::EXTENSION_DISABLED_REASON_NONE;
135 } else {
136 ExtensionPrefs* prefs = ExtensionPrefs::Get(context);
137 if (prefs->DidExtensionEscalatePermissions(extension.id())) {
138 info.disabled_reason =
139 management::EXTENSION_DISABLED_REASON_PERMISSIONS_INCREASE;
140 } else {
141 info.disabled_reason = management::EXTENSION_DISABLED_REASON_UNKNOWN;
142 }
143
144 info.may_enable = std::make_unique<bool>(
145 system->management_policy()->ExtensionMayModifySettings(
146 source_extension, &extension, nullptr) &&
147 !system->management_policy()->MustRemainDisabled(&extension, nullptr,
148 nullptr));
149 }
150
151 if (!ManifestURL::GetUpdateURL(&extension).is_empty()) {
152 info.update_url.reset(
153 new std::string(ManifestURL::GetUpdateURL(&extension).spec()));
154 }
155
156 if (extension.is_app()) {
157 info.app_launch_url.reset(
158 new std::string(delegate->GetFullLaunchURL(&extension).spec()));
159 }
160
161 const ExtensionIconSet::IconMap& icons =
162 IconsInfo::GetIcons(&extension).map();
163 if (!icons.empty()) {
164 info.icons.reset(new IconInfoList());
165 ExtensionIconSet::IconMap::const_iterator icon_iter;
166 for (icon_iter = icons.begin(); icon_iter != icons.end(); ++icon_iter) {
167 management::IconInfo icon_info;
168 icon_info.size = icon_iter->first;
169 GURL url = delegate->GetIconURL(&extension, icon_info.size,
170 ExtensionIconSet::MATCH_EXACTLY, false);
171 icon_info.url = url.spec();
172 info.icons->push_back(std::move(icon_info));
173 }
174 }
175
176 const std::set<std::string> perms =
177 extension.permissions_data()->active_permissions().GetAPIsAsStrings();
178 if (!perms.empty()) {
179 std::set<std::string>::const_iterator perms_iter;
180 for (perms_iter = perms.begin(); perms_iter != perms.end(); ++perms_iter)
181 info.permissions.push_back(*perms_iter);
182 }
183
184 if (!extension.is_hosted_app()) {
185 // Skip host permissions for hosted apps.
186 const URLPatternSet& host_perms =
187 extension.permissions_data()->active_permissions().explicit_hosts();
188 if (!host_perms.is_empty()) {
189 for (auto iter = host_perms.begin(); iter != host_perms.end(); ++iter) {
190 info.host_permissions.push_back(iter->GetAsString());
191 }
192 }
193 }
194
195 switch (extension.location()) {
196 case Manifest::INTERNAL:
197 info.install_type = management::EXTENSION_INSTALL_TYPE_NORMAL;
198 break;
199 case Manifest::UNPACKED:
200 case Manifest::COMMAND_LINE:
201 info.install_type = management::EXTENSION_INSTALL_TYPE_DEVELOPMENT;
202 break;
203 case Manifest::EXTERNAL_PREF:
204 case Manifest::EXTERNAL_REGISTRY:
205 case Manifest::EXTERNAL_PREF_DOWNLOAD:
206 info.install_type = management::EXTENSION_INSTALL_TYPE_SIDELOAD;
207 break;
208 case Manifest::EXTERNAL_POLICY:
209 case Manifest::EXTERNAL_POLICY_DOWNLOAD:
210 info.install_type = management::EXTENSION_INSTALL_TYPE_ADMIN;
211 break;
212 case Manifest::NUM_LOCATIONS:
213 NOTREACHED();
214 FALLTHROUGH;
215 case Manifest::INVALID_LOCATION:
216 case Manifest::COMPONENT:
217 case Manifest::EXTERNAL_COMPONENT:
218 info.install_type = management::EXTENSION_INSTALL_TYPE_OTHER;
219 break;
220 }
221
222 info.launch_type = management::LAUNCH_TYPE_NONE;
223 if (extension.is_app()) {
224 LaunchType launch_type;
225 if (extension.is_platform_app()) {
226 launch_type = LAUNCH_TYPE_WINDOW;
227 } else {
228 launch_type =
229 delegate->GetLaunchType(ExtensionPrefs::Get(context), &extension);
230 }
231
232 switch (launch_type) {
233 case LAUNCH_TYPE_PINNED:
234 info.launch_type = management::LAUNCH_TYPE_OPEN_AS_PINNED_TAB;
235 break;
236 case LAUNCH_TYPE_REGULAR:
237 info.launch_type = management::LAUNCH_TYPE_OPEN_AS_REGULAR_TAB;
238 break;
239 case LAUNCH_TYPE_FULLSCREEN:
240 info.launch_type = management::LAUNCH_TYPE_OPEN_FULL_SCREEN;
241 break;
242 case LAUNCH_TYPE_WINDOW:
243 info.launch_type = management::LAUNCH_TYPE_OPEN_AS_WINDOW;
244 break;
245 case LAUNCH_TYPE_INVALID:
246 case NUM_LAUNCH_TYPES:
247 NOTREACHED();
248 }
249
250 info.available_launch_types.reset(new std::vector<management::LaunchType>(
251 GetAvailableLaunchTypes(extension, delegate)));
252 }
253
254 return info;
255 }
256
AddExtensionInfo(const Extension * source_extension,const ExtensionSet & extensions,ExtensionInfoList * extension_list,content::BrowserContext * context)257 void AddExtensionInfo(const Extension* source_extension,
258 const ExtensionSet& extensions,
259 ExtensionInfoList* extension_list,
260 content::BrowserContext* context) {
261 for (ExtensionSet::const_iterator iter = extensions.begin();
262 iter != extensions.end(); ++iter) {
263 const Extension& extension = **iter;
264
265 if (!extension.ShouldExposeViaManagementAPI())
266 continue;
267
268 extension_list->push_back(
269 CreateExtensionInfo(source_extension, extension, context));
270 }
271 }
272
273 } // namespace
274
Run()275 ExtensionFunction::ResponseAction ManagementGetAllFunction::Run() {
276 ExtensionInfoList extensions;
277 ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context());
278
279 AddExtensionInfo(extension(), registry->enabled_extensions(), &extensions,
280 browser_context());
281 AddExtensionInfo(extension(), registry->disabled_extensions(), &extensions,
282 browser_context());
283 AddExtensionInfo(extension(), registry->terminated_extensions(), &extensions,
284 browser_context());
285
286 return RespondNow(
287 ArgumentList(management::GetAll::Results::Create(extensions)));
288 }
289
Run()290 ExtensionFunction::ResponseAction ManagementGetFunction::Run() {
291 std::unique_ptr<management::Get::Params> params(
292 management::Get::Params::Create(*args_));
293 EXTENSION_FUNCTION_VALIDATE(params.get());
294 ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context());
295
296 const Extension* target_extension =
297 registry->GetExtensionById(params->id, ExtensionRegistry::EVERYTHING);
298 if (!target_extension)
299 return RespondNow(Error(keys::kNoExtensionError, params->id));
300
301 return RespondNow(ArgumentList(management::Get::Results::Create(
302 CreateExtensionInfo(extension(), *target_extension, browser_context()))));
303 }
304
Run()305 ExtensionFunction::ResponseAction ManagementGetSelfFunction::Run() {
306 return RespondNow(ArgumentList(management::Get::Results::Create(
307 CreateExtensionInfo(extension(), *extension_, browser_context()))));
308 }
309
310 ExtensionFunction::ResponseAction
Run()311 ManagementGetPermissionWarningsByIdFunction::Run() {
312 std::unique_ptr<management::GetPermissionWarningsById::Params> params(
313 management::GetPermissionWarningsById::Params::Create(*args_));
314 EXTENSION_FUNCTION_VALIDATE(params.get());
315
316 const Extension* extension =
317 ExtensionRegistry::Get(browser_context())
318 ->GetExtensionById(params->id, ExtensionRegistry::EVERYTHING);
319 if (!extension)
320 return RespondNow(Error(keys::kNoExtensionError, params->id));
321
322 std::vector<std::string> warnings = CreateWarningsList(extension);
323 return RespondNow(ArgumentList(
324 management::GetPermissionWarningsById::Results::Create(warnings)));
325 }
326
327 ExtensionFunction::ResponseAction
Run()328 ManagementGetPermissionWarningsByManifestFunction::Run() {
329 std::unique_ptr<management::GetPermissionWarningsByManifest::Params> params(
330 management::GetPermissionWarningsByManifest::Params::Create(*args_));
331 EXTENSION_FUNCTION_VALIDATE(params.get());
332
333 const ManagementAPIDelegate* delegate = ManagementAPI::GetFactoryInstance()
334 ->Get(browser_context())
335 ->GetDelegate();
336
337 if (delegate) {
338 delegate->GetPermissionWarningsByManifestFunctionDelegate(
339 this, params->manifest_str);
340
341 // Matched with a Release() in OnParse().
342 AddRef();
343
344 // Response is sent async in OnParse().
345 return RespondLater();
346 } else {
347 // TODO(lfg) add error string
348 return RespondNow(Error(kUnknownErrorDoNotUse));
349 }
350 }
OnParse(data_decoder::DataDecoder::ValueOrError result)351 void ManagementGetPermissionWarningsByManifestFunction::OnParse(
352 data_decoder::DataDecoder::ValueOrError result) {
353 if (!result.value) {
354 Respond(Error(*result.error));
355
356 // Matched with AddRef() in Run().
357 Release();
358 return;
359 }
360
361 const base::DictionaryValue* parsed_manifest;
362 if (!result.value->GetAsDictionary(&parsed_manifest)) {
363 Respond(Error(keys::kManifestParseError));
364 Release();
365 return;
366 }
367
368 std::string error;
369 scoped_refptr<Extension> extension =
370 Extension::Create(base::FilePath(), Manifest::INVALID_LOCATION,
371 *parsed_manifest, Extension::NO_FLAGS, &error);
372 // TODO(lazyboy): Do we need to use |error|?
373 if (!extension) {
374 Respond(Error(keys::kExtensionCreateError));
375 Release();
376 return;
377 }
378
379 std::vector<std::string> warnings = CreateWarningsList(extension.get());
380 Respond(ArgumentList(
381 management::GetPermissionWarningsByManifest::Results::Create(warnings)));
382
383 // Matched with AddRef() in Run().
384 Release();
385 }
386
Run()387 ExtensionFunction::ResponseAction ManagementLaunchAppFunction::Run() {
388 std::unique_ptr<management::LaunchApp::Params> params(
389 management::LaunchApp::Params::Create(*args_));
390 EXTENSION_FUNCTION_VALIDATE(params.get());
391
392 if (ExtensionsBrowserClient::Get()->IsRunningInForcedAppMode())
393 return RespondNow(Error(keys::kNotAllowedInKioskError));
394
395 const Extension* extension =
396 ExtensionRegistry::Get(browser_context())
397 ->GetExtensionById(params->id, ExtensionRegistry::EVERYTHING);
398 if (!extension)
399 return RespondNow(Error(keys::kNoExtensionError, params->id));
400 if (!extension->is_app())
401 return RespondNow(Error(keys::kNotAnAppError, params->id));
402
403 const ManagementAPIDelegate* delegate = ManagementAPI::GetFactoryInstance()
404 ->Get(browser_context())
405 ->GetDelegate();
406 delegate->LaunchAppFunctionDelegate(extension, browser_context());
407 return RespondNow(NoArguments());
408 }
409
410 ManagementSetEnabledFunction::ManagementSetEnabledFunction() = default;
411
412 ManagementSetEnabledFunction::~ManagementSetEnabledFunction() = default;
413
Run()414 ExtensionFunction::ResponseAction ManagementSetEnabledFunction::Run() {
415 std::unique_ptr<management::SetEnabled::Params> params(
416 management::SetEnabled::Params::Create(*args_));
417 EXTENSION_FUNCTION_VALIDATE(params.get());
418 extension_id_ = params->id;
419
420 if (ExtensionsBrowserClient::Get()->IsAppModeForcedForApp(extension_id_))
421 return RespondNow(Error(keys::kCannotChangePrimaryKioskAppError));
422
423 ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context());
424 const ManagementAPIDelegate* delegate = ManagementAPI::GetFactoryInstance()
425 ->Get(browser_context())
426 ->GetDelegate();
427
428 const Extension* target_extension =
429 registry->GetExtensionById(extension_id_, ExtensionRegistry::EVERYTHING);
430 if (!target_extension || !target_extension->ShouldExposeViaManagementAPI())
431 return RespondNow(Error(keys::kNoExtensionError, extension_id_));
432
433 bool should_enable = params->enabled;
434
435 const ManagementPolicy* policy =
436 ExtensionSystem::Get(browser_context())->management_policy();
437 if (!policy->ExtensionMayModifySettings(extension(), target_extension,
438 nullptr)) {
439 return RespondNow(Error(keys::kUserCantModifyError, extension_id_));
440 }
441
442 SupervisedUserExtensionsDelegate* supervised_user_extensions_delegate =
443 ManagementAPI::GetFactoryInstance()
444 ->Get(browser_context())
445 ->GetSupervisedUserExtensionsDelegate();
446 if (supervised_user_extensions_delegate &&
447 supervised_user_extensions_delegate->IsChild(browser_context()) &&
448 // Don't prompt the user if the extension has unsupported requirements.
449 // TODO(crbug/1071978): If OnRequirementsChecked() passes, the extension
450 // will enable, bypassing parent approval.
451 !HasUnsupportedRequirements(extension_id_) &&
452 // Only ask for parent approval if the extension still requires approval.
453 !supervised_user_extensions_delegate->IsExtensionAllowedByParent(
454 *target_extension, browser_context())) {
455 // Either ask for parent permission or notify the child that their parent
456 // has disabled this action.
457 auto parent_permission_callback = base::BindOnce(
458 &ManagementSetEnabledFunction::OnParentPermissionDialogDone, this);
459 auto error_callback = base::BindOnce(
460 &ManagementSetEnabledFunction::OnBlockedByParentDialogDone, this);
461 AddRef(); // Matched in OnParentPermissionDialogDone() or
462 // OnBlockedByParentDialogDone().
463 supervised_user_extensions_delegate->PromptForParentPermissionOrShowError(
464 *target_extension, browser_context(), GetSenderWebContents(),
465 std::move(parent_permission_callback), std::move(error_callback));
466 return RespondLater();
467 }
468
469 if (should_enable &&
470 policy->MustRemainDisabled(target_extension, nullptr, nullptr)) {
471 return RespondNow(Error(keys::kUserCantModifyError, extension_id_));
472 }
473
474 bool currently_enabled =
475 registry->enabled_extensions().Contains(extension_id_) ||
476 registry->terminated_extensions().Contains(extension_id_);
477
478 if (!currently_enabled && should_enable) {
479 ExtensionPrefs* prefs = ExtensionPrefs::Get(browser_context());
480 if (prefs->DidExtensionEscalatePermissions(extension_id_)) {
481 if (!user_gesture())
482 return RespondNow(Error(keys::kGestureNeededForEscalationError));
483
484 AddRef(); // Matched in OnInstallPromptDone().
485 install_prompt_ = delegate->SetEnabledFunctionDelegate(
486 GetSenderWebContents(), browser_context(), target_extension,
487 base::Bind(&ManagementSetEnabledFunction::OnInstallPromptDone, this));
488 return RespondLater();
489 }
490 if (HasUnsupportedRequirements(extension_id_)) {
491 // Recheck the requirements.
492 requirements_checker_ =
493 std::make_unique<RequirementsChecker>(target_extension);
494 requirements_checker_->Start(
495 base::BindOnce(&ManagementSetEnabledFunction::OnRequirementsChecked,
496 this)); // This bind creates a reference.
497 return RespondLater();
498 }
499 delegate->EnableExtension(browser_context(), extension_id_);
500 } else if (currently_enabled && !params->enabled) {
501 delegate->DisableExtension(
502 browser_context(), extension(), extension_id_,
503 Manifest::IsPolicyLocation(target_extension->location())
504 ? disable_reason::DISABLE_BLOCKED_BY_POLICY
505 : disable_reason::DISABLE_USER_ACTION);
506 }
507
508 return RespondNow(NoArguments());
509 }
510
OnInstallPromptDone(bool did_accept)511 void ManagementSetEnabledFunction::OnInstallPromptDone(bool did_accept) {
512 if (did_accept) {
513 ManagementAPI::GetFactoryInstance()
514 ->Get(browser_context())
515 ->GetDelegate()
516 ->EnableExtension(browser_context(), extension_id_);
517 Respond(NoArguments());
518 } else {
519 Respond(Error(keys::kUserDidNotReEnableError));
520 }
521
522 Release(); // Balanced in Run().
523 }
524
HasUnsupportedRequirements(const std::string & extension_id)525 bool ManagementSetEnabledFunction::HasUnsupportedRequirements(
526 const std::string& extension_id) {
527 ExtensionPrefs* prefs = ExtensionPrefs::Get(browser_context());
528 return prefs->GetDisableReasons(extension_id) &
529 disable_reason::DISABLE_UNSUPPORTED_REQUIREMENT;
530 }
531
OnRequirementsChecked(const PreloadCheck::Errors & errors)532 void ManagementSetEnabledFunction::OnRequirementsChecked(
533 const PreloadCheck::Errors& errors) {
534 if (errors.empty()) {
535 ManagementAPI::GetFactoryInstance()->Get(browser_context())->GetDelegate()->
536 EnableExtension(browser_context(), extension_id_);
537 Respond(NoArguments());
538 } else {
539 // TODO(devlin): Should we really be noisy here all the time?
540 Respond(Error(keys::kMissingRequirementsError,
541 base::UTF16ToUTF8(requirements_checker_->GetErrorMessage())));
542 }
543 }
544
OnParentPermissionDialogDone(SupervisedUserExtensionsDelegate::ParentPermissionDialogResult result)545 void ManagementSetEnabledFunction::OnParentPermissionDialogDone(
546 SupervisedUserExtensionsDelegate::ParentPermissionDialogResult result) {
547 #if BUILDFLAG(IS_CHROMEOS_ASH)
548 switch (result) {
549 case SupervisedUserExtensionsDelegate::ParentPermissionDialogResult::
550 kParentPermissionReceived: {
551 const ManagementAPIDelegate* delegate =
552 ManagementAPI::GetFactoryInstance()
553 ->Get(browser_context())
554 ->GetDelegate();
555 delegate->EnableExtension(browser_context(), extension_id_);
556 Respond(NoArguments());
557 break;
558 }
559
560 case SupervisedUserExtensionsDelegate::ParentPermissionDialogResult::
561 kParentPermissionCanceled: {
562 Respond(Error(keys::kUserDidNotReEnableError));
563 break;
564 }
565
566 case SupervisedUserExtensionsDelegate::ParentPermissionDialogResult::
567 kParentPermissionFailed: {
568 Respond(Error(keys::kParentPermissionFailedError));
569 break;
570 }
571 }
572 // Matches the AddRef in Run().
573 Release();
574 #endif // BUILDFLAG(IS_CHROMEOS_ASH)
575 }
576
OnBlockedByParentDialogDone()577 void ManagementSetEnabledFunction::OnBlockedByParentDialogDone() {
578 #if BUILDFLAG(IS_CHROMEOS_ASH)
579 Respond(Error(keys::kUserCantModifyError, extension_id_));
580 // Matches the AddRef in Run().
581 Release();
582 #endif // BUILDFLAG(IS_CHROMEOS_ASH)
583 }
584
585 ManagementUninstallFunctionBase::ManagementUninstallFunctionBase() = default;
586
587 ManagementUninstallFunctionBase::~ManagementUninstallFunctionBase() = default;
588
Uninstall(const std::string & target_extension_id,bool show_confirm_dialog)589 ExtensionFunction::ResponseAction ManagementUninstallFunctionBase::Uninstall(
590 const std::string& target_extension_id,
591 bool show_confirm_dialog) {
592 if (ExtensionsBrowserClient::Get()->IsRunningInForcedAppMode())
593 return RespondNow(Error(keys::kNotAllowedInKioskError));
594
595 const ManagementAPIDelegate* delegate = ManagementAPI::GetFactoryInstance()
596 ->Get(browser_context())
597 ->GetDelegate();
598 target_extension_id_ = target_extension_id;
599 const Extension* target_extension =
600 extensions::ExtensionRegistry::Get(browser_context())
601 ->GetExtensionById(target_extension_id_,
602 ExtensionRegistry::EVERYTHING);
603 if (!target_extension || !target_extension->ShouldExposeViaManagementAPI()) {
604 return RespondNow(Error(keys::kNoExtensionError, target_extension_id_));
605 }
606
607 ManagementPolicy* policy =
608 ExtensionSystem::Get(browser_context())->management_policy();
609 if (!policy->UserMayModifySettings(target_extension, nullptr) ||
610 policy->MustRemainInstalled(target_extension, nullptr)) {
611 return RespondNow(Error(keys::kUserCantModifyError, target_extension_id_));
612 }
613
614 // Note: null extension() means it's WebUI.
615 bool self_uninstall = extension() && extension_id() == target_extension_id_;
616 // We need to show a dialog for any extension uninstalling another extension.
617 show_confirm_dialog |= !self_uninstall;
618
619 if (show_confirm_dialog && !user_gesture())
620 return RespondNow(Error(keys::kGestureNeededForUninstallError));
621
622 if (show_confirm_dialog) {
623 // We show the programmatic uninstall ui for extensions uninstalling
624 // other extensions.
625 bool show_programmatic_uninstall_ui =
626 !self_uninstall && extension() &&
627 extension()->id() != extensions::kWebStoreAppId;
628 AddRef(); // Balanced in OnExtensionUninstallDialogClosed.
629 // TODO(devlin): A method called "UninstallFunctionDelegate" does not in
630 // any way imply that this actually creates a dialog and runs it.
631 uninstall_dialog_ = delegate->UninstallFunctionDelegate(
632 this, target_extension, show_programmatic_uninstall_ui);
633 } else { // No confirm dialog.
634 base::ThreadTaskRunnerHandle::Get()->PostTask(
635 FROM_HERE,
636 base::BindOnce(&ManagementUninstallFunctionBase::UninstallExtension,
637 this));
638 }
639
640 return RespondLater();
641 }
642
Finish(bool did_start_uninstall,const std::string & error)643 void ManagementUninstallFunctionBase::Finish(bool did_start_uninstall,
644 const std::string& error) {
645 Respond(did_start_uninstall ? NoArguments() : Error(error));
646 }
647
OnExtensionUninstallDialogClosed(bool did_start_uninstall,const base::string16 & error)648 void ManagementUninstallFunctionBase::OnExtensionUninstallDialogClosed(
649 bool did_start_uninstall,
650 const base::string16& error) {
651 Finish(did_start_uninstall,
652 ErrorUtils::FormatErrorMessage(keys::kUninstallCanceledError,
653 target_extension_id_));
654 Release(); // Balanced in Uninstall().
655 }
656
UninstallExtension()657 void ManagementUninstallFunctionBase::UninstallExtension() {
658 // The extension can be uninstalled in another window while the UI was
659 // showing. Do nothing in that case.
660 const Extension* target_extension =
661 extensions::ExtensionRegistry::Get(browser_context())
662 ->GetExtensionById(target_extension_id_,
663 ExtensionRegistry::EVERYTHING);
664 std::string error;
665 bool success = false;
666 if (target_extension) {
667 const ManagementAPIDelegate* delegate = ManagementAPI::GetFactoryInstance()
668 ->Get(browser_context())
669 ->GetDelegate();
670 base::string16 utf16_error;
671 success = delegate->UninstallExtension(
672 browser_context(), target_extension_id_,
673 extensions::UNINSTALL_REASON_MANAGEMENT_API, &utf16_error);
674 error = base::UTF16ToUTF8(utf16_error);
675 } else {
676 error = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
677 target_extension_id_);
678 }
679 Finish(success, error);
680 }
681
ManagementUninstallFunction()682 ManagementUninstallFunction::ManagementUninstallFunction() {
683 }
684
~ManagementUninstallFunction()685 ManagementUninstallFunction::~ManagementUninstallFunction() {
686 }
687
Run()688 ExtensionFunction::ResponseAction ManagementUninstallFunction::Run() {
689 std::unique_ptr<management::Uninstall::Params> params(
690 management::Uninstall::Params::Create(*args_));
691 EXTENSION_FUNCTION_VALIDATE(params.get());
692
693 bool show_confirm_dialog = params->options.get() &&
694 params->options->show_confirm_dialog.get() &&
695 *params->options->show_confirm_dialog;
696 return Uninstall(params->id, show_confirm_dialog);
697 }
698
ManagementUninstallSelfFunction()699 ManagementUninstallSelfFunction::ManagementUninstallSelfFunction() {
700 }
701
~ManagementUninstallSelfFunction()702 ManagementUninstallSelfFunction::~ManagementUninstallSelfFunction() {
703 }
704
Run()705 ExtensionFunction::ResponseAction ManagementUninstallSelfFunction::Run() {
706 std::unique_ptr<management::UninstallSelf::Params> params(
707 management::UninstallSelf::Params::Create(*args_));
708 EXTENSION_FUNCTION_VALIDATE(params.get());
709 EXTENSION_FUNCTION_VALIDATE(extension_.get());
710
711 bool show_confirm_dialog = params->options.get() &&
712 params->options->show_confirm_dialog.get() &&
713 *params->options->show_confirm_dialog;
714 return Uninstall(extension_->id(), show_confirm_dialog);
715 }
716
ManagementCreateAppShortcutFunction()717 ManagementCreateAppShortcutFunction::ManagementCreateAppShortcutFunction() {
718 }
719
~ManagementCreateAppShortcutFunction()720 ManagementCreateAppShortcutFunction::~ManagementCreateAppShortcutFunction() {
721 }
722
723 // static
SetAutoConfirmForTest(bool should_proceed)724 void ManagementCreateAppShortcutFunction::SetAutoConfirmForTest(
725 bool should_proceed) {
726 auto_confirm_for_test = should_proceed ? PROCEED : ABORT;
727 }
728
OnCloseShortcutPrompt(bool created)729 void ManagementCreateAppShortcutFunction::OnCloseShortcutPrompt(bool created) {
730 Respond(created ? NoArguments() : Error(keys::kCreateShortcutCanceledError));
731 Release(); // Balanced in Run().
732 }
733
Run()734 ExtensionFunction::ResponseAction ManagementCreateAppShortcutFunction::Run() {
735 if (ExtensionsBrowserClient::Get()->IsRunningInForcedAppMode())
736 return RespondNow(Error(keys::kNotAllowedInKioskError));
737
738 if (!user_gesture())
739 return RespondNow(Error(keys::kGestureNeededForCreateAppShortcutError));
740
741 std::unique_ptr<management::CreateAppShortcut::Params> params(
742 management::CreateAppShortcut::Params::Create(*args_));
743 EXTENSION_FUNCTION_VALIDATE(params.get());
744 const Extension* extension =
745 ExtensionRegistry::Get(browser_context())
746 ->GetExtensionById(params->id, ExtensionRegistry::EVERYTHING);
747 if (!extension) {
748 return RespondNow(Error(
749 ErrorUtils::FormatErrorMessage(keys::kNoExtensionError, params->id)));
750 }
751
752 if (!extension->is_app()) {
753 return RespondNow(Error(
754 ErrorUtils::FormatErrorMessage(keys::kNotAnAppError, params->id)));
755 }
756
757 #if defined(OS_MAC)
758 if (!extension->is_platform_app())
759 return RespondNow(Error(keys::kCreateOnlyPackagedAppShortcutMac));
760 #endif
761
762 if (auto_confirm_for_test != DO_NOT_SKIP) {
763 // Matched with a Release() in OnCloseShortcutPrompt().
764 AddRef();
765
766 OnCloseShortcutPrompt(auto_confirm_for_test == PROCEED);
767 // OnCloseShortcutPrompt() might have called Respond() already.
768 return did_respond() ? AlreadyResponded() : RespondLater();
769 }
770
771 std::string error;
772 if (ManagementAPI::GetFactoryInstance()
773 ->Get(browser_context())
774 ->GetDelegate()
775 ->CreateAppShortcutFunctionDelegate(this, extension, &error)) {
776 // Matched with a Release() in OnCloseShortcutPrompt().
777 AddRef();
778 // Response is sent async in OnCloseShortcutPrompt().
779 return RespondLater();
780 } else {
781 return RespondNow(Error(std::move(error)));
782 }
783 }
784
Run()785 ExtensionFunction::ResponseAction ManagementSetLaunchTypeFunction::Run() {
786 if (ExtensionsBrowserClient::Get()->IsRunningInForcedAppMode())
787 return RespondNow(Error(keys::kNotAllowedInKioskError));
788
789 if (!user_gesture())
790 return RespondNow(Error(keys::kGestureNeededForSetLaunchTypeError));
791
792 std::unique_ptr<management::SetLaunchType::Params> params(
793 management::SetLaunchType::Params::Create(*args_));
794 EXTENSION_FUNCTION_VALIDATE(params.get());
795 const Extension* extension =
796 ExtensionRegistry::Get(browser_context())
797 ->GetExtensionById(params->id, ExtensionRegistry::EVERYTHING);
798 const ManagementAPIDelegate* delegate = ManagementAPI::GetFactoryInstance()
799 ->Get(browser_context())
800 ->GetDelegate();
801 if (!extension)
802 return RespondNow(Error(keys::kNoExtensionError, params->id));
803
804 if (!extension->is_app())
805 return RespondNow(Error(keys::kNotAnAppError, params->id));
806
807 std::vector<management::LaunchType> available_launch_types =
808 GetAvailableLaunchTypes(*extension, delegate);
809
810 management::LaunchType app_launch_type = params->launch_type;
811 if (!base::Contains(available_launch_types, app_launch_type)) {
812 return RespondNow(Error(keys::kLaunchTypeNotAvailableError));
813 }
814
815 LaunchType launch_type = LAUNCH_TYPE_DEFAULT;
816 switch (app_launch_type) {
817 case management::LAUNCH_TYPE_OPEN_AS_PINNED_TAB:
818 launch_type = LAUNCH_TYPE_PINNED;
819 break;
820 case management::LAUNCH_TYPE_OPEN_AS_REGULAR_TAB:
821 launch_type = LAUNCH_TYPE_REGULAR;
822 break;
823 case management::LAUNCH_TYPE_OPEN_FULL_SCREEN:
824 launch_type = LAUNCH_TYPE_FULLSCREEN;
825 break;
826 case management::LAUNCH_TYPE_OPEN_AS_WINDOW:
827 launch_type = LAUNCH_TYPE_WINDOW;
828 break;
829 case management::LAUNCH_TYPE_NONE:
830 NOTREACHED();
831 }
832
833 delegate->SetLaunchType(browser_context(), params->id, launch_type);
834
835 return RespondNow(NoArguments());
836 }
837
ManagementGenerateAppForLinkFunction()838 ManagementGenerateAppForLinkFunction::ManagementGenerateAppForLinkFunction() {}
839
~ManagementGenerateAppForLinkFunction()840 ManagementGenerateAppForLinkFunction::~ManagementGenerateAppForLinkFunction() {}
841
FinishCreateWebApp(const std::string & web_app_id,bool install_success)842 void ManagementGenerateAppForLinkFunction::FinishCreateWebApp(
843 const std::string& web_app_id,
844 bool install_success) {
845 ResponseValue response;
846 if (install_success) {
847 response = ArgumentList(management::GenerateAppForLink::Results::Create(
848 app_for_link_delegate_->CreateExtensionInfoFromWebApp(
849 web_app_id, browser_context())));
850 } else {
851 response = Error(keys::kGenerateAppForLinkInstallError);
852 }
853
854 Respond(std::move(response));
855 Release(); // Balanced in Run().
856 }
857
Run()858 ExtensionFunction::ResponseAction ManagementGenerateAppForLinkFunction::Run() {
859 if (ExtensionsBrowserClient::Get()->IsRunningInForcedAppMode())
860 return RespondNow(Error(keys::kNotAllowedInKioskError));
861
862 if (!user_gesture())
863 return RespondNow(Error(keys::kGestureNeededForGenerateAppForLinkError));
864
865 std::unique_ptr<management::GenerateAppForLink::Params> params(
866 management::GenerateAppForLink::Params::Create(*args_));
867 EXTENSION_FUNCTION_VALIDATE(params.get());
868
869 GURL launch_url(params->url);
870 if (!launch_url.is_valid() || !launch_url.SchemeIsHTTPOrHTTPS()) {
871 return RespondNow(Error(
872 ErrorUtils::FormatErrorMessage(keys::kInvalidURLError, params->url)));
873 }
874
875 if (params->title.empty())
876 return RespondNow(Error(keys::kEmptyTitleError));
877
878 app_for_link_delegate_ =
879 ManagementAPI::GetFactoryInstance()
880 ->Get(browser_context())
881 ->GetDelegate()
882 ->GenerateAppForLinkFunctionDelegate(this, browser_context(),
883 params->title, launch_url);
884
885 // Matched with a Release() in FinishCreateWebApp().
886 AddRef();
887
888 // Response is sent async in FinishCreateWebApp().
889 return RespondLater();
890 }
891
892 ManagementCanInstallReplacementAndroidAppFunction::
ManagementCanInstallReplacementAndroidAppFunction()893 ManagementCanInstallReplacementAndroidAppFunction() {}
894
895 ManagementCanInstallReplacementAndroidAppFunction::
~ManagementCanInstallReplacementAndroidAppFunction()896 ~ManagementCanInstallReplacementAndroidAppFunction() {}
897
898 ExtensionFunction::ResponseAction
Run()899 ManagementCanInstallReplacementAndroidAppFunction::Run() {
900 if (ExtensionsBrowserClient::Get()->IsRunningInForcedAppMode())
901 return RespondNow(Error(keys::kNotAllowedInKioskError));
902
903 if (!extension()->from_webstore()) {
904 return RespondNow(
905 Error(keys::kInstallReplacementAndroidAppNotFromWebstoreError));
906 }
907
908 auto* api_delegate = ManagementAPI::GetFactoryInstance()
909 ->Get(browser_context())
910 ->GetDelegate();
911
912 DCHECK(api_delegate);
913
914 if (!api_delegate->CanContextInstallAndroidApps(browser_context())) {
915 return RespondNow(ArgumentList(
916 management::CanInstallReplacementAndroidApp::Results::Create(false)));
917 }
918
919 DCHECK(ReplacementAppsInfo::HasReplacementAndroidApp(extension()));
920
921 const std::string& package_name =
922 ReplacementAppsInfo::GetReplacementAndroidApp(extension());
923
924 api_delegate->CheckAndroidAppInstallStatus(
925 package_name,
926 base::BindOnce(&ManagementCanInstallReplacementAndroidAppFunction::
927 OnFinishedAndroidAppCheck,
928 this));
929
930 // Response is sent async in FinishCheckAndroidApp().
931 return RespondLater();
932 }
933
934 void ManagementCanInstallReplacementAndroidAppFunction::
OnFinishedAndroidAppCheck(bool installable)935 OnFinishedAndroidAppCheck(bool installable) {
936 Respond(
937 ArgumentList(management::CanInstallReplacementAndroidApp::Results::Create(
938 installable)));
939 }
940
941 ManagementInstallReplacementAndroidAppFunction::
ManagementInstallReplacementAndroidAppFunction()942 ManagementInstallReplacementAndroidAppFunction() {}
943
944 ManagementInstallReplacementAndroidAppFunction::
~ManagementInstallReplacementAndroidAppFunction()945 ~ManagementInstallReplacementAndroidAppFunction() {}
946
947 ExtensionFunction::ResponseAction
Run()948 ManagementInstallReplacementAndroidAppFunction::Run() {
949 if (ExtensionsBrowserClient::Get()->IsRunningInForcedAppMode())
950 return RespondNow(Error(keys::kNotAllowedInKioskError));
951
952 if (!extension()->from_webstore()) {
953 return RespondNow(
954 Error(keys::kInstallReplacementAndroidAppNotFromWebstoreError));
955 }
956
957 if (!user_gesture()) {
958 return RespondNow(
959 Error(keys::kGestureNeededForInstallReplacementAndroidAppError));
960 }
961
962 auto* api_delegate = ManagementAPI::GetFactoryInstance()
963 ->Get(browser_context())
964 ->GetDelegate();
965
966 DCHECK(api_delegate);
967 if (!api_delegate->CanContextInstallAndroidApps(browser_context())) {
968 return RespondNow(
969 Error(keys::kInstallReplacementAndroidAppInvalidContextError));
970 }
971
972 DCHECK(ReplacementAppsInfo::HasReplacementAndroidApp(extension()));
973
974 api_delegate->InstallReplacementAndroidApp(
975 ReplacementAppsInfo::GetReplacementAndroidApp(extension()),
976 base::BindOnce(&ManagementInstallReplacementAndroidAppFunction::
977 OnAppInstallInitiated,
978 this));
979
980 // Response is sent async in OnAppInstallInitiated().
981 return RespondLater();
982 }
983
OnAppInstallInitiated(bool initiated)984 void ManagementInstallReplacementAndroidAppFunction::OnAppInstallInitiated(
985 bool initiated) {
986 if (!initiated)
987 return Respond(Error(keys::kInstallReplacementAndroidAppCannotInstallApp));
988
989 return Respond(NoArguments());
990 }
991
992 ManagementInstallReplacementWebAppFunction::
ManagementInstallReplacementWebAppFunction()993 ManagementInstallReplacementWebAppFunction() {}
994
995 ManagementInstallReplacementWebAppFunction::
~ManagementInstallReplacementWebAppFunction()996 ~ManagementInstallReplacementWebAppFunction() {}
997
998 ExtensionFunction::ResponseAction
Run()999 ManagementInstallReplacementWebAppFunction::Run() {
1000 if (ExtensionsBrowserClient::Get()->IsRunningInForcedAppMode())
1001 return RespondNow(Error(keys::kNotAllowedInKioskError));
1002
1003 if (!extension()->from_webstore()) {
1004 return RespondNow(
1005 Error(keys::kInstallReplacementWebAppNotFromWebstoreError));
1006 }
1007
1008 if (!user_gesture()) {
1009 return RespondNow(
1010 Error(keys::kGestureNeededForInstallReplacementWebAppError));
1011 }
1012
1013 DCHECK(ReplacementAppsInfo::HasReplacementWebApp(extension()));
1014 const GURL& web_app_url =
1015 ReplacementAppsInfo::GetReplacementWebApp(extension());
1016
1017 DCHECK(web_app_url.is_valid());
1018 DCHECK(web_app_url.SchemeIs(url::kHttpsScheme));
1019
1020 auto* api_delegate = ManagementAPI::GetFactoryInstance()
1021 ->Get(browser_context())
1022 ->GetDelegate();
1023 if (!api_delegate->CanContextInstallWebApps(browser_context())) {
1024 return RespondNow(
1025 Error(keys::kInstallReplacementWebAppInvalidContextError));
1026 }
1027
1028 // Adds a ref-count.
1029 api_delegate->InstallOrLaunchReplacementWebApp(
1030 browser_context(), web_app_url,
1031 base::BindOnce(
1032 &ManagementInstallReplacementWebAppFunction::FinishResponse, this));
1033
1034 // Response is sent async in FinishResponse().
1035 return RespondLater();
1036 }
1037
FinishResponse(ManagementAPIDelegate::InstallOrLaunchWebAppResult result)1038 void ManagementInstallReplacementWebAppFunction::FinishResponse(
1039 ManagementAPIDelegate::InstallOrLaunchWebAppResult result) {
1040 ResponseValue response;
1041 switch (result) {
1042 case ManagementAPIDelegate::InstallOrLaunchWebAppResult::kSuccess:
1043 response = NoArguments();
1044 break;
1045 case ManagementAPIDelegate::InstallOrLaunchWebAppResult::kInvalidWebApp:
1046 response = Error(keys::kInstallReplacementWebAppInvalidWebAppError);
1047 break;
1048 case ManagementAPIDelegate::InstallOrLaunchWebAppResult::kUnknownError:
1049 response = Error(keys::kGenerateAppForLinkInstallError);
1050 }
1051 Respond(std::move(response));
1052 }
1053
ManagementEventRouter(content::BrowserContext * context)1054 ManagementEventRouter::ManagementEventRouter(content::BrowserContext* context)
1055 : browser_context_(context) {
1056 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
1057 }
1058
~ManagementEventRouter()1059 ManagementEventRouter::~ManagementEventRouter() {}
1060
OnExtensionLoaded(content::BrowserContext * browser_context,const Extension * extension)1061 void ManagementEventRouter::OnExtensionLoaded(
1062 content::BrowserContext* browser_context,
1063 const Extension* extension) {
1064 BroadcastEvent(extension, events::MANAGEMENT_ON_ENABLED,
1065 management::OnEnabled::kEventName);
1066 }
1067
OnExtensionUnloaded(content::BrowserContext * browser_context,const Extension * extension,UnloadedExtensionReason reason)1068 void ManagementEventRouter::OnExtensionUnloaded(
1069 content::BrowserContext* browser_context,
1070 const Extension* extension,
1071 UnloadedExtensionReason reason) {
1072 BroadcastEvent(extension, events::MANAGEMENT_ON_DISABLED,
1073 management::OnDisabled::kEventName);
1074 }
1075
OnExtensionInstalled(content::BrowserContext * browser_context,const Extension * extension,bool is_update)1076 void ManagementEventRouter::OnExtensionInstalled(
1077 content::BrowserContext* browser_context,
1078 const Extension* extension,
1079 bool is_update) {
1080 BroadcastEvent(extension, events::MANAGEMENT_ON_INSTALLED,
1081 management::OnInstalled::kEventName);
1082 }
1083
OnExtensionUninstalled(content::BrowserContext * browser_context,const Extension * extension,extensions::UninstallReason reason)1084 void ManagementEventRouter::OnExtensionUninstalled(
1085 content::BrowserContext* browser_context,
1086 const Extension* extension,
1087 extensions::UninstallReason reason) {
1088 BroadcastEvent(extension, events::MANAGEMENT_ON_UNINSTALLED,
1089 management::OnUninstalled::kEventName);
1090 }
1091
BroadcastEvent(const Extension * extension,events::HistogramValue histogram_value,const char * event_name)1092 void ManagementEventRouter::BroadcastEvent(
1093 const Extension* extension,
1094 events::HistogramValue histogram_value,
1095 const char* event_name) {
1096 if (!extension->ShouldExposeViaManagementAPI())
1097 return;
1098 std::unique_ptr<base::ListValue> args(new base::ListValue());
1099 if (event_name == management::OnUninstalled::kEventName) {
1100 args->AppendString(extension->id());
1101 } else {
1102 args->Append(
1103 CreateExtensionInfo(nullptr, *extension, browser_context_).ToValue());
1104 }
1105
1106 EventRouter::Get(browser_context_)
1107 ->BroadcastEvent(std::unique_ptr<Event>(
1108 new Event(histogram_value, event_name, std::move(args))));
1109 }
1110
ManagementAPI(content::BrowserContext * context)1111 ManagementAPI::ManagementAPI(content::BrowserContext* context)
1112 : browser_context_(context),
1113 delegate_(ExtensionsAPIClient::Get()->CreateManagementAPIDelegate()),
1114 supervised_user_extensions_delegate_(
1115 ExtensionsAPIClient::Get()
1116 ->CreateSupervisedUserExtensionsDelegate()) {
1117 EventRouter* event_router = EventRouter::Get(browser_context_);
1118 event_router->RegisterObserver(this, management::OnInstalled::kEventName);
1119 event_router->RegisterObserver(this, management::OnUninstalled::kEventName);
1120 event_router->RegisterObserver(this, management::OnEnabled::kEventName);
1121 event_router->RegisterObserver(this, management::OnDisabled::kEventName);
1122 }
1123
~ManagementAPI()1124 ManagementAPI::~ManagementAPI() {
1125 }
1126
Shutdown()1127 void ManagementAPI::Shutdown() {
1128 EventRouter::Get(browser_context_)->UnregisterObserver(this);
1129 }
1130
1131 static base::LazyInstance<
1132 BrowserContextKeyedAPIFactory<ManagementAPI>>::DestructorAtExit g_factory =
1133 LAZY_INSTANCE_INITIALIZER;
1134
1135 // static
1136 BrowserContextKeyedAPIFactory<ManagementAPI>*
GetFactoryInstance()1137 ManagementAPI::GetFactoryInstance() {
1138 return g_factory.Pointer();
1139 }
1140
OnListenerAdded(const EventListenerInfo & details)1141 void ManagementAPI::OnListenerAdded(const EventListenerInfo& details) {
1142 management_event_router_.reset(new ManagementEventRouter(browser_context_));
1143 EventRouter::Get(browser_context_)->UnregisterObserver(this);
1144 }
1145
1146 } // namespace extensions
1147