普通文本  |  159行  |  5.13 KB

// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "extensions/renderer/user_script_set_manager.h"

#include "components/crx_file/id_util.h"
#include "content/public/renderer/render_thread.h"
#include "extensions/common/extension_messages.h"
#include "extensions/renderer/dispatcher.h"
#include "extensions/renderer/script_injection.h"
#include "extensions/renderer/user_script_set.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_message_macros.h"
#include "third_party/WebKit/public/web/WebFrame.h"

namespace extensions {

UserScriptSetManager::UserScriptSetManager(const ExtensionSet* extensions)
    : static_scripts_(extensions), extensions_(extensions) {
  content::RenderThread::Get()->AddObserver(this);
}

UserScriptSetManager::~UserScriptSetManager() {
}

void UserScriptSetManager::AddObserver(Observer* observer) {
  observers_.AddObserver(observer);
}

void UserScriptSetManager::RemoveObserver(Observer* observer) {
  observers_.RemoveObserver(observer);
}

scoped_ptr<ScriptInjection>
UserScriptSetManager::GetInjectionForDeclarativeScript(
    int script_id,
    blink::WebFrame* web_frame,
    int tab_id,
    const GURL& url,
    const Extension* extension) {
  UserScriptSet* user_script_set =
      GetProgrammaticScriptsByExtension(extension->id());
  if (!user_script_set)
    return scoped_ptr<ScriptInjection>();

  return user_script_set->GetDeclarativeScriptInjection(
      script_id,
      web_frame,
      tab_id,
      UserScript::BROWSER_DRIVEN,
      url,
      extension);
}

bool UserScriptSetManager::OnControlMessageReceived(
    const IPC::Message& message) {
  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(UserScriptSetManager, message)
    IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateUserScripts, OnUpdateUserScripts)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

void UserScriptSetManager::GetAllInjections(
    ScopedVector<ScriptInjection>* injections,
    blink::WebFrame* web_frame,
    int tab_id,
    UserScript::RunLocation run_location) {
  static_scripts_.GetInjections(injections, web_frame, tab_id, run_location);
  for (UserScriptSetMap::iterator it = programmatic_scripts_.begin();
       it != programmatic_scripts_.end();
       ++it) {
    it->second->GetInjections(injections, web_frame, tab_id, run_location);
  }
}

void UserScriptSetManager::GetAllActiveExtensionIds(
    std::set<std::string>* ids) const {
  DCHECK(ids);
  static_scripts_.GetActiveExtensionIds(ids);
  for (UserScriptSetMap::const_iterator it = programmatic_scripts_.begin();
       it != programmatic_scripts_.end();
       ++it) {
    it->second->GetActiveExtensionIds(ids);
  }
}

UserScriptSet* UserScriptSetManager::GetProgrammaticScriptsByExtension(
    const ExtensionId& extension_id) {
  UserScriptSetMap::const_iterator it =
      programmatic_scripts_.find(extension_id);
  return it != programmatic_scripts_.end() ? it->second.get() : NULL;
}

void UserScriptSetManager::OnUpdateUserScripts(
    base::SharedMemoryHandle shared_memory,
    const ExtensionId& extension_id,
    const std::set<std::string>& changed_extensions) {
  if (!base::SharedMemory::IsHandleValid(shared_memory)) {
    NOTREACHED() << "Bad scripts handle";
    return;
  }

  for (std::set<std::string>::const_iterator iter = changed_extensions.begin();
       iter != changed_extensions.end();
       ++iter) {
    if (!crx_file::id_util::IdIsValid(*iter)) {
      NOTREACHED() << "Invalid extension id: " << *iter;
      return;
    }
  }

  UserScriptSet* scripts = NULL;
  if (!extension_id.empty()) {
    // The expectation when there is an extension that "owns" this shared
    // memory region is that the |changed_extensions| is either the empty list
    // or just the owner.
    CHECK(changed_extensions.size() <= 1);
    if (programmatic_scripts_.find(extension_id) ==
        programmatic_scripts_.end()) {
      scripts = new UserScriptSet(extensions_);
      programmatic_scripts_[extension_id] = make_linked_ptr(scripts);
    } else {
      scripts = programmatic_scripts_[extension_id].get();
    }
  } else {
    scripts = &static_scripts_;
  }
  DCHECK(scripts);

  // If no extensions are included in the set, that indicates that all
  // extensions were updated. Add them all to the set so that observers and
  // individual UserScriptSets don't need to know this detail.
  const std::set<std::string>* effective_extensions = &changed_extensions;
  std::set<std::string> all_extensions;
  if (changed_extensions.empty()) {
    // The meaning of "all extensions" varies, depending on whether some
    // extension "owns" this shared memory region.
    // No owner => all known extensions.
    // Owner    => just the owner extension.
    if (extension_id.empty())
      all_extensions = extensions_->GetIDs();
    else
      all_extensions.insert(extension_id);
    effective_extensions = &all_extensions;
  }

  if (scripts->UpdateUserScripts(shared_memory, *effective_extensions)) {
    FOR_EACH_OBSERVER(
        Observer,
        observers_,
        OnUserScriptsUpdated(*effective_extensions, scripts->scripts()));
  }
}

}  // namespace extensions