Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 98a6db5c authored by Mark Salyzyn's avatar Mark Salyzyn Committed by Gerrit Code Review
Browse files

Merge changes I69e6489d,Ic17d52a7

* changes:
  liblog: add android_lookupEventTagNum
  liblog: add /dev/event-log-tags for Tag Map
parents 1cd4102a c9e5f371
Loading
Loading
Loading
Loading
+311 −68
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -26,15 +27,63 @@

#include <experimental/string_view>
#include <functional>
#include <string>
#include <unordered_map>

#include <log/event_tag_map.h>
#include <utils/FastStrcmp.h>
#include <utils/RWLock.h>
#include <private/android_logger.h>

#include "log_portability.h"
#include "logd_reader.h"

#define OUT_TAG "EventTagMap"

typedef std::experimental::string_view MapString;
class MapString {
private:
    const std::string* alloc; // HAS-AN
    const std::experimental::string_view str; // HAS-A

public:
    operator const std::experimental::string_view() const { return str; }

    const char* data() const { return str.data(); }
    size_t length() const { return str.length(); }

    bool operator== (const MapString& rval) const {
        if (length() != rval.length()) return false;
        if (length() == 0) return true;
        return fastcmp<strncmp>(data(), rval.data(), length()) == 0;
    }
    bool operator!= (const MapString& rval) const {
        return !(*this == rval);
    }

    MapString(const char* str, size_t len) : alloc(NULL), str(str, len) { }
    explicit MapString(const std::string& str) :
            alloc(new std::string(str)),
            str(alloc->data(), alloc->length()) { }
    MapString(MapString &&rval) :
            alloc(rval.alloc),
            str(rval.data(), rval.length()) {
        rval.alloc = NULL;
    }
    explicit MapString(const MapString &rval) :
            alloc(rval.alloc ? new std::string(*rval.alloc) : NULL),
            str(alloc ? alloc->data() : rval.data(), rval.length()) { }

    ~MapString() { if (alloc) delete alloc; }
};

// Hash for MapString
template <> struct std::hash<MapString>
        : public std::unary_function<const MapString&, size_t> {
    size_t operator()(const MapString& __t) const noexcept {
        if (!__t.length()) return 0;
        return std::hash<std::experimental::string_view>()(std::experimental::string_view(__t));
    }
};

typedef std::pair<MapString, MapString> TagFmt;

@@ -53,36 +102,54 @@ template <> struct std::hash<TagFmt>

// Map
struct EventTagMap {
#   define NUM_MAPS 2
    // memory-mapped source file; we get strings from here
    void*  mapAddr;
    size_t mapLen;
    void*  mapAddr[NUM_MAPS];
    size_t mapLen[NUM_MAPS];

private:
    std::unordered_map<uint32_t, TagFmt> Idx2TagFmt;
    std::unordered_map<TagFmt, uint32_t> TagFmt2Idx;
    std::unordered_map<MapString, uint32_t> Tag2Idx;
    // protect unordered sets
    android::RWLock rwlock;

public:
    EventTagMap() : mapAddr(NULL), mapLen(0) { }
    EventTagMap() {
        memset(mapAddr, 0, sizeof(mapAddr));
        memset(mapLen, 0, sizeof(mapLen));
    }

