code:
/* Copyright (c) 2015, 2017, 2020 The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials provided
 *       with the distribution.
 *     * Neither the name of The Linux Foundation, nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
#ifndef __LOC_UNORDERDED_SETMAP_H__
#define __LOC_UNORDERDED_SETMAP_H__

#include <algorithm>
#include <loc_pla.h>

#ifdef NO_UNORDERED_SET_OR_MAP
    #include <set>
    #include <map>
#else
    #include <unordered_set>
    #include <unordered_map>
#endif

using std::unordered_set;
using std::unordered_map;

namespace loc_util {

// Trim from *fromSet* any elements that also exist in *rVals*.
// The optional *goneVals*, if not null, will be populated with removed elements.
template <typename T>
inline static void trimSet(unordered_set<T>& fromSet, const unordered_set<T>& rVals,
                           unordered_set<T>* goneVals) {
    for (auto val : rVals) {
        if (fromSet.erase(val) > 0 && nullptr != goneVals) {
            goneVals->insert(val);
        }
    }
}

// this method is destructive to the input unordered_sets.
// the return set is the interset extracted out from the two input sets, *s1* and *s2*.
// *s1* and *s2* will be left with the intersect removed from them.
template <typename T>
static unordered_set<T> removeAndReturnInterset(unordered_set<T>& s1, unordered_set<T>& s2) {
    unordered_set<T> common = {};
    for (auto b = s2.begin(); b != s2.end(); b++) {
        auto a = find(s1.begin(), s1.end(), *b);
        if (a != s1.end()) {
            // this is a common item of both l1 and l2, remove from both
            // but after we add to common
            common.insert(*a);
            s1.erase(a);
            s2.erase(b);
        }
    }
    return common;
}

template <typename KEY, typename VAL>
class LocUnorderedSetMap {
    unordered_map<KEY, unordered_set<VAL>> mMap;

    // Trim the VALs pointed to by *iter*, with everything that also exist in *rVals*.
    // If the set becomes empty, remove the map entry. *goneVals*, if not null, records
    // the trimmed VALs.
    bool trimOrRemove(typename unordered_map<KEY, unordered_set<VAL>>::iterator iter,
                      const unordered_set<VAL>& rVals, unordered_set<VAL>* goneVals) {
        trimSet<VAL>(iter->second, rVals, goneVals);
        bool removeEntry = (iter->second.empty());
        if (removeEntry) {
            mMap.erase(iter);
        }
        return removeEntry;
    }

public:
    inline LocUnorderedSetMap() {}
    inline LocUnorderedSetMap(size_t size) : LocUnorderedSetMap() {
        mMap.get_allocator().allocate(size);
    }

    inline bool empty() { return mMap.empty(); }

    // This gets the raw pointer to the VALs pointed to by *key*
    // If the entry is not in the map, nullptr will be returned.
    inline unordered_set<VAL>* getValSetPtr(const KEY& key) {
        auto entry = mMap.find(key);
        return (entry != mMap.end()) ? &(entry->second) : nullptr;
    }

    //  This gets a copy of VALs pointed to by *key*
    // If the entry is not in the map, an empty set will be returned.
    inline unordered_set<VAL> getValSet(const KEY& key) {
        auto entry = mMap.find(key);
        return (entry != mMap.end()) ? entry->second : unordered_set<VAL>{};
    }

    // This gets all the KEYs from the map
    inline unordered_set<KEY> getKeys() {
        unordered_set<KEY> keys = {};
        for (auto entry : mMap) {
            keys.insert(entry.first);
        }
        return keys;
    }

    inline bool remove(const KEY& key) {
        return mMap.erase(key) > 0;
    }

    // This looks into all the entries keyed by *keys*. Remove any VALs from the entries
    // that also exist in *rVals*. If the entry is left with an empty set, the entry will
    // be removed. The optional parameters *goneKeys* and *goneVals* will record the KEYs
    // (or entries) and the collapsed VALs removed from the map, respectively.
    inline void trimOrRemove(unordered_set<KEY>&& keys, const unordered_set<VAL>& rVals,
                             unordered_set<KEY>* goneKeys, unordered_set<VAL>* goneVals) {
        trimOrRemove(keys, rVals, goneKeys, goneVals);
    }

    inline void trimOrRemove(unordered_set<KEY>& keys, const unordered_set<VAL>& rVals,
                             unordered_set<KEY>* goneKeys, unordered_set<VAL>* goneVals) {
        for (auto key : keys) {
            auto iter = mMap.find(key);
            if (iter != mMap.end() && trimOrRemove(iter, rVals, goneVals) && nullptr != goneKeys) {
                goneKeys->insert(iter->first);
            }
        }
    }

    // This adds all VALs from *newVals* to the map entry keyed by *key*. Or if it
    // doesn't exist yet, add the set to the map.
    bool add(const KEY& key, const unordered_set<VAL>& newVals) {
        bool newEntryAdded = false;
        if (!newVals.empty()) {
            auto iter = mMap.find(key);
            if (iter != mMap.end()) {
                iter->second.insert(newVals.begin(), newVals.end());
            } else {
                mMap[key] = newVals;
                newEntryAdded = true;
            }
        }
        return newEntryAdded;
    }

    // This adds to each of entries in the map keyed by *keys* with the VALs in the
    // *enwVals*. If there new entries added (new key in *keys*), *newKeys*, if not
    // null, would be populated with those keys.
    inline void add(const unordered_set<KEY>& keys, const unordered_set<VAL>&& newVals,
                    unordered_set<KEY>* newKeys) {
        add(keys, newVals, newKeys);
    }

    inline void add(const unordered_set<KEY>& keys, const unordered_set<VAL>& newVals,
                    unordered_set<KEY>* newKeys) {
        for (auto key : keys) {
            if (add(key, newVals) && nullptr != newKeys) {
                newKeys->insert(key);
            }
        }
    }

    // This puts *newVals* into the map keyed by *key*, and returns the VALs that are
    // in effect removed from the keyed VAL set in the map entry.
    // This call would also remove those same VALs from *newVals*.
    inline unordered_set<VAL> update(const KEY& key, unordered_set<VAL>& newVals) {
        unordered_set<VAL> goneVals = {};
        if (newVals.empty()) {
            mMap.erase(key);
        } else {
            auto curVals = mMap[key];
            mMap[key] = newVals;
            goneVals = removeAndReturnInterset(curVals, newVals);
        }
        return goneVals;
    }
};

} // namespace loc_util

#endif // #ifndef __LOC_UNORDERDED_SETMAP_H__


code:
/* Copyright (c) 2019 - 2020 The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials provided
 *       with the distribution.
 *     * Neither the name of The Linux Foundation, nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "LogBuffer.h"
#ifdef USE_GLIB
#include <execinfo.h>
#endif

#ifdef LOG_TAG
#undef LOG_TAG
#endif
#define LOG_TAG "LocSvc_LogBuffer"

namespace loc_util {

LogBuffer* LogBuffer::mInstance;
struct sigaction LogBuffer::mOriSigAction[NSIG];
struct sigaction LogBuffer::mNewSigAction;
mutex LogBuffer::sLock;

LogBuffer* LogBuffer::getInstance() {
    if (mInstance == nullptr) {
        lock_guard<mutex> guard(sLock);
        if (mInstance == nullptr) {
            mInstance = new LogBuffer();
        }
    }
    return mInstance;
}

LogBuffer::LogBuffer(): mLogList(TOTAL_LOG_LEVELS),
        mConfigVec(TOTAL_LOG_LEVELS, ConfigsInLevel(TIME_DEPTH_THRESHOLD_MINIMAL_IN_SEC,
                    MAXIMUM_NUM_IN_LIST, 0)) {
    loc_param_s_type log_buff_config_table[] =
    {
        {"E_LEVEL_TIME_DEPTH",      &mConfigVec[0].mTimeDepthThres,  NULL, 'n'},
        {"E_LEVEL_MAX_CAPACITY",    &mConfigVec[0].mMaxNumThres,     NULL, 'n'},
        {"W_LEVEL_TIME_DEPTH",      &mConfigVec[1].mTimeDepthThres,  NULL, 'n'},
        {"W_LEVEL_MAX_CAPACITY",    &mConfigVec[1].mMaxNumThres,     NULL, 'n'},
        {"I_LEVEL_TIME_DEPTH",      &mConfigVec[2].mTimeDepthThres,  NULL, 'n'},
        {"I_LEVEL_MAX_CAPACITY",    &mConfigVec[2].mMaxNumThres,     NULL, 'n'},
        {"D_LEVEL_TIME_DEPTH",      &mConfigVec[3].mTimeDepthThres,  NULL, 'n'},
        {"D_LEVEL_MAX_CAPACITY",    &mConfigVec[3].mMaxNumThres,     NULL, 'n'},
        {"V_LEVEL_TIME_DEPTH",      &mConfigVec[4].mTimeDepthThres,  NULL, 'n'},
        {"V_LEVEL_MAX_CAPACITY",    &mConfigVec[4].mMaxNumThres,     NULL, 'n'},
    };
    loc_read_conf(LOC_PATH_GPS_CONF_STR, log_buff_config_table,
            sizeof(log_buff_config_table)/sizeof(log_buff_config_table[0]));
    registerSignalHandler();
}

void LogBuffer::append(string& data, int level, uint64_t timestamp) {
    lock_guard<mutex> guard(mLock);
    pair<uint64_t, string> item(timestamp, data);
    mLogList.append(item, level);
    mConfigVec[level].mCurrentSize++;

    while ((timestamp - mLogList.front(level).first) > mConfigVec[level].mTimeDepthThres ||
            mConfigVec[level].mCurrentSize > mConfigVec[level].mMaxNumThres) {
        mLogList.pop(level);
        mConfigVec[level].mCurrentSize--;
    }
}

//Dump the log buffer of specific level, level = -1 to dump all the levels in log buffer.
void LogBuffer::dump(std::function<void(stringstream&)> log, int level) {
    lock_guard<mutex> guard(mLock);
    list<pair<pair<uint64_t, string>, int>> li;
    if (-1 == level) {
        li = mLogList.dump();
    } else {
        li = mLogList.dump(level);
    }
    ALOGE("Begining of dump, buffer size: %d", (int)li.size());
    stringstream ln;
    ln << "dump log buffer, level[" << level << "]" << ", buffer size: " << li.size() << endl;
    log(ln);
    for_each (li.begin(), li.end(), [&, this](const pair<pair<uint64_t, string>, int> &item){
        stringstream line;
        line << "["<<item.first.first << "] ";
        line << "Level " << mLevelMap[item.second] << ": ";
        line << item.first.second << endl;
        if (log != nullptr) {
            log(line);
        }
    });
    ALOGE("End of dump");
}

void LogBuffer::dumpToAdbLogcat() {
    dump([](stringstream& line){
        ALOGE("%s", line.str().c_str());
    });
}

void LogBuffer::dumpToLogFile(string filePath) {
    ALOGE("Dump GPS log buffer to file: %s", filePath.c_str());
    fstream s;
    s.open(filePath, std::fstream::out | std::fstream::app);
    dump([&s](stringstream& line){
        s << line.str();
    });
    s.close();
}

void LogBuffer::flush() {
    mLogList.flush();
}

void LogBuffer::registerSignalHandler() {
    ALOGE("Singal handler registered");
    mNewSigAction.sa_sigaction = &LogBuffer::signalHandler;
    mNewSigAction.sa_flags = SA_SIGINFO | SA_RESTART;
    sigemptyset(&mNewSigAction.sa_mask);

    sigaction(SIGINT, &mNewSigAction, &mOriSigAction[SIGINT]);
    sigaction(SIGKILL, &mNewSigAction, &mOriSigAction[SIGKILL]);
    sigaction(SIGSEGV, &mNewSigAction, &mOriSigAction[SIGSEGV]);
    sigaction(SIGABRT, &mNewSigAction, &mOriSigAction[SIGABRT]);
    sigaction(SIGTRAP, &mNewSigAction, &mOriSigAction[SIGTRAP]);
    sigaction(SIGUSR1, &mNewSigAction, &mOriSigAction[SIGUSR1]);
}

void LogBuffer::signalHandler(const int code, siginfo_t *const si, void *const sc) {
    ALOGE("[Gnss Log buffer]Singal handler, signal ID: %d", code);

#ifdef USE_GLIB
    int nptrs;
    void *buffer[100];
    char **strings;

    nptrs = backtrace(buffer, sizeof(buffer)/sizeof(*buffer));
    strings = backtrace_symbols(buffer, nptrs);
    if (strings != NULL) {
        timespec tv;
        clock_gettime(CLOCK_BOOTTIME, &tv);
        uint64_t elapsedTime = (uint64_t)tv.tv_sec + (uint64_t)tv.tv_nsec/1000000000;
        for (int i = 0; i < nptrs; i++) {
            string s(strings[i]);
            mInstance->append(s, 0, elapsedTime);
        }
    }
#endif
    //Dump the log buffer to adb logcat
    mInstance->dumpToAdbLogcat();

    //Dump the log buffer to file
    time_t now = time(NULL);
    struct tm *curr_time = localtime(&now);
    char path[50];
    snprintf(path, 50, LOG_BUFFER_FILE_PATH "gpslog_%d%d%d-%d%d%d.log",
            (1900 + curr_time->tm_year), ( 1 + curr_time->tm_mon), curr_time->tm_mday,
            curr_time->tm_hour, curr_time->tm_min, curr_time->tm_sec);

    mInstance->dumpToLogFile(path);

    //Process won't be terminated if SIGUSR1 is recieved
    if (code != SIGUSR1) {
        mOriSigAction[code].sa_sigaction(code, si, sc);
    }
}

}

license: unknown


code:
/* Copyright (c) 2019 The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials provided
 *       with the distribution.
 *     * Neither the name of The Linux Foundation, nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#ifndef LOG_BUFFER_H
#define LOG_BUFFER_H

#include "SkipList.h"
#include "log_util.h"
#include <loc_cfg.h>
#include <loc_pla.h>
#include <string>
#include <sstream>
#include <ostream>
#include <fstream>
#include <time.h>
#include <mutex>
#include <signal.h>
#include <thread>
#include <functional>

//default error level time depth threshold,
#define TIME_DEPTH_THRESHOLD_MINIMAL_IN_SEC 60
//default maximum log buffer size
#define MAXIMUM_NUM_IN_LIST 50
//file path of dumped log buffer
#define LOG_BUFFER_FILE_PATH "/data/vendor/location/"

namespace loc_util {

class ConfigsInLevel{
public:
    uint32_t mTimeDepthThres;
    uint32_t mMaxNumThres;
    int mCurrentSize;

    ConfigsInLevel(uint32_t time, int num, int size):
        mTimeDepthThres(time), mMaxNumThres(num), mCurrentSize(size) {}
};

class LogBuffer {
private:
    static LogBuffer* mInstance;
    static struct sigaction mOriSigAction[NSIG];
    static struct sigaction mNewSigAction;
    static mutex sLock;

    SkipList<pair<uint64_t, string>> mLogList;
    vector<ConfigsInLevel> mConfigVec;
    mutex mLock;

    const vector<string> mLevelMap {"E", "W", "I", "D", "V"};

public:
    static LogBuffer* getInstance();
    void append(string& data, int level, uint64_t timestamp);
    void dump(std::function<void(stringstream&)> log, int level = -1);
    void dumpToAdbLogcat();
    void dumpToLogFile(string filePath);
    void flush();
private:
    LogBuffer();
    void registerSignalHandler();
    static void signalHandler(const int code, siginfo_t *const si, void *const sc);

};

}

#endif


code:
/* Copyright (c) 2011-2013, 2015, 2017, 2020 The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials provided
 *       with the distribution.
 *     * Neither the name of The Linux Foundation, nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
#define LOG_NDEBUG 0
#define LOG_TAG "LocSvc_MsgTask"

#include <unistd.h>
#include <MsgTask.h>
#include <msg_q.h>
#include <log_util.h>
#include <loc_log.h>
#include <loc_pla.h>

namespace loc_util {

class MTRunnable : public LocRunnable {
    const void* mQ;
public:
    inline MTRunnable(const void* q) : mQ(q) {}
    virtual ~MTRunnable();
    // Overrides of LocRunnable methods
    // This method will be repeated called until it returns false; or
    // until thread is stopped.
    virtual bool run() override;

    // The method to be run before thread loop (conditionally repeatedly)
    // calls run()
    virtual void prerun() override;

    // to interrupt the run() method and come out of that
    virtual void interrupt() override;
};

static void LocMsgDestroy(void* msg) {
    delete (LocMsg*)msg;
}

MsgTask::MsgTask(const char* threadName) :
    mQ(msg_q_init2()), mThread() {
    mThread.start(threadName, std::make_shared<MTRunnable>(mQ));
}

void MsgTask::sendMsg(const LocMsg* msg) const {
    if (msg && this) {
        msg_q_snd((void*)mQ, (void*)msg, LocMsgDestroy);
    } else {
        LOC_LOGE("%s: msg is %p and this is %p",
                 __func__, msg, this);
    }
}

void MsgTask::sendMsg(const std::function<void()> runnable) const {
    struct RunMsg : public LocMsg {
        const std::function<void()> mRunnable;
    public:
        inline RunMsg(const std::function<void()> runnable) : mRunnable(runnable) {}
        ~RunMsg() = default;
        inline virtual void proc() const override { mRunnable(); }
    };
    sendMsg(new RunMsg(runnable));
}

void MTRunnable::interrupt() {
    msg_q_unblock((void*)mQ);
}

void MTRunnable::prerun() {
    // make sure we do not run in background scheduling group
     set_sched_policy(gettid(), SP_FOREGROUND);
}

bool MTRunnable::run() {
    LocMsg* msg;
    msq_q_err_type result = msg_q_rcv((void*)mQ, (void **)&msg);
    if (eMSG_Q_SUCCESS != result) {
        LOC_LOGE("%s:%d] fail receiving msg: %s\n", __func__, __LINE__,
                 loc_get_msg_q_status(result));
        return false;
    }

    msg->log();
    // there is where each individual msg handling is invoked
    msg->proc();

    delete msg;

    return true;
}

MTRunnable::~MTRunnable() {
    msg_q_flush((void*)mQ);
    msg_q_destroy((void**)&mQ);
}

} // namespace loc_util


code:
/* Copyright (c) 2011-2013, 2015, 2020 The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials provided
 *       with the distribution.
 *     * Neither the name of The Linux Foundation, nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
#ifndef __MSG_TASK__
#define __MSG_TASK__

#include <functional>
#include <LocThread.h>

namespace loc_util {

struct LocMsg {
    inline LocMsg() {}
    inline virtual ~LocMsg() {}
    virtual void proc() const = 0;
    inline virtual void log() const {}
};

class MsgTask {
    const void* mQ;
    LocThread mThread;
public:
    ~MsgTask() = default;
    MsgTask(const char* threadName = NULL);
    void sendMsg(const LocMsg* msg) const;
    void sendMsg(const std::function<void()> runnable) const;
};

} //

#endif //__MSG_TASK__


code:
/* Copyright (c) 2019 The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials provided
 *       with the distribution.
 *     * Neither the name of The Linux Foundation, nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#ifndef LOC_SKIP_LIST_H
#define LOC_SKIP_LIST_H

#include <stdlib.h>
#include <list>
#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

namespace loc_util {

template <typename T,
         template<typename elem, typename Allocator = std::allocator<elem>> class container = list>
class SkipNode {
public:
    typedef typename container<SkipNode<T, container>>::iterator NodeIterator;

    int mLevel;
    T mData;
    NodeIterator mNextInLevel;

    SkipNode(int level, T& data): mLevel(level), mData(data) {}
};

template <typename T>
class SkipList {
    using NodeIterator = typename SkipNode<T>::NodeIterator;
private:
    list<SkipNode<T>> mMainList;
    vector<NodeIterator> mHeadVec;
    vector<NodeIterator> mTailVec;
public:
    SkipList(int totalLevels);
    void append(T& data, int level);
    void pop(int level);
    void pop();
    T front(int level);
    int size();
    void flush();
    list<pair<T, int>> dump();
    list<pair<T, int>> dump(int level);
};

template <typename T>
SkipList<T>::SkipList(int totalLevels): mHeadVec(totalLevels, mMainList.end()),
        mTailVec(totalLevels, mMainList.end()) {}

template <typename T>
void SkipList<T>::append(T& data, int level) {
    if ( level < 0 || level >= mHeadVec.size()) {
        return;
    }

    SkipNode<T> node(level, data);
    node.mNextInLevel = mMainList.end();
    mMainList.push_back(node);
    auto iter = --mMainList.end();
    if (mHeadVec[level] == mMainList.end()) {
        mHeadVec[level] = iter;
    } else {
        (*mTailVec[level]).mNextInLevel = iter;
    }
    mTailVec[level] = iter;
}

template <typename T>
void SkipList<T>::pop(int level) {
    if (mHeadVec[level] == mMainList.end()) {
        return;
    }

    if ((*mHeadVec[level]).mNextInLevel == mMainList.end()) {
        mTailVec[level] = mMainList.end();
    }

    auto tmp_iter = (*mHeadVec[level]).mNextInLevel;
    mMainList.erase(mHeadVec[level]);
    mHeadVec[level] = tmp_iter;
}

template <typename T>
void SkipList<T>::pop() {
    pop(mMainList.front().mLevel);
}

template <typename T>
T SkipList<T>::front(int level) {
    return (*mHeadVec[level]).mData;
}

template <typename T>
int SkipList<T>::size() {
    return mMainList.size();
}

template <typename T>
void SkipList<T>::flush() {
    mMainList.clear();
    for (int i = 0; i < mHeadVec.size(); i++) {
        mHeadVec[i] = mMainList.end();
        mTailVec[i] = mMainList.end();
    }
}

template <typename T>
list<pair<T, int>> SkipList<T>::dump() {
    list<pair<T, int>> li;
    for_each(mMainList.begin(), mMainList.end(), [&](SkipNode<T> &item) {
        li.push_back(make_pair(item.mData, item.mLevel));
    });
    return li;
}

template <typename T>
list<pair<T, int>> SkipList<T>::dump(int level) {
    list<pair<T, int>> li;
    auto head = mHeadVec[level];
    while (head != mMainList.end()) {
        li.push_back(make_pair((*head).mData, (*head).mLevel));
        head = (*head).mNextInLevel;
    }
    return li;
}

}

#endif


code:
/* Copyright (c) 2013-2017 The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials provided
 *       with the distribution.
 *     * Neither the name of The Linux Foundation nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef GPS_EXTENDED_H
#define GPS_EXTENDED_H

/**
 * @file
 * @brief C++ declarations for GPS types
 */

