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

Commit 5dcbc6c0 authored by Joe Onorato's avatar Joe Onorato
Browse files

Add statsd.

It doesn't start yet by default. When you start it manually, it sets
itself up as a binder system service and starts a thread to read the
event log.

Test: Run statsd, observe output. also run stats_test
Change-Id: If435d6a80fef3c1d957aedb61699bf5e9aae7e56
parent 6ae44280
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -270,6 +270,7 @@ LOCAL_SRC_FILES += \
	core/java/android/os/IRecoverySystemProgressListener.aidl \
	core/java/android/os/IRemoteCallback.aidl \
	core/java/android/os/ISchedulingPolicyService.aidl \
	core/java/android/os/IStatsManager.aidl \
	core/java/android/os/IThermalEventListener.aidl \
	core/java/android/os/IThermalService.aidl \
	core/java/android/os/IUpdateLock.aidl \

cmds/statsd/Android.mk

0 → 100644
+106 −0
Original line number Diff line number Diff line
# Copyright (C) 2017 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.

LOCAL_PATH:= $(call my-dir)

# =========
# statsd
# =========

include $(CLEAR_VARS)

LOCAL_MODULE := statsd

LOCAL_SRC_FILES := \
    ../../core/java/android/os/IStatsManager.aidl \
    src/StatsService.cpp \
    src/LogEntryPrinter.cpp \
    src/LogReader.cpp \
    src/main.cpp

LOCAL_CFLAGS += \
    -Wall \
    -Werror \
    -Wno-missing-field-initializers \
    -Wno-unused-variable \
    -Wno-unused-function \
    -Wno-unused-parameter

ifeq (debug,)
    LOCAL_CFLAGS += \
            -g -O0
else
    # optimize for size (protobuf glop can get big)
    LOCAL_CFLAGS += \
            -Os
endif

LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/../../core/java
LOCAL_C_INCLUDES += $(LOCAL_PATH)/src

LOCAL_SHARED_LIBRARIES := \
        libbase \
        libbinder \
        libcutils \
        libincident \
        liblog \
        libselinux \
        libutils

LOCAL_MODULE_CLASS := EXECUTABLES

#LOCAL_INIT_RC := statsd.rc

include $(BUILD_EXECUTABLE)

# ==============
# statsd_test
# ==============

include $(CLEAR_VARS)

LOCAL_MODULE := statsd_test
LOCAL_COMPATIBILITY_SUITE := device-tests
LOCAL_MODULE_TAGS := tests

LOCAL_CFLAGS += \
    -Wall \
    -Werror \
    -Wno-missing-field-initializers \
    -Wno-unused-variable \
    -Wno-unused-function \
    -Wno-unused-parameter

LOCAL_C_INCLUDES += $(LOCAL_PATH)/src

LOCAL_SRC_FILES := \
    ../../core/java/android/os/IStatsManager.aidl \
    src/StatsService.cpp \
    src/LogEntryPrinter.cpp \
    src/LogReader.cpp \
    tests/LogReader_test.cpp \

LOCAL_STATIC_LIBRARIES := \
    libgmock \

LOCAL_SHARED_LIBRARIES := \
    libbase \
    libbinder \
    libcutils \
    liblog \
    libselinux \
    libutils

include $(BUILD_NATIVE_TEST)
+61 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 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.
 */

#include <LogEntryPrinter.h>

#include <log/event_tag_map.h>
#include <log/logprint.h>
#include <utils/Errors.h>

using namespace android;

LogEntryPrinter::LogEntryPrinter(int out)
    :m_out(out)
{
    // Initialize the EventTagMap, which is how we know the names of the numeric event tags.
    // If this fails, we can't print well, but something will print.
    m_tags = android_openEventTagMap(NULL);

    // Printing format
    m_format = android_log_format_new();
    android_log_setPrintFormat(m_format, FORMAT_THREADTIME);
}

LogEntryPrinter::~LogEntryPrinter()
{
    if (m_tags != NULL) {
        android_closeEventTagMap(m_tags);
    }
    android_log_format_free(m_format);
}

