// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include #include #include #include #include #include #include #include #include ServiceDesktop::ServiceDesktop(const std::filesystem::path &mtpRootPath) : sys::Service(service::name::service_desktop, "", sdesktop::service_stack), btMsgHandler(std::make_unique(this)), connectionActiveTimer{sys::TimerFactory::createSingleShotTimer( this, sdesktop::connectionActiveTimerName, sdesktop::connectionActiveTimerDelayMs, [this](sys::Timer & /*timer*/) { outboxNotifications.clearNotifications(); })}, mtpRootPath{mtpRootPath} { LOG_INFO("[ServiceDesktop] Initializing"); bus.channels.push_back(sys::BusChannel::PhoneLockChanges); bus.channels.push_back(sys::BusChannel::ServiceDBNotifications); bus.channels.push_back(sys::BusChannel::USBNotifications); } ServiceDesktop::~ServiceDesktop() { LOG_INFO("[ServiceDesktop] Cleaning resources"); } sys::ReturnCodes ServiceDesktop::InitHandler() { settings = std::make_unique(); settings->init(service::ServiceProxy(shared_from_this())); usbSecurityModel = std::make_unique(this, settings.get()); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); connectHandler(); checkChargingCondition(); return sys::ReturnCodes::Success; } sys::ReturnCodes ServiceDesktop::DeinitHandler() { return usbWorkerDeinit(); } sys::ReturnCodes ServiceDesktop::SwitchPowerModeHandler(const sys::ServicePowerMode /*mode*/) { return sys::ReturnCodes::Success; } sys::MessagePointer ServiceDesktop::DataReceivedHandler(sys::DataMessage * /*msg*/, sys::ResponseMessage *resp) { auto response = std::make_shared(); if (resp == nullptr) { return response; } if (resp->responseTo != MessageType::DBQuery) { return response; } if (auto queryResponse = dynamic_cast(resp)) { auto result = queryResponse->getResult(); if (result == nullptr) { LOG_ERROR("Wrong result - nullptr!"); return response; } if (result->hasListener()) { LOG_DEBUG("Handling result..."); result->handle(); } } return response; } void ServiceDesktop::prepareSyncData() { syncStatus.state = Sync::OperationState::Stopped; syncStatus.tempDir = purefs::dir::getTemporaryPath() / "sync"; } auto ServiceDesktop::requestLogsFlush() -> void { int response = 0; auto ret = bus.sendUnicastSync( std::make_shared(), service::name::evt_manager, DefaultLogFlushTimeoutInMs); if (ret.first == sys::ReturnCodes::Success) { auto responseMsg = std::dynamic_pointer_cast(ret.second); if ((responseMsg != nullptr) && responseMsg->retCode) { response = responseMsg->data; LOG_DEBUG("Respone data: %d", response); } } if (ret.first == sys::ReturnCodes::Failure || response < 0) { throw std::runtime_error("Logs flush failed"); } } auto ServiceDesktop::getSerialNumber() const -> std::string { return settings->getValue(sdesktop::pathFactoryDataSerial, settings::SettingsScope::Global); } auto ServiceDesktop::getCaseColour() const -> std::string { return settings->getValue(sdesktop::pathFactoryDataCaseColour, settings::SettingsScope::Global); } auto ServiceDesktop::getDeviceToken() -> std::string { auto tokenSeed = getDeviceUniqueId(); if (tokenSeed.empty()) { LOG_DEBUG("Device unique id is empty, generating one..."); generateDeviceUniqueId(); tokenSeed = getDeviceUniqueId(); } return tokenSeed; } auto ServiceDesktop::getNotificationEntries() const -> std::vector { return outboxNotifications.getNotificationEntries(); } void ServiceDesktop::removeNotificationEntries(const std::vector &uidsOfNotificationsToBeRemoved) { outboxNotifications.removeNotificationEntries(uidsOfNotificationsToBeRemoved); } auto ServiceDesktop::generateDeviceUniqueId() -> void { const auto deviceUniqueId = utils::generateRandomId(sdesktop::DeviceUniqueIdLength); LOG_SENSITIVE(LOGINFO, "Device unique id: %s", deviceUniqueId.c_str()); setDeviceUniqueId(deviceUniqueId); } auto ServiceDesktop::getDeviceUniqueId() const -> std::string { return settings->getValue(sdesktop::DeviceUniqueIdName); } auto ServiceDesktop::setDeviceUniqueId(const std::string &token) -> void { return settings->setValue(sdesktop::DeviceUniqueIdName, token); } auto ServiceDesktop::usbWorkerInit() -> sys::ReturnCodes { if (initialized) { return sys::ReturnCodes::Success; } auto serialNumber = getSerialNumber(); auto caseColour = getCaseColour(); LOG_DEBUG("usbWorkerInit Serial Number: %s, Case Colour: %s", serialNumber.c_str(), caseColour.c_str()); desktopWorker = std::make_unique(this, std::bind(&ServiceDesktop::restartConnectionActiveTimer, this), *usbSecurityModel, serialNumber, caseColour, mtpRootPath); initialized = desktopWorker->init({{sdesktop::RECEIVE_QUEUE_BUFFER_NAME, sizeof(std::string *), sdesktop::cdc_queue_len}, {sdesktop::SEND_QUEUE_BUFFER_NAME, sizeof(std::string *), sdesktop::cdc_queue_object_size}, {sdesktop::IRQ_QUEUE_BUFFER_NAME, 1, sdesktop::irq_queue_object_size}}); if (!initialized) { LOG_ERROR("!!! service-desktop usbWorkerInit failed to initialize worker, service-desktop won't work"); return sys::ReturnCodes::Failure; } else { desktopWorker->run(); return sys::ReturnCodes::Success; } } auto ServiceDesktop::usbWorkerDeinit() -> sys::ReturnCodes { if (initialized) { LOG_DEBUG(".. usbWorkerDeinit .."); settings->deinit(); desktopWorker->closeWorker(); desktopWorker.reset(); initialized = false; isUsbConfigured = false; } return sys::ReturnCodes::Success; } void ServiceDesktop::restartConnectionActiveTimer() { connectionActiveTimer.restart(sdesktop::connectionActiveTimerDelayMs); } void ServiceDesktop::checkChargingCondition() { if (Store::Battery::get().state == Store::Battery::State::Discharging) { usbWorkerDeinit(); } else { usbWorkerInit(); isPlugEventUnhandled = true; } } auto ServiceDesktop::handle(db::NotificationMessage *msg) -> std::shared_ptr { if (!connectionActiveTimer.isActive()) { return sys::MessageNone{}; } auto notificationMessage = static_cast(msg); outboxNotifications.newNotificationHandler(notificationMessage); return sys::MessageNone{}; } auto ServiceDesktop::handle(locks::UnlockedPhone * /*msg*/) -> std::shared_ptr { LOG_INFO("Phone unlocked."); usbSecurityModel->setPhoneUnlocked(); if (isUsbConfigured && isPlugEventUnhandled) { bus.sendUnicast(std::make_shared(sys::phone_modes::Tethering::On), service::name::system_manager); isPlugEventUnhandled = false; } return sys::MessageNone{}; } auto ServiceDesktop::handle(locks::LockedPhone * /*msg*/) -> std::shared_ptr { LOG_INFO("Phone locked."); usbSecurityModel->setPhoneLocked(); return sys::MessageNone{}; } auto ServiceDesktop::handle(locks::NextPhoneUnlockAttemptLockTime *msg) -> std::shared_ptr { auto message = static_cast(msg); usbSecurityModel->updatePhoneLockTime(message->getTime()); return sys::MessageNone{}; } auto ServiceDesktop::handle(message::bluetooth::ResponseStatus *msg) -> std::shared_ptr { auto msgl = static_cast(msg); return btMsgHandler->handle(msgl); } auto ServiceDesktop::handle(message::bluetooth::ResponseBondedDevices *msg) -> std::shared_ptr { auto msgl = static_cast(msg); return btMsgHandler->handle(msgl); } auto ServiceDesktop::handle(message::bluetooth::ResponseVisibleDevices *msg) -> std::shared_ptr { auto msgl = static_cast(msg); return btMsgHandler->handle(msgl); } auto ServiceDesktop::handle(sdesktop::developerMode::DeveloperModeRequest *msg) -> std::shared_ptr { auto request = static_cast(msg); if (request->event != nullptr) { request->event->send(); } return sys::MessageNone{}; } auto ServiceDesktop::handle(sdesktop::SyncMessage * /*msg*/) -> std::shared_ptr { syncStatus.state = Sync::OperationState::Running; syncStatus.completionCode = Sync::PrepareSyncPackage(this, syncStatus.tempDir); if (syncStatus.completionCode == Sync::CompletionCode::Success) { LOG_INFO("Sync package preparation finished"); syncStatus.state = Sync::OperationState::Finished; } else { LOG_ERROR("Sync package preparation failed"); syncStatus.state = Sync::OperationState::Error; } return sys::MessageNone{}; } auto ServiceDesktop::handle(sdesktop::FactoryMessage * /*msg*/) -> std::shared_ptr { LOG_DEBUG("ServiceDesktop: FactoryMessage received"); sys::SystemManagerCommon::FactoryReset(this); return sys::MessageNone{}; } auto ServiceDesktop::handle(sdesktop::usb::USBConfigured *msg) -> std::shared_ptr { isUsbConfigured = true; if (usbSecurityModel->isSecurityEnabled()) { LOG_INFO("Endpoint security enabled, requesting passcode"); bus.sendUnicast(std::make_shared(), service::name::appmgr); } else { auto message = static_cast(msg); if (message->getConfigurationType() == sdesktop::usb::USBConfigurationType::firstConfiguration && isPlugEventUnhandled) { bus.sendUnicast(std::make_shared(sys::phone_modes::Tethering::On), service::name::system_manager); isPlugEventUnhandled = false; } } return sys::MessageNone{}; } auto ServiceDesktop::handle(sdesktop::usb::USBDisconnected * /*msg*/) -> std::shared_ptr { LOG_INFO("USB disconnected"); if (usbSecurityModel->isSecurityEnabled()) { bus.sendUnicast(std::make_shared(), service::name::appmgr); } bus.sendUnicast(std::make_shared(sys::phone_modes::Tethering::Off), service::name::system_manager); return sys::MessageNone{}; } auto ServiceDesktop::handle(sevm::USBPlugEvent *msg) -> std::shared_ptr { auto message = static_cast(msg); if (message->event == sevm::USBPlugEvent::Event::CablePlugged) { usbWorkerInit(); isPlugEventUnhandled = true; } else { usbWorkerDeinit(); } return sys::MessageNone{}; } auto ServiceDesktop::getMtpPath() const noexcept -> std::filesystem::path { return mtpRootPath; }