blob: 6bc1132dbd150e8790aad7f72a9b9c78d8138274 [file] [log] [blame]
// Copyright 2015 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "android/crashreport/CrashSystem.h"
#include "android/base/files/PathUtils.h"
#include "android/base/memory/LazyInstance.h"
#include "android/base/StringFormat.h"
#include "android/base/system/System.h"
#ifdef _WIN32
#include "android/base/system/Win32UnicodeString.h"
#include "android/base/system/Win32Utils.h"
#endif
#include "android/crashreport/CrashReporter.h"
#include "android/emulation/ConfigDirs.h"
#include "android/utils/debug.h"
#include "android/utils/path.h"
#if defined(__linux__)
#include "client/linux/crash_generation/crash_generation_server.h"
#endif
#ifdef _WIN32
#include <process.h>
#else
#include <fcntl.h>
#include <unistd.h>
#endif
#ifdef __APPLE__
#import <Carbon/Carbon.h>
#endif // __APPLE__
#define E(...) derror(__VA_ARGS__)
#define W(...) dwarning(__VA_ARGS__)
#define D(...) VERBOSE_PRINT(init, __VA_ARGS__)
#define I(...) printf(__VA_ARGS__)
namespace android {
namespace crashreport {
using ::android::base::LazyInstance;
using ::android::base::PathUtils;
using ::android::base::RunOptions;
using ::android::base::StringFormat;
using ::android::base::System;
namespace {
const char kCrashURL_prod[] = "https://clients2.google.com/cr/report";
const char kCrashURL_staging[] =
"https://clients2.google.com/cr/staging_report";
#if defined(_WIN32)
const char kPipeName[] = "\\\\.\\pipe\\AndroidEmulatorCrashService";
#elif defined(__APPLE__)
const char kPipeName[] = "com.google.AndroidEmulator.CrashService";
#endif
const char kCrashSubDir[] = "breakpad";
class HostCrashSystem : public CrashSystem {
public:
HostCrashSystem() = default;
virtual ~HostCrashSystem() = default;
virtual const std::string& getCrashDirectory() override {
if (mCrashDir.empty()) {
mCrashDir =
PathUtils::join(::android::ConfigDirs::getUserDirectory(),
kCrashSubDir)
.c_str();
}
return mCrashDir;
}
virtual const std::string& getCrashURL() override {
if (mCrashURL.empty()) {
if (CrashType::CRASHUPLOAD == CrashType::PROD) {
mCrashURL.assign(kCrashURL_prod);
} else if (CrashType::CRASHUPLOAD == CrashType::STAGING) {
mCrashURL.assign(kCrashURL_staging);
}
}
return mCrashURL;
}
virtual bool validatePaths() override {
bool valid = CrashSystem::validatePaths();
std::string crashDir = getCrashDirectory();
if (!System::get()->pathExists(crashDir)) {
if (path_mkdir_if_needed(crashDir.c_str(), 0744) == -1) {
W("Couldn't create crash dir %s\n", crashDir.c_str());
valid = false;
}
} else if (System::get()->pathIsFile(crashDir)) {
W("Crash dir is a file! %s\n", crashDir.c_str());
valid = false;
}
return valid;
}
private:
std::string mCrashDir;
std::string mCrashURL;
};
LazyInstance<HostCrashSystem> sCrashSystem = LAZY_INSTANCE_INIT;
CrashSystem* sCrashSystemForTesting = nullptr;
} // namespace
int CrashSystem::spawnService(const std::vector<std::string>& commandLine) {
System::Pid pid;
auto success = System::get()->runCommand(commandLine, RunOptions::Default,
System::kInfinite, nullptr, &pid);
return success ? pid : -1;
}
const std::string& CrashSystem::getCaBundlePath() {
if (mCaBundlePath.empty()) {
mCaBundlePath = PathUtils::join(System::get()->getLauncherDirectory(),
"lib", "ca-bundle.pem")
.c_str();
}
return mCaBundlePath;
}
const std::string& CrashSystem::getCrashServicePath() {
if (mCrashServicePath.empty()) {
mCrashServicePath =
PathUtils::join(
System::get()->getLauncherDirectory(),
PathUtils::toExecutableName(StringFormat(
"emulator%s-crash-service",
System::kProgramBitness == 64 ? "64" : "")))
.c_str();
}
return mCrashServicePath;
}
const std::string& CrashSystem::getProcessId() {
if (mProcessId.empty()) {
#if defined(__linux__) || defined(__APPLE__)
mProcessId = std::to_string(getpid());
#elif defined(_WIN32)
mProcessId = std::to_string(GetCurrentProcessId());
#endif
}
return mProcessId;
}
const CrashSystem::CrashPipe& CrashSystem::getCrashPipe() {
if (!mCrashPipe.isValid()) {
#if defined(__linux__)
int server_fd;
int client_fd;
if (!google_breakpad::CrashGenerationServer::CreateReportChannel(
&server_fd, &client_fd)) {
W("CrashReporter CreateReportChannel failed!\n");
} else {
mCrashPipe = CrashPipe(server_fd, client_fd);
}
#elif defined(__APPLE__) || defined(_WIN32)
std::string pipename;
pipename.append(kPipeName);
pipename.append(".");
pipename.append(getProcessId());
mCrashPipe = CrashPipe(pipename);
#endif
}
return mCrashPipe;
}
std::vector<std::string> CrashSystem::getCrashServiceCmdLine(
const std::string& pipe,
const std::string& proc) {
const std::vector<std::string> cmdline = {
getCrashServicePath(),
"-pipe",
pipe,
"-ppid",
proc,
"-data-dir",
CrashReporter::get()->getDataExchangeDir()};
return cmdline;
}
bool CrashSystem::validatePaths() {
bool valid = true;
std::string caBundlePath = getCaBundlePath();
std::string crashServicePath = getCrashServicePath();
if (!System::get()->pathIsFile(caBundlePath)) {
W("Couldn't find file %s\n", caBundlePath.c_str());
valid = false;
}
if (!System::get()->pathIsFile(crashServicePath)) {
W("Couldn't find crash service executable %s\n",
crashServicePath.c_str());
valid = false;
}
return valid;
}
CrashSystem* CrashSystem::get() {
CrashSystem* result = sCrashSystemForTesting;
if (!result) {
result = sCrashSystem.ptr();
}
return result;
}
// static
bool CrashSystem::isDump(const std::string& path) {
return PathUtils::extension(path) == ".dmp" &&
System::get()->pathIsFile(path);
}
// static
CrashSystem* CrashSystem::setForTesting(CrashSystem* crashsystem) {
CrashSystem* result = sCrashSystemForTesting;
sCrashSystemForTesting = crashsystem;
return result;
}
} // namespace crashreport
} // namespace android