void
LogEntryPrinter::OnLogEvent(const log_msg& msg)
{
    status_t err;
    AndroidLogEntry entry;
    char buf[1024];

    err = android_log_processBinaryLogBuffer(&(const_cast<log_msg*>(&msg)->entry_v1),
                &entry, m_tags, buf, sizeof(buf));
    if (err == NO_ERROR) {
        android_log_printLogLine(m_format, m_out, &entry);
    } else {
        printf("log entry: %s\n", buf);
        fflush(stdout);
    }
}
+54 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 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 LOG_ENTRY_PRINTER_H
#define LOG_ENTRY_PRINTER_H

#include "LogReader.h"

#include <log/logprint.h>

#include <stdio.h>

/**
 * Decodes the log entry and prints it to the supplied file descriptor.
 */
class LogEntryPrinter : public LogListener
{
public:
    LogEntryPrinter(int out);
    virtual ~LogEntryPrinter();

    virtual void OnLogEvent(const log_msg& msg);

private:
    /**
     * Where to write to.
     */
    int m_out;

    /**
     * Numeric to string tag name mapping.
     */
    EventTagMap* m_tags;

    /**
     * Pretty printing format.
     */
    AndroidLogFormat* m_format;
};

#endif // LOG_ENTRY_PRINTER_H
+143 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 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.
 */

#include "LogReader.h"

#include <log/log_read.h>

#include <utils/Errors.h>

#include <time.h>
#include <unistd.h>

using namespace android;
using namespace std;

#define SNOOZE_INITIAL_MS 100
#define SNOOZE_MAX_MS (10 * 60 * 1000) // Ten minutes


// ================================================================================
LogListener::LogListener()
{
}

LogListener::~LogListener()
{
}


// ================================================================================
LogReader::LogReader()
{
}

LogReader::~LogReader()
{
}

void
LogReader::AddListener(const sp<LogListener>& listener)
{
    m_listeners.push_back(listener);
}

void
LogReader::Run()
{
    int nextSnoozeMs = SNOOZE_INITIAL_MS;

    // In an ideal world, this outer loop will only ever run one iteration, but it
    // exists to handle crashes in logd.  The inner loop inside connect_and_read()
    // reads from logd forever, but if that read fails, we fall out to the outer
    // loop, do the backoff (resetting the backoff timeout if we successfully read
    // something), and then try again.
    while (true) {
        // Connect and read
        int lineCount = connect_and_read();

        // Figure out how long to sleep.
        if (lineCount > 0) {
            // If we managed to read at least one line, reset the backoff
            nextSnoozeMs = SNOOZE_INITIAL_MS;
        } else {
            // Otherwise, expontial backoff
            nextSnoozeMs *= 1.5f;
            if (nextSnoozeMs > 10 * 60 * 1000) {
                // Don't wait for toooo long.
                nextSnoozeMs = SNOOZE_MAX_MS;
            }
        }

        // Sleep
        timespec ts;
        timespec rem;
        ts.tv_sec = nextSnoozeMs / 1000;
        ts.tv_nsec = (nextSnoozeMs % 1000) * 1000000L;
        while (nanosleep(&ts, &rem) == -1) {
            if (errno == EINTR) {
                ts = rem;
            }
            // other errors are basically impossible
        }
    }
}

int
LogReader::connect_and_read()
{
    int lineCount = 0;
    status_t err;
    logger_list* loggers;
    logger* eventLogger;

    // Prepare the logging context
    loggers = android_logger_list_alloc(ANDROID_LOG_RDONLY,
            /* don't stop after N lines */ 0,
            /* no pid restriction */ 0);

    // Open the buffer(s)
    eventLogger = android_logger_open(loggers, LOG_ID_EVENTS);

    // Read forever
    if (eventLogger) {
        while (true) {
            log_msg msg;

            // Read a message
            err = android_logger_list_read(loggers, &msg);
            if (err < 0) {
                fprintf(stderr, "logcat read failure: %s\n", strerror(err));
                break;
            }

            // Record that we read one (used above to know how to snooze).
            lineCount++;

            // Call the listeners
            for (vector<sp<LogListener> >::iterator it = m_listeners.begin();
                    it != m_listeners.end(); it++) {
                (*it)->OnLogEvent(msg);
            }
        }
    }

    // Free the logger list and close the individual loggers
    android_logger_list_free(loggers);

    return lineCount;
}
Loading