Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "extensions/browser/user_script_loader.h" | 5 #include "extensions/browser/user_script_loader.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <set> | 9 #include <set> |
| 10 #include <string> | 10 #include <string> |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 21 #include "extensions/browser/notification_types.h" | 21 #include "extensions/browser/notification_types.h" |
| 22 #include "extensions/common/extension_messages.h" | 22 #include "extensions/common/extension_messages.h" |
| 23 | 23 |
| 24 using content::BrowserThread; | 24 using content::BrowserThread; |
| 25 using content::BrowserContext; | 25 using content::BrowserContext; |
| 26 | 26 |
| 27 namespace extensions { | 27 namespace extensions { |
| 28 | 28 |
| 29 namespace { | 29 namespace { |
| 30 | 30 |
| 31 #if DCHECK_IS_ON() | |
| 32 bool AreScriptsUnique(const UserScriptList& scripts) { | |
| 33 std::set<int> script_ids; | |
| 34 for (const UserScript& script : scripts) { | |
| 35 if (script_ids.count(script.id())) | |
| 36 return false; | |
| 37 script_ids.insert(script.id()); | |
| 38 } | |
| 39 return true; | |
| 40 } | |
| 41 #endif // DCHECK_IS_ON() | |
| 42 | |
| 31 // Helper function to parse greasesmonkey headers | 43 // Helper function to parse greasesmonkey headers |
| 32 bool GetDeclarationValue(const base::StringPiece& line, | 44 bool GetDeclarationValue(const base::StringPiece& line, |
| 33 const base::StringPiece& prefix, | 45 const base::StringPiece& prefix, |
| 34 std::string* value) { | 46 std::string* value) { |
| 35 base::StringPiece::size_type index = line.find(prefix); | 47 base::StringPiece::size_type index = line.find(prefix); |
| 36 if (index == base::StringPiece::npos) | 48 if (index == base::StringPiece::npos) |
| 37 return false; | 49 return false; |
| 38 | 50 |
| 39 std::string temp(line.data() + index + prefix.length(), | 51 std::string temp(line.data() + index + prefix.length(), |
| 40 line.length() - index - prefix.length()); | 52 line.length() - index - prefix.length()); |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 154 weak_factory_(this) { | 166 weak_factory_(this) { |
| 155 registrar_.Add(this, | 167 registrar_.Add(this, |
| 156 content::NOTIFICATION_RENDERER_PROCESS_CREATED, | 168 content::NOTIFICATION_RENDERER_PROCESS_CREATED, |
| 157 content::NotificationService::AllBrowserContextsAndSources()); | 169 content::NotificationService::AllBrowserContextsAndSources()); |
| 158 } | 170 } |
| 159 | 171 |
| 160 UserScriptLoader::~UserScriptLoader() { | 172 UserScriptLoader::~UserScriptLoader() { |
| 161 FOR_EACH_OBSERVER(Observer, observers_, OnUserScriptLoaderDestroyed(this)); | 173 FOR_EACH_OBSERVER(Observer, observers_, OnUserScriptLoaderDestroyed(this)); |
| 162 } | 174 } |
| 163 | 175 |
| 164 void UserScriptLoader::AddScripts(const std::set<UserScript>& scripts) { | 176 void UserScriptLoader::AddScripts(const UserScriptList& scripts) { |
| 165 for (std::set<UserScript>::const_iterator it = scripts.begin(); | 177 #if DCHECK_IS_ON() |
| 166 it != scripts.end(); | 178 // |scripts| with non-unique IDs will work, but that would indicate we are |
| 167 ++it) { | 179 // doing something wrong somewhere, so DCHECK that. |
| 168 removed_scripts_.erase(*it); | 180 DCHECK(AreScriptsUnique(scripts)) |
| 169 added_scripts_.insert(*it); | 181 << "AddScripts() expects scripts with unique IDs."; |
| 182 #endif // DCHECK_IS_ON() | |
| 183 for (const UserScript& user_script : scripts) { | |
| 184 int id = user_script.id(); | |
| 185 removed_script_hosts_.erase(UserScriptIDPair(id)); | |
| 186 if (added_scripts_map_.count(id) == 0) | |
| 187 added_scripts_map_[id] = user_script; | |
| 170 } | 188 } |
| 171 AttemptLoad(); | 189 AttemptLoad(); |
| 172 } | 190 } |
| 173 | 191 |
| 174 void UserScriptLoader::AddScripts(const std::set<UserScript>& scripts, | 192 void UserScriptLoader::AddScripts(const UserScriptList& scripts, |
| 175 int render_process_id, | 193 int render_process_id, |
| 176 int render_view_id) { | 194 int render_view_id) { |
| 177 AddScripts(scripts); | 195 AddScripts(scripts); |
| 178 } | 196 } |
| 179 | 197 |
| 180 void UserScriptLoader::RemoveScripts(const std::set<UserScript>& scripts) { | 198 void UserScriptLoader::RemoveScripts( |
| 181 for (std::set<UserScript>::const_iterator it = scripts.begin(); | 199 const std::set<UserScriptIDPair>& scripts) { |
| 182 it != scripts.end(); | 200 for (const UserScriptIDPair& id_pair : scripts) { |
| 183 ++it) { | 201 removed_script_hosts_.insert(UserScriptIDPair(id_pair.id, id_pair.host_id)); |
| 184 added_scripts_.erase(*it); | 202 // TODO(lazyboy): We shouldn't be trying to remove scripts that were never |
| 185 removed_scripts_.insert(*it); | 203 // a) added to |added_scripts_map_| or b) being loaded or has done loading |
| 204 // through |user_scripts_|. This would reduce sending redundant IPC. | |
| 205 DCHECK(added_scripts_map_.count(id_pair.id) > 0u); | |
|
Devlin
2016/08/11 01:09:27
Nit: DCHECK_GT
lazyboy
2016/08/11 01:51:06
Done.
lazyboy
2016/08/11 02:00:21
Actually just realized that this DCHECK is wrong b
| |
| 206 added_scripts_map_.erase(id_pair.id); | |
| 186 } | 207 } |
| 187 AttemptLoad(); | 208 AttemptLoad(); |
| 188 } | 209 } |
| 189 | 210 |
| 190 void UserScriptLoader::ClearScripts() { | 211 void UserScriptLoader::ClearScripts() { |
| 191 clear_scripts_ = true; | 212 clear_scripts_ = true; |
| 192 added_scripts_.clear(); | 213 added_scripts_map_.clear(); |
| 193 removed_scripts_.clear(); | 214 removed_script_hosts_.clear(); |
| 194 AttemptLoad(); | 215 AttemptLoad(); |
| 195 } | 216 } |
| 196 | 217 |
| 197 void UserScriptLoader::Observe(int type, | 218 void UserScriptLoader::Observe(int type, |
| 198 const content::NotificationSource& source, | 219 const content::NotificationSource& source, |
| 199 const content::NotificationDetails& details) { | 220 const content::NotificationDetails& details) { |
| 200 DCHECK_EQ(type, content::NOTIFICATION_RENDERER_PROCESS_CREATED); | 221 DCHECK_EQ(type, content::NOTIFICATION_RENDERER_PROCESS_CREATED); |
| 201 content::RenderProcessHost* process = | 222 content::RenderProcessHost* process = |
| 202 content::Source<content::RenderProcessHost>(source).ptr(); | 223 content::Source<content::RenderProcessHost>(source).ptr(); |
| 203 if (!ExtensionsBrowserClient::Get()->IsSameContext( | 224 if (!ExtensionsBrowserClient::Get()->IsSameContext( |
| 204 browser_context_, process->GetBrowserContext())) | 225 browser_context_, process->GetBrowserContext())) |
| 205 return; | 226 return; |
| 206 if (scripts_ready()) { | 227 if (scripts_ready()) { |
| 207 SendUpdate(process, shared_memory_.get(), | 228 SendUpdate(process, shared_memory_.get(), |
| 208 std::set<HostID>()); // Include all hosts. | 229 std::set<HostID>()); // Include all hosts. |
| 209 } | 230 } |
| 210 } | 231 } |
| 211 | 232 |
| 212 bool UserScriptLoader::ScriptsMayHaveChanged() const { | 233 bool UserScriptLoader::ScriptsMayHaveChanged() const { |
| 213 // Scripts may have changed if there are scripts added, scripts removed, or | 234 // Scripts may have changed if there are scripts added, scripts removed, or |
| 214 // if scripts were cleared and either: | 235 // if scripts were cleared and either: |
| 215 // (1) A load is in progress (which may result in a non-zero number of | 236 // (1) A load is in progress (which may result in a non-zero number of |
| 216 // scripts that need to be cleared), or | 237 // scripts that need to be cleared), or |
| 217 // (2) The current set of scripts is non-empty (so they need to be cleared). | 238 // (2) The current set of scripts is non-empty (so they need to be cleared). |
| 218 return (added_scripts_.size() || | 239 return (added_scripts_map_.size() || removed_script_hosts_.size() || |
| 219 removed_scripts_.size() || | 240 (clear_scripts_ && (is_loading() || user_scripts_->size()))); |
| 220 (clear_scripts_ && | |
| 221 (is_loading() || user_scripts_->size()))); | |
| 222 } | 241 } |
| 223 | 242 |
| 224 void UserScriptLoader::AttemptLoad() { | 243 void UserScriptLoader::AttemptLoad() { |
| 225 if (ready_ && ScriptsMayHaveChanged()) { | 244 if (ready_ && ScriptsMayHaveChanged()) { |
| 226 if (is_loading()) | 245 if (is_loading()) |
| 227 pending_load_ = true; | 246 pending_load_ = true; |
| 228 else | 247 else |
| 229 StartLoad(); | 248 StartLoad(); |
| 230 } | 249 } |
| 231 } | 250 } |
| 232 | 251 |
| 233 void UserScriptLoader::StartLoad() { | 252 void UserScriptLoader::StartLoad() { |
| 234 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 253 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 235 DCHECK(!is_loading()); | 254 DCHECK(!is_loading()); |
| 236 | 255 |
| 237 // If scripts were marked for clearing before adding and removing, then clear | 256 // If scripts were marked for clearing before adding and removing, then clear |
| 238 // them. | 257 // them. |
| 239 if (clear_scripts_) { | 258 if (clear_scripts_) { |
| 240 user_scripts_->clear(); | 259 user_scripts_->clear(); |
| 241 } else { | 260 } else { |
| 242 for (UserScriptList::iterator it = user_scripts_->begin(); | 261 for (UserScriptList::iterator it = user_scripts_->begin(); |
| 243 it != user_scripts_->end();) { | 262 it != user_scripts_->end();) { |
| 244 if (removed_scripts_.count(*it)) | 263 UserScriptIDPair id_pair(it->id()); |
| 264 if (removed_script_hosts_.count(id_pair) > 0u) | |
| 245 it = user_scripts_->erase(it); | 265 it = user_scripts_->erase(it); |
| 246 else | 266 else |
| 247 ++it; | 267 ++it; |
| 248 } | 268 } |
| 249 } | 269 } |
| 250 | 270 |
| 251 user_scripts_->insert( | |
| 252 user_scripts_->end(), added_scripts_.begin(), added_scripts_.end()); | |
| 253 | |
| 254 std::set<int> added_script_ids; | 271 std::set<int> added_script_ids; |
| 255 for (std::set<UserScript>::const_iterator it = added_scripts_.begin(); | 272 for (const auto& id_and_script : added_scripts_map_) |
| 256 it != added_scripts_.end(); | 273 added_script_ids.insert(id_and_script.second.id()); |
| 257 ++it) { | |
| 258 added_script_ids.insert(it->id()); | |
| 259 } | |
| 260 | 274 |
| 261 // Expand |changed_hosts_| for OnScriptsLoaded, which will use it in | 275 // Expand |changed_hosts_| for OnScriptsLoaded, which will use it in |
| 262 // its IPC message. This must be done before we clear |added_scripts_| and | 276 // its IPC message. This must be done before we clear |added_scripts_map_| and |
| 263 // |removed_scripts_| below. | 277 // |removed_script_hosts_| below. |
| 264 std::set<UserScript> changed_scripts(added_scripts_); | 278 for (const auto& id_and_script : added_scripts_map_) |
|
Devlin
2016/08/11 01:09:27
Could we do this and the addition to user scripts
Devlin
2016/08/11 01:09:27
Could we do this and the addition to user scripts
lazyboy
2016/08/11 01:51:06
Done.
| |
| 265 changed_scripts.insert(removed_scripts_.begin(), removed_scripts_.end()); | 279 changed_hosts_.insert(id_and_script.second.host_id()); |
| 266 for (const UserScript& script : changed_scripts) | 280 for (const UserScriptIDPair& id_pair : removed_script_hosts_) |
| 267 changed_hosts_.insert(script.host_id()); | 281 changed_hosts_.insert(id_pair.host_id); |
| 282 | |
| 283 // Done with |added_scripts_map_|, now put them into |user_scripts_|. | |
| 284 user_scripts_->reserve(user_scripts_->size() + added_scripts_map_.size()); | |
| 285 for (int id : added_script_ids) | |
| 286 user_scripts_->push_back(std::move(added_scripts_map_[id])); | |
| 268 | 287 |
| 269 LoadScripts(std::move(user_scripts_), changed_hosts_, added_script_ids, | 288 LoadScripts(std::move(user_scripts_), changed_hosts_, added_script_ids, |
| 270 base::Bind(&UserScriptLoader::OnScriptsLoaded, | 289 base::Bind(&UserScriptLoader::OnScriptsLoaded, |
| 271 weak_factory_.GetWeakPtr())); | 290 weak_factory_.GetWeakPtr())); |
| 272 | 291 |
| 273 clear_scripts_ = false; | 292 clear_scripts_ = false; |
| 274 added_scripts_.clear(); | 293 added_scripts_map_.clear(); |
| 275 removed_scripts_.clear(); | 294 removed_script_hosts_.clear(); |
| 276 user_scripts_.reset(); | 295 user_scripts_.reset(); |
| 277 } | 296 } |
| 278 | 297 |
| 279 // static | 298 // static |
| 280 std::unique_ptr<base::SharedMemory> UserScriptLoader::Serialize( | 299 std::unique_ptr<base::SharedMemory> UserScriptLoader::Serialize( |
| 281 const UserScriptList& scripts) { | 300 const UserScriptList& scripts) { |
| 282 base::Pickle pickle; | 301 base::Pickle pickle; |
| 283 pickle.WriteUInt32(scripts.size()); | 302 pickle.WriteUInt32(scripts.size()); |
| 284 for (const UserScript& script : scripts) { | 303 for (const UserScript& script : scripts) { |
| 285 // TODO(aa): This can be replaced by sending content script metadata to | 304 // TODO(aa): This can be replaced by sending content script metadata to |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 401 if (!shared_memory->ShareToProcess(handle, &handle_for_process)) | 420 if (!shared_memory->ShareToProcess(handle, &handle_for_process)) |
| 402 return; // This can legitimately fail if the renderer asserts at startup. | 421 return; // This can legitimately fail if the renderer asserts at startup. |
| 403 | 422 |
| 404 if (base::SharedMemory::IsHandleValid(handle_for_process)) { | 423 if (base::SharedMemory::IsHandleValid(handle_for_process)) { |
| 405 process->Send(new ExtensionMsg_UpdateUserScripts( | 424 process->Send(new ExtensionMsg_UpdateUserScripts( |
| 406 handle_for_process, host_id(), changed_hosts, whitelisted_only)); | 425 handle_for_process, host_id(), changed_hosts, whitelisted_only)); |
| 407 } | 426 } |
| 408 } | 427 } |
| 409 | 428 |
| 410 } // namespace extensions | 429 } // namespace extensions |
| OLD | NEW |