| // 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; |
| } |