Chromium Code Reviews| 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/common/extensions/extension.h" | 5 #include "chrome/common/extensions/extension.h" |
| 6 | 6 |
| 7 #include <ostream> | |
| 8 | |
| 7 #include "base/base64.h" | 9 #include "base/base64.h" |
| 8 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
| 9 #include "base/command_line.h" | 11 #include "base/command_line.h" |
| 10 #include "base/file_path.h" | 12 #include "base/file_path.h" |
| 11 #include "base/file_util.h" | 13 #include "base/file_util.h" |
| 12 #include "base/i18n/rtl.h" | 14 #include "base/i18n/rtl.h" |
| 13 #include "base/logging.h" | 15 #include "base/logging.h" |
| 14 #include "base/memory/singleton.h" | 16 #include "base/memory/singleton.h" |
| 15 #include "base/stl_util.h" | 17 #include "base/stl_util.h" |
| 16 #include "base/string16.h" | 18 #include "base/string16.h" |
| (...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 408 const std::string Extension::VersionString() const { | 410 const std::string Extension::VersionString() const { |
| 409 return version()->GetString(); | 411 return version()->GetString(); |
| 410 } | 412 } |
| 411 | 413 |
| 412 void Extension::AddInstallWarnings( | 414 void Extension::AddInstallWarnings( |
| 413 const InstallWarningVector& new_warnings) { | 415 const InstallWarningVector& new_warnings) { |
| 414 install_warnings_.insert(install_warnings_.end(), | 416 install_warnings_.insert(install_warnings_.end(), |
| 415 new_warnings.begin(), new_warnings.end()); | 417 new_warnings.begin(), new_warnings.end()); |
| 416 } | 418 } |
| 417 | 419 |
| 420 void Extension::AddDeveloperInstallWarning( | |
| 421 InstallWarning::Format format, | |
| 422 const std::string& message) { | |
| 423 if (location() == LOAD) | |
|
not at google - send to devlin
2012/06/18 22:59:41
Install warnings only show up when developer mode
Jeffrey Yasskin
2012/06/18 23:58:42
My idea here was that it would show up for extensi
not at google - send to devlin
2012/06/19 00:27:32
Yeah, makes sense. I'm just saying that this happe
| |
| 424 install_warnings_.push_back(InstallWarning(format, message)); | |
| 425 } | |
| 426 | |
| 418 // static | 427 // static |
| 419 bool Extension::IsExtension(const FilePath& file_name) { | 428 bool Extension::IsExtension(const FilePath& file_name) { |
| 420 return file_name.MatchesExtension(chrome::kExtensionFileExtension); | 429 return file_name.MatchesExtension(chrome::kExtensionFileExtension); |
| 421 } | 430 } |
| 422 | 431 |
| 423 // static | 432 // static |
| 424 bool Extension::IdIsValid(const std::string& id) { | 433 bool Extension::IdIsValid(const std::string& id) { |
| 425 // Verify that the id is legal. | 434 // Verify that the id is legal. |
| 426 if (id.size() != (kIdSize * 2)) | 435 if (id.size() != (kIdSize * 2)) |
| 427 return false; | 436 return false; |
| (...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 794 return false; | 803 return false; |
| 795 } | 804 } |
| 796 | 805 |
| 797 (instance->*add_method)(glob); | 806 (instance->*add_method)(glob); |
| 798 } | 807 } |
| 799 | 808 |
| 800 return true; | 809 return true; |
| 801 } | 810 } |
| 802 | 811 |
| 803 scoped_ptr<ExtensionAction> Extension::LoadExtensionActionHelper( | 812 scoped_ptr<ExtensionAction> Extension::LoadExtensionActionHelper( |
| 804 const DictionaryValue* extension_action, string16* error) { | 813 const DictionaryValue* extension_action, |
| 814 ExtensionAction::Type action_type, | |
| 815 string16* error) { | |
| 805 scoped_ptr<ExtensionAction> result(new ExtensionAction(id())); | 816 scoped_ptr<ExtensionAction> result(new ExtensionAction(id())); |
| 806 | 817 |
| 807 // Page actions are hidden by default, and browser actions ignore | 818 // Page actions are hidden by default, and browser actions ignore |
| 808 // visibility. | 819 // visibility. |
| 809 result->SetIsVisible(ExtensionAction::kDefaultTabId, false); | 820 result->SetIsVisible(ExtensionAction::kDefaultTabId, false); |
| 810 | 821 |
| 811 if (manifest_version_ == 1) { | 822 if (manifest_version_ == 1) { |
| 812 ListValue* icons = NULL; | 823 ListValue* icons = NULL; |
| 813 if (extension_action->HasKey(keys::kPageActionIcons) && | 824 if (extension_action->HasKey(keys::kPageActionIcons) && |
| 814 extension_action->GetList(keys::kPageActionIcons, &icons)) { | 825 extension_action->GetList(keys::kPageActionIcons, &icons)) { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 830 *error = ASCIIToUTF16(errors::kInvalidPageActionId); | 841 *error = ASCIIToUTF16(errors::kInvalidPageActionId); |
| 831 return scoped_ptr<ExtensionAction>(); | 842 return scoped_ptr<ExtensionAction>(); |
| 832 } | 843 } |
| 833 result->set_id(id); | 844 result->set_id(id); |
| 834 } | 845 } |
| 835 } | 846 } |
| 836 | 847 |
| 837 std::string default_icon; | 848 std::string default_icon; |
| 838 // Read the page action |default_icon| (optional). | 849 // Read the page action |default_icon| (optional). |
| 839 if (extension_action->HasKey(keys::kPageActionDefaultIcon)) { | 850 if (extension_action->HasKey(keys::kPageActionDefaultIcon)) { |
| 840 if (!extension_action->GetString(keys::kPageActionDefaultIcon, | 851 if (action_type == ExtensionAction::TYPE_SCRIPT_BADGE) { |
| 841 &default_icon) || | 852 AddDeveloperInstallWarning(InstallWarning::FORMAT_TEXT, |
| 842 default_icon.empty()) { | 853 errors::kScriptBadgeIconIgnored); |
| 843 *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath); | 854 } else { |
| 844 return scoped_ptr<ExtensionAction>(); | 855 if (!extension_action->GetString(keys::kPageActionDefaultIcon, |
| 856 &default_icon) || | |
| 857 default_icon.empty()) { | |
| 858 *error = ASCIIToUTF16(errors::kInvalidPageActionIconPath); | |
| 859 return scoped_ptr<ExtensionAction>(); | |
| 860 } | |
| 861 result->set_default_icon_path(default_icon); | |
| 845 } | 862 } |
| 846 result->set_default_icon_path(default_icon); | |
| 847 } | 863 } |
| 848 | 864 |
| 849 // Read the page action title from |default_title| if present, |name| if not | 865 // Read the page action title from |default_title| if present, |name| if not |
| 850 // (both optional). | 866 // (both optional). |
| 851 std::string title; | 867 std::string title; |
| 852 if (extension_action->HasKey(keys::kPageActionDefaultTitle)) { | 868 if (extension_action->HasKey(keys::kPageActionDefaultTitle)) { |
| 853 if (!extension_action->GetString(keys::kPageActionDefaultTitle, &title)) { | 869 if (!extension_action->GetString(keys::kPageActionDefaultTitle, &title)) { |
| 854 *error = ASCIIToUTF16(errors::kInvalidPageActionDefaultTitle); | 870 *error = ASCIIToUTF16(errors::kInvalidPageActionDefaultTitle); |
| 855 return scoped_ptr<ExtensionAction>(); | 871 return scoped_ptr<ExtensionAction>(); |
| 856 } | 872 } |
| (...skipping 1162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2019 string16* error) { | 2035 string16* error) { |
| 2020 if (manifest_->HasKey(keys::kConvertedFromUserScript)) | 2036 if (manifest_->HasKey(keys::kConvertedFromUserScript)) |
| 2021 manifest_->GetBoolean(keys::kConvertedFromUserScript, | 2037 manifest_->GetBoolean(keys::kConvertedFromUserScript, |
| 2022 &converted_from_user_script_); | 2038 &converted_from_user_script_); |
| 2023 | 2039 |
| 2024 if (!LoadDevToolsPage(error) || | 2040 if (!LoadDevToolsPage(error) || |
| 2025 !LoadInputComponents(api_permissions, error) || | 2041 !LoadInputComponents(api_permissions, error) || |
| 2026 !LoadContentScripts(error) || | 2042 !LoadContentScripts(error) || |
| 2027 !LoadPageAction(error) || | 2043 !LoadPageAction(error) || |
| 2028 !LoadBrowserAction(error) || | 2044 !LoadBrowserAction(error) || |
| 2045 !LoadScriptBadge(error) || | |
| 2029 !LoadFileBrowserHandlers(error) || | 2046 !LoadFileBrowserHandlers(error) || |
| 2030 !LoadChromeURLOverrides(error) || | 2047 !LoadChromeURLOverrides(error) || |
| 2031 !LoadOmnibox(error) || | 2048 !LoadOmnibox(error) || |
| 2032 !LoadTextToSpeechVoices(error) || | 2049 !LoadTextToSpeechVoices(error) || |
| 2033 !LoadIncognitoMode(error) || | 2050 !LoadIncognitoMode(error) || |
| 2034 !LoadContentSecurityPolicy(error)) | 2051 !LoadContentSecurityPolicy(error)) |
| 2035 return false; | 2052 return false; |
| 2036 | 2053 |
| 2037 return true; | 2054 return true; |
| 2038 } | 2055 } |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2239 } | 2256 } |
| 2240 } else if (manifest_->HasKey(keys::kPageAction)) { | 2257 } else if (manifest_->HasKey(keys::kPageAction)) { |
| 2241 if (!manifest_->GetDictionary(keys::kPageAction, &page_action_value)) { | 2258 if (!manifest_->GetDictionary(keys::kPageAction, &page_action_value)) { |
| 2242 *error = ASCIIToUTF16(errors::kInvalidPageAction); | 2259 *error = ASCIIToUTF16(errors::kInvalidPageAction); |
| 2243 return false; | 2260 return false; |
| 2244 } | 2261 } |
| 2245 } | 2262 } |
| 2246 | 2263 |
| 2247 // If page_action_value is not NULL, then there was a valid page action. | 2264 // If page_action_value is not NULL, then there was a valid page action. |
| 2248 if (page_action_value) { | 2265 if (page_action_value) { |
| 2249 page_action_ = LoadExtensionActionHelper(page_action_value, error); | 2266 page_action_ = LoadExtensionActionHelper( |
| 2267 page_action_value, ExtensionAction::TYPE_PAGE, error); | |
| 2250 if (!page_action_.get()) | 2268 if (!page_action_.get()) |
| 2251 return false; // Failed to parse page action definition. | 2269 return false; // Failed to parse page action definition. |
| 2252 declared_action_type_ = ExtensionAction::TYPE_PAGE; | 2270 declared_action_type_ = ExtensionAction::TYPE_PAGE; |
| 2253 | 2271 |
| 2254 // The action box changes the meaning of the page action area, so we need | 2272 // The action box changes the meaning of the page action area, so we need |
| 2255 // to convert page actions into browser actions. | 2273 // to convert page actions into browser actions. |
| 2256 if (switch_utils::IsActionBoxEnabled()) { | 2274 if (switch_utils::IsActionBoxEnabled()) { |
| 2257 browser_action_ = page_action_.Pass(); | 2275 browser_action_ = page_action_.Pass(); |
| 2258 // declared_action_type_ stays the same; that's the point. | 2276 // declared_action_type_ stays the same; that's the point. |
| 2259 } | 2277 } |
| 2260 } | 2278 } |
| 2261 | 2279 |
| 2262 return true; | 2280 return true; |
| 2263 } | 2281 } |
| 2264 | 2282 |
| 2265 bool Extension::LoadBrowserAction(string16* error) { | 2283 bool Extension::LoadBrowserAction(string16* error) { |
| 2266 if (!manifest_->HasKey(keys::kBrowserAction)) | 2284 if (!manifest_->HasKey(keys::kBrowserAction)) |
| 2267 return true; | 2285 return true; |
| 2268 DictionaryValue* browser_action_value = NULL; | 2286 DictionaryValue* browser_action_value = NULL; |
| 2269 if (!manifest_->GetDictionary(keys::kBrowserAction, &browser_action_value)) { | 2287 if (!manifest_->GetDictionary(keys::kBrowserAction, &browser_action_value)) { |
| 2270 *error = ASCIIToUTF16(errors::kInvalidBrowserAction); | 2288 *error = ASCIIToUTF16(errors::kInvalidBrowserAction); |
| 2271 return false; | 2289 return false; |
| 2272 } | 2290 } |
| 2273 | 2291 |
| 2274 browser_action_ = LoadExtensionActionHelper(browser_action_value, error); | 2292 browser_action_ = LoadExtensionActionHelper( |
| 2293 browser_action_value, ExtensionAction::TYPE_BROWSER, error); | |
| 2275 if (!browser_action_.get()) | 2294 if (!browser_action_.get()) |
| 2276 return false; // Failed to parse browser action definition. | 2295 return false; // Failed to parse browser action definition. |
| 2277 declared_action_type_ = ExtensionAction::TYPE_BROWSER; | 2296 declared_action_type_ = ExtensionAction::TYPE_BROWSER; |
| 2278 return true; | 2297 return true; |
| 2279 } | 2298 } |
| 2280 | 2299 |
| 2300 bool Extension::LoadScriptBadge(string16* error) { | |
| 2301 DictionaryValue* script_badge_value = NULL; | |
| 2302 | |
| 2303 if (!switch_utils::IsActionBoxEnabled()) { | |
|
not at google - send to devlin
2012/06/18 22:59:41
(has been submitted now btw)
Jeffrey Yasskin
2012/06/18 23:58:42
And I've now synced past it.
| |
| 2304 if (manifest_->HasKey(keys::kScriptBadge)) { | |
| 2305 AddDeveloperInstallWarning(InstallWarning::FORMAT_TEXT, | |
| 2306 errors::kScriptBadgeRequiresActionBox); | |
| 2307 } | |
| 2308 return true; | |
|
not at google - send to devlin
2012/06/18 22:59:41
Could we just generate a warning here and not earl
Jeffrey Yasskin
2012/06/18 23:58:42
Sure. Then script_badge_ should never be null.
| |
| 2309 } | |
| 2310 | |
| 2311 if (manifest_->HasKey(keys::kScriptBadge)) { | |
| 2312 if (!manifest_->GetDictionary(keys::kScriptBadge, &script_badge_value)) { | |
| 2313 *error = ASCIIToUTF16(errors::kInvalidScriptBadge); | |
| 2314 return false; | |
| 2315 } | |
| 2316 script_badge_ = LoadExtensionActionHelper( | |
| 2317 script_badge_value, ExtensionAction::TYPE_SCRIPT_BADGE, error); | |
| 2318 if (!script_badge_.get()) | |
| 2319 return false; // Failed to parse script badge definition. | |
| 2320 declared_action_type_ = ExtensionAction::TYPE_SCRIPT_BADGE; | |
| 2321 } else { | |
| 2322 script_badge_.reset(new ExtensionAction(id())); | |
| 2323 | |
| 2324 // Make sure there is always a title. | |
| 2325 script_badge_->SetTitle(ExtensionAction::kDefaultTabId, name()); | |
| 2326 } | |
| 2327 | |
| 2328 // Script badges always use their extension's icon so users can rely on the | |
| 2329 // visual appearance to know which extension is running. This isn't | |
| 2330 // bulletproof since an malicious extension could use a different 16x16 icon | |
| 2331 // that matches the icon of a trusted extension, and users wouldn't be warned | |
| 2332 // during installation. | |
| 2333 | |
| 2334 script_badge_->set_default_icon_path( | |
| 2335 icons().Get(ExtensionIconSet::EXTENSION_ICON_BITTY, | |
| 2336 ExtensionIconSet::MATCH_BIGGER)); | |
| 2337 | |
| 2338 script_badge_->SetIsVisible(ExtensionAction::kDefaultTabId, true); | |
| 2339 | |
| 2340 return true; | |
| 2341 } | |
| 2342 | |
| 2281 bool Extension::LoadFileBrowserHandlers(string16* error) { | 2343 bool Extension::LoadFileBrowserHandlers(string16* error) { |
| 2282 if (!manifest_->HasKey(keys::kFileBrowserHandlers)) | 2344 if (!manifest_->HasKey(keys::kFileBrowserHandlers)) |
| 2283 return true; | 2345 return true; |
| 2284 ListValue* file_browser_handlers_value = NULL; | 2346 ListValue* file_browser_handlers_value = NULL; |
| 2285 if (!manifest_->GetList(keys::kFileBrowserHandlers, | 2347 if (!manifest_->GetList(keys::kFileBrowserHandlers, |
| 2286 &file_browser_handlers_value)) { | 2348 &file_browser_handlers_value)) { |
| 2287 *error = ASCIIToUTF16(errors::kInvalidFileBrowserHandler); | 2349 *error = ASCIIToUTF16(errors::kInvalidFileBrowserHandler); |
| 2288 return false; | 2350 return false; |
| 2289 } | 2351 } |
| 2290 file_browser_handlers_.reset( | 2352 file_browser_handlers_.reset( |
| (...skipping 1319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3610 // We want to sync any extensions that are internal and the chrome web store. | 3672 // We want to sync any extensions that are internal and the chrome web store. |
| 3611 return location() == Extension::INTERNAL || | 3673 return location() == Extension::INTERNAL || |
| 3612 id() == extension_misc::kWebStoreAppId; | 3674 id() == extension_misc::kWebStoreAppId; |
| 3613 } | 3675 } |
| 3614 | 3676 |
| 3615 bool Extension::ShouldDisplayInLauncher() const { | 3677 bool Extension::ShouldDisplayInLauncher() const { |
| 3616 // All apps should be displayed on the NTP except for the Cloud Print App. | 3678 // All apps should be displayed on the NTP except for the Cloud Print App. |
| 3617 return is_app() && id() != extension_misc::kCloudPrintAppId; | 3679 return is_app() && id() != extension_misc::kCloudPrintAppId; |
| 3618 } | 3680 } |
| 3619 | 3681 |
| 3682 bool Extension::InstallWarning::operator==(const InstallWarning& other) const { | |
| 3683 return format == other.format && message == other.message; | |
| 3684 } | |
| 3685 | |
| 3686 void PrintTo(const Extension::InstallWarning& warning, ::std::ostream* os){ | |
| 3687 *os << "InstallWarning("; | |
| 3688 switch (warning.format) { | |
| 3689 case Extension::InstallWarning::FORMAT_TEXT: | |
| 3690 *os << "FORMAT_TEXT, \""; | |
| 3691 break; | |
| 3692 case Extension::InstallWarning::FORMAT_HTML: | |
| 3693 *os << "FORMAT_HTML, \""; | |
| 3694 break; | |
| 3695 } | |
| 3696 // This is just for test error messages, so no need to escape '"' | |
| 3697 // characters inside the message. | |
| 3698 *os << warning.message << "\")"; | |
| 3699 } | |
| 3700 | |
| 3620 ExtensionInfo::ExtensionInfo(const DictionaryValue* manifest, | 3701 ExtensionInfo::ExtensionInfo(const DictionaryValue* manifest, |
| 3621 const std::string& id, | 3702 const std::string& id, |
| 3622 const FilePath& path, | 3703 const FilePath& path, |
| 3623 Extension::Location location) | 3704 Extension::Location location) |
| 3624 : extension_id(id), | 3705 : extension_id(id), |
| 3625 extension_path(path), | 3706 extension_path(path), |
| 3626 extension_location(location) { | 3707 extension_location(location) { |
| 3627 if (manifest) | 3708 if (manifest) |
| 3628 extension_manifest.reset(manifest->DeepCopy()); | 3709 extension_manifest.reset(manifest->DeepCopy()); |
| 3629 } | 3710 } |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 3657 | 3738 |
| 3658 bool Extension::HasContentScriptAtURL(const GURL& url) const { | 3739 bool Extension::HasContentScriptAtURL(const GURL& url) const { |
| 3659 for (UserScriptList::const_iterator it = content_scripts_.begin(); | 3740 for (UserScriptList::const_iterator it = content_scripts_.begin(); |
| 3660 it != content_scripts_.end(); ++it) { | 3741 it != content_scripts_.end(); ++it) { |
| 3661 if (it->MatchesURL(url)) | 3742 if (it->MatchesURL(url)) |
| 3662 return true; | 3743 return true; |
| 3663 } | 3744 } |
| 3664 return false; | 3745 return false; |
| 3665 } | 3746 } |
| 3666 | 3747 |
| 3667 ExtensionAction* Extension::GetScriptBadge() const { | |
| 3668 if (!script_badge_.get()) { | |
| 3669 script_badge_.reset(new ExtensionAction(id())); | |
| 3670 | |
| 3671 // On initialization, copy the default icon path from the browser action, | |
| 3672 // or generate a puzzle piece if there isn't one. Extensions may later | |
| 3673 // overwrite this icon using the browserAction API. | |
| 3674 if (browser_action() && !browser_action()->default_icon_path().empty()) { | |
| 3675 script_badge_->set_default_icon_path( | |
| 3676 browser_action()->default_icon_path()); | |
| 3677 } else { | |
| 3678 script_badge_->SetIcon( | |
| 3679 ExtensionAction::kDefaultTabId, | |
| 3680 *ui::ResourceBundle::GetSharedInstance().GetImageNamed( | |
| 3681 IDR_EXTENSIONS_FAVICON).ToSkBitmap()); | |
| 3682 } | |
| 3683 | |
| 3684 // Likewise, make sure there is always a title. | |
| 3685 script_badge_->SetTitle(ExtensionAction::kDefaultTabId, name()); | |
| 3686 } | |
| 3687 | |
| 3688 // Every time, re-initialize the script badge based on the current state of | |
| 3689 // the browser action. | |
| 3690 int kDefaultTabId = ExtensionAction::kDefaultTabId; | |
| 3691 | |
| 3692 script_badge_->SetIsVisible(kDefaultTabId, true); | |
| 3693 | |
| 3694 if (browser_action()) { | |
| 3695 SkBitmap icon = browser_action()->GetIcon(kDefaultTabId); | |
| 3696 if (!icon.isNull()) | |
| 3697 script_badge_->SetIcon(kDefaultTabId, icon); | |
| 3698 | |
| 3699 std::string title = browser_action()->GetTitle(kDefaultTabId); | |
| 3700 if (!title.empty()) | |
| 3701 script_badge_->SetTitle(kDefaultTabId, title); | |
| 3702 } | |
| 3703 | |
| 3704 return script_badge_.get(); | |
| 3705 } | |
| 3706 | |
| 3707 const URLPatternSet* Extension::GetTabSpecificHostPermissions( | 3748 const URLPatternSet* Extension::GetTabSpecificHostPermissions( |
| 3708 int tab_id) const { | 3749 int tab_id) const { |
| 3709 base::AutoLock auto_lock(runtime_data_lock_); | 3750 base::AutoLock auto_lock(runtime_data_lock_); |
| 3710 return runtime_data_.GetTabSpecificHostPermissions(tab_id); | 3751 return runtime_data_.GetTabSpecificHostPermissions(tab_id); |
| 3711 } | 3752 } |
| 3712 | 3753 |
| 3713 void Extension::SetTabSpecificHostPermissions( | 3754 void Extension::SetTabSpecificHostPermissions( |
| 3714 int tab_id, | 3755 int tab_id, |
| 3715 const URLPatternSet& permissions) const { | 3756 const URLPatternSet& permissions) const { |
| 3716 base::AutoLock auto_lock(runtime_data_lock_); | 3757 base::AutoLock auto_lock(runtime_data_lock_); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3797 | 3838 |
| 3798 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo( | 3839 UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo( |
| 3799 const Extension* extension, | 3840 const Extension* extension, |
| 3800 const ExtensionPermissionSet* permissions, | 3841 const ExtensionPermissionSet* permissions, |
| 3801 Reason reason) | 3842 Reason reason) |
| 3802 : reason(reason), | 3843 : reason(reason), |
| 3803 extension(extension), | 3844 extension(extension), |
| 3804 permissions(permissions) {} | 3845 permissions(permissions) {} |
| 3805 | 3846 |
| 3806 } // namespace extensions | 3847 } // namespace extensions |
| OLD | NEW |