~aleteoryx/muditaos

6a207e7a2a12395fecd54fd7f5874832d43a577b — Roman Kubiak 5 years ago e352630
[EGD-4559] store update history in settings db (#1134)

* [EGD-4559] store update history in settings db

* [EGD-4559] first review fixes

* [EGD-4559] catch changed

Co-authored-by: Alek Rudnik <aleksander.rudnik@mudita.com>

M module-apps/application-desktop/windows/Update.cpp => module-apps/application-desktop/windows/Update.cpp +4 -4
@@ 8,7 8,7 @@
#include <source/version.hpp>

// module-utils
#include "module-utils/i18n/i18n.hpp"
#include "i18n/i18n.hpp"

#include "Update.hpp"
#include "../ApplicationDesktop.hpp"


@@ 176,11 176,11 @@ namespace gui
                updateVersion << utils::localize.get("app_desktop_update_to");
                updateVersion << ": ";
                updateVersion << msg.updateStats
                                     .versioInformation[purefs::json::os_version][purefs::json::version_string]
                                     .versionInformation[purefs::json::os_version][purefs::json::version_string]
                                     .string_value();
                updateVersion << " (";
                updateVersion << msg.updateStats
                                     .versioInformation[purefs::json::git_info][purefs::json::os_git_revision]
                                     .versionInformation[purefs::json::git_info][purefs::json::os_git_revision]
                                     .string_value();
                updateVersion << ")";



@@ 189,7 189,7 @@ namespace gui
                updateFileDetails << std::to_string(msg.updateStats.totalBytes / 1024);
                updateFileDetails << "Kb (";
                updateFileDetails
                    << msg.updateStats.versioInformation[purefs::json::misc][purefs::json::builddate].string_value();
                    << msg.updateStats.versionInformation[purefs::json::misc][purefs::json::builddate].string_value();
                updateFileDetails << ")";

                currentVersionInfo->setText(currentVersion.str());

M module-services/service-desktop/ServiceDesktop.cpp => module-services/service-desktop/ServiceDesktop.cpp +12 -2
@@ 16,6 16,7 @@
#include <json/json11.hpp>
#include <log/log.hpp>
#include <module-apps/application-desktop/ApplicationDesktop.hpp>
#include <service-db/service-db/Settings.hpp>
#include <service-db/QueryMessage.hpp>
#include <vfs.hpp>



@@ 27,6 28,10 @@ ServiceDesktop::ServiceDesktop() : sys::Service(service::name::service_desktop, 
    LOG_INFO("[ServiceDesktop] Initializing");

    updateOS = std::make_unique<UpdateMuditaOS>(this);
    settings = std::make_unique<settings::Settings>(this);

    settings->registerValueChange(updateos::settings::history,
                                  [this](const std::string &value) { updateOS->setInitialHistory(value); });
}

ServiceDesktop::~ServiceDesktop()


@@ 95,7 100,7 @@ sys::ReturnCodes ServiceDesktop::InitHandler()
                /* send info to applicationDesktop that there is an update waiting */
                auto msgToSend =
                    std::make_shared<sdesktop::UpdateOsMessage>(updateos::UpdateMessageType::UpdateFoundOnBoot, file);
                msgToSend->updateStats.versioInformation = UpdateMuditaOS::getVersionInfoFromFile(file);
                msgToSend->updateStats.versionInformation = UpdateMuditaOS::getVersionInfoFromFile(file);
                sys::Bus::SendUnicast(msgToSend, app::name_desktop, this);
            }
        }


@@ 116,7 121,7 @@ sys::ReturnCodes ServiceDesktop::InitHandler()

sys::ReturnCodes ServiceDesktop::DeinitHandler()
{
    desktopWorker->close();
    desktopWorker->deinit();
    return sys::ReturnCodes::Success;
}



@@ 151,3 156,8 @@ sys::MessagePointer ServiceDesktop::DataReceivedHandler(sys::DataMessage *msg, s

    return std::make_shared<sys::ResponseMessage>();
}

void ServiceDesktop::storeHistory(const std::string &historyValue)
{
    settings->setValue(updateos::settings::history, historyValue);
}

