479 lines
20 KiB
C++
479 lines
20 KiB
C++
// Copyright (C) 2023 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.
|
|
|
|
#include <android-modules-utils/sdk_level.h>
|
|
#include <gtest/gtest.h>
|
|
|
|
#include "flags/FlagProvider.h"
|
|
#include "storage/StorageManager.h"
|
|
#include "tests/statsd_test_util.h"
|
|
|
|
namespace android {
|
|
namespace os {
|
|
namespace statsd {
|
|
|
|
using android::modules::sdklevel::IsAtLeastU;
|
|
|
|
#ifdef __ANDROID__
|
|
|
|
namespace {
|
|
const int32_t atomTag = 666;
|
|
const string delegatePackageName = "com.test.restricted.metrics.package";
|
|
const int32_t delegateUid = 10200;
|
|
const string configPackageName = "com.test.config.package";
|
|
int64_t metricId;
|
|
int64_t anotherMetricId;
|
|
|
|
StatsdConfig CreateConfigWithOneMetric() {
|
|
StatsdConfig config;
|
|
config.add_allowed_log_source("AID_ROOT");
|
|
AtomMatcher atomMatcher = CreateSimpleAtomMatcher("testmatcher", atomTag);
|
|
*config.add_atom_matcher() = atomMatcher;
|
|
|
|
EventMetric eventMetric = createEventMetric("EventMetric", atomMatcher.id(), nullopt);
|
|
metricId = eventMetric.id();
|
|
*config.add_event_metric() = eventMetric;
|
|
return config;
|
|
}
|
|
StatsdConfig CreateConfigWithTwoMetrics() {
|
|
StatsdConfig config;
|
|
config.add_allowed_log_source("AID_ROOT");
|
|
AtomMatcher atomMatcher = CreateSimpleAtomMatcher("testmatcher", atomTag);
|
|
*config.add_atom_matcher() = atomMatcher;
|
|
|
|
EventMetric eventMetric = createEventMetric("EventMetric", atomMatcher.id(), nullopt);
|
|
metricId = eventMetric.id();
|
|
*config.add_event_metric() = eventMetric;
|
|
EventMetric anotherEventMetric =
|
|
createEventMetric("AnotherEventMetric", atomMatcher.id(), nullopt);
|
|
anotherMetricId = anotherEventMetric.id();
|
|
*config.add_event_metric() = anotherEventMetric;
|
|
return config;
|
|
}
|
|
|
|
std::vector<std::unique_ptr<LogEvent>> CreateLogEvents(int64_t configAddedTimeNs) {
|
|
std::vector<std::unique_ptr<LogEvent>> events;
|
|
events.push_back(CreateNonRestrictedLogEvent(atomTag, configAddedTimeNs + 10 * NS_PER_SEC));
|
|
events.push_back(CreateNonRestrictedLogEvent(atomTag, configAddedTimeNs + 20 * NS_PER_SEC));
|
|
events.push_back(CreateNonRestrictedLogEvent(atomTag, configAddedTimeNs + 30 * NS_PER_SEC));
|
|
return events;
|
|
}
|
|
|
|
} // Anonymous namespace
|
|
|
|
class RestrictedConfigE2ETest : public StatsServiceConfigTest {
|
|
protected:
|
|
shared_ptr<MockStatsQueryCallback> mockStatsQueryCallback;
|
|
const ConfigKey configKey = ConfigKey(kCallingUid, kConfigKey);
|
|
vector<string> queryDataResult;
|
|
vector<string> columnNamesResult;
|
|
vector<int32_t> columnTypesResult;
|
|
int32_t rowCountResult = 0;
|
|
string error;
|
|
|
|
void SetUp() override {
|
|
if (!IsAtLeastU()) {
|
|
GTEST_SKIP();
|
|
}
|
|
StatsServiceConfigTest::SetUp();
|
|
|
|
mockStatsQueryCallback = SharedRefBase::make<StrictMock<MockStatsQueryCallback>>();
|
|
EXPECT_CALL(*mockStatsQueryCallback, sendResults(_, _, _, _))
|
|
.Times(AnyNumber())
|
|
.WillRepeatedly(Invoke(
|
|
[this](const vector<string>& queryData, const vector<string>& columnNames,
|
|
const vector<int32_t>& columnTypes, int32_t rowCount) {
|
|
queryDataResult = queryData;
|
|
columnNamesResult = columnNames;
|
|
columnTypesResult = columnTypes;
|
|
rowCountResult = rowCount;
|
|
error = "";
|
|
return Status::ok();
|
|
}));
|
|
EXPECT_CALL(*mockStatsQueryCallback, sendFailure(_))
|
|
.Times(AnyNumber())
|
|
.WillRepeatedly(Invoke([this](const string& err) {
|
|
error = err;
|
|
queryDataResult.clear();
|
|
columnNamesResult.clear();
|
|
columnTypesResult.clear();
|
|
rowCountResult = 0;
|
|
return Status::ok();
|
|
}));
|
|
|
|
int64_t startTimeNs = getElapsedRealtimeNs();
|
|
service->mUidMap->updateMap(
|
|
startTimeNs, {delegateUid, kCallingUid},
|
|
/*versionCode=*/{1, 1}, /*versionString=*/{String16("v2"), String16("v2")},
|
|
{String16(delegatePackageName.c_str()), String16(configPackageName.c_str())},
|
|
/*installer=*/{String16(), String16()}, /*certificateHash=*/{{}, {}});
|
|
}
|
|
void TearDown() override {
|
|
if (!IsAtLeastU()) {
|
|
GTEST_SKIP();
|
|
}
|
|
Mock::VerifyAndClear(mockStatsQueryCallback.get());
|
|
queryDataResult.clear();
|
|
columnNamesResult.clear();
|
|
columnTypesResult.clear();
|
|
rowCountResult = 0;
|
|
error = "";
|
|
StatsServiceConfigTest::TearDown();
|
|
FlagProvider::getInstance().resetOverrides();
|
|
dbutils::deleteDb(configKey);
|
|
}
|
|
|
|
void verifyRestrictedData(int32_t expectedNumOfMetrics, int64_t metricIdToVerify = metricId,
|
|
bool shouldExist = true) {
|
|
std::stringstream query;
|
|
query << "SELECT * FROM metric_" << dbutils::reformatMetricId(metricIdToVerify);
|
|
string err;
|
|
std::vector<int32_t> columnTypes;
|
|
std::vector<string> columnNames;
|
|
std::vector<std::vector<std::string>> rows;
|
|
if (shouldExist) {
|
|
EXPECT_TRUE(
|
|
dbutils::query(configKey, query.str(), rows, columnTypes, columnNames, err));
|
|
EXPECT_EQ(rows.size(), expectedNumOfMetrics);
|
|
} else {
|
|
// Expect that table is deleted.
|
|
EXPECT_FALSE(
|
|
dbutils::query(configKey, query.str(), rows, columnTypes, columnNames, err));
|
|
}
|
|
}
|
|
};
|
|
|
|
TEST_F(RestrictedConfigE2ETest, RestrictedConfigNoReport) {
|
|
StatsdConfig config = CreateConfigWithOneMetric();
|
|
config.set_restricted_metrics_delegate_package_name("delegate");
|
|
sendConfig(config);
|
|
int64_t configAddedTimeNs = getElapsedRealtimeNs();
|
|
|
|
for (auto& event : CreateLogEvents(configAddedTimeNs)) {
|
|
service->OnLogEvent(event.get());
|
|
}
|
|
|
|
vector<uint8_t> output;
|
|
ConfigKey configKey(kCallingUid, kConfigKey);
|
|
service->getData(kConfigKey, kCallingUid, &output);
|
|
|
|
EXPECT_TRUE(output.empty());
|
|
}
|
|
|
|
TEST_F(RestrictedConfigE2ETest, NonRestrictedConfigGetReport) {
|
|
StatsdConfig config = CreateConfigWithOneMetric();
|
|
sendConfig(config);
|
|
int64_t configAddedTimeNs = getElapsedRealtimeNs();
|
|
|
|
for (auto& event : CreateLogEvents(configAddedTimeNs)) {
|
|
service->OnLogEvent(event.get());
|
|
}
|
|
|
|
ConfigMetricsReport report = getReports(service->mProcessor, /*timestamp=*/10);
|
|
EXPECT_EQ(report.metrics_size(), 1);
|
|
}
|
|
|
|
TEST_F(RestrictedConfigE2ETest, RestrictedShutdownFlushToRestrictedDB) {
|
|
StatsdConfig config = CreateConfigWithOneMetric();
|
|
config.set_restricted_metrics_delegate_package_name("delegate");
|
|
sendConfig(config);
|
|
int64_t configAddedTimeNs = getElapsedRealtimeNs();
|
|
std::vector<std::unique_ptr<LogEvent>> logEvents = CreateLogEvents(configAddedTimeNs);
|
|
for (const auto& e : logEvents) {
|
|
service->OnLogEvent(e.get());
|
|
}
|
|
|
|
service->informDeviceShutdown();
|
|
|
|
// Should not be written to non-restricted storage.
|
|
EXPECT_FALSE(StorageManager::hasConfigMetricsReport(ConfigKey(kCallingUid, kConfigKey)));
|
|
verifyRestrictedData(logEvents.size());
|
|
}
|
|
|
|
TEST_F(RestrictedConfigE2ETest, NonRestrictedOnShutdownWriteDataToDisk) {
|
|
StatsdConfig config = CreateConfigWithOneMetric();
|
|
sendConfig(config);
|
|
int64_t configAddedTimeNs = getElapsedRealtimeNs();
|
|
for (auto& event : CreateLogEvents(configAddedTimeNs)) {
|
|
service->OnLogEvent(event.get());
|
|
}
|
|
|
|
service->informDeviceShutdown();
|
|
|
|
EXPECT_TRUE(StorageManager::hasConfigMetricsReport(ConfigKey(kCallingUid, kConfigKey)));
|
|
}
|
|
|
|
TEST_F(RestrictedConfigE2ETest, RestrictedConfigOnTerminateFlushToRestrictedDB) {
|
|
StatsdConfig config = CreateConfigWithOneMetric();
|
|
config.set_restricted_metrics_delegate_package_name("delegate");
|
|
sendConfig(config);
|
|
int64_t configAddedTimeNs = getElapsedRealtimeNs();
|
|
std::vector<std::unique_ptr<LogEvent>> logEvents = CreateLogEvents(configAddedTimeNs);
|
|
for (auto& event : logEvents) {
|
|
service->OnLogEvent(event.get());
|
|
}
|
|
|
|
service->Terminate();
|
|
|
|
EXPECT_FALSE(StorageManager::hasConfigMetricsReport(ConfigKey(kCallingUid, kConfigKey)));
|
|
verifyRestrictedData(logEvents.size());
|
|
}
|
|
|
|
TEST_F(RestrictedConfigE2ETest, NonRestrictedConfigOnTerminateWriteDataToDisk) {
|
|
StatsdConfig config = CreateConfigWithOneMetric();
|
|
sendConfig(config);
|
|
int64_t configAddedTimeNs = getElapsedRealtimeNs();
|
|
for (auto& event : CreateLogEvents(configAddedTimeNs)) {
|
|
service->OnLogEvent(event.get());
|
|
}
|
|
|
|
service->Terminate();
|
|
|
|
EXPECT_TRUE(StorageManager::hasConfigMetricsReport(ConfigKey(kCallingUid, kConfigKey)));
|
|
}
|
|
|
|
TEST_F(RestrictedConfigE2ETest, RestrictedConfigOnUpdateWithMetricRemoval) {
|
|
StatsdConfig complexConfig = CreateConfigWithTwoMetrics();
|
|
complexConfig.set_restricted_metrics_delegate_package_name(delegatePackageName);
|
|
sendConfig(complexConfig);
|
|
int64_t configAddedTimeNs = getElapsedRealtimeNs();
|
|
std::vector<std::unique_ptr<LogEvent>> logEvents = CreateLogEvents(configAddedTimeNs);
|
|
for (auto& event : logEvents) {
|
|
service->OnLogEvent(event.get());
|
|
}
|
|
|
|
// Use query API to make sure data is flushed.
|
|
std::stringstream query;
|
|
query << "SELECT * FROM metric_" << dbutils::reformatMetricId(metricId);
|
|
service->querySql(query.str(), /*minSqlClientVersion=*/0,
|
|
/*policyConfig=*/{}, mockStatsQueryCallback,
|
|
/*configKey=*/kConfigKey, /*configPackage=*/configPackageName,
|
|
/*callingUid=*/delegateUid);
|
|
EXPECT_EQ(error, "");
|
|
EXPECT_EQ(rowCountResult, logEvents.size());
|
|
verifyRestrictedData(logEvents.size(), anotherMetricId, true);
|
|
|
|
// Update config to have only one metric
|
|
StatsdConfig config = CreateConfigWithOneMetric();
|
|
config.set_restricted_metrics_delegate_package_name(delegatePackageName);
|
|
sendConfig(config);
|
|
|
|
// Make sure metric data is deleted.
|
|
verifyRestrictedData(logEvents.size(), metricId, true);
|
|
verifyRestrictedData(logEvents.size(), anotherMetricId, false);
|
|
}
|
|
|
|
TEST_F(RestrictedConfigE2ETest, TestSendRestrictedMetricsChangedBroadcast) {
|
|
vector<int64_t> receivedMetricIds;
|
|
int receiveCount = 0;
|
|
shared_ptr<MockPendingIntentRef> pir = SharedRefBase::make<StrictMock<MockPendingIntentRef>>();
|
|
EXPECT_CALL(*pir, sendRestrictedMetricsChangedBroadcast(_))
|
|
.Times(7)
|
|
.WillRepeatedly(Invoke([&receivedMetricIds, &receiveCount](const vector<int64_t>& ids) {
|
|
receiveCount++;
|
|
receivedMetricIds = ids;
|
|
return Status::ok();
|
|
}));
|
|
|
|
// Set the operation. No configs present so empty list is returned.
|
|
vector<int64_t> returnedMetricIds;
|
|
service->setRestrictedMetricsChangedOperation(kConfigKey, configPackageName, pir, delegateUid,
|
|
&returnedMetricIds);
|
|
EXPECT_EQ(receiveCount, 0);
|
|
EXPECT_THAT(returnedMetricIds, IsEmpty());
|
|
|
|
// Add restricted config. Should receive one metric
|
|
StatsdConfig config = CreateConfigWithOneMetric();
|
|
config.set_restricted_metrics_delegate_package_name(delegatePackageName);
|
|
sendConfig(config);
|
|
EXPECT_EQ(receiveCount, 1);
|
|
EXPECT_THAT(receivedMetricIds, UnorderedElementsAre(metricId));
|
|
|
|
// Config update, should receive two metrics.
|
|
config = CreateConfigWithTwoMetrics();
|
|
config.set_restricted_metrics_delegate_package_name(delegatePackageName);
|
|
sendConfig(config);
|
|
EXPECT_EQ(receiveCount, 2);
|
|
EXPECT_THAT(receivedMetricIds, UnorderedElementsAre(metricId, anotherMetricId));
|
|
|
|
// Make config unrestricted. Should receive empty list.
|
|
config.clear_restricted_metrics_delegate_package_name();
|
|
sendConfig(config);
|
|
EXPECT_EQ(receiveCount, 3);
|
|
EXPECT_THAT(receivedMetricIds, IsEmpty());
|
|
|
|
// Update the unrestricted config. Nothing should be sent.
|
|
config = CreateConfigWithOneMetric();
|
|
sendConfig(config);
|
|
|
|
// Update config and make it restricted. Should receive one metric.
|
|
config.set_restricted_metrics_delegate_package_name(delegatePackageName);
|
|
sendConfig(config);
|
|
EXPECT_EQ(receiveCount, 4);
|
|
EXPECT_THAT(receivedMetricIds, UnorderedElementsAre(metricId));
|
|
|
|
// Send an invalid config. Should receive empty list.
|
|
config.clear_allowed_log_source();
|
|
sendConfig(config);
|
|
EXPECT_EQ(receiveCount, 5);
|
|
EXPECT_THAT(receivedMetricIds, IsEmpty());
|
|
|
|
service->removeRestrictedMetricsChangedOperation(kConfigKey, configPackageName, delegateUid);
|
|
|
|
// Nothing should be sent since the operation is removed.
|
|
config = CreateConfigWithTwoMetrics();
|
|
config.set_restricted_metrics_delegate_package_name(delegatePackageName);
|
|
sendConfig(config);
|
|
|
|
// Set the operation. Two metrics should be returned.
|
|
returnedMetricIds.clear();
|
|
service->setRestrictedMetricsChangedOperation(kConfigKey, configPackageName, pir, delegateUid,
|
|
&returnedMetricIds);
|
|
EXPECT_THAT(returnedMetricIds, UnorderedElementsAre(metricId, anotherMetricId));
|
|
EXPECT_EQ(receiveCount, 5);
|
|
|
|
// Config update, should receive two metrics.
|
|
config = CreateConfigWithOneMetric();
|
|
config.set_restricted_metrics_delegate_package_name(delegatePackageName);
|
|
sendConfig(config);
|
|
EXPECT_EQ(receiveCount, 6);
|
|
EXPECT_THAT(receivedMetricIds, UnorderedElementsAre(metricId));
|
|
|
|
// Remove the config and verify an empty list is received
|
|
service->removeConfiguration(kConfigKey, kCallingUid);
|
|
EXPECT_EQ(receiveCount, 7);
|
|
EXPECT_THAT(receivedMetricIds, IsEmpty());
|
|
|
|
// Cleanup.
|
|
service->removeRestrictedMetricsChangedOperation(kConfigKey, configPackageName, delegateUid);
|
|
}
|
|
|
|
TEST_F(RestrictedConfigE2ETest, TestSendRestrictedMetricsChangedBroadcastMultipleListeners) {
|
|
const string configPackageName2 = "com.test.config.package2";
|
|
const int32_t delegateUid2 = delegateUid + 1, delegateUid3 = delegateUid + 2;
|
|
service->informOnePackage(configPackageName2, kCallingUid, 0, "", "", {});
|
|
service->informOnePackage(delegatePackageName, delegateUid2, 0, "", "", {});
|
|
service->informOnePackage("not.a.good.package", delegateUid3, 0, "", "", {});
|
|
|
|
vector<int64_t> receivedMetricIds;
|
|
int receiveCount = 0;
|
|
shared_ptr<MockPendingIntentRef> pir = SharedRefBase::make<StrictMock<MockPendingIntentRef>>();
|
|
EXPECT_CALL(*pir, sendRestrictedMetricsChangedBroadcast(_))
|
|
.Times(2)
|
|
.WillRepeatedly(Invoke([&receivedMetricIds, &receiveCount](const vector<int64_t>& ids) {
|
|
receiveCount++;
|
|
receivedMetricIds = ids;
|
|
return Status::ok();
|
|
}));
|
|
|
|
int receiveCount2 = 0;
|
|
vector<int64_t> receivedMetricIds2;
|
|
shared_ptr<MockPendingIntentRef> pir2 = SharedRefBase::make<StrictMock<MockPendingIntentRef>>();
|
|
EXPECT_CALL(*pir2, sendRestrictedMetricsChangedBroadcast(_))
|
|
.Times(2)
|
|
.WillRepeatedly(
|
|
Invoke([&receivedMetricIds2, &receiveCount2](const vector<int64_t>& ids) {
|
|
receiveCount2++;
|
|
receivedMetricIds2 = ids;
|
|
return Status::ok();
|
|
}));
|
|
|
|
// This one should never be called.
|
|
shared_ptr<MockPendingIntentRef> pir3 = SharedRefBase::make<StrictMock<MockPendingIntentRef>>();
|
|
EXPECT_CALL(*pir3, sendRestrictedMetricsChangedBroadcast(_)).Times(0);
|
|
|
|
// Set the operations. No configs present so empty list is returned.
|
|
vector<int64_t> returnedMetricIds;
|
|
service->setRestrictedMetricsChangedOperation(kConfigKey, configPackageName, pir, delegateUid,
|
|
&returnedMetricIds);
|
|
EXPECT_EQ(receiveCount, 0);
|
|
EXPECT_THAT(returnedMetricIds, IsEmpty());
|
|
|
|
vector<int64_t> returnedMetricIds2;
|
|
service->setRestrictedMetricsChangedOperation(kConfigKey, configPackageName2, pir2,
|
|
delegateUid2, &returnedMetricIds2);
|
|
EXPECT_EQ(receiveCount2, 0);
|
|
EXPECT_THAT(returnedMetricIds2, IsEmpty());
|
|
|
|
// Represents a package listening for changes but doesn't match the restricted package in the
|
|
// config.
|
|
vector<int64_t> returnedMetricIds3;
|
|
service->setRestrictedMetricsChangedOperation(kConfigKey, configPackageName, pir3, delegateUid3,
|
|
&returnedMetricIds3);
|
|
EXPECT_THAT(returnedMetricIds3, IsEmpty());
|
|
|
|
// Add restricted config. Should receive one metric on pir1 and 2.
|
|
StatsdConfig config = CreateConfigWithOneMetric();
|
|
config.set_restricted_metrics_delegate_package_name(delegatePackageName);
|
|
sendConfig(config);
|
|
EXPECT_EQ(receiveCount, 1);
|
|
EXPECT_THAT(receivedMetricIds, UnorderedElementsAre(metricId));
|
|
EXPECT_EQ(receiveCount2, 1);
|
|
EXPECT_THAT(receivedMetricIds2, UnorderedElementsAre(metricId));
|
|
|
|
// Config update, should receive two metrics on pir1 and 2.
|
|
config = CreateConfigWithTwoMetrics();
|
|
config.set_restricted_metrics_delegate_package_name(delegatePackageName);
|
|
sendConfig(config);
|
|
EXPECT_EQ(receiveCount, 2);
|
|
EXPECT_THAT(receivedMetricIds, UnorderedElementsAre(metricId, anotherMetricId));
|
|
EXPECT_EQ(receiveCount2, 2);
|
|
EXPECT_THAT(receivedMetricIds2, UnorderedElementsAre(metricId, anotherMetricId));
|
|
|
|
// Cleanup.
|
|
service->removeRestrictedMetricsChangedOperation(kConfigKey, configPackageName, delegateUid);
|
|
service->removeRestrictedMetricsChangedOperation(kConfigKey, configPackageName2, delegateUid2);
|
|
service->removeRestrictedMetricsChangedOperation(kConfigKey, configPackageName, delegateUid3);
|
|
}
|
|
|
|
TEST_F(RestrictedConfigE2ETest, TestSendRestrictedMetricsChangedBroadcastMultipleMatchedConfigs) {
|
|
const int32_t callingUid2 = kCallingUid + 1;
|
|
service->informOnePackage(configPackageName, callingUid2, 0, "", "", {});
|
|
|
|
// Add restricted config.
|
|
StatsdConfig config = CreateConfigWithOneMetric();
|
|
config.set_restricted_metrics_delegate_package_name(delegatePackageName);
|
|
sendConfig(config);
|
|
|
|
// Add a second config.
|
|
const int64_t metricId2 = 42;
|
|
config.mutable_event_metric(0)->set_id(42);
|
|
string str;
|
|
config.SerializeToString(&str);
|
|
std::vector<uint8_t> configAsVec(str.begin(), str.end());
|
|
service->addConfiguration(kConfigKey, configAsVec, callingUid2);
|
|
|
|
// Set the operation. Matches multiple configs so a union of metrics are returned.
|
|
shared_ptr<MockPendingIntentRef> pir = SharedRefBase::make<StrictMock<MockPendingIntentRef>>();
|
|
vector<int64_t> returnedMetricIds;
|
|
service->setRestrictedMetricsChangedOperation(kConfigKey, configPackageName, pir, delegateUid,
|
|
&returnedMetricIds);
|
|
EXPECT_THAT(returnedMetricIds, UnorderedElementsAre(metricId, metricId2));
|
|
|
|
// Cleanup.
|
|
service->removeRestrictedMetricsChangedOperation(kConfigKey, configPackageName, delegateUid);
|
|
|
|
ConfigKey cfgKey(callingUid2, kConfigKey);
|
|
service->removeConfiguration(kConfigKey, callingUid2);
|
|
service->mProcessor->onDumpReport(cfgKey, getElapsedRealtimeNs(),
|
|
false /* include_current_bucket*/, true /* erase_data */,
|
|
ADB_DUMP, NO_TIME_CONSTRAINTS, nullptr);
|
|
}
|
|
#else
|
|
GTEST_LOG_(INFO) << "This test does nothing.\n";
|
|
#endif
|
|
|
|
} // namespace statsd
|
|
} // namespace os
|
|
} // namespace android
|