OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // The history system runs on a background thread so that potentially slow | 5 // The history system runs on a background thread so that potentially slow |
6 // database operations don't delay the browser. This backend processing is | 6 // database operations don't delay the browser. This backend processing is |
7 // represented by HistoryBackend. The HistoryService's job is to dispatch to | 7 // represented by HistoryBackend. The HistoryService's job is to dispatch to |
8 // that thread. | 8 // that thread. |
9 // | 9 // |
10 // Main thread History thread | 10 // Main thread History thread |
11 // ----------- -------------- | 11 // ----------- -------------- |
12 // HistoryService <----------------> HistoryBackend | 12 // HistoryService <----------------> HistoryBackend |
13 // -> HistoryDatabase | 13 // -> HistoryDatabase |
14 // -> SQLite connection to History | 14 // -> SQLite connection to History |
15 // -> ArchivedDatabase | 15 // -> ArchivedDatabase |
16 // -> SQLite connection to Archived History | 16 // -> SQLite connection to Archived History |
17 // -> TextDatabaseManager | 17 // -> TextDatabaseManager |
18 // -> SQLite connection to one month's data | 18 // -> SQLite connection to one month's data |
19 // -> SQLite connection to one month's data | 19 // -> SQLite connection to one month's data |
20 // ... | 20 // ... |
21 // -> ThumbnailDatabase | 21 // -> ThumbnailDatabase |
22 // -> SQLite connection to Thumbnails | 22 // -> SQLite connection to Thumbnails |
23 // (and favicons) | 23 // (and favicons) |
24 | 24 |
25 #include "chrome/browser/history/history.h" | 25 #include "chrome/browser/history/history.h" |
26 | 26 |
| 27 #include "base/bind_helpers.h" |
27 #include "base/callback.h" | 28 #include "base/callback.h" |
28 #include "base/command_line.h" | 29 #include "base/command_line.h" |
29 #include "base/compiler_specific.h" | 30 #include "base/compiler_specific.h" |
| 31 #include "base/json/json_writer.h" |
30 #include "base/location.h" | 32 #include "base/location.h" |
31 #include "base/memory/ref_counted.h" | 33 #include "base/memory/ref_counted.h" |
32 #include "base/message_loop.h" | 34 #include "base/message_loop.h" |
33 #include "base/path_service.h" | 35 #include "base/path_service.h" |
34 #include "base/sequenced_task_runner.h" | 36 #include "base/sequenced_task_runner.h" |
35 #include "base/string_util.h" | 37 #include "base/string_util.h" |
36 #include "base/thread_task_runner_handle.h" | 38 #include "base/thread_task_runner_handle.h" |
37 #include "base/threading/thread.h" | 39 #include "base/threading/thread.h" |
38 #include "chrome/browser/autocomplete/history_url_provider.h" | 40 #include "chrome/browser/autocomplete/history_url_provider.h" |
39 #include "chrome/browser/bookmarks/bookmark_model.h" | 41 #include "chrome/browser/bookmarks/bookmark_model.h" |
(...skipping 20 matching lines...) Expand all Loading... |
60 #include "chrome/common/pref_names.h" | 62 #include "chrome/common/pref_names.h" |
61 #include "chrome/common/thumbnail_score.h" | 63 #include "chrome/common/thumbnail_score.h" |
62 #include "chrome/common/url_constants.h" | 64 #include "chrome/common/url_constants.h" |
63 #include "content/public/browser/browser_thread.h" | 65 #include "content/public/browser/browser_thread.h" |
64 #include "content/public/browser/notification_service.h" | 66 #include "content/public/browser/notification_service.h" |
65 #include "grit/chromium_strings.h" | 67 #include "grit/chromium_strings.h" |
66 #include "grit/generated_resources.h" | 68 #include "grit/generated_resources.h" |
67 #include "sync/api/sync_change.h" | 69 #include "sync/api/sync_change.h" |
68 #include "sync/api/sync_data.h" | 70 #include "sync/api/sync_data.h" |
69 #include "sync/api/sync_error_factory.h" | 71 #include "sync/api/sync_error_factory.h" |
| 72 #include "sync/protocol/history_delete_directive_specifics.pb.h" |
| 73 #include "sync/protocol/proto_value_conversions.h" |
70 #include "sync/protocol/sync.pb.h" | 74 #include "sync/protocol/sync.pb.h" |
71 #include "third_party/skia/include/core/SkBitmap.h" | 75 #include "third_party/skia/include/core/SkBitmap.h" |
72 | 76 |
73 using base::Time; | 77 using base::Time; |
74 using history::HistoryBackend; | 78 using history::HistoryBackend; |
75 | 79 |
76 namespace { | 80 namespace { |
77 | 81 |
78 static const char* kHistoryThreadName = "Chrome_HistoryThread"; | 82 static const char* kHistoryThreadName = "Chrome_HistoryThread"; |
79 | 83 |
| 84 std::string DeleteDirectiveToString( |
| 85 const sync_pb::HistoryDeleteDirectiveSpecifics& delete_directive) { |
| 86 scoped_ptr<base::DictionaryValue> value( |
| 87 syncer::HistoryDeleteDirectiveSpecificsToValue(delete_directive)); |
| 88 std::string str; |
| 89 base::JSONWriter::Write(value.get(), &str); |
| 90 return str; |
| 91 } |
| 92 |
80 } // namespace | 93 } // namespace |
81 | 94 |
82 // Sends messages from the backend to us on the main thread. This must be a | 95 // Sends messages from the backend to us on the main thread. This must be a |
83 // separate class from the history service so that it can hold a reference to | 96 // separate class from the history service so that it can hold a reference to |
84 // the history service (otherwise we would have to manually AddRef and | 97 // the history service (otherwise we would have to manually AddRef and |
85 // Release when the Backend has a reference to us). | 98 // Release when the Backend has a reference to us). |
86 class HistoryService::BackendDelegate : public HistoryBackend::Delegate { | 99 class HistoryService::BackendDelegate : public HistoryBackend::Delegate { |
87 public: | 100 public: |
88 BackendDelegate( | 101 BackendDelegate( |
89 const base::WeakPtr<HistoryService>& history_service, | 102 const base::WeakPtr<HistoryService>& history_service, |
(...skipping 803 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
893 return false; | 906 return false; |
894 | 907 |
895 return true; | 908 return true; |
896 } | 909 } |
897 | 910 |
898 base::WeakPtr<HistoryService> HistoryService::AsWeakPtr() { | 911 base::WeakPtr<HistoryService> HistoryService::AsWeakPtr() { |
899 DCHECK(thread_checker_.CalledOnValidThread()); | 912 DCHECK(thread_checker_.CalledOnValidThread()); |
900 return weak_ptr_factory_.GetWeakPtr(); | 913 return weak_ptr_factory_.GetWeakPtr(); |
901 } | 914 } |
902 | 915 |
| 916 void HistoryService::ProcessDeleteDirectiveForTest( |
| 917 const sync_pb::HistoryDeleteDirectiveSpecifics& delete_directive) { |
| 918 DCHECK(thread_checker_.CalledOnValidThread()); |
| 919 ProcessDeleteDirective(delete_directive); |
| 920 } |
| 921 |
903 syncer::SyncMergeResult HistoryService::MergeDataAndStartSyncing( | 922 syncer::SyncMergeResult HistoryService::MergeDataAndStartSyncing( |
904 syncer::ModelType type, | 923 syncer::ModelType type, |
905 const syncer::SyncDataList& initial_sync_data, | 924 const syncer::SyncDataList& initial_sync_data, |
906 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, | 925 scoped_ptr<syncer::SyncChangeProcessor> sync_processor, |
907 scoped_ptr<syncer::SyncErrorFactory> error_handler) { | 926 scoped_ptr<syncer::SyncErrorFactory> error_handler) { |
908 DCHECK(thread_checker_.CalledOnValidThread()); | 927 DCHECK(thread_checker_.CalledOnValidThread()); |
909 DCHECK_EQ(type, syncer::HISTORY_DELETE_DIRECTIVES); | 928 DCHECK_EQ(type, syncer::HISTORY_DELETE_DIRECTIVES); |
910 for (syncer::SyncDataList::const_iterator it = initial_sync_data.begin(); | 929 for (syncer::SyncDataList::const_iterator it = initial_sync_data.begin(); |
911 it != initial_sync_data.end(); ++it) { | 930 it != initial_sync_data.end(); ++it) { |
912 DCHECK_EQ(it->GetDataType(), syncer::HISTORY_DELETE_DIRECTIVES); | 931 DCHECK_EQ(it->GetDataType(), syncer::HISTORY_DELETE_DIRECTIVES); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
947 break; | 966 break; |
948 } | 967 } |
949 } | 968 } |
950 return syncer::SyncError(); | 969 return syncer::SyncError(); |
951 } | 970 } |
952 | 971 |
953 void HistoryService::SetInMemoryBackend(int backend_id, | 972 void HistoryService::SetInMemoryBackend(int backend_id, |
954 history::InMemoryHistoryBackend* mem_backend) { | 973 history::InMemoryHistoryBackend* mem_backend) { |
955 DCHECK(thread_checker_.CalledOnValidThread()); | 974 DCHECK(thread_checker_.CalledOnValidThread()); |
956 if (!history_backend_ || current_backend_id_ != backend_id) { | 975 if (!history_backend_ || current_backend_id_ != backend_id) { |
957 VLOG(1) << "Message from obsolete backend"; | 976 DVLOG(1) << "Message from obsolete backend"; |
958 // Cleaning up the memory backend. | 977 // Cleaning up the memory backend. |
959 delete mem_backend; | 978 delete mem_backend; |
960 return; | 979 return; |
961 } | 980 } |
962 DCHECK(!in_memory_backend_.get()) << "Setting mem DB twice"; | 981 DCHECK(!in_memory_backend_.get()) << "Setting mem DB twice"; |
963 in_memory_backend_.reset(mem_backend); | 982 in_memory_backend_.reset(mem_backend); |
964 | 983 |
965 // The database requires additional initialization once we own it. | 984 // The database requires additional initialization once we own it. |
966 in_memory_backend_->AttachToHistoryService(profile_); | 985 in_memory_backend_->AttachToHistoryService(profile_); |
967 } | 986 } |
968 | 987 |
969 void HistoryService::NotifyProfileError(int backend_id, | 988 void HistoryService::NotifyProfileError(int backend_id, |
970 sql::InitStatus init_status) { | 989 sql::InitStatus init_status) { |
971 DCHECK(thread_checker_.CalledOnValidThread()); | 990 DCHECK(thread_checker_.CalledOnValidThread()); |
972 if (!history_backend_ || current_backend_id_ != backend_id) { | 991 if (!history_backend_ || current_backend_id_ != backend_id) { |
973 VLOG(1) << "Message from obsolete backend"; | 992 DVLOG(1) << "Message from obsolete backend"; |
974 return; | 993 return; |
975 } | 994 } |
976 ShowProfileErrorDialog( | 995 ShowProfileErrorDialog( |
977 (init_status == sql::INIT_FAILURE) ? | 996 (init_status == sql::INIT_FAILURE) ? |
978 IDS_COULDNT_OPEN_PROFILE_ERROR : IDS_PROFILE_TOO_NEW_ERROR); | 997 IDS_COULDNT_OPEN_PROFILE_ERROR : IDS_PROFILE_TOO_NEW_ERROR); |
979 } | 998 } |
980 | 999 |
981 void HistoryService::DeleteURL(const GURL& url) { | 1000 void HistoryService::DeleteURL(const GURL& url) { |
982 DCHECK(thread_checker_.CalledOnValidThread()); | 1001 DCHECK(thread_checker_.CalledOnValidThread()); |
983 // We will update the visited links when we observe the delete notifications. | 1002 // We will update the visited links when we observe the delete notifications. |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1054 if (profile_) { | 1073 if (profile_) { |
1055 PrefService* prefs = profile_->GetPrefs(); | 1074 PrefService* prefs = profile_->GetPrefs(); |
1056 languages = prefs->GetString(prefs::kAcceptLanguages); | 1075 languages = prefs->GetString(prefs::kAcceptLanguages); |
1057 } | 1076 } |
1058 ScheduleAndForget(PRIORITY_UI, &HistoryBackend::Init, languages, no_db_); | 1077 ScheduleAndForget(PRIORITY_UI, &HistoryBackend::Init, languages, no_db_); |
1059 } | 1078 } |
1060 | 1079 |
1061 void HistoryService::OnDBLoaded(int backend_id) { | 1080 void HistoryService::OnDBLoaded(int backend_id) { |
1062 DCHECK(thread_checker_.CalledOnValidThread()); | 1081 DCHECK(thread_checker_.CalledOnValidThread()); |
1063 if (!history_backend_ || current_backend_id_ != backend_id) { | 1082 if (!history_backend_ || current_backend_id_ != backend_id) { |
1064 VLOG(1) << "Message from obsolete backend"; | 1083 DVLOG(1) << "Message from obsolete backend"; |
1065 return; | 1084 return; |
1066 } | 1085 } |
1067 backend_loaded_ = true; | 1086 backend_loaded_ = true; |
1068 content::NotificationService::current()->Notify( | 1087 content::NotificationService::current()->Notify( |
1069 chrome::NOTIFICATION_HISTORY_LOADED, | 1088 chrome::NOTIFICATION_HISTORY_LOADED, |
1070 content::Source<Profile>(profile_), | 1089 content::Source<Profile>(profile_), |
1071 content::Details<HistoryService>(this)); | 1090 content::Details<HistoryService>(this)); |
1072 if (thread_ && profile_) { | 1091 if (thread_ && profile_) { |
1073 // We don't want to force creation of TopSites. | 1092 // We don't want to force creation of TopSites. |
1074 history::TopSites* ts = profile_->GetTopSitesWithoutCreating(); | 1093 history::TopSites* ts = profile_->GetTopSitesWithoutCreating(); |
1075 if (ts) | 1094 if (ts) |
1076 ts->HistoryLoaded(); | 1095 ts->HistoryLoaded(); |
1077 } | 1096 } |
1078 } | 1097 } |
1079 | 1098 |
1080 bool HistoryService::GetRowForURL(const GURL& url, history::URLRow* url_row) { | 1099 bool HistoryService::GetRowForURL(const GURL& url, history::URLRow* url_row) { |
1081 DCHECK(thread_checker_.CalledOnValidThread()); | 1100 DCHECK(thread_checker_.CalledOnValidThread()); |
1082 history::URLDatabase* db = InMemoryDatabase(); | 1101 history::URLDatabase* db = InMemoryDatabase(); |
1083 return db && (db->GetRowForURL(url, url_row) != 0); | 1102 return db && (db->GetRowForURL(url, url_row) != 0); |
1084 } | 1103 } |
1085 | 1104 |
1086 void HistoryService::StartTopSitesMigration(int backend_id) { | 1105 void HistoryService::StartTopSitesMigration(int backend_id) { |
1087 DCHECK(thread_checker_.CalledOnValidThread()); | 1106 DCHECK(thread_checker_.CalledOnValidThread()); |
1088 if (!history_backend_ || current_backend_id_ != backend_id) { | 1107 if (!history_backend_ || current_backend_id_ != backend_id) { |
1089 VLOG(1) << "Message from obsolete backend"; | 1108 DVLOG(1) << "Message from obsolete backend"; |
1090 return; | 1109 return; |
1091 } | 1110 } |
1092 needs_top_sites_migration_ = true; | 1111 needs_top_sites_migration_ = true; |
1093 if (thread_ && profile_) { | 1112 if (thread_ && profile_) { |
1094 // We don't want to force creation of TopSites. | 1113 // We don't want to force creation of TopSites. |
1095 history::TopSites* ts = profile_->GetTopSitesWithoutCreating(); | 1114 history::TopSites* ts = profile_->GetTopSitesWithoutCreating(); |
1096 if (ts) | 1115 if (ts) |
1097 ts->MigrateFromHistory(); | 1116 ts->MigrateFromHistory(); |
1098 } | 1117 } |
1099 } | 1118 } |
(...skipping 19 matching lines...) Expand all Loading... |
1119 void HistoryService::NotifyVisitDBObserversOnAddVisit( | 1138 void HistoryService::NotifyVisitDBObserversOnAddVisit( |
1120 const history::BriefVisitInfo& info) { | 1139 const history::BriefVisitInfo& info) { |
1121 DCHECK(thread_checker_.CalledOnValidThread()); | 1140 DCHECK(thread_checker_.CalledOnValidThread()); |
1122 FOR_EACH_OBSERVER(history::VisitDatabaseObserver, visit_database_observers_, | 1141 FOR_EACH_OBSERVER(history::VisitDatabaseObserver, visit_database_observers_, |
1123 OnAddVisit(info)); | 1142 OnAddVisit(info)); |
1124 } | 1143 } |
1125 | 1144 |
1126 void HistoryService::ProcessDeleteDirective( | 1145 void HistoryService::ProcessDeleteDirective( |
1127 const sync_pb::HistoryDeleteDirectiveSpecifics& delete_directive) { | 1146 const sync_pb::HistoryDeleteDirectiveSpecifics& delete_directive) { |
1128 DCHECK(thread_checker_.CalledOnValidThread()); | 1147 DCHECK(thread_checker_.CalledOnValidThread()); |
1129 // TODO(akalin): Actually process the delete directive. | 1148 |
| 1149 DVLOG(1) << "Processing delete directive: " |
| 1150 << DeleteDirectiveToString(delete_directive); |
| 1151 |
| 1152 base::Closure done_callback = |
| 1153 base::Bind(&HistoryService::OnDeleteDirectiveProcessed, |
| 1154 weak_ptr_factory_.GetWeakPtr(), |
| 1155 delete_directive); |
| 1156 |
| 1157 // Execute |done_callback| on return unless we pass it to something |
| 1158 // else. |
| 1159 base::ScopedClosureRunner scoped_done_callback(done_callback); |
| 1160 |
| 1161 // Exactly one directive must be filled in. If not, ignore. |
| 1162 if (delete_directive.has_global_id_directive() == |
| 1163 delete_directive.has_time_range_directive()) { |
| 1164 return; |
| 1165 } |
| 1166 |
| 1167 base::Closure backend_task; |
| 1168 |
| 1169 if (delete_directive.has_global_id_directive()) { |
| 1170 const sync_pb::GlobalIdDirective& global_id_directive = |
| 1171 delete_directive.global_id_directive(); |
| 1172 std::vector<base::Time> times; |
| 1173 for (int i = 0; i < global_id_directive.global_id_size(); ++i) { |
| 1174 int64 global_id = global_id_directive.global_id(i); |
| 1175 // The global id is just an internal time value. |
| 1176 base::Time time = base::Time::FromInternalValue(global_id); |
| 1177 times.push_back(time); |
| 1178 } |
| 1179 |
| 1180 if (!times.empty()) { |
| 1181 backend_task = |
| 1182 base::Bind(&HistoryBackend::ExpireHistoryForTimes, |
| 1183 history_backend_, times); |
| 1184 } |
| 1185 } else if (delete_directive.has_time_range_directive()) { |
| 1186 const sync_pb::TimeRangeDirective& time_range_directive = |
| 1187 delete_directive.time_range_directive(); |
| 1188 // {start,end}_time_usec must both be filled in. If not, ignore. |
| 1189 if (!time_range_directive.has_start_time_usec() || |
| 1190 !time_range_directive.has_end_time_usec()) { |
| 1191 return; |
| 1192 } |
| 1193 |
| 1194 // The directive is for the closed interval [start_time_usec, |
| 1195 // end_time_usec], but ExpireHistoryBetween() expects the |
| 1196 // half-open interval [begin_time, end_time), so add 1 to |
| 1197 // end_time_usec before converting. |
| 1198 base::Time begin_time = |
| 1199 base::Time::UnixEpoch() + |
| 1200 base::TimeDelta::FromMicroseconds( |
| 1201 time_range_directive.start_time_usec()); |
| 1202 base::Time end_time = |
| 1203 base::Time::UnixEpoch() + |
| 1204 base::TimeDelta::FromMicroseconds( |
| 1205 time_range_directive.end_time_usec() + 1); |
| 1206 |
| 1207 backend_task = |
| 1208 base::Bind(&HistoryBackend::ExpireHistoryBetween, |
| 1209 history_backend_, std::set<GURL>(), |
| 1210 begin_time, end_time); |
| 1211 } |
| 1212 |
| 1213 if (!backend_task.is_null()) { |
| 1214 LoadBackendIfNecessary(); |
| 1215 DCHECK(thread_); |
| 1216 if (thread_->message_loop_proxy()->PostTaskAndReply( |
| 1217 FROM_HERE, |
| 1218 backend_task, |
| 1219 done_callback)) { |
| 1220 ignore_result(scoped_done_callback.Release()); |
| 1221 } |
| 1222 } |
| 1223 } |
| 1224 |
| 1225 void HistoryService::OnDeleteDirectiveProcessed( |
| 1226 const sync_pb::HistoryDeleteDirectiveSpecifics& delete_directive) { |
| 1227 DVLOG(1) << "Processed delete directive: " |
| 1228 << DeleteDirectiveToString(delete_directive); |
1130 // TODO(akalin): Keep track of which delete directives we've already | 1229 // TODO(akalin): Keep track of which delete directives we've already |
1131 // processed. | 1230 // processed. |
1132 NOTREACHED(); | |
1133 } | 1231 } |
OLD | NEW |