M module-services/service-desktop/endpoints/deviceInfo/DeviceInfoEndpoint.cpp => module-services/service-desktop/endpoints/deviceInfo/DeviceInfoEndpoint.cpp +4 -2
@@ 10,7 10,7 @@
#include <source/version.hpp>
#include <time/time_conversion.hpp>
#include <vfs.hpp>

#include <service-desktop/service-desktop/ServiceDesktop.hpp>
#include <cstdint>
#include <string>



@@ 29,6 29,7 @@ auto DeviceInfoEndpoint::handle(Context &context) -> void
auto DeviceInfoEndpoint::getDeviceInfo(Context &context) -> bool
{
    vfs::FilesystemStats fsStats = vfs.getFilesystemStats();
    json11::Json updateHistory   = static_cast<ServiceDesktop *>(ownerServicePtr)->updateOS->getUpdateHistory();

    context.setResponseBody(json11::Json::object(
        {{json::batteryLevel, std::to_string(Store::Battery::get().level)},


@@ 44,7 45,8 @@ auto DeviceInfoEndpoint::getDeviceInfo(Context &context) -> bool
         {json::gitRevision, (std::string)(GIT_REV)},
         {json::gitTag, (std::string)GIT_TAG},
         {json::gitBranch, (std::string)GIT_BRANCH},
         {json::currentRTCTime, std::to_string(static_cast<uint32_t>(utils::time::Time().getTime()))}}));
         {json::updateHistory, updateHistory},
         {json::currentRTCTime, std::to_string(static_cast<uint32_t>(utils::time::getCurrentTimestamp().getTime()))}}));

    MessageHandler::putToSendQueue(context.createSimpleResponse());
    return true;

M module-services/service-desktop/endpoints/update/UpdateMuditaOS.cpp => module-services/service-desktop/endpoints/update/UpdateMuditaOS.cpp +81 -5
@@ 12,9 12,10 @@
#include <log/log.hpp>
#include <microtar/src/microtar.hpp>
#include <module-apps/application-desktop/ApplicationDesktop.hpp>
#include <service-db/service-db/Settings.hpp>
#include <purefs/filesystem_paths.hpp>
#include <vfs.hpp>

#include <time/time_conversion.hpp>
#if defined(TARGET_RT1051)
#include <board/cross/eMMC/eMMC.hpp>
#include "bsp/watchdog/watchdog.hpp"


@@ 54,7 55,7 @@ updateos::UpdateError UpdateMuditaOS::setUpdateFile(fs::path updateFileToUse)
{
    updateFile = purefs::dir::getUpdatesOSPath() / updateFileToUse;
    if (vfs.fileExists(updateFile.c_str())) {
        versioInformation = UpdateMuditaOS::getVersionInfoFromFile(updateFile);
        versionInformation = UpdateMuditaOS::getVersionInfoFromFile(updateFile);
        if (mtar_open(&updateTar, updateFile.c_str(), "r") == MTAR_ESUCCESS) {
            totalBytes = vfs.filelength(updateTar.stream);
        }


@@ 78,6 79,10 @@ updateos::UpdateError UpdateMuditaOS::runUpdate()
{
    informDebug("Prepraring temp dir");

    updateRunStatus.startTime   = utils::time::getCurrentTimestamp().getTime();
    updateRunStatus.fromVersion = vfs.getBootConfig().to_json();
    storeRunStatusInDB();

    updateos::UpdateError err = prepareTempDirForUpdate();
    if (err != updateos::UpdateError::NoError) {
        return informError(err, "runUpdate can't prepare temp directory for update");


@@ 123,6 128,9 @@ updateos::UpdateError UpdateMuditaOS::runUpdate()
        informError(err, "runUpdate cleanupAfterUpdate failed, resetting anyway");
    }

    updateRunStatus.endTime = utils::time::Time().getTime();
    storeRunStatusInDB();

    // reboot always
    sys::SystemManager::Reboot(owner);



@@ 211,19 219,29 @@ updateos::UpdateError UpdateMuditaOS::verifyVersion()

    std::string versionJsonString = vfs.loadFileAsString(getUpdateTmpChild(updateos::file::version));
    std::string parserError;
    json11::Json updateVersionInformation = json11::Json::parse(versionJsonString, parserError);
    if (parserError != "") {
    targetVersionInfo = json11::Json::parse(versionJsonString, parserError);
    if (!parserError.empty()) {
        return informError(
            updateos::UpdateError::VerifyVersionFailure, "verifyVersion parse json error: %s", parserError.c_str());
    }
    else {
        /* version comparison goes here */
        updateRunStatus.toVersion = targetVersionInfo;
        const bool ret            = vfs.getBootConfig().version_compare(
            targetVersionInfo[purefs::json::version_string].string_value(), vfs.getBootConfig().os_version);
        LOG_DEBUG("verifyVersion comaprison result == %s", ret ? "true" : "false");
    }
    return updateos::UpdateError::NoError;
}

updateos::UpdateError UpdateMuditaOS::updateBootloader()
{
    informDebug("updateBootloader noError");
    informDebug("updateBootloader");
    if (targetVersionInfo[purefs::json::bootloader][parserFSM::json::fileName].is_string()) {
        fs::path bootloaderFile =
            getUpdateTmpChild(targetVersionInfo[purefs::json::bootloader][parserFSM::json::fileName].string_value());
        return writeBootloader(bootloaderFile);
    }
    return updateos::UpdateError::NoError;
}



@@ 426,9 444,11 @@ updateos::UpdateError UpdateMuditaOS::cleanupAfterUpdate()
            updateos::UpdateError::CantRemoveUniqueTmpDir, "ff_deltree failed on %s", updateTempDirectory.c_str());
    }
    mtar_close(&updateTar);

    if (vfs.remove(updateFile.c_str())) {
        return informError(updateos::UpdateError::CantRemoveUpdateFile, "Failed to delete %s", updateFile.c_str());
    }

    status = updateos::UpdateState::ReadyForReset;
    return updateos::UpdateError::NoError;
}


