Merge "Allow statsd_config be able to set destination value AUTO/EXPLICIT."

This commit is contained in:
TreeHugger Robot
2018-02-07 00:27:56 +00:00
committed by Android (Google) Code Review
9 changed files with 162 additions and 57 deletions

View File

@@ -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.");
}

View File

@@ -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 \

View File

@@ -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

View File

@@ -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:

View File

@@ -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) {

View File

@@ -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:

View File

@@ -275,6 +275,12 @@ message Alarm {
message IncidentdDetails {
repeated int32 section = 1;
enum Destination {
AUTOMATIC = 0;
EXPLICIT = 1;
}
optional Destination dest = 2;
}
message PerfettoDetails {

View 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

View 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