Home | History | Annotate | Download | only in preference
      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 "chrome/browser/extensions/api/preference/preference_api.h"
      6 
      7 #include <map>
      8 #include <utility>
      9 
     10 #include "base/lazy_instance.h"
     11 #include "base/memory/singleton.h"
     12 #include "base/prefs/pref_service.h"
     13 #include "base/stl_util.h"
     14 #include "base/strings/stringprintf.h"
     15 #include "base/values.h"
     16 #include "chrome/browser/chrome_notification_types.h"
     17 #include "chrome/browser/extensions/api/content_settings/content_settings_service.h"
     18 #include "chrome/browser/extensions/api/preference/preference_api_constants.h"
     19 #include "chrome/browser/extensions/api/preference/preference_helpers.h"
     20 #include "chrome/browser/extensions/api/proxy/proxy_api.h"
     21 #include "chrome/browser/extensions/extension_service.h"
     22 #include "chrome/browser/profiles/profile.h"
     23 #include "chrome/common/pref_names.h"
     24 #include "components/translate/core/common/translate_pref_names.h"
     25 #include "content/public/browser/notification_details.h"
     26 #include "content/public/browser/notification_source.h"
     27 #include "extensions/browser/extension_pref_value_map.h"
     28 #include "extensions/browser/extension_pref_value_map_factory.h"
     29 #include "extensions/browser/extension_prefs.h"
     30 #include "extensions/browser/extension_prefs_factory.h"
     31 #include "extensions/browser/extension_system_provider.h"
     32 #include "extensions/browser/extensions_browser_client.h"
     33 #include "extensions/browser/pref_names.h"
     34 #include "extensions/common/error_utils.h"
     35 #include "extensions/common/permissions/api_permission.h"
     36 #include "extensions/common/permissions/permissions_data.h"
     37 
     38 namespace keys = extensions::preference_api_constants;
     39 namespace helpers = extensions::preference_helpers;
     40 
     41 using base::DictionaryValue;
     42 
     43 namespace extensions {
     44 
     45 namespace {
     46 
     47 struct PrefMappingEntry {
     48   // Name of the preference referenced by the extension API JSON.
     49   const char* extension_pref;
     50 
     51   // Name of the preference in the PrefStores.
     52   const char* browser_pref;
     53 
     54   // Permission required to read and observe this preference.
     55   // Use APIPermission::kInvalid for |read_permission| to express that the read
     56   // permission should not be granted.
     57   APIPermission::ID read_permission;
     58 
     59   // Permission required to write this preference.
     60   // Use APIPermission::kInvalid for |write_permission| to express that the
     61   // write permission should not be granted.
     62   APIPermission::ID write_permission;
     63 };
     64 
     65 const char kOnPrefChangeFormat[] = "types.ChromeSetting.%s.onChange";
     66 const char kConversionErrorMessage[] =
     67     "Internal error: Stored value for preference '*' cannot be converted "
     68     "properly.";
     69 
     70 PrefMappingEntry kPrefMapping[] = {
     71     {"protectedContentEnabled", prefs::kEnableDRM, APIPermission::kPrivacy,
     72      APIPermission::kPrivacy},
     73     {"alternateErrorPagesEnabled", prefs::kAlternateErrorPagesEnabled,
     74      APIPermission::kPrivacy, APIPermission::kPrivacy},
     75     {"autofillEnabled", autofill::prefs::kAutofillEnabled,
     76      APIPermission::kPrivacy, APIPermission::kPrivacy},
     77     {"hyperlinkAuditingEnabled", prefs::kEnableHyperlinkAuditing,
     78      APIPermission::kPrivacy, APIPermission::kPrivacy},
     79     {"networkPredictionEnabled", prefs::kNetworkPredictionEnabled,
     80      APIPermission::kPrivacy, APIPermission::kPrivacy},
     81     {"proxy", prefs::kProxy, APIPermission::kProxy, APIPermission::kProxy},
     82     {"referrersEnabled", prefs::kEnableReferrers, APIPermission::kPrivacy,
     83      APIPermission::kPrivacy},
     84     {"safeBrowsingEnabled", prefs::kSafeBrowsingEnabled,
     85      APIPermission::kPrivacy, APIPermission::kPrivacy},
     86     {"searchSuggestEnabled", prefs::kSearchSuggestEnabled,
     87      APIPermission::kPrivacy, APIPermission::kPrivacy},
     88     {"spellingServiceEnabled", prefs::kSpellCheckUseSpellingService,
     89      APIPermission::kPrivacy, APIPermission::kPrivacy},
     90     {"thirdPartyCookiesAllowed", prefs::kBlockThirdPartyCookies,
     91      APIPermission::kPrivacy, APIPermission::kPrivacy},
     92     {"translationServiceEnabled", prefs::kEnableTranslate,
     93      APIPermission::kPrivacy, APIPermission::kPrivacy},
     94 #if defined(OS_CHROMEOS)
     95     {"autoclick", prefs::kAccessibilityAutoclickEnabled,
     96      APIPermission::kAccessibilityFeaturesRead,
     97      APIPermission::kAccessibilityFeaturesModify},
     98     {"highContrast", prefs::kAccessibilityHighContrastEnabled,
     99      APIPermission::kAccessibilityFeaturesRead,
    100      APIPermission::kAccessibilityFeaturesModify},
    101     {"largeCursor", prefs::kAccessibilityLargeCursorEnabled,
    102      APIPermission::kAccessibilityFeaturesRead,
    103      APIPermission::kAccessibilityFeaturesModify},
    104     {"screenMagnifier", prefs::kAccessibilityScreenMagnifierEnabled,
    105      APIPermission::kAccessibilityFeaturesRead,
    106      APIPermission::kAccessibilityFeaturesModify},
    107     {"spokenFeedback", prefs::kAccessibilitySpokenFeedbackEnabled,
    108      APIPermission::kAccessibilityFeaturesRead,
    109      APIPermission::kAccessibilityFeaturesModify},
    110     {"stickyKeys", prefs::kAccessibilityStickyKeysEnabled,
    111      APIPermission::kAccessibilityFeaturesRead,
    112      APIPermission::kAccessibilityFeaturesModify},
    113     {"virtualKeyboard", prefs::kAccessibilityVirtualKeyboardEnabled,
    114      APIPermission::kAccessibilityFeaturesRead,
    115      APIPermission::kAccessibilityFeaturesModify},
    116 #endif
    117 };
    118 
    119 class IdentityPrefTransformer : public PrefTransformerInterface {
    120  public:
    121   virtual base::Value* ExtensionToBrowserPref(const base::Value* extension_pref,
    122                                               std::string* error,
    123                                               bool* bad_message) OVERRIDE {
    124     return extension_pref->DeepCopy();
    125   }
    126 
    127   virtual base::Value* BrowserToExtensionPref(
    128       const base::Value* browser_pref) OVERRIDE {
    129     return browser_pref->DeepCopy();
    130   }
    131 };
    132 
    133 class InvertBooleanTransformer : public PrefTransformerInterface {
    134  public:
    135   virtual base::Value* ExtensionToBrowserPref(const base::Value* extension_pref,
    136                                               std::string* error,
    137                                               bool* bad_message) OVERRIDE {
    138     return InvertBooleanValue(extension_pref);
    139   }
    140 
    141   virtual base::Value* BrowserToExtensionPref(
    142       const base::Value* browser_pref) OVERRIDE {
    143     return InvertBooleanValue(browser_pref);
    144   }
    145 
    146  private:
    147   static base::Value* InvertBooleanValue(const base::Value* value) {
    148     bool bool_value = false;
    149     bool result = value->GetAsBoolean(&bool_value);
    150     DCHECK(result);
    151     return new base::FundamentalValue(!bool_value);
    152   }
    153 };
    154 
    155 class PrefMapping {
    156  public:
    157   static PrefMapping* GetInstance() {
    158     return Singleton<PrefMapping>::get();
    159   }
    160 
    161   bool FindBrowserPrefForExtensionPref(const std::string& extension_pref,
    162                                        std::string* browser_pref,
    163                                        APIPermission::ID* read_permission,
    164                                        APIPermission::ID* write_permission) {
    165     PrefMap::iterator it = mapping_.find(extension_pref);
    166     if (it != mapping_.end()) {
    167       *browser_pref = it->second.pref_name;
    168       *read_permission = it->second.read_permission;
    169       *write_permission = it->second.write_permission;
    170       return true;
    171     }
    172     return false;
    173   }
    174 
    175   bool FindEventForBrowserPref(const std::string& browser_pref,
    176                                std::string* event_name,
    177                                APIPermission::ID* permission) {
    178     PrefMap::iterator it = event_mapping_.find(browser_pref);
    179     if (it != event_mapping_.end()) {
    180       *event_name = it->second.pref_name;
    181       *permission = it->second.read_permission;
    182       return true;
    183     }
    184     return false;
    185   }
    186 
    187   PrefTransformerInterface* FindTransformerForBrowserPref(
    188       const std::string& browser_pref) {
    189     std::map<std::string, PrefTransformerInterface*>::iterator it =
    190         transformers_.find(browser_pref);
    191     if (it != transformers_.end())
    192       return it->second;
    193     else
    194       return identity_transformer_.get();
    195   }
    196 
    197  private:
    198   friend struct DefaultSingletonTraits<PrefMapping>;
    199 
    200   PrefMapping() {
    201     identity_transformer_.reset(new IdentityPrefTransformer());
    202     for (size_t i = 0; i < arraysize(kPrefMapping); ++i) {
    203       mapping_[kPrefMapping[i].extension_pref] =
    204           PrefMapData(kPrefMapping[i].browser_pref,
    205                       kPrefMapping[i].read_permission,
    206                       kPrefMapping[i].write_permission);
    207       std::string event_name =
    208           base::StringPrintf(kOnPrefChangeFormat,
    209                              kPrefMapping[i].extension_pref);
    210       event_mapping_[kPrefMapping[i].browser_pref] =
    211           PrefMapData(event_name,
    212                       kPrefMapping[i].read_permission,
    213                       kPrefMapping[i].write_permission);
    214     }
    215     DCHECK_EQ(arraysize(kPrefMapping), mapping_.size());
    216     DCHECK_EQ(arraysize(kPrefMapping), event_mapping_.size());
    217     RegisterPrefTransformer(prefs::kProxy, new ProxyPrefTransformer());
    218     RegisterPrefTransformer(prefs::kBlockThirdPartyCookies,
    219                             new InvertBooleanTransformer());
    220   }
    221 
    222   ~PrefMapping() {
    223     STLDeleteContainerPairSecondPointers(transformers_.begin(),
    224                                          transformers_.end());
    225   }
    226 
    227   void RegisterPrefTransformer(const std::string& browser_pref,
    228                                PrefTransformerInterface* transformer) {
    229     DCHECK_EQ(0u, transformers_.count(browser_pref)) <<
    230         "Trying to register pref transformer for " << browser_pref << " twice";
    231     transformers_[browser_pref] = transformer;
    232   }
    233 
    234   struct PrefMapData {
    235     PrefMapData()
    236         : read_permission(APIPermission::kInvalid),
    237           write_permission(APIPermission::kInvalid) {}
    238 
    239     PrefMapData(const std::string& pref_name,
    240                 APIPermission::ID read,
    241                 APIPermission::ID write)
    242         : pref_name(pref_name),
    243           read_permission(read),
    244           write_permission(write) {}
    245 
    246     // Browser or extension preference to which the data maps.
    247     std::string pref_name;
    248 
    249     // Permission needed to read the preference.
    250     APIPermission::ID read_permission;
    251 
    252     // Permission needed to write the preference.
    253     APIPermission::ID write_permission;
    254   };
    255 
    256   typedef std::map<std::string, PrefMapData> PrefMap;
    257 
    258   // Mapping from extension pref keys to browser pref keys and permissions.
    259   PrefMap mapping_;
    260 
    261   // Mapping from browser pref keys to extension event names and permissions.
    262   PrefMap event_mapping_;
    263 
    264   // Mapping from browser pref keys to transformers.
    265   std::map<std::string, PrefTransformerInterface*> transformers_;
    266 
    267   scoped_ptr<PrefTransformerInterface> identity_transformer_;
    268 
    269   DISALLOW_COPY_AND_ASSIGN(PrefMapping);
    270 };
    271 
    272 }  // namespace
    273 
    274 PreferenceEventRouter::PreferenceEventRouter(Profile* profile)
    275     : profile_(profile) {
    276   registrar_.Init(profile_->GetPrefs());
    277   incognito_registrar_.Init(profile_->GetOffTheRecordPrefs());
    278   for (size_t i = 0; i < arraysize(kPrefMapping); ++i) {
    279     registrar_.Add(kPrefMapping[i].browser_pref,
    280                    base::Bind(&PreferenceEventRouter::OnPrefChanged,
    281                               base::Unretained(this),
    282                               registrar_.prefs()));
    283     incognito_registrar_.Add(kPrefMapping[i].browser_pref,
    284                              base::Bind(&PreferenceEventRouter::OnPrefChanged,
    285                                         base::Unretained(this),
    286                                         incognito_registrar_.prefs()));
    287   }
    288 }
    289 
    290 PreferenceEventRouter::~PreferenceEventRouter() { }
    291 
    292 void PreferenceEventRouter::OnPrefChanged(PrefService* pref_service,
    293                                           const std::string& browser_pref) {
    294   bool incognito = (pref_service != profile_->GetPrefs());
    295 
    296   std::string event_name;
    297   APIPermission::ID permission = APIPermission::kInvalid;
    298   bool rv = PrefMapping::GetInstance()->FindEventForBrowserPref(
    299       browser_pref, &event_name, &permission);
    300   DCHECK(rv);
    301 
    302   base::ListValue args;
    303   base::DictionaryValue* dict = new base::DictionaryValue();
    304   args.Append(dict);
    305   const PrefService::Preference* pref =
    306       pref_service->FindPreference(browser_pref.c_str());
    307   CHECK(pref);
    308   PrefTransformerInterface* transformer =
    309       PrefMapping::GetInstance()->FindTransformerForBrowserPref(browser_pref);
    310   base::Value* transformed_value =
    311       transformer->BrowserToExtensionPref(pref->GetValue());
    312   if (!transformed_value) {
    313     LOG(ERROR) << ErrorUtils::FormatErrorMessage(kConversionErrorMessage,
    314                                                  pref->name());
    315     return;
    316   }
    317 
    318   dict->Set(keys::kValue, transformed_value);
    319   if (incognito) {
    320     ExtensionPrefs* ep = ExtensionPrefs::Get(profile_);
    321     dict->SetBoolean(keys::kIncognitoSpecific,
    322                      ep->HasIncognitoPrefValue(browser_pref));
    323   }
    324 
    325   helpers::DispatchEventToExtensions(profile_,
    326                                      event_name,
    327                                      &args,
    328                                      permission,
    329                                      incognito,
    330                                      browser_pref);
    331 }
    332 
    333 void PreferenceAPIBase::SetExtensionControlledPref(
    334     const std::string& extension_id,
    335     const std::string& pref_key,
    336     ExtensionPrefsScope scope,
    337     base::Value* value) {
    338 #ifndef NDEBUG
    339   const PrefService::Preference* pref =
    340       extension_prefs()->pref_service()->FindPreference(pref_key.c_str());
    341   DCHECK(pref) << "Extension controlled preference key " << pref_key
    342                << " not registered.";
    343   DCHECK_EQ(pref->GetType(), value->GetType())
    344       << "Extension controlled preference " << pref_key << " has wrong type.";
    345 #endif
    346 
    347   std::string scope_string;
    348   // ScopeToPrefName() returns false if the scope is not persisted.
    349   if (pref_names::ScopeToPrefName(scope, &scope_string)) {
    350     // Also store in persisted Preferences file to recover after a
    351     // browser restart.
    352     ExtensionPrefs::ScopedDictionaryUpdate update(extension_prefs(),
    353                                                   extension_id,
    354                                                   scope_string);
    355     base::DictionaryValue* preference = update.Get();
    356     if (!preference)
    357       preference = update.Create();
    358     preference->SetWithoutPathExpansion(pref_key, value->DeepCopy());
    359   }
    360   extension_pref_value_map()->SetExtensionPref(
    361       extension_id, pref_key, scope, value);
    362 }
    363 
    364 void PreferenceAPIBase::RemoveExtensionControlledPref(
    365     const std::string& extension_id,
    366     const std::string& pref_key,
    367     ExtensionPrefsScope scope) {
    368   DCHECK(extension_prefs()->pref_service()->FindPreference(pref_key.c_str()))
    369       << "Extension controlled preference key " << pref_key
    370       << " not registered.";
    371 
    372   std::string scope_string;
    373   if (pref_names::ScopeToPrefName(scope, &scope_string)) {
    374     ExtensionPrefs::ScopedDictionaryUpdate update(extension_prefs(),
    375                                                   extension_id,
    376                                                   scope_string);
    377     base::DictionaryValue* preference = update.Get();
    378     if (preference)
    379       preference->RemoveWithoutPathExpansion(pref_key, NULL);
    380   }
    381   extension_pref_value_map()->RemoveExtensionPref(
    382       extension_id, pref_key, scope);
    383 }
    384 
    385 bool PreferenceAPIBase::CanExtensionControlPref(
    386      const std::string& extension_id,
    387      const std::string& pref_key,
    388      bool incognito) {
    389   DCHECK(extension_prefs()->pref_service()->FindPreference(pref_key.c_str()))
    390       << "Extension controlled preference key " << pref_key
    391       << " not registered.";
    392 
    393   return extension_pref_value_map()->CanExtensionControlPref(
    394        extension_id, pref_key, incognito);
    395 }
    396 
    397 bool PreferenceAPIBase::DoesExtensionControlPref(
    398     const std::string& extension_id,
    399     const std::string& pref_key,
    400     bool* from_incognito) {
    401   DCHECK(extension_prefs()->pref_service()->FindPreference(pref_key.c_str()))
    402       << "Extension controlled preference key " << pref_key
    403       << " not registered.";
    404 
    405   return extension_pref_value_map()->DoesExtensionControlPref(
    406       extension_id, pref_key, from_incognito);
    407 }
    408 
    409 PreferenceAPI::PreferenceAPI(content::BrowserContext* context)
    410     : profile_(Profile::FromBrowserContext(context)) {
    411   for (size_t i = 0; i < arraysize(kPrefMapping); ++i) {
    412     std::string event_name;
    413     APIPermission::ID permission = APIPermission::kInvalid;
    414     bool rv = PrefMapping::GetInstance()->FindEventForBrowserPref(
    415         kPrefMapping[i].browser_pref, &event_name, &permission);
    416     DCHECK(rv);
    417     EventRouter::Get(profile_)->RegisterObserver(this, event_name);
    418   }
    419   content_settings_store()->AddObserver(this);
    420 }
    421 
    422 PreferenceAPI::~PreferenceAPI() {
    423 }
    424 
    425 void PreferenceAPI::Shutdown() {
    426   EventRouter::Get(profile_)->UnregisterObserver(this);
    427   if (!extension_prefs()->extensions_disabled())
    428     ClearIncognitoSessionOnlyContentSettings();
    429   content_settings_store()->RemoveObserver(this);
    430 }
    431 
    432 static base::LazyInstance<BrowserContextKeyedAPIFactory<PreferenceAPI> >
    433     g_factory = LAZY_INSTANCE_INITIALIZER;
    434 
    435 // static
    436 BrowserContextKeyedAPIFactory<PreferenceAPI>*
    437 PreferenceAPI::GetFactoryInstance() {
    438   return g_factory.Pointer();
    439 }
    440 
    441 // static
    442 PreferenceAPI* PreferenceAPI::Get(content::BrowserContext* context) {
    443   return BrowserContextKeyedAPIFactory<PreferenceAPI>::Get(context);
    444 }
    445 
    446 void PreferenceAPI::OnListenerAdded(const EventListenerInfo& details) {
    447   preference_event_router_.reset(new PreferenceEventRouter(profile_));
    448   EventRouter::Get(profile_)->UnregisterObserver(this);
    449 }
    450 
    451 void PreferenceAPI::OnContentSettingChanged(const std::string& extension_id,
    452                                             bool incognito) {
    453   if (incognito) {
    454     extension_prefs()->UpdateExtensionPref(
    455         extension_id,
    456         pref_names::kPrefIncognitoContentSettings,
    457         content_settings_store()->GetSettingsForExtension(
    458             extension_id, kExtensionPrefsScopeIncognitoPersistent));
    459   } else {
    460     extension_prefs()->UpdateExtensionPref(
    461         extension_id,
    462         pref_names::kPrefContentSettings,
    463         content_settings_store()->GetSettingsForExtension(
    464             extension_id, kExtensionPrefsScopeRegular));
    465   }
    466 }
    467 
    468 void PreferenceAPI::ClearIncognitoSessionOnlyContentSettings() {
    469   ExtensionIdList extension_ids;
    470   extension_prefs()->GetExtensions(&extension_ids);
    471   for (ExtensionIdList::iterator extension_id = extension_ids.begin();
    472        extension_id != extension_ids.end(); ++extension_id) {
    473     content_settings_store()->ClearContentSettingsForExtension(
    474         *extension_id, kExtensionPrefsScopeIncognitoSessionOnly);
    475   }
    476 }
    477 
    478 ExtensionPrefs* PreferenceAPI::extension_prefs() {
    479   return ExtensionPrefs::Get(profile_);
    480 }
    481 
    482 ExtensionPrefValueMap* PreferenceAPI::extension_pref_value_map() {
    483   return ExtensionPrefValueMapFactory::GetForBrowserContext(profile_);
    484 }
    485 
    486 scoped_refptr<ContentSettingsStore> PreferenceAPI::content_settings_store() {
    487   return ContentSettingsService::Get(profile_)->content_settings_store();
    488 }
    489 
    490 template <>
    491 void
    492 BrowserContextKeyedAPIFactory<PreferenceAPI>::DeclareFactoryDependencies() {
    493   DependsOn(ContentSettingsService::GetFactoryInstance());
    494   DependsOn(ExtensionPrefsFactory::GetInstance());
    495   DependsOn(ExtensionPrefValueMapFactory::GetInstance());
    496   DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
    497 }
    498 
    499 PreferenceFunction::~PreferenceFunction() { }
    500 
    501 bool PreferenceFunction::ValidateBrowserPref(
    502     const std::string& extension_pref_key,
    503     PreferenceFunction::PermissionType permission_type,
    504     std::string* browser_pref_key) {
    505   APIPermission::ID read_permission = APIPermission::kInvalid;
    506   APIPermission::ID write_permission = APIPermission::kInvalid;
    507   EXTENSION_FUNCTION_VALIDATE(
    508       PrefMapping::GetInstance()->FindBrowserPrefForExtensionPref(
    509           extension_pref_key,
    510           browser_pref_key,
    511           &read_permission,
    512           &write_permission));
    513   APIPermission::ID permission = permission_type == PERMISSION_TYPE_READ
    514                                      ? read_permission
    515                                      : write_permission;
    516   if (!GetExtension()->permissions_data()->HasAPIPermission(permission)) {
    517     error_ = ErrorUtils::FormatErrorMessage(
    518         keys::kPermissionErrorMessage, extension_pref_key);
    519     return false;
    520   }
    521   return true;
    522 }
    523 
    524 GetPreferenceFunction::~GetPreferenceFunction() { }
    525 
    526 bool GetPreferenceFunction::RunSync() {
    527   std::string pref_key;
    528   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key));
    529   base::DictionaryValue* details = NULL;
    530   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details));
    531 
    532   bool incognito = false;
    533   if (details->HasKey(keys::kIncognitoKey))
    534     EXTENSION_FUNCTION_VALIDATE(details->GetBoolean(keys::kIncognitoKey,
    535                                                     &incognito));
    536 
    537   // Check incognito access.
    538   if (incognito && !include_incognito()) {
    539     error_ = keys::kIncognitoErrorMessage;
    540     return false;
    541   }
    542 
    543   // Obtain pref.
    544   std::string browser_pref;
    545   if (!ValidateBrowserPref(
    546           pref_key, PreferenceFunction::PERMISSION_TYPE_READ, &browser_pref)) {
    547     return false;
    548   }
    549   PrefService* prefs = incognito ? GetProfile()->GetOffTheRecordPrefs()
    550                                  : GetProfile()->GetPrefs();
    551   const PrefService::Preference* pref =
    552       prefs->FindPreference(browser_pref.c_str());
    553   CHECK(pref);
    554 
    555   scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue);
    556 
    557   // Retrieve level of control.
    558   std::string level_of_control = helpers::GetLevelOfControl(
    559       GetProfile(), extension_id(), browser_pref, incognito);
    560   result->SetString(keys::kLevelOfControl, level_of_control);
    561 
    562   // Retrieve pref value.
    563   PrefTransformerInterface* transformer =
    564       PrefMapping::GetInstance()->FindTransformerForBrowserPref(browser_pref);
    565   base::Value* transformed_value =
    566       transformer->BrowserToExtensionPref(pref->GetValue());
    567   if (!transformed_value) {
    568     LOG(ERROR) <<
    569         ErrorUtils::FormatErrorMessage(kConversionErrorMessage,
    570                                                 pref->name());
    571     return false;
    572   }
    573   result->Set(keys::kValue, transformed_value);
    574 
    575   // Retrieve incognito status.
    576   if (incognito) {
    577     ExtensionPrefs* ep = ExtensionPrefs::Get(GetProfile());
    578     result->SetBoolean(keys::kIncognitoSpecific,
    579                        ep->HasIncognitoPrefValue(browser_pref));
    580   }
    581 
    582   SetResult(result.release());
    583   return true;
    584 }
    585 
    586 SetPreferenceFunction::~SetPreferenceFunction() { }
    587 
    588 bool SetPreferenceFunction::RunSync() {
    589   std::string pref_key;
    590   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key));
    591   base::DictionaryValue* details = NULL;
    592   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details));
    593 
    594   base::Value* value = NULL;
    595   EXTENSION_FUNCTION_VALIDATE(details->Get(keys::kValue, &value));
    596 
    597   ExtensionPrefsScope scope = kExtensionPrefsScopeRegular;
    598   if (details->HasKey(keys::kScopeKey)) {
    599     std::string scope_str;
    600     EXTENSION_FUNCTION_VALIDATE(
    601         details->GetString(keys::kScopeKey, &scope_str));
    602 
    603     EXTENSION_FUNCTION_VALIDATE(helpers::StringToScope(scope_str, &scope));
    604   }
    605 
    606   // Check incognito scope.
    607   bool incognito =
    608       (scope == kExtensionPrefsScopeIncognitoPersistent ||
    609        scope == kExtensionPrefsScopeIncognitoSessionOnly);
    610   if (incognito) {
    611     // Regular profiles can't access incognito unless include_incognito is true.
    612     if (!GetProfile()->IsOffTheRecord() && !include_incognito()) {
    613       error_ = keys::kIncognitoErrorMessage;
    614       return false;
    615     }
    616   } else {
    617     // Incognito profiles can't access regular mode ever, they only exist in
    618     // split mode.
    619     if (GetProfile()->IsOffTheRecord()) {
    620       error_ = "Can't modify regular settings from an incognito context.";
    621       return false;
    622     }
    623   }
    624 
    625   if (scope == kExtensionPrefsScopeIncognitoSessionOnly &&
    626       !GetProfile()->HasOffTheRecordProfile()) {
    627     error_ = keys::kIncognitoSessionOnlyErrorMessage;
    628     return false;
    629   }
    630 
    631   // Obtain pref.
    632   std::string browser_pref;
    633   if (!ValidateBrowserPref(
    634           pref_key, PreferenceFunction::PERMISSION_TYPE_WRITE, &browser_pref)) {
    635     return false;
    636   }
    637   ExtensionPrefs* prefs = ExtensionPrefs::Get(GetProfile());
    638   const PrefService::Preference* pref =
    639       prefs->pref_service()->FindPreference(browser_pref.c_str());
    640   CHECK(pref);
    641 
    642   // Validate new value.
    643   EXTENSION_FUNCTION_VALIDATE(value->GetType() == pref->GetType());
    644   PrefTransformerInterface* transformer =
    645       PrefMapping::GetInstance()->FindTransformerForBrowserPref(browser_pref);
    646   std::string error;
    647   bool bad_message = false;
    648   scoped_ptr<base::Value> browser_pref_value(
    649       transformer->ExtensionToBrowserPref(value, &error, &bad_message));
    650   if (!browser_pref_value) {
    651     error_ = error;
    652     bad_message_ = bad_message;
    653     return false;
    654   }
    655 
    656   // Validate also that the stored value can be converted back by the
    657   // transformer.
    658   scoped_ptr<base::Value> extensionPrefValue(
    659       transformer->BrowserToExtensionPref(browser_pref_value.get()));
    660   if (!extensionPrefValue) {
    661     error_ =  ErrorUtils::FormatErrorMessage(kConversionErrorMessage,
    662                                                       pref->name());
    663     bad_message_ = true;
    664     return false;
    665   }
    666 
    667   PreferenceAPI::Get(GetProfile())->SetExtensionControlledPref(
    668       extension_id(), browser_pref, scope, browser_pref_value.release());
    669   return true;
    670 }
    671 
    672 ClearPreferenceFunction::~ClearPreferenceFunction() { }
    673 
    674 bool ClearPreferenceFunction::RunSync() {
    675   std::string pref_key;
    676   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key));
    677   base::DictionaryValue* details = NULL;
    678   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details));
    679 
    680   ExtensionPrefsScope scope = kExtensionPrefsScopeRegular;
    681   if (details->HasKey(keys::kScopeKey)) {
    682     std::string scope_str;
    683     EXTENSION_FUNCTION_VALIDATE(
    684         details->GetString(keys::kScopeKey, &scope_str));
    685 
    686     EXTENSION_FUNCTION_VALIDATE(helpers::StringToScope(scope_str, &scope));
    687   }
    688 
    689   // Check incognito scope.
    690   bool incognito =
    691       (scope == kExtensionPrefsScopeIncognitoPersistent ||
    692        scope == kExtensionPrefsScopeIncognitoSessionOnly);
    693   if (incognito) {
    694     // We don't check incognito permissions here, as an extension should be
    695     // always allowed to clear its own settings.
    696   } else {
    697     // Incognito profiles can't access regular mode ever, they only exist in
    698     // split mode.
    699     if (GetProfile()->IsOffTheRecord()) {
    700       error_ = "Can't modify regular settings from an incognito context.";
    701       return false;
    702     }
    703   }
    704 
    705   std::string browser_pref;
    706   if (!ValidateBrowserPref(
    707           pref_key, PreferenceFunction::PERMISSION_TYPE_WRITE, &browser_pref)) {
    708     return false;
    709   }
    710 
    711   PreferenceAPI::Get(GetProfile())
    712       ->RemoveExtensionControlledPref(extension_id(), browser_pref, scope);
    713   return true;
    714 }
    715 
    716 }  // namespace extensions
    717