#include <gps_extended_c.h>
#if defined(USE_GLIB) || defined(OFF_TARGET)
#include <string.h>
#endif

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

struct LocPosMode
{
    LocPositionMode mode;
    LocGpsPositionRecurrence recurrence;
    uint32_t min_interval;
    uint32_t preferred_accuracy;
    uint32_t preferred_time;
    bool share_position;
    char credentials[14];
    char provider[8];
    GnssPowerMode powerMode;
    uint32_t timeBetweenMeasurements;
    LocPosMode(LocPositionMode m, LocGpsPositionRecurrence recr,
               uint32_t gap, uint32_t accu, uint32_t time,
               bool sp, const char* cred, const char* prov,
               GnssPowerMode pMode = GNSS_POWER_MODE_INVALID,
               uint32_t tbm = 0) :
        mode(m), recurrence(recr),
        min_interval(gap < GPS_MIN_POSSIBLE_FIX_INTERVAL_MS ?
                     GPS_MIN_POSSIBLE_FIX_INTERVAL_MS : gap),
        preferred_accuracy(accu), preferred_time(time),
        share_position(sp), powerMode(pMode),
        timeBetweenMeasurements(tbm) {
        memset(credentials, 0, sizeof(credentials));
        memset(provider, 0, sizeof(provider));
        if (NULL != cred) {
            memcpy(credentials, cred, sizeof(credentials)-1);
        }
        if (NULL != prov) {
            memcpy(provider, prov, sizeof(provider)-1);
        }
    }

