blob: 68e086d40919d1fad966f59750d2156233ab4dd3 [file] [log] [blame]
// Copyright 2013 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 "chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.h"
#include "base/json/json_string_value_serializer.h"
#include "base/strings/string_util.h"
#include "base/sys_info.h"
#include "base/task_scheduler/post_task.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/google/google_brand.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/sync/profile_sync_service_factory.h"
#include "chrome/common/channel_info.h"
#include "chrome/common/pref_names.h"
#include "components/browser_sync/profile_sync_service.h"
#include "components/prefs/pref_service.h"
#include "components/sync/driver/about_sync_util.h"
#include "content/public/browser/browser_thread.h"
#include "extensions/browser/api/power/power_api.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/common/api/power.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_set.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/metrics/chromeos_metrics_provider.h"
#include "chromeos/system/statistics_provider.h"
#include "chromeos/system/version_loader.h"
#endif
#if defined(OS_WIN)
#include "base/win/win_util.h"
#endif
namespace system_logs {
namespace {
constexpr char kSyncDataKey[] = "about_sync_data";
constexpr char kExtensionsListKey[] = "extensions";
constexpr char kPowerApiListKey[] = "chrome.power extensions";
constexpr char kDataReductionProxyKey[] = "data_reduction_proxy";
constexpr char kChromeVersionTag[] = "CHROME VERSION";
#if defined(OS_CHROMEOS)
constexpr char kChromeOsFirmwareVersion[] = "CHROMEOS_FIRMWARE_VERSION";
constexpr char kChromeEnrollmentTag[] = "ENTERPRISE_ENROLLED";
constexpr char kHWIDKey[] = "HWID";
constexpr char kSettingsKey[] = "settings";
constexpr char kLocalStateSettingsResponseKey[] = "Local State: settings";
#else
constexpr char kOsVersionTag[] = "OS VERSION";
#endif
#if defined(OS_WIN)
constexpr char kUsbKeyboardDetected[] = "usb_keyboard_detected";
constexpr char kIsEnrolledToDomain[] = "enrolled_to_domain";
constexpr char kInstallerBrandCode[] = "installer_brand_code";
#endif
#if defined(OS_CHROMEOS)
std::string GetEnrollmentStatusString() {
switch (ChromeOSMetricsProvider::GetEnrollmentStatus()) {
case ChromeOSMetricsProvider::NON_MANAGED:
return "Not managed";
case ChromeOSMetricsProvider::MANAGED:
return "Managed";
case ChromeOSMetricsProvider::UNUSED:
case ChromeOSMetricsProvider::ERROR_GETTING_ENROLLMENT_STATUS:
case ChromeOSMetricsProvider::ENROLLMENT_STATUS_MAX:
return "Error retrieving status";
}
// For compilers that don't recognize all cases handled above.
NOTREACHED();
return std::string();
}
void GetEntriesAsync(SystemLogsResponse* response) {
DCHECK(response);
chromeos::system::StatisticsProvider* stats =
chromeos::system::StatisticsProvider::GetInstance();
DCHECK(stats);
// Get the HWID.
std::string hwid;
if (!stats->GetMachineStatistic(chromeos::system::kHardwareClassKey, &hwid))
VLOG(1) << "Couldn't get machine statistic 'hardware_class'.";
else
(*response)[kHWIDKey] = hwid;
// Get the firmware version.
(*response)[kChromeOsFirmwareVersion] =
chromeos::version_loader::GetFirmware();
}
#endif
} // namespace
ChromeInternalLogSource::ChromeInternalLogSource()
: SystemLogsSource("ChromeInternal") {
}
ChromeInternalLogSource::~ChromeInternalLogSource() {
}
void ChromeInternalLogSource::Fetch(const SysLogsSourceCallback& callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK(!callback.is_null());
std::unique_ptr<SystemLogsResponse> response(new SystemLogsResponse());
(*response)[kChromeVersionTag] = chrome::GetVersionString();
#if defined(OS_CHROMEOS)
(*response)[kChromeEnrollmentTag] = GetEnrollmentStatusString();
#else
// On ChromeOS, this will be pulled in from the LSB_RELEASE.
std::string os_version = base::SysInfo::OperatingSystemName() + ": " +
base::SysInfo::OperatingSystemVersion();
(*response)[kOsVersionTag] = os_version;
#endif
PopulateSyncLogs(response.get());
PopulateExtensionInfoLogs(response.get());
PopulatePowerApiLogs(response.get());
PopulateDataReductionProxyLogs(response.get());
#if defined(OS_WIN)
PopulateUsbKeyboardDetected(response.get());
PopulateEnrolledToDomain(response.get());
PopulateInstallerBrandCode(response.get());
#endif
if (ProfileManager::GetLastUsedProfile()->IsChild())
(*response)["account_type"] = "child";
#if defined(OS_CHROMEOS)
PopulateLocalStateSettings(response.get());
// Get the entries that should be retrieved on the blocking pool and invoke
// the callback later when done.
SystemLogsResponse* response_ptr = response.release();
base::PostTaskWithTraitsAndReply(
FROM_HERE, base::TaskTraits().MayBlock().WithPriority(
base::TaskPriority::BACKGROUND),
base::Bind(&GetEntriesAsync, response_ptr),
base::Bind(callback, base::Owned(response_ptr)));
#else
// On other platforms, we're done. Invoke the callback.
callback.Run(response.get());
#endif // defined(OS_CHROMEOS)
}
void ChromeInternalLogSource::PopulateSyncLogs(SystemLogsResponse* response) {
// We are only interested in sync logs for the primary user profile.
Profile* profile = ProfileManager::GetPrimaryUserProfile();
if (!profile ||
!ProfileSyncServiceFactory::GetInstance()->HasProfileSyncService(profile))
return;
browser_sync::ProfileSyncService* service =
ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile);
std::unique_ptr<base::DictionaryValue> sync_logs(
syncer::sync_ui_util::ConstructAboutInformation(
service, service->signin(), chrome::GetChannel()));
// Remove identity section.
base::ListValue* details = NULL;
sync_logs->GetList(syncer::sync_ui_util::kDetailsKey, &details);
if (!details)
return;
for (base::ListValue::iterator it = details->begin();
it != details->end(); ++it) {
base::DictionaryValue* dict = NULL;
if ((*it)->GetAsDictionary(&dict)) {
std::string title;
dict->GetString("title", &title);
if (title == syncer::sync_ui_util::kIdentityTitle) {
details->Erase(it, NULL);
break;
}
}
}
// Add sync logs to logs.
std::string sync_logs_string;
JSONStringValueSerializer serializer(&sync_logs_string);
serializer.Serialize(*sync_logs.get());
(*response)[kSyncDataKey] = sync_logs_string;
}
void ChromeInternalLogSource::PopulateExtensionInfoLogs(
SystemLogsResponse* response) {
Profile* primary_profile =
g_browser_process->profile_manager()->GetPrimaryUserProfile();
if (!primary_profile)
return;
extensions::ExtensionRegistry* extension_registry =
extensions::ExtensionRegistry::Get(primary_profile);
std::string extensions_list;
for (const scoped_refptr<const extensions::Extension>& extension :
extension_registry->enabled_extensions()) {
// Format the list as:
// "extension_id" : "extension_name" : "extension_version".
// Work around the anonymizer tool recognizing some versions as IPv4s.
// Replaces dots "." by underscores "_".
// We shouldn't change the anonymizer tool as it is working as intended; it
// must err on the side of safety.
std::string version;
base::ReplaceChars(extension->VersionString(), ".", "_", &version);
extensions_list += extension->id() + " : " + extension->name() +
" : version " + version + "\n";
}
if (!extensions_list.empty())
(*response)[kExtensionsListKey] = extensions_list;
}
void ChromeInternalLogSource::PopulatePowerApiLogs(
SystemLogsResponse* response) {
std::string info;
for (auto* profile :
g_browser_process->profile_manager()->GetLoadedProfiles()) {
for (const auto& it :
extensions::PowerAPI::Get(profile)->extension_levels()) {
if (!info.empty())
info += ",\n";
info += it.first + ": " + extensions::api::power::ToString(it.second);
}
}
if (!info.empty())
(*response)[kPowerApiListKey] = info;
}
void ChromeInternalLogSource::PopulateDataReductionProxyLogs(
SystemLogsResponse* response) {
PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs();
bool is_data_reduction_proxy_enabled =
prefs->HasPrefPath(prefs::kDataSaverEnabled) &&
prefs->GetBoolean(prefs::kDataSaverEnabled);
(*response)[kDataReductionProxyKey] = is_data_reduction_proxy_enabled ?
"enabled" : "disabled";
}
#if defined(OS_CHROMEOS)
void ChromeInternalLogSource::PopulateLocalStateSettings(
SystemLogsResponse* response) {
// Extract the "settings" entry in the local state and serialize back to
// a string.
std::unique_ptr<base::DictionaryValue> local_state =
g_browser_process->local_state()->GetPreferenceValuesOmitDefaults();
const base::DictionaryValue* local_state_settings = nullptr;
if (!local_state->GetDictionary(kSettingsKey, &local_state_settings)) {
VLOG(1) << "Failed to extract the settings entry from Local State.";
return;
}
std::string serialized_settings;
JSONStringValueSerializer serializer(&serialized_settings);
if (!serializer.Serialize(*local_state_settings))
return;
(*response)[kLocalStateSettingsResponseKey] = serialized_settings;
}
#endif // defined(OS_CHROMEOS)
#if defined(OS_WIN)
void ChromeInternalLogSource::PopulateUsbKeyboardDetected(
SystemLogsResponse* response) {
std::string reason;
bool result = base::win::IsKeyboardPresentOnSlate(&reason);
(*response)[kUsbKeyboardDetected] = result ? "Keyboard Detected:\n" :
"No Keyboard:\n";
(*response)[kUsbKeyboardDetected] += reason;
}
void ChromeInternalLogSource::PopulateEnrolledToDomain(
SystemLogsResponse* response) {
(*response)[kIsEnrolledToDomain] = base::win::IsEnrolledToDomain()
? "Enrolled to domain"
: "Not enrolled to domain";
}
void ChromeInternalLogSource::PopulateInstallerBrandCode(
SystemLogsResponse* response) {
std::string brand;
google_brand::GetBrand(&brand);
(*response)[kInstallerBrandCode] =
brand.empty() ? "Unknown brand code" : brand;
}
#endif
} // namespace system_logs