Chromium Code Reviews| Index: chrome/browser/extensions/api/feedback_private/feedback_private_api.cc |
| diff --git a/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc b/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc |
| index b13cf765fee1e86d05d99ee2bb3f87d5ef7e24a0..f6658230ff7ab36d12039b88e63eef63db2c74ac 100644 |
| --- a/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc |
| +++ b/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc |
| @@ -36,7 +36,11 @@ |
| #include "url/url_util.h" |
| #if defined(OS_CHROMEOS) |
| +#include "base/strings/string_split.h" |
| #include "chrome/browser/chromeos/arc/arc_util.h" |
| +#include "chrome/browser/chromeos/system_logs/single_log_source.h" |
| +#include "chrome/browser/extensions/api/feedback_private/single_log_source_factory.h" |
| +#include "extensions/browser/api/api_resource_manager.h" |
| #endif // defined(OS_CHROMEOS) |
| #if defined(OS_WIN) |
| @@ -66,6 +70,15 @@ constexpr base::Feature kSrtPromptOnFeedbackForm { |
| }; |
| #endif |
| +#if defined(OS_CHROMEOS) |
| +// The minimum time between consecutive reads of a log source by a particular |
| +// extension. |
| +const int kDefaultRateLimitingTimeoutMs = 1000; |
| + |
| +// If this is null, then |kDefaultRateLimitingTimeoutMs| is used as the timeout. |
| +const base::TimeDelta* g_rate_limiting_timeout = nullptr; |
| +#endif // defined(OS_CHROMEOS) |
| + |
| } // namespace |
| namespace extensions { |
| @@ -82,6 +95,38 @@ using SystemInformationList = |
| static base::LazyInstance<BrowserContextKeyedAPIFactory<FeedbackPrivateAPI>>:: |
| DestructorAtExit g_factory = LAZY_INSTANCE_INITIALIZER; |
| +#if defined(OS_CHROMEOS) |
| +using feedback_private::LogSource; |
| +using SingleLogSource = system_logs::SingleLogSource; |
| +using SupportedSource = system_logs::SingleLogSource::SupportedSource; |
| +using LogSourceResourceManager = ApiResourceManager<LogSourceResource>; |
| + |
| +// For managing API resources of type LogSourceResource. |
| +static base::LazyInstance< |
| + BrowserContextKeyedAPIFactory<LogSourceResourceManager>>::DestructorAtExit |
| + g_log_source_resource_factory = LAZY_INSTANCE_INITIALIZER; |
| + |
| +// static |
| +template <> |
| +BrowserContextKeyedAPIFactory<LogSourceResourceManager>* |
| +LogSourceResourceManager::GetFactoryInstance() { |
| + return g_log_source_resource_factory.Pointer(); |
| +} |
| + |
| +// Converts from feedback_private::LogSource to SupportedSource. |
| +SupportedSource GetSupportedSourceType(LogSource source) { |
| + switch (source) { |
| + case feedback_private::LOG_SOURCE_MESSAGES: |
| + return SupportedSource::kMessages; |
| + case feedback_private::LOG_SOURCE_UI_LATEST: |
| + return SupportedSource::kUiLatest; |
| + case feedback_private::LOG_SOURCE_NONE: |
| + DLOG(FATAL) << "Invalid log source type requested."; |
| + return SingleLogSource::SupportedSource::kMessages; |
| + } |
| +} |
| +#endif // defined(OS_CHROMEOS) |
| + |
| // static |
| BrowserContextKeyedAPIFactory<FeedbackPrivateAPI>* |
| FeedbackPrivateAPI::GetFactoryInstance() { |
| @@ -89,8 +134,12 @@ FeedbackPrivateAPI::GetFactoryInstance() { |
| } |
| FeedbackPrivateAPI::FeedbackPrivateAPI(content::BrowserContext* context) |
| - : browser_context_(context), service_(new FeedbackService()) { |
| -} |
| + : browser_context_(context), |
| + service_(new FeedbackService()), |
| + access_manager_(new LogSourceAccessManager( |
| + g_rate_limiting_timeout ? *g_rate_limiting_timeout |
|
tbarzic
2017/05/25 22:46:44
can you just move this const to LogSourceAccessMan
Simon Que
2017/05/26 04:34:38
Done.
|
| + : base::TimeDelta::FromMilliseconds( |
| + kDefaultRateLimitingTimeoutMs))) {} |
| FeedbackPrivateAPI::~FeedbackPrivateAPI() { |
| delete service_; |
| @@ -259,6 +308,129 @@ void FeedbackPrivateGetSystemInformationFunction::OnCompleted( |
| feedback_private::GetSystemInformation::Results::Create(sys_info_list))); |
| } |
| +#if defined(OS_CHROMEOS) |
| +// static |
| +void FeedbackPrivateReadLogSourceFunction::SetRateLimitingTimeoutForTesting( |
| + const base::TimeDelta* timeout) { |
| + g_rate_limiting_timeout = timeout; |
| +} |
| +#endif // defined(OS_CHROMEOS) |
| + |
| +ExtensionFunction::ResponseAction FeedbackPrivateReadLogSourceFunction::Run() { |
| +#if defined(OS_CHROMEOS) |
| + using Params = feedback_private::ReadLogSource::Params; |
| + std::unique_ptr<Params> api_params = Params::Create(*args_); |
| + |
| + int reader_id = |
| + api_params->params.reader_id ? *api_params->params.reader_id : 0; |
| + LogSource source = api_params->params.source; |
| + |
| + LogSourceResource* resource = GetOrCreateLogSourceResource(reader_id, source); |
| + if (!resource) |
| + return RespondNow( |
| + Error("Unable to get existing or create new log source.")); |
| + |
| + // Enforce the rules: rate-limit access to the source from the current |
| + // extension. If not enough time has elapsed since the last access, do not |
| + // read from the source, but instead return an empty response. From the |
| + // caller's perspective, there is no new data. There is no need for the caller |
| + // to keep track of the time since last access. |
| + LogSourceAccessManager* log_source_manager = |
| + FeedbackPrivateAPI::GetFactoryInstance() |
| + ->Get(browser_context()) |
| + ->GetLogSourceAccessManager(); |
| + DCHECK(log_source_manager); |
| + if (!log_source_manager->AccessSourceFromExtension( |
| + LogSourceAccessManager::SourceAndExtension(source, extension_id()))) |
|
tbarzic
2017/05/25 22:46:44
add {}
Simon Que
2017/05/26 04:34:38
Done.
|
| + return RespondNow( |
| + ArgumentList(feedback_private::ReadLogSource::Results::Create( |
| + 0, std::vector<std::string>()))); |
| + |
| + // Now we are ready to access the log source. |
| + resource->GetLogSource()->Fetch( |
| + base::Bind(&FeedbackPrivateReadLogSourceFunction::OnCompleted, this, |
| + source, reader_id, api_params->params.incremental)); |
| + |
| + return RespondLater(); |
| +#else |
| + return RespondNow(Error("API function is not supported.")); |
| +#endif // defined(OS_CHROMEOS) |
| +} |
| + |
| +#if defined(OS_CHROMEOS) |
| +LogSourceResource* |
| +FeedbackPrivateReadLogSourceFunction::GetOrCreateLogSourceResource( |
| + int reader_id, |
| + LogSource source) { |
| + LogSourceResourceManager* resource_manager = |
| + LogSourceResourceManager::Get(browser_context()); |
| + DCHECK(resource_manager); |
| + |
| + LogSourceResource* resource = nullptr; |
| + // If the caller passed in a valid ID, look up the ID in the resource manager. |
| + if (reader_id > 0) { |
| + resource = resource_manager->Get(extension_id(), reader_id); |
| + if (!resource) |
| + return nullptr; |
|
tbarzic
2017/05/25 22:46:44
Shouldn't you just return resource here?
i.e.
if (
Simon Que
2017/05/26 04:34:38
Done.
|
| + } |
| + |
| + LogSourceAccessManager* log_source_manager = |
| + FeedbackPrivateAPI::GetFactoryInstance() |
| + ->Get(browser_context()) |
| + ->GetLogSourceAccessManager(); |
| + DCHECK(log_source_manager); |
| + |
| + LogSourceAccessManager::SourceAndExtension source_and_extension( |
| + source, extension_id()); |
| + |
| + // If caller passed in |reader_id| == 0, create a new SingleLogSource. |
| + |
| + // Enforce the rules: Do not create a new SingleLogSource if there was |
| + // already one created for |source_and_extension|. |
| + if (!log_source_manager->AddExtension(source_and_extension)) |
| + return nullptr; |
| + |
| + SupportedSource source_type = GetSupportedSourceType(source); |
| + std::unique_ptr<LogSourceResource> new_resource(new LogSourceResource( |
|
tbarzic
2017/05/25 22:46:45
prefer MakeUnique over new
Simon Que
2017/05/26 04:34:38
Done.
|
| + extension_id(), |
| + SingleLogSourceFactory::CreateSingleLogSource(source_type).release(), |
| + log_source_manager->GetUnregisterCallback(source_and_extension))); |
| + resource = new_resource.get(); |
| + |
| + reader_id = resource_manager->Add(new_resource.release()); |
|
tbarzic
2017/05/25 22:46:45
you don't use this anywhere
Simon Que
2017/05/26 04:34:38
Done.
|
| + |
| + return resource; |
| +} |
| + |
| +void FeedbackPrivateReadLogSourceFunction::OnCompleted( |
| + LogSource source, |
| + int reader_id, |
| + bool incremental, |
| + system_logs::SystemLogsResponse* response) { |
| + std::vector<std::string> result; |
| + for (const std::pair<std::string, std::string>& pair : *response) { |
| + // TODO(sque): Use std::move? |
| + std::vector<std::string> new_lines = base::SplitString( |
| + pair.second, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); |
| + result.reserve(result.size() + new_lines.size()); |
| + result.insert(result.end(), new_lines.begin(), new_lines.end()); |
| + } |
| + |
| + // If the API call requested a non-incremental access, clean up the |
| + // SingleLogSource by removing its API resource. |
| + if (!incremental) { |
| + LogSourceResourceManager::Get(browser_context()) |
| + ->Remove(extension_id(), reader_id); |
| + // Must return reader_id=0 when the resource has been deleted. |
| + reader_id = 0; |
| + } |
| + |
| + Respond(ArgumentList( |
| + feedback_private::ReadLogSource::Results::Create(reader_id, result))); |
| +} |
| + |
| +#endif // defined(OS_CHROMEOS) |
| + |
| bool FeedbackPrivateSendFeedbackFunction::RunAsync() { |
| std::unique_ptr<feedback_private::SendFeedback::Params> params( |
| feedback_private::SendFeedback::Params::Create(*args_)); |