Merge "Merge changes I342cd7d0,I2c55831b into qt-dev am: a58591179b" into qt-dev-plus-aosp
This commit is contained in:
committed by
Android (Google) Code Review
commit
431d180650
@@ -263,6 +263,9 @@ main(int argc, char** argv)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (destination == DEST_UNSET) {
|
||||||
|
destination = DEST_STDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
string pkg;
|
string pkg;
|
||||||
string cls;
|
string cls;
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ cc_binary {
|
|||||||
"-Wno-missing-field-initializers",
|
"-Wno-missing-field-initializers",
|
||||||
"-Wno-unused-variable",
|
"-Wno-unused-variable",
|
||||||
"-Wunused-parameter",
|
"-Wunused-parameter",
|
||||||
|
"-Wno-tautological-undefined-compare",
|
||||||
|
|
||||||
// Allow implicit fallthrough in IncidentService.cpp:85 until it is fixed.
|
// Allow implicit fallthrough in IncidentService.cpp:85 until it is fixed.
|
||||||
"-Wno-error=implicit-fallthrough",
|
"-Wno-error=implicit-fallthrough",
|
||||||
@@ -96,6 +97,7 @@ cc_test {
|
|||||||
"-Wno-unused-variable",
|
"-Wno-unused-variable",
|
||||||
"-Wunused-parameter",
|
"-Wunused-parameter",
|
||||||
"-g",
|
"-g",
|
||||||
|
"-Wno-tautological-undefined-compare",
|
||||||
|
|
||||||
// Allow implicit fallthrough in IncidentService.cpp:85 until it is fixed.
|
// Allow implicit fallthrough in IncidentService.cpp:85 until it is fixed.
|
||||||
"-Wno-error=implicit-fallthrough",
|
"-Wno-error=implicit-fallthrough",
|
||||||
|
|||||||
@@ -174,12 +174,11 @@ void ReportHandler::schedule_send_broadcasts_locked() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ReportHandler::take_report() {
|
void ReportHandler::take_report() {
|
||||||
// Cycle the batch
|
// Cycle the batch and throttle.
|
||||||
sp<ReportBatch> batch;
|
sp<ReportBatch> batch;
|
||||||
{
|
{
|
||||||
unique_lock<mutex> lock(mLock);
|
unique_lock<mutex> lock(mLock);
|
||||||
batch = mBatch;
|
batch = mThrottler->filterBatch(mBatch);
|
||||||
mBatch = new ReportBatch();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (batch->empty()) {
|
if (batch->empty()) {
|
||||||
@@ -189,13 +188,6 @@ void ReportHandler::take_report() {
|
|||||||
|
|
||||||
sp<Reporter> reporter = new Reporter(mWorkDirectory, batch);
|
sp<Reporter> reporter = new Reporter(mWorkDirectory, batch);
|
||||||
|
|
||||||
// TODO: Do we really want to clear the reports if we throttle? Should we only throttle
|
|
||||||
// requests going to dropbox? How do we reconcile throttling with testing?
|
|
||||||
if (mThrottler->shouldThrottle()) {
|
|
||||||
ALOGW("RunReport got throttled.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Take the report, which might take a while. More requests might queue
|
// 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.
|
// 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.
|
// TODO: We should further rate-limit the reports to no more than N per time-period.
|
||||||
@@ -203,7 +195,13 @@ void ReportHandler::take_report() {
|
|||||||
size_t reportByteSize = 0;
|
size_t reportByteSize = 0;
|
||||||
reporter->runReport(&reportByteSize);
|
reporter->runReport(&reportByteSize);
|
||||||
|
|
||||||
mThrottler->addReportSize(reportByteSize);
|
// Tell the throttler how big it was, for the next throttling.
|
||||||
|
// TODO: This still isn't ideal. The throttler really should just track the
|
||||||
|
// persisted reqeusts, but changing Reporter::runReport() to track that individually
|
||||||
|
// will be a big change.
|
||||||
|
if (batch->hasPersistedReports()) {
|
||||||
|
mThrottler->addReportSize(reportByteSize);
|
||||||
|
}
|
||||||
|
|
||||||
// Kick off the next steps, one of which is to send any new or otherwise remaining
|
// Kick off the next steps, one of which is to send any new or otherwise remaining
|
||||||
// approvals, and one of which is to send any new or remaining broadcasts.
|
// approvals, and one of which is to send any new or remaining broadcasts.
|
||||||
@@ -247,11 +245,11 @@ IncidentService::IncidentService(const sp<Looper>& handlerLooper) {
|
|||||||
IncidentService::~IncidentService() {}
|
IncidentService::~IncidentService() {}
|
||||||
|
|
||||||
Status IncidentService::reportIncident(const IncidentReportArgs& args) {
|
Status IncidentService::reportIncident(const IncidentReportArgs& args) {
|
||||||
// TODO: Validate that the privacy policy is one of the real ones.
|
IncidentReportArgs argsCopy(args);
|
||||||
// If it isn't, clamp it to the next more restrictive real one.
|
|
||||||
|
|
||||||
// TODO: This function should reject the LOCAL privacy policy.
|
// Validate that the privacy policy is one of the real ones.
|
||||||
// Those have to stream.
|
// If it isn't, clamp it to the next more restrictive real one.
|
||||||
|
argsCopy.setPrivacyPolicy(cleanup_privacy_policy(args.getPrivacyPolicy()));
|
||||||
|
|
||||||
// TODO: Check that the broadcast recevier has the proper permissions
|
// TODO: Check that the broadcast recevier has the proper permissions
|
||||||
// TODO: Maybe we should consider relaxing the permissions if it's going to
|
// TODO: Maybe we should consider relaxing the permissions if it's going to
|
||||||
@@ -261,8 +259,15 @@ Status IncidentService::reportIncident(const IncidentReportArgs& args) {
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If they asked for the LOCAL privacy policy, give them EXPLICT. LOCAL has to
|
||||||
|
// be streamed. (This only applies to shell/root, because everyone else would have
|
||||||
|
// been rejected by checkIncidentPermissions()).
|
||||||
|
if (argsCopy.getPrivacyPolicy() < PRIVACY_POLICY_EXPLICIT) {
|
||||||
|
ALOGI("Demoting privacy policy to EXPLICT for persisted report.");
|
||||||
|
argsCopy.setPrivacyPolicy(PRIVACY_POLICY_EXPLICIT);
|
||||||
|
}
|
||||||
|
|
||||||
// If they didn't specify a component, use dropbox.
|
// If they didn't specify a component, use dropbox.
|
||||||
IncidentReportArgs argsCopy(args);
|
|
||||||
if (argsCopy.receiverPkg().length() == 0 && argsCopy.receiverCls().length() == 0) {
|
if (argsCopy.receiverPkg().length() == 0 && argsCopy.receiverCls().length() == 0) {
|
||||||
argsCopy.setReceiverPkg(DROPBOX_SENTINEL.getPackageName());
|
argsCopy.setReceiverPkg(DROPBOX_SENTINEL.getPackageName());
|
||||||
argsCopy.setReceiverCls(DROPBOX_SENTINEL.getClassName());
|
argsCopy.setReceiverCls(DROPBOX_SENTINEL.getClassName());
|
||||||
@@ -276,22 +281,21 @@ Status IncidentService::reportIncident(const IncidentReportArgs& args) {
|
|||||||
Status IncidentService::reportIncidentToStream(const IncidentReportArgs& args,
|
Status IncidentService::reportIncidentToStream(const IncidentReportArgs& args,
|
||||||
const sp<IIncidentReportStatusListener>& listener,
|
const sp<IIncidentReportStatusListener>& listener,
|
||||||
const unique_fd& stream) {
|
const unique_fd& stream) {
|
||||||
// TODO: Validate that the privacy policy is one of the real ones.
|
IncidentReportArgs argsCopy(args);
|
||||||
// If it isn't, clamp it to the next more restrictive real one.
|
|
||||||
|
|
||||||
// TODO: Only shell should be able to do a LOCAL privacy policy report.
|
|
||||||
|
|
||||||
// Streaming reports can not also be broadcast.
|
// Streaming reports can not also be broadcast.
|
||||||
IncidentReportArgs argsCopy(args);
|
|
||||||
argsCopy.setReceiverPkg("");
|
argsCopy.setReceiverPkg("");
|
||||||
argsCopy.setReceiverCls("");
|
argsCopy.setReceiverCls("");
|
||||||
|
|
||||||
|
// Validate that the privacy policy is one of the real ones.
|
||||||
|
// If it isn't, clamp it to the next more restrictive real one.
|
||||||
|
argsCopy.setPrivacyPolicy(cleanup_privacy_policy(args.getPrivacyPolicy()));
|
||||||
|
|
||||||
Status status = checkIncidentPermissions(argsCopy);
|
Status status = checkIncidentPermissions(argsCopy);
|
||||||
if (!status.isOk()) {
|
if (!status.isOk()) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// The ReportRequest takes ownership of the fd, so we need to dup it.
|
// The ReportRequest takes ownership of the fd, so we need to dup it.
|
||||||
int fd = dup(stream.get());
|
int fd = dup(stream.get());
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
|
|||||||
@@ -18,17 +18,30 @@
|
|||||||
|
|
||||||
#include <android/os/IncidentReportArgs.h>
|
#include <android/os/IncidentReportArgs.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <strstream>
|
||||||
|
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
namespace os {
|
namespace os {
|
||||||
namespace incidentd {
|
namespace incidentd {
|
||||||
|
|
||||||
using namespace android::os;
|
using namespace android::os;
|
||||||
|
using std::strstream;
|
||||||
|
|
||||||
static const bool kEncryptionEnabled = false;
|
static const bool kEncryptionEnabled = false;
|
||||||
|
|
||||||
uint64_t encode_field_id(const Privacy* p) { return (uint64_t)p->type << 32 | p->field_id; }
|
uint64_t encode_field_id(const Privacy* p) { return (uint64_t)p->type << 32 | p->field_id; }
|
||||||
|
|
||||||
|
string Privacy::toString() const {
|
||||||
|
if (this == NULL) {
|
||||||
|
return "Privacy{null}";
|
||||||
|
}
|
||||||
|
strstream os;
|
||||||
|
os << "Privacy{field_id=" << field_id << " type=" << ((int)type)
|
||||||
|
<< " children=" << ((void*)children) << " policy=" << ((int)policy) << "}";
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
const Privacy* lookup(const Privacy* p, uint32_t fieldId) {
|
const Privacy* lookup(const Privacy* p, uint32_t fieldId) {
|
||||||
if (p->children == NULL) return NULL;
|
if (p->children == NULL) return NULL;
|
||||||
for (int i = 0; p->children[i] != NULL; i++) { // NULL-terminated.
|
for (int i = 0; p->children[i] != NULL; i++) { // NULL-terminated.
|
||||||
@@ -87,6 +100,16 @@ bool PrivacySpec::RequireAll() const {
|
|||||||
return mPolicy == android::os::PRIVACY_POLICY_LOCAL;
|
return mPolicy == android::os::PRIVACY_POLICY_LOCAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t cleanup_privacy_policy(uint8_t policy) {
|
||||||
|
if (policy >= PRIVACY_POLICY_AUTOMATIC) {
|
||||||
|
return PRIVACY_POLICY_AUTOMATIC;
|
||||||
|
}
|
||||||
|
if (policy >= PRIVACY_POLICY_EXPLICIT) {
|
||||||
|
return PRIVACY_POLICY_EXPLICIT;
|
||||||
|
}
|
||||||
|
return PRIVACY_POLICY_LOCAL;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace incidentd
|
} // namespace incidentd
|
||||||
} // namespace os
|
} // namespace os
|
||||||
} // namespace android
|
} // namespace android
|
||||||
|
|||||||
@@ -50,8 +50,11 @@ struct Privacy {
|
|||||||
|
|
||||||
// DESTINATION Enum in frameworks/base/core/proto/android/privacy.proto.
|
// DESTINATION Enum in frameworks/base/core/proto/android/privacy.proto.
|
||||||
uint8_t policy;
|
uint8_t policy;
|
||||||
|
|
||||||
// A list of regexp rules for stripping string fields in proto.
|
// A list of regexp rules for stripping string fields in proto.
|
||||||
const char** patterns;
|
const char** patterns;
|
||||||
|
|
||||||
|
string toString() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Encode field id used by ProtoOutputStream.
|
// Encode field id used by ProtoOutputStream.
|
||||||
@@ -90,6 +93,11 @@ private:
|
|||||||
// TODO: Add privacy flag in incident.proto and auto generate it inside Privacy.
|
// TODO: Add privacy flag in incident.proto and auto generate it inside Privacy.
|
||||||
bool sectionEncryption(int section_id);
|
bool sectionEncryption(int section_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a privacy policy is other than the defined values, update it to a real one.
|
||||||
|
*/
|
||||||
|
uint8_t cleanup_privacy_policy(uint8_t policy);
|
||||||
|
|
||||||
} // namespace incidentd
|
} // namespace incidentd
|
||||||
} // namespace os
|
} // namespace os
|
||||||
} // namespace android
|
} // namespace android
|
||||||
|
|||||||
@@ -18,6 +18,10 @@
|
|||||||
|
|
||||||
#include "PrivacyFilter.h"
|
#include "PrivacyFilter.h"
|
||||||
|
|
||||||
|
#include "incidentd_util.h"
|
||||||
|
#include "proto_util.h"
|
||||||
|
#include "Section.h"
|
||||||
|
|
||||||
#include <android-base/file.h>
|
#include <android-base/file.h>
|
||||||
#include <android/util/ProtoFileReader.h>
|
#include <android/util/ProtoFileReader.h>
|
||||||
#include <android/util/protobuf.h>
|
#include <android/util/protobuf.h>
|
||||||
@@ -25,8 +29,6 @@
|
|||||||
|
|
||||||
#include "cipher/IncidentKeyStore.h"
|
#include "cipher/IncidentKeyStore.h"
|
||||||
#include "cipher/ProtoEncryption.h"
|
#include "cipher/ProtoEncryption.h"
|
||||||
#include "incidentd_util.h"
|
|
||||||
#include "proto_util.h"
|
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
namespace os {
|
namespace os {
|
||||||
@@ -190,7 +192,7 @@ status_t FieldStripper::strip(const uint8_t privacyPolicy) {
|
|||||||
ProtoOutputStream proto;
|
ProtoOutputStream proto;
|
||||||
|
|
||||||
// Optimization when no strip happens.
|
// Optimization when no strip happens.
|
||||||
if (mRestrictions == NULL || mRestrictions->children == NULL || spec.RequireAll()) {
|
if (mRestrictions == NULL || spec.RequireAll()) {
|
||||||
if (spec.CheckPremission(mRestrictions)) {
|
if (spec.CheckPremission(mRestrictions)) {
|
||||||
mSize = mData->size();
|
mSize = mData->size();
|
||||||
}
|
}
|
||||||
@@ -220,6 +222,11 @@ status_t FieldStripper::strip(const uint8_t privacyPolicy) {
|
|||||||
status_t FieldStripper::writeData(int fd) {
|
status_t FieldStripper::writeData(int fd) {
|
||||||
status_t err = NO_ERROR;
|
status_t err = NO_ERROR;
|
||||||
sp<ProtoReader> reader = mData;
|
sp<ProtoReader> reader = mData;
|
||||||
|
if (mData == nullptr) {
|
||||||
|
// There had been an error processing the data. We won't write anything,
|
||||||
|
// but we also won't return an error, because errors are fatal.
|
||||||
|
return NO_ERROR;
|
||||||
|
}
|
||||||
while (reader->readBuffer() != NULL) {
|
while (reader->readBuffer() != NULL) {
|
||||||
err = WriteFully(fd, reader->readBuffer(), reader->currentToRead()) ? NO_ERROR : -errno;
|
err = WriteFully(fd, reader->readBuffer(), reader->currentToRead()) ? NO_ERROR : -errno;
|
||||||
reader->move(reader->currentToRead());
|
reader->move(reader->currentToRead());
|
||||||
@@ -316,7 +323,7 @@ status_t PrivacyFilter::writeData(const FdBuffer& buffer, uint8_t bufferLevel, s
|
|||||||
if (err != NO_ERROR) {
|
if (err != NO_ERROR) {
|
||||||
// We can't successfully strip this data. We will skip
|
// We can't successfully strip this data. We will skip
|
||||||
// the rest of this section.
|
// the rest of this section.
|
||||||
return err;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,8 +374,8 @@ status_t filter_and_write_report(int to, int from, uint8_t bufferLevel,
|
|||||||
uint64_t fieldTag = reader->readRawVarint();
|
uint64_t fieldTag = reader->readRawVarint();
|
||||||
uint32_t fieldId = read_field_id(fieldTag);
|
uint32_t fieldId = read_field_id(fieldTag);
|
||||||
uint8_t wireType = read_wire_type(fieldTag);
|
uint8_t wireType = read_wire_type(fieldTag);
|
||||||
if (wireType == WIRE_TYPE_LENGTH_DELIMITED && args.containsSection(fieldId)) {
|
if (wireType == WIRE_TYPE_LENGTH_DELIMITED
|
||||||
VLOG("Read section %d", fieldId);
|
&& args.containsSection(fieldId, section_requires_specific_mention(fieldId))) {
|
||||||
// We need this field, but we need to strip it to the level provided in args.
|
// We need this field, but we need to strip it to the level provided in args.
|
||||||
PrivacyFilter filter(fieldId, get_privacy_of_section(fieldId));
|
PrivacyFilter filter(fieldId, get_privacy_of_section(fieldId));
|
||||||
filter.addFd(new ReadbackFilterFd(args.getPrivacyPolicy(), to));
|
filter.addFd(new ReadbackFilterFd(args.getPrivacyPolicy(), to));
|
||||||
|
|||||||
@@ -66,22 +66,18 @@ IncidentMetadata_Destination privacy_policy_to_dest(uint8_t privacyPolicy) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void poo_make_metadata(IncidentMetadata* result, const IncidentMetadata& full,
|
|
||||||
int64_t reportId, int32_t privacyPolicy, const IncidentReportArgs& args) {
|
|
||||||
result->set_report_id(reportId);
|
|
||||||
result->set_dest(privacy_policy_to_dest(privacyPolicy));
|
|
||||||
|
|
||||||
size_t sectionCount = full.sections_size();
|
static bool contains_section(const IncidentReportArgs& args, int sectionId) {
|
||||||
for (int sectionIndex = 0; sectionIndex < sectionCount; sectionIndex++) {
|
return args.containsSection(sectionId, section_requires_specific_mention(sectionId));
|
||||||
const IncidentMetadata::SectionStats& sectionStats = full.sections(sectionIndex);
|
}
|
||||||
if (args.containsSection(sectionStats.id())) {
|
|
||||||
*result->add_sections() = sectionStats;
|
static bool contains_section(const sp<ReportRequest>& args, int sectionId) {
|
||||||
}
|
return args->containsSection(sectionId);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ARGS must have a containsSection(int) method
|
// ARGS must have a containsSection(int) method
|
||||||
template <typename ARGS> void make_metadata(IncidentMetadata* result, const IncidentMetadata& full,
|
template <typename ARGS>
|
||||||
|
void make_metadata(IncidentMetadata* result, const IncidentMetadata& full,
|
||||||
int64_t reportId, int32_t privacyPolicy, ARGS args) {
|
int64_t reportId, int32_t privacyPolicy, ARGS args) {
|
||||||
result->set_report_id(reportId);
|
result->set_report_id(reportId);
|
||||||
result->set_dest(privacy_policy_to_dest(privacyPolicy));
|
result->set_dest(privacy_policy_to_dest(privacyPolicy));
|
||||||
@@ -89,7 +85,7 @@ template <typename ARGS> void make_metadata(IncidentMetadata* result, const Inci
|
|||||||
size_t sectionCount = full.sections_size();
|
size_t sectionCount = full.sections_size();
|
||||||
for (int sectionIndex = 0; sectionIndex < sectionCount; sectionIndex++) {
|
for (int sectionIndex = 0; sectionIndex < sectionCount; sectionIndex++) {
|
||||||
const IncidentMetadata::SectionStats& sectionStats = full.sections(sectionIndex);
|
const IncidentMetadata::SectionStats& sectionStats = full.sections(sectionIndex);
|
||||||
if (args->containsSection(sectionStats.id())) {
|
if (contains_section(args, sectionStats.id())) {
|
||||||
*result->add_sections() = sectionStats;
|
*result->add_sections() = sectionStats;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,6 +156,10 @@ bool ReportRequest::ok() {
|
|||||||
return mFd >= 0 && mStatus == NO_ERROR;
|
return mFd >= 0 && mStatus == NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ReportRequest::containsSection(int sectionId) const {
|
||||||
|
return args.containsSection(sectionId, section_requires_specific_mention(sectionId));
|
||||||
|
}
|
||||||
|
|
||||||
void ReportRequest::closeFd() {
|
void ReportRequest::closeFd() {
|
||||||
if (mIsStreaming && mFd >= 0) {
|
if (mIsStreaming && mFd >= 0) {
|
||||||
close(mFd);
|
close(mFd);
|
||||||
@@ -286,6 +286,22 @@ void ReportBatch::clearPersistedRequests() {
|
|||||||
mPersistedRequests.clear();
|
mPersistedRequests.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ReportBatch::transferStreamingRequests(const sp<ReportBatch>& that) {
|
||||||
|
for (vector<sp<ReportRequest>>::iterator request = mStreamingRequests.begin();
|
||||||
|
request != mStreamingRequests.end(); request++) {
|
||||||
|
that->mStreamingRequests.push_back(*request);
|
||||||
|
}
|
||||||
|
mStreamingRequests.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReportBatch::transferPersistedRequests(const sp<ReportBatch>& that) {
|
||||||
|
for (map<ComponentName, sp<ReportRequest>>::iterator it = mPersistedRequests.begin();
|
||||||
|
it != mPersistedRequests.end(); it++) {
|
||||||
|
that->mPersistedRequests[it->first] = it->second;
|
||||||
|
}
|
||||||
|
mPersistedRequests.clear();
|
||||||
|
}
|
||||||
|
|
||||||
void ReportBatch::getFailedRequests(vector<sp<ReportRequest>>* requests) {
|
void ReportBatch::getFailedRequests(vector<sp<ReportRequest>>* requests) {
|
||||||
for (map<ComponentName, sp<ReportRequest>>::iterator it = mPersistedRequests.begin();
|
for (map<ComponentName, sp<ReportRequest>>::iterator it = mPersistedRequests.begin();
|
||||||
it != mPersistedRequests.end(); it++) {
|
it != mPersistedRequests.end(); it++) {
|
||||||
@@ -441,7 +457,9 @@ status_t ReportWriter::writeSection(const FdBuffer& buffer) {
|
|||||||
|
|
||||||
// Add the fds for the streamed requests
|
// Add the fds for the streamed requests
|
||||||
mBatch->forEachStreamingRequest([&filter, this](const sp<ReportRequest>& request) {
|
mBatch->forEachStreamingRequest([&filter, this](const sp<ReportRequest>& request) {
|
||||||
if (request->ok() && request->args.containsSection(mCurrentSectionId)) {
|
if (request->ok()
|
||||||
|
&& request->args.containsSection(mCurrentSectionId,
|
||||||
|
section_requires_specific_mention(mCurrentSectionId))) {
|
||||||
filter.addFd(new StreamingFilterFd(request->args.getPrivacyPolicy(),
|
filter.addFd(new StreamingFilterFd(request->args.getPrivacyPolicy(),
|
||||||
request->getFd(), request));
|
request->getFd(), request));
|
||||||
}
|
}
|
||||||
@@ -619,7 +637,7 @@ DONE:
|
|||||||
mBatch->getCombinedPersistedArgs(&combinedArgs);
|
mBatch->getCombinedPersistedArgs(&combinedArgs);
|
||||||
IncidentMetadata persistedMetadata;
|
IncidentMetadata persistedMetadata;
|
||||||
make_metadata(&persistedMetadata, metadata, mPersistedFile->getTimestampNs(),
|
make_metadata(&persistedMetadata, metadata, mPersistedFile->getTimestampNs(),
|
||||||
persistedPrivacyPolicy, &combinedArgs);
|
persistedPrivacyPolicy, combinedArgs);
|
||||||
mPersistedFile->setMetadata(persistedMetadata);
|
mPersistedFile->setMetadata(persistedMetadata);
|
||||||
|
|
||||||
mPersistedFile->markCompleted();
|
mPersistedFile->markCompleted();
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "FdBuffer.h"
|
#include "FdBuffer.h"
|
||||||
#include "Throttler.h"
|
|
||||||
#include "WorkDirectory.h"
|
#include "WorkDirectory.h"
|
||||||
|
|
||||||
#include "frameworks/base/core/proto/android/os/metadata.pb.h"
|
#include "frameworks/base/core/proto/android/os/metadata.pb.h"
|
||||||
@@ -58,7 +57,7 @@ public:
|
|||||||
|
|
||||||
bool ok(); // returns true if the request is ok for write.
|
bool ok(); // returns true if the request is ok for write.
|
||||||
|
|
||||||
bool containsSection(int sectionId) const { return args.containsSection(sectionId); }
|
bool containsSection(int sectionId) const;
|
||||||
|
|
||||||
sp<IIncidentReportStatusListener> getListener() { return mListener; }
|
sp<IIncidentReportStatusListener> getListener() { return mListener; }
|
||||||
|
|
||||||
@@ -154,6 +153,18 @@ public:
|
|||||||
*/
|
*/
|
||||||
void clearPersistedRequests();
|
void clearPersistedRequests();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move the streaming requests in this batch to that batch. After this call there
|
||||||
|
* will be no streaming requests in this batch.
|
||||||
|
*/
|
||||||
|
void transferStreamingRequests(const sp<ReportBatch>& that);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move the persisted requests in this batch to that batch. After this call there
|
||||||
|
* will be no streaming requests in this batch.
|
||||||
|
*/
|
||||||
|
void transferPersistedRequests(const sp<ReportBatch>& that);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the requests that have encountered errors.
|
* Get the requests that have encountered errors.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -63,6 +63,15 @@ static pid_t fork_execute_incident_helper(const int id, Fpipe* p2cPipe, Fpipe* c
|
|||||||
return fork_execute_cmd(const_cast<char**>(ihArgs), p2cPipe, c2pPipe);
|
return fork_execute_cmd(const_cast<char**>(ihArgs), p2cPipe, c2pPipe);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool section_requires_specific_mention(int sectionId) {
|
||||||
|
switch (sectionId) {
|
||||||
|
case 3025: // restricted_images
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ================================================================================
|
// ================================================================================
|
||||||
Section::Section(int i, int64_t timeoutMs)
|
Section::Section(int i, int64_t timeoutMs)
|
||||||
: id(i),
|
: id(i),
|
||||||
|
|||||||
@@ -171,6 +171,13 @@ private:
|
|||||||
std::string mType;
|
std::string mType;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These sections will not be generated when doing an 'all' report, either
|
||||||
|
* for size, speed of collection, or privacy.
|
||||||
|
*/
|
||||||
|
bool section_requires_specific_mention(int sectionId);
|
||||||
|
|
||||||
} // namespace incidentd
|
} // namespace incidentd
|
||||||
} // namespace os
|
} // namespace os
|
||||||
} // namespace android
|
} // namespace android
|
||||||
|
|||||||
@@ -33,6 +33,21 @@ Throttler::Throttler(size_t limit, int64_t refractoryPeriodMs)
|
|||||||
|
|
||||||
Throttler::~Throttler() {}
|
Throttler::~Throttler() {}
|
||||||
|
|
||||||
|
sp<ReportBatch> Throttler::filterBatch(const sp<ReportBatch>& queued) {
|
||||||
|
sp<ReportBatch> result = new ReportBatch();
|
||||||
|
|
||||||
|
// We will never throttle the streaming ones.
|
||||||
|
queued->transferStreamingRequests(result);
|
||||||
|
|
||||||
|
// If the persisted ones aren't to be throttled, then add them to the
|
||||||
|
// batch we're going to do.
|
||||||
|
if (!shouldThrottle()) {
|
||||||
|
queued->transferPersistedRequests(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
bool Throttler::shouldThrottle() {
|
bool Throttler::shouldThrottle() {
|
||||||
int64_t now = android::elapsedRealtime();
|
int64_t now = android::elapsedRealtime();
|
||||||
if (now > mRefractoryPeriodMs + mLastRefractoryMs) {
|
if (now > mRefractoryPeriodMs + mLastRefractoryMs) {
|
||||||
@@ -56,4 +71,4 @@ void Throttler::dump(FILE* out) {
|
|||||||
|
|
||||||
} // namespace incidentd
|
} // namespace incidentd
|
||||||
} // namespace os
|
} // namespace os
|
||||||
} // namespace android
|
} // namespace android
|
||||||
|
|||||||
@@ -14,16 +14,19 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef THROTTLER_H
|
#pragma once
|
||||||
#define THROTTLER_H
|
|
||||||
|
#include "Reporter.h"
|
||||||
|
|
||||||
#include <utils/RefBase.h>
|
#include <utils/RefBase.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
namespace os {
|
namespace os {
|
||||||
namespace incidentd {
|
namespace incidentd {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a size-based throttler which prevents incidentd to take more data.
|
* This is a size-based throttler which prevents incidentd to take more data.
|
||||||
*/
|
*/
|
||||||
@@ -33,8 +36,11 @@ public:
|
|||||||
~Throttler();
|
~Throttler();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asserts this before starting taking report.
|
* Return a batch containing reports, if any that should be executed.
|
||||||
|
* Those will be removed from 'queued'.
|
||||||
*/
|
*/
|
||||||
|
sp<ReportBatch> filterBatch(const sp<ReportBatch>& queued);
|
||||||
|
|
||||||
bool shouldThrottle();
|
bool shouldThrottle();
|
||||||
|
|
||||||
void addReportSize(size_t reportByteSize);
|
void addReportSize(size_t reportByteSize);
|
||||||
@@ -52,5 +58,3 @@ private:
|
|||||||
} // namespace incidentd
|
} // namespace incidentd
|
||||||
} // namespace os
|
} // namespace os
|
||||||
} // namespace android
|
} // namespace android
|
||||||
|
|
||||||
#endif // THROTTLER_H
|
|
||||||
|
|||||||
1
cmds/incidentd/testdata/morethan24MB.txt
vendored
Normal file
1
cmds/incidentd/testdata/morethan24MB.txt
vendored
Normal file
File diff suppressed because one or more lines are too long
1
cmds/incidentd/testdata/morethan4MB.txt
vendored
1
cmds/incidentd/testdata/morethan4MB.txt
vendored
File diff suppressed because one or more lines are too long
@@ -233,8 +233,8 @@ TEST_F(FdBufferTest, ReadInStreamEmpty) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FdBufferTest, ReadInStreamMoreThan4MBWithMove) {
|
TEST_F(FdBufferTest, ReadInStreamMoreThan4MBWithMove) {
|
||||||
const std::string testFile = kTestDataPath + "morethan4MB.txt";
|
const std::string testFile = kTestDataPath + "morethan24MB.txt";
|
||||||
size_t fourMB = (size_t)4 * 1024 * 1024;
|
size_t twentyfourMB = (size_t)24 * 1024 * 1024;
|
||||||
unique_fd fd(open(testFile.c_str(), O_RDONLY | O_CLOEXEC));
|
unique_fd fd(open(testFile.c_str(), O_RDONLY | O_CLOEXEC));
|
||||||
ASSERT_NE(fd.get(), -1);
|
ASSERT_NE(fd.get(), -1);
|
||||||
int pid = fork();
|
int pid = fork();
|
||||||
@@ -254,21 +254,21 @@ TEST_F(FdBufferTest, ReadInStreamMoreThan4MBWithMove) {
|
|||||||
ASSERT_EQ(NO_ERROR,
|
ASSERT_EQ(NO_ERROR,
|
||||||
buffer.readProcessedDataInStream(fd, std::move(p2cPipe.writeFd()),
|
buffer.readProcessedDataInStream(fd, std::move(p2cPipe.writeFd()),
|
||||||
std::move(c2pPipe.readFd()), READ_TIMEOUT));
|
std::move(c2pPipe.readFd()), READ_TIMEOUT));
|
||||||
EXPECT_EQ(buffer.size(), fourMB);
|
EXPECT_EQ(buffer.size(), twentyfourMB);
|
||||||
EXPECT_FALSE(buffer.timedOut());
|
EXPECT_FALSE(buffer.timedOut());
|
||||||
EXPECT_TRUE(buffer.truncated());
|
EXPECT_TRUE(buffer.truncated());
|
||||||
wait(&pid);
|
wait(&pid);
|
||||||
sp<ProtoReader> reader = buffer.data()->read();
|
sp<ProtoReader> reader = buffer.data()->read();
|
||||||
reader->move(fourMB);
|
reader->move(twentyfourMB);
|
||||||
|
|
||||||
EXPECT_EQ(reader->bytesRead(), fourMB);
|
EXPECT_EQ(reader->bytesRead(), twentyfourMB);
|
||||||
EXPECT_FALSE(reader->hasNext());
|
EXPECT_FALSE(reader->hasNext());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(FdBufferTest, ReadInStreamMoreThan4MBWithNext) {
|
TEST_F(FdBufferTest, ReadInStreamMoreThan4MBWithNext) {
|
||||||
const std::string testFile = kTestDataPath + "morethan4MB.txt";
|
const std::string testFile = kTestDataPath + "morethan24MB.txt";
|
||||||
size_t fourMB = (size_t)4 * 1024 * 1024;
|
size_t twentyfourMB = (size_t)24 * 1024 * 1024;
|
||||||
unique_fd fd(open(testFile.c_str(), O_RDONLY | O_CLOEXEC));
|
unique_fd fd(open(testFile.c_str(), O_RDONLY | O_CLOEXEC));
|
||||||
ASSERT_NE(fd.get(), -1);
|
ASSERT_NE(fd.get(), -1);
|
||||||
int pid = fork();
|
int pid = fork();
|
||||||
@@ -288,7 +288,7 @@ TEST_F(FdBufferTest, ReadInStreamMoreThan4MBWithNext) {
|
|||||||
ASSERT_EQ(NO_ERROR,
|
ASSERT_EQ(NO_ERROR,
|
||||||
buffer.readProcessedDataInStream(fd, std::move(p2cPipe.writeFd()),
|
buffer.readProcessedDataInStream(fd, std::move(p2cPipe.writeFd()),
|
||||||
std::move(c2pPipe.readFd()), READ_TIMEOUT));
|
std::move(c2pPipe.readFd()), READ_TIMEOUT));
|
||||||
EXPECT_EQ(buffer.size(), fourMB);
|
EXPECT_EQ(buffer.size(), twentyfourMB);
|
||||||
EXPECT_FALSE(buffer.timedOut());
|
EXPECT_FALSE(buffer.timedOut());
|
||||||
EXPECT_TRUE(buffer.truncated());
|
EXPECT_TRUE(buffer.truncated());
|
||||||
wait(&pid);
|
wait(&pid);
|
||||||
|
|||||||
@@ -144,9 +144,9 @@ TEST_F(ReporterTest, IncidentReportArgs) {
|
|||||||
args2.addSection(3);
|
args2.addSection(3);
|
||||||
|
|
||||||
args1.merge(args2);
|
args1.merge(args2);
|
||||||
ASSERT_TRUE(args1.containsSection(1));
|
ASSERT_TRUE(args1.containsSection(1, false));
|
||||||
ASSERT_FALSE(args1.containsSection(2));
|
ASSERT_FALSE(args1.containsSection(2, false));
|
||||||
ASSERT_TRUE(args1.containsSection(3));
|
ASSERT_TRUE(args1.containsSection(3, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ public:
|
|||||||
void addHeader(const vector<uint8_t>& headerProto);
|
void addHeader(const vector<uint8_t>& headerProto);
|
||||||
|
|
||||||
inline bool all() const { return mAll; }
|
inline bool all() const { return mAll; }
|
||||||
bool containsSection(int section) const;
|
bool containsSection(int section, bool specific) const;
|
||||||
inline int getPrivacyPolicy() const { return mPrivacyPolicy; }
|
inline int getPrivacyPolicy() const { return mPrivacyPolicy; }
|
||||||
inline const set<int>& sections() const { return mSections; }
|
inline const set<int>& sections() const { return mSections; }
|
||||||
inline const string& receiverPkg() const { return mReceiverPkg; }
|
inline const string& receiverPkg() const { return mReceiverPkg; }
|
||||||
|
|||||||
@@ -194,9 +194,13 @@ IncidentReportArgs::addHeader(const vector<uint8_t>& headerProto)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
IncidentReportArgs::containsSection(int section) const
|
IncidentReportArgs::containsSection(int section, bool specific) const
|
||||||
{
|
{
|
||||||
return mAll || mSections.find(section) != mSections.end();
|
if (specific) {
|
||||||
|
return mSections.find(section) != mSections.end();
|
||||||
|
} else {
|
||||||
|
return mAll || mSections.find(section) != mSections.end();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -469,6 +469,7 @@ static bool generateSectionListCpp(Descriptor const* descriptor) {
|
|||||||
const FieldDescriptor* field = fieldsInOrder[i];
|
const FieldDescriptor* field = fieldsInOrder[i];
|
||||||
const string fieldName = getFieldName(field);
|
const string fieldName = getFieldName(field);
|
||||||
const Destination fieldDest = getFieldDest(field);
|
const Destination fieldDest = getFieldDest(field);
|
||||||
|
printf("\n// Incident Report Section: %s (%d)\n", field->name().c_str(), field->number());
|
||||||
if (field->type() != FieldDescriptor::TYPE_MESSAGE) {
|
if (field->type() != FieldDescriptor::TYPE_MESSAGE) {
|
||||||
printPrivacy(fieldName, field, "NULL", fieldDest, "NULL");
|
printPrivacy(fieldName, field, "NULL", fieldDest, "NULL");
|
||||||
continue;
|
continue;
|
||||||
@@ -477,9 +478,11 @@ static bool generateSectionListCpp(Descriptor const* descriptor) {
|
|||||||
skip[i] = true;
|
skip[i] = true;
|
||||||
const string fieldMessageName = getMessageName(field->message_type(), fieldDest);
|
const string fieldMessageName = getMessageName(field->message_type(), fieldDest);
|
||||||
// generate privacy flags for each section.
|
// generate privacy flags for each section.
|
||||||
if (generatePrivacyFlags(field->message_type(), fieldDest, variableNames, &parents)) {
|
if (generatePrivacyFlags(field->message_type(), incidentDest, variableNames, &parents)) {
|
||||||
printPrivacy(fieldName, field, fieldMessageName, fieldDest, "NULL");
|
printPrivacy(fieldName, field, fieldMessageName, fieldDest, "NULL");
|
||||||
} else if (isDefaultField(field, incidentDest)) {
|
} else if (fieldDest == incidentDest) {
|
||||||
|
printf("// default %s: fieldDest=%d incidentDest=%d\n", fieldName.c_str(),
|
||||||
|
getFieldDest(field), incidentDest);
|
||||||
continue; // don't create a new privacy if the value is default.
|
continue; // don't create a new privacy if the value is default.
|
||||||
} else {
|
} else {
|
||||||
printPrivacy(fieldName, field, "NULL", fieldDest, "NULL");
|
printPrivacy(fieldName, field, "NULL", fieldDest, "NULL");
|
||||||
|
|||||||
Reference in New Issue
Block a user