    inline LocPosMode() :
        mode(LOC_POSITION_MODE_MS_BASED),
        recurrence(LOC_GPS_POSITION_RECURRENCE_PERIODIC),
        min_interval(GPS_DEFAULT_FIX_INTERVAL_MS),
        preferred_accuracy(50), preferred_time(120000),
        share_position(true), powerMode(GNSS_POWER_MODE_INVALID),
        timeBetweenMeasurements(GPS_DEFAULT_FIX_INTERVAL_MS) {
        memset(credentials, 0, sizeof(credentials));
        memset(provider, 0, sizeof(provider));
    }

    inline bool equals(const LocPosMode &anotherMode) const
    {
        return anotherMode.mode == mode &&
            anotherMode.recurrence == recurrence &&
            anotherMode.min_interval == min_interval &&
            anotherMode.preferred_accuracy == preferred_accuracy &&
            anotherMode.preferred_time == preferred_time &&
            anotherMode.powerMode == powerMode &&
            anotherMode.timeBetweenMeasurements == timeBetweenMeasurements &&
            !strncmp(anotherMode.credentials, credentials, sizeof(credentials)-1) &&
            !strncmp(anotherMode.provider, provider, sizeof(provider)-1);
    }

    void logv() const;
};

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* GPS_EXTENDED_H */