    ~EventTagMap() {
        Idx2TagFmt.clear();
        if (mapAddr) {
            munmap(mapAddr, mapLen);
            mapAddr = 0;
        TagFmt2Idx.clear();
        Tag2Idx.clear();
        for (size_t which = 0; which < NUM_MAPS; ++which) {
            if (mapAddr[which]) {
                munmap(mapAddr[which], mapLen[which]);
                mapAddr[which] = 0;
            }
        }
    }

    bool emplaceUnique(uint32_t tag, const TagFmt& tagfmt, bool verbose = false);
    const TagFmt* find(uint32_t tag) const;
    int find(TagFmt&& tagfmt) const;
    int find(MapString&& tag) const;
};

bool EventTagMap::emplaceUnique(uint32_t tag, const TagFmt& tagfmt, bool verbose) {
    bool ret = true;
    static const char errorFormat[] = OUT_TAG ": duplicate tag entries %" PRIu32
                                      ":%.*s:%.*s and %" PRIu32
                                      ":%.*s:%.*s)\n";
    android::RWLock::AutoWLock writeLock(rwlock);
    {
        std::unordered_map<uint32_t, TagFmt>::const_iterator it;
        it = Idx2TagFmt.find(tag);
        if (it != Idx2TagFmt.end()) {
            if (verbose) {
            fprintf(stderr,
                    OUT_TAG ": duplicate tag entries %" PRIu32
                        ":%.*s:%.*s and %" PRIu32 ":%.*s:%.*s)\n",
                fprintf(stderr, errorFormat,
                        it->first,
                        (int)it->second.first.length(), it->second.first.data(),
                        (int)it->second.second.length(), it->second.second.data(),
@@ -90,20 +157,70 @@ bool EventTagMap::emplaceUnique(uint32_t tag, const TagFmt& tagfmt, bool verbose
                        (int)tagfmt.first.length(), tagfmt.first.data(),
                        (int)tagfmt.second.length(), tagfmt.second.data());
            }
        return false;
            ret = false;
        } else {
            Idx2TagFmt.emplace(std::make_pair(tag, tagfmt));
        }
    }

    Idx2TagFmt.emplace(std::make_pair(tag, tagfmt));
    return true;
    {
        std::unordered_map<TagFmt, uint32_t>::const_iterator it;
        it = TagFmt2Idx.find(tagfmt);
        if (it != TagFmt2Idx.end()) {
            if (verbose) {
                fprintf(stderr, errorFormat,
                        it->second,
                        (int)it->first.first.length(), it->first.first.data(),
                        (int)it->first.second.length(), it->first.second.data(),
                        tag,
                        (int)tagfmt.first.length(), tagfmt.first.data(),
                        (int)tagfmt.second.length(), tagfmt.second.data());
            }
            ret = false;
        } else {
            TagFmt2Idx.emplace(std::make_pair(tagfmt, tag));
        }
    }

    {
        std::unordered_map<MapString, uint32_t>::const_iterator it;
        it = Tag2Idx.find(tagfmt.first);
        if (!tagfmt.second.length() && (it != Tag2Idx.end())) {
            Tag2Idx.erase(it);
            it = Tag2Idx.end();
        }
        if (it == Tag2Idx.end()) {
            Tag2Idx.emplace(std::make_pair(tagfmt.first, tag));
        }
    }

    return ret;
}

const TagFmt* EventTagMap::find(uint32_t tag) const {
    std::unordered_map<uint32_t, TagFmt>::const_iterator it;
    android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
    it = Idx2TagFmt.find(tag);
    if (it == Idx2TagFmt.end()) return NULL;
    return &(it->second);
}

int EventTagMap::find(TagFmt&& tagfmt) const {
    std::unordered_map<TagFmt, uint32_t>::const_iterator it;
    android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
    it = TagFmt2Idx.find(std::move(tagfmt));
    if (it == TagFmt2Idx.end()) return -1;
    return it->second;
}

int EventTagMap::find(MapString&& tag) const {
    std::unordered_map<MapString, uint32_t>::const_iterator it;
    android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
    it = Tag2Idx.find(std::move(tag));
    if (it == Tag2Idx.end()) return -1;
    return it->second;
}

// Scan one tag line.
//
// "*pData" should be pointing to the first digit in the tag number.  On
@@ -157,6 +274,19 @@ static int scanTagLine(EventTagMap* map, char** pData, int lineNum) {
        fmtLen = cp - fmt;
    }

    // KISS Only report identicals if they are global
    // Ideally we want to check if there are identicals
    // recorded for the same uid, but recording that
    // unused detail in our database is too burdensome.
    bool verbose = true;
    while ((*cp != '#') && (*cp != '\n')) ++cp;
    if (*cp == '#') {
        do {
            ++cp;
        } while (isspace(*cp) && (*cp != '\n'));
        verbose = !!fastcmp<strncmp>(cp, "uid=", strlen("uid="));
    }

    while (*cp != '\n') ++cp;
#ifdef DEBUG
    fprintf(stderr, "%d: %p: %.*s\n", lineNum, tag, (int)(cp - *pData), *pData);
@@ -164,24 +294,33 @@ static int scanTagLine(EventTagMap* map, char** pData, int lineNum) {
    *pData = cp;

    if (map->emplaceUnique(tagIndex, TagFmt(std::make_pair(
            MapString(tag, tagLen), MapString(fmt, fmtLen))), true)) {
            MapString(tag, tagLen), MapString(fmt, fmtLen))), verbose)) {
        return 0;
    }
    errno = EMLINK;
    return -1;
}

static const char* eventTagFiles[NUM_MAPS] = {
    EVENT_TAG_MAP_FILE,
    "/dev/event-log-tags",
};

