Use StatsDimensionsValueParcel within statsd apex

Because statsd now uses StatsDimensionsValueParcel instead of
StatsDimensionsValue.h/c, statsd no longer has to depend on libservices.

Test: m -j
Test: atest StatsdHostTestCases#testBroadcastSubscriber
Bug: 148604617
Change-Id: I6d65383ccec99f4672d6575232981c0f6cc40fcf
This commit is contained in:
Ruchir Rastogi
2020-02-03 18:53:24 -08:00
committed by Jeffrey Huang
parent 86379b14a7
commit 56da4c3862
14 changed files with 165 additions and 314 deletions

View File

@@ -42,5 +42,5 @@ interface IPendingIntentRef {
*/
oneway void sendSubscriberBroadcast(long configUid, long configId, long subscriptionId,
long subscriptionRuleId, in String[] cookies,
in StatsDimensionsValueParcel dimensionsValue);
in StatsDimensionsValueParcel dimensionsValueParcel);
}

View File

@@ -4,7 +4,12 @@ package android.os;
* @hide
*/
parcelable StatsDimensionsValueParcel {
int atomTag;
/**
* Field equals:
* - atomTag for top level StatsDimensionsValueParcel
* - position in dimension for all other levels
*/
int field;
int valueType;
String stringValue;
@@ -12,5 +17,5 @@ parcelable StatsDimensionsValueParcel {
long longValue;
boolean boolValue;
float floatValue;
StatsDimensionsValueParcel[] arrayValue;
StatsDimensionsValueParcel[] tupleValue;
}

View File

@@ -95,6 +95,47 @@ public final class StatsDimensionsValue implements Parcelable {
mValue = readValueFromParcel(mValueType, in);
}
/**
* Creates a {@code StatsDimensionsValue} from a StatsDimensionsValueParcel
* TODO(b/149103391): Make StatsDimensionsValue a wrapper on top of
* StatsDimensionsValueParcel.
*
* @hide
*/
public StatsDimensionsValue(StatsDimensionsValueParcel parcel) {
mField = parcel.field;
mValueType = parcel.valueType;
switch (mValueType) {
case STRING_VALUE_TYPE:
mValue = parcel.stringValue;
break;
case INT_VALUE_TYPE:
mValue = parcel.intValue;
break;
case LONG_VALUE_TYPE:
mValue = parcel.longValue;
break;
case BOOLEAN_VALUE_TYPE:
mValue = parcel.boolValue;
break;
case FLOAT_VALUE_TYPE:
mValue = parcel.floatValue;
break;
case TUPLE_VALUE_TYPE:
StatsDimensionsValue[] values = new StatsDimensionsValue[parcel.tupleValue.length];
for (int i = 0; i < parcel.tupleValue.length; i++) {
values[i] = new StatsDimensionsValue(parcel.tupleValue[i]);
}
mValue = values;
break;
default:
Slog.w(TAG, "StatsDimensionsValueParcel contains bad valueType: " + mValueType);
mValue = null;
break;
}
}
/**
* Return the field, i.e. the tag of a statsd atom.
*

View File

@@ -147,8 +147,9 @@ public class StatsCompanion {
@Override
public void sendSubscriberBroadcast(long configUid, long configId, long subscriptionId,
long subscriptionRuleId, String[] cookies,
StatsDimensionsValueParcel dimensionsValue) {
enforceStatsCompanionPermission(mContext);
StatsDimensionsValueParcel dimensionsValueParcel) {
enforceStatsdCallingUid();
StatsDimensionsValue dimensionsValue = new StatsDimensionsValue(dimensionsValueParcel);
Intent intent =
new Intent()
.putExtra(StatsManager.EXTRA_STATS_CONFIG_UID, configUid)
@@ -169,8 +170,6 @@ public class StatsCompanion {
"Statsd sendSubscriberBroadcast with params {%d %d %d %d %s %s}",
configUid, configId, subscriptionId, subscriptionRuleId,
Arrays.toString(cookies),
// TODO (b/148604617): convert StatsDimensionsValueParcel into
// StatsDimensionsValue
dimensionsValue));
}
try {

View File

@@ -126,7 +126,6 @@ cc_defaults {
"libbinder",
"libincident",
"liblog",
"libservices",
"libstatssocket",
"statsd-aidl-cpp",
],

View File

@@ -26,6 +26,86 @@ namespace statsd {
using std::string;
using std::vector;
// These constants must be kept in sync with those in StatsDimensionsValue.java
const static int STATS_DIMENSIONS_VALUE_STRING_TYPE = 2;
const static int STATS_DIMENSIONS_VALUE_INT_TYPE = 3;
const static int STATS_DIMENSIONS_VALUE_LONG_TYPE = 4;
// const static int STATS_DIMENSIONS_VALUE_BOOL_TYPE = 5; (commented out because
// unused -- statsd does not correctly support bool types)
const static int STATS_DIMENSIONS_VALUE_FLOAT_TYPE = 6;
const static int STATS_DIMENSIONS_VALUE_TUPLE_TYPE = 7;
/**
* Recursive helper function that populates a parent StatsDimensionsValueParcel
* with children StatsDimensionsValueParcels.
*
* \param dims vector of FieldValues stored by HashableDimensionKey
* \param index positions in dims vector to start reading children from
* \param depth level of parent parcel in the full StatsDimensionsValueParcel
* tree
*/
static void populateStatsDimensionsValueParcelChildren(StatsDimensionsValueParcel &parentParcel,
const vector<FieldValue>& dims, size_t& index,
int depth, int prefix) {
while (index < dims.size()) {
const FieldValue& dim = dims[index];
int fieldDepth = dim.mField.getDepth();
int fieldPrefix = dim.mField.getPrefix(depth);
StatsDimensionsValueParcel childParcel;
childParcel.field = dim.mField.getPosAtDepth(depth);
if (depth > 2) {
ALOGE("Depth > 2 not supported by StatsDimensionsValueParcel.");
return;
}
if (depth == fieldDepth && prefix == fieldPrefix) {
switch (dim.mValue.getType()) {
case INT:
childParcel.valueType = STATS_DIMENSIONS_VALUE_INT_TYPE;
childParcel.intValue = dim.mValue.int_value;
break;
case LONG:
childParcel.valueType = STATS_DIMENSIONS_VALUE_LONG_TYPE;
childParcel.longValue = dim.mValue.long_value;
break;
case FLOAT:
childParcel.valueType = STATS_DIMENSIONS_VALUE_FLOAT_TYPE;
childParcel.floatValue = dim.mValue.float_value;
break;
case STRING:
childParcel.valueType = STATS_DIMENSIONS_VALUE_STRING_TYPE;
childParcel.stringValue = String16(dim.mValue.str_value.c_str());
break;
default:
ALOGE("Encountered FieldValue with unsupported value type.");
break;
}
index++;
parentParcel.tupleValue.push_back(childParcel);
} else if (fieldDepth > depth && fieldPrefix == prefix) {
childParcel.valueType = STATS_DIMENSIONS_VALUE_TUPLE_TYPE;
populateStatsDimensionsValueParcelChildren(childParcel, dims, index, depth + 1,
dim.mField.getPrefix(depth + 1));
parentParcel.tupleValue.push_back(childParcel);
} else {
return;
}
}
}
StatsDimensionsValueParcel HashableDimensionKey::toStatsDimensionsValueParcel() const {
StatsDimensionsValueParcel parcel;
if (mValues.size() == 0) {
return parcel;
}
parcel.field = mValues[0].mField.getTag();
parcel.valueType = STATS_DIMENSIONS_VALUE_TUPLE_TYPE;
size_t index = 0;
populateStatsDimensionsValueParcelChildren(parcel, mValues, index, /*depth=*/0, /*prefix=*/0);
return parcel;
}
android::hash_t hashDimension(const HashableDimensionKey& value) {
android::hash_t hash = 0;
for (const auto& fieldValue : value.getValues()) {

View File

@@ -16,10 +16,11 @@
#pragma once
#include <android/os/StatsDimensionsValueParcel.h>
#include <utils/JenkinsHash.h>
#include <vector>
#include "FieldValue.h"
#include "android-base/stringprintf.h"
#include "FieldValue.h"
#include "logd/LogEvent.h"
namespace android {
@@ -69,6 +70,8 @@ public:
return nullptr;
}
StatsDimensionsValueParcel toStatsDimensionsValueParcel() const;
std::string toString() const;
bool operator!=(const HashableDimensionKey& that) const;

View File

@@ -115,15 +115,13 @@ void SubscriberReporter::sendBroadcastLocked(const sp<IPendingIntentRef>& pir,
const vector<String16>& cookies,
const MetricDimensionKey& dimKey) const {
VLOG("SubscriberReporter::sendBroadcastLocked called.");
// TODO (b/148604617): convert MetricDimensionKey to StatsDimensiosnValueParcel
StatsDimensionsValueParcel parcel;
pir->sendSubscriberBroadcast(
configKey.GetUid(),
configKey.GetId(),
subscription.id(),
subscription.rule_id(),
cookies,
parcel);
dimKey.getDimensionKeyInWhat().toStatsDimensionsValueParcel());
}
sp<IPendingIntentRef> SubscriberReporter::getBroadcastSubscriber(const ConfigKey& configKey,
@@ -140,61 +138,6 @@ sp<IPendingIntentRef> SubscriberReporter::getBroadcastSubscriber(const ConfigKey
return pirMapIt->second;
}
void getStatsDimensionsValueHelper(const vector<FieldValue>& dims, size_t* index, int depth,
int prefix, vector<StatsDimensionsValue>* output) {
size_t count = dims.size();
while (*index < count) {
const auto& dim = dims[*index];
const int valueDepth = dim.mField.getDepth();
const int valuePrefix = dim.mField.getPrefix(depth);
if (valueDepth > 2) {
ALOGE("Depth > 2 not supported");
return;
}
if (depth == valueDepth && valuePrefix == prefix) {
switch (dim.mValue.getType()) {
case INT:
output->push_back(StatsDimensionsValue(dim.mField.getPosAtDepth(depth),
dim.mValue.int_value));
break;
case LONG:
output->push_back(StatsDimensionsValue(dim.mField.getPosAtDepth(depth),
dim.mValue.long_value));
break;
case FLOAT:
output->push_back(StatsDimensionsValue(dim.mField.getPosAtDepth(depth),
dim.mValue.float_value));
break;
case STRING:
output->push_back(StatsDimensionsValue(dim.mField.getPosAtDepth(depth),
String16(dim.mValue.str_value.c_str())));
break;
default:
break;
}
(*index)++;
} else if (valueDepth > depth && valuePrefix == prefix) {
vector<StatsDimensionsValue> childOutput;
getStatsDimensionsValueHelper(dims, index, depth + 1, dim.mField.getPrefix(depth + 1),
&childOutput);
output->push_back(StatsDimensionsValue(dim.mField.getPosAtDepth(depth), childOutput));
} else {
return;
}
}
}
StatsDimensionsValue SubscriberReporter::getStatsDimensionsValue(const HashableDimensionKey& dim) {
if (dim.getValues().size() == 0) {
return StatsDimensionsValue();
}
vector<StatsDimensionsValue> fields;
size_t index = 0;
getStatsDimensionsValueHelper(dim.getValues(), &index, 0, 0, &fields);
return StatsDimensionsValue(dim.getValues()[0].mField.getTag(), fields);
}
} // namespace statsd
} // namespace os
} // namespace android

