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

Commit b487b553 authored by Bookatz's avatar Bookatz
Browse files

statsd & statscompanion communication more robust

If statsd or statsdcompanion crashes, or if one loads
before the other, the other will be able to accomodate.

When statsd loads, it will attempt to tell statscompanion that it's
alive, and then get on to its business, while assuming that
statscompanion is not alive. Only when statscompanion tells statsd
that it is alive, statsd will then start to use it.

When statscompanion loads, it will attempt to tell statsd that it's
alive and then do nothing (since it has nothing to do). When statsd
tells statscompanion that statsd is alive, statscompanion will respond,
telling statsd that it is alive and, if that binder call returns, will
get to work.

This way, if statsd loads first, it can work unobstructed until
statscompanion informs statsd that it is alive, at which point they
shake hands and work. Conversely, if statscompanion loads first, it will
do nothing until statsd contacts it, at which point they will shake
hands and work.

Test: manual
Change-Id: I969ad47fb8060e27814d05ad37433a02711cfa6a
parent 1b0b114a
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -40,8 +40,8 @@ include $(CLEAR_VARS)
LOCAL_MODULE := statsd

LOCAL_SRC_FILES := \
    ../../core/java/android/os/IStatsManager.aidl \
    ../../core/java/android/os/IStatsCompanionService.aidl \
    ../../core/java/android/os/IStatsManager.aidl \
    src/StatsService.cpp \
    src/AnomalyMonitor.cpp \
    src/LogEntryPrinter.cpp \
@@ -119,6 +119,7 @@ LOCAL_C_INCLUDES += $(LOCAL_PATH)/src \
	STATSD_PROTO_INCLUDES

LOCAL_SRC_FILES := \
    ../../core/java/android/os/IStatsCompanionService.aidl \
    ../../core/java/android/os/IStatsManager.aidl \
    src/StatsService.cpp \
    tests/indexed_priority_queue_test.cpp \
+25 −34
Original line number Diff line number Diff line
@@ -19,10 +19,9 @@

#include <AnomalyMonitor.h>

#include <binder/IServiceManager.h>
#include <cutils/log.h>

