Merge "Move statsd (and tests) to libbinder_ndk"

This commit is contained in:
TreeHugger Robot
2020-02-17 01:11:32 +00:00
committed by Android (Google) Code Review
38 changed files with 711 additions and 669 deletions

View File

@@ -123,11 +123,11 @@ cc_defaults {
"libutils",
],
shared_libs: [
"libbinder",
"libbinder_ndk",
"libincident",
"liblog",
"libstatssocket",
"statsd-aidl-cpp",
"statsd-aidl-ndk_platform",
],
}

View File

@@ -25,6 +25,7 @@ namespace statsd {
using std::string;
using std::vector;
using android::base::StringPrintf;
// These constants must be kept in sync with those in StatsDimensionsValue.java
const static int STATS_DIMENSIONS_VALUE_STRING_TYPE = 2;
@@ -73,7 +74,7 @@ static void populateStatsDimensionsValueParcelChildren(StatsDimensionsValueParce
break;
case STRING:
childParcel.valueType = STATS_DIMENSIONS_VALUE_STRING_TYPE;
childParcel.stringValue = String16(dim.mValue.str_value.c_str());
childParcel.stringValue = dim.mValue.str_value;
break;
default:
ALOGE("Encountered FieldValue with unsupported value type.");

View File

@@ -16,7 +16,7 @@
#pragma once
#include <android/os/StatsDimensionsValueParcel.h>
#include <aidl/android/os/StatsDimensionsValueParcel.h>
#include <utils/JenkinsHash.h>
#include <vector>
#include "android-base/stringprintf.h"
@@ -27,7 +27,7 @@ namespace android {
namespace os {
namespace statsd {
using android::base::StringPrintf;
using ::aidl::android::os::StatsDimensionsValueParcel;
struct Metric2Condition {
int64_t conditionId;

View File

@@ -28,8 +28,6 @@
#include <android-base/file.h>
#include <android-base/strings.h>
#include <binder/IPCThreadState.h>
#include <binder/PermissionController.h>
#include <cutils/multiuser.h>
#include <frameworks/base/cmds/statsd/src/statsd_config.pb.h>
#include <frameworks/base/cmds/statsd/src/uid_data.pb.h>
@@ -47,85 +45,42 @@ using android::base::StringPrintf;
using android::util::FIELD_COUNT_REPEATED;
using android::util::FIELD_TYPE_MESSAGE;
using Status = ::ndk::ScopedAStatus;
namespace android {
namespace os {
namespace statsd {
constexpr const char* kPermissionDump = "android.permission.DUMP";
constexpr const char* kPermissionUsage = "android.permission.PACKAGE_USAGE_STATS";
constexpr const char* kOpUsage = "android:get_usage_stats";
#define STATS_SERVICE_DIR "/data/misc/stats-service"
// for StatsDataDumpProto
const int FIELD_ID_REPORTS_LIST = 1;
static binder::Status ok() {
return binder::Status::ok();
}
static binder::Status exception(uint32_t code, const std::string& msg) {
static Status exception(int32_t code, const std::string& msg) {
ALOGE("%s (%d)", msg.c_str(), code);
return binder::Status::fromExceptionCode(code, String8(msg.c_str()));
return ::ndk::ScopedAStatus(AStatus_fromExceptionCodeWithMessage(code, msg.c_str()));
}
static bool checkPermission(const char* permission) {
pid_t pid = IPCThreadState::self()->getCallingPid();
uid_t uid = IPCThreadState::self()->getCallingUid();
pid_t pid = AIBinder_getCallingPid();
uid_t uid = AIBinder_getCallingUid();
return checkPermissionForIds(permission, pid, uid);
}
binder::Status checkUid(uid_t expectedUid) {
uid_t uid = IPCThreadState::self()->getCallingUid();
Status checkUid(uid_t expectedUid) {
uid_t uid = AIBinder_getCallingUid();
if (uid == expectedUid || uid == AID_ROOT) {
return ok();
return Status::ok();
} else {
return exception(binder::Status::EX_SECURITY,
StringPrintf("UID %d is not expected UID %d", uid, expectedUid));
}
}
binder::Status checkDumpAndUsageStats(const String16& packageName) {
pid_t pid = IPCThreadState::self()->getCallingPid();
uid_t uid = IPCThreadState::self()->getCallingUid();
// Root, system, and shell always have access
if (uid == AID_ROOT || uid == AID_SYSTEM || uid == AID_SHELL) {
return ok();
}
// Caller must be granted these permissions
if (!checkPermission(kPermissionDump)) {
return exception(binder::Status::EX_SECURITY,
StringPrintf("UID %d / PID %d lacks permission %s", uid, pid, kPermissionDump));
}
if (!checkPermission(kPermissionUsage)) {
return exception(binder::Status::EX_SECURITY,
StringPrintf("UID %d / PID %d lacks permission %s", uid, pid, kPermissionUsage));
}
// Caller must also have usage stats op granted
PermissionController pc;
switch (pc.noteOp(String16(kOpUsage), uid, packageName)) {
case PermissionController::MODE_ALLOWED:
case PermissionController::MODE_DEFAULT:
return ok();
default:
return exception(binder::Status::EX_SECURITY,
StringPrintf("UID %d / PID %d lacks app-op %s", uid, pid, kOpUsage));
return exception(EX_SECURITY,
StringPrintf("UID %d is not expected UID %d", uid, expectedUid));
}
}
#define ENFORCE_UID(uid) { \
binder::Status status = checkUid((uid)); \
if (!status.isOk()) { \
return status; \
} \
}
#define ENFORCE_DUMP_AND_USAGE_STATS(packageName) { \
binder::Status status = checkDumpAndUsageStats(packageName); \
Status status = checkUid((uid)); \
if (!status.isOk()) { \
return status; \
} \
@@ -134,13 +89,13 @@ binder::Status checkDumpAndUsageStats(const String16& packageName) {
StatsService::StatsService(const sp<Looper>& handlerLooper, shared_ptr<LogEventQueue> queue)
: mAnomalyAlarmMonitor(new AlarmMonitor(
MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS,
[](const sp<IStatsCompanionService>& sc, int64_t timeMillis) {
[](const shared_ptr<IStatsCompanionService>& sc, int64_t timeMillis) {
if (sc != nullptr) {
sc->setAnomalyAlarm(timeMillis);
StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
}
},
[](const sp<IStatsCompanionService>& sc) {
[](const shared_ptr<IStatsCompanionService>& sc) {
if (sc != nullptr) {
sc->cancelAnomalyAlarm();
StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
@@ -148,19 +103,21 @@ StatsService::StatsService(const sp<Looper>& handlerLooper, shared_ptr<LogEventQ
})),
mPeriodicAlarmMonitor(new AlarmMonitor(
MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS,
[](const sp<IStatsCompanionService>& sc, int64_t timeMillis) {
[](const shared_ptr<IStatsCompanionService>& sc, int64_t timeMillis) {
if (sc != nullptr) {
sc->setAlarmForSubscriberTriggering(timeMillis);
StatsdStats::getInstance().noteRegisteredPeriodicAlarmChanged();
}
},
[](const sp<IStatsCompanionService>& sc) {
[](const shared_ptr<IStatsCompanionService>& sc) {
if (sc != nullptr) {
sc->cancelAlarmForSubscriberTriggering();
StatsdStats::getInstance().noteRegisteredPeriodicAlarmChanged();
}
})),
mEventQueue(queue) {
mEventQueue(queue),
mStatsCompanionServiceDeathRecipient(AIBinder_DeathRecipient_new(
StatsService::statsCompanionServiceDied)) {
mUidMap = UidMap::getInstance();
mPullerManager = new StatsPullerManager();
StatsPuller::SetUidMap(mUidMap);
@@ -169,22 +126,20 @@ StatsService::StatsService(const sp<Looper>& handlerLooper, shared_ptr<LogEventQ
mUidMap, mPullerManager, mAnomalyAlarmMonitor, mPeriodicAlarmMonitor,
getElapsedRealtimeNs(),
[this](const ConfigKey& key) {
sp<IPendingIntentRef> receiver = mConfigManager->GetConfigReceiver(key);
shared_ptr<IPendingIntentRef> receiver = mConfigManager->GetConfigReceiver(key);
if (receiver == nullptr) {
VLOG("Could not find a broadcast receiver for %s",
key.ToString().c_str());
VLOG("Could not find a broadcast receiver for %s", key.ToString().c_str());
return false;
} else if (receiver->sendDataBroadcast(
mProcessor->getLastReportTimeNs(key)).isOk()) {
return true;
} else {
VLOG("Failed to send a broadcast for receiver %s",
key.ToString().c_str());
VLOG("Failed to send a broadcast for receiver %s", key.ToString().c_str());
return false;
}
},
[this](const int& uid, const vector<int64_t>& activeConfigs) {
sp<IPendingIntentRef> receiver =
shared_ptr<IPendingIntentRef> receiver =
mConfigManager->GetActiveConfigsChangedReceiver(uid);
if (receiver == nullptr) {
VLOG("Could not find receiver for uid %d", uid);
@@ -244,36 +199,6 @@ void StatsService::init_build_type_callback(void* cookie, const char* /*name*/,
}
}
/**
* Implement our own because the default binder implementation isn't
* properly handling SHELL_COMMAND_TRANSACTION.
*/
status_t StatsService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
uint32_t flags) {
switch (code) {
case SHELL_COMMAND_TRANSACTION: {
int in = data.readFileDescriptor();
int out = data.readFileDescriptor();
int err = data.readFileDescriptor();
int argc = data.readInt32();
Vector<String8> args;
for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
args.add(String8(data.readString16()));
}
sp<IShellCallback> shellCallback = IShellCallback::asInterface(data.readStrongBinder());
sp<IResultReceiver> resultReceiver =
IResultReceiver::asInterface(data.readStrongBinder());
err = command(in, out, err, args, resultReceiver);
if (resultReceiver != nullptr) {
resultReceiver->send(err);
}
return NO_ERROR;
}
default: { return BnStatsd::onTransact(code, data, reply, flags); }
}
}
/**
* Write data from statsd.
* Format for statsdStats: adb shell dumpsys stats --metadata [-v] [--proto]
@@ -283,20 +208,21 @@ status_t StatsService::onTransact(uint32_t code, const Parcel& data, Parcel* rep
* (bugreports call "adb shell dumpsys stats --dump-priority NORMAL -a --proto")
* TODO: Come up with a more robust method of enacting <serviceutils/PriorityDumper.h>.
*/
status_t StatsService::dump(int fd, const Vector<String16>& args) {
status_t StatsService::dump(int fd, const char** args, uint32_t numArgs) {
if (!checkPermission(kPermissionDump)) {
return PERMISSION_DENIED;
}
int lastArg = args.size() - 1;
int lastArg = numArgs - 1;
bool asProto = false;
if (lastArg >= 0 && !args[lastArg].compare(String16("--proto"))) { // last argument
if (lastArg >= 0 && string(args[lastArg]) == "--proto") { // last argument
asProto = true;
lastArg--;
}
if (args.size() > 0 && !args[0].compare(String16("--metadata"))) { // first argument
if (numArgs > 0 && string(args[0]) == "--metadata") { // first argument
// Request is to dump statsd stats.
bool verbose = false;
if (lastArg >= 0 && !args[lastArg].compare(String16("-v"))) {
if (lastArg >= 0 && string(args[lastArg]) == "-v") {
verbose = true;
lastArg--;
}
@@ -351,67 +277,72 @@ void StatsService::dumpIncidentSection(int out) {
/**
* Implementation of the adb shell cmd stats command.
*/
status_t StatsService::command(int in, int out, int err, Vector<String8>& args,
sp<IResultReceiver> resultReceiver) {
uid_t uid = IPCThreadState::self()->getCallingUid();
if (uid != AID_ROOT && uid != AID_SHELL) {
status_t StatsService::handleShellCommand(int in, int out, int err, const char** argv,
uint32_t argc) {
uid_t uid = AIBinder_getCallingUid();
if (uid != AID_ROOT || uid != AID_SHELL) {
return PERMISSION_DENIED;
}
const int argCount = args.size();
if (argCount >= 1) {
Vector<String8> utf8Args;
utf8Args.setCapacity(argc);
for (uint32_t i = 0; i < argc; i++) {
utf8Args.push(String8(argv[i]));
}
if (argc >= 1) {
// adb shell cmd stats config ...
if (!args[0].compare(String8("config"))) {
return cmd_config(in, out, err, args);
if (!utf8Args[0].compare(String8("config"))) {
return cmd_config(in, out, err, utf8Args);
}
if (!args[0].compare(String8("print-uid-map"))) {
return cmd_print_uid_map(out, args);
if (!utf8Args[0].compare(String8("print-uid-map"))) {
return cmd_print_uid_map(out, utf8Args);
}
if (!args[0].compare(String8("dump-report"))) {
return cmd_dump_report(out, args);
if (!utf8Args[0].compare(String8("dump-report"))) {
return cmd_dump_report(out, utf8Args);
}
if (!args[0].compare(String8("pull-source")) && args.size() > 1) {
return cmd_print_pulled_metrics(out, args);
if (!utf8Args[0].compare(String8("pull-source")) && argc > 1) {
return cmd_print_pulled_metrics(out, utf8Args);
}
if (!args[0].compare(String8("send-broadcast"))) {
return cmd_trigger_broadcast(out, args);
if (!utf8Args[0].compare(String8("send-broadcast"))) {
return cmd_trigger_broadcast(out, utf8Args);
}
if (!args[0].compare(String8("print-stats"))) {
return cmd_print_stats(out, args);
if (!utf8Args[0].compare(String8("print-stats"))) {
return cmd_print_stats(out, utf8Args);
}
if (!args[0].compare(String8("meminfo"))) {
if (!utf8Args[0].compare(String8("meminfo"))) {
return cmd_dump_memory_info(out);
}
if (!args[0].compare(String8("write-to-disk"))) {
if (!utf8Args[0].compare(String8("write-to-disk"))) {
return cmd_write_data_to_disk(out);
}
if (!args[0].compare(String8("log-app-breadcrumb"))) {
return cmd_log_app_breadcrumb(out, args);
if (!utf8Args[0].compare(String8("log-app-breadcrumb"))) {
return cmd_log_app_breadcrumb(out, utf8Args);
}
if (!args[0].compare(String8("log-binary-push"))) {
return cmd_log_binary_push(out, args);
if (!utf8Args[0].compare(String8("log-binary-push"))) {
return cmd_log_binary_push(out, utf8Args);
}
if (!args[0].compare(String8("clear-puller-cache"))) {
if (!utf8Args[0].compare(String8("clear-puller-cache"))) {
return cmd_clear_puller_cache(out);
}
if (!args[0].compare(String8("print-logs"))) {
return cmd_print_logs(out, args);
if (!utf8Args[0].compare(String8("print-logs"))) {
return cmd_print_logs(out, utf8Args);
}
if (!args[0].compare(String8("send-active-configs"))) {
return cmd_trigger_active_config_broadcast(out, args);
if (!utf8Args[0].compare(String8("send-active-configs"))) {
return cmd_trigger_active_config_broadcast(out, utf8Args);
}
if (!args[0].compare(String8("data-subscribe"))) {
if (!utf8Args[0].compare(String8("data-subscribe"))) {
{
std::lock_guard<std::mutex> lock(mShellSubscriberMutex);
if (mShellSubscriber == nullptr) {
@@ -419,14 +350,10 @@ status_t StatsService::command(int in, int out, int err, Vector<String8>& args,
}
}
int timeoutSec = -1;
if (argCount >= 2) {
timeoutSec = atoi(args[1].c_str());
if (argc >= 2) {
timeoutSec = atoi(utf8Args[1].c_str());
}
if (resultReceiver == nullptr) {
ALOGI("Null resultReceiver given, no subscription will be started");
return UNEXPECTED_NULL;
}
mShellSubscriber->startNewSubscription(in, out, resultReceiver, timeoutSec);
mShellSubscriber->startNewSubscription(in, out, timeoutSec);
return NO_ERROR;
}
}
@@ -556,7 +483,7 @@ status_t StatsService::cmd_trigger_broadcast(int out, Vector<String8>& args) {
const int argCount = args.size();
if (argCount == 2) {
// Automatically pick the UID
uid = IPCThreadState::self()->getCallingUid();
uid = AIBinder_getCallingUid();
name.assign(args[1].c_str(), args[1].size());
good = true;
} else if (argCount == 3) {
@@ -572,17 +499,15 @@ status_t StatsService::cmd_trigger_broadcast(int out, Vector<String8>& args) {
return UNKNOWN_ERROR;
}
ConfigKey key(uid, StrToInt64(name));
sp<IPendingIntentRef> receiver = mConfigManager->GetConfigReceiver(key);
shared_ptr<IPendingIntentRef> receiver = mConfigManager->GetConfigReceiver(key);
if (receiver == nullptr) {
VLOG("Could not find receiver for %s, %s", args[1].c_str(), args[2].c_str());
return UNKNOWN_ERROR;
} else if (receiver->sendDataBroadcast(
mProcessor->getLastReportTimeNs(key)).isOk()) {
} else if (receiver->sendDataBroadcast(mProcessor->getLastReportTimeNs(key)).isOk()) {
VLOG("StatsService::trigger broadcast succeeded to %s, %s", args[1].c_str(),
args[2].c_str());
} else {
VLOG("StatsService::trigger broadcast failed to %s, %s", args[1].c_str(),
args[2].c_str());
VLOG("StatsService::trigger broadcast failed to %s, %s", args[1].c_str(), args[2].c_str());
return UNKNOWN_ERROR;
}
return NO_ERROR;
@@ -594,7 +519,7 @@ status_t StatsService::cmd_trigger_active_config_broadcast(int out, Vector<Strin
vector<int64_t> configIds;
if (argCount == 1) {
// Automatically pick the uid and send a broadcast that has no active configs.
uid = IPCThreadState::self()->getCallingUid();
uid = AIBinder_getCallingUid();
mProcessor->GetActiveConfigs(uid, configIds);
} else {
int curArg = 1;
@@ -608,7 +533,7 @@ status_t StatsService::cmd_trigger_active_config_broadcast(int out, Vector<Strin
}
curArg++;
} else {
uid = IPCThreadState::self()->getCallingUid();
uid = AIBinder_getCallingUid();
}
if (curArg == argCount || args[curArg] != "--configs") {
VLOG("Reached end of args, or specify configs not set. Sending actual active configs,");
@@ -628,7 +553,7 @@ status_t StatsService::cmd_trigger_active_config_broadcast(int out, Vector<Strin
}
}
}
sp<IPendingIntentRef> receiver = mConfigManager->GetActiveConfigsChangedReceiver(uid);
shared_ptr<IPendingIntentRef> receiver = mConfigManager->GetActiveConfigsChangedReceiver(uid);
if (receiver == nullptr) {
VLOG("Could not find receiver for uid %d", uid);
return UNKNOWN_ERROR;
@@ -651,7 +576,7 @@ status_t StatsService::cmd_config(int in, int out, int err, Vector<String8>& arg
if (argCount == 3) {
// Automatically pick the UID
uid = IPCThreadState::self()->getCallingUid();
uid = AIBinder_getCallingUid();
name.assign(args[2].c_str(), args[2].size());
good = true;
} else if (argCount == 4) {
@@ -734,7 +659,7 @@ status_t StatsService::cmd_dump_report(int out, const Vector<String8>& args) {
}
if (argCount == 2) {
// Automatically pick the UID
uid = IPCThreadState::self()->getCallingUid();
uid = AIBinder_getCallingUid();
name.assign(args[1].c_str(), args[1].size());
good = true;
} else if (argCount == 3) {
@@ -826,7 +751,7 @@ status_t StatsService::cmd_log_app_breadcrumb(int out, const Vector<String8>& ar
const int argCount = args.size();
if (argCount == 3) {
// Automatically pick the UID
uid = IPCThreadState::self()->getCallingUid();
uid = AIBinder_getCallingUid();
label = atoi(args[1].c_str());
state = atoi(args[2].c_str());
good = true;
@@ -903,9 +828,8 @@ status_t StatsService::cmd_dump_memory_info(int out) {
}
status_t StatsService::cmd_clear_puller_cache(int out) {
IPCThreadState* ipc = IPCThreadState::self();
VLOG("StatsService::cmd_clear_puller_cache with Pid %i, Uid %i",
ipc->getCallingPid(), ipc->getCallingUid());
AIBinder_getCallingPid(), AIBinder_getCallingUid());
if (checkPermission(kPermissionDump)) {
int cleared = mPullerManager->ForceClearPullerCache();
dprintf(out, "Puller removed %d cached data!\n", cleared);
@@ -916,9 +840,8 @@ status_t StatsService::cmd_clear_puller_cache(int out) {
}
status_t StatsService::cmd_print_logs(int out, const Vector<String8>& args) {
IPCThreadState* ipc = IPCThreadState::self();
VLOG("StatsService::cmd_print_logs with Pid %i, Uid %i", ipc->getCallingPid(),
ipc->getCallingUid());
VLOG("StatsService::cmd_print_logs with Pid %i, Uid %i", AIBinder_getCallingPid(),
AIBinder_getCallingUid());
if (checkPermission(kPermissionDump)) {
bool enabled = true;
if (args.size() >= 2) {
@@ -950,24 +873,24 @@ bool StatsService::getUidFromString(const char* s, int32_t& uid) {
}
uid = goodUid;
int32_t callingUid = IPCThreadState::self()->getCallingUid();
int32_t callingUid = AIBinder_getCallingUid();
return mEngBuild // UserDebug/EngBuild are allowed to impersonate uids.
|| (callingUid == goodUid) // Anyone can 'impersonate' themselves.
|| (callingUid == AID_ROOT && goodUid == AID_SHELL); // ROOT can impersonate SHELL.
}
Status StatsService::informAllUidData(const ParcelFileDescriptor& fd) {
Status StatsService::informAllUidData(const ScopedFileDescriptor& fd) {
ENFORCE_UID(AID_SYSTEM);
// Read stream into buffer.
string buffer;
if (!android::base::ReadFdToString(fd.get(), &buffer)) {
return exception(Status::EX_ILLEGAL_ARGUMENT, "Failed to read all data from the pipe.");
return exception(EX_ILLEGAL_ARGUMENT, "Failed to read all data from the pipe.");
}
// Parse buffer.
UidData uidData;
if (!uidData.ParseFromString(buffer)) {
return exception(Status::EX_ILLEGAL_ARGUMENT, "Error parsing proto stream for UidData.");
return exception(EX_ILLEGAL_ARGUMENT, "Error parsing proto stream for UidData.");
}
vector<String16> versionStrings;
@@ -1002,20 +925,28 @@ Status StatsService::informAllUidData(const ParcelFileDescriptor& fd) {
return Status::ok();
}
Status StatsService::informOnePackage(const String16& app, int32_t uid, int64_t version,
const String16& version_string, const String16& installer) {
Status StatsService::informOnePackage(const string& app, int32_t uid, int64_t version,
const string& versionString, const string& installer) {
ENFORCE_UID(AID_SYSTEM);
VLOG("StatsService::informOnePackage was called");
mUidMap->updateApp(getElapsedRealtimeNs(), app, uid, version, version_string, installer);
// TODO(b/149254662): This is gross. We should consider changing statsd
// internals to use std::string.
String16 utf16App = String16(app.c_str());
String16 utf16VersionString = String16(versionString.c_str());
String16 utf16Installer = String16(installer.c_str());
mUidMap->updateApp(getElapsedRealtimeNs(), utf16App, uid, version, utf16VersionString,
utf16Installer);
return Status::ok();
}
Status StatsService::informOnePackageRemoved(const String16& app, int32_t uid) {
Status StatsService::informOnePackageRemoved(const string& app, int32_t uid) {
ENFORCE_UID(AID_SYSTEM);
VLOG("StatsService::informOnePackageRemoved was called");
mUidMap->removeApp(getElapsedRealtimeNs(), app, uid);
String16 utf16App = String16(app.c_str());
mUidMap->removeApp(getElapsedRealtimeNs(), utf16App, uid);
mConfigManager->RemoveConfigs(uid);
return Status::ok();
}
@@ -1079,7 +1010,7 @@ Status StatsService::informDeviceShutdown() {
}
void StatsService::sayHiToStatsCompanion() {
sp<IStatsCompanionService> statsCompanion = getStatsCompanionService();
shared_ptr<IStatsCompanionService> statsCompanion = getStatsCompanionService();
if (statsCompanion != nullptr) {
VLOG("Telling statsCompanion that statsd is ready");
statsCompanion->statsdReady();
@@ -1092,14 +1023,14 @@ Status StatsService::statsCompanionReady() {
ENFORCE_UID(AID_SYSTEM);
VLOG("StatsService::statsCompanionReady was called");
sp<IStatsCompanionService> statsCompanion = getStatsCompanionService();
shared_ptr<IStatsCompanionService> statsCompanion = getStatsCompanionService();
if (statsCompanion == nullptr) {
return Status::fromExceptionCode(
Status::EX_NULL_POINTER,
"statscompanion unavailable despite it contacting statsd!");
return exception(EX_NULL_POINTER,
"StatsCompanion unavailable despite it contacting statsd.");
}
VLOG("StatsService::statsCompanionReady linking to statsCompanion.");
IInterface::asBinder(statsCompanion)->linkToDeath(this);
AIBinder_linkToDeath(statsCompanion->asBinder().get(),
mStatsCompanionServiceDeathRecipient.get(), this);
mPullerManager->SetStatsCompanionService(statsCompanion);
mAnomalyAlarmMonitor->setStatsCompanionService(statsCompanion);
mPeriodicAlarmMonitor->setStatsCompanionService(statsCompanion);
@@ -1127,39 +1058,47 @@ void StatsService::OnLogEvent(LogEvent* event) {
}
}
Status StatsService::getData(int64_t key, const int32_t callingUid, vector<uint8_t>* output) {
Status StatsService::getData(int64_t key, const int32_t callingUid, vector<int8_t>* output) {
ENFORCE_UID(AID_SYSTEM);
VLOG("StatsService::getData with Uid %i", callingUid);
ConfigKey configKey(callingUid, key);
// TODO(b/149254662): Since libbinder_ndk uses int8_t instead of uint8_t,
// there are inconsistencies with internal statsd logic. Instead of
// modifying lots of files, we create a temporary output array of int8_t and
// copy its data into output. This is a bad hack, but hopefully
// libbinder_ndk will transition to using uint8_t soon: progress is tracked
// in b/144957764. Same applies to StatsService::getMetadata.
vector<uint8_t> unsignedOutput;
// The dump latency does not matter here since we do not include the current bucket, we do not
// need to pull any new data anyhow.
mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(), false /* include_current_bucket*/,
true /* erase_data */, GET_DATA_CALLED, FAST, output);
true /* erase_data */, GET_DATA_CALLED, FAST, &unsignedOutput);
*output = vector<int8_t>(unsignedOutput.begin(), unsignedOutput.end());
return Status::ok();
}
Status StatsService::getMetadata(vector<uint8_t>* output) {
Status StatsService::getMetadata(vector<int8_t>* output) {
ENFORCE_UID(AID_SYSTEM);
StatsdStats::getInstance().dumpStats(output, false); // Don't reset the counters.
vector<uint8_t> unsignedOutput;
StatsdStats::getInstance().dumpStats(&unsignedOutput, false); // Don't reset the counters.
*output = vector<int8_t>(unsignedOutput.begin(), unsignedOutput.end());
return Status::ok();
}
Status StatsService::addConfiguration(int64_t key, const vector <uint8_t>& config,
Status StatsService::addConfiguration(int64_t key, const vector <int8_t>& config,
const int32_t callingUid) {
ENFORCE_UID(AID_SYSTEM);
if (addConfigurationChecked(callingUid, key, config)) {
return Status::ok();
} else {
ALOGE("Could not parse malformatted StatsdConfig");
return Status::fromExceptionCode(binder::Status::EX_ILLEGAL_ARGUMENT,
"config does not correspond to a StatsdConfig proto");
return exception(EX_ILLEGAL_ARGUMENT, "Could not parse malformatted StatsdConfig.");
}
}
bool StatsService::addConfigurationChecked(int uid, int64_t key, const vector<uint8_t>& config) {
bool StatsService::addConfigurationChecked(int uid, int64_t key, const vector<int8_t>& config) {
ConfigKey configKey(uid, key);
StatsdConfig cfg;
if (config.size() > 0) { // If the config is empty, skip parsing.
@@ -1180,7 +1119,7 @@ Status StatsService::removeDataFetchOperation(int64_t key,
}
Status StatsService::setDataFetchOperation(int64_t key,
const sp<IPendingIntentRef>& pir,
const shared_ptr<IPendingIntentRef>& pir,
const int32_t callingUid) {
ENFORCE_UID(AID_SYSTEM);
@@ -1194,7 +1133,7 @@ Status StatsService::setDataFetchOperation(int64_t key,
return Status::ok();
}
Status StatsService::setActiveConfigsChangedOperation(const sp<IPendingIntentRef>& pir,
Status StatsService::setActiveConfigsChangedOperation(const shared_ptr<IPendingIntentRef>& pir,
const int32_t callingUid,
vector<int64_t>* output) {
ENFORCE_UID(AID_SYSTEM);
@@ -1225,7 +1164,7 @@ Status StatsService::removeConfiguration(int64_t key, const int32_t callingUid)
Status StatsService::setBroadcastSubscriber(int64_t configId,
int64_t subscriberId,
const sp<IPendingIntentRef>& pir,
const shared_ptr<IPendingIntentRef>& pir,
const int32_t callingUid) {
ENFORCE_UID(AID_SYSTEM);
@@ -1252,14 +1191,14 @@ Status StatsService::sendAppBreadcrumbAtom(int32_t label, int32_t state) {
// Permission check not necessary as it's meant for applications to write to
// statsd.
android::util::stats_write(util::APP_BREADCRUMB_REPORTED,
(int32_t) IPCThreadState::self()->getCallingUid(), label,
(int32_t) AIBinder_getCallingUid(), label,
state);
return Status::ok();
}
Status StatsService::registerPullAtomCallback(int32_t uid, int32_t atomTag, int64_t coolDownNs,
int64_t timeoutNs, const std::vector<int32_t>& additiveFields,
const sp<android::os::IPullAtomCallback>& pullerCallback) {
const shared_ptr<IPullAtomCallback>& pullerCallback) {
ENFORCE_UID(AID_SYSTEM);
VLOG("StatsService::registerPullAtomCallback called.");
@@ -1270,10 +1209,10 @@ Status StatsService::registerPullAtomCallback(int32_t uid, int32_t atomTag, int6
Status StatsService::registerNativePullAtomCallback(int32_t atomTag, int64_t coolDownNs,
int64_t timeoutNs, const std::vector<int32_t>& additiveFields,
const sp<android::os::IPullAtomCallback>& pullerCallback) {
const shared_ptr<IPullAtomCallback>& pullerCallback) {
VLOG("StatsService::registerNativePullAtomCallback called.");
int32_t uid = IPCThreadState::self()->getCallingUid();
int32_t uid = AIBinder_getCallingUid();
mPullerManager->RegisterPullAtomCallback(uid, atomTag, coolDownNs, timeoutNs, additiveFields,
pullerCallback);
return Status::ok();
@@ -1288,7 +1227,7 @@ Status StatsService::unregisterPullAtomCallback(int32_t uid, int32_t atomTag) {
Status StatsService::unregisterNativePullAtomCallback(int32_t atomTag) {
VLOG("StatsService::unregisterNativePullAtomCallback called.");
int32_t uid = IPCThreadState::self()->getCallingUid();
int32_t uid = AIBinder_getCallingUid();
mPullerManager->UnregisterPullAtomCallback(uid, atomTag);
return Status::ok();
}
@@ -1314,7 +1253,13 @@ Status StatsService::getRegisteredExperimentIds(std::vector<int64_t>* experiment
return Status::ok();
}
void StatsService::binderDied(const wp <IBinder>& who) {
void StatsService::statsCompanionServiceDied(void* cookie) {
auto thiz = static_cast<StatsService*>(cookie);
thiz->statsCompanionServiceDiedImpl();
}
void StatsService::statsCompanionServiceDiedImpl() {
ALOGW("statscompanion service died");
StatsdStats::getInstance().noteSystemServerRestart(getWallClockSec());
if (mProcessor != nullptr) {

View File

@@ -27,27 +27,30 @@
#include "shell/ShellSubscriber.h"
#include "statscompanion_util.h"
#include <android/os/BnStatsd.h>
#include <android/os/IPendingIntentRef.h>
#include <android/os/IStatsCompanionService.h>
#include <android/os/IStatsd.h>
#include <binder/IResultReceiver.h>
#include <binder/ParcelFileDescriptor.h>
#include <aidl/android/os/BnStatsd.h>
#include <aidl/android/os/IPendingIntentRef.h>
#include <aidl/android/os/IPullAtomCallback.h>
#include <utils/Looper.h>
#include <mutex>
using namespace android;
using namespace android::binder;
using namespace android::os;
using namespace std;
using Status = ::ndk::ScopedAStatus;
using aidl::android::os::BnStatsd;
using aidl::android::os::IPendingIntentRef;
using aidl::android::os::IPullAtomCallback;
using ::ndk::ScopedAIBinder_DeathRecipient;
using ::ndk::ScopedFileDescriptor;
using std::shared_ptr;
namespace android {
namespace os {
namespace statsd {
class StatsService : public BnStatsd,
public IBinder::DeathRecipient {
class StatsService : public BnStatsd {
public:
StatsService(const sp<Looper>& handlerLooper, std::shared_ptr<LogEventQueue> queue);
virtual ~StatsService();
@@ -55,10 +58,9 @@ public:
/** The anomaly alarm registered with AlarmManager won't be updated by less than this. */
const uint32_t MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS = 5;
virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
virtual status_t dump(int fd, const Vector<String16>& args);
virtual status_t command(int inFd, int outFd, int err, Vector<String8>& args,
sp<IResultReceiver> resultReceiver);
virtual status_t dump(int fd, const char** args, uint32_t numArgs) override;
virtual status_t handleShellCommand(int in, int out, int err, const char** argv,
uint32_t argc) override;
virtual Status systemRunning();
virtual Status statsCompanionReady();
@@ -66,10 +68,10 @@ public:
virtual Status informPollAlarmFired();
virtual Status informAlarmForSubscriberTriggeringFired();
virtual Status informAllUidData(const ParcelFileDescriptor& fd);
virtual Status informOnePackage(const String16& app, int32_t uid, int64_t version,
const String16& version_string, const String16& installer);
virtual Status informOnePackageRemoved(const String16& app, int32_t uid);
virtual Status informAllUidData(const ScopedFileDescriptor& fd);
virtual Status informOnePackage(const string& app, int32_t uid, int64_t version,
const string& versionString, const string& installer);
virtual Status informOnePackageRemoved(const string& app, int32_t uid);
virtual Status informDeviceShutdown();
/**
@@ -92,13 +94,13 @@ public:
*/
virtual Status getData(int64_t key,
const int32_t callingUid,
vector<uint8_t>* output) override;
vector<int8_t>* output) override;
/**
* Binder call for clients to get metadata across all configs in statsd.
*/
virtual Status getMetadata(vector<uint8_t>* output) override;
virtual Status getMetadata(vector<int8_t>* output) override;
/**
@@ -106,14 +108,14 @@ public:
* should requestData for this configuration.
*/
virtual Status addConfiguration(int64_t key,
const vector<uint8_t>& config,
const vector<int8_t>& config,
const int32_t callingUid) override;
/**
* Binder call to let clients register the data fetch operation for a configuration.
*/
virtual Status setDataFetchOperation(int64_t key,
const sp<IPendingIntentRef>& pir,
const shared_ptr<IPendingIntentRef>& pir,
const int32_t callingUid) override;
/**
@@ -125,7 +127,7 @@ public:
/**
* Binder call to let clients register the active configs changed operation.
*/
virtual Status setActiveConfigsChangedOperation(const sp<IPendingIntentRef>& pir,
virtual Status setActiveConfigsChangedOperation(const shared_ptr<IPendingIntentRef>& pir,
const int32_t callingUid,
vector<int64_t>* output) override;
@@ -144,7 +146,7 @@ public:
*/
virtual Status setBroadcastSubscriber(int64_t configId,
int64_t subscriberId,
const sp<IPendingIntentRef>& pir,
const shared_ptr<IPendingIntentRef>& pir,
const int32_t callingUid) override;
/**
@@ -167,14 +169,14 @@ public:
*/
virtual Status registerPullAtomCallback(int32_t uid, int32_t atomTag, int64_t coolDownNs,
int64_t timeoutNs, const std::vector<int32_t>& additiveFields,
const sp<android::os::IPullAtomCallback>& pullerCallback) override;
const shared_ptr<IPullAtomCallback>& pullerCallback) override;
/**
* Binder call to register a callback function for a pulled atom.
*/
virtual Status registerNativePullAtomCallback(int32_t atomTag, int64_t coolDownNs,
int64_t timeoutNs, const std::vector<int32_t>& additiveFields,
const sp<android::os::IPullAtomCallback>& pullerCallback) override;
const shared_ptr<IPullAtomCallback>& pullerCallback) override;
/**
* Binder call to unregister any existing callback for the given uid and atom.
@@ -191,9 +193,6 @@ public:
*/
virtual Status getRegisteredExperimentIds(std::vector<int64_t>* expIdsOut);
/** IBinder::DeathRecipient */
virtual void binderDied(const wp<IBinder>& who) override;
private:
/**
* Load system properties at init.
@@ -317,13 +316,24 @@ private:
/**
* Adds a configuration after checking permissions and obtaining UID from binder call.
*/
bool addConfigurationChecked(int uid, int64_t key, const vector<uint8_t>& config);
bool addConfigurationChecked(int uid, int64_t key, const vector<int8_t>& config);
/**
* Update a configuration.
*/
void set_config(int uid, const string& name, const StatsdConfig& config);
/**
* Death recipient callback that is called when StatsCompanionService dies.
* The cookie is a pointer to a StatsService object.
*/
static void statsCompanionServiceDied(void* cookie);
/**
* Implementation of statsCompanionServiceDied.
*/
void statsCompanionServiceDiedImpl();
/**
* Tracks the uid <--> package name mapping.
*/
@@ -367,6 +377,8 @@ private:
mutable mutex mShellSubscriberMutex;
std::shared_ptr<LogEventQueue> mEventQueue;
ScopedAIBinder_DeathRecipient mStatsCompanionServiceDeathRecipient;
FRIEND_TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart);
FRIEND_TEST(StatsServiceTest, TestAddConfig_simple);
FRIEND_TEST(StatsServiceTest, TestAddConfig_empty);

View File

@@ -26,17 +26,21 @@ namespace statsd {
AlarmMonitor::AlarmMonitor(
uint32_t minDiffToUpdateRegisteredAlarmTimeSec,
const std::function<void(const sp<IStatsCompanionService>&, int64_t)>& updateAlarm,
const std::function<void(const sp<IStatsCompanionService>&)>& cancelAlarm)
: mRegisteredAlarmTimeSec(0), mMinUpdateTimeSec(minDiffToUpdateRegisteredAlarmTimeSec),
const std::function<void(const shared_ptr<IStatsCompanionService>&, int64_t)>& updateAlarm,
const std::function<void(const shared_ptr<IStatsCompanionService>&)>& cancelAlarm)
: mRegisteredAlarmTimeSec(0),
mMinUpdateTimeSec(minDiffToUpdateRegisteredAlarmTimeSec),
mUpdateAlarm(updateAlarm),
mCancelAlarm(cancelAlarm) {}
AlarmMonitor::~AlarmMonitor() {}
void AlarmMonitor::setStatsCompanionService(sp<IStatsCompanionService> statsCompanionService) {
void AlarmMonitor::setStatsCompanionService(
shared_ptr<IStatsCompanionService> statsCompanionService) {
std::lock_guard<std::mutex> lock(mLock);
sp<IStatsCompanionService> tmpForLock = mStatsCompanionService;
// TODO(b/149254662): determine if tmpForLock is needed now that we have moved
// from sp to shared_ptr
shared_ptr<IStatsCompanionService> tmpForLock = mStatsCompanionService;
mStatsCompanionService = statsCompanionService;
if (statsCompanionService == nullptr) {
VLOG("Erasing link to statsCompanionService");

View File

@@ -18,7 +18,7 @@
#include "anomaly/indexed_priority_queue.h"
#include <android/os/IStatsCompanionService.h>
#include <aidl/android/os/IStatsCompanionService.h>
#include <utils/RefBase.h>
#include <unordered_set>
@@ -26,7 +26,9 @@
using namespace android;
using android::os::IStatsCompanionService;
using aidl::android::os::IStatsCompanionService;
using std::function;
using std::shared_ptr;
using std::unordered_set;
namespace android {
@@ -64,8 +66,9 @@ public:
* alarm.
*/
AlarmMonitor(uint32_t minDiffToUpdateRegisteredAlarmTimeSec,
const std::function<void(const sp<IStatsCompanionService>&, int64_t)>& updateAlarm,
const std::function<void(const sp<IStatsCompanionService>&)>& cancelAlarm);
const function<void(const shared_ptr<IStatsCompanionService>&, int64_t)>&
updateAlarm,
const function<void(const shared_ptr<IStatsCompanionService>&)>& cancelAlarm);
~AlarmMonitor();
/**
@@ -74,7 +77,7 @@ public:
* If nullptr, AnomalyMonitor will continue to add/remove alarms, but won't
* update IStatsCompanionService (until such time as it is set non-null).
*/
void setStatsCompanionService(sp<IStatsCompanionService> statsCompanionService);
void setStatsCompanionService(shared_ptr<IStatsCompanionService> statsCompanionService);
/**
* Adds the given alarm (reference) to the queue.
@@ -123,7 +126,7 @@ private:
/**
* Binder interface for communicating with StatsCompanionService.
*/
sp<IStatsCompanionService> mStatsCompanionService = nullptr;
shared_ptr<IStatsCompanionService> mStatsCompanionService = nullptr;
/**
* Amount by which the soonest projected alarm must differ from
@@ -147,10 +150,10 @@ private:
int64_t secToMs(uint32_t timeSec);
// Callback function to update the alarm via StatsCompanionService.
std::function<void(const sp<IStatsCompanionService>, int64_t)> mUpdateAlarm;
std::function<void(const shared_ptr<IStatsCompanionService>, int64_t)> mUpdateAlarm;
// Callback function to cancel the alarm via StatsCompanionService.
std::function<void(const sp<IStatsCompanionService>)> mCancelAlarm;
std::function<void(const shared_ptr<IStatsCompanionService>)> mCancelAlarm;
};

View File

@@ -22,12 +22,9 @@
#include "config/ConfigKey.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alarm
#include <android/os/IStatsCompanionService.h>
#include <stdlib.h>
#include <utils/RefBase.h>
using android::os::IStatsCompanionService;
namespace android {
namespace os {
namespace statsd {

View File

@@ -42,42 +42,67 @@ using std::vector;
using android::base::StringPrintf;
using std::unique_ptr;
class ConfigReceiverDeathRecipient : public android::IBinder::DeathRecipient {
public:
ConfigReceiverDeathRecipient(sp<ConfigManager> configManager, const ConfigKey& configKey):
mConfigManager(configManager),
mConfigKey(configKey) {}
~ConfigReceiverDeathRecipient() override = default;
private:
sp<ConfigManager> mConfigManager;
ConfigKey mConfigKey;
struct ConfigReceiverDeathCookie {
ConfigReceiverDeathCookie(sp<ConfigManager> configManager, const ConfigKey& configKey,
const shared_ptr<IPendingIntentRef>& pir):
mConfigManager(configManager),
mConfigKey(configKey),
mPir(pir) {}
void binderDied(const android::wp<android::IBinder>& who) override {
if (IInterface::asBinder(mConfigManager->GetConfigReceiver(mConfigKey)) == who.promote()) {
mConfigManager->RemoveConfigReceiver(mConfigKey);
}
}
sp<ConfigManager> mConfigManager;
ConfigKey mConfigKey;
shared_ptr<IPendingIntentRef> mPir;
};
class ActiveConfigChangedReceiverDeathRecipient : public android::IBinder::DeathRecipient {
public:
ActiveConfigChangedReceiverDeathRecipient(sp<ConfigManager> configManager, const int uid):
mConfigManager(configManager),
mUid(uid) {}
~ActiveConfigChangedReceiverDeathRecipient() override = default;
private:
sp<ConfigManager> mConfigManager;
int mUid;
static void configReceiverDied(void* cookie) {
auto cookie_ = static_cast<ConfigReceiverDeathCookie*>(cookie);
sp<ConfigManager> configManager = cookie_->mConfigManager;
ConfigKey configKey = cookie_->mConfigKey;
shared_ptr<IPendingIntentRef> pir = cookie_->mPir;
void binderDied(const android::wp<android::IBinder>& who) override {
if (IInterface::asBinder(mConfigManager->GetActiveConfigsChangedReceiver(mUid))
== who.promote()) {
mConfigManager->RemoveActiveConfigsChangedReceiver(mUid);
}
// TODO(b/149254662): Fix threading. This currently fails if a new
// pir gets set between the get and the remove.
if (configManager->GetConfigReceiver(configKey) == pir) {
configManager->RemoveConfigReceiver(configKey);
}
// The death recipient corresponding to this specific pir can never
// be triggered again, so free up resources.
// TODO(b/149254662): Investigate other options to manage the memory.
delete cookie_;
}
struct ActiveConfigChangedReceiverDeathCookie {
ActiveConfigChangedReceiverDeathCookie(sp<ConfigManager> configManager, const int uid,
const shared_ptr<IPendingIntentRef>& pir):
mConfigManager(configManager),
mUid(uid),
mPir(pir) {}
sp<ConfigManager> mConfigManager;
int mUid;
shared_ptr<IPendingIntentRef> mPir;
};
ConfigManager::ConfigManager() {
static void activeConfigChangedReceiverDied(void* cookie) {
auto cookie_ = static_cast<ActiveConfigChangedReceiverDeathCookie*>(cookie);
sp<ConfigManager> configManager = cookie_->mConfigManager;
int uid = cookie_->mUid;
shared_ptr<IPendingIntentRef> pir = cookie_->mPir;
// TODO(b/149254662): Fix threading. This currently fails if a new
// pir gets set between the get and the remove.
if (configManager->GetActiveConfigsChangedReceiver(uid) == pir) {
configManager->RemoveActiveConfigsChangedReceiver(uid);
}
// The death recipient corresponding to this specific pir can never
// be triggered again, so free up resources.
delete cookie_;
}
ConfigManager::ConfigManager():
mConfigReceiverDeathRecipient(AIBinder_DeathRecipient_new(configReceiverDied)),
mActiveConfigChangedReceiverDeathRecipient(
AIBinder_DeathRecipient_new(activeConfigChangedReceiverDied)) {
}
ConfigManager::~ConfigManager() {
@@ -150,10 +175,11 @@ void ConfigManager::UpdateConfig(const ConfigKey& key, const StatsdConfig& confi
}
void ConfigManager::SetConfigReceiver(const ConfigKey& key,
const sp<IPendingIntentRef>& pir) {
const shared_ptr<IPendingIntentRef>& pir) {
lock_guard<mutex> lock(mMutex);
mConfigReceivers[key] = pir;
IInterface::asBinder(pir)->linkToDeath(new ConfigReceiverDeathRecipient(this, key));
AIBinder_linkToDeath(pir->asBinder().get(), mConfigReceiverDeathRecipient.get(),
new ConfigReceiverDeathCookie(this, key, pir));
}
void ConfigManager::RemoveConfigReceiver(const ConfigKey& key) {
@@ -162,11 +188,11 @@ void ConfigManager::RemoveConfigReceiver(const ConfigKey& key) {
}
void ConfigManager::SetActiveConfigsChangedReceiver(const int uid,
const sp<IPendingIntentRef>& pir) {
const shared_ptr<IPendingIntentRef>& pir) {
lock_guard<mutex> lock(mMutex);
mActiveConfigsChangedReceivers[uid] = pir;
IInterface::asBinder(pir)->linkToDeath(
new ActiveConfigChangedReceiverDeathRecipient(this, uid));
AIBinder_linkToDeath(pir->asBinder().get(), mActiveConfigChangedReceiverDeathRecipient.get(),
new ActiveConfigChangedReceiverDeathCookie(this, uid, pir));
}
void ConfigManager::RemoveActiveConfigsChangedReceiver(const int uid) {
@@ -279,7 +305,7 @@ vector<ConfigKey> ConfigManager::GetAllConfigKeys() const {
return ret;
}
const sp<IPendingIntentRef> ConfigManager::GetConfigReceiver(const ConfigKey& key) const {
const shared_ptr<IPendingIntentRef> ConfigManager::GetConfigReceiver(const ConfigKey& key) const {
lock_guard<mutex> lock(mMutex);
auto it = mConfigReceivers.find(key);
@@ -290,7 +316,8 @@ const sp<IPendingIntentRef> ConfigManager::GetConfigReceiver(const ConfigKey& ke
}
}
const sp<IPendingIntentRef> ConfigManager::GetActiveConfigsChangedReceiver(const int uid) const {
const shared_ptr<IPendingIntentRef> ConfigManager::GetActiveConfigsChangedReceiver(const int uid)
const {
lock_guard<mutex> lock(mMutex);
auto it = mActiveConfigsChangedReceivers.find(uid);

View File

@@ -19,12 +19,15 @@
#include "config/ConfigKey.h"
#include "config/ConfigListener.h"
#include <android/os/IPendingIntentRef.h>
#include <aidl/android/os/IPendingIntentRef.h>
#include <mutex>
#include <string>
#include <stdio.h>
using aidl::android::os::IPendingIntentRef;
using std::shared_ptr;
namespace android {
namespace os {
namespace statsd {
@@ -62,12 +65,12 @@ public:
/**
* Sets the broadcast receiver for a configuration key.
*/
void SetConfigReceiver(const ConfigKey& key, const sp<IPendingIntentRef>& pir);
void SetConfigReceiver(const ConfigKey& key, const shared_ptr<IPendingIntentRef>& pir);
/**
* Returns the package name and class name representing the broadcast receiver for this config.
*/
const sp<IPendingIntentRef> GetConfigReceiver(const ConfigKey& key) const;
const shared_ptr<IPendingIntentRef> GetConfigReceiver(const ConfigKey& key) const;
/**
* Returns all config keys registered.
@@ -83,13 +86,13 @@ public:
* Sets the broadcast receiver that is notified whenever the list of active configs
* changes for this uid.
*/
void SetActiveConfigsChangedReceiver(const int uid, const sp<IPendingIntentRef>& pir);
void SetActiveConfigsChangedReceiver(const int uid, const shared_ptr<IPendingIntentRef>& pir);
/**
* Returns the broadcast receiver for active configs changed for this uid.
*/
const sp<IPendingIntentRef> GetActiveConfigsChangedReceiver(const int uid) const;
const shared_ptr<IPendingIntentRef> GetActiveConfigsChangedReceiver(const int uid) const;
/**
* Erase any active configs changed broadcast receiver associated with this uid.
@@ -141,18 +144,23 @@ private:
/**
* Each config key can be subscribed by up to one receiver, specified as IPendingIntentRef.
*/
std::map<ConfigKey, sp<IPendingIntentRef>> mConfigReceivers;
std::map<ConfigKey, shared_ptr<IPendingIntentRef>> mConfigReceivers;
/**
* Each uid can be subscribed by up to one receiver to notify that the list of active configs
* for this uid has changed. The receiver is specified as IPendingIntentRef.
*/
std::map<int, sp<IPendingIntentRef>> mActiveConfigsChangedReceivers;
std::map<int, shared_ptr<IPendingIntentRef>> mActiveConfigsChangedReceivers;
/**
* The ConfigListeners that will be told about changes.
*/
std::vector<sp<ConfigListener>> mListeners;
// Death recipients that are triggered when the host process holding an
// IPendingIntentRef dies.
::ndk::ScopedAIBinder_DeathRecipient mConfigReceiverDeathRecipient;
::ndk::ScopedAIBinder_DeathRecipient mActiveConfigChangedReceiverDeathRecipient;
};
} // namespace statsd

View File

@@ -16,17 +16,12 @@
#include "PullResultReceiver.h"
using namespace android::binder;
using namespace android::util;
using namespace std;
namespace android {
namespace os {
namespace statsd {
PullResultReceiver::PullResultReceiver(
std::function<void(int32_t, bool, const vector<android::util::StatsEventParcel>&)>
pullFinishCb)
std::function<void(int32_t, bool, const vector<StatsEventParcel>&)> pullFinishCb)
: pullFinishCallback(std::move(pullFinishCb)) {
}

View File

@@ -14,29 +14,33 @@
* limitations under the License.
*/
#include <android/os/BnPullAtomResultReceiver.h>
#include <aidl/android/os/BnPullAtomResultReceiver.h>
#include <aidl/android/util/StatsEventParcel.h>
using namespace std;
using Status = ::ndk::ScopedAStatus;
using aidl::android::os::BnPullAtomResultReceiver;
using aidl::android::util::StatsEventParcel;
namespace android {
namespace os {
namespace statsd {
class PullResultReceiver : public BnPullAtomResultReceiver {
public:
PullResultReceiver(function<void(int32_t, bool, const vector<android::util::StatsEventParcel>&)>
PullResultReceiver(function<void(int32_t, bool, const vector<StatsEventParcel>&)>
pullFinishCallback);
~PullResultReceiver();
/**
* Binder call for finishing a pull.
*/
binder::Status pullFinished(int32_t atomTag, bool success,
const vector<android::util::StatsEventParcel>& output) override;
Status pullFinished(int32_t atomTag, bool success,
const vector<StatsEventParcel>& output) override;
private:
function<void(int32_t, bool, const vector<android::util::StatsEventParcel>&)>
pullFinishCallback;
function<void(int32_t, bool, const vector<StatsEventParcel>&)> pullFinishCallback;
};
} // namespace statsd

View File

@@ -18,24 +18,24 @@
#include "Log.h"
#include "StatsCallbackPuller.h"
#include <android/os/IPullAtomCallback.h>
#include <android/util/StatsEventParcel.h>
#include "PullResultReceiver.h"
#include "StatsPullerManager.h"
#include "logd/LogEvent.h"
#include "stats_log_util.h"
using namespace android::binder;
using namespace android::util;
#include <aidl/android/util/StatsEventParcel.h>
using namespace std;
using Status = ::ndk::ScopedAStatus;
using aidl::android::util::StatsEventParcel;
using ::ndk::SharedRefBase;
namespace android {
namespace os {
namespace statsd {
StatsCallbackPuller::StatsCallbackPuller(int tagId, const sp<IPullAtomCallback>& callback,
StatsCallbackPuller::StatsCallbackPuller(int tagId, const shared_ptr<IPullAtomCallback>& callback,
const int64_t coolDownNs, int64_t timeoutNs,
const vector<int> additiveFields)
: StatsPuller(tagId, coolDownNs, timeoutNs, additiveFields), mCallback(callback) {
@@ -57,7 +57,7 @@ bool StatsCallbackPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
shared_ptr<vector<shared_ptr<LogEvent>>> sharedData =
make_shared<vector<shared_ptr<LogEvent>>>();
sp<PullResultReceiver> resultReceiver = new PullResultReceiver(
shared_ptr<PullResultReceiver> resultReceiver = SharedRefBase::make<PullResultReceiver>(
[cv_mutex, cv, pullFinish, pullSuccess, sharedData](
int32_t atomTag, bool success, const vector<StatsEventParcel>& output) {
// This is the result of the pull, executing in a statsd binder thread.
@@ -66,9 +66,11 @@ bool StatsCallbackPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
{
lock_guard<mutex> lk(*cv_mutex);
for (const StatsEventParcel& parcel: output) {
uint8_t* buf = reinterpret_cast<uint8_t*>(
const_cast<int8_t*>(parcel.buffer.data()));
shared_ptr<LogEvent> event = make_shared<LogEvent>(
const_cast<uint8_t*>(parcel.buffer.data()), parcel.buffer.size(),
/*uid=*/-1, /*pid=*/-1, /*useNewSchema=*/true);
buf, parcel.buffer.size(), /*uid=*/-1, /*pid=*/-1,
/*useNewSchema=*/true);
sharedData->push_back(event);
}
*pullSuccess = success;

View File

@@ -16,23 +16,25 @@
#pragma once
#include <android/os/IPullAtomCallback.h>
#include <aidl/android/os/IPullAtomCallback.h>
#include "StatsPuller.h"
using aidl::android::os::IPullAtomCallback;
using std::shared_ptr;
namespace android {
namespace os {
namespace statsd {
class StatsCallbackPuller : public StatsPuller {
public:
explicit StatsCallbackPuller(int tagId, const sp<IPullAtomCallback>& callback,
explicit StatsCallbackPuller(int tagId, const shared_ptr<IPullAtomCallback>& callback,
const int64_t coolDownNs, const int64_t timeoutNs,
const std::vector<int> additiveFields);
private:
bool PullInternal(vector<std::shared_ptr<LogEvent> >* data) override;
const sp<IPullAtomCallback> mCallback;
bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override;
const shared_ptr<IPullAtomCallback> mCallback;
FRIEND_TEST(StatsCallbackPullerTest, PullFail);
FRIEND_TEST(StatsCallbackPullerTest, PullSuccess);

View File

@@ -16,7 +16,7 @@
#pragma once
#include <android/os/IStatsCompanionService.h>
#include <aidl/android/os/IStatsCompanionService.h>
#include <utils/RefBase.h>
#include <mutex>
#include <vector>
@@ -26,6 +26,9 @@
#include "logd/LogEvent.h"
#include "puller_util.h"
using aidl::android::os::IStatsCompanionService;
using std::shared_ptr;
namespace android {
namespace os {
namespace statsd {
@@ -58,7 +61,8 @@ public:
static void SetUidMap(const sp<UidMap>& uidMap);
virtual void SetStatsCompanionService(sp<IStatsCompanionService> statsCompanionService){};
virtual void SetStatsCompanionService(
shared_ptr<IStatsCompanionService> statsCompanionService) {};
protected:
const int mTagId;

View File

@@ -19,8 +19,6 @@
#include "StatsPullerManager.h"
#include <android/os/IPullAtomCallback.h>
#include <android/os/IStatsCompanionService.h>
#include <cutils/log.h>
#include <math.h>
#include <stdint.h>
@@ -87,7 +85,10 @@ void StatsPullerManager::updateAlarmLocked() {
return;
}
sp<IStatsCompanionService> statsCompanionServiceCopy = mStatsCompanionService;
// TODO(b/149254662): Why are we creating a copy here? This is different
// from the other places where we create a copy because we don't reassign
// mStatsCompanionService so a destructor can't implicitly be called...
shared_ptr<IStatsCompanionService> statsCompanionServiceCopy = mStatsCompanionService;
if (statsCompanionServiceCopy != nullptr) {
statsCompanionServiceCopy->setPullingAlarm(mNextPullTimeNs / 1000000);
} else {
@@ -97,9 +98,11 @@ void StatsPullerManager::updateAlarmLocked() {
}
void StatsPullerManager::SetStatsCompanionService(
sp<IStatsCompanionService> statsCompanionService) {
shared_ptr<IStatsCompanionService> statsCompanionService) {
// TODO(b/149254662): Why are we using AutoMutex instead of lock_guard?
// Additionally, do we need the temporary shared_ptr to prevent deadlocks?
AutoMutex _l(mLock);
sp<IStatsCompanionService> tmpForLock = mStatsCompanionService;
shared_ptr<IStatsCompanionService> tmpForLock = mStatsCompanionService;
mStatsCompanionService = statsCompanionService;
for (const auto& pulledAtom : kAllPullAtomInfo) {
pulledAtom.second->SetStatsCompanionService(statsCompanionService);
@@ -250,10 +253,11 @@ int StatsPullerManager::ClearPullerCacheIfNecessary(int64_t timestampNs) {
void StatsPullerManager::RegisterPullAtomCallback(const int uid, const int32_t atomTag,
const int64_t coolDownNs, const int64_t timeoutNs,
const vector<int32_t>& additiveFields,
const sp<IPullAtomCallback>& callback) {
const shared_ptr<IPullAtomCallback>& callback) {
AutoMutex _l(mLock);
VLOG("RegisterPullerCallback: adding puller for tag %d", atomTag);
// TODO: linkToDeath with the callback so that we can remove it and delete the puller.
// TODO(b/146439412): linkToDeath with the callback so that we can remove it
// and delete the puller.
StatsdStats::getInstance().notePullerCallbackRegistrationChanged(atomTag, /*registered=*/true);
kAllPullAtomInfo[{.atomTag = atomTag}] =
new StatsCallbackPuller(atomTag, callback, coolDownNs, timeoutNs, additiveFields);

View File

@@ -16,9 +16,8 @@
#pragma once
#include <android/os/IPullAtomCallback.h>
#include <android/os/IStatsCompanionService.h>
#include <binder/IServiceManager.h>
#include <aidl/android/os/IPullAtomCallback.h>
#include <aidl/android/os/IStatsCompanionService.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
@@ -30,11 +29,14 @@
#include "guardrail/StatsdStats.h"
#include "logd/LogEvent.h"
using aidl::android::os::IPullAtomCallback;
using aidl::android::os::IStatsCompanionService;
using std::shared_ptr;
namespace android {
namespace os {
namespace statsd {
typedef struct PullerKey {
// The uid of the process that registers this puller.
const int uid = -1;
@@ -93,18 +95,18 @@ public:
// Clear pull data cache if it is beyond respective cool down time.
int ClearPullerCacheIfNecessary(int64_t timestampNs);
void SetStatsCompanionService(sp<IStatsCompanionService> statsCompanionService);
void SetStatsCompanionService(shared_ptr<IStatsCompanionService> statsCompanionService);
void RegisterPullAtomCallback(const int uid, const int32_t atomTag, const int64_t coolDownNs,
const int64_t timeoutNs, const vector<int32_t>& additiveFields,
const sp<IPullAtomCallback>& callback);
const shared_ptr<IPullAtomCallback>& callback);
void UnregisterPullAtomCallback(const int uid, const int32_t atomTag);
std::map<const PullerKey, sp<StatsPuller>> kAllPullAtomInfo;
private:
sp<IStatsCompanionService> mStatsCompanionService = nullptr;
shared_ptr<IStatsCompanionService> mStatsCompanionService = nullptr;
typedef struct {
int64_t nextPullTimeNs;

View File

@@ -20,7 +20,8 @@
#include "stats_log_util.h"
#include "statslog.h"
#include <binder/IPCThreadState.h>
#include <android/binder_ibinder.h>
#include <android-base/stringprintf.h>
#include <private/android_filesystem_config.h>
namespace android {
@@ -31,6 +32,7 @@ namespace statsd {
const int FIELD_ID_EXPERIMENT_ID = 1;
using namespace android::util;
using android::base::StringPrintf;
using android::util::ProtoOutputStream;
using std::string;
using std::vector;
@@ -180,8 +182,8 @@ LogEvent::LogEvent(const string& trainName, int64_t trainVersionCode, bool requi
mLogdTimestampNs = getWallClockNs();
mElapsedTimestampNs = getElapsedRealtimeNs();
mTagId = android::util::BINARY_PUSH_STATE_CHANGED;
mLogUid = android::IPCThreadState::self()->getCallingUid();
mLogPid = android::IPCThreadState::self()->getCallingPid();
mLogUid = AIBinder_getCallingUid();
mLogPid = AIBinder_getCallingPid();
mValues.push_back(FieldValue(Field(mTagId, getSimpleField(1)), Value(trainName)));
mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)), Value(trainVersionCode)));

View File

@@ -20,9 +20,9 @@
#include "StatsService.h"
#include "socket/StatsSocketListener.h"
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <android/binder_interface_utils.h>
#include <android/binder_process.h>
#include <android/binder_manager.h>
#include <utils/Looper.h>
#include <stdio.h>
@@ -32,16 +32,11 @@
using namespace android;
using namespace android::os::statsd;
using ::ndk::SharedRefBase;
using std::shared_ptr;
using std::make_shared;
/**
* Thread function data.
*/
struct log_reader_thread_data {
sp<StatsService> service;
};
sp<StatsService> gStatsService = nullptr;
shared_ptr<StatsService> gStatsService = nullptr;
void sigHandler(int sig) {
if (gStatsService != nullptr) {
@@ -68,20 +63,18 @@ int main(int /*argc*/, char** /*argv*/) {
sp<Looper> looper(Looper::prepare(0 /* opts */));
// Set up the binder
sp<ProcessState> ps(ProcessState::self());
ps->setThreadPoolMaxThreadCount(9);
ps->startThreadPool();
ps->giveThreadPoolName();
IPCThreadState::self()->disableBackgroundScheduling(true);
ABinderProcess_setThreadPoolMaxThreadCount(9);
ABinderProcess_startThreadPool();
std::shared_ptr<LogEventQueue> eventQueue =
std::make_shared<LogEventQueue>(2000 /*buffer limit. Buffer is NOT pre-allocated*/);
// Create the service
gStatsService = new StatsService(looper, eventQueue);
if (defaultServiceManager()->addService(String16("stats"), gStatsService, false,
IServiceManager::DUMP_FLAG_PRIORITY_NORMAL | IServiceManager::DUMP_FLAG_PROTO)
!= 0) {
gStatsService = SharedRefBase::make<StatsService>(looper, eventQueue);
// TODO(b/149582373): Set DUMP_FLAG_PROTO once libbinder_ndk supports
// setting dumpsys priorities.
binder_status_t status = AServiceManager_addService(gStatsService->asBinder().get(), "stats");
if (status != STATUS_OK) {
ALOGE("Failed to add service as AIDL service");
return -1;
}

View File

@@ -21,10 +21,11 @@
#include "packages/PackageInfoListener.h"
#include "stats_util.h"
#include <binder/IShellCallback.h>
#include <gtest/gtest_prod.h>
#include <stdio.h>
#include <utils/RefBase.h>
#include <utils/String16.h>
#include <list>
#include <mutex>
#include <set>

View File

@@ -29,49 +29,88 @@ namespace statsd {
const static int FIELD_ID_ATOM = 1;
void ShellSubscriber::startNewSubscription(int in, int out, sp<IResultReceiver> resultReceiver,
int timeoutSec) {
void ShellSubscriber::startNewSubscription(int in, int out, int timeoutSec) {
VLOG("start new shell subscription");
int64_t subscriberId = getElapsedRealtimeNs();
{
std::lock_guard<std::mutex> lock(mMutex);
if (mResultReceiver != nullptr) {
if (mSubscriberId> 0) {
VLOG("Only one shell subscriber is allowed.");
return;
}
mSubscriberId = subscriberId;
mInput = in;
mOutput = out;
mResultReceiver = resultReceiver;
IInterface::asBinder(mResultReceiver)->linkToDeath(this);
}
// Note that the following is blocking, and it's intended as we cannot return until the shell
// cmd exits, otherwise all resources & FDs will be automatically closed.
bool success = readConfig();
if (!success) {
std::lock_guard<std::mutex> lock(mMutex);
cleanUpLocked();
}
// Read config forever until EOF is reached. Clients may send multiple configs -- each new
// config replace the previous one.
readConfig(in);
VLOG("timeout : %d", timeoutSec);
// Now we have read an EOF we now wait for the semaphore until the client exits.
VLOG("Now wait for client to exit");
VLOG("Wait for client to exit or timeout (%d sec)", timeoutSec);
std::unique_lock<std::mutex> lk(mMutex);
// Note that the following is blocking, and it's intended as we cannot return until the shell
// cmd exits or we time out.
if (timeoutSec > 0) {
mShellDied.wait_for(lk, timeoutSec * 1s,
[this, resultReceiver] { return mResultReceiver != resultReceiver; });
[this, subscriberId] { return mSubscriberId != subscriberId; });
} else {
mShellDied.wait(lk, [this, resultReceiver] { return mResultReceiver != resultReceiver; });
mShellDied.wait(lk, [this, subscriberId] { return mSubscriberId != subscriberId; });
}
}
// Read configs until EOF is reached. There may be multiple configs in the input
// -- each new config should replace the previous one.
//
// Returns a boolean indicating whether the input was read successfully.
bool ShellSubscriber::readConfig() {
if (mInput < 0) {
return false;
}
while (true) {
// Read the size of the config.
size_t bufferSize = 0;
ssize_t bytesRead = read(mInput, &bufferSize, sizeof(bufferSize));
if (bytesRead == 0) {
VLOG("We have reached the end of the input.");
return true;
} else if (bytesRead < 0 || (size_t)bytesRead != sizeof(bufferSize)) {
ALOGE("Error reading config size");
return false;
}
// Read and parse the config.
vector<uint8_t> buffer(bufferSize);
bytesRead = read(mInput, buffer.data(), bufferSize);
if (bytesRead > 0 && (size_t)bytesRead == bufferSize) {
ShellSubscription config;
if (config.ParseFromArray(buffer.data(), bufferSize)) {
updateConfig(config);
} else {
ALOGE("Error parsing the config");
return false;
}
} else {
VLOG("Error reading the config, expected bytes: %zu, actual bytes: %zu", bufferSize,
bytesRead);
return false;
}
}
}
void ShellSubscriber::updateConfig(const ShellSubscription& config) {
std::lock_guard<std::mutex> lock(mMutex);
mPushedMatchers.clear();
mPulledInfo.clear();
for (const auto& pushed : config.pushed()) {
mPushedMatchers.push_back(pushed);
VLOG("adding matcher for atom %d", pushed.atom_id());
VLOG("adding matcher for pushed atom %d", pushed.atom_id());
}
int64_t token = getElapsedRealtimeNs();
@@ -89,46 +128,20 @@ void ShellSubscriber::updateConfig(const ShellSubscription& config) {
}
if (mPulledInfo.size() > 0 && minInterval > 0) {
// This thread is guaranteed to terminate after it detects the token is different or
// cleaned up.
// This thread is guaranteed to terminate after it detects the token is
// different.
std::thread puller([token, minInterval, this] { startPull(token, minInterval); });
puller.detach();
}
}
void ShellSubscriber::writeToOutputLocked(const vector<std::shared_ptr<LogEvent>>& data,
const SimpleAtomMatcher& matcher) {
if (mOutput == 0) return;
int count = 0;
mProto.clear();
for (const auto& event : data) {
VLOG("%s", event->ToString().c_str());
if (matchesSimple(*mUidMap, matcher, *event)) {
VLOG("matched");
count++;
uint64_t atomToken = mProto.start(util::FIELD_TYPE_MESSAGE |
util::FIELD_COUNT_REPEATED | FIELD_ID_ATOM);
event->ToProto(mProto);
mProto.end(atomToken);
}
}
if (count > 0) {
// First write the payload size.
size_t bufferSize = mProto.size();
write(mOutput, &bufferSize, sizeof(bufferSize));
VLOG("%d atoms, proto size: %zu", count, bufferSize);
// Then write the payload.
mProto.flush(mOutput);
}
mProto.clear();
}
void ShellSubscriber::startPull(int64_t token, int64_t intervalMillis) {
while (1) {
while (true) {
int64_t nowMillis = getElapsedRealtimeMillis();
{
std::lock_guard<std::mutex> lock(mMutex);
// If the token has changed, the config has changed, so this
// puller can now stop.
if (mPulledInfo.size() == 0 || mPullToken != token) {
VLOG("Pulling thread %lld done!", (long long)token);
return;
@@ -152,55 +165,47 @@ void ShellSubscriber::startPull(int64_t token, int64_t intervalMillis) {
}
}
void ShellSubscriber::readConfig(int in) {
if (in <= 0) {
// Must be called with the lock acquired, so that mProto isn't being written to
// at the same time by multiple threads.
void ShellSubscriber::writeToOutputLocked(const vector<std::shared_ptr<LogEvent>>& data,
const SimpleAtomMatcher& matcher) {
if (mOutput < 0) {
return;
}
while (1) {
size_t bufferSize = 0;
int result = 0;
if ((result = read(in, &bufferSize, sizeof(bufferSize))) == 0) {
VLOG("Done reading");
break;
} else if (result < 0 || result != sizeof(bufferSize)) {
ALOGE("Error reading config size");
break;
}
vector<uint8_t> buffer(bufferSize);
if ((result = read(in, buffer.data(), bufferSize)) > 0 && ((size_t)result) == bufferSize) {
ShellSubscription config;
if (config.ParseFromArray(buffer.data(), bufferSize)) {
updateConfig(config);
} else {
ALOGE("error parsing the config");
break;
}
} else {
VLOG("Error reading the config, returned: %d, expecting %zu", result, bufferSize);
break;
int count = 0;
mProto.clear();
for (const auto& event : data) {
VLOG("%s", event->ToString().c_str());
if (matchesSimple(*mUidMap, matcher, *event)) {
VLOG("matched");
count++;
uint64_t atomToken = mProto.start(util::FIELD_TYPE_MESSAGE |
util::FIELD_COUNT_REPEATED | FIELD_ID_ATOM);
event->ToProto(mProto);
mProto.end(atomToken);
}
}
}
void ShellSubscriber::cleanUpLocked() {
// The file descriptors will be closed by binder.
mInput = 0;
mOutput = 0;
mResultReceiver = nullptr;
mPushedMatchers.clear();
mPulledInfo.clear();
mPullToken = 0;
VLOG("done clean up");
if (count > 0) {
// First write the payload size.
size_t bufferSize = mProto.size();
write(mOutput, &bufferSize, sizeof(bufferSize));
VLOG("%d atoms, proto size: %zu", count, bufferSize);
// Then write the payload.
mProto.flush(mOutput);
}
}
void ShellSubscriber::onLogEvent(const LogEvent& event) {
// Acquire a lock to prevent corruption from multiple threads writing to
// mProto.
std::lock_guard<std::mutex> lock(mMutex);
if (mOutput <= 0) {
if (mOutput < 0) {
return;
}
mProto.clear();
for (const auto& matcher : mPushedMatchers) {
if (matchesSimple(*mUidMap, matcher, event)) {
VLOG("%s", event.ToString().c_str());
@@ -208,25 +213,27 @@ void ShellSubscriber::onLogEvent(const LogEvent& event) {
util::FIELD_COUNT_REPEATED | FIELD_ID_ATOM);
event.ToProto(mProto);
mProto.end(atomToken);
// First write the payload size.
size_t bufferSize = mProto.size();
write(mOutput, &bufferSize, sizeof(bufferSize));
// Then write the payload.
mProto.flush(mOutput);
mProto.clear();
break;
}
}
}
void ShellSubscriber::binderDied(const wp<IBinder>& who) {
{
VLOG("Shell exits");
std::lock_guard<std::mutex> lock(mMutex);
cleanUpLocked();
}
mShellDied.notify_all();
void ShellSubscriber::cleanUpLocked() {
// The file descriptors will be closed by binder.
mInput = -1;
mOutput = -1;
mSubscriberId = 0;
mPushedMatchers.clear();
mPulledInfo.clear();
// Setting mPullToken == 0 tells pull thread that its work is done.
mPullToken = 0;
VLOG("done clean up");
}
} // namespace statsd

View File

@@ -19,7 +19,6 @@
#include "logd/LogEvent.h"
#include <android/util/ProtoOutputStream.h>
#include <binder/IResultReceiver.h>
#include <condition_variable>
#include <mutex>
#include <thread>
@@ -56,7 +55,7 @@ namespace statsd {
* Only one shell subscriber allowed at a time, because each shell subscriber blocks one thread
* until it exits.
*/
class ShellSubscriber : public virtual IBinder::DeathRecipient {
class ShellSubscriber : public virtual RefBase {
public:
ShellSubscriber(sp<UidMap> uidMap, sp<StatsPullerManager> pullerMgr)
: mUidMap(uidMap), mPullerMgr(pullerMgr){};
@@ -64,10 +63,7 @@ public:
/**
* Start a new subscription.
*/
void startNewSubscription(int inFd, int outFd, sp<IResultReceiver> resultReceiver,
int timeoutSec);
void binderDied(const wp<IBinder>& who);
void startNewSubscription(int inFd, int outFd, int timeoutSec);
void onLogEvent(const LogEvent& event);
@@ -80,7 +76,7 @@ private:
int64_t mInterval;
int64_t mPrevPullElapsedRealtimeMs;
};
void readConfig(int in);
bool readConfig();
void updateConfig(const ShellSubscription& config);
@@ -101,16 +97,16 @@ private:
std::condition_variable mShellDied; // semaphore for waiting until shell exits.
int mInput; // The input file descriptor
int mInput = -1; // The input file descriptor
int mOutput; // The output file descriptor
sp<IResultReceiver> mResultReceiver;
int mOutput = -1; // The output file descriptor
std::vector<SimpleAtomMatcher> mPushedMatchers;
std::vector<PullInfo> mPulledInfo;
int64_t mSubscriberId = 0; // A unique id to identify a subscriber.
int64_t mPullToken = 0; // A unique token to identify a puller thread.
};

View File

@@ -17,6 +17,7 @@
#include "hash.h"
#include "stats_log_util.h"
#include <aidl/android/os/IStatsCompanionService.h>
#include <private/android_filesystem_config.h>
#include <set>
#include <utils/SystemClock.h>
@@ -35,6 +36,10 @@ using android::util::FIELD_TYPE_STRING;
using android::util::FIELD_TYPE_UINT64;
using android::util::ProtoOutputStream;
using aidl::android::os::IStatsCompanionService;
using std::shared_ptr;
using std::string;
namespace android {
namespace os {
namespace statsd {
@@ -587,13 +592,13 @@ int64_t MillisToNano(const int64_t millis) {
}
bool checkPermissionForIds(const char* permission, pid_t pid, uid_t uid) {
sp<IStatsCompanionService> scs = getStatsCompanionService();
shared_ptr<IStatsCompanionService> scs = getStatsCompanionService();
if (scs == nullptr) {
return false;
}
bool success;
binder::Status status = scs->checkPermission(String16(permission), pid, uid, &success);
::ndk::ScopedAStatus status = scs->checkPermission(string(permission), pid, uid, &success);
if (!status.isOk()) {
return false;
}

View File

@@ -18,26 +18,16 @@
#include "Log.h"
#include "statscompanion_util.h"
#include <android/binder_auto_utils.h>
#include <android/binder_manager.h>
namespace android {
namespace os {
namespace statsd {
sp <IStatsCompanionService> getStatsCompanionService() {
sp<IStatsCompanionService> statsCompanion = nullptr;
// Get statscompanion service from service manager
static const sp <IServiceManager> sm(defaultServiceManager());
if (statsCompanion == nullptr) {
if (sm != nullptr) {
const String16 name("statscompanion");
statsCompanion = interface_cast<IStatsCompanionService>(sm->checkService(name));
if (statsCompanion == nullptr) {
ALOGW("statscompanion service unavailable!");
return nullptr;
}
}
}
return statsCompanion;
shared_ptr<IStatsCompanionService> getStatsCompanionService() {
::ndk::SpAIBinder binder(AServiceManager_getService("statscompanion"));
return IStatsCompanionService::fromBinder(binder);
}
} // namespace statsd

View File

@@ -16,14 +16,17 @@
#pragma once
#include "StatsLogProcessor.h"
#include <aidl/android/os/IStatsCompanionService.h>
using aidl::android::os::IStatsCompanionService;
using std::shared_ptr;
namespace android {
namespace os {
namespace statsd {
/** Fetches and returns the StatsCompanionService. */
sp<IStatsCompanionService> getStatsCompanionService();
shared_ptr<IStatsCompanionService> getStatsCompanionService();
} // namespace statsd
} // namespace os

View File

@@ -27,38 +27,52 @@ namespace statsd {
using std::vector;
class BroadcastSubscriberDeathRecipient : public android::IBinder::DeathRecipient {
public:
BroadcastSubscriberDeathRecipient(const ConfigKey& configKey, int64_t subscriberId):
mConfigKey(configKey),
mSubscriberId(subscriberId) {}
~BroadcastSubscriberDeathRecipient() override = default;
private:
ConfigKey mConfigKey;
int64_t mSubscriberId;
struct BroadcastSubscriberDeathCookie {
BroadcastSubscriberDeathCookie(const ConfigKey& configKey, int64_t subscriberId,
const shared_ptr<IPendingIntentRef>& pir):
mConfigKey(configKey),
mSubscriberId(subscriberId),
mPir(pir) {}
void binderDied(const android::wp<android::IBinder>& who) override {
if (IInterface::asBinder(SubscriberReporter::getInstance().getBroadcastSubscriber(
mConfigKey, mSubscriberId)) == who.promote()) {
SubscriberReporter::getInstance().unsetBroadcastSubscriber(mConfigKey, mSubscriberId);
}
}
ConfigKey mConfigKey;
int64_t mSubscriberId;
shared_ptr<IPendingIntentRef> mPir;
};
static void broadcastSubscriberDied(void* cookie) {
BroadcastSubscriberDeathCookie* cookie_ = (BroadcastSubscriberDeathCookie*)cookie;
ConfigKey configKey = cookie_->mConfigKey;
int64_t subscriberId = cookie_->mSubscriberId;
shared_ptr<IPendingIntentRef> pir = cookie_->mPir;
// TODO(b/149254662): Fix threading. This currently fails if a new pir gets
// set between the get and the unset.
if (SubscriberReporter::getInstance().getBroadcastSubscriber(configKey, subscriberId) == pir) {
SubscriberReporter::getInstance().unsetBroadcastSubscriber(configKey, subscriberId);
}
// The death recipient corresponding to this specific pir can never be
// triggered again, so free up resources.
delete cookie_;
}
static ::ndk::ScopedAIBinder_DeathRecipient sBroadcastSubscriberDeathRecipient(
AIBinder_DeathRecipient_new(broadcastSubscriberDied));
void SubscriberReporter::setBroadcastSubscriber(const ConfigKey& configKey,
int64_t subscriberId,
const sp<IPendingIntentRef>& pir) {
const shared_ptr<IPendingIntentRef>& pir) {
VLOG("SubscriberReporter::setBroadcastSubscriber called.");
lock_guard<std::mutex> lock(mLock);
lock_guard<mutex> lock(mLock);
mIntentMap[configKey][subscriberId] = pir;
IInterface::asBinder(pir)->linkToDeath(
new BroadcastSubscriberDeathRecipient(configKey, subscriberId));
// TODO(b/149254662): Is it ok to call linkToDeath while holding a lock?
AIBinder_linkToDeath(pir->asBinder().get(), sBroadcastSubscriberDeathRecipient.get(),
new BroadcastSubscriberDeathCookie(configKey, subscriberId, pir));
}
void SubscriberReporter::unsetBroadcastSubscriber(const ConfigKey& configKey,
int64_t subscriberId) {
VLOG("SubscriberReporter::unsetBroadcastSubscriber called.");
lock_guard<std::mutex> lock(mLock);
lock_guard<mutex> lock(mLock);
auto subscriberMapIt = mIntentMap.find(configKey);
if (subscriberMapIt != mIntentMap.end()) {
subscriberMapIt->second.erase(subscriberId);
@@ -80,7 +94,7 @@ void SubscriberReporter::alertBroadcastSubscriber(const ConfigKey& configKey,
// config id - the name of this config (for this particular uid)
VLOG("SubscriberReporter::alertBroadcastSubscriber called.");
lock_guard<std::mutex> lock(mLock);
lock_guard<mutex> lock(mLock);
if (!subscription.has_broadcast_subscriber_details()
|| !subscription.broadcast_subscriber_details().has_subscriber_id()) {
@@ -89,10 +103,12 @@ void SubscriberReporter::alertBroadcastSubscriber(const ConfigKey& configKey,
}
int64_t subscriberId = subscription.broadcast_subscriber_details().subscriber_id();
vector<String16> cookies;
// TODO(b/149254662): Is there a way to convert a RepeatedPtrField into a
// vector without copying?
vector<string> cookies;
cookies.reserve(subscription.broadcast_subscriber_details().cookie_size());
for (auto& cookie : subscription.broadcast_subscriber_details().cookie()) {
cookies.push_back(String16(cookie.c_str()));
cookies.push_back(cookie);
}
auto it1 = mIntentMap.find(configKey);
@@ -109,10 +125,10 @@ void SubscriberReporter::alertBroadcastSubscriber(const ConfigKey& configKey,
sendBroadcastLocked(it2->second, configKey, subscription, cookies, dimKey);
}
void SubscriberReporter::sendBroadcastLocked(const sp<IPendingIntentRef>& pir,
void SubscriberReporter::sendBroadcastLocked(const shared_ptr<IPendingIntentRef>& pir,
const ConfigKey& configKey,
const Subscription& subscription,
const vector<String16>& cookies,
const vector<string>& cookies,
const MetricDimensionKey& dimKey) const {
VLOG("SubscriberReporter::sendBroadcastLocked called.");
pir->sendSubscriberBroadcast(
@@ -124,9 +140,9 @@ void SubscriberReporter::sendBroadcastLocked(const sp<IPendingIntentRef>& pir,
dimKey.getDimensionKeyInWhat().toStatsDimensionsValueParcel());
}
sp<IPendingIntentRef> SubscriberReporter::getBroadcastSubscriber(const ConfigKey& configKey,
int64_t subscriberId) {
lock_guard<std::mutex> lock(mLock);
shared_ptr<IPendingIntentRef> SubscriberReporter::getBroadcastSubscriber(const ConfigKey& configKey,
int64_t subscriberId) {
lock_guard<mutex> lock(mLock);
auto subscriberMapIt = mIntentMap.find(configKey);
if (subscriberMapIt == mIntentMap.end()) {
return nullptr;

View File

@@ -16,9 +16,9 @@
#pragma once
#include <android/os/IPendingIntentRef.h>
#include <android/os/IStatsCompanionService.h>
#include <aidl/android/os/IPendingIntentRef.h>
#include <utils/RefBase.h>
#include <utils/String16.h>
#include "config/ConfigKey.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // subscription
@@ -28,6 +28,13 @@
#include <unordered_map>
#include <vector>
using aidl::android::os::IPendingIntentRef;
using std::mutex;
using std::shared_ptr;
using std::string;
using std::unordered_map;
using std::vector;
namespace android {
namespace os {
namespace statsd {
@@ -51,7 +58,7 @@ public:
*/
void setBroadcastSubscriber(const ConfigKey& configKey,
int64_t subscriberId,
const sp<IPendingIntentRef>& pir);
const shared_ptr<IPendingIntentRef>& pir);
/**
* Erases any intentSender information from the given (configKey, subscriberId) pair.
@@ -67,28 +74,25 @@ public:
const Subscription& subscription,
const MetricDimensionKey& dimKey) const;
sp<IPendingIntentRef> getBroadcastSubscriber(const ConfigKey& configKey, int64_t subscriberId);
shared_ptr<IPendingIntentRef> getBroadcastSubscriber(const ConfigKey& configKey,
int64_t subscriberId);
private:
SubscriberReporter() {};
mutable std::mutex mLock;
/** Binder interface for communicating with StatsCompanionService. */
sp<IStatsCompanionService> mStatsCompanionService = nullptr;
mutable mutex mLock;
/** Maps <ConfigKey, SubscriberId> -> IPendingIntentRef (which represents a PendingIntent). */
std::unordered_map<ConfigKey,
std::unordered_map<int64_t, sp<IPendingIntentRef>>> mIntentMap;
unordered_map<ConfigKey, unordered_map<int64_t, shared_ptr<IPendingIntentRef>>> mIntentMap;
/**
* Sends a broadcast via the given intentSender (using mStatsCompanionService), along
* with the information in the other parameters.
*/
void sendBroadcastLocked(const sp<IPendingIntentRef>& pir,
void sendBroadcastLocked(const shared_ptr<IPendingIntentRef>& pir,
const ConfigKey& configKey,
const Subscription& subscription,
const std::vector<String16>& cookies,
const vector<string>& cookies,
const MetricDimensionKey& dimKey) const;
};

View File

@@ -17,14 +17,16 @@
#include <gtest/gtest.h>
using namespace android::os::statsd;
using std::shared_ptr;
#ifdef __ANDROID__
TEST(AlarmMonitor, popSoonerThan) {
std::string emptyMetricId;
std::string emptyDimensionId;
unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> set;
AlarmMonitor am(2, [](const sp<IStatsCompanionService>&, int64_t){},
[](const sp<IStatsCompanionService>&){});
AlarmMonitor am(2,
[](const shared_ptr<IStatsCompanionService>&, int64_t){},
[](const shared_ptr<IStatsCompanionService>&){});
set = am.popSoonerThan(5);
EXPECT_TRUE(set.empty());

View File

@@ -32,6 +32,8 @@
using namespace android;
using namespace testing;
using ::ndk::SharedRefBase;
using std::shared_ptr;
namespace android {
namespace os {
@@ -49,10 +51,12 @@ public:
MockMetricsManager()
: MetricsManager(ConfigKey(1, 12345), StatsdConfig(), 1000, 1000, new UidMap(),
new StatsPullerManager(),
new AlarmMonitor(10, [](const sp<IStatsCompanionService>&, int64_t) {},
[](const sp<IStatsCompanionService>&) {}),
new AlarmMonitor(10, [](const sp<IStatsCompanionService>&, int64_t) {},
[](const sp<IStatsCompanionService>&) {})) {
new AlarmMonitor(10,
[](const shared_ptr<IStatsCompanionService>&, int64_t) {},
[](const shared_ptr<IStatsCompanionService>&) {}),
new AlarmMonitor(10,
[](const shared_ptr<IStatsCompanionService>&, int64_t) {},
[](const shared_ptr<IStatsCompanionService>&) {})) {
}
MOCK_METHOD0(byteSize, size_t());
@@ -1488,9 +1492,9 @@ TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart) {
metric2ActivationTrigger2->set_activation_type(ACTIVATE_IMMEDIATELY);
// Send the config.
StatsService service(nullptr, nullptr);
shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
string serialized = config1.SerializeAsString();
service.addConfigurationChecked(uid, configId, {serialized.begin(), serialized.end()});
service->addConfigurationChecked(uid, configId, {serialized.begin(), serialized.end()});
// Make sure the config is stored on disk. Otherwise, we will not reset on system server death.
StatsdConfig tmpConfig;
@@ -1501,7 +1505,7 @@ TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart) {
// Metric 2 is not active.
// Metric 3 is active.
// {{{---------------------------------------------------------------------------
sp<StatsLogProcessor> processor = service.mProcessor;
sp<StatsLogProcessor> processor = service->mProcessor;
EXPECT_EQ(1, processor->mMetricsManagers.size());
auto it = processor->mMetricsManagers.find(cfgKey1);
EXPECT_TRUE(it != processor->mMetricsManagers.end());
@@ -1592,7 +1596,7 @@ TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart) {
EXPECT_TRUE(approximateSystemServerDeath < NS_PER_SEC + configAddedTimeNs);
// System server dies.
service.binderDied(nullptr);
service->statsCompanionServiceDiedImpl();
// We should have a new metrics manager. Lets get it and ensure activation status is restored.
// {{{---------------------------------------------------------------------------

View File

@@ -16,6 +16,7 @@
#include "config/ConfigKey.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include <android/binder_interface_utils.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -29,33 +30,34 @@ namespace os {
namespace statsd {
using android::util::ProtoOutputStream;
using ::ndk::SharedRefBase;
#ifdef __ANDROID__
TEST(StatsServiceTest, TestAddConfig_simple) {
StatsService service(nullptr, nullptr);
shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
StatsdConfig config;
config.set_id(12345);
string serialized = config.SerializeAsString();
EXPECT_TRUE(
service.addConfigurationChecked(123, 12345, {serialized.begin(), serialized.end()}));
service->addConfigurationChecked(123, 12345, {serialized.begin(), serialized.end()}));
}
TEST(StatsServiceTest, TestAddConfig_empty) {
StatsService service(nullptr, nullptr);
shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
string serialized = "";
EXPECT_TRUE(
service.addConfigurationChecked(123, 12345, {serialized.begin(), serialized.end()}));
service->addConfigurationChecked(123, 12345, {serialized.begin(), serialized.end()}));
}
TEST(StatsServiceTest, TestAddConfig_invalid) {
StatsService service(nullptr, nullptr);
shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
string serialized = "Invalid config!";
EXPECT_FALSE(
service.addConfigurationChecked(123, 12345, {serialized.begin(), serialized.end()}));
service->addConfigurationChecked(123, 12345, {serialized.begin(), serialized.end()}));
}
TEST(StatsServiceTest, TestGetUidFromArgs) {
@@ -69,32 +71,32 @@ TEST(StatsServiceTest, TestGetUidFromArgs) {
int32_t uid;
StatsService service(nullptr, nullptr);
service.mEngBuild = true;
shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
service->mEngBuild = true;
// "-1"
EXPECT_FALSE(service.getUidFromArgs(args, 0, uid));
EXPECT_FALSE(service->getUidFromArgs(args, 0, uid));
// "0"
EXPECT_TRUE(service.getUidFromArgs(args, 1, uid));
EXPECT_TRUE(service->getUidFromArgs(args, 1, uid));
EXPECT_EQ(0, uid);
// "1"
EXPECT_TRUE(service.getUidFromArgs(args, 2, uid));
EXPECT_TRUE(service->getUidFromArgs(args, 2, uid));
EXPECT_EQ(1, uid);
// "999999999999999999"
EXPECT_FALSE(service.getUidFromArgs(args, 3, uid));
EXPECT_FALSE(service->getUidFromArgs(args, 3, uid));
// "a1"
EXPECT_FALSE(service.getUidFromArgs(args, 4, uid));
EXPECT_FALSE(service->getUidFromArgs(args, 4, uid));
// ""
EXPECT_FALSE(service.getUidFromArgs(args, 5, uid));
EXPECT_FALSE(service->getUidFromArgs(args, 5, uid));
// For a non-userdebug, uid "1" cannot be impersonated.
service.mEngBuild = false;
EXPECT_FALSE(service.getUidFromArgs(args, 2, uid));
service->mEngBuild = false;
EXPECT_FALSE(service->getUidFromArgs(args, 2, uid));
}
#else

View File

@@ -15,12 +15,14 @@
#include "src/anomaly/AlarmTracker.h"
#include <gtest/gtest.h>
#include <log/log_time.h>
#include <stdio.h>
#include <vector>
using namespace testing;
using android::sp;
using std::set;
using std::shared_ptr;
using std::unordered_map;
using std::vector;
@@ -34,8 +36,9 @@ const ConfigKey kConfigKey(0, 12345);
TEST(AlarmTrackerTest, TestTriggerTimestamp) {
sp<AlarmMonitor> subscriberAlarmMonitor =
new AlarmMonitor(100, [](const sp<IStatsCompanionService>&, int64_t){},
[](const sp<IStatsCompanionService>&){});
new AlarmMonitor(100,
[](const shared_ptr<IStatsCompanionService>&, int64_t){},
[](const shared_ptr<IStatsCompanionService>&){});
Alarm alarm;
alarm.set_offset_millis(15 * MS_PER_SEC);
alarm.set_period_millis(60 * 60 * MS_PER_SEC); // 1hr

View File

@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <android/binder_interface_utils.h>
#include <gtest/gtest.h>
#include <vector>
@@ -20,6 +21,8 @@
#include "src/stats_log_util.h"
#include "tests/statsd_test_util.h"
using ::ndk::SharedRefBase;
namespace android {
namespace os {
namespace statsd {
@@ -71,7 +74,8 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) {
ConfigKey cfgKey;
auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
new FakeSubsystemSleepCallback(), ATOM_TAG);
SharedRefBase::make<FakeSubsystemSleepCallback>(),
ATOM_TAG);
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
processor->mPullerManager->ForceClearPullerCache();
@@ -216,7 +220,8 @@ TEST(GaugeMetricE2eTest, TestConditionChangeToTrueSamplePulledEvents) {
ConfigKey cfgKey;
auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
new FakeSubsystemSleepCallback(), ATOM_TAG);
SharedRefBase::make<FakeSubsystemSleepCallback>(),
ATOM_TAG);
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
processor->mPullerManager->ForceClearPullerCache();
@@ -317,7 +322,8 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm) {
ConfigKey cfgKey;
auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
new FakeSubsystemSleepCallback, ATOM_TAG);
SharedRefBase::make<FakeSubsystemSleepCallback>(),
ATOM_TAG);
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
processor->mPullerManager->ForceClearPullerCache();
@@ -426,7 +432,8 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsWithActivation) {
ConfigKey cfgKey;
auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
new FakeSubsystemSleepCallback(), ATOM_TAG);
SharedRefBase::make<FakeSubsystemSleepCallback>(),
ATOM_TAG);
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
processor->mPullerManager->ForceClearPullerCache();
@@ -544,7 +551,8 @@ TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsNoCondition) {
ConfigKey cfgKey;
auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
new FakeSubsystemSleepCallback(), ATOM_TAG);
SharedRefBase::make<FakeSubsystemSleepCallback>(),
ATOM_TAG);
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
processor->mPullerManager->ForceClearPullerCache();

View File

@@ -12,9 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <android/os/BnPullAtomCallback.h>
#include <android/os/IPullAtomResultReceiver.h>
#include <binder/IPCThreadState.h>
#include <android/binder_ibinder.h>
#include <android/binder_interface_utils.h>
#include <gtest/gtest.h>
#include <vector>
@@ -24,6 +23,9 @@
#include "src/stats_log_util.h"
#include "tests/statsd_test_util.h"
using::ndk::SharedRefBase;
using std::shared_ptr;
namespace android {
namespace os {
namespace statsd {
@@ -34,19 +36,17 @@ const string kApp1 = "app1.sharing.1";
const int kConfigKey = 789130123; // Randomly chosen to avoid collisions with existing configs.
const int kCallingUid = 0; // Randomly chosen
void SendConfig(StatsService& service, const StatsdConfig& config) {
void SendConfig(shared_ptr<StatsService>& service, const StatsdConfig& config) {
string str;
config.SerializeToString(&str);
std::vector<uint8_t> configAsVec(str.begin(), str.end());
bool success;
service.addConfiguration(kConfigKey, configAsVec, kCallingUid);
std::vector<int8_t> configAsVec(str.begin(), str.end());
service->addConfiguration(kConfigKey, configAsVec, kCallingUid);
}
ConfigMetricsReport GetReports(sp<StatsLogProcessor> processor, int64_t timestamp,
bool include_current = false) {
vector<uint8_t> output;
IPCThreadState* ipc = IPCThreadState::self();
ConfigKey configKey(ipc->getCallingUid(), kConfigKey);
ConfigKey configKey(AIBinder_getCallingUid(), kConfigKey);
processor->onDumpReport(configKey, timestamp, include_current /* include_current_bucket*/,
true /* erase_data */, ADB_DUMP, NO_TIME_CONSTRAINTS, &output);
ConfigMetricsReportList reports;
@@ -114,56 +114,56 @@ StatsdConfig MakeGaugeMetricConfig(int64_t minTime) {
} // anonymous namespace
TEST(PartialBucketE2eTest, TestCountMetricWithoutSplit) {
StatsService service(nullptr, nullptr);
shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
SendConfig(service, MakeConfig());
int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
// initialized with.
service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 2).get());
service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 2).get());
ConfigMetricsReport report = GetReports(service.mProcessor, start + 3);
ConfigMetricsReport report = GetReports(service->mProcessor, start + 3);
// Expect no metrics since the bucket has not finished yet.
EXPECT_EQ(1, report.metrics_size());
EXPECT_EQ(0, report.metrics(0).count_metrics().data_size());
}
TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnNewApp) {
StatsService service(nullptr, nullptr);
shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
SendConfig(service, MakeConfig());
int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
// initialized with.
// Force the uidmap to update at timestamp 2.
service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
// This is a new installation, so there shouldn't be a split (should be same as the without
// split case).
service.mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"),
service->mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"),
String16(""));
// Goes into the second bucket.
service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
ConfigMetricsReport report = GetReports(service.mProcessor, start + 4);
ConfigMetricsReport report = GetReports(service->mProcessor, start + 4);
EXPECT_EQ(1, report.metrics_size());
EXPECT_EQ(0, report.metrics(0).count_metrics().data_size());
}
TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade) {
StatsService service(nullptr, nullptr);
shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
SendConfig(service, MakeConfig());
int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
// initialized with.
service.mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())},
{String16("")});
service->mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())},
{String16("")});
// Force the uidmap to update at timestamp 2.
service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
service.mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"),
service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
service->mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"),
String16(""));
// Goes into the second bucket.
service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
ConfigMetricsReport report = GetReports(service.mProcessor, start + 4);
ConfigMetricsReport report = GetReports(service->mProcessor, start + 4);
backfillStartEndTimestamp(&report);
ASSERT_EQ(1, report.metrics_size());
@@ -177,20 +177,20 @@ TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade) {
}
TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval) {
StatsService service(nullptr, nullptr);
shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
SendConfig(service, MakeConfig());
int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
// initialized with.
service.mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())},
{String16("")});
service->mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())},
{String16("")});
// Force the uidmap to update at timestamp 2.
service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
service.mUidMap->removeApp(start + 2, String16(kApp1.c_str()), 1);
service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
service->mUidMap->removeApp(start + 2, String16(kApp1.c_str()), 1);
// Goes into the second bucket.
service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
ConfigMetricsReport report = GetReports(service.mProcessor, start + 4);
ConfigMetricsReport report = GetReports(service->mProcessor, start + 4);
backfillStartEndTimestamp(&report);
ASSERT_EQ(1, report.metrics_size());
@@ -204,44 +204,44 @@ TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval) {
}
TEST(PartialBucketE2eTest, TestValueMetricWithoutMinPartialBucket) {
StatsService service(nullptr, nullptr);
service.mPullerManager->RegisterPullAtomCallback(
shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
service->mPullerManager->RegisterPullAtomCallback(
/*uid=*/0, android::util::SUBSYSTEM_SLEEP_STATE, NS_PER_SEC, NS_PER_SEC * 10, {},
new FakeSubsystemSleepCallback());
SharedRefBase::make<FakeSubsystemSleepCallback>());
// Partial buckets don't occur when app is first installed.
service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""));
service->mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""));
SendConfig(service, MakeValueMetricConfig(0));
int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
// initialized with.
service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
service.mUidMap->updateApp(5 * 60 * NS_PER_SEC + start + 2, String16(kApp1.c_str()), 1, 2,
String16("v2"), String16(""));
service->mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
service->mUidMap->updateApp(5 * 60 * NS_PER_SEC + start + 2, String16(kApp1.c_str()), 1, 2,
String16("v2"), String16(""));
ConfigMetricsReport report =
GetReports(service.mProcessor, 5 * 60 * NS_PER_SEC + start + 100, true);
GetReports(service->mProcessor, 5 * 60 * NS_PER_SEC + start + 100, true);
EXPECT_EQ(1, report.metrics_size());
EXPECT_EQ(0, report.metrics(0).value_metrics().skipped_size());
}
TEST(PartialBucketE2eTest, TestValueMetricWithMinPartialBucket) {
StatsService service(nullptr, nullptr);
service.mPullerManager->RegisterPullAtomCallback(
shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
service->mPullerManager->RegisterPullAtomCallback(
/*uid=*/0, android::util::SUBSYSTEM_SLEEP_STATE, NS_PER_SEC, NS_PER_SEC * 10, {},
new FakeSubsystemSleepCallback());
SharedRefBase::make<FakeSubsystemSleepCallback>());
// Partial buckets don't occur when app is first installed.
service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""));
service->mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""));
SendConfig(service, MakeValueMetricConfig(60 * NS_PER_SEC /* One minute */));
int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
// initialized with.
const int64_t endSkipped = 5 * 60 * NS_PER_SEC + start + 2;
service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
service.mUidMap->updateApp(endSkipped, String16(kApp1.c_str()), 1, 2, String16("v2"),
service->mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
service->mUidMap->updateApp(endSkipped, String16(kApp1.c_str()), 1, 2, String16("v2"),
String16(""));
ConfigMetricsReport report =
GetReports(service.mProcessor, 5 * 60 * NS_PER_SEC + start + 100 * NS_PER_SEC, true);
GetReports(service->mProcessor, 5 * 60 * NS_PER_SEC + start + 100 * NS_PER_SEC, true);
backfillStartEndTimestamp(&report);
ASSERT_EQ(1, report.metrics_size());
@@ -253,38 +253,38 @@ TEST(PartialBucketE2eTest, TestValueMetricWithMinPartialBucket) {
}
TEST(PartialBucketE2eTest, TestGaugeMetricWithoutMinPartialBucket) {
StatsService service(nullptr, nullptr);
shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
// Partial buckets don't occur when app is first installed.
service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""));
service->mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""));
SendConfig(service, MakeGaugeMetricConfig(0));
int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
// initialized with.
service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
service.mUidMap->updateApp(5 * 60 * NS_PER_SEC + start + 2, String16(kApp1.c_str()), 1, 2,
service->mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
service->mUidMap->updateApp(5 * 60 * NS_PER_SEC + start + 2, String16(kApp1.c_str()), 1, 2,
String16("v2"), String16(""));
ConfigMetricsReport report =
GetReports(service.mProcessor, 5 * 60 * NS_PER_SEC + start + 100, true);
GetReports(service->mProcessor, 5 * 60 * NS_PER_SEC + start + 100, true);
EXPECT_EQ(1, report.metrics_size());
EXPECT_EQ(0, report.metrics(0).gauge_metrics().skipped_size());
}
TEST(PartialBucketE2eTest, TestGaugeMetricWithMinPartialBucket) {
StatsService service(nullptr, nullptr);
shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
// Partial buckets don't occur when app is first installed.
service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""));
service->mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""));
SendConfig(service, MakeGaugeMetricConfig(60 * NS_PER_SEC /* One minute */));
int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
// initialized with.
const int64_t endSkipped = 5 * 60 * NS_PER_SEC + start + 2;
service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
service.mUidMap->updateApp(endSkipped, String16(kApp1.c_str()), 1, 2, String16("v2"),
String16(""));
service->mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start);
service->mUidMap->updateApp(endSkipped, String16(kApp1.c_str()), 1, 2, String16("v2"),
String16(""));
ConfigMetricsReport report =
GetReports(service.mProcessor, 5 * 60 * NS_PER_SEC + start + 100 * NS_PER_SEC, true);
GetReports(service->mProcessor, 5 * 60 * NS_PER_SEC + start + 100 * NS_PER_SEC, true);
backfillStartEndTimestamp(&report);
ASSERT_EQ(1, report.metrics_size());
ASSERT_EQ(1, report.metrics(0).gauge_metrics().skipped_size());

View File

@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <android/binder_interface_utils.h>
#include <gtest/gtest.h>
#include "src/StatsLogProcessor.h"
@@ -20,6 +21,8 @@
#include <vector>
using ::ndk::SharedRefBase;
namespace android {
namespace os {
namespace statsd {
@@ -70,7 +73,7 @@ TEST(ValueMetricE2eTest, TestPulledEvents) {
ConfigKey cfgKey;
auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
new FakeSubsystemSleepCallback(),
SharedRefBase::make<FakeSubsystemSleepCallback>(),
android::util::SUBSYSTEM_SLEEP_STATE);
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
@@ -175,7 +178,7 @@ TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm) {
ConfigKey cfgKey;
auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
new FakeSubsystemSleepCallback(),
SharedRefBase::make<FakeSubsystemSleepCallback>(),
android::util::SUBSYSTEM_SLEEP_STATE);
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
@@ -288,7 +291,7 @@ TEST(ValueMetricE2eTest, TestPulledEvents_WithActivation) {
ConfigKey cfgKey;
auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
new FakeSubsystemSleepCallback(),
SharedRefBase::make<FakeSubsystemSleepCallback>(),
android::util::SUBSYSTEM_SLEEP_STATE);
EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());

View File

@@ -14,8 +14,10 @@
#include "src/external/StatsCallbackPuller.h"
#include <android/os/BnPullAtomCallback.h>
#include <android/os/IPullAtomResultReceiver.h>
#include <aidl/android/os/BnPullAtomCallback.h>
#include <aidl/android/os/IPullAtomResultReceiver.h>
#include <aidl/android/util/StatsEventParcel.h>
#include <android/binder_interface_utils.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <stdio.h>
@@ -35,6 +37,11 @@ namespace os {
namespace statsd {
using namespace testing;
using Status = ::ndk::ScopedAStatus;
using aidl::android::os::BnPullAtomCallback;
using aidl::android::os::IPullAtomResultReceiver;
using aidl::android::util::StatsEventParcel;
using ::ndk::SharedRefBase;
using std::make_shared;
using std::shared_ptr;
using std::vector;
@@ -58,15 +65,15 @@ AStatsEvent* createSimpleEvent(int64_t value) {
return event;
}
void executePull(const sp<IPullAtomResultReceiver>& resultReceiver) {
void executePull(const shared_ptr<IPullAtomResultReceiver>& resultReceiver) {
// Convert stats_events into StatsEventParcels.
std::vector<android::util::StatsEventParcel> parcels;
vector<StatsEventParcel> parcels;
for (int i = 0; i < values.size(); i++) {
AStatsEvent* event = createSimpleEvent(values[i]);
size_t size;
uint8_t* buffer = AStatsEvent_getBuffer(event, &size);
android::util::StatsEventParcel p;
StatsEventParcel p;
// vector.assign() creates a copy, but this is inevitable unless
// stats_event.h/c uses a vector as opposed to a buffer.
p.buffer.assign(buffer, buffer + size);
@@ -80,11 +87,11 @@ void executePull(const sp<IPullAtomResultReceiver>& resultReceiver) {
class FakePullAtomCallback : public BnPullAtomCallback {
public:
binder::Status onPullAtom(int atomTag,
const sp<IPullAtomResultReceiver>& resultReceiver) override {
Status onPullAtom(int atomTag,
const shared_ptr<IPullAtomResultReceiver>& resultReceiver) override {
// Force pull to happen in separate thread to simulate binder.
pullThread = std::thread(executePull, resultReceiver);
return binder::Status::ok();
return Status::ok();
}
};
@@ -111,7 +118,7 @@ public:
} // Anonymous namespace.
TEST_F(StatsCallbackPullerTest, PullSuccess) {
sp<FakePullAtomCallback> cb = new FakePullAtomCallback();
shared_ptr<FakePullAtomCallback> cb = SharedRefBase::make<FakePullAtomCallback>();
int64_t value = 43;
pullSuccess = true;
values.push_back(value);
@@ -132,20 +139,20 @@ TEST_F(StatsCallbackPullerTest, PullSuccess) {
}
TEST_F(StatsCallbackPullerTest, PullFail) {
sp<FakePullAtomCallback> cb = new FakePullAtomCallback();
shared_ptr<FakePullAtomCallback> cb = SharedRefBase::make<FakePullAtomCallback>();
pullSuccess = false;
int64_t value = 1234;
values.push_back(value);
StatsCallbackPuller puller(pullTagId, cb, pullCoolDownNs, pullTimeoutNs, {});
vector<std::shared_ptr<LogEvent>> dataHolder;
vector<shared_ptr<LogEvent>> dataHolder;
EXPECT_FALSE(puller.PullInternal(&dataHolder));
EXPECT_EQ(0, dataHolder.size());
}
TEST_F(StatsCallbackPullerTest, PullTimeout) {
sp<FakePullAtomCallback> cb = new FakePullAtomCallback();
shared_ptr<FakePullAtomCallback> cb = SharedRefBase::make<FakePullAtomCallback>();
pullSuccess = true;
pullDelayNs = 500000000; // 500ms.
pullTimeoutNs = 10000; // 10 microseconds.
@@ -154,7 +161,7 @@ TEST_F(StatsCallbackPullerTest, PullTimeout) {
StatsCallbackPuller puller(pullTagId, cb, pullCoolDownNs, pullTimeoutNs, {});
vector<std::shared_ptr<LogEvent>> dataHolder;
vector<shared_ptr<LogEvent>> dataHolder;
int64_t startTimeNs = getElapsedRealtimeNs();
// Returns true to let StatsPuller code evaluate the timeout.
EXPECT_TRUE(puller.PullInternal(&dataHolder));
@@ -174,7 +181,7 @@ TEST_F(StatsCallbackPullerTest, PullTimeout) {
// Register a puller and ensure that the timeout logic works.
TEST_F(StatsCallbackPullerTest, RegisterAndTimeout) {
sp<FakePullAtomCallback> cb = new FakePullAtomCallback();
shared_ptr<FakePullAtomCallback> cb = SharedRefBase::make<FakePullAtomCallback>();
pullSuccess = true;
pullDelayNs = 500000000; // 500 ms.
pullTimeoutNs = 10000; // 10 microsseconds.
@@ -184,7 +191,7 @@ TEST_F(StatsCallbackPullerTest, RegisterAndTimeout) {
StatsPullerManager pullerManager;
pullerManager.RegisterPullAtomCallback(/*uid=*/-1, pullTagId, pullCoolDownNs, pullTimeoutNs,
vector<int32_t>(), cb);
vector<std::shared_ptr<LogEvent>> dataHolder;
vector<shared_ptr<LogEvent>> dataHolder;
int64_t startTimeNs = getElapsedRealtimeNs();
// Returns false, since StatsPuller code will evaluate the timeout.
EXPECT_FALSE(pullerManager.Pull(pullTagId, &dataHolder));

View File

@@ -34,27 +34,6 @@ using testing::StrictMock;
#ifdef __ANDROID__
class MyResultReceiver : public BnResultReceiver {
public:
Mutex mMutex;
Condition mCondition;
bool mHaveResult = false;
int32_t mResult = 0;
virtual void send(int32_t resultCode) {
AutoMutex _l(mMutex);
mResult = resultCode;
mHaveResult = true;
mCondition.signal();
}
int32_t waitForResult() {
AutoMutex _l(mMutex);
mCondition.waitRelative(mMutex, 1000000000);
return mResult;
}
};
void runShellTest(ShellSubscription config, sp<MockUidMap> uidMap,
sp<MockStatsPullerManager> pullerManager,
const vector<std::shared_ptr<LogEvent>>& pushedEvents,
@@ -67,10 +46,7 @@ void runShellTest(ShellSubscription config, sp<MockUidMap> uidMap,
ASSERT_EQ(0, pipe(fds_data));
size_t bufferSize = config.ByteSize();
// write the config to pipe, first write size of the config
vector<uint8_t> size_buffer(sizeof(bufferSize));
std::memcpy(size_buffer.data(), &bufferSize, sizeof(bufferSize));
write(fds_config[1], &bufferSize, sizeof(bufferSize));
// then write config itself
vector<uint8_t> buffer(bufferSize);
@@ -79,11 +55,10 @@ void runShellTest(ShellSubscription config, sp<MockUidMap> uidMap,
close(fds_config[1]);
sp<ShellSubscriber> shellClient = new ShellSubscriber(uidMap, pullerManager);
sp<MyResultReceiver> resultReceiver = new MyResultReceiver();
// mimic a binder thread that a shell subscriber runs on. it would block.
std::thread reader([&resultReceiver, &fds_config, &fds_data, &shellClient] {
shellClient->startNewSubscription(fds_config[0], fds_data[1], resultReceiver, -1);
std::thread reader([&shellClient, &fds_config, &fds_data] {
shellClient->startNewSubscription(fds_config[0], fds_data[1], /*timeoutSec=*/-1);
});
reader.detach();

View File

@@ -14,6 +14,11 @@
#include "statsd_test_util.h"
#include <aidl/android/util/StatsEventParcel.h>
using aidl::android::util::StatsEventParcel;
using std::shared_ptr;
namespace android {
namespace os {
namespace statsd {
@@ -581,7 +586,7 @@ std::unique_ptr<LogEvent> CreateUidProcessStateChangedEvent(
sp<StatsLogProcessor> CreateStatsLogProcessor(const int64_t timeBaseNs, const int64_t currentTimeNs,
const StatsdConfig& config, const ConfigKey& key,
const sp<IPullAtomCallback>& puller,
const shared_ptr<IPullAtomCallback>& puller,
const int32_t atomTag) {
sp<UidMap> uidMap = new UidMap();
sp<StatsPullerManager> pullerManager = new StatsPullerManager();
@@ -590,11 +595,13 @@ sp<StatsLogProcessor> CreateStatsLogProcessor(const int64_t timeBaseNs, const in
puller);
}
sp<AlarmMonitor> anomalyAlarmMonitor =
new AlarmMonitor(1, [](const sp<IStatsCompanionService>&, int64_t){},
[](const sp<IStatsCompanionService>&){});
new AlarmMonitor(1,
[](const shared_ptr<IStatsCompanionService>&, int64_t){},
[](const shared_ptr<IStatsCompanionService>&){});
sp<AlarmMonitor> periodicAlarmMonitor =
new AlarmMonitor(1, [](const sp<IStatsCompanionService>&, int64_t){},
[](const sp<IStatsCompanionService>&){});
new AlarmMonitor(1,
[](const shared_ptr<IStatsCompanionService>&, int64_t){},
[](const shared_ptr<IStatsCompanionService>&){});
sp<StatsLogProcessor> processor =
new StatsLogProcessor(uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
timeBaseNs, [](const ConfigKey&) { return true; },
@@ -948,10 +955,10 @@ void backfillStartEndTimestamp(ConfigMetricsReportList *config_report_list) {
}
}
binder::Status FakeSubsystemSleepCallback::onPullAtom(
int atomTag, const sp<IPullAtomResultReceiver>& resultReceiver) {
Status FakeSubsystemSleepCallback::onPullAtom(int atomTag,
const shared_ptr<IPullAtomResultReceiver>& resultReceiver) {
// Convert stats_events into StatsEventParcels.
std::vector<android::util::StatsEventParcel> parcels;
std::vector<StatsEventParcel> parcels;
for (int i = 1; i < 3; i++) {
AStatsEvent* event = AStatsEvent_obtain();
AStatsEvent_setAtomId(event, atomTag);
@@ -965,7 +972,7 @@ binder::Status FakeSubsystemSleepCallback::onPullAtom(
size_t size;
uint8_t* buffer = AStatsEvent_getBuffer(event, &size);
android::util::StatsEventParcel p;
StatsEventParcel p;
// vector.assign() creates a copy, but this is inevitable unless
// stats_event.h/c uses a vector as opposed to a buffer.
p.buffer.assign(buffer, buffer + size);
@@ -973,7 +980,7 @@ binder::Status FakeSubsystemSleepCallback::onPullAtom(
AStatsEvent_write(event);
}
resultReceiver->pullFinished(atomTag, /*success=*/true, parcels);
return binder::Status::ok();
return Status::ok();
}
} // namespace statsd

View File

@@ -14,9 +14,9 @@
#pragma once
#include <android/os/BnPullAtomCallback.h>
#include <android/os/IPullAtomCallback.h>
#include <android/os/IPullAtomResultReceiver.h>
#include <aidl/android/os/BnPullAtomCallback.h>
#include <aidl/android/os/IPullAtomCallback.h>
#include <aidl/android/os/IPullAtomResultReceiver.h>
#include <gtest/gtest.h>
#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
@@ -31,8 +31,12 @@ namespace android {
namespace os {
namespace statsd {
using ::aidl::android::os::BnPullAtomCallback;
using ::aidl::android::os::IPullAtomCallback;
using ::aidl::android::os::IPullAtomResultReceiver;
using android::util::ProtoReader;
using google::protobuf::RepeatedPtrField;
using Status = ::ndk::ScopedAStatus;
const int SCREEN_STATE_ATOM_ID = android::util::SCREEN_STATE_CHANGED;
const int UID_PROCESS_STATE_ATOM_ID = android::util::UID_PROCESS_STATE_CHANGED;
@@ -230,7 +234,7 @@ AttributionNodeInternal CreateAttribution(const int& uid, const string& tag);
// Create a statsd log event processor upon the start time in seconds, config and key.
sp<StatsLogProcessor> CreateStatsLogProcessor(const int64_t timeBaseNs, const int64_t currentTimeNs,
const StatsdConfig& config, const ConfigKey& key,
const sp<IPullAtomCallback>& puller = nullptr,
const shared_ptr<IPullAtomCallback>& puller = nullptr,
const int32_t atomTag = 0 /*for puller only*/);
// Util function to sort the log events by timestamp.
@@ -285,8 +289,8 @@ bool backfillDimensionPath(const DimensionsValue& path,
class FakeSubsystemSleepCallback : public BnPullAtomCallback {
public:
binder::Status onPullAtom(int atomTag,
const sp<IPullAtomResultReceiver>& resultReceiver) override;
Status onPullAtom(int atomTag,
const shared_ptr<IPullAtomResultReceiver>& resultReceiver) override;
};
template <typename T>