@@ 668,6 688,8 @@ updateos::UpdateError UpdateMuditaOS::informError(const updateos::UpdateError er
    responseContext.setResponseBody(responseJson);
    parserFSM::MessageHandler::putToSendQueue(responseContext.createSimpleResponse());

    updateRunStatus.finishedState = status;
    updateRunStatus.finishedError = errorCode;
    return errorCode;
}



@@ 705,4 727,58 @@ void UpdateMuditaOS::informUpdate(const updateos::UpdateState statusCode, const 
                                                     {parserFSM::json::statusCode, static_cast<uint8_t>(statusCode)}};
    responseContext.setResponseBody(responseJson);
    parserFSM::MessageHandler::putToSendQueue(responseContext.createSimpleResponse());

    updateRunStatus.finishedState = status;
}

void UpdateMuditaOS::setInitialHistory(const std::string &initialHistory)
{
    LOG_DEBUG("setInitialHistory %s", initialHistory.c_str());
    std::string parseErrors;
    updateHistory = json11::Json::parse(initialHistory, parseErrors);

    if (!parseErrors.empty() && !initialHistory.empty()) {
        LOG_ERROR("Can't parse current update history, resetting");
        updateHistory = json11::Json();
    }
}

void UpdateMuditaOS::storeRunStatusInDB()
{
    std::vector<json11::Json> tempTable;
    bool statusRunFound = false;
    if (updateHistory.is_array()) {
        for (const auto &value : updateHistory.array_items()) {
            try {
                // need to use stoul as json does not seem to handle it well
                if (std::stoul(value[updateos::settings::startTime].string_value()) == updateRunStatus.startTime) {
                    tempTable.emplace_back(updateRunStatus);

                    // this tells us we already found and element in history
                    statusRunFound = true;
                }
                else {
                    // if we found a value in history that's not ours, just copy it to temptable
                    tempTable.emplace_back(value);
                }
            }
            catch (const std::exception &arg) {
                LOG_ERROR("storeRunStatusInDB %s error - %s",
                          arg.what(),
                          value[updateos::settings::startTime].string_value().c_str());
            }
        }

        if (statusRunFound == false) {
            // if our element was not found, insert it
            tempTable.emplace_back(updateRunStatus);
        }
    }
    else {
        // if the history is not a json array, initialize it
        tempTable = json11::Json::array{updateRunStatus};
    }

    updateHistory = tempTable;
    owner->storeHistory(updateHistory.dump());
}

