Merge "Allow statsd_config be able to set destination value AUTO/EXPLICIT."
This commit is contained in:
committed by
Android (Google) Code Review
commit
5935d347bd
@@ -46,6 +46,7 @@ static Status
|
||||
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 @@ checkIncidentPermissions(const IncidentReportArgs& args)
|
||||
// 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 @@ checkIncidentPermissions(const IncidentReportArgs& args)
|
||||
// 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.");
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ statsd_common_src := \
|
||||
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 \
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -38,15 +36,14 @@ AnomalyTracker::AnomalyTracker(const Alert& alert, const ConfigKey& configKey)
|
||||
: 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() {
|
||||
@@ -169,8 +166,8 @@ bool AnomalyTracker::detectAnomaly(const int64_t& currentBucketNum, const Metric
|
||||
// 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) {
|
||||
@@ -186,7 +183,7 @@ void AnomalyTracker::declareAnomaly(const uint64_t& timestampNs, const MetricDim
|
||||
|
||||
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.");
|
||||
@@ -231,44 +228,26 @@ void AnomalyTracker::informSubscribers(const MetricDimensionKey& key) {
|
||||
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
|
||||
|
||||
@@ -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 @@ public:
|
||||
|
||||
// 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 @@ public:
|
||||
|
||||
// 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:
|
||||
|
||||
@@ -52,8 +52,7 @@ void DurationAnomalyTracker::declareAnomalyIfAlarmExpired(const MetricDimensionK
|
||||
}
|
||||
|
||||
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::stopAllAlarms() {
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
@@ -53,7 +53,8 @@ public:
|
||||
// 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:
|
||||
|
||||
@@ -275,6 +275,12 @@ message Alarm {
|
||||
|
||||
message IncidentdDetails {
|
||||
repeated int32 section = 1;
|
||||
|
||||
enum Destination {
|
||||
AUTOMATIC = 0;
|
||||
EXPLICIT = 1;
|
||||
}
|
||||
optional Destination dest = 2;
|
||||
}
|
||||
|
||||
message PerfettoDetails {
|
||||
|
||||
78
cmds/statsd/src/subscriber/IncidentdReporter.cpp
Normal file
78
cmds/statsd/src/subscriber/IncidentdReporter.cpp
Normal file
@@ -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
|
||||
34
cmds/statsd/src/subscriber/IncidentdReporter.h
Normal file
34
cmds/statsd/src/subscriber/IncidentdReporter.h
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user