blob: 4fa2d705b62b81f81209f8fc7aff4fa83e0d16b7 [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.
/*
* This is the source for the crash service that is spawned by the main
* emulator. It is spawned once per emulator instance and services that
* emulator instance in case of a crash.
*
* Confirmation to send the crash dump is requested by a gui element.
*
* Once confirmation is given, the crash dump is curl'd to google crash servers.
*/
#include "android/base/Uuid.h"
#include "android/crashreport/CrashService.h"
#include "android/crashreport/CrashSystem.h"
#include "android/crashreport/ui/ConfirmDialog.h"
#include "android/qt/qt_path.h"
#include "android/skin/qt/init-qt.h"
#include "android/metrics/CrashMetricsReporting.h"
#include "android/metrics/FileMetricsWriter.h"
#include "android/metrics/MetricsPaths.h"
#include "android/metrics/SyncMetricsReporter.h"
#include "android/utils/debug.h"
#include "android/version.h"
#include <QApplication>
#include <QCoreApplication>
#include <QProgressDialog>
#include <QSettings>
#include <QTimer>
#include <QThread>
#include <stdio.h>
#include <stdlib.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__)
static bool displayConfirmDialog(
android::crashreport::CrashService* crashservice,
Ui::Settings::CRASHREPORT_PREFERENCE_VALUE reportPreference,
const char* data_dir) {
if (reportPreference == Ui::Settings::CRASHREPORT_PREFERENCE_NEVER) {
return false;
}
if (crashservice->getDumpMessage().empty() &&
crashservice->didCrashOnExit() &&
reportPreference != Ui::Settings::CRASHREPORT_PREFERENCE_ALWAYS) {
return false;
}
ConfirmDialog msgBox(nullptr, crashservice, reportPreference, data_dir);
if (reportPreference == Ui::Settings::CRASHREPORT_PREFERENCE_ASK) {
msgBox.show();
int ret = msgBox.exec();
return ret == ConfirmDialog::Accepted;
} else if (reportPreference == Ui::Settings::CRASHREPORT_PREFERENCE_ALWAYS) {
msgBox.sendReport();
return true;
}
return false;
}
static void finalizeMetrics() {
using namespace android::metrics;
D("Finalizing the metrics log file");
const auto crashedSessions =
FileMetricsWriter::finalizeAbandonedSessionFiles(
getSpoolDirectory());
D("found %d crashed sessions", (int)crashedSessions.size());
if (crashedSessions.empty()) {
return;
}
auto writer = FileMetricsWriter::create(
getSpoolDirectory(), android::base::Uuid::generate().toString(),
0, nullptr, 0); // No record or time limits for this writer.
const auto reporter =
MetricsReporter::Ptr(new SyncMetricsReporter(std::move(writer)));
reportCrashMetrics(*reporter, crashedSessions);
}
/* Main routine */
int main(int argc, char** argv) {
// Parse args
const char* service_arg = nullptr;
const char* dump_file = nullptr;
const char* data_dir = nullptr;
int ppid = 0;
for (int nn = 1; nn < argc; nn++) {
const char* opt = argv[nn];
if (!strcmp(opt, "-pipe")) {
if (nn + 1 < argc) {
nn++;
service_arg = argv[nn];
}
} else if (!strcmp(opt, "-dumpfile")) {
if (nn + 1 < argc) {
nn++;
dump_file = argv[nn];
}
} else if (!strcmp(opt, "-ppid")) {
if (nn + 1 < argc) {
nn++;
ppid = atoi(argv[nn]);
}
} else if (!strcmp(opt, "-data-dir")) {
if (nn + 1 < argc) {
nn++;
data_dir = argv[nn];
}
}
}
auto crashservice = ::android::crashreport::CrashService::makeCrashService(
EMULATOR_VERSION_STRING, EMULATOR_BUILD_STRING, data_dir);
if (dump_file &&
::android::crashreport::CrashSystem::get()->isDump(dump_file)) {
crashservice->setDumpFile(dump_file);
} else if (service_arg && ppid) {
if (!crashservice->startCrashServer(service_arg)) {
return 1;
}
if (crashservice->waitForDumpFile(ppid) == -1) {
return 1;
}
crashservice->stopCrashServer();
finalizeMetrics();
if (crashservice->getDumpFile().empty()) {
// No crash dump created
return 0;
}
} else {
E("Must supply a dump path\n");
return 1;
}
if (!crashservice->validDumpFile()) {
E("CrashPath '%s' is invalid\n", crashservice->getDumpFile().c_str());
return 1;
}
crashservice->retrieveDumpMessage();
crashservice->collectProcessList();
QApplication app(argc, argv);
androidQtDefaultInit();
QSettings settings;
auto reportPreference =
static_cast<Ui::Settings::CRASHREPORT_PREFERENCE_VALUE>(
settings.value(Ui::Settings::CRASHREPORT_PREFERENCE, 0).toInt());
if (!displayConfirmDialog(crashservice.get(),
reportPreference,
data_dir) ) {
return 1;
}
return 0;
}