extension_management_api.cc revision 72a454cd3513ac24fbdd0e0cb9ad70b86a99b801
1// Copyright (c) 2010 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 "chrome/browser/extensions/extension_management_api.h" 6 7#include <map> 8#include <string> 9 10#include "base/basictypes.h" 11#include "base/json/json_writer.h" 12#include "base/string_number_conversions.h" 13#include "base/string_util.h" 14#include "chrome/browser/extensions/extension_event_names.h" 15#include "chrome/browser/extensions/extension_event_router.h" 16#include "chrome/browser/extensions/extension_service.h" 17#include "chrome/browser/extensions/extension_updater.h" 18#include "chrome/browser/profiles/profile.h" 19#include "chrome/browser/ui/browser.h" 20#include "chrome/common/extensions/extension_constants.h" 21#include "chrome/common/extensions/extension_error_utils.h" 22#include "chrome/common/extensions/extension.h" 23#include "chrome/common/extensions/extension_icon_set.h" 24#include "chrome/common/extensions/url_pattern.h" 25#include "chrome/common/notification_service.h" 26#include "chrome/common/notification_type.h" 27 28using base::IntToString; 29namespace events = extension_event_names; 30 31namespace { 32 33const char kAppLaunchUrlKey[] = "appLaunchUrl"; 34const char kDescriptionKey[] = "description"; 35const char kEnabledKey[] = "enabled"; 36const char kIconsKey[] = "icons"; 37const char kIdKey[] = "id"; 38const char kIsAppKey[] = "isApp"; 39const char kNameKey[] = "name"; 40const char kOptionsUrlKey[] = "optionsUrl"; 41const char kPermissionsKey[] = "permissions"; 42const char kSizeKey[] = "size"; 43const char kUrlKey[] = "url"; 44const char kVersionKey[] = "version"; 45 46const char kNoExtensionError[] = "No extension with id *"; 47const char kNotAnAppError[] = "Extension * is not an App"; 48} 49 50ExtensionService* ExtensionManagementFunction::service() { 51 return profile()->GetExtensionService(); 52} 53 54static DictionaryValue* CreateExtensionInfo(const Extension& extension, 55 bool enabled) { 56 DictionaryValue* info = new DictionaryValue(); 57 info->SetString(kIdKey, extension.id()); 58 info->SetBoolean(kIsAppKey, extension.is_app()); 59 info->SetString(kNameKey, extension.name()); 60 info->SetBoolean(kEnabledKey, enabled); 61 info->SetString(kVersionKey, extension.VersionString()); 62 info->SetString(kDescriptionKey, extension.description()); 63 info->SetString(kOptionsUrlKey, 64 extension.options_url().possibly_invalid_spec()); 65 if (extension.is_app()) 66 info->SetString(kAppLaunchUrlKey, 67 extension.GetFullLaunchURL().possibly_invalid_spec()); 68 69 const ExtensionIconSet::IconMap& icons = extension.icons().map(); 70 if (!icons.empty()) { 71 ListValue* icon_list = new ListValue(); 72 std::map<int, std::string>::const_iterator icon_iter; 73 for (icon_iter = icons.begin(); icon_iter != icons.end(); ++icon_iter) { 74 DictionaryValue* icon_info = new DictionaryValue(); 75 GURL url = extension.GetResourceURL(icon_iter->second); 76 icon_info->SetInteger(kSizeKey, icon_iter->first); 77 icon_info->SetString(kUrlKey, url.possibly_invalid_spec()); 78 icon_list->Append(icon_info); 79 } 80 info->Set("icons", icon_list); 81 } 82 83 const std::set<std::string> perms = extension.api_permissions(); 84 ListValue* permission_list = new ListValue(); 85 if (!perms.empty()) { 86 std::set<std::string>::const_iterator perms_iter; 87 for (perms_iter = perms.begin(); perms_iter != perms.end(); ++perms_iter) { 88 StringValue* permission_name = new StringValue(*perms_iter); 89 permission_list->Append(permission_name); 90 } 91 } 92 info->Set("permissions", permission_list); 93 94 ListValue* host_permission_list = new ListValue(); 95 if (!extension.is_hosted_app()) { 96 // Skip host permissions for hosted apps. 97 const URLPatternList host_perms = extension.host_permissions(); 98 if (!host_perms.empty()) { 99 std::vector<URLPattern>::const_iterator host_perms_iter; 100 for (host_perms_iter = host_perms.begin(); 101 host_perms_iter != host_perms.end(); 102 ++host_perms_iter) { 103 StringValue* name = new StringValue(host_perms_iter->GetAsString()); 104 host_permission_list->Append(name); 105 } 106 } 107 } 108 info->Set("hostPermissions", host_permission_list); 109 110 return info; 111} 112 113static void AddExtensionInfo(ListValue* list, 114 const ExtensionList& extensions, 115 bool enabled) { 116 for (ExtensionList::const_iterator i = extensions.begin(); 117 i != extensions.end(); ++i) { 118 const Extension& extension = **i; 119 120 if (extension.location() == Extension::COMPONENT) 121 continue; // Skip built-in extensions. 122 123 list->Append(CreateExtensionInfo(extension, enabled)); 124 } 125} 126 127bool GetAllExtensionsFunction::RunImpl() { 128 ListValue* result = new ListValue(); 129 result_.reset(result); 130 131 AddExtensionInfo(result, *service()->extensions(), true); 132 AddExtensionInfo(result, *service()->disabled_extensions(), false); 133 134 return true; 135} 136 137bool GetExtensionByIdFunction::RunImpl() { 138 std::string extension_id; 139 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &extension_id)); 140 const Extension* extension = service()->GetExtensionById(extension_id, true); 141 if (!extension) { 142 error_ = ExtensionErrorUtils::FormatErrorMessage(kNoExtensionError, 143 extension_id); 144 return false; 145 } 146 bool enabled = service()->extension_prefs()-> 147 GetExtensionState(extension_id) == Extension::ENABLED; 148 149 DictionaryValue* result = CreateExtensionInfo(*extension, enabled); 150 result_.reset(result); 151 152 return true; 153} 154 155bool LaunchAppFunction::RunImpl() { 156 std::string extension_id; 157 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &extension_id)); 158 const Extension* extension = service()->GetExtensionById(extension_id, true); 159 if (!extension) { 160 error_ = ExtensionErrorUtils::FormatErrorMessage(kNoExtensionError, 161 extension_id); 162 return false; 163 } 164 if (!extension->is_app()) { 165 error_ = ExtensionErrorUtils::FormatErrorMessage(kNotAnAppError, 166 extension_id); 167 return false; 168 } 169 170 // Look at prefs to find the right launch container. 171 // |default_pref_value| is set to LAUNCH_REGULAR so that if 172 // the user has not set a preference, we open the app in a tab. 173 extension_misc::LaunchContainer launch_container = 174 service()->extension_prefs()->GetLaunchContainer( 175 extension, ExtensionPrefs::LAUNCH_DEFAULT); 176 Browser::OpenApplication(profile(), extension, launch_container, NULL); 177 178 return true; 179} 180 181bool SetEnabledFunction::RunImpl() { 182 std::string extension_id; 183 bool enable; 184 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &extension_id)); 185 EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(1, &enable)); 186 187 if (!service()->GetExtensionById(extension_id, true)) { 188 error_ = ExtensionErrorUtils::FormatErrorMessage( 189 kNoExtensionError, extension_id); 190 return false; 191 } 192 193 ExtensionPrefs* prefs = service()->extension_prefs(); 194 Extension::State state = prefs->GetExtensionState(extension_id); 195 196 if (state == Extension::DISABLED && enable) { 197 service()->EnableExtension(extension_id); 198 } else if (state == Extension::ENABLED && !enable) { 199 service()->DisableExtension(extension_id); 200 } 201 202 return true; 203} 204 205bool UninstallFunction::RunImpl() { 206 std::string extension_id; 207 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &extension_id)); 208 209 if (!service()->GetExtensionById(extension_id, true)) { 210 error_ = ExtensionErrorUtils::FormatErrorMessage( 211 kNoExtensionError, extension_id); 212 return false; 213 } 214 215 service()->UninstallExtension(extension_id, false /* external_uninstall */); 216 return true; 217} 218 219// static 220ExtensionManagementEventRouter* ExtensionManagementEventRouter::GetInstance() { 221 return Singleton<ExtensionManagementEventRouter>::get(); 222} 223 224ExtensionManagementEventRouter::ExtensionManagementEventRouter() {} 225 226ExtensionManagementEventRouter::~ExtensionManagementEventRouter() {} 227 228void ExtensionManagementEventRouter::Init() { 229 NotificationType::Type types[] = { 230 NotificationType::EXTENSION_INSTALLED, 231 NotificationType::EXTENSION_UNINSTALLED, 232 NotificationType::EXTENSION_LOADED, 233 NotificationType::EXTENSION_UNLOADED 234 }; 235 236 for (size_t i = 0; i < arraysize(types); i++) { 237 registrar_.Add(this, 238 types[i], 239 NotificationService::AllSources()); 240 } 241} 242 243void ExtensionManagementEventRouter::Observe( 244 NotificationType type, 245 const NotificationSource& source, 246 const NotificationDetails& details) { 247 const char* event_name = NULL; 248 switch (type.value) { 249 case NotificationType::EXTENSION_INSTALLED: 250 event_name = events::kOnExtensionInstalled; 251 break; 252 case NotificationType::EXTENSION_UNINSTALLED: 253 event_name = events::kOnExtensionUninstalled; 254 break; 255 case NotificationType::EXTENSION_LOADED: 256 event_name = events::kOnExtensionEnabled; 257 break; 258 case NotificationType::EXTENSION_UNLOADED: 259 event_name = events::kOnExtensionDisabled; 260 break; 261 default: 262 NOTREACHED(); 263 return; 264 } 265 266 Profile* profile = Source<Profile>(source).ptr(); 267 CHECK(profile); 268 269 ListValue args; 270 if (event_name == events::kOnExtensionUninstalled) { 271 const std::string& extension_id = 272 Details<UninstalledExtensionInfo>(details).ptr()->extension_id; 273 args.Append(Value::CreateStringValue(extension_id)); 274 } else { 275 const Extension* extension = NULL; 276 if (event_name == events::kOnExtensionDisabled) { 277 extension = Details<UnloadedExtensionInfo>(details)->extension; 278 } else { 279 extension = Details<const Extension>(details).ptr(); 280 } 281 CHECK(extension); 282 ExtensionService* service = profile->GetExtensionService(); 283 bool enabled = service->GetExtensionById(extension->id(), false) != NULL; 284 args.Append(CreateExtensionInfo(*extension, enabled)); 285 } 286 287 std::string args_json; 288 base::JSONWriter::Write(&args, false /* pretty_print */, &args_json); 289 290 profile->GetExtensionEventRouter()->DispatchEventToRenderers( 291 event_name, args_json, NULL, GURL()); 292} 293