#include "chrome/updater/updater.h"
#include <algorithm>
#include <iterator>
#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/message_loop/message_pump_type.h"
#include "base/process/memory.h"
#include "base/task/single_thread_task_executor.h"
#include "base/threading/platform_thread.h"
#include "build/build_config.h"
#include "chrome/updater/app/app.h"
#include "chrome/updater/app/app_install.h"
#include "chrome/updater/app/app_uninstall.h"
#include "chrome/updater/app/app_update.h"
#include "chrome/updater/app/app_wake.h"
#include "chrome/updater/configurator.h"
#include "chrome/updater/constants.h"
#include "chrome/updater/crash_client.h"
#include "chrome/updater/crash_reporter.h"
#include "chrome/updater/updater_scope.h"
#include "chrome/updater/updater_version.h"
#include "chrome/updater/util.h"
#include "components/crash/core/common/crash_key.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#if BUILDFLAG(IS_WIN)
#include "base/win/process_startup_helper.h"
#include "chrome/updater/app/server/win/server.h"
#include "chrome/updater/app/server/win/service_main.h"
#include "chrome/updater/win/win_util.h"
#elif BUILDFLAG(IS_MAC)
#include "chrome/updater/app/server/mac/server.h"
#elif BUILDFLAG(IS_LINUX)
#include "chrome/updater/app/server/linux/server.h"
#endif
namespace updater {
namespace {
void InitLogging(UpdaterScope updater_scope) {
logging::LoggingSettings settings;
const absl::optional<base::FilePath> log_dir =
GetBaseDirectory(updater_scope);
if (!log_dir) {
LOG(ERROR) << "Error getting base dir.";
return;
}
const auto log_file = log_dir->Append(FILE_PATH_LITERAL("updater.log"));
settings.log_file_path = log_file.value().c_str();
settings.logging_dest = logging::LOG_TO_ALL;
logging::InitLogging(settings);
logging::SetLogItems(true,
true,
true,
false);
}
void ReinitializeLoggingAfterCrashHandler(UpdaterScope updater_scope) {
base::CommandLine::ForCurrentProcess()->RemoveSwitch(kLoggingModuleSwitch);
InitLogging(updater_scope);
}
void InitializeCrashReporting(UpdaterScope updater_scope) {
crash_reporter::InitializeCrashKeys();
static crash_reporter::CrashKeyString<16> crash_key_process_type(
"process_type");
crash_key_process_type.Set("updater");
if (!CrashClient::GetInstance()->InitializeCrashReporting(updater_scope)) {
VLOG(1) << "Crash reporting is not available.";
return;
}
VLOG(1) << "Crash reporting initialized.";
}
int HandleUpdaterCommands(UpdaterScope updater_scope,
const base::CommandLine* command_line) {
if (command_line->HasSwitch(kTestSwitch))
return 0;
if (command_line->HasSwitch(kCrashHandlerSwitch)) {
const int retval = CrashReporterMain();
ReinitializeLoggingAfterCrashHandler(updater_scope);
return retval;
}
StartCrashReporter(updater_scope, kUpdaterVersion);
InitializeCrashReporting(updater_scope);
base::EnableTerminationOnHeapCorruption();
base::EnableTerminationOnOutOfMemory();
#if BUILDFLAG(IS_WIN)
base::win::RegisterInvalidParamHandler();
VLOG(1) << GetUACState();
#endif
base::SingleThreadTaskExecutor main_task_executor(base::MessagePumpType::UI);
if (command_line->HasSwitch(kCrashMeSwitch)) {
CHECK(false) << "--crash-me was used.";
}
if (command_line->HasSwitch(kServerSwitch)) {
#if BUILDFLAG(IS_WIN)
return AppServerSingletonInstance()->Run();
#else
return MakeAppServer()->Run();
#endif
}
if (command_line->HasSwitch(kUpdateSwitch))
return MakeAppUpdate()->Run();
#if BUILDFLAG(IS_WIN)
if (command_line->HasSwitch(kComServiceSwitch))
return ServiceMain::RunComService(command_line);
#endif
if (command_line->HasSwitch(kInstallSwitch) ||
command_line->HasSwitch(kTagSwitch)) {
return MakeAppInstall()->Run();
}
if (command_line->HasSwitch(kUninstallSwitch) ||
command_line->HasSwitch(kUninstallSelfSwitch) ||
command_line->HasSwitch(kUninstallIfUnusedSwitch)) {
return MakeAppUninstall()->Run();
}
if (command_line->HasSwitch(kWakeSwitch)) {
return MakeAppWake()->Run();
}
VLOG(1) << "Unknown command line switch.";
return -1;
}
const char* GetUpdaterCommand(const base::CommandLine* command_line) {
const char* commands[] = {
kComServiceSwitch,
kCrashHandlerSwitch,
kInstallSwitch,
kServerSwitch,
kTagSwitch,
kTestSwitch,
kUninstallIfUnusedSwitch,
kUninstallSelfSwitch,
kUninstallSwitch,
kUpdateSwitch,
kWakeSwitch,
};
const char** it = std::find_if(
std::begin(commands), std::end(commands),
[command_line](auto cmd) { return command_line->HasSwitch(cmd); });
return it != std::end(commands) ? *it : "";
}
}
int UpdaterMain(int argc, const char* const* argv) {
base::PlatformThread::SetName("UpdaterMain");
base::AtExitManager exit_manager;
base::CommandLine::Init(argc, argv);
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
const UpdaterScope updater_scope = GetUpdaterScope();
InitLogging(updater_scope);
VLOG(1) << "Version " << kUpdaterVersion
<< ", command line: " << command_line->GetCommandLineString();
const int retval = HandleUpdaterCommands(updater_scope, command_line);
VLOG(1) << __func__ << " (--" << GetUpdaterCommand(command_line) << ")"
<< " returned " << retval << ".";
return retval;
}
}