Throttler for incidentd based on size putting into dropbox.
The incidentd will accumulate the total size put into dropbox and once
it exceeds a threshold (currently 20MB) daily, it will stop further
requests. It allows collection again 24 hours later.
Bug: 64219725
Test: atest incidentd_test and manually flashed incidentd and test.
Change-Id: Iea21fbae40d5d01108797b190231d73e74eff213
diff --git a/cmds/incidentd/Android.mk b/cmds/incidentd/Android.mk
index d2d24c8..6bdd9be 100644
--- a/cmds/incidentd/Android.mk
+++ b/cmds/incidentd/Android.mk
@@ -25,16 +25,7 @@
LOCAL_MODULE := incidentd
-LOCAL_SRC_FILES := \
- src/PrivacyBuffer.cpp \
- src/FdBuffer.cpp \
- src/IncidentService.cpp \
- src/Privacy.cpp \
- src/Reporter.cpp \
- src/Section.cpp \
- src/incidentd_util.cpp \
- src/main.cpp \
- src/report_directory.cpp
+LOCAL_SRC_FILES := $(call all-cpp-files-under, src) \
LOCAL_CFLAGS += \
-Wall -Werror -Wno-missing-field-initializers -Wno-unused-variable -Wunused-parameter
@@ -110,19 +101,15 @@
LOCAL_C_INCLUDES += $(LOCAL_PATH)/src
-LOCAL_SRC_FILES := \
+LOCAL_SRC_FILES := $(call all-cpp-files-under, tests) \
src/PrivacyBuffer.cpp \
src/FdBuffer.cpp \
src/Privacy.cpp \
src/Reporter.cpp \
src/Section.cpp \
+ src/Throttler.cpp \
src/incidentd_util.cpp \
src/report_directory.cpp \
- tests/section_list.cpp \
- tests/PrivacyBuffer_test.cpp \
- tests/FdBuffer_test.cpp \
- tests/Reporter_test.cpp \
- tests/Section_test.cpp \
LOCAL_STATIC_LIBRARIES := \
libgmock \
diff --git a/cmds/incidentd/src/FdBuffer.cpp b/cmds/incidentd/src/FdBuffer.cpp
index 883924c8..db60794 100644
--- a/cmds/incidentd/src/FdBuffer.cpp
+++ b/cmds/incidentd/src/FdBuffer.cpp
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#define DEBUG false
#include "Log.h"
#include "FdBuffer.h"
diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp
index 9ae6240..28fb38a 100644
--- a/cmds/incidentd/src/IncidentService.cpp
+++ b/cmds/incidentd/src/IncidentService.cpp
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#define DEBUG false
#include "Log.h"
#include "IncidentService.h"
@@ -38,9 +39,11 @@
enum { WHAT_RUN_REPORT = 1, WHAT_SEND_BACKLOG_TO_DROPBOX = 2 };
-//#define DEFAULT_BACKLOG_DELAY_NS (1000000000LL * 60 * 5)
#define DEFAULT_BACKLOG_DELAY_NS (1000000000LL)
+#define DEFAULT_BYTES_SIZE_LIMIT (20 * 1024 * 1024) // 20MB
+#define DEFAULT_REFACTORY_PERIOD_MS (24 * 60 * 60 * 1000) // 1 Day
+
// ================================================================================
String16 const DUMP_PERMISSION("android.permission.DUMP");
String16 const USAGE_STATS_PERMISSION("android.permission.PACKAGE_USAGE_STATS");
@@ -113,8 +116,12 @@
}
// ================================================================================
-ReportHandler::ReportHandler(const sp<Looper>& handlerLooper, const sp<ReportRequestQueue>& queue)
- : mBacklogDelay(DEFAULT_BACKLOG_DELAY_NS), mHandlerLooper(handlerLooper), mQueue(queue) {}
+ReportHandler::ReportHandler(const sp<Looper>& handlerLooper, const sp<ReportRequestQueue>& queue,
+ const sp<Throttler>& throttler)
+ : mBacklogDelay(DEFAULT_BACKLOG_DELAY_NS),
+ mHandlerLooper(handlerLooper),
+ mQueue(queue),
+ mThrottler(throttler) {}
ReportHandler::~ReportHandler() {}
@@ -159,10 +166,17 @@
reporter->batch.add(request);
}
+ if (mThrottler->shouldThrottle()) {
+ ALOGW("RunReport got throttled.");
+ return;
+ }
+
// Take the report, which might take a while. More requests might queue
// up while we're doing this, and we'll handle them in their next batch.
// TODO: We should further rate-limit the reports to no more than N per time-period.
- Reporter::run_report_status_t reportStatus = reporter->runReport();
+ size_t reportByteSize = 0;
+ Reporter::run_report_status_t reportStatus = reporter->runReport(&reportByteSize);
+ mThrottler->addReportSize(reportByteSize);
if (reportStatus == Reporter::REPORT_NEEDS_DROPBOX) {
unique_lock<mutex> lock(mLock);
schedule_send_backlog_to_dropbox_locked();
@@ -184,8 +198,9 @@
// ================================================================================
IncidentService::IncidentService(const sp<Looper>& handlerLooper)
- : mQueue(new ReportRequestQueue()) {
- mHandler = new ReportHandler(handlerLooper, mQueue);
+ : mQueue(new ReportRequestQueue()),
+ mThrottler(new Throttler(DEFAULT_BYTES_SIZE_LIMIT, DEFAULT_REFACTORY_PERIOD_MS)) {
+ mHandler = new ReportHandler(handlerLooper, mQueue, mThrottler);
}
IncidentService::~IncidentService() {}
@@ -294,6 +309,10 @@
if (!args[0].compare(String8("privacy"))) {
return cmd_privacy(in, out, err, args);
}
+ if (!args[0].compare(String8("throttler"))) {
+ mThrottler->dump(out);
+ return NO_ERROR;
+ }
}
return cmd_help(out);
}
@@ -302,6 +321,9 @@
fprintf(out, "usage: adb shell cmd incident privacy print <section_id>\n");
fprintf(out, "usage: adb shell cmd incident privacy parse <section_id> < proto.txt\n");
fprintf(out, " Prints/parses for the section id.\n");
+ fprintf(out, "\n");
+ fprintf(out, "usage: adb shell cmd incident throttler\n");
+ fprintf(out, " Prints the current throttler state\n");
return NO_ERROR;
}
diff --git a/cmds/incidentd/src/IncidentService.h b/cmds/incidentd/src/IncidentService.h
index 3c66507..0ab34ed 100644
--- a/cmds/incidentd/src/IncidentService.h
+++ b/cmds/incidentd/src/IncidentService.h
@@ -26,6 +26,8 @@
#include <deque>
#include <mutex>
+#include "Throttler.h"
+
using namespace android;
using namespace android::base;
using namespace android::binder;
@@ -49,7 +51,8 @@
// ================================================================================
class ReportHandler : public MessageHandler {
public:
- ReportHandler(const sp<Looper>& handlerLooper, const sp<ReportRequestQueue>& queue);
+ ReportHandler(const sp<Looper>& handlerLooper, const sp<ReportRequestQueue>& queue,
+ const sp<Throttler>& throttler);
virtual ~ReportHandler();
virtual void handleMessage(const Message& message);
@@ -70,6 +73,7 @@
nsecs_t mBacklogDelay;
sp<Looper> mHandlerLooper;
sp<ReportRequestQueue> mQueue;
+ sp<Throttler> mThrottler;
/**
* Runs all of the reports that have been queued.
@@ -109,6 +113,7 @@
private:
sp<ReportRequestQueue> mQueue;
sp<ReportHandler> mHandler;
+ sp<Throttler> mThrottler;
/**
* Commands print out help.
diff --git a/cmds/incidentd/src/Log.h b/cmds/incidentd/src/Log.h
index 46efbd1..22de46d 100644
--- a/cmds/incidentd/src/Log.h
+++ b/cmds/incidentd/src/Log.h
@@ -23,7 +23,6 @@
#pragma once
#define LOG_TAG "incidentd"
-#define DEBUG false
#include <log/log.h>
diff --git a/cmds/incidentd/src/PrivacyBuffer.cpp b/cmds/incidentd/src/PrivacyBuffer.cpp
index e4128f4..ee57f4d 100644
--- a/cmds/incidentd/src/PrivacyBuffer.cpp
+++ b/cmds/incidentd/src/PrivacyBuffer.cpp
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#define DEBUG false
#include "Log.h"
#include "PrivacyBuffer.h"
diff --git a/cmds/incidentd/src/Reporter.cpp b/cmds/incidentd/src/Reporter.cpp
index c0b5358..12764f8 100644
--- a/cmds/incidentd/src/Reporter.cpp
+++ b/cmds/incidentd/src/Reporter.cpp
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#define DEBUG false
#include "Log.h"
#include "Reporter.h"
@@ -118,7 +119,7 @@
Reporter::~Reporter() {}
-Reporter::run_report_status_t Reporter::runReport() {
+Reporter::run_report_status_t Reporter::runReport(size_t* reportByteSize) {
status_t err = NO_ERROR;
bool needMainFd = false;
int mainFd = -1;
@@ -185,7 +186,6 @@
int64_t startTime = uptimeMillis();
err = (*section)->Execute(&batch);
int64_t endTime = uptimeMillis();
-
stats->set_success(err == NO_ERROR);
stats->set_exec_duration_ms(endTime - startTime);
if (err != NO_ERROR) {
@@ -193,6 +193,7 @@
(*section)->name.string(), id, strerror(-err));
goto DONE;
}
+ (*reportByteSize) += stats->report_size_bytes();
// Notify listener of starting
for (ReportRequestSet::iterator it = batch.begin(); it != batch.end(); it++) {
diff --git a/cmds/incidentd/src/Reporter.h b/cmds/incidentd/src/Reporter.h
index 0f3f221..ba8965e 100644
--- a/cmds/incidentd/src/Reporter.h
+++ b/cmds/incidentd/src/Reporter.h
@@ -18,8 +18,6 @@
#ifndef REPORTER_H
#define REPORTER_H
-#include "frameworks/base/libs/incident/proto/android/os/metadata.pb.h"
-
#include <android/os/IIncidentReportStatusListener.h>
#include <android/os/IncidentReportArgs.h>
@@ -29,6 +27,9 @@
#include <time.h>
+#include "Throttler.h"
+#include "frameworks/base/libs/incident/proto/android/os/metadata.pb.h"
+
using namespace android;
using namespace android::os;
using namespace std;
@@ -91,7 +92,7 @@
virtual ~Reporter();
// Run the report as described in the batch and args parameters.
- run_report_status_t runReport();
+ run_report_status_t runReport(size_t* reportByteSize);
static run_report_status_t upload_backlog();
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 2e4e980..64eae3a 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#define DEBUG false
#include "Log.h"
#include "Section.h"
@@ -244,7 +245,8 @@
}
if (requests->mainFd() >= 0 && !metadataBuf.empty()) {
write_section_header(requests->mainFd(), id, metadataBuf.size());
- if (!WriteFully(requests->mainFd(), (uint8_t const*)metadataBuf.data(), metadataBuf.size())) {
+ if (!WriteFully(requests->mainFd(), (uint8_t const*)metadataBuf.data(),
+ metadataBuf.size())) {
ALOGW("Failed to write metadata to dropbox fd %d", requests->mainFd());
return -1;
}
diff --git a/cmds/incidentd/src/Throttler.cpp b/cmds/incidentd/src/Throttler.cpp
new file mode 100644
index 0000000..1abf267
--- /dev/null
+++ b/cmds/incidentd/src/Throttler.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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 false
+#include "Log.h"
+
+#include "Throttler.h"
+
+#include <utils/SystemClock.h>
+
+Throttler::Throttler(size_t limit, int64_t refractoryPeriodMs)
+ : mSizeLimit(limit),
+ mRefractoryPeriodMs(refractoryPeriodMs),
+ mAccumulatedSize(0),
+ mLastRefractoryMs(android::elapsedRealtime()) {}
+
+Throttler::~Throttler() {}
+
+bool Throttler::shouldThrottle() {
+ int64_t now = android::elapsedRealtime();
+ if (now > mRefractoryPeriodMs + mLastRefractoryMs) {
+ mLastRefractoryMs = now;
+ mAccumulatedSize = 0;
+ }
+ return mAccumulatedSize > mSizeLimit;
+}
+
+void Throttler::addReportSize(size_t reportByteSize) {
+ VLOG("The current request took %d bytes to dropbox", (int)reportByteSize);
+ mAccumulatedSize += reportByteSize;
+}
+
+void Throttler::dump(FILE* out) {
+ fprintf(out, "mSizeLimit=%d\n", (int)mSizeLimit);
+ fprintf(out, "mAccumulatedSize=%d\n", (int)mAccumulatedSize);
+ fprintf(out, "mRefractoryPeriodMs=%d\n", (int)mRefractoryPeriodMs);
+ fprintf(out, "mLastRefractoryMs=%d\n", (int)mLastRefractoryMs);
+}
diff --git a/cmds/incidentd/src/Throttler.h b/cmds/incidentd/src/Throttler.h
new file mode 100644
index 0000000..c56f753
--- /dev/null
+++ b/cmds/incidentd/src/Throttler.h
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#ifndef THROTTLER_H
+#define THROTTLER_H
+
+#include <utils/RefBase.h>
+
+#include <unistd.h>
+/**
+ * This is a size-based throttler which prevents incidentd to take more data.
+ */
+class Throttler : public virtual android::RefBase {
+public:
+ Throttler(size_t limit, int64_t refractoryPeriodMs);
+ ~Throttler();
+
+ /**
+ * Asserts this before starting taking report.
+ */
+ bool shouldThrottle();
+
+ void addReportSize(size_t reportByteSize);
+
+ void dump(FILE* out);
+
+private:
+ const size_t mSizeLimit;
+ const int64_t mRefractoryPeriodMs;
+
+ size_t mAccumulatedSize;
+ int64_t mLastRefractoryMs;
+};
+
+#endif // THROTTLER_H
diff --git a/cmds/incidentd/src/report_directory.cpp b/cmds/incidentd/src/report_directory.cpp
index b71c066..f023ee1 100644
--- a/cmds/incidentd/src/report_directory.cpp
+++ b/cmds/incidentd/src/report_directory.cpp
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#define DEBUG false
#include "Log.h"
#include "report_directory.h"
diff --git a/cmds/incidentd/tests/FdBuffer_test.cpp b/cmds/incidentd/tests/FdBuffer_test.cpp
index 956c8d3..0e5eec6 100644
--- a/cmds/incidentd/tests/FdBuffer_test.cpp
+++ b/cmds/incidentd/tests/FdBuffer_test.cpp
@@ -11,6 +11,7 @@
// 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 false
#include "Log.h"
#include "FdBuffer.h"
diff --git a/cmds/incidentd/tests/PrivacyBuffer_test.cpp b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
index 7ea9bbf..c7c69a7 100644
--- a/cmds/incidentd/tests/PrivacyBuffer_test.cpp
+++ b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
@@ -11,6 +11,7 @@
// 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 false
#include "Log.h"
#include "FdBuffer.h"
diff --git a/cmds/incidentd/tests/Reporter_test.cpp b/cmds/incidentd/tests/Reporter_test.cpp
index bd359ac..955dbac 100644
--- a/cmds/incidentd/tests/Reporter_test.cpp
+++ b/cmds/incidentd/tests/Reporter_test.cpp
@@ -11,6 +11,7 @@
// 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 false
#include "Log.h"
#include "Reporter.h"
@@ -106,6 +107,7 @@
ReportRequestSet requests;
sp<Reporter> reporter;
sp<TestListener> l;
+ size_t size;
};
TEST_F(ReporterTest, IncidentReportArgs) {
@@ -125,7 +127,7 @@
}
TEST_F(ReporterTest, RunReportEmpty) {
- ASSERT_EQ(Reporter::REPORT_FINISHED, reporter->runReport());
+ ASSERT_EQ(Reporter::REPORT_FINISHED, reporter->runReport(&size));
EXPECT_EQ(l->startInvoked, 0);
EXPECT_EQ(l->finishInvoked, 0);
EXPECT_TRUE(l->startSections.empty());
@@ -147,7 +149,7 @@
reporter->batch.add(r1);
reporter->batch.add(r2);
- ASSERT_EQ(Reporter::REPORT_FINISHED, reporter->runReport());
+ ASSERT_EQ(Reporter::REPORT_FINISHED, reporter->runReport(&size));
string result;
ReadFileToString(tf.path, &result);
@@ -171,7 +173,7 @@
sp<ReportRequest> r = new ReportRequest(args, l, -1);
reporter->batch.add(r);
- ASSERT_EQ(Reporter::REPORT_FINISHED, reporter->runReport());
+ ASSERT_EQ(Reporter::REPORT_FINISHED, reporter->runReport(&size));
vector<string> results = InspectFiles();
ASSERT_EQ((int)results.size(), 1);
EXPECT_EQ(results[0],
@@ -188,7 +190,7 @@
sp<ReportRequest> r = new ReportRequest(args, l, -1);
reporter->batch.add(r);
- ASSERT_EQ(Reporter::REPORT_FINISHED, reporter->runReport());
+ ASSERT_EQ(Reporter::REPORT_FINISHED, reporter->runReport(&size));
auto metadata = reporter->batch.metadata();
EXPECT_EQ(IncidentMetadata_Destination_EXPLICIT, metadata.dest());
EXPECT_EQ(1, metadata.request_size());
diff --git a/cmds/incidentd/tests/Section_test.cpp b/cmds/incidentd/tests/Section_test.cpp
index a1f4fdc..026bf74 100644
--- a/cmds/incidentd/tests/Section_test.cpp
+++ b/cmds/incidentd/tests/Section_test.cpp
@@ -11,6 +11,7 @@
// 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 false
#include "Log.h"
#include "Section.h"
diff --git a/cmds/incidentd/tests/Throttler_test.cpp b/cmds/incidentd/tests/Throttler_test.cpp
new file mode 100644
index 0000000..213dcef
--- /dev/null
+++ b/cmds/incidentd/tests/Throttler_test.cpp
@@ -0,0 +1,37 @@
+// 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 false
+#include "Log.h"
+
+#include "Throttler.h"
+
+#include <android-base/test_utils.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+TEST(ThrottlerTest, DataSizeExceeded) {
+ Throttler t(100, 100000);
+ EXPECT_FALSE(t.shouldThrottle());
+ t.addReportSize(200);
+ EXPECT_TRUE(t.shouldThrottle());
+}
+
+TEST(ThrottlerTest, TimeReset) {
+ Throttler t(100, 500);
+ EXPECT_FALSE(t.shouldThrottle());
+ t.addReportSize(200);
+ EXPECT_TRUE(t.shouldThrottle());
+ sleep(1); // sleep for 1 second to make sure throttler resets
+ EXPECT_FALSE(t.shouldThrottle());
+}