• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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/sync/syncable/model_type.h"
6 
7 #include "base/metrics/histogram.h"
8 #include "base/values.h"
9 #include "chrome/browser/sync/engine/syncproto.h"
10 #include "chrome/browser/sync/protocol/app_specifics.pb.h"
11 #include "chrome/browser/sync/protocol/autofill_specifics.pb.h"
12 #include "chrome/browser/sync/protocol/bookmark_specifics.pb.h"
13 #include "chrome/browser/sync/protocol/extension_specifics.pb.h"
14 #include "chrome/browser/sync/protocol/nigori_specifics.pb.h"
15 #include "chrome/browser/sync/protocol/password_specifics.pb.h"
16 #include "chrome/browser/sync/protocol/preference_specifics.pb.h"
17 #include "chrome/browser/sync/protocol/session_specifics.pb.h"
18 #include "chrome/browser/sync/protocol/sync.pb.h"
19 #include "chrome/browser/sync/protocol/theme_specifics.pb.h"
20 #include "chrome/browser/sync/protocol/typed_url_specifics.pb.h"
21 
22 namespace syncable {
23 
AddDefaultExtensionValue(syncable::ModelType datatype,sync_pb::EntitySpecifics * specifics)24 void AddDefaultExtensionValue(syncable::ModelType datatype,
25                               sync_pb::EntitySpecifics* specifics) {
26   switch (datatype) {
27     case BOOKMARKS:
28       specifics->MutableExtension(sync_pb::bookmark);
29       break;
30     case PASSWORDS:
31       specifics->MutableExtension(sync_pb::password);
32       break;
33     case PREFERENCES:
34       specifics->MutableExtension(sync_pb::preference);
35       break;
36     case AUTOFILL:
37       specifics->MutableExtension(sync_pb::autofill);
38       break;
39     case AUTOFILL_PROFILE:
40       specifics->MutableExtension(sync_pb::autofill_profile);
41       break;
42     case THEMES:
43       specifics->MutableExtension(sync_pb::theme);
44       break;
45     case TYPED_URLS:
46       specifics->MutableExtension(sync_pb::typed_url);
47       break;
48     case EXTENSIONS:
49       specifics->MutableExtension(sync_pb::extension);
50       break;
51     case NIGORI:
52       specifics->MutableExtension(sync_pb::nigori);
53       break;
54     case SESSIONS:
55       specifics->MutableExtension(sync_pb::session);
56       break;
57     case APPS:
58       specifics->MutableExtension(sync_pb::app);
59       break;
60     default:
61       NOTREACHED() << "No known extension for model type.";
62   }
63 }
64 
GetModelTypeFromExtensionFieldNumber(int field_number)65 ModelType GetModelTypeFromExtensionFieldNumber(int field_number) {
66   for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) {
67     ModelType model_type = ModelTypeFromInt(i);
68     if (GetExtensionFieldNumberFromModelType(model_type) == field_number)
69       return model_type;
70   }
71   NOTREACHED();
72   return UNSPECIFIED;
73 }
74 
GetExtensionFieldNumberFromModelType(ModelType model_type)75 int GetExtensionFieldNumberFromModelType(ModelType model_type) {
76   switch (model_type) {
77     case BOOKMARKS:
78       return sync_pb::kBookmarkFieldNumber;
79       break;
80     case PASSWORDS:
81       return sync_pb::kPasswordFieldNumber;
82       break;
83     case PREFERENCES:
84       return sync_pb::kPreferenceFieldNumber;
85       break;
86     case AUTOFILL:
87       return sync_pb::kAutofillFieldNumber;
88       break;
89     case AUTOFILL_PROFILE:
90       return sync_pb::kAutofillProfileFieldNumber;
91       break;
92     case THEMES:
93       return sync_pb::kThemeFieldNumber;
94       break;
95     case TYPED_URLS:
96       return sync_pb::kTypedUrlFieldNumber;
97       break;
98     case EXTENSIONS:
99       return sync_pb::kExtensionFieldNumber;
100       break;
101     case NIGORI:
102       return sync_pb::kNigoriFieldNumber;
103       break;
104     case SESSIONS:
105       return sync_pb::kSessionFieldNumber;
106       break;
107     case APPS:
108       return sync_pb::kAppFieldNumber;
109       break;
110     default:
111       NOTREACHED() << "No known extension for model type.";
112       return 0;
113   }
114   NOTREACHED() << "Needed for linux_keep_shadow_stacks because of "
115                << "http://gcc.gnu.org/bugzilla/show_bug.cgi?id=20681";
116   return 0;
117 }
118 
119 // Note: keep this consistent with GetModelType in syncable.cc!
GetModelType(const sync_pb::SyncEntity & sync_pb_entity)120 ModelType GetModelType(const sync_pb::SyncEntity& sync_pb_entity) {
121   const browser_sync::SyncEntity& sync_entity =
122       static_cast<const browser_sync::SyncEntity&>(sync_pb_entity);
123   DCHECK(!sync_entity.id().IsRoot());  // Root shouldn't ever go over the wire.
124 
125   if (sync_entity.deleted())
126     return UNSPECIFIED;
127 
128   // Backwards compatibility with old (pre-specifics) protocol.
129   if (sync_entity.has_bookmarkdata())
130     return BOOKMARKS;
131 
132   ModelType specifics_type = GetModelTypeFromSpecifics(sync_entity.specifics());
133   if (specifics_type != UNSPECIFIED)
134     return specifics_type;
135 
136   // Loose check for server-created top-level folders that aren't
137   // bound to a particular model type.
138   if (!sync_entity.server_defined_unique_tag().empty() &&
139       sync_entity.IsFolder()) {
140     return TOP_LEVEL_FOLDER;
141   }
142 
143   // This is an item of a datatype we can't understand. Maybe it's
144   // from the future?  Either we mis-encoded the object, or the
145   // server sent us entries it shouldn't have.
146   NOTREACHED() << "Unknown datatype in sync proto.";
147   return UNSPECIFIED;
148 }
149 
GetModelTypeFromSpecifics(const sync_pb::EntitySpecifics & specifics)150 ModelType GetModelTypeFromSpecifics(const sync_pb::EntitySpecifics& specifics) {
151   if (specifics.HasExtension(sync_pb::bookmark))
152     return BOOKMARKS;
153 
154   if (specifics.HasExtension(sync_pb::password))
155     return PASSWORDS;
156 
157   if (specifics.HasExtension(sync_pb::preference))
158     return PREFERENCES;
159 
160   if (specifics.HasExtension(sync_pb::autofill))
161     return AUTOFILL;
162 
163   if (specifics.HasExtension(sync_pb::autofill_profile))
164     return AUTOFILL_PROFILE;
165 
166   if (specifics.HasExtension(sync_pb::theme))
167     return THEMES;
168 
169   if (specifics.HasExtension(sync_pb::typed_url))
170     return TYPED_URLS;
171 
172   if (specifics.HasExtension(sync_pb::extension))
173     return EXTENSIONS;
174 
175   if (specifics.HasExtension(sync_pb::nigori))
176     return NIGORI;
177 
178   if (specifics.HasExtension(sync_pb::app))
179     return APPS;
180 
181   if (specifics.HasExtension(sync_pb::session))
182     return SESSIONS;
183 
184   return UNSPECIFIED;
185 }
186 
ModelTypeToString(ModelType model_type)187 std::string ModelTypeToString(ModelType model_type) {
188   switch (model_type) {
189     case BOOKMARKS:
190       return "Bookmarks";
191     case PREFERENCES:
192       return "Preferences";
193     case PASSWORDS:
194       return "Passwords";
195     case AUTOFILL:
196       return "Autofill";
197     case THEMES:
198       return "Themes";
199     case TYPED_URLS:
200       return "Typed URLs";
201     case EXTENSIONS:
202       return "Extensions";
203     case NIGORI:
204       return "Encryption keys";
205     case SESSIONS:
206       return "Sessions";
207     case APPS:
208       return "Apps";
209     case AUTOFILL_PROFILE:
210       return "Autofill Profiles";
211     default:
212       break;
213   }
214   NOTREACHED() << "No known extension for model type.";
215   return "INVALID";
216 }
217 
ModelTypeToValue(ModelType model_type)218 StringValue* ModelTypeToValue(ModelType model_type) {
219   if (model_type >= syncable::FIRST_REAL_MODEL_TYPE) {
220     return Value::CreateStringValue(ModelTypeToString(model_type));
221   } else if (model_type == syncable::TOP_LEVEL_FOLDER) {
222     return Value::CreateStringValue("Top-level folder");
223   } else if (model_type == syncable::UNSPECIFIED) {
224     return Value::CreateStringValue("Unspecified");
225   }
226   NOTREACHED();
227   return Value::CreateStringValue("");
228 }
229 
ModelTypeSetToString(const ModelTypeSet & model_types)230 std::string ModelTypeSetToString(const ModelTypeSet& model_types) {
231   std::string result;
232   for (ModelTypeSet::const_iterator iter = model_types.begin();
233        iter != model_types.end();) {
234     result += ModelTypeToString(*iter);
235     if (++iter != model_types.end())
236       result += ", ";
237   }
238   return result;
239 }
240 
ModelTypeFromString(const std::string & model_type_string)241 ModelType ModelTypeFromString(const std::string& model_type_string) {
242   if (model_type_string == "Bookmarks")
243     return BOOKMARKS;
244   else if (model_type_string == "Preferences")
245     return PREFERENCES;
246   else if (model_type_string == "Passwords")
247     return PASSWORDS;
248   else if (model_type_string == "Autofill")
249     return AUTOFILL;
250   else if (model_type_string == "Autofill Profiles")
251     return AUTOFILL_PROFILE;
252   else if (model_type_string == "Themes")
253     return THEMES;
254   else if (model_type_string == "Typed URLs")
255     return TYPED_URLS;
256   else if (model_type_string == "Extensions")
257     return EXTENSIONS;
258   else if (model_type_string == "Encryption keys")
259     return NIGORI;
260   else if (model_type_string == "Sessions")
261     return SESSIONS;
262   else if (model_type_string == "Apps")
263     return APPS;
264   else
265     NOTREACHED() << "No known model type corresponding to "
266                  << model_type_string << ".";
267   return UNSPECIFIED;
268 }
269 
ModelTypeBitSetFromString(const std::string & model_type_bitset_string,ModelTypeBitSet * model_types)270 bool ModelTypeBitSetFromString(
271     const std::string& model_type_bitset_string,
272     ModelTypeBitSet* model_types) {
273   DCHECK(model_types);
274   if (model_type_bitset_string.length() != MODEL_TYPE_COUNT)
275     return false;
276   if (model_type_bitset_string.find_first_not_of("01") != std::string::npos)
277     return false;
278   *model_types = ModelTypeBitSet(model_type_bitset_string);
279   return true;
280 }
281 
ModelTypeBitSetFromSet(const ModelTypeSet & set)282 ModelTypeBitSet ModelTypeBitSetFromSet(const ModelTypeSet& set) {
283   ModelTypeBitSet bitset;
284   for (ModelTypeSet::const_iterator iter = set.begin(); iter != set.end();
285        ++iter) {
286     bitset.set(*iter);
287   }
288   return bitset;
289 }
290 
ModelTypeBitSetToValue(const ModelTypeBitSet & model_types)291 ListValue* ModelTypeBitSetToValue(const ModelTypeBitSet& model_types) {
292   ListValue* value = new ListValue();
293   for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) {
294     if (model_types[i]) {
295       value->Append(
296           Value::CreateStringValue(ModelTypeToString(ModelTypeFromInt(i))));
297     }
298   }
299   return value;
300 }
301 
ModelTypeSetToValue(const ModelTypeSet & model_types)302 ListValue* ModelTypeSetToValue(const ModelTypeSet& model_types) {
303   ListValue* value = new ListValue();
304   for (ModelTypeSet::const_iterator i = model_types.begin();
305        i != model_types.end(); ++i) {
306     value->Append(Value::CreateStringValue(ModelTypeToString(*i)));
307   }
308   return value;
309 }
310 
311 // TODO(zea): remove all hardcoded tags in model associators and have them use
312 // this instead.
ModelTypeToRootTag(ModelType type)313 std::string ModelTypeToRootTag(ModelType type) {
314   switch (type) {
315     case BOOKMARKS:
316       return "google_chrome_bookmarks";
317     case PREFERENCES:
318       return "google_chrome_preferences";
319     case PASSWORDS:
320       return "google_chrome_passwords";
321     case AUTOFILL:
322       return "google_chrome_autofill";
323     case THEMES:
324       return "google_chrome_themes";
325     case TYPED_URLS:
326       return "google_chrome_typed_urls";
327     case EXTENSIONS:
328       return "google_chrome_extensions";
329     case NIGORI:
330       return "google_chrome_nigori";
331     case SESSIONS:
332       return "google_chrome_sessions";
333     case APPS:
334       return "google_chrome_apps";
335     case AUTOFILL_PROFILE:
336       return "google_chrome_autofill_profiles";
337     default:
338       break;
339   }
340   NOTREACHED() << "No known extension for model type.";
341   return "INVALID";
342 }
343 
344 // For now, this just implements UMA_HISTOGRAM_LONG_TIMES. This can be adjusted
345 // if we feel the min, max, or bucket count amount are not appropriate.
346 #define SYNC_FREQ_HISTOGRAM(name, time) UMA_HISTOGRAM_CUSTOM_TIMES( \
347     name, time, base::TimeDelta::FromMilliseconds(1), \
348     base::TimeDelta::FromHours(1), 50)
349 
PostTimeToTypeHistogram(ModelType model_type,base::TimeDelta time)350 void PostTimeToTypeHistogram(ModelType model_type, base::TimeDelta time) {
351   switch (model_type) {
352     case BOOKMARKS: {
353         SYNC_FREQ_HISTOGRAM("Sync.FreqBookmarks", time);
354         return;
355     }
356     case PREFERENCES: {
357         SYNC_FREQ_HISTOGRAM("Sync.FreqPreferences", time);
358         return;
359     }
360     case PASSWORDS: {
361         SYNC_FREQ_HISTOGRAM("Sync.FreqPasswords", time);
362         return;
363     }
364     case AUTOFILL: {
365         SYNC_FREQ_HISTOGRAM("Sync.FreqAutofill", time);
366         return;
367     }
368     case AUTOFILL_PROFILE: {
369         SYNC_FREQ_HISTOGRAM("Sync.FreqAutofillProfiles", time);
370         return;
371     }
372     case THEMES: {
373         SYNC_FREQ_HISTOGRAM("Sync.FreqThemes", time);
374         return;
375     }
376     case TYPED_URLS: {
377         SYNC_FREQ_HISTOGRAM("Sync.FreqTypedUrls", time);
378         return;
379     }
380     case EXTENSIONS: {
381         SYNC_FREQ_HISTOGRAM("Sync.FreqExtensions", time);
382         return;
383     }
384     case NIGORI: {
385         SYNC_FREQ_HISTOGRAM("Sync.FreqNigori", time);
386         return;
387     }
388     case SESSIONS: {
389         SYNC_FREQ_HISTOGRAM("Sync.FreqSessions", time);
390         return;
391     }
392     case APPS: {
393         SYNC_FREQ_HISTOGRAM("Sync.FreqApps", time);
394         return;
395     }
396     default:
397       LOG(ERROR) << "No known extension for model type.";
398   }
399 }
400 
401 #undef SYNC_FREQ_HISTOGRAM
402 
403 // TODO(akalin): Figure out a better way to do these mappings.
404 
405 namespace {
406 const char kBookmarkNotificationType[] = "BOOKMARK";
407 const char kPreferenceNotificationType[] = "PREFERENCE";
408 const char kPasswordNotificationType[] = "PASSWORD";
409 const char kAutofillNotificationType[] = "AUTOFILL";
410 const char kThemeNotificationType[] = "THEME";
411 const char kTypedUrlNotificationType[] = "TYPED_URL";
412 const char kExtensionNotificationType[] = "EXTENSION";
413 const char kNigoriNotificationType[] = "NIGORI";
414 const char kAppNotificationType[] = "APP";
415 const char kSessionNotificationType[] = "SESSION";
416 const char kAutofillProfileNotificationType[] = "AUTOFILL_PROFILE";
417 }  // namespace
418 
RealModelTypeToNotificationType(ModelType model_type,std::string * notification_type)419 bool RealModelTypeToNotificationType(ModelType model_type,
420                                      std::string* notification_type) {
421   switch (model_type) {
422     case BOOKMARKS:
423       *notification_type = kBookmarkNotificationType;
424       return true;
425     case PREFERENCES:
426       *notification_type = kPreferenceNotificationType;
427       return true;
428     case PASSWORDS:
429       *notification_type = kPasswordNotificationType;
430       return true;
431     case AUTOFILL:
432       *notification_type = kAutofillNotificationType;
433       return true;
434     case THEMES:
435       *notification_type = kThemeNotificationType;
436       return true;
437     case TYPED_URLS:
438       *notification_type = kTypedUrlNotificationType;
439       return true;
440     case EXTENSIONS:
441       *notification_type = kExtensionNotificationType;
442       return true;
443     case NIGORI:
444       *notification_type = kNigoriNotificationType;
445       return true;
446     case APPS:
447       *notification_type = kAppNotificationType;
448       return true;
449     case SESSIONS:
450       *notification_type = kSessionNotificationType;
451       return true;
452     case AUTOFILL_PROFILE:
453       *notification_type = kAutofillProfileNotificationType;
454       return true;
455     default:
456       break;
457   }
458   notification_type->clear();
459   return false;
460 }
461 
NotificationTypeToRealModelType(const std::string & notification_type,ModelType * model_type)462 bool NotificationTypeToRealModelType(const std::string& notification_type,
463                                      ModelType* model_type) {
464   if (notification_type == kBookmarkNotificationType) {
465     *model_type = BOOKMARKS;
466     return true;
467   } else if (notification_type == kPreferenceNotificationType) {
468     *model_type = PREFERENCES;
469     return true;
470   } else if (notification_type == kPasswordNotificationType) {
471     *model_type = PASSWORDS;
472     return true;
473   } else if (notification_type == kAutofillNotificationType) {
474     *model_type = AUTOFILL;
475     return true;
476   } else if (notification_type == kThemeNotificationType) {
477     *model_type = THEMES;
478     return true;
479   } else if (notification_type == kTypedUrlNotificationType) {
480     *model_type = TYPED_URLS;
481     return true;
482   } else if (notification_type == kExtensionNotificationType) {
483     *model_type = EXTENSIONS;
484     return true;
485   } else if (notification_type == kNigoriNotificationType) {
486     *model_type = NIGORI;
487     return true;
488   } else if (notification_type == kAppNotificationType) {
489     *model_type = APPS;
490     return true;
491   } else if (notification_type == kSessionNotificationType) {
492     *model_type = SESSIONS;
493     return true;
494   } else if (notification_type == kAutofillProfileNotificationType) {
495     *model_type = AUTOFILL_PROFILE;
496     return true;
497   }
498   *model_type = UNSPECIFIED;
499   return false;
500 }
501 
502 }  // namespace syncable
503