View File

@@ -22,7 +22,6 @@
#include "config/ConfigKey.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // subscription
#include "android/os/StatsDimensionsValue.h"
#include "HashableDimensionKey.h"
#include <mutex>
@@ -70,8 +69,6 @@ public:
sp<IPendingIntentRef> getBroadcastSubscriber(const ConfigKey& configKey, int64_t subscriberId);
static StatsDimensionsValue getStatsDimensionsValue(const HashableDimensionKey& dim);
private:
SubscriberReporter() {};

View File

@@ -290,33 +290,34 @@ TEST(AtomMatcherTest, TestWriteDimensionPath) {
}
}
TEST(AtomMatcherTest, TestSubscriberDimensionWrite) {
HashableDimensionKey dim;
int pos1[] = {1, 1, 1};
int pos2[] = {1, 1, 2};
int pos3[] = {1, 1, 3};
int pos4[] = {2, 0, 0};
Field field1(10, pos1, 2);
Field field2(10, pos2, 2);
Field field3(10, pos3, 2);
Field field4(10, pos4, 0);
Value value1((int32_t)10025);
Value value2("tag");
Value value3((int32_t)987654);
Value value4((int32_t)99999);
dim.addValue(FieldValue(field1, value1));
dim.addValue(FieldValue(field2, value2));
dim.addValue(FieldValue(field3, value3));
dim.addValue(FieldValue(field4, value4));
SubscriberReporter::getStatsDimensionsValue(dim);
// TODO(b/110562792): can't test anything here because StatsDimensionsValue class doesn't
// have any read api.
}
//TODO(b/149050405) Update this test for StatsDimensionValueParcel
//TEST(AtomMatcherTest, TestSubscriberDimensionWrite) {
// HashableDimensionKey dim;
//
// int pos1[] = {1, 1, 1};
// int pos2[] = {1, 1, 2};
// int pos3[] = {1, 1, 3};
// int pos4[] = {2, 0, 0};
//
// Field field1(10, pos1, 2);
// Field field2(10, pos2, 2);
// Field field3(10, pos3, 2);
// Field field4(10, pos4, 0);
//
// Value value1((int32_t)10025);
// Value value2("tag");
// Value value3((int32_t)987654);
// Value value4((int32_t)99999);
//
// dim.addValue(FieldValue(field1, value1));
// dim.addValue(FieldValue(field2, value2));
// dim.addValue(FieldValue(field3, value3));
// dim.addValue(FieldValue(field4, value4));
//
// SubscriberReporter::getStatsDimensionsValue(dim);
// // TODO(b/110562792): can't test anything here because StatsDimensionsValue class doesn't
// // have any read api.
//}
TEST(AtomMatcherTest, TestWriteDimensionToProto) {
HashableDimensionKey dim;

View File

@@ -1,20 +0,0 @@
/**
* 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.
*/
package android.os;
/** @hide */
parcelable StatsDimensionsValue cpp_header "android/os/StatsDimensionsValue.h";

View File

@@ -20,7 +20,6 @@ cc_library_shared {
":IDropBoxManagerService.aidl",
"src/content/ComponentName.cpp",
"src/os/DropBoxManager.cpp",
"src/os/StatsDimensionsValue.cpp",
],
shared_libs: [

View File

@@ -1,70 +0,0 @@
/*
* 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 STATS_DIMENSIONS_VALUE_H
#define STATS_DIMENSIONS_VALUE_H
#include <binder/Parcel.h>
#include <binder/Parcelable.h>
#include <binder/Status.h>
#include <utils/String16.h>
#include <vector>
namespace android {
namespace os {
// Represents a parcelable object. Used to send data from statsd to StatsCompanionService.java.
class StatsDimensionsValue : public android::Parcelable {
public:
StatsDimensionsValue();
StatsDimensionsValue(int32_t field, String16 value);
StatsDimensionsValue(int32_t field, int32_t value);
StatsDimensionsValue(int32_t field, int64_t value);
StatsDimensionsValue(int32_t field, bool value);
StatsDimensionsValue(int32_t field, float value);
StatsDimensionsValue(int32_t field, std::vector<StatsDimensionsValue> value);
virtual ~StatsDimensionsValue();
virtual android::status_t writeToParcel(android::Parcel* out) const override;
virtual android::status_t readFromParcel(const android::Parcel* in) override;
private:
// Keep constants in sync with android/os/StatsDimensionsValue.java
// and stats_log.proto's DimensionValue.
static const int kStrValueType = 2;
static const int kIntValueType = 3;
static const int kLongValueType = 4;
static const int kBoolValueType = 5;
static const int kFloatValueType = 6;
static const int kTupleValueType = 7;
int32_t mField;
int32_t mValueType;
// This isn't very clever, but it isn't used for long-term storage, so it'll do.
String16 mStrValue;
int32_t mIntValue;
int64_t mLongValue;
bool mBoolValue;
float mFloatValue;
std::vector<StatsDimensionsValue> mTupleValue;
};
} // namespace os
} // namespace android
#endif // STATS_DIMENSIONS_VALUE_H

View File

@@ -1,126 +0,0 @@
/*
* 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 LOG_TAG "StatsDimensionsValue"
#include "android/os/StatsDimensionsValue.h"
#include <cutils/log.h>
using android::Parcel;
using android::Parcelable;
using android::status_t;
using std::vector;
namespace android {
namespace os {
StatsDimensionsValue::StatsDimensionsValue() {};
StatsDimensionsValue::StatsDimensionsValue(int32_t field, String16 value) :
mField(field),
mValueType(kStrValueType),
mStrValue(value) {
}
StatsDimensionsValue::StatsDimensionsValue(int32_t field, int32_t value) :
mField(field),
mValueType(kIntValueType),
mIntValue(value) {
}
StatsDimensionsValue::StatsDimensionsValue(int32_t field, int64_t value) :
mField(field),
mValueType(kLongValueType),
mLongValue(value) {
}
StatsDimensionsValue::StatsDimensionsValue(int32_t field, bool value) :
mField(field),
mValueType(kBoolValueType),
mBoolValue(value) {
}
StatsDimensionsValue::StatsDimensionsValue(int32_t field, float value) :
mField(field),
mValueType(kFloatValueType),
mFloatValue(value) {
}
StatsDimensionsValue::StatsDimensionsValue(int32_t field, vector<StatsDimensionsValue> value) :
mField(field),
mValueType(kTupleValueType),
mTupleValue(value) {
}
StatsDimensionsValue::~StatsDimensionsValue() {}
status_t
StatsDimensionsValue::writeToParcel(Parcel* out) const {
status_t err ;
err = out->writeInt32(mField);
if (err != NO_ERROR) {
return err;
}
err = out->writeInt32(mValueType);
if (err != NO_ERROR) {
return err;
}
switch (mValueType) {
case kStrValueType:
err = out->writeString16(mStrValue);
break;
case kIntValueType:
err = out->writeInt32(mIntValue);
break;
case kLongValueType:
err = out->writeInt64(mLongValue);
break;
case kBoolValueType:
err = out->writeBool(mBoolValue);
break;
case kFloatValueType:
err = out->writeFloat(mFloatValue);
break;
case kTupleValueType:
{
int sz = mTupleValue.size();
err = out->writeInt32(sz);
if (err != NO_ERROR) {
return err;
}
for (int i = 0; i < sz; ++i) {
err = mTupleValue[i].writeToParcel(out);
if (err != NO_ERROR) {
return err;
}
}
}
break;
default:
err = UNKNOWN_ERROR;
break;
}
return err;
}
status_t
StatsDimensionsValue::readFromParcel(const Parcel* in)
{
// Implement me if desired. We don't currently use this.
ALOGE("Cannot do c++ StatsDimensionsValue.readFromParcel(); it is not implemented.");
(void)in; // To prevent compile error of unused parameter 'in'
return UNKNOWN_ERROR;
}
} // namespace os
} // namespace android