Home | History | Annotate | Download | only in syncable
      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 "sync/internal_api/public/base/model_type.h"
      6 
      7 #include "base/strings/string_split.h"
      8 #include "base/values.h"
      9 #include "sync/protocol/app_notification_specifics.pb.h"
     10 #include "sync/protocol/app_setting_specifics.pb.h"
     11 #include "sync/protocol/app_specifics.pb.h"
     12 #include "sync/protocol/autofill_specifics.pb.h"
     13 #include "sync/protocol/bookmark_specifics.pb.h"
     14 #include "sync/protocol/extension_setting_specifics.pb.h"
     15 #include "sync/protocol/extension_specifics.pb.h"
     16 #include "sync/protocol/nigori_specifics.pb.h"
     17 #include "sync/protocol/password_specifics.pb.h"
     18 #include "sync/protocol/preference_specifics.pb.h"
     19 #include "sync/protocol/search_engine_specifics.pb.h"
     20 #include "sync/protocol/session_specifics.pb.h"
     21 #include "sync/protocol/sync.pb.h"
     22 #include "sync/protocol/theme_specifics.pb.h"
     23 #include "sync/protocol/typed_url_specifics.pb.h"
     24 #include "sync/syncable/syncable_proto_util.h"
     25 
     26 namespace syncer {
     27 
     28 void AddDefaultFieldValue(ModelType datatype,
     29                           sync_pb::EntitySpecifics* specifics) {
     30   if (!ProtocolTypes().Has(datatype)) {
     31     NOTREACHED() << "Only protocol types have field values.";
     32     return;
     33   }
     34   switch (datatype) {
     35     case BOOKMARKS:
     36       specifics->mutable_bookmark();
     37       break;
     38     case PASSWORDS:
     39       specifics->mutable_password();
     40       break;
     41     case PREFERENCES:
     42       specifics->mutable_preference();
     43       break;
     44     case AUTOFILL:
     45       specifics->mutable_autofill();
     46       break;
     47     case AUTOFILL_PROFILE:
     48       specifics->mutable_autofill_profile();
     49       break;
     50     case THEMES:
     51       specifics->mutable_theme();
     52       break;
     53     case TYPED_URLS:
     54       specifics->mutable_typed_url();
     55       break;
     56     case EXTENSIONS:
     57       specifics->mutable_extension();
     58       break;
     59     case NIGORI:
     60       specifics->mutable_nigori();
     61       break;
     62     case SEARCH_ENGINES:
     63       specifics->mutable_search_engine();
     64       break;
     65     case SESSIONS:
     66       specifics->mutable_session();
     67       break;
     68     case APPS:
     69       specifics->mutable_app();
     70       break;
     71     case APP_LIST:
     72       specifics->mutable_app_list();
     73       break;
     74     case APP_SETTINGS:
     75       specifics->mutable_app_setting();
     76       break;
     77     case EXTENSION_SETTINGS:
     78       specifics->mutable_extension_setting();
     79       break;
     80     case APP_NOTIFICATIONS:
     81       specifics->mutable_app_notification();
     82       break;
     83     case HISTORY_DELETE_DIRECTIVES:
     84       specifics->mutable_history_delete_directive();
     85       break;
     86     case SYNCED_NOTIFICATIONS:
     87       specifics->mutable_synced_notification();
     88       break;
     89     case SYNCED_NOTIFICATION_APP_INFO:
     90       specifics->mutable_synced_notification_app_info();
     91       break;
     92     case DEVICE_INFO:
     93       specifics->mutable_device_info();
     94       break;
     95     case EXPERIMENTS:
     96       specifics->mutable_experiments();
     97       break;
     98     case PRIORITY_PREFERENCES:
     99       specifics->mutable_priority_preference();
    100       break;
    101     case DICTIONARY:
    102       specifics->mutable_dictionary();
    103       break;
    104     case FAVICON_IMAGES:
    105       specifics->mutable_favicon_image();
    106       break;
    107     case FAVICON_TRACKING:
    108       specifics->mutable_favicon_tracking();
    109       break;
    110     case SUPERVISED_USER_SETTINGS:
    111       specifics->mutable_managed_user_setting();
    112       break;
    113     case SUPERVISED_USERS:
    114       specifics->mutable_managed_user();
    115       break;
    116     case SUPERVISED_USER_SHARED_SETTINGS:
    117       specifics->mutable_managed_user_shared_setting();
    118       break;
    119     case ARTICLES:
    120       specifics->mutable_article();
    121       break;
    122     default:
    123       NOTREACHED() << "No known extension for model type.";
    124   }
    125 }
    126 
    127 ModelType GetModelTypeFromSpecificsFieldNumber(int field_number) {
    128   ModelTypeSet protocol_types = ProtocolTypes();
    129   for (ModelTypeSet::Iterator iter = protocol_types.First(); iter.Good();
    130        iter.Inc()) {
    131     if (GetSpecificsFieldNumberFromModelType(iter.Get()) == field_number)
    132       return iter.Get();
    133   }
    134   return UNSPECIFIED;
    135 }
    136 
    137 int GetSpecificsFieldNumberFromModelType(ModelType model_type) {
    138   DCHECK(ProtocolTypes().Has(model_type))
    139       << "Only protocol types have field values.";
    140   switch (model_type) {
    141     case BOOKMARKS:
    142       return sync_pb::EntitySpecifics::kBookmarkFieldNumber;
    143     case PASSWORDS:
    144       return sync_pb::EntitySpecifics::kPasswordFieldNumber;
    145     case PREFERENCES:
    146       return sync_pb::EntitySpecifics::kPreferenceFieldNumber;
    147     case AUTOFILL:
    148       return sync_pb::EntitySpecifics::kAutofillFieldNumber;
    149     case AUTOFILL_PROFILE:
    150       return sync_pb::EntitySpecifics::kAutofillProfileFieldNumber;
    151     case THEMES:
    152       return sync_pb::EntitySpecifics::kThemeFieldNumber;
    153     case TYPED_URLS:
    154       return sync_pb::EntitySpecifics::kTypedUrlFieldNumber;
    155     case EXTENSIONS:
    156       return sync_pb::EntitySpecifics::kExtensionFieldNumber;
    157     case NIGORI:
    158       return sync_pb::EntitySpecifics::kNigoriFieldNumber;
    159     case SEARCH_ENGINES:
    160       return sync_pb::EntitySpecifics::kSearchEngineFieldNumber;
    161     case SESSIONS:
    162       return sync_pb::EntitySpecifics::kSessionFieldNumber;
    163     case APPS:
    164       return sync_pb::EntitySpecifics::kAppFieldNumber;
    165     case APP_LIST:
    166       return sync_pb::EntitySpecifics::kAppListFieldNumber;
    167     case APP_SETTINGS:
    168       return sync_pb::EntitySpecifics::kAppSettingFieldNumber;
    169     case EXTENSION_SETTINGS:
    170       return sync_pb::EntitySpecifics::kExtensionSettingFieldNumber;
    171     case APP_NOTIFICATIONS:
    172       return sync_pb::EntitySpecifics::kAppNotificationFieldNumber;
    173     case HISTORY_DELETE_DIRECTIVES:
    174       return sync_pb::EntitySpecifics::kHistoryDeleteDirectiveFieldNumber;
    175     case SYNCED_NOTIFICATIONS:
    176       return sync_pb::EntitySpecifics::kSyncedNotificationFieldNumber;
    177     case SYNCED_NOTIFICATION_APP_INFO:
    178       return sync_pb::EntitySpecifics::kSyncedNotificationAppInfoFieldNumber;
    179     case DEVICE_INFO:
    180       return sync_pb::EntitySpecifics::kDeviceInfoFieldNumber;
    181     case EXPERIMENTS:
    182       return sync_pb::EntitySpecifics::kExperimentsFieldNumber;
    183     case PRIORITY_PREFERENCES:
    184       return sync_pb::EntitySpecifics::kPriorityPreferenceFieldNumber;
    185     case DICTIONARY:
    186       return sync_pb::EntitySpecifics::kDictionaryFieldNumber;
    187     case FAVICON_IMAGES:
    188       return sync_pb::EntitySpecifics::kFaviconImageFieldNumber;
    189     case FAVICON_TRACKING:
    190       return sync_pb::EntitySpecifics::kFaviconTrackingFieldNumber;
    191     case SUPERVISED_USER_SETTINGS:
    192       return sync_pb::EntitySpecifics::kManagedUserSettingFieldNumber;
    193     case SUPERVISED_USERS:
    194       return sync_pb::EntitySpecifics::kManagedUserFieldNumber;
    195     case SUPERVISED_USER_SHARED_SETTINGS:
    196       return sync_pb::EntitySpecifics::kManagedUserSharedSettingFieldNumber;
    197     case ARTICLES:
    198       return sync_pb::EntitySpecifics::kArticleFieldNumber;
    199     default:
    200       NOTREACHED() << "No known extension for model type.";
    201       return 0;
    202   }
    203 }
    204 
    205 FullModelTypeSet ToFullModelTypeSet(ModelTypeSet in) {
    206   FullModelTypeSet out;
    207   for (ModelTypeSet::Iterator i = in.First(); i.Good(); i.Inc()) {
    208     out.Put(i.Get());
    209   }
    210   return out;
    211 }
    212 
    213 // Note: keep this consistent with GetModelType in entry.cc!
    214 ModelType GetModelType(const sync_pb::SyncEntity& sync_entity) {
    215   DCHECK(!IsRoot(sync_entity));  // Root shouldn't ever go over the wire.
    216 
    217   // Backwards compatibility with old (pre-specifics) protocol.
    218   if (sync_entity.has_bookmarkdata())
    219     return BOOKMARKS;
    220 
    221   ModelType specifics_type = GetModelTypeFromSpecifics(sync_entity.specifics());
    222   if (specifics_type != UNSPECIFIED)
    223     return specifics_type;
    224 
    225   // Loose check for server-created top-level folders that aren't
    226   // bound to a particular model type.
    227   if (!sync_entity.server_defined_unique_tag().empty() &&
    228       IsFolder(sync_entity)) {
    229     return TOP_LEVEL_FOLDER;
    230   }
    231 
    232   // This is an item of a datatype we can't understand. Maybe it's
    233   // from the future?  Either we mis-encoded the object, or the
    234   // server sent us entries it shouldn't have.
    235   NOTREACHED() << "Unknown datatype in sync proto.";
    236   return UNSPECIFIED;
    237 }
    238 
    239 ModelType GetModelTypeFromSpecifics(const sync_pb::EntitySpecifics& specifics) {
    240   if (specifics.has_bookmark())
    241     return BOOKMARKS;
    242 
    243   if (specifics.has_password())
    244     return PASSWORDS;
    245 
    246   if (specifics.has_preference())
    247     return PREFERENCES;
    248 
    249   if (specifics.has_autofill())
    250     return AUTOFILL;
    251 
    252   if (specifics.has_autofill_profile())
    253     return AUTOFILL_PROFILE;
    254 
    255   if (specifics.has_theme())
    256     return THEMES;
    257 
    258   if (specifics.has_typed_url())
    259     return TYPED_URLS;
    260 
    261   if (specifics.has_extension())
    262     return EXTENSIONS;
    263 
    264   if (specifics.has_nigori())
    265     return NIGORI;
    266 
    267   if (specifics.has_app())
    268     return APPS;
    269 
    270   if (specifics.has_app_list())
    271     return APP_LIST;
    272 
    273   if (specifics.has_search_engine())
    274     return SEARCH_ENGINES;
    275 
    276   if (specifics.has_session())
    277     return SESSIONS;
    278 
    279   if (specifics.has_app_setting())
    280     return APP_SETTINGS;
    281 
    282   if (specifics.has_extension_setting())
    283     return EXTENSION_SETTINGS;
    284 
    285   if (specifics.has_app_notification())
    286     return APP_NOTIFICATIONS;
    287 
    288   if (specifics.has_history_delete_directive())
    289     return HISTORY_DELETE_DIRECTIVES;
    290 
    291   if (specifics.has_synced_notification())
    292     return SYNCED_NOTIFICATIONS;
    293 
    294   if (specifics.has_synced_notification_app_info())
    295     return SYNCED_NOTIFICATION_APP_INFO;
    296 
    297   if (specifics.has_device_info())
    298     return DEVICE_INFO;
    299 
    300   if (specifics.has_experiments())
    301     return EXPERIMENTS;
    302 
    303   if (specifics.has_priority_preference())
    304     return PRIORITY_PREFERENCES;
    305 
    306   if (specifics.has_dictionary())
    307     return DICTIONARY;
    308 
    309   if (specifics.has_favicon_image())
    310     return FAVICON_IMAGES;
    311 
    312   if (specifics.has_favicon_tracking())
    313     return FAVICON_TRACKING;
    314 
    315   if (specifics.has_managed_user_setting())
    316     return SUPERVISED_USER_SETTINGS;
    317 
    318   if (specifics.has_managed_user())
    319     return SUPERVISED_USERS;
    320 
    321   if (specifics.has_managed_user_shared_setting())
    322     return SUPERVISED_USER_SHARED_SETTINGS;
    323 
    324   if (specifics.has_article())
    325     return ARTICLES;
    326 
    327   return UNSPECIFIED;
    328 }
    329 
    330 ModelTypeSet ProtocolTypes() {
    331   ModelTypeSet set = ModelTypeSet::All();
    332   set.RemoveAll(ProxyTypes());
    333   return set;
    334 }
    335 
    336 ModelTypeSet UserTypes() {
    337   ModelTypeSet set;
    338   // TODO(sync): We should be able to build the actual enumset's internal
    339   // bitset value here at compile time, rather than performing an iteration
    340   // every time.
    341   for (int i = FIRST_USER_MODEL_TYPE; i <= LAST_USER_MODEL_TYPE; ++i) {
    342     set.Put(ModelTypeFromInt(i));
    343   }
    344   return set;
    345 }
    346 
    347 ModelTypeSet UserSelectableTypes() {
    348   ModelTypeSet set;
    349   // Although the order doesn't technically matter here, it's clearer to keep
    350   // these in the same order as their definition in the ModelType enum.
    351   set.Put(BOOKMARKS);
    352   set.Put(PREFERENCES);
    353   set.Put(PASSWORDS);
    354   set.Put(AUTOFILL);
    355   set.Put(THEMES);
    356   set.Put(TYPED_URLS);
    357   set.Put(EXTENSIONS);
    358   set.Put(APPS);
    359   set.Put(PROXY_TABS);
    360   return set;
    361 }
    362 
    363 bool IsUserSelectableType(ModelType model_type) {
    364   return UserSelectableTypes().Has(model_type);
    365 }
    366 
    367 ModelTypeSet EncryptableUserTypes() {
    368   ModelTypeSet encryptable_user_types = UserTypes();
    369   // We never encrypt history delete directives.
    370   encryptable_user_types.Remove(HISTORY_DELETE_DIRECTIVES);
    371   // Synced notifications are not encrypted since the server must see changes.
    372   encryptable_user_types.Remove(SYNCED_NOTIFICATIONS);
    373   // Synced Notification App Info does not have private data, so it is not
    374   // encrypted.
    375   encryptable_user_types.Remove(SYNCED_NOTIFICATION_APP_INFO);
    376   // Device info data is not encrypted because it might be synced before
    377   // encryption is ready.
    378   encryptable_user_types.Remove(DEVICE_INFO);
    379   // Priority preferences are not encrypted because they might be synced before
    380   // encryption is ready.
    381   encryptable_user_types.Remove(PRIORITY_PREFERENCES);
    382   // Supervised user settings are not encrypted since they are set server-side.
    383   encryptable_user_types.Remove(SUPERVISED_USER_SETTINGS);
    384   // Supervised users are not encrypted since they are managed server-side.
    385   encryptable_user_types.Remove(SUPERVISED_USERS);
    386   // Supervised user shared settings are not encrypted since they are managed
    387   // server-side and shared between manager and supervised user.
    388   encryptable_user_types.Remove(SUPERVISED_USER_SHARED_SETTINGS);
    389   // Proxy types have no sync representation and are therefore not encrypted.
    390   // Note however that proxy types map to one or more protocol types, which
    391   // may or may not be encrypted themselves.
    392   encryptable_user_types.RemoveAll(ProxyTypes());
    393   return encryptable_user_types;
    394 }
    395 
    396 ModelTypeSet PriorityUserTypes() {
    397   return ModelTypeSet(DEVICE_INFO, PRIORITY_PREFERENCES);
    398 }
    399 
    400 ModelTypeSet ControlTypes() {
    401   ModelTypeSet set;
    402   // TODO(sync): We should be able to build the actual enumset's internal
    403   // bitset value here at compile time, rather than performing an iteration
    404   // every time.
    405   for (int i = FIRST_CONTROL_MODEL_TYPE; i <= LAST_CONTROL_MODEL_TYPE; ++i) {
    406     set.Put(ModelTypeFromInt(i));
    407   }
    408 
    409   return set;
    410 }
    411 
    412 ModelTypeSet ProxyTypes() {
    413   ModelTypeSet set;
    414   set.Put(PROXY_TABS);
    415   return set;
    416 }
    417 
    418 bool IsControlType(ModelType model_type) {
    419   return ControlTypes().Has(model_type);
    420 }
    421 
    422 ModelTypeSet CoreTypes() {
    423   syncer::ModelTypeSet result;
    424   result.PutAll(PriorityCoreTypes());
    425 
    426   // The following are low priority core types.
    427   result.Put(SYNCED_NOTIFICATIONS);
    428   result.Put(SYNCED_NOTIFICATION_APP_INFO);
    429   result.Put(SUPERVISED_USER_SHARED_SETTINGS);
    430 
    431   return result;
    432 }
    433 
    434 ModelTypeSet PriorityCoreTypes() {
    435   syncer::ModelTypeSet result;
    436   result.PutAll(ControlTypes());
    437 
    438   // The following are non-control core types.
    439   result.Put(SUPERVISED_USERS);
    440   result.Put(SUPERVISED_USER_SETTINGS);
    441 
    442   return result;
    443 }
    444 
    445 ModelTypeSet BackupTypes() {
    446   ModelTypeSet result;
    447   result.Put(BOOKMARKS);
    448   result.Put(PREFERENCES);
    449   result.Put(THEMES);
    450   result.Put(EXTENSIONS);
    451   result.Put(SEARCH_ENGINES);
    452   result.Put(APPS);
    453   result.Put(APP_LIST);
    454   result.Put(APP_SETTINGS);
    455   result.Put(EXTENSION_SETTINGS);
    456   result.Put(PRIORITY_PREFERENCES);
    457   return result;
    458 }
    459 
    460 const char* ModelTypeToString(ModelType model_type) {
    461   // This is used in serialization routines as well as for displaying debug
    462   // information.  Do not attempt to change these string values unless you know
    463   // what you're doing.
    464   switch (model_type) {
    465     case TOP_LEVEL_FOLDER:
    466       return "Top Level Folder";
    467     case UNSPECIFIED:
    468       return "Unspecified";
    469     case BOOKMARKS:
    470       return "Bookmarks";
    471     case PREFERENCES:
    472       return "Preferences";
    473     case PASSWORDS:
    474       return "Passwords";
    475     case AUTOFILL:
    476       return "Autofill";
    477     case THEMES:
    478       return "Themes";
    479     case TYPED_URLS:
    480       return "Typed URLs";
    481     case EXTENSIONS:
    482       return "Extensions";
    483     case NIGORI:
    484       return "Encryption keys";
    485     case SEARCH_ENGINES:
    486       return "Search Engines";
    487     case SESSIONS:
    488       return "Sessions";
    489     case APPS:
    490       return "Apps";
    491     case APP_LIST:
    492       return "App List";
    493     case AUTOFILL_PROFILE:
    494       return "Autofill Profiles";
    495     case APP_SETTINGS:
    496       return "App settings";
    497     case EXTENSION_SETTINGS:
    498       return "Extension settings";
    499     case APP_NOTIFICATIONS:
    500       return "App Notifications";
    501     case HISTORY_DELETE_DIRECTIVES:
    502       return "History Delete Directives";
    503     case SYNCED_NOTIFICATIONS:
    504       return "Synced Notifications";
    505     case SYNCED_NOTIFICATION_APP_INFO:
    506       return "Synced Notification App Info";
    507     case DEVICE_INFO:
    508       return "Device Info";
    509     case EXPERIMENTS:
    510       return "Experiments";
    511     case PRIORITY_PREFERENCES:
    512       return "Priority Preferences";
    513     case DICTIONARY:
    514       return "Dictionary";
    515     case FAVICON_IMAGES:
    516       return "Favicon Images";
    517     case FAVICON_TRACKING:
    518       return "Favicon Tracking";
    519     case SUPERVISED_USER_SETTINGS:
    520       return "Managed User Settings";
    521     case SUPERVISED_USERS:
    522       return "Managed Users";
    523     case SUPERVISED_USER_SHARED_SETTINGS:
    524       return "Managed User Shared Settings";
    525     case ARTICLES:
    526       return "Articles";
    527     case PROXY_TABS:
    528       return "Tabs";
    529     default:
    530       break;
    531   }
    532   NOTREACHED() << "No known extension for model type.";
    533   return "INVALID";
    534 }
    535 
    536 // The normal rules about histograms apply here.  Always append to the bottom of
    537 // the list, and be careful to not reuse integer values that have already been
    538 // assigned.  Don't forget to update histograms.xml when you make changes to
    539 // this list.
    540 int ModelTypeToHistogramInt(ModelType model_type) {
    541   switch (model_type) {
    542     case UNSPECIFIED:
    543       return 0;
    544     case TOP_LEVEL_FOLDER:
    545       return 1;
    546     case BOOKMARKS:
    547       return 2;
    548     case PREFERENCES:
    549       return 3;
    550     case PASSWORDS:
    551       return 4;
    552     case AUTOFILL_PROFILE:
    553       return 5;
    554     case AUTOFILL:
    555       return 6;
    556     case THEMES:
    557       return 7;
    558     case TYPED_URLS:
    559       return 8;
    560     case EXTENSIONS:
    561       return 9;
    562     case SEARCH_ENGINES:
    563       return 10;
    564     case SESSIONS:
    565       return 11;
    566     case APPS:
    567       return 12;
    568     case APP_SETTINGS:
    569       return 13;
    570     case EXTENSION_SETTINGS:
    571       return 14;
    572     case APP_NOTIFICATIONS:
    573       return 15;
    574     case HISTORY_DELETE_DIRECTIVES:
    575       return 16;
    576     case NIGORI:
    577       return 17;
    578     case DEVICE_INFO:
    579       return 18;
    580     case EXPERIMENTS:
    581       return 19;
    582     case SYNCED_NOTIFICATIONS:
    583       return 20;
    584     case PRIORITY_PREFERENCES:
    585       return 21;
    586     case DICTIONARY:
    587       return 22;
    588     case FAVICON_IMAGES:
    589       return 23;
    590     case FAVICON_TRACKING:
    591       return 24;
    592     case PROXY_TABS:
    593       return 25;
    594     case SUPERVISED_USER_SETTINGS:
    595       return 26;
    596     case SUPERVISED_USERS:
    597       return 27;
    598     case ARTICLES:
    599       return 28;
    600     case APP_LIST:
    601       return 29;
    602     case SUPERVISED_USER_SHARED_SETTINGS:
    603       return 30;
    604     case SYNCED_NOTIFICATION_APP_INFO:
    605       return 31;
    606     // Silence a compiler warning.
    607     case MODEL_TYPE_COUNT:
    608       return 0;
    609   }
    610   return 0;
    611 }
    612 
    613 base::StringValue* ModelTypeToValue(ModelType model_type) {
    614   if (model_type >= FIRST_REAL_MODEL_TYPE) {
    615     return new base::StringValue(ModelTypeToString(model_type));
    616   } else if (model_type == TOP_LEVEL_FOLDER) {
    617     return new base::StringValue("Top-level folder");
    618   } else if (model_type == UNSPECIFIED) {
    619     return new base::StringValue("Unspecified");
    620   }
    621   NOTREACHED();
    622   return new base::StringValue(std::string());
    623 }
    624 
    625 ModelType ModelTypeFromValue(const base::Value& value) {
    626   if (value.IsType(base::Value::TYPE_STRING)) {
    627     std::string result;
    628     CHECK(value.GetAsString(&result));
    629     return ModelTypeFromString(result);
    630   } else if (value.IsType(base::Value::TYPE_INTEGER)) {
    631     int result;
    632     CHECK(value.GetAsInteger(&result));
    633     return ModelTypeFromInt(result);
    634   } else {
    635     NOTREACHED() << "Unsupported value type: " << value.GetType();
    636     return UNSPECIFIED;
    637   }
    638 }
    639 
    640 ModelType ModelTypeFromString(const std::string& model_type_string) {
    641   if (model_type_string == "Bookmarks")
    642     return BOOKMARKS;
    643   else if (model_type_string == "Preferences")
    644     return PREFERENCES;
    645   else if (model_type_string == "Passwords")
    646     return PASSWORDS;
    647   else if (model_type_string == "Autofill")
    648     return AUTOFILL;
    649   else if (model_type_string == "Autofill Profiles")
    650     return AUTOFILL_PROFILE;
    651   else if (model_type_string == "Themes")
    652     return THEMES;
    653   else if (model_type_string == "Typed URLs")
    654     return TYPED_URLS;
    655   else if (model_type_string == "Extensions")
    656     return EXTENSIONS;
    657   else if (model_type_string == "Encryption keys")
    658     return NIGORI;
    659   else if (model_type_string == "Search Engines")
    660     return SEARCH_ENGINES;
    661   else if (model_type_string == "Sessions")
    662     return SESSIONS;
    663   else if (model_type_string == "Apps")
    664     return APPS;
    665   else if (model_type_string == "App List")
    666     return APP_LIST;
    667   else if (model_type_string == "App settings")
    668     return APP_SETTINGS;
    669   else if (model_type_string == "Extension settings")
    670     return EXTENSION_SETTINGS;
    671   else if (model_type_string == "App Notifications")
    672     return APP_NOTIFICATIONS;
    673   else if (model_type_string == "History Delete Directives")
    674     return HISTORY_DELETE_DIRECTIVES;
    675   else if (model_type_string == "Synced Notifications")
    676     return SYNCED_NOTIFICATIONS;
    677   else if (model_type_string == "Synced Notification App Info")
    678     return SYNCED_NOTIFICATION_APP_INFO;
    679   else if (model_type_string == "Device Info")
    680     return DEVICE_INFO;
    681   else if (model_type_string == "Experiments")
    682     return EXPERIMENTS;
    683   else if (model_type_string == "Priority Preferences")
    684     return PRIORITY_PREFERENCES;
    685   else if (model_type_string == "Dictionary")
    686     return DICTIONARY;
    687   else if (model_type_string == "Favicon Images")
    688     return FAVICON_IMAGES;
    689   else if (model_type_string == "Favicon Tracking")
    690     return FAVICON_TRACKING;
    691   else if (model_type_string == "Managed User Settings")
    692     return SUPERVISED_USER_SETTINGS;
    693   else if (model_type_string == "Managed Users")
    694     return SUPERVISED_USERS;
    695   else if (model_type_string == "Managed User Shared Settings")
    696     return SUPERVISED_USER_SHARED_SETTINGS;
    697   else if (model_type_string == "Articles")
    698     return ARTICLES;
    699   else if (model_type_string == "Tabs")
    700     return PROXY_TABS;
    701   else
    702     NOTREACHED() << "No known model type corresponding to "
    703                  << model_type_string << ".";
    704   return UNSPECIFIED;
    705 }
    706 
    707 std::string ModelTypeSetToString(ModelTypeSet model_types) {
    708   std::string result;
    709   for (ModelTypeSet::Iterator it = model_types.First(); it.Good(); it.Inc()) {
    710     if (!result.empty()) {
    711       result += ", ";
    712     }
    713     result += ModelTypeToString(it.Get());
    714   }
    715   return result;
    716 }
    717 
    718 ModelTypeSet ModelTypeSetFromString(const std::string& model_types_string) {
    719   std::string working_copy = model_types_string;
    720   ModelTypeSet model_types;
    721   while (!working_copy.empty()) {
    722     // Remove any leading spaces.
    723     working_copy = working_copy.substr(working_copy.find_first_not_of(' '));
    724     if (working_copy.empty())
    725       break;
    726     std::string type_str;
    727     size_t end = working_copy.find(',');
    728     if (end == std::string::npos) {
    729       end = working_copy.length() - 1;
    730       type_str = working_copy;
    731     } else {
    732       type_str = working_copy.substr(0, end);
    733     }
    734     syncer::ModelType type = ModelTypeFromString(type_str);
    735     if (IsRealDataType(type))
    736       model_types.Put(type);
    737     working_copy = working_copy.substr(end + 1);
    738   }
    739   return model_types;
    740 }
    741 
    742 base::ListValue* ModelTypeSetToValue(ModelTypeSet model_types) {
    743   base::ListValue* value = new base::ListValue();
    744   for (ModelTypeSet::Iterator it = model_types.First(); it.Good(); it.Inc()) {
    745     value->Append(new base::StringValue(ModelTypeToString(it.Get())));
    746   }
    747   return value;
    748 }
    749 
    750 ModelTypeSet ModelTypeSetFromValue(const base::ListValue& value) {
    751   ModelTypeSet result;
    752   for (base::ListValue::const_iterator i = value.begin();
    753        i != value.end(); ++i) {
    754     result.Put(ModelTypeFromValue(**i));
    755   }
    756   return result;
    757 }
    758 
    759 // TODO(zea): remove all hardcoded tags in model associators and have them use
    760 // this instead.
    761 // NOTE: Proxy types should return empty strings (so that we don't NOTREACHED
    762 // in tests when we verify they have no root node).
    763 std::string ModelTypeToRootTag(ModelType type) {
    764   switch (type) {
    765     case BOOKMARKS:
    766       return "google_chrome_bookmarks";
    767     case PREFERENCES:
    768       return "google_chrome_preferences";
    769     case PASSWORDS:
    770       return "google_chrome_passwords";
    771     case AUTOFILL:
    772       return "google_chrome_autofill";
    773     case THEMES:
    774       return "google_chrome_themes";
    775     case TYPED_URLS:
    776       return "google_chrome_typed_urls";
    777     case EXTENSIONS:
    778       return "google_chrome_extensions";
    779     case NIGORI:
    780       return "google_chrome_nigori";
    781     case SEARCH_ENGINES:
    782       return "google_chrome_search_engines";
    783     case SESSIONS:
    784       return "google_chrome_sessions";
    785     case APPS:
    786       return "google_chrome_apps";
    787     case APP_LIST:
    788       return "google_chrome_app_list";
    789     case AUTOFILL_PROFILE:
    790       return "google_chrome_autofill_profiles";
    791     case APP_SETTINGS:
    792       return "google_chrome_app_settings";
    793     case EXTENSION_SETTINGS:
    794       return "google_chrome_extension_settings";
    795     case APP_NOTIFICATIONS:
    796       return "google_chrome_app_notifications";
    797     case HISTORY_DELETE_DIRECTIVES:
    798       return "google_chrome_history_delete_directives";
    799     case SYNCED_NOTIFICATIONS:
    800       return "google_chrome_synced_notifications";
    801     case SYNCED_NOTIFICATION_APP_INFO:
    802       return "google_chrome_synced_notification_app_info";
    803     case DEVICE_INFO:
    804       return "google_chrome_device_info";
    805     case EXPERIMENTS:
    806       return "google_chrome_experiments";
    807     case PRIORITY_PREFERENCES:
    808       return "google_chrome_priority_preferences";
    809     case DICTIONARY:
    810       return "google_chrome_dictionary";
    811     case FAVICON_IMAGES:
    812       return "google_chrome_favicon_images";
    813     case FAVICON_TRACKING:
    814       return "google_chrome_favicon_tracking";
    815     case SUPERVISED_USER_SETTINGS:
    816       return "google_chrome_managed_user_settings";
    817     case SUPERVISED_USERS:
    818       return "google_chrome_managed_users";
    819     case SUPERVISED_USER_SHARED_SETTINGS:
    820       return "google_chrome_managed_user_shared_settings";
    821     case ARTICLES:
    822       return "google_chrome_articles";
    823     case PROXY_TABS:
    824       return std::string();
    825     default:
    826       break;
    827   }
    828   NOTREACHED() << "No known extension for model type.";
    829   return "INVALID";
    830 }
    831 
    832 // TODO(akalin): Figure out a better way to do these mappings.
    833 // Note: Do not include proxy types in this list. They should never receive
    834 // or trigger notifications.
    835 namespace {
    836 const char kBookmarkNotificationType[] = "BOOKMARK";
    837 const char kPreferenceNotificationType[] = "PREFERENCE";
    838 const char kPasswordNotificationType[] = "PASSWORD";
    839 const char kAutofillNotificationType[] = "AUTOFILL";
    840 const char kThemeNotificationType[] = "THEME";
    841 const char kTypedUrlNotificationType[] = "TYPED_URL";
    842 const char kExtensionNotificationType[] = "EXTENSION";
    843 const char kExtensionSettingNotificationType[] = "EXTENSION_SETTING";
    844 const char kNigoriNotificationType[] = "NIGORI";
    845 const char kAppSettingNotificationType[] = "APP_SETTING";
    846 const char kAppNotificationType[] = "APP";
    847 const char kAppListNotificationType[] = "APP_LIST";
    848 const char kSearchEngineNotificationType[] = "SEARCH_ENGINE";
    849 const char kSessionNotificationType[] = "SESSION";
    850 const char kAutofillProfileNotificationType[] = "AUTOFILL_PROFILE";
    851 const char kAppNotificationNotificationType[] = "APP_NOTIFICATION";
    852 const char kHistoryDeleteDirectiveNotificationType[] =
    853     "HISTORY_DELETE_DIRECTIVE";
    854 const char kSyncedNotificationType[] = "SYNCED_NOTIFICATION";
    855 const char kSyncedNotificationAppInfoType[] = "SYNCED_NOTIFICATION_APP_INFO";
    856 const char kDeviceInfoNotificationType[] = "DEVICE_INFO";
    857 const char kExperimentsNotificationType[] = "EXPERIMENTS";
    858 const char kPriorityPreferenceNotificationType[] = "PRIORITY_PREFERENCE";
    859 const char kDictionaryNotificationType[] = "DICTIONARY";
    860 const char kFaviconImageNotificationType[] = "FAVICON_IMAGE";
    861 const char kFaviconTrackingNotificationType[] = "FAVICON_TRACKING";
    862 const char kSupervisedUserSettingNotificationType[] = "MANAGED_USER_SETTING";
    863 const char kSupervisedUserNotificationType[] = "MANAGED_USER";
    864 const char kSupervisedUserSharedSettingNotificationType[] =
    865     "MANAGED_USER_SHARED_SETTING";
    866 const char kArticleNotificationType[] = "ARTICLE";
    867 }  // namespace
    868 
    869 bool RealModelTypeToNotificationType(ModelType model_type,
    870                                      std::string* notification_type) {
    871   switch (model_type) {
    872     case BOOKMARKS:
    873       *notification_type = kBookmarkNotificationType;
    874       return true;
    875     case PREFERENCES:
    876       *notification_type = kPreferenceNotificationType;
    877       return true;
    878     case PASSWORDS:
    879       *notification_type = kPasswordNotificationType;
    880       return true;
    881     case AUTOFILL:
    882       *notification_type = kAutofillNotificationType;
    883       return true;
    884     case THEMES:
    885       *notification_type = kThemeNotificationType;
    886       return true;
    887     case TYPED_URLS:
    888       *notification_type = kTypedUrlNotificationType;
    889       return true;
    890     case EXTENSIONS:
    891       *notification_type = kExtensionNotificationType;
    892       return true;
    893     case NIGORI:
    894       *notification_type = kNigoriNotificationType;
    895       return true;
    896     case APP_SETTINGS:
    897       *notification_type = kAppSettingNotificationType;
    898       return true;
    899     case APPS:
    900       *notification_type = kAppNotificationType;
    901       return true;
    902     case APP_LIST:
    903       *notification_type = kAppListNotificationType;
    904       return true;
    905     case SEARCH_ENGINES:
    906       *notification_type = kSearchEngineNotificationType;
    907       return true;
    908     case SESSIONS:
    909       *notification_type = kSessionNotificationType;
    910       return true;
    911     case AUTOFILL_PROFILE:
    912       *notification_type = kAutofillProfileNotificationType;
    913       return true;
    914     case EXTENSION_SETTINGS:
    915       *notification_type = kExtensionSettingNotificationType;
    916       return true;
    917     case APP_NOTIFICATIONS:
    918       *notification_type = kAppNotificationNotificationType;
    919       return true;
    920     case HISTORY_DELETE_DIRECTIVES:
    921       *notification_type = kHistoryDeleteDirectiveNotificationType;
    922       return true;
    923     case SYNCED_NOTIFICATIONS:
    924       *notification_type = kSyncedNotificationType;
    925       return true;
    926     case SYNCED_NOTIFICATION_APP_INFO:
    927       *notification_type = kSyncedNotificationAppInfoType;
    928       return true;
    929     case DEVICE_INFO:
    930       *notification_type = kDeviceInfoNotificationType;
    931       return true;
    932     case EXPERIMENTS:
    933       *notification_type = kExperimentsNotificationType;
    934       return true;
    935     case PRIORITY_PREFERENCES:
    936       *notification_type = kPriorityPreferenceNotificationType;
    937       return true;
    938     case DICTIONARY:
    939       *notification_type = kDictionaryNotificationType;
    940       return true;
    941     case FAVICON_IMAGES:
    942       *notification_type = kFaviconImageNotificationType;
    943       return true;
    944     case FAVICON_TRACKING:
    945       *notification_type = kFaviconTrackingNotificationType;
    946       return true;
    947     case SUPERVISED_USER_SETTINGS:
    948       *notification_type = kSupervisedUserSettingNotificationType;
    949       return true;
    950     case SUPERVISED_USERS:
    951       *notification_type = kSupervisedUserNotificationType;
    952       return true;
    953     case SUPERVISED_USER_SHARED_SETTINGS:
    954       *notification_type = kSupervisedUserSharedSettingNotificationType;
    955       return true;
    956     case ARTICLES:
    957       *notification_type = kArticleNotificationType;
    958       return true;
    959     default:
    960       break;
    961   }
    962   notification_type->clear();
    963   return false;
    964 }
    965 
    966 bool NotificationTypeToRealModelType(const std::string& notification_type,
    967                                      ModelType* model_type) {
    968   if (notification_type == kBookmarkNotificationType) {
    969     *model_type = BOOKMARKS;
    970     return true;
    971   } else if (notification_type == kPreferenceNotificationType) {
    972     *model_type = PREFERENCES;
    973     return true;
    974   } else if (notification_type == kPasswordNotificationType) {
    975     *model_type = PASSWORDS;
    976     return true;
    977   } else if (notification_type == kAutofillNotificationType) {
    978     *model_type = AUTOFILL;
    979     return true;
    980   } else if (notification_type == kThemeNotificationType) {
    981     *model_type = THEMES;
    982     return true;
    983   } else if (notification_type == kTypedUrlNotificationType) {
    984     *model_type = TYPED_URLS;
    985     return true;
    986   } else if (notification_type == kExtensionNotificationType) {
    987     *model_type = EXTENSIONS;
    988     return true;
    989   } else if (notification_type == kNigoriNotificationType) {
    990     *model_type = NIGORI;
    991     return true;
    992   } else if (notification_type == kAppNotificationType) {
    993     *model_type = APPS;
    994     return true;
    995   } else if (notification_type == kAppListNotificationType) {
    996     *model_type = APP_LIST;
    997     return true;
    998   } else if (notification_type == kSearchEngineNotificationType) {
    999     *model_type = SEARCH_ENGINES;
   1000     return true;
   1001   } else if (notification_type == kSessionNotificationType) {
   1002     *model_type = SESSIONS;
   1003     return true;
   1004   } else if (notification_type == kAutofillProfileNotificationType) {
   1005     *model_type = AUTOFILL_PROFILE;
   1006     return true;
   1007   } else if (notification_type == kAppSettingNotificationType) {
   1008     *model_type = APP_SETTINGS;
   1009     return true;
   1010   } else if (notification_type == kExtensionSettingNotificationType) {
   1011     *model_type = EXTENSION_SETTINGS;
   1012     return true;
   1013   } else if (notification_type == kAppNotificationNotificationType) {
   1014     *model_type = APP_NOTIFICATIONS;
   1015     return true;
   1016   } else if (notification_type == kHistoryDeleteDirectiveNotificationType) {
   1017     *model_type = HISTORY_DELETE_DIRECTIVES;
   1018     return true;
   1019   } else if (notification_type == kSyncedNotificationType) {
   1020     *model_type = SYNCED_NOTIFICATIONS;
   1021     return true;
   1022   } else if (notification_type == kSyncedNotificationAppInfoType) {
   1023     *model_type = SYNCED_NOTIFICATION_APP_INFO;
   1024     return true;
   1025   } else if (notification_type == kDeviceInfoNotificationType) {
   1026     *model_type = DEVICE_INFO;
   1027     return true;
   1028   } else if (notification_type == kExperimentsNotificationType) {
   1029     *model_type = EXPERIMENTS;
   1030     return true;
   1031   } else if (notification_type == kPriorityPreferenceNotificationType) {
   1032     *model_type = PRIORITY_PREFERENCES;
   1033     return true;
   1034   } else if (notification_type == kDictionaryNotificationType) {
   1035     *model_type = DICTIONARY;
   1036     return true;
   1037   } else if (notification_type == kFaviconImageNotificationType) {
   1038     *model_type = FAVICON_IMAGES;
   1039     return true;
   1040   } else if (notification_type == kFaviconTrackingNotificationType) {
   1041     *model_type = FAVICON_TRACKING;
   1042     return true;
   1043   } else if (notification_type == kSupervisedUserSettingNotificationType) {
   1044     *model_type = SUPERVISED_USER_SETTINGS;
   1045     return true;
   1046   } else if (notification_type == kSupervisedUserNotificationType) {
   1047     *model_type = SUPERVISED_USERS;
   1048     return true;
   1049   } else if (notification_type ==
   1050       kSupervisedUserSharedSettingNotificationType) {
   1051     *model_type = SUPERVISED_USER_SHARED_SETTINGS;
   1052     return true;
   1053   } else if (notification_type == kArticleNotificationType) {
   1054     *model_type = ARTICLES;
   1055     return true;
   1056   }
   1057   *model_type = UNSPECIFIED;
   1058   return false;
   1059 }
   1060 
   1061 bool IsRealDataType(ModelType model_type) {
   1062   return model_type >= FIRST_REAL_MODEL_TYPE && model_type < MODEL_TYPE_COUNT;
   1063 }
   1064 
   1065 bool IsProxyType(ModelType model_type) {
   1066   return model_type >= FIRST_PROXY_TYPE && model_type <= LAST_PROXY_TYPE;
   1067 }
   1068 
   1069 bool IsActOnceDataType(ModelType model_type) {
   1070   return model_type == HISTORY_DELETE_DIRECTIVES;
   1071 }
   1072 
   1073 }  // namespace syncer
   1074