-
Notifications
You must be signed in to change notification settings - Fork 6.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add chrome.tabs API extension telemetry signal and processor
Define a new extension telemetry signal type for intercepting certain chrome.tabs API invocations. Also implement a signal processor that processes this signal type and generates an associated report. The actual invoking of this signal processor by the extension telemetry service will be implemented in a follow-on CL. Bug: 1465947 Change-Id: I085adee814e0a99eb58bd7b1d34d453fbe3fc035 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4793940 Reviewed-by: Richard Chen <richche@google.com> Commit-Queue: Anunoy Ghosh <anunoy@chromium.org> Reviewed-by: Xinghui Lu <xinghuilu@chromium.org> Cr-Commit-Position: refs/heads/main@{#1187933}
- Loading branch information
Anunoy Ghosh
authored and
Chromium LUCI CQ
committed
Aug 24, 2023
1 parent
53d87d7
commit 9d99c19
Showing
11 changed files
with
517 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
37 changes: 37 additions & 0 deletions
37
chrome/browser/safe_browsing/extension_telemetry/tabs_api_signal.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// Copyright 2023 The Chromium Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "chrome/browser/safe_browsing/extension_telemetry/tabs_api_signal.h" | ||
#include "base/strings/string_number_conversions.h" | ||
#include "base/strings/string_util.h" | ||
#include "chrome/browser/safe_browsing/extension_telemetry/extension_signal_util.h" | ||
|
||
namespace safe_browsing { | ||
|
||
TabsApiSignal::TabsApiSignal(const extensions::ExtensionId& extension_id, | ||
TabsApiInfo::ApiMethod api_method, | ||
const std::string& current_url, | ||
const std::string& new_url) | ||
: ExtensionSignal(extension_id), api_method_(api_method) { | ||
if (!current_url.empty()) { | ||
current_url_ = SanitizeURLWithoutFilename(current_url); | ||
} | ||
if (!new_url.empty()) { | ||
new_url_ = SanitizeURLWithoutFilename(new_url); | ||
} | ||
} | ||
|
||
TabsApiSignal::~TabsApiSignal() = default; | ||
|
||
ExtensionSignalType TabsApiSignal::GetType() const { | ||
return ExtensionSignalType::kTabsApi; | ||
} | ||
|
||
std::string TabsApiSignal::GetUniqueCallDetailsId() const { | ||
return base::JoinString({base::NumberToString(static_cast<int>(api_method_)), | ||
current_url_, new_url_}, | ||
","); | ||
} | ||
|
||
} // namespace safe_browsing |
45 changes: 45 additions & 0 deletions
45
chrome/browser/safe_browsing/extension_telemetry/tabs_api_signal.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// Copyright 2023 The Chromium Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#ifndef CHROME_BROWSER_SAFE_BROWSING_EXTENSION_TELEMETRY_TABS_API_SIGNAL_H_ | ||
#define CHROME_BROWSER_SAFE_BROWSING_EXTENSION_TELEMETRY_TABS_API_SIGNAL_H_ | ||
|
||
#include <string> | ||
|
||
#include "chrome/browser/safe_browsing/extension_telemetry/extension_signal.h" | ||
#include "components/safe_browsing/core/common/proto/csd.pb.h" | ||
|
||
namespace safe_browsing { | ||
|
||
using TabsApiInfo = ExtensionTelemetryReportRequest::SignalInfo::TabsApiInfo; | ||
|
||
// A signal that is created when an extension invokes chrome.tabs API methods. | ||
class TabsApiSignal : public ExtensionSignal { | ||
public: | ||
TabsApiSignal(const extensions::ExtensionId& extension_id, | ||
TabsApiInfo::ApiMethod api_method, | ||
const std::string& current_url, | ||
const std::string& new_url); | ||
~TabsApiSignal() override; | ||
|
||
// ExtensionSignal: | ||
ExtensionSignalType GetType() const override; | ||
|
||
// Returns a unique id, which can be used to compare API arguments and as a | ||
// key for storage (e.g., in a map). | ||
std::string GetUniqueCallDetailsId() const; | ||
|
||
TabsApiInfo::ApiMethod api_method() const { return api_method_; } | ||
const std::string& current_url() const { return current_url_; } | ||
const std::string& new_url() const { return new_url_; } | ||
|
||
protected: | ||
TabsApiInfo::ApiMethod api_method_; | ||
std::string current_url_; | ||
std::string new_url_; | ||
}; | ||
|
||
} // namespace safe_browsing | ||
|
||
#endif // CHROME_BROWSER_SAFE_BROWSING_EXTENSION_TELEMETRY_TABS_EXECUTE_SCRIPT_SIGNAL_H_ |
102 changes: 102 additions & 0 deletions
102
chrome/browser/safe_browsing/extension_telemetry/tabs_api_signal_processor.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
// Copyright 2023 The Chromium Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "chrome/browser/safe_browsing/extension_telemetry/tabs_api_signal_processor.h" | ||
#include <string> | ||
|
||
#include "base/check_op.h" | ||
#include "chrome/browser/safe_browsing/extension_telemetry/tabs_api_signal.h" | ||
#include "components/safe_browsing/core/common/proto/csd.pb.h" | ||
|
||
namespace safe_browsing { | ||
|
||
namespace { | ||
|
||
// Used to limit the number of unique API call details stored for each | ||
// extension. | ||
constexpr size_t kMaxUniqueCallDetails = 100; | ||
|
||
} // namespace | ||
|
||
TabsApiSignalProcessor::TabsApiInfoStoreEntry::TabsApiInfoStoreEntry() = | ||
default; | ||
TabsApiSignalProcessor::TabsApiInfoStoreEntry::~TabsApiInfoStoreEntry() = | ||
default; | ||
TabsApiSignalProcessor::TabsApiInfoStoreEntry::TabsApiInfoStoreEntry( | ||
const TabsApiInfoStoreEntry& src) = default; | ||
TabsApiSignalProcessor::TabsApiSignalProcessor() | ||
: max_unique_call_details_(kMaxUniqueCallDetails) {} | ||
TabsApiSignalProcessor::~TabsApiSignalProcessor() = default; | ||
|
||
void TabsApiSignalProcessor::ProcessSignal(const ExtensionSignal& signal) { | ||
// Validate TabsApi signal. | ||
DCHECK_EQ(ExtensionSignalType::kTabsApi, signal.GetType()); | ||
const auto& tabs_api_signal = static_cast<const TabsApiSignal&>(signal); | ||
// Ignore the signal if both URL (current and new) are empty (sanity check). | ||
if (tabs_api_signal.current_url().empty() && | ||
tabs_api_signal.new_url().empty()) { | ||
return; | ||
} | ||
|
||
// Retrieve the signal info store entry for this extension from the store. If | ||
// this is the first signal for an extension, a new entry is created in the | ||
// store. | ||
TabsApiInfoStoreEntry& info_store_entry = | ||
tabs_api_info_store_[tabs_api_signal.extension_id()]; | ||
TabsApiCallDetailsMap& call_details_map = | ||
info_store_entry.tabs_api_call_details_map; | ||
|
||
const std::string call_details_id = tabs_api_signal.GetUniqueCallDetailsId(); | ||
auto call_details_it = call_details_map.find(call_details_id); | ||
if (call_details_it != call_details_map.end()) { | ||
// If a tabs API call with the same arguments has been invoked | ||
// before, simply increment the count for the corresponding record. | ||
auto count = call_details_it->second.count(); | ||
call_details_it->second.set_count(count + 1); | ||
} else if (call_details_map.size() < max_unique_call_details_) { | ||
// For new call details, process the signal only if under max limit, i.e, | ||
// add a new TabsApiCallDetails object to the call details map. | ||
TabsApiCallDetails call_details; | ||
call_details.set_method(tabs_api_signal.api_method()); | ||
call_details.set_current_url(tabs_api_signal.current_url()); | ||
call_details.set_new_url(tabs_api_signal.new_url()); | ||
call_details.set_count(1); | ||
call_details_map.emplace(call_details_id, call_details); | ||
} | ||
} | ||
|
||
std::unique_ptr<ExtensionTelemetryReportRequest_SignalInfo> | ||
TabsApiSignalProcessor::GetSignalInfoForReport( | ||
const extensions::ExtensionId& extension_id) { | ||
auto tabs_api_info_store_entry = tabs_api_info_store_.find(extension_id); | ||
if (tabs_api_info_store_entry == tabs_api_info_store_.end()) { | ||
return nullptr; | ||
} | ||
|
||
// Create the signal info protobuf. | ||
auto signal_info = | ||
std::make_unique<ExtensionTelemetryReportRequest_SignalInfo>(); | ||
TabsApiInfo* tabs_api_info = signal_info->mutable_tabs_api_info(); | ||
|
||
for (auto& call_details : | ||
tabs_api_info_store_entry->second.tabs_api_call_details_map) { | ||
*tabs_api_info->add_call_details() = std::move(call_details.second); | ||
} | ||
|
||
// Finally, clear the data in the info store. | ||
tabs_api_info_store_.erase(tabs_api_info_store_entry); | ||
|
||
return signal_info; | ||
} | ||
|
||
bool TabsApiSignalProcessor::HasDataToReportForTest() const { | ||
return !tabs_api_info_store_.empty(); | ||
} | ||
|
||
void TabsApiSignalProcessor::SetMaxUniqueCallDetailsForTest( | ||
size_t max_unique_call_details) { | ||
max_unique_call_details_ = max_unique_call_details; | ||
} | ||
|
||
} // namespace safe_browsing |
71 changes: 71 additions & 0 deletions
71
chrome/browser/safe_browsing/extension_telemetry/tabs_api_signal_processor.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// Copyright 2023 The Chromium Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#ifndef CHROME_BROWSER_SAFE_BROWSING_EXTENSION_TELEMETRY_TABS_API_SIGNAL_PROCESSOR_H_ | ||
#define CHROME_BROWSER_SAFE_BROWSING_EXTENSION_TELEMETRY_TABS_API_SIGNAL_PROCESSOR_H_ | ||
|
||
#include <memory> | ||
#include <string> | ||
|
||
#include "base/containers/flat_map.h" | ||
#include "chrome/browser/safe_browsing/extension_telemetry/extension_signal_processor.h" | ||
#include "components/safe_browsing/core/common/proto/csd.pb.h" | ||
|
||
namespace safe_browsing { | ||
|
||
class ExtensionSignal; | ||
class ExtensionTelemetryReportRequest_SignalInfo; | ||
|
||
using TabsApiCallDetails = | ||
ExtensionTelemetryReportRequest::SignalInfo::TabsApiInfo::CallDetails; | ||
|
||
// A class that processes chrome.tabs API signal data to generate telemetry | ||
// reports. | ||
class TabsApiSignalProcessor : public ExtensionSignalProcessor { | ||
public: | ||
TabsApiSignalProcessor(); | ||
~TabsApiSignalProcessor() override; | ||
|
||
TabsApiSignalProcessor(TabsApiSignalProcessor&) = delete; | ||
TabsApiSignalProcessor& operator=(const TabsApiSignalProcessor&) = delete; | ||
|
||
// ExtensionSignalProcessor: | ||
void ProcessSignal(const ExtensionSignal& signal) override; | ||
std::unique_ptr<ExtensionTelemetryReportRequest_SignalInfo> | ||
GetSignalInfoForReport(const extensions::ExtensionId& extension_id) override; | ||
bool HasDataToReportForTest() const override; | ||
|
||
void SetMaxUniqueCallDetailsForTest(size_t max_unique_call_details); | ||
|
||
protected: | ||
// Max number of unique API call details stored per extension. | ||
// The signal processor only stores up to this number of unique API call | ||
// details. | ||
size_t max_unique_call_details_; | ||
|
||
// Stores a map of unique API call details. The key used is a string | ||
// concatenation of the call arguments stored. | ||
using TabsApiCallDetailsMap = base::flat_map<std::string, TabsApiCallDetails>; | ||
|
||
// Stores chrome.tabs API signal info for a single extension. If | ||
// `max_unique_call_details_` is exceeded, no more call details will be | ||
// recorded. | ||
struct TabsApiInfoStoreEntry { | ||
TabsApiInfoStoreEntry(); | ||
~TabsApiInfoStoreEntry(); | ||
TabsApiInfoStoreEntry(const TabsApiInfoStoreEntry&); | ||
|
||
TabsApiCallDetailsMap tabs_api_call_details_map; | ||
}; | ||
|
||
// Stores chrome.tabs API signal for multiple extensions, keyed by extension | ||
// id. | ||
using TabsApiInfoStore = | ||
base::flat_map<extensions::ExtensionId, TabsApiInfoStoreEntry>; | ||
TabsApiInfoStore tabs_api_info_store_; | ||
}; | ||
|
||
} // namespace safe_browsing | ||
|
||
#endif // CHROME_BROWSER_SAFE_BROWSING_EXTENSION_TELEMETRY_TABS_API_SIGNAL_PROCESSOR_H_ |
Oops, something went wrong.