blob: 83cdc3484cb6287d6d7d5fc5dfcea7dc3c95dae0 [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/CrashService_linux.h"
#include "android/base/files/PathUtils.h"
#include "android/base/system/System.h"
#include "android/crashreport/CrashService.h"
#include "android/crashreport/CrashSystem.h"
#include "android/utils/debug.h"
#include "android/utils/path.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <memory>
#define E(...) derror(__VA_ARGS__)
#define W(...) dwarning(__VA_ARGS__)
#define D(...) VERBOSE_PRINT(init, __VA_ARGS__)
#define I(...) printf(__VA_ARGS__)
#define HWINFO_CMD "lshw"
namespace android {
using ::android::base::PathUtils;
using ::android::base::System;
namespace crashreport {
HostCrashService::~HostCrashService() {
stopCrashServer();
}
void HostCrashService::OnClientDumpRequest(
void* context,
const ::google_breakpad::ClientInfo* client_info,
const ::std::string* file_path) {
if (static_cast<CrashService::DumpRequestContext*>(context)
->file_path.empty()) {
D("Client Requesting dump %s\n", file_path->c_str());
static_cast<CrashService::DumpRequestContext*>(context)->file_path =
*file_path;
}
}
void HostCrashService::OnClientExit(
void* context,
const ::google_breakpad::ClientInfo* client_info) {
D("Client exiting\n");
CrashService::ServerState* serverstate =
static_cast<CrashService::ServerState*>(context);
if (serverstate->connected > 0) {
serverstate->connected -= 1;
}
if (serverstate->connected == 0) {
serverstate->waiting = false;
}
}
bool HostCrashService::startCrashServer(const std::string& pipe) {
const int listen_fd = std::stoi(pipe);
if (mCrashServer) {
return false;
}
initCrashServer();
mCrashServer.reset(new ::google_breakpad::CrashGenerationServer(
listen_fd, OnClientDumpRequest, &mDumpRequestContext, OnClientExit,
&mServerState, true, &CrashSystem::get()->getCrashDirectory()));
return mCrashServer->Start();
}
bool HostCrashService::stopCrashServer() {
if (mCrashServer) {
mCrashServer.reset();
return true;
} else {
return false;
}
}
bool HostCrashService::isClientAlive() {
if (!mClientPID) {
return 0;
}
// waitpid for child clients
waitpid(mClientPID, nullptr, WNOHANG);
// kill with 0 signal will return non 0 if process does not exist
if (kill(mClientPID, 0) != 0) {
return false;
} else {
return true;
}
}
bool HostCrashService::getHWInfo() {
std::string data_directory = getDataDirectory();
if (data_directory.empty()) {
E("Unable to get data directory for crash report attachments");
return false;
}
std::string file_path = PathUtils::join(data_directory, kHwInfoName);
std::string syscmd(HWINFO_CMD);
syscmd += " > ";
syscmd += file_path;
fprintf(stderr, "Running '%s' to get hardware info", syscmd.c_str());
int status = system(syscmd.c_str());
if (status != 0) {
E("Unable to get hardware info for crash report");
return false;
}
return true;
}
bool HostCrashService::getMemInfo() {
// /proc/meminfo contains all the details we need so just upload that
std::string file_path = PathUtils::join(getDataDirectory(), kMemInfoName);
return path_copy_file(file_path.c_str(), "/proc/meminfo") == 0;
}
} // namespace crashreport
} // namespace android