Commit 06c73d04 authored by David Bertoni's avatar David Bertoni Committed by Commit Bot

[Extensions] Add event listener info to the extensions-internals page.

Bug: 891788
Change-Id: I2bbef101cf0d95114836391a508b366982da5d4d
Reviewed-on: https://chromium-review.googlesource.com/c/1257552
Commit-Queue: David Bertoni <dbertoni@chromium.org>
Reviewed-by: default avatarDevlin <rdevlin.cronin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#596364}
parent 9adcaaa2
......@@ -5,17 +5,22 @@
#include "chrome/browser/ui/webui/extensions/extensions_internals_source.h"
#include <string>
#include <unordered_map>
#include <utility>
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/memory/ref_counted_memory.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_piece.h"
#include "base/values.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/webui_url_constants.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/browser_thread.h"
#include "extensions/browser/activity.h"
#include "extensions/browser/event_listener_map.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/process_manager.h"
......@@ -77,11 +82,78 @@ const char* LocationToString(extensions::Manifest::Location loc) {
return "";
}
// The JSON we generate looks like this:
//
// [ {
// "event_listeners": {
// "count": 2,
// "events": [ {
// "name": "runtime.onInstalled"
// }, {
// "name": "runtime.onSuspend"
// } ]
// },
// "id": "bhloflhklmhfpedakmangadcdofhnnoh",
// "keepalive": {
// "activities": [ {
// "extra_data": "render-frame",
// "type": "PROCESS_MANAGER"
// } ],
// "count": 1
// },
// "location": "INTERNAL",
// "manifest_version": 2,
// "name": "Earth View from Google Earth",
// "path": "/user/Extensions/bhloflhklmhfpedakmangadcdofhnnoh/2.18.5_0",
// "type": "TYPE_EXTENSION",
// "version": "2.18.5"
// } ]
//
// Which is:
//
// LIST
// DICT
// "event_listeners": DICT
// "count": INT
// "events": LIST
// DICT
// "name": STRING
// "filter": DICT
// "id": STRING
// "keepalive": DICT
// "activities": LIST
// DICT
// "extra_data": STRING
// "type": STRING
// "count": INT
// "location": STRING
// "manifest_version": INT
// "name": STRING
// "path": STRING
// "type": STRING
// "version": STRING
constexpr base::StringPiece kActivitesKey = "activites";
constexpr base::StringPiece kCountKey = "count";
constexpr base::StringPiece kEventsKey = "events";
constexpr base::StringPiece kEventsListenersKey = "event_listeners";
constexpr base::StringPiece kExtraDataKey = "extra_data";
constexpr base::StringPiece kFilterKey = "filter";
constexpr base::StringPiece kKeepaliveKey = "keepalive";
constexpr base::StringPiece kLocationKey = "location";
constexpr base::StringPiece kIdKey = "id";
constexpr base::StringPiece kManifestVersionKey = "manifest_version";
constexpr base::StringPiece kNameKey = "name";
constexpr base::StringPiece kPathKey = "path";
constexpr base::StringPiece kTypeKey = "type";
constexpr base::StringPiece kVersionKey = "version";
base::Value FormatKeepaliveData(extensions::ProcessManager* process_manager,
const extensions::Extension* extension) {
base::Value keepalive_data(base::Value::Type::DICTIONARY);
keepalive_data.SetKey(
"count", base::Value(process_manager->GetLazyKeepaliveCount(extension)));
kCountKey,
base::Value(process_manager->GetLazyKeepaliveCount(extension)));
const extensions::ProcessManager::ActivitiesMultiset activities =
process_manager->GetLazyKeepaliveActivities(extension);
base::Value activities_data(base::Value::Type::LIST);
......@@ -89,14 +161,64 @@ base::Value FormatKeepaliveData(extensions::ProcessManager* process_manager,
for (const auto& activity : activities) {
base::Value activities_entry(base::Value::Type::DICTIONARY);
activities_entry.SetKey(
"type", base::Value(extensions::Activity::ToString(activity.first)));
activities_entry.SetKey("extra_data", base::Value(activity.second));
kTypeKey, base::Value(extensions::Activity::ToString(activity.first)));
activities_entry.SetKey(kExtraDataKey, base::Value(activity.second));
activities_data.GetList().push_back(std::move(activities_entry));
}
keepalive_data.SetKey("activites", std::move(activities_data));
keepalive_data.SetKey(kActivitesKey, std::move(activities_data));
return keepalive_data;
}
void AddEventListenerData(extensions::EventRouter* event_router,
base::Value* data) {
CHECK(data->is_list());
// A map of extension ID to the event data for that extension,
// which is of type LIST of DICTIONARY.
std::unordered_map<base::StringPiece, base::Value, base::StringPieceHash>
events_map;
// Build the map of extension IDs to the list of events.
for (const auto& entry : event_router->listeners().listeners()) {
for (const auto& listener_entry : entry.second) {
auto& events_list = events_map[listener_entry->extension_id()];
if (events_list.is_none()) {
// Not there, so make it a LIST.
events_list = base::Value(base::Value::Type::LIST);
}
// The data for each event is a dictionary, with a name and a
// filter.
base::Value event_data(base::Value::Type::DICTIONARY);
event_data.SetKey(kNameKey, base::Value(listener_entry->event_name()));
// Add the filter if one exists.
base::Value* const filter = listener_entry->filter();
if (filter != nullptr) {
event_data.SetKey(kFilterKey, filter->Clone());
}
events_list.GetList().push_back(std::move(event_data));
}
}
// Move all of the entries from the map into the output data.
for (auto& output_entry : data->GetList()) {
const base::Value* const value = output_entry.FindKey(kIdKey);
CHECK(value && value->is_string());
const auto it = events_map.find(value->GetString());
base::Value listeners(base::Value::Type::DICTIONARY);
if (it == events_map.end()) {
// We didn't find any events, so initialize an empty dictionary.
listeners.SetKey(kCountKey, base::Value(0));
listeners.SetKey(kEventsKey, base::Value(base::Value::Type::LIST));
} else {
// Set the count and the events values.
listeners.SetKey(
kCountKey,
base::Value(base::checked_cast<int>(it->second.GetList().size())));
listeners.SetKey(kEventsKey, std::move(it->second));
}
output_entry.SetKey(kEventsListenersKey, std::move(listeners));
}
}
} // namespace
ExtensionsInternalsSource::ExtensionsInternalsSource(Profile* profile)
......@@ -131,23 +253,26 @@ std::string ExtensionsInternalsSource::WriteToString() const {
base::Value data(base::Value::Type::LIST);
for (const auto& extension : *extensions) {
base::Value extension_data(base::Value::Type::DICTIONARY);
extension_data.SetKey("id", base::Value(extension->id()));
extension_data.SetKey(kIdKey, base::Value(extension->id()));
extension_data.SetKey(
"keepalive", FormatKeepaliveData(process_manager, extension.get()));
extension_data.SetKey("location",
kKeepaliveKey, FormatKeepaliveData(process_manager, extension.get()));
extension_data.SetKey(kLocationKey,
base::Value(LocationToString(extension->location())));
extension_data.SetKey("manifest_version",
extension_data.SetKey(kManifestVersionKey,
base::Value(extension->manifest_version()));
extension_data.SetKey("name", base::Value(extension->name()));
extension_data.SetKey("path",
extension_data.SetKey(kNameKey, base::Value(extension->name()));
extension_data.SetKey(kPathKey,
base::Value(extension->path().LossyDisplayName()));
extension_data.SetKey("type",
extension_data.SetKey(kTypeKey,
base::Value(TypeToString(extension->GetType())));
extension_data.SetKey("version",
extension_data.SetKey(kVersionKey,
base::Value(extension->GetVersionForDisplay()));
data.GetList().push_back(std::move(extension_data));
}
// Aggregate and add the data for the registered event listeners.
AddEventListenerData(extensions::EventRouter::Get(profile_), &data);
std::string json;
base::JSONWriter::WriteWithOptions(
data, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
......
......@@ -144,6 +144,8 @@ class EventListener {
class EventListenerMap {
public:
using ListenerList = std::vector<std::unique_ptr<EventListener>>;
// The key here is an event name.
using ListenerMap = std::unordered_map<std::string, ListenerList>;
class Delegate {
public:
......@@ -166,6 +168,9 @@ class EventListenerMap {
// Returns true if the listener was removed .
bool RemoveListener(const EventListener* listener);
// Get the map of all EventListeners.
const ListenerMap& listeners() const { return listeners_; };
// Returns the set of listeners that want to be notified of |event|.
std::set<const EventListener*> GetEventListeners(const Event& event);
......@@ -218,8 +223,6 @@ class EventListenerMap {
const base::DictionaryValue& filtered);
private:
// The key here is an event name.
using ListenerMap = std::map<std::string, ListenerList>;
void CleanupListener(EventListener* listener);
bool IsFilteredEvent(const Event& event) const;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment