| // Copyright 2019 The Chromium OS 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 "crash-reporter/arc_util.h" |
| |
| namespace arc_util { |
| |
| namespace { |
| |
| bool HasExceptionInfo(const std::string& type) { |
| static const std::unordered_set<std::string> kTypes = { |
| "data_app_crash", "system_app_crash", "system_app_wtf", |
| "system_server_crash", "system_server_wtf"}; |
| return kTypes.count(type); |
| } |
| |
| base::TimeTicks ToSeconds(const base::TimeTicks& time) { |
| return base::TimeTicks::FromInternalValue( |
| base::TimeDelta::FromSeconds( |
| base::TimeDelta::FromInternalValue(time.ToInternalValue()) |
| .InSeconds()) |
| .ToInternalValue()); |
| } |
| |
| } // namespace |
| |
| using CrashLogHeaderMap = std::unordered_map<std::string, std::string>; |
| |
| const char kArcProduct[] = "ChromeOS_ARC"; |
| |
| const char kAndroidVersionField[] = "android_version"; |
| const char kArcVersionField[] = "arc_version"; |
| const char kBoardField[] = "board"; |
| const char kChromeOsVersionField[] = "chrome_os_version"; |
| const char kCpuAbiField[] = "cpu_abi"; |
| const char kCrashTypeField[] = "crash_type"; |
| const char kDeviceField[] = "device"; |
| const char kProcessField[] = "process"; |
| const char kProductField[] = "prod"; |
| const char kUptimeField[] = "uptime"; |
| |
| const char kExceptionInfoField[] = "exception_info"; |
| const char kSignatureField[] = "sig"; |
| |
| const char kSilentKey[] = "silent"; |
| |
| const char kProcessKey[] = "Process"; |
| const char kSubjectKey[] = "Subject"; |
| |
| const std::vector<std::pair<const char*, const char*>> kHeaderToFieldMapping = { |
| {"Crash-Tag", "crash_tag"}, |
| {"NDK-Execution", "ndk_execution"}, |
| {"Package", "package"}, |
| {"Target-SDK", "target_sdk"}, |
| }; |
| |
| base::Optional<std::string> GetVersionFromFingerprint( |
| const std::string& fingerprint) { |
| // fingerprint has the following format: |
| // $(PRODUCT_BRAND)/$(TARGET_PRODUCT)/$(TARGET_DEVICE):$(PLATFORM_VERSION)/ |
| // ..$(BUILD_ID)/$(BF_BUILD_NUMBER):$(TARGET_BUILD_VARIANT)/ |
| // ..$(BUILD_VERSION_TAGS) |
| // eg: |
| // google/caroline/caroline_cheets:7.1.1/R65-10317.0.9999/ |
| // ..4548207:user/release-keys |
| // we want to get the $(PLATFORM_VERSION). eg: 7.1.1 |
| |
| std::string android_version; |
| // Assuming the fingerprint format won't change. Everything between ':' and |
| // '/R' is the version. |
| auto begin = fingerprint.find(':'); |
| if (begin == std::string::npos) |
| return base::nullopt; |
| |
| // Make begin point to the start of the "version". |
| begin++; |
| |
| // Version must have at least one digit. |
| const auto end = fingerprint.find("/R", begin + 1); |
| if (end == std::string::npos) |
| return base::nullopt; |
| |
| return fingerprint.substr(begin, end - begin); |
| } |
| |
| bool ParseCrashLog(const std::string& type, |
| std::stringstream* stream, |
| std::unordered_map<std::string, std::string>* map, |
| std::string* exception_info, |
| std::string* log) { |
| std::string line; |
| |
| // The last header is followed by an empty line. |
| while (std::getline(*stream, line) && !line.empty()) { |
| const auto end = line.find(':'); |
| |
| if (end != std::string::npos) { |
| const auto begin = line.find_first_not_of(' ', end + 1); |
| |
| if (begin != std::string::npos) { |
| // TODO(domlaskowski): Use multimap to allow multiple "Package" headers. |
| if (!map->emplace(line.substr(0, end), line.substr(begin)).second) |
| LOG(WARNING) << "Duplicate header: " << line; |
| continue; |
| } |
| } |
| |
| // Ignore malformed headers. The report is still created, but the associated |
| // metadata fields are set to "unknown". |
| LOG(WARNING) << "Header has unexpected format: " << line; |
| } |
| |
| if (stream->fail()) |
| return false; |
| |
| if (HasExceptionInfo(type)) { |
| std::ostringstream out; |
| out << stream->rdbuf(); |
| *exception_info = out.str(); |
| } |
| *log = stream->str(); |
| |
| return true; |
| } |
| |
| const char* GetSubjectTag(const std::string& type) { |
| static const CrashLogHeaderMap kTags = { |
| {"data_app_native_crash", "native app crash"}, |
| {"system_app_anr", "ANR"}, |
| {"data_app_anr", "app ANR"}, |
| {"system_server_watchdog", "system server watchdog"}}; |
| |
| const auto it = kTags.find(type); |
| return it == kTags.cend() ? nullptr : it->second.c_str(); |
| } |
| |
| bool IsSilentReport(const std::string& type) { |
| return type == "system_app_wtf" || type == "system_server_wtf"; |
| } |
| |
| std::string GetCrashLogHeader(const CrashLogHeaderMap& map, const char* key) { |
| const auto it = map.find(key); |
| return it == map.end() ? "unknown" : it->second; |
| } |
| |
| pid_t CreateRandomPID() { |
| const auto now = base::TimeTicks::Now(); |
| return (now - ToSeconds(now)).InMicroseconds(); |
| } |
| |
| } // namespace arc_util |