M module-services/service-desktop/endpoints/update/UpdateMuditaOS.hpp => module-services/service-desktop/endpoints/update/UpdateMuditaOS.hpp +41 -2
@@ 22,9 22,18 @@ namespace updateos
        inline constexpr auto checksums = "checksums.txt";
        inline constexpr auto sql_mig   = "sqlmig.json";
        inline constexpr auto version   = "version.json";

    } // namespace file

    namespace settings
    {
        inline constexpr auto history       = "history";
        inline constexpr auto startTime     = "startTime";
        inline constexpr auto endTime       = "endTime";
        inline constexpr auto finishedState = "finishedState";
        inline constexpr auto finishedError = "finishedError";
        inline constexpr auto fromVersion   = "fromVersion";
        inline constexpr auto toVersion     = "toVersion";
    } // namespace settings
    namespace extension
    {
        inline constexpr auto update = ".tar";


@@ 92,7 101,25 @@ namespace updateos
        uint32_t uuid                  = 0;
        std::string messageText        = "";
        updateos::UpdateState status;
        json11::Json versioInformation;
        json11::Json versionInformation;
    };

    struct UpdateRunStatus
    {
        uint32_t startTime = 0, endTime = 0;
        UpdateState finishedState = UpdateState::Initial;
        UpdateError finishedError = UpdateError::NoError;
        json11::Json fromVersion, toVersion;

        json11::Json to_json() const
        {
            return json11::Json::object{{updateos::settings::startTime, std::to_string(startTime)},
                                        {updateos::settings::endTime, std::to_string(endTime)},
                                        {updateos::settings::finishedState, (int)finishedState},
                                        {updateos::settings::finishedError, (int)finishedError},
                                        {updateos::settings::fromVersion, fromVersion},
                                        {updateos::settings::toVersion, toVersion}};
        }
    };

}; // namespace updateos


@@ 138,9 165,21 @@ class UpdateMuditaOS : public updateos::UpdateStats
    static const json11::Json getVersionInfoFromFile(const fs::path &updateFile);
    static bool isUpgradeToCurrent(const std::string &versionToCompare);
    static const fs::path checkForUpdate();
    void historyValueChanged(const std::string &value);
    void setInitialHistory(const std::string &initialHistory);
    json11::Json getUpdateHistory() const
    {
        return updateHistory;
    }

  private:
    std::vector<FileInfo> filesInUpdatePackage;
    mtar_t updateTar      = {};
    ServiceDesktop *owner = nullptr;

    void storeRunStatusInDB();

    updateos::UpdateRunStatus updateRunStatus;
    json11::Json updateHistory;
    json11::Json targetVersionInfo;
};

M module-services/service-desktop/parser/ParserUtils.hpp => module-services/service-desktop/parser/ParserUtils.hpp +6 -7
@@ 124,13 124,12 @@ namespace parserFSM
        inline constexpr auto accessTechnology = "accessTechnology";
        inline constexpr auto fileName         = "fileName";
        inline constexpr auto fileSize         = "fileSize";

        inline constexpr auto update      = "update";
        inline constexpr auto updateInfo  = "updateInfo";
        inline constexpr auto updateError = "updateError";
        inline constexpr auto errorCode   = "errorCode";
        inline constexpr auto statusCode  = "statusCode";

        inline constexpr auto update           = "update";
        inline constexpr auto updateInfo       = "updateInfo";
        inline constexpr auto updateError      = "updateError";
        inline constexpr auto errorCode        = "errorCode";
        inline constexpr auto statusCode       = "statusCode";
        inline constexpr auto updateHistory    = "updateHistory";
        namespace filesystem
        {
            inline constexpr auto command = "command";

M module-services/service-desktop/service-desktop/ServiceDesktop.hpp => module-services/service-desktop/service-desktop/ServiceDesktop.hpp +9 -1
@@ 16,9 16,13 @@
#include <Service/Common.hpp>
#include <Service/Message.hpp>
#include <Service/Service.hpp>

#include <memory>

namespace settings
{
    class Settings;
}

namespace sdesktop
{
    inline constexpr auto service_stack         = 8192;


@@ 41,4 45,8 @@ class ServiceDesktop : public sys::Service

    std::unique_ptr<UpdateMuditaOS> updateOS;
    std::unique_ptr<WorkerDesktop> desktopWorker;
    void storeHistory(const std::string &historyValue);

  private:
    std::unique_ptr<settings::Settings> settings;
};