namespace statsd {
using namespace android::os::statsd;

AnomalyMonitor::AnomalyMonitor(uint32_t minDiffToUpdateRegisteredAlarmTimeSec)
        : mRegisteredAlarmTimeSec(0),
@@ -32,7 +31,23 @@ AnomalyMonitor::AnomalyMonitor(uint32_t minDiffToUpdateRegisteredAlarmTimeSec)
AnomalyMonitor::~AnomalyMonitor() {
}

void AnomalyMonitor::setStatsCompanionService(sp<IStatsCompanionService> statsCompanionService) {
    std::lock_guard<std::mutex> lock(mLock);
    sp<IStatsCompanionService> tmpForLock = mStatsCompanionService;
    mStatsCompanionService = statsCompanionService;
    if (statsCompanionService == nullptr) {
        if (DEBUG) ALOGD("Erasing link to statsCompanionService");
        return;
    }
    if (DEBUG) ALOGD("Creating link to statsCompanionService");
    const sp<const AnomalyAlarm> top = mPq.top();
    if (top != nullptr) {
        updateRegisteredAlarmTime_l(top->timestampSec);
    }
}

void AnomalyMonitor::add(sp<const AnomalyAlarm> alarm) {
    std::lock_guard<std::mutex> lock(mLock);
    if (alarm == nullptr) {
        ALOGW("Asked to add a null alarm.");
        return;
@@ -42,70 +57,46 @@ void AnomalyMonitor::add(sp<const AnomalyAlarm> alarm) {
        ALOGW("Asked to add a 0-time alarm.");
        return;
    }
    std::lock_guard<std::mutex> lock(mLock);
    // TODO: Ensure that refractory period is respected.
    if (DEBUG) ALOGD("Adding alarm with time %u", alarm->timestampSec);
    mPq.push(alarm);
    if (mRegisteredAlarmTimeSec < 1 ||
            alarm->timestampSec + mMinUpdateTimeSec < mRegisteredAlarmTimeSec) {
        updateRegisteredAlarmTime(alarm->timestampSec);
        updateRegisteredAlarmTime_l(alarm->timestampSec);
    }
}

void AnomalyMonitor::remove(sp<const AnomalyAlarm> alarm) {
    std::lock_guard<std::mutex> lock(mLock);
    if (alarm == nullptr) {
        ALOGW("Asked to remove a null alarm.");
        return;
    }
    std::lock_guard<std::mutex> lock(mLock);
    if (DEBUG) ALOGD("Removing alarm with time %u", alarm->timestampSec);
    mPq.remove(alarm);
    if (mPq.empty()) {
        if (DEBUG) ALOGD("Queue is empty. Cancel any alarm.");
        mRegisteredAlarmTimeSec = 0;
        // TODO: Make this resistant to doing work when companion is not ready yet
        sp<IStatsCompanionService> statsCompanionService = getStatsCompanion_l();
        if (statsCompanionService != nullptr) {
            statsCompanionService->cancelAnomalyAlarm();
        if (mStatsCompanionService != nullptr) {
            mStatsCompanionService->cancelAnomalyAlarm();
        }
        return;
    }
    uint32_t soonestAlarmTimeSec = mPq.top()->timestampSec;
    if (DEBUG) ALOGD("Soonest alarm is %u", soonestAlarmTimeSec);
    if (soonestAlarmTimeSec > mRegisteredAlarmTimeSec + mMinUpdateTimeSec) {
        updateRegisteredAlarmTime(soonestAlarmTimeSec);
        updateRegisteredAlarmTime_l(soonestAlarmTimeSec);
    }
}

void AnomalyMonitor::updateRegisteredAlarmTime(uint32_t timestampSec) {
void AnomalyMonitor::updateRegisteredAlarmTime_l(uint32_t timestampSec) {
    if (DEBUG) ALOGD("Updating reg alarm time to %u", timestampSec);
    mRegisteredAlarmTimeSec = timestampSec;
    sp<IStatsCompanionService> statsCompanionService = getStatsCompanion_l();
    if (statsCompanionService != nullptr) {
        statsCompanionService->setAnomalyAlarm(secToMs(mRegisteredAlarmTimeSec));
    }
}

sp<IStatsCompanionService> AnomalyMonitor::getStatsCompanion_l() {
    if (mStatsCompanion != nullptr) {
        return mStatsCompanion;
    }
    // Get statscompanion service from service manager
    const sp<IServiceManager> sm(defaultServiceManager());
    if (sm != nullptr) {
        const String16 name("statscompanion");
        mStatsCompanion =
                interface_cast<IStatsCompanionService>(sm->checkService(name));
        if (mStatsCompanion == nullptr) {
            ALOGW("statscompanion service unavailable!");
            return nullptr;
    if (mStatsCompanionService != nullptr) {
        mStatsCompanionService->setAnomalyAlarm(secToMs(mRegisteredAlarmTimeSec));
    }
}
    return mStatsCompanion;
}

int64_t AnomalyMonitor::secToMs(uint32_t timeSec) {
    return ((int64_t) timeSec) * 1000;
}

}  // namespace statsd
 No newline at end of file
+17 −9
Original line number Diff line number Diff line
@@ -24,9 +24,11 @@
#include <queue>
#include <vector>

using namespace android::os;
using namespace android;
using namespace android::os;

namespace android {
namespace os {
namespace statsd {

/**
@@ -52,7 +54,7 @@ struct AnomalyAlarm : public RefBase {
/**
 * Manages alarms for Anomaly Detection.
 */
class AnomalyMonitor {
class AnomalyMonitor : public RefBase {
 public:
    /**
     * @param minDiffToUpdateRegisteredAlarmTimeSec If the soonest alarm differs
@@ -62,6 +64,14 @@ class AnomalyMonitor {
    AnomalyMonitor(uint32_t minDiffToUpdateRegisteredAlarmTimeSec);
    ~AnomalyMonitor();

    /**
     * Tells AnomalyMonitor what IStatsCompanionService to use and, if
     * applicable, immediately registers an existing alarm with it.
     * If nullptr, AnomalyMonitor will continue to add/remove alarms, but won't
     * update IStatsCompanionService (until such time as it is set non-null).
     */
    void setStatsCompanionService(sp<IStatsCompanionService> statsCompanionService);

    /**
     * Adds the given alarm (reference) to the queue.
     */
@@ -84,7 +94,6 @@ class AnomalyMonitor {
    }

 private:
    /** Lock for accessing/writing to mPq. */
    std::mutex mLock;

    /**
@@ -103,11 +112,11 @@ class AnomalyMonitor {
    /**
     * Binder interface for communicating with StatsCompanionService.
     */
    sp<IStatsCompanionService> mStatsCompanion;
    sp<IStatsCompanionService> mStatsCompanionService = nullptr;

    /**
     * Amount by which the soonest projected alarm must differ from
     * mRegisteredAlarmTimeSec before updateRegisteredAlarmTime is called.
     * mRegisteredAlarmTimeSec before updateRegisteredAlarmTime_l is called.
     */
    uint32_t mMinUpdateTimeSec;

@@ -115,15 +124,14 @@ class AnomalyMonitor {
     * Updates the alarm registered with StatsCompanionService to the given time.
     * Also correspondingly updates mRegisteredAlarmTimeSec.
     */
    void updateRegisteredAlarmTime(uint32_t timestampSec);

    /** Returns the StatsCompanionService. */
    sp<IStatsCompanionService> getStatsCompanion_l();
    void updateRegisteredAlarmTime_l(uint32_t timestampSec);

    /** Converts uint32 timestamp in seconds to a Java long in msec. */
    int64_t secToMs(uint32_t timeSec);
};

} // namespace statsd
} // namespace os
} // namespace android

#endif // ANOMALY_MONITOR_H
 No newline at end of file
+65 −4
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */

#define LOG_TAG "statsd"
#define DEBUG true

#include "StatsService.h"
#include "DropboxReader.h"
@@ -37,6 +38,7 @@ using android::os::statsd::StatsdConfig;

// ================================================================================
StatsService::StatsService(const sp<Looper>& handlerLooper)
        : mAnomalyMonitor(new AnomalyMonitor(2)) // TODO: Change this based on the config
{
    ALOGD("stats service constructed");
}
@@ -164,14 +166,14 @@ StatsService::doLoadConfig(FILE* in)
Status
StatsService::informAnomalyAlarmFired()
{
    ALOGD("StatsService::informAnomalyAlarmFired was called");
    if (DEBUG) ALOGD("StatsService::informAnomalyAlarmFired was called");

    if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
        return Status::fromExceptionCode(Status::EX_SECURITY,
                "Only system uid can call informAnomalyAlarmFired");
    }

    ALOGD("StatsService::informAnomalyAlarmFired succeeded");
    if (DEBUG) ALOGD("StatsService::informAnomalyAlarmFired succeeded");
    // TODO: check through all counters/timers and see if an anomaly has indeed occurred.

    return Status::ok();
@@ -180,14 +182,14 @@ StatsService::informAnomalyAlarmFired()
Status
StatsService::informPollAlarmFired()
{
    ALOGD("StatsService::informPollAlarmFired was called");
    if (DEBUG) ALOGD("StatsService::informPollAlarmFired was called");

    if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
        return Status::fromExceptionCode(Status::EX_SECURITY,
                "Only system uid can call informPollAlarmFired");
    }

    ALOGD("StatsService::informPollAlarmFired succeeded");
    if (DEBUG) ALOGD("StatsService::informPollAlarmFired succeeded");
    // TODO: determine what services to poll and poll (or ask StatsCompanionService to poll) them.

    return Status::ok();
@@ -204,6 +206,8 @@ StatsService::systemRunning()
    // When system_server is up and running, schedule the dropbox task to run.
    ALOGD("StatsService::systemRunning");

    sayHiToStatsCompanion();

    return Status::ok();
}

@@ -223,3 +227,60 @@ StatsService::printCmdHelp(FILE* out) {
    fprintf(out, "\t print-stats-log [tag_required] [timestamp_nsec_optional]\n");
    fprintf(out, "\t config\t Loads a new config from command-line (must be proto in wire-encoded format).\n");
}

void
StatsService::sayHiToStatsCompanion()
{
    // TODO: This method needs to be private. It is temporarily public and unsecured for testing purposes.
    sp<IStatsCompanionService> statsCompanion = getStatsCompanionService();
    if (statsCompanion != nullptr) {
        if (DEBUG) ALOGD("Telling statsCompanion that statsd is ready");
        statsCompanion->statsdReady();
    } else {
        if (DEBUG) ALOGD("Could not access statsCompanion");
    }
}

Status
StatsService::statsCompanionReady()
{
    if (DEBUG) ALOGD("StatsService::statsCompanionReady was called");

    if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
        return Status::fromExceptionCode(Status::EX_SECURITY,
                                         "Only system uid can call statsCompanionReady");
    }

    sp<IStatsCompanionService> statsCompanion = getStatsCompanionService();
    if (statsCompanion == nullptr) {
        return Status::fromExceptionCode(Status::EX_NULL_POINTER,
                                         "statscompanion unavailable despite it contacting statsd!");
    }
    if (DEBUG) ALOGD("StatsService::statsCompanionReady linking to statsCompanion.");
    IInterface::asBinder(statsCompanion)->linkToDeath(new StatsdDeathRecipient(mAnomalyMonitor));
    mAnomalyMonitor->setStatsCompanionService(statsCompanion);

    return Status::ok();
}

sp<IStatsCompanionService>
StatsService::getStatsCompanionService() {
    sp<IStatsCompanionService> statsCompanion = nullptr;
    // Get statscompanion service from service manager
    const sp<IServiceManager> sm(defaultServiceManager());
    if (sm != nullptr) {
        const String16 name("statscompanion");
        statsCompanion = interface_cast<IStatsCompanionService>(sm->checkService(name));
        if (statsCompanion == nullptr) {
            ALOGW("statscompanion service unavailable!");
            return nullptr;
        }
    }
    return statsCompanion;
}

void
StatsdDeathRecipient::binderDied(const wp<IBinder>& who) {
    ALOGW("statscompanion service died");
    mAnmlyMntr->setStatsCompanionService(nullptr);
}
 No newline at end of file
+33 −0
Original line number Diff line number Diff line
@@ -17,9 +17,11 @@
#ifndef STATS_SERVICE_H
#define STATS_SERVICE_H

#include "AnomalyMonitor.h"
#include "StatsLogProcessor.h"

#include <android/os/BnStatsManager.h>
#include <android/os/IStatsCompanionService.h>
#include <binder/IResultReceiver.h>
#include <binder/IShellCallback.h>
#include <frameworks/base/cmds/statsd/src/statsd_config.pb.h>
@@ -32,7 +34,9 @@ using namespace android;
using namespace android::base;
using namespace android::binder;
using namespace android::os;
using namespace android::os::statsd;
using namespace std;

using android::os::statsd::StatsdConfig;

// ================================================================================
@@ -49,17 +53,46 @@ public:

    virtual Status systemRunning();

    // Inform statsd that statsCompanion is ready.
    virtual Status statsCompanionReady();

    virtual Status informAnomalyAlarmFired();

    virtual Status informPollAlarmFired();

    virtual status_t setProcessor(const sp<StatsLogProcessor>& main_processor);

    // TODO: public for testing since statsd doesn't run when system starts. Change to private later.
    /** Inform statsCompanion that statsd is ready. */
    virtual void sayHiToStatsCompanion();

private:
    sp<StatsLogProcessor> m_processor; // Reference to the processor for updating configs.

    status_t doPrintStatsLog(FILE* out, const Vector<String8>& args);

    void printCmdHelp(FILE* out);

    status_t doLoadConfig(FILE* in);

    const sp<AnomalyMonitor> mAnomalyMonitor;  // TODO: Move this to a more logical file/class

 private:
    /** Fetches the StatsCompanionService. */
    sp<IStatsCompanionService> getStatsCompanionService();
};

// --- StatsdDeathRecipient ---
class StatsdDeathRecipient : public IBinder::DeathRecipient {
public:
    StatsdDeathRecipient(sp<AnomalyMonitor> anomalyMonitor)
            : mAnmlyMntr(anomalyMonitor) {
    }

    virtual void binderDied(const wp<IBinder>& who);

private:
    const sp<AnomalyMonitor> mAnmlyMntr;
};

#endif // STATS_SERVICE_H
Loading