// Parse the tags out of the file.
static int parseMapLines(EventTagMap* map) {
    char* cp = static_cast<char*>(map->mapAddr);
    size_t len = map->mapLen;
static int parseMapLines(EventTagMap* map, size_t which) {
    char* cp = static_cast<char*>(map->mapAddr[which]);
    size_t len = map->mapLen[which];
    char* endp = cp + len;

    // insist on EOL at EOF; simplifies parsing and null-termination
    if (!len || (*(endp - 1) != '\n')) {
#ifdef DEBUG
        fprintf(stderr, OUT_TAG ": map file missing EOL on last line\n");
        fprintf(stderr, OUT_TAG ": map file %zu[%zu] missing EOL on last line\n",
                which, len);
#endif
        if (which) { // do not propagate errors for other files
            return 0;
        }
        errno = EINVAL;
        return -1;
    }
@@ -199,8 +338,10 @@ static int parseMapLines(EventTagMap* map) {
            } else if (isdigit(*cp)) {
                // looks like a tag; scan it out
                if (scanTagLine(map, &cp, lineNum) != 0) {
                    if (!which || (errno != EMLINK)) {
                        return -1;
                    }
                }
                lineNum++;      // we eat the '\n'
                // leave lineStart==true
            } else if (isspace(*cp)) {
@@ -226,57 +367,87 @@ static int parseMapLines(EventTagMap* map) {
// We create a private mapping because we want to terminate the log tag
// strings with '\0'.
LIBLOG_ABI_PUBLIC EventTagMap* android_openEventTagMap(const char* fileName) {
    int save_errno;
    EventTagMap* newTagMap;
    off_t end[NUM_MAPS];
    int save_errno, fd[NUM_MAPS];
    size_t which;

    memset(fd, -1, sizeof(fd));
    memset(end, 0, sizeof(end));

    const char* tagfile = fileName ? fileName : EVENT_TAG_MAP_FILE;
    int fd = open(tagfile, O_RDONLY | O_CLOEXEC);
    if (fd < 0) {
    for (which = 0; which < NUM_MAPS; ++which) {
        const char* tagfile = fileName ? fileName : eventTagFiles[which];

        fd[which] = open(tagfile, O_RDONLY | O_CLOEXEC);
        if (fd[which] < 0) {
            if (!which) {
                save_errno = errno;
                fprintf(stderr, OUT_TAG ": unable to open map '%s': %s\n",
                        tagfile, strerror(save_errno));
        errno = save_errno;
        return NULL;
                goto fail_errno;
            }
    off_t end = lseek(fd, 0L, SEEK_END);
            continue;
        }
        end[which] = lseek(fd[which], 0L, SEEK_END);
        save_errno = errno;
    (void)lseek(fd, 0L, SEEK_SET);
    if (end < 0) {
        (void)lseek(fd[which], 0L, SEEK_SET);
        if (!which && (end[0] < 0)) {
            fprintf(stderr, OUT_TAG ": unable to seek map '%s' %s\n",
                    tagfile, strerror(save_errno));
        close(fd);
        errno = save_errno;
        return NULL;
            goto fail_close;
        }
        if (fileName) break; // Only allow one as specified
    }

    EventTagMap* newTagMap = new EventTagMap;
    newTagMap = new EventTagMap;
    if (newTagMap == NULL) {
        save_errno = errno;
        close(fd);
        errno = save_errno;
        return NULL;
        goto fail_close;
    }

    newTagMap->mapAddr = mmap(NULL, end, PROT_READ | PROT_WRITE,
                              MAP_PRIVATE, fd, 0);
    for (which = 0; which < NUM_MAPS; ++which) {
        if (fd[which] >= 0) {
            newTagMap->mapAddr[which] = mmap(NULL, end[which],
                                             which ?
                                                 PROT_READ :
                                                 PROT_READ | PROT_WRITE,
                                             which ?
                                                 MAP_SHARED :
                                                 MAP_PRIVATE,
                                             fd[which], 0);
            save_errno = errno;
    close(fd);
    fd = -1;
    if ((newTagMap->mapAddr == MAP_FAILED) || (newTagMap->mapAddr == NULL)) {
            close(fd[which]);
            fd[which] = -1;
            if ((newTagMap->mapAddr[which] != MAP_FAILED) &&
                (newTagMap->mapAddr[which] != NULL)) {
                newTagMap->mapLen[which] = end[which];
            } else if (!which) {
                const char* tagfile = fileName ? fileName : eventTagFiles[which];

                fprintf(stderr, OUT_TAG ": mmap(%s) failed: %s\n",
                        tagfile, strerror(save_errno));
        delete newTagMap;
        errno = save_errno;
        return NULL;
                goto fail_unmap;
            }
        }
    }

    newTagMap->mapLen = end;

    if (parseMapLines(newTagMap) != 0) {
    for (which = 0; which < NUM_MAPS; ++which) {
        if (parseMapLines(newTagMap, which) != 0) {
            delete newTagMap;
            return NULL;
        }
    }

    return newTagMap;

fail_unmap:
    save_errno = EINVAL;
    delete newTagMap;
fail_close:
    for (which = 0; which < NUM_MAPS; ++which) close(fd[which]);
fail_errno:
    errno = save_errno;
    return NULL;
}

// Close the map.
@@ -320,3 +491,75 @@ LIBLOG_ABI_PUBLIC const char* android_lookupEventTag(const EventTagMap* map,
    if (*cp) *cp = '\0'; // Trigger copy on write :-( and why deprecated.
    return tagStr;
}

// Look up tagname, generate one if necessary, and return a tag
LIBLOG_ABI_PUBLIC int android_lookupEventTagNum(EventTagMap* map,
                                                const char* tagname,
                                                const char* format,
                                                int prio) {
    size_t len = strlen(tagname);
    if (!len) {
        errno = EINVAL;
        return -1;
    }

    if ((prio != ANDROID_LOG_UNKNOWN) && (prio < ANDROID_LOG_SILENT) &&
            !__android_log_is_loggable_len(prio, tagname, len,
                                           __android_log_is_debuggable() ?
                                             ANDROID_LOG_VERBOSE :
                                             ANDROID_LOG_DEBUG)) {
        errno = EPERM;
        return -1;
    }

    if (!format) format="";
    ssize_t fmtLen = strlen(format);
    int ret = map->find(TagFmt(std::make_pair(MapString(tagname, len),
                                              MapString(format, fmtLen))));
    if (ret != -1) return ret;

    // call event tag service to arrange for a new tag
    char *buf = NULL;
    // Can not use android::base::StringPrintf, asprintf + free instead.
    static const char command_template[] = "getEventTag name=%s format=\"%s\"";
    ret = asprintf(&buf, command_template, tagname, format);
    if (ret > 0) {
        // Add some buffer margin for an estimate of the full return content.
        char *cp;
        size_t size = ret - strlen(command_template) +
            strlen("65535\n4294967295\t?\t\t\t?\t# uid=32767\n\n\f?success?");
        if (size > (size_t)ret) {
            cp = static_cast<char*>(realloc(buf, size));
            if (cp) {
                buf = cp;
            } else {
                size = ret;
            }
        } else {
            size = ret;
        }
        // Ask event log tag service for an allocation
        if (__send_log_msg(buf, size) >= 0) {
            buf[size - 1] = '\0';
            unsigned long val = strtoul(buf, &cp, 10); // return size
            if ((buf != cp) && (val > 0) && (*cp == '\n')) { // truncation OK
                val = strtoul(cp + 1, &cp, 10); // allocated tag number
                if ((val > 0) && (val < UINT32_MAX) && (*cp == '\t')) {
                    free(buf);
                    ret = val;
                    // cache
                    map->emplaceUnique(ret, TagFmt(std::make_pair(
                            MapString(std::string(tagname, len)),
                            MapString(std::string(format, fmtLen)))));
                    return ret;
                }
            }
        }
        free(buf);
    }

    // Hail Mary
    ret = map->find(MapString(tagname, len));
    if (ret == -1) errno = ESRCH;
    return ret;
}
+6 −0
Original line number Diff line number Diff line
@@ -715,6 +715,12 @@ LIBLOG_HIDDEN ssize_t fakeLogWritev(int fd,
    return redirectWritev(fd, vector, count);
}

LIBLOG_HIDDEN ssize_t __send_log_msg(char *buf __unused,
                                     size_t buf_size __unused)
{
    return -ENODEV;
}

LIBLOG_ABI_PUBLIC int __android_log_is_loggable(int prio,
                                                const char *tag __unused,
                                                int def)
+6 −0
Original line number Diff line number Diff line
@@ -58,6 +58,12 @@ const char* android_lookupEventTag_len(const EventTagMap* map,
const char* android_lookupEventFormat_len(const EventTagMap* map,
                                          size_t* len, unsigned int tag);

/*
 * Look up tagname, generate one if necessary, and return a tag
 */
int android_lookupEventTagNum(EventTagMap* map, const char* tagname,
                              const char* format, int prio);

#ifdef __cplusplus
}
#endif
+6 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@

#include "config_read.h"
#include "log_portability.h"
#include "logd_reader.h"
#include "logger.h"

/* branchless on many architectures. */
@@ -324,6 +325,11 @@ done:
    return ret;
}

LIBLOG_HIDDEN ssize_t __send_log_msg(char *buf, size_t buf_size)
{
    return send_log_msg(NULL, NULL, buf, buf_size);
}

static int check_log_success(char *buf, ssize_t ret)
{
    if (ret < 0) {

liblog/logd_reader.h

0 → 100644
+30 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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.
 */

#ifndef _LIBLOG_LOGD_READER_H__
#define _LIBLOG_LOGD_READER_H__

#include <unistd.h>

#include "log_portability.h"

__BEGIN_DECLS

LIBLOG_HIDDEN ssize_t __send_log_msg(char *buf, size_t buf_size);

__END_DECLS

#endif /* _LIBLOG_LOGD_READER_H__ */
Loading