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

Commit c697797d authored by Bookatz's avatar Bookatz
Browse files

Statsd broadcast subscriber

Allows a uid that uploads a statsd config to additionally
register a BroadcastSubscriber with statsd. If statsd
detects an anomaly (according to the config's Alert),
statsd can inform a BroadcastSubscriber provided in the config.
The config uses a subscriberId (just an int) to identify the
BroadcastSubscriber. It then uses StatsManager.setBroadcastSubscriber
to associate that subscriberId with a given PendingIntent.
Then, when the anomaly is detected, statsd sends a broadcast
using that PendingIntent, alerting whoever was specified by
the config/setBroadcastSubscriber.

Bug: 70356901
Test: cts-tradefed run cts-dev -m CtsStatsdHostTestCases -t android.cts.statsd.alert.BroadcastSubscriberTests
Change-Id: I4d9ea9a6c8a85e61fadfd99c1513c55abbadd5e9
parent 96c73a3c
Loading
Loading
Loading
Loading
+34 −10
Original line number Diff line number Diff line
@@ -354,6 +354,19 @@ package android.app {
    method public org.json.JSONObject toJson() throws org.json.JSONException;
  }

  public final class StatsManager {
    method public boolean addConfiguration(long, byte[], java.lang.String, java.lang.String);
    method public byte[] getData(long);
    method public byte[] getMetadata();
    method public boolean removeConfiguration(long);
    method public boolean setBroadcastSubscriber(long, long, android.app.PendingIntent);
    field public static final java.lang.String EXTRA_STATS_CONFIG_KEY = "android.app.extra.STATS_CONFIG_KEY";
    field public static final java.lang.String EXTRA_STATS_CONFIG_UID = "android.app.extra.STATS_CONFIG_UID";
    field public static final java.lang.String EXTRA_STATS_DIMENSIONS_VALUE = "android.app.extra.STATS_DIMENSIONS_VALUE";
    field public static final java.lang.String EXTRA_STATS_SUBSCRIPTION_ID = "android.app.extra.STATS_SUBSCRIPTION_ID";
    field public static final java.lang.String EXTRA_STATS_SUBSCRIPTION_RULE_ID = "android.app.extra.STATS_SUBSCRIPTION_RULE_ID";
  }

  public class VrManager {
    method public void setAndBindVrCompositor(android.content.ComponentName);
    method public void setPersistentVrModeEnabled(boolean);
@@ -3538,6 +3551,27 @@ package android.os {
    method public abstract void onResult(android.os.Bundle);
  }

  public final class StatsDimensionsValue implements android.os.Parcelable {
    method public int describeContents();
    method public boolean getBooleanValue();
    method public int getField();
    method public float getFloatValue();
    method public int getIntValue();
    method public long getLongValue();
    method public java.lang.String getStringValue();
    method public java.util.List<android.os.StatsDimensionsValue> getTupleValueList();
    method public int getValueType();
    method public boolean isValueType(int);
    method public void writeToParcel(android.os.Parcel, int);
    field public static final int BOOLEAN_VALUE_TYPE = 5; // 0x5
    field public static final android.os.Parcelable.Creator<android.os.StatsDimensionsValue> CREATOR;
    field public static final int FLOAT_VALUE_TYPE = 6; // 0x6
    field public static final int INT_VALUE_TYPE = 3; // 0x3
    field public static final int LONG_VALUE_TYPE = 4; // 0x4
    field public static final int STRING_VALUE_TYPE = 2; // 0x2
    field public static final int TUPLE_VALUE_TYPE = 7; // 0x7
  }

  public class SystemProperties {
    method public static java.lang.String get(java.lang.String);
    method public static java.lang.String get(java.lang.String, java.lang.String);
@@ -4900,16 +4934,6 @@ package android.util {
    method public int getUid();
  }

  public final class StatsManager {
    method public boolean addConfiguration(java.lang.String, byte[], java.lang.String, java.lang.String);
    method public boolean addConfiguration(long, byte[], java.lang.String, java.lang.String);
    method public byte[] getData(java.lang.String);
    method public byte[] getData(long);
    method public byte[] getMetadata();
    method public boolean removeConfiguration(java.lang.String);
    method public boolean removeConfiguration(long);
  }

}

package android.view {
+1 −0
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ statsd_common_src := \
    src/storage/StorageManager.cpp \
    src/StatsLogProcessor.cpp \
    src/StatsService.cpp \
    src/subscriber/SubscriberReporter.cpp \
    src/HashableDimensionKey.cpp \
    src/guardrail/MemoryLeakTrackUtil.cpp \
    src/guardrail/StatsdStats.cpp
+42 −1
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include "guardrail/MemoryLeakTrackUtil.h"
#include "guardrail/StatsdStats.h"
#include "storage/StorageManager.h"
#include "subscriber/SubscriberReporter.h"

#include <android-base/file.h>
#include <binder/IPCThreadState.h>
@@ -67,6 +68,7 @@ CompanionDeathRecipient::CompanionDeathRecipient(const sp<AnomalyMonitor>& anoma
void CompanionDeathRecipient::binderDied(const wp<IBinder>& who) {
    ALOGW("statscompanion service died");
    mAnomalyMonitor->setStatsCompanionService(nullptr);
    SubscriberReporter::getInstance().setStatsCompanionService(nullptr);
}

// ======================================================================
@@ -681,6 +683,7 @@ Status StatsService::statsCompanionReady() {
    VLOG("StatsService::statsCompanionReady linking to statsCompanion.");
    IInterface::asBinder(statsCompanion)->linkToDeath(new CompanionDeathRecipient(mAnomalyMonitor));
    mAnomalyMonitor->setStatsCompanionService(statsCompanion);
    SubscriberReporter::getInstance().setStatsCompanionService(statsCompanion);

    return Status::ok();
}
@@ -743,7 +746,27 @@ Status StatsService::addConfiguration(int64_t key,
Status StatsService::removeConfiguration(int64_t key, bool* success) {
    IPCThreadState* ipc = IPCThreadState::self();
    if (checkCallingPermission(String16(kPermissionDump))) {
        mConfigManager->RemoveConfig(ConfigKey(ipc->getCallingUid(), key));
        ConfigKey configKey(ipc->getCallingUid(), key);
        mConfigManager->RemoveConfig(configKey);
        SubscriberReporter::getInstance().removeConfig(configKey);
        *success = true;
        return Status::ok();
    } else {
        *success = false;
        return Status::fromExceptionCode(binder::Status::EX_SECURITY);
    }
}

Status StatsService::setBroadcastSubscriber(int64_t configId,
                                            int64_t subscriberId,
                                            const sp<android::IBinder>& intentSender,
                                            bool* success) {
    VLOG("StatsService::setBroadcastSubscriber called.");
    IPCThreadState* ipc = IPCThreadState::self();
    if (checkCallingPermission(String16(kPermissionDump))) {
        ConfigKey configKey(ipc->getCallingUid(), configId);
        SubscriberReporter::getInstance()
                .setBroadcastSubscriber(configKey, subscriberId, intentSender);
        *success = true;
        return Status::ok();
    } else {
@@ -752,6 +775,24 @@ Status StatsService::removeConfiguration(int64_t key, bool* success) {
    }
}

Status StatsService::unsetBroadcastSubscriber(int64_t configId,
                                              int64_t subscriberId,
                                              bool* success) {
    VLOG("StatsService::unsetBroadcastSubscriber called.");
    IPCThreadState* ipc = IPCThreadState::self();
    if (checkCallingPermission(String16(kPermissionDump))) {
        ConfigKey configKey(ipc->getCallingUid(), configId);
        SubscriberReporter::getInstance()
                .unsetBroadcastSubscriber(configKey, subscriberId);
        *success = true;
        return Status::ok();
    } else {
        *success = false;
        return Status::fromExceptionCode(binder::Status::EX_SECURITY);
    }
}


void StatsService::binderDied(const wp <IBinder>& who) {
}

+15 −0
Original line number Diff line number Diff line
@@ -99,6 +99,21 @@ public:
     */
    virtual Status removeConfiguration(int64_t key, bool* success) override;

    /**
     * Binder call to associate the given config's subscriberId with the given intentSender.
     * intentSender must be convertible into an IntentSender (in Java) using IntentSender(IBinder).
     */
    virtual Status setBroadcastSubscriber(int64_t configId,
                                          int64_t subscriberId,
                                          const sp<android::IBinder>& intentSender,
                                          bool* success) override;

    /**
     * Binder call to unassociate the given config's subscriberId with any intentSender.
     */
    virtual Status unsetBroadcastSubscriber(int64_t configId, int64_t subscriberId,
                                            bool* success) override;

    // TODO: public for testing since statsd doesn't run when system starts. Change to private
    // later.
    /** Inform statsCompanion that statsd is ready. */
+6 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include "external/Perfetto.h"
#include "guardrail/StatsdStats.h"
#include "frameworks/base/libs/incident/proto/android/os/header.pb.h"
#include "subscriber/SubscriberReporter.h"

#include <android/os/IIncidentManager.h>
#include <android/os/IncidentReportArgs.h>
@@ -233,6 +234,7 @@ void AnomalyTracker::informSubscribers(const HashableDimensionKey& key) {
    }

    std::set<int> incidentdSections;

    for (const Subscription& subscription : mSubscriptions) {
        switch (subscription.subscriber_information_case()) {
            case Subscription::SubscriberInformationCase::kIncidentdDetails:
@@ -243,6 +245,10 @@ void AnomalyTracker::informSubscribers(const HashableDimensionKey& key) {
            case Subscription::SubscriberInformationCase::kPerfettoDetails:
                CollectPerfettoTraceAndUploadToDropbox(subscription.perfetto_details());
                break;
            case Subscription::SubscriberInformationCase::kBroadcastSubscriberDetails:
                SubscriberReporter::getInstance()
                        .alertBroadcastSubscriber(mConfigKey, subscription, key);
                break;
            default:
                break;
        }
Loading