Allow statsd_config be able to set destination value AUTO/EXPLICIT.
Also move incidentd integration to its own files.
clang-format -style=file -i src/anomaly/* and src/subscribers/Incidentd*
Bug: 70239380
Test: manual
Change-Id: I7bfe14d704d9e86d925365a8a21ffed726723e60
diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp
index 1d5ab59..654036e 100644
--- a/cmds/incidentd/src/IncidentService.cpp
+++ b/cmds/incidentd/src/IncidentService.cpp
@@ -46,6 +46,7 @@
checkIncidentPermissions(const IncidentReportArgs& args)
{
uid_t callingUid = IPCThreadState::self()->getCallingUid();
+ pid_t callingPid = IPCThreadState::self()->getCallingPid();
if (callingUid == AID_ROOT || callingUid == AID_SHELL) {
// root doesn't have permission.DUMP if don't do this!
return Status::ok();
@@ -54,13 +55,13 @@
// checking calling permission.
if (!checkCallingPermission(DUMP_PERMISSION)) {
ALOGW("Calling pid %d and uid %d does not have permission: android.permission.DUMP",
- IPCThreadState::self()->getCallingPid(), callingUid);
+ callingPid, callingUid);
return Status::fromExceptionCode(Status::EX_SECURITY,
"Calling process does not have permission: android.permission.DUMP");
}
if (!checkCallingPermission(USAGE_STATS_PERMISSION)) {
ALOGW("Calling pid %d and uid %d does not have permission: android.permission.USAGE_STATS",
- IPCThreadState::self()->getCallingPid(), callingUid);
+ callingPid, callingUid);
return Status::fromExceptionCode(Status::EX_SECURITY,
"Calling process does not have permission: android.permission.USAGE_STATS");
}
@@ -68,13 +69,17 @@
// checking calling request uid permission.
switch (args.dest()) {
case DEST_LOCAL:
- if (callingUid != AID_SHELL || callingUid != AID_ROOT) {
+ if (callingUid != AID_SHELL && callingUid != AID_ROOT) {
+ ALOGW("Calling pid %d and uid %d does not have permission to get local data.",
+ callingPid, callingUid);
return Status::fromExceptionCode(Status::EX_SECURITY,
"Calling process does not have permission to get local data.");
}
case DEST_EXPLICIT:
- if (callingUid != AID_SHELL || callingUid != AID_ROOT ||
- callingUid != AID_STATSD || callingUid != AID_SYSTEM) {
+ if (callingUid != AID_SHELL && callingUid != AID_ROOT &&
+ callingUid != AID_STATSD && callingUid != AID_SYSTEM) {
+ ALOGW("Calling pid %d and uid %d does not have permission to get explicit data.",
+ callingPid, callingUid);
return Status::fromExceptionCode(Status::EX_SECURITY,
"Calling process does not have permission to get explicit data.");
}
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index b0019ac..b46c5c1 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -65,6 +65,7 @@
src/storage/StorageManager.cpp \
src/StatsLogProcessor.cpp \
src/StatsService.cpp \
+ src/subscriber/IncidentdReporter.cpp \
src/subscriber/SubscriberReporter.cpp \
src/HashableDimensionKey.cpp \
src/guardrail/MemoryLeakTrackUtil.cpp \
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index c84a5b4..7c5e45e 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -19,13 +19,11 @@
#include "AnomalyTracker.h"
#include "external/Perfetto.h"
-#include "guardrail/StatsdStats.h"
#include "frameworks/base/libs/incident/proto/android/os/header.pb.h"
+#include "guardrail/StatsdStats.h"
+#include "subscriber/IncidentdReporter.h"
#include "subscriber/SubscriberReporter.h"
-#include <android/os/IIncidentManager.h>
-#include <android/os/IncidentReportArgs.h>
-#include <binder/IServiceManager.h>
#include <statslog.h>
#include <time.h>
@@ -35,20 +33,17 @@
// TODO: Get rid of bucketNumbers, and return to the original circular array method.
AnomalyTracker::AnomalyTracker(const Alert& alert, const ConfigKey& configKey)
- : mAlert(alert),
- mConfigKey(configKey),
- mNumOfPastBuckets(mAlert.num_buckets() - 1) {
+ : mAlert(alert), mConfigKey(configKey), mNumOfPastBuckets(mAlert.num_buckets() - 1) {
VLOG("AnomalyTracker() called");
if (mAlert.num_buckets() <= 0) {
- ALOGE("Cannot create AnomalyTracker with %lld buckets",
- (long long)mAlert.num_buckets());
+ ALOGE("Cannot create AnomalyTracker with %lld buckets", (long long)mAlert.num_buckets());
return;
}
if (!mAlert.has_trigger_if_sum_gt()) {
ALOGE("Cannot create AnomalyTracker without threshold");
return;
}
- resetStorage(); // initialization
+ resetStorage(); // initialization
}
AnomalyTracker::~AnomalyTracker() {
@@ -171,8 +166,8 @@
// TODO: This creates a needless 0 entry in mSumOverPastBuckets. Fix this.
addPastBucket(key, 0, currentBucketNum - 1);
}
- return mAlert.has_trigger_if_sum_gt()
- && getSumOverPastBuckets(key) + currentBucketValue > mAlert.trigger_if_sum_gt();
+ return mAlert.has_trigger_if_sum_gt() &&
+ getSumOverPastBuckets(key) + currentBucketValue > mAlert.trigger_if_sum_gt();
}
void AnomalyTracker::declareAnomaly(const uint64_t& timestampNs, const MetricDimensionKey& key) {
@@ -188,7 +183,7 @@
if (!mSubscriptions.empty()) {
if (mAlert.has_id()) {
- ALOGI("An anomaly (%llu) has occurred! Informing subscribers.",mAlert.id());
+ ALOGI("An anomaly (%llu) has occurred! Informing subscribers.", mAlert.id());
informSubscribers(key);
} else {
ALOGI("An anomaly (with no id) has occurred! Not informing any subscribers.");
@@ -233,44 +228,26 @@
return;
}
- std::set<int> incidentdSections;
-
for (const Subscription& subscription : mSubscriptions) {
switch (subscription.subscriber_information_case()) {
case Subscription::SubscriberInformationCase::kIncidentdDetails:
- for (int i = 0; i < subscription.incidentd_details().section_size(); i++) {
- incidentdSections.insert(subscription.incidentd_details().section(i));
+ if (!GenerateIncidentReport(subscription.incidentd_details(), mAlert, mConfigKey)) {
+ ALOGW("Failed to generate incident report.");
}
break;
case Subscription::SubscriberInformationCase::kPerfettoDetails:
- CollectPerfettoTraceAndUploadToDropbox(subscription.perfetto_details());
+ if (!CollectPerfettoTraceAndUploadToDropbox(subscription.perfetto_details())) {
+ ALOGW("Failed to generate prefetto traces.");
+ }
break;
case Subscription::SubscriberInformationCase::kBroadcastSubscriberDetails:
- SubscriberReporter::getInstance()
- .alertBroadcastSubscriber(mConfigKey, subscription, key);
+ SubscriberReporter::getInstance().alertBroadcastSubscriber(mConfigKey, subscription,
+ key);
break;
default:
break;
}
}
- if (!incidentdSections.empty()) {
- sp<IIncidentManager> service = interface_cast<IIncidentManager>(
- defaultServiceManager()->getService(android::String16("incident")));
- if (service != NULL) {
- IncidentReportArgs incidentReport;
- for (const auto section : incidentdSections) {
- incidentReport.addSection(section);
- }
- android::os::IncidentHeaderProto header;
- header.set_alert_id(mAlert.id());
- header.mutable_config_key()->set_uid(mConfigKey.GetUid());
- header.mutable_config_key()->set_id(mConfigKey.GetId());
- incidentReport.addHeader(header);
- service->reportIncident(incidentReport);
- } else {
- ALOGW("Couldn't get the incident service.");
- }
- }
}
} // namespace statsd
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.h b/cmds/statsd/src/anomaly/AnomalyTracker.h
index f01a97f..3be959d 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.h
@@ -16,22 +16,24 @@
#pragma once
+#include <memory> // unique_ptr
+
+#include <stdlib.h>
+
#include <gtest/gtest_prod.h>
+#include <utils/RefBase.h>
+
#include "AnomalyMonitor.h"
#include "config/ConfigKey.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alert
#include "stats_util.h" // HashableDimensionKey and DimToValMap
-#include <memory> // unique_ptr
-#include <stdlib.h>
-#include <utils/RefBase.h>
-
namespace android {
namespace os {
namespace statsd {
-using std::unordered_map;
using std::shared_ptr;
+using std::unordered_map;
// Does NOT allow negative values.
class AnomalyTracker : public virtual RefBase {
@@ -60,12 +62,11 @@
// Detects the alert and informs the incidentd when applicable.
void detectAndDeclareAnomaly(const uint64_t& timestampNs, const int64_t& currBucketNum,
- const MetricDimensionKey& key,
- const int64_t& currentBucketValue);
+ const MetricDimensionKey& key, const int64_t& currentBucketValue);
// Init the AnomalyMonitor which is shared across anomaly trackers.
virtual void setAnomalyMonitor(const sp<AnomalyMonitor>& anomalyMonitor) {
- return; // Base AnomalyTracker class has no need for the AnomalyMonitor.
+ return; // Base AnomalyTracker class has no need for the AnomalyMonitor.
}
// Helper function to return the sum value of past buckets at given dimension.
@@ -92,9 +93,10 @@
// Declares an anomaly for each alarm in firedAlarms that belongs to this AnomalyTracker,
// and removes it from firedAlarms. Does NOT remove the alarm from the AnomalyMonitor.
- virtual void informAlarmsFired(const uint64_t& timestampNs,
+ virtual void informAlarmsFired(
+ const uint64_t& timestampNs,
unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& firedAlarms) {
- return; // The base AnomalyTracker class doesn't have alarms.
+ return; // The base AnomalyTracker class doesn't have alarms.
}
protected:
diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
index bbee9fa..e459f76 100644
--- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
@@ -52,8 +52,7 @@
}
void DurationAnomalyTracker::startAlarm(const MetricDimensionKey& dimensionKey,
- const uint64_t& timestampNs) {
-
+ const uint64_t& timestampNs) {
uint32_t timestampSec = static_cast<uint32_t>(timestampNs / NS_PER_SEC);
if (isInRefractoryPeriod(timestampNs, dimensionKey)) {
VLOG("Skipping setting anomaly alarm since it'd fall in the refractory period");
@@ -86,15 +85,15 @@
}
}
-void DurationAnomalyTracker::informAlarmsFired(const uint64_t& timestampNs,
+void DurationAnomalyTracker::informAlarmsFired(
+ const uint64_t& timestampNs,
unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& firedAlarms) {
-
if (firedAlarms.empty() || mAlarms.empty()) return;
// Find the intersection of firedAlarms and mAlarms.
// The for loop is inefficient, since it loops over all keys, but that's okay since it is very
// seldomly called. The alternative would be having AnomalyAlarms store information about the
- // DurationAnomalyTracker and key, but that's a lot of data overhead to speed up something that is
- // rarely ever called.
+ // DurationAnomalyTracker and key, but that's a lot of data overhead to speed up something that
+ // is rarely ever called.
unordered_map<MetricDimensionKey, sp<const AnomalyAlarm>> matchedAlarms;
for (const auto& kv : mAlarms) {
if (firedAlarms.count(kv.second) > 0) {
diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.h b/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
index 052fdf57..ba687da 100644
--- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.h
@@ -53,7 +53,8 @@
// and removes it from firedAlarms.
// Note that this will generally be called from a different thread from the other functions;
// the caller is responsible for thread safety.
- void informAlarmsFired(const uint64_t& timestampNs,
+ void informAlarmsFired(
+ const uint64_t& timestampNs,
unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>>& firedAlarms) override;
protected:
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 3eaf7a1..5a326a4 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -275,6 +275,12 @@
message IncidentdDetails {
repeated int32 section = 1;
+
+ enum Destination {
+ AUTOMATIC = 0;
+ EXPLICIT = 1;
+ }
+ optional Destination dest = 2;
}
message PerfettoDetails {
diff --git a/cmds/statsd/src/subscriber/IncidentdReporter.cpp b/cmds/statsd/src/subscriber/IncidentdReporter.cpp
new file mode 100644
index 0000000..d9a8fc8
--- /dev/null
+++ b/cmds/statsd/src/subscriber/IncidentdReporter.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+#define DEBUG true
+#include "Log.h"
+
+#include "IncidentdReporter.h"
+#include "frameworks/base/libs/incident/proto/android/os/header.pb.h"
+
+#include <android/os/IIncidentManager.h>
+#include <android/os/IncidentReportArgs.h>
+#include <binder/IBinder.h>
+#include <binder/IServiceManager.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+bool GenerateIncidentReport(const IncidentdDetails& config, const Alert& alert,
+ const ConfigKey& configKey) {
+ if (config.section_size() == 0) {
+ VLOG("The alert %lld contains zero section in config(%d,%lld)", alert.id(),
+ configKey.GetUid(), (long long) configKey.GetId());
+ return false;
+ }
+
+ IncidentReportArgs incidentReport;
+
+ android::os::IncidentHeaderProto header;
+ header.set_alert_id(alert.id());
+ header.mutable_config_key()->set_uid(configKey.GetUid());
+ header.mutable_config_key()->set_id(configKey.GetId());
+ incidentReport.addHeader(header);
+
+ for (int i = 0; i < config.section_size(); i++) {
+ incidentReport.addSection(config.section(i));
+ }
+
+ uint8_t dest;
+ switch (config.dest()) {
+ case IncidentdDetails_Destination_AUTOMATIC:
+ dest = android::os::DEST_AUTOMATIC;
+ break;
+ case IncidentdDetails_Destination_EXPLICIT:
+ dest = android::os::DEST_EXPLICIT;
+ break;
+ default:
+ dest = android::os::DEST_AUTOMATIC;
+ }
+ incidentReport.setDest(dest);
+
+ sp<IIncidentManager> service = interface_cast<IIncidentManager>(
+ defaultServiceManager()->getService(android::String16("incident")));
+ if (service == nullptr) {
+ ALOGW("Failed to fetch incident service.");
+ return false;
+ }
+ VLOG("Calling incidentd %p", service.get());
+ binder::Status s = service->reportIncident(incidentReport);
+ VLOG("Report incident status: %s", s.toString8().string());
+ return s.isOk();
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/subscriber/IncidentdReporter.h b/cmds/statsd/src/subscriber/IncidentdReporter.h
new file mode 100644
index 0000000..229ed77
--- /dev/null
+++ b/cmds/statsd/src/subscriber/IncidentdReporter.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include "config/ConfigKey.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alert, IncidentdDetails
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/**
+ * Calls incidentd to trigger an incident report and put in dropbox for uploading.
+ */
+bool GenerateIncidentReport(const IncidentdDetails& config, const Alert& alert,
+ const ConfigKey& configKey);
+
+} // namespace statsd
+} // namespace os
+} // namespace android