StatsdStats.cpp revision 484524a246ffe453f8cd89b698a279c23b0bde1f
1/* 2 * Copyright 2017, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16#define DEBUG false // STOPSHIP if true 17#include "Log.h" 18 19#include "StatsdStats.h" 20 21#include <android/util/ProtoOutputStream.h> 22#include "../stats_log_util.h" 23#include "statslog.h" 24 25namespace android { 26namespace os { 27namespace statsd { 28 29using android::util::FIELD_COUNT_REPEATED; 30using android::util::FIELD_TYPE_BOOL; 31using android::util::FIELD_TYPE_FLOAT; 32using android::util::FIELD_TYPE_INT32; 33using android::util::FIELD_TYPE_INT64; 34using android::util::FIELD_TYPE_MESSAGE; 35using android::util::FIELD_TYPE_STRING; 36using android::util::ProtoOutputStream; 37using std::lock_guard; 38using std::map; 39using std::string; 40using std::vector; 41 42const int FIELD_ID_BEGIN_TIME = 1; 43const int FIELD_ID_END_TIME = 2; 44const int FIELD_ID_CONFIG_STATS = 3; 45const int FIELD_ID_ATOM_STATS = 7; 46const int FIELD_ID_UIDMAP_STATS = 8; 47const int FIELD_ID_ANOMALY_ALARM_STATS = 9; 48const int FIELD_ID_PULLED_ATOM_STATS = 10; 49const int FIELD_ID_LOGGER_ERROR_STATS = 11; 50 51const int FIELD_ID_MATCHER_STATS_NAME = 1; 52const int FIELD_ID_MATCHER_STATS_COUNT = 2; 53 54const int FIELD_ID_CONDITION_STATS_NAME = 1; 55const int FIELD_ID_CONDITION_STATS_COUNT = 2; 56 57const int FIELD_ID_METRIC_STATS_NAME = 1; 58const int FIELD_ID_METRIC_STATS_COUNT = 2; 59 60const int FIELD_ID_ATOM_STATS_TAG = 1; 61const int FIELD_ID_ATOM_STATS_COUNT = 2; 62 63const int FIELD_ID_ANOMALY_ALARMS_REGISTERED = 1; 64 65const int FIELD_ID_LOGGER_STATS_TIME = 1; 66const int FIELD_ID_LOGGER_STATS_ERROR_CODE = 2; 67 68std::map<int, long> StatsdStats::kPullerCooldownMap = { 69 {android::util::KERNEL_WAKELOCK, 1}, 70 {android::util::WIFI_BYTES_TRANSFER, 1}, 71 {android::util::MOBILE_BYTES_TRANSFER, 1}, 72 {android::util::WIFI_BYTES_TRANSFER_BY_FG_BG, 1}, 73 {android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG, 1}, 74 {android::util::SUBSYSTEM_SLEEP_STATE, 1}, 75 {android::util::CPU_TIME_PER_FREQ, 1}, 76 {android::util::CPU_TIME_PER_UID, 1}, 77 {android::util::CPU_TIME_PER_UID_FREQ, 1}, 78}; 79 80// TODO: add stats for pulled atoms. 81StatsdStats::StatsdStats() { 82 mPushedAtomStats.resize(android::util::kMaxPushedAtomId + 1); 83 mStartTimeSec = time(nullptr); 84} 85 86StatsdStats& StatsdStats::getInstance() { 87 static StatsdStats statsInstance; 88 return statsInstance; 89} 90 91void StatsdStats::addToIceBoxLocked(const StatsdStatsReport_ConfigStats& stats) { 92 // The size of mIceBox grows strictly by one at a time. It won't be > kMaxIceBoxSize. 93 if (mIceBox.size() == kMaxIceBoxSize) { 94 mIceBox.pop_front(); 95 } 96 mIceBox.push_back(stats); 97} 98 99void StatsdStats::noteConfigReceived(const ConfigKey& key, int metricsCount, int conditionsCount, 100 int matchersCount, int alertsCount, bool isValid) { 101 lock_guard<std::mutex> lock(mLock); 102 int32_t nowTimeSec = time(nullptr); 103 104 // If there is an existing config for the same key, icebox the old config. 105 noteConfigRemovedInternalLocked(key); 106 107 StatsdStatsReport_ConfigStats configStats; 108 configStats.set_uid(key.GetUid()); 109 configStats.set_id(key.GetId()); 110 configStats.set_creation_time_sec(nowTimeSec); 111 configStats.set_metric_count(metricsCount); 112 configStats.set_condition_count(conditionsCount); 113 configStats.set_matcher_count(matchersCount); 114 configStats.set_alert_count(alertsCount); 115 configStats.set_is_valid(isValid); 116 117 if (isValid) { 118 mConfigStats[key] = configStats; 119 } else { 120 configStats.set_deletion_time_sec(nowTimeSec); 121 addToIceBoxLocked(configStats); 122 } 123} 124 125void StatsdStats::noteConfigRemovedInternalLocked(const ConfigKey& key) { 126 auto it = mConfigStats.find(key); 127 if (it != mConfigStats.end()) { 128 int32_t nowTimeSec = time(nullptr); 129 it->second.set_deletion_time_sec(nowTimeSec); 130 // Add condition stats, metrics stats, matcher stats, alert stats 131 addSubStatsToConfigLocked(key, it->second); 132 // Remove them after they are added to the config stats. 133 mMatcherStats.erase(key); 134 mMetricsStats.erase(key); 135 mAlertStats.erase(key); 136 mConditionStats.erase(key); 137 addToIceBoxLocked(it->second); 138 mConfigStats.erase(it); 139 } 140} 141 142void StatsdStats::noteConfigRemoved(const ConfigKey& key) { 143 lock_guard<std::mutex> lock(mLock); 144 noteConfigRemovedInternalLocked(key); 145} 146 147void StatsdStats::noteBroadcastSent(const ConfigKey& key) { 148 noteBroadcastSent(key, time(nullptr)); 149} 150 151void StatsdStats::noteBroadcastSent(const ConfigKey& key, int32_t timeSec) { 152 lock_guard<std::mutex> lock(mLock); 153 auto it = mConfigStats.find(key); 154 if (it == mConfigStats.end()) { 155 ALOGE("Config key %s not found!", key.ToString().c_str()); 156 return; 157 } 158 if (it->second.broadcast_sent_time_sec_size() >= kMaxTimestampCount) { 159 auto timestampList = it->second.mutable_broadcast_sent_time_sec(); 160 // This is O(N) operation. It shouldn't happen often, and N is only 20. 161 timestampList->erase(timestampList->begin()); 162 } 163 it->second.add_broadcast_sent_time_sec(timeSec); 164} 165 166void StatsdStats::noteDataDropped(const ConfigKey& key) { 167 noteDataDropped(key, time(nullptr)); 168} 169 170void StatsdStats::noteDataDropped(const ConfigKey& key, int32_t timeSec) { 171 lock_guard<std::mutex> lock(mLock); 172 auto it = mConfigStats.find(key); 173 if (it == mConfigStats.end()) { 174 ALOGE("Config key %s not found!", key.ToString().c_str()); 175 return; 176 } 177 if (it->second.data_drop_time_sec_size() >= kMaxTimestampCount) { 178 auto timestampList = it->second.mutable_data_drop_time_sec(); 179 // This is O(N) operation. It shouldn't happen often, and N is only 20. 180 timestampList->erase(timestampList->begin()); 181 } 182 it->second.add_data_drop_time_sec(timeSec); 183} 184 185void StatsdStats::noteMetricsReportSent(const ConfigKey& key) { 186 noteMetricsReportSent(key, time(nullptr)); 187} 188 189void StatsdStats::noteMetricsReportSent(const ConfigKey& key, int32_t timeSec) { 190 lock_guard<std::mutex> lock(mLock); 191 auto it = mConfigStats.find(key); 192 if (it == mConfigStats.end()) { 193 ALOGE("Config key %s not found!", key.ToString().c_str()); 194 return; 195 } 196 if (it->second.dump_report_time_sec_size() >= kMaxTimestampCount) { 197 auto timestampList = it->second.mutable_dump_report_time_sec(); 198 // This is O(N) operation. It shouldn't happen often, and N is only 20. 199 timestampList->erase(timestampList->begin()); 200 } 201 it->second.add_dump_report_time_sec(timeSec); 202} 203 204void StatsdStats::noteUidMapDropped(int snapshots, int deltas) { 205 lock_guard<std::mutex> lock(mLock); 206 mUidMapStats.set_dropped_snapshots(mUidMapStats.dropped_snapshots() + snapshots); 207 mUidMapStats.set_dropped_changes(mUidMapStats.dropped_changes() + deltas); 208} 209 210void StatsdStats::setUidMapSnapshots(int snapshots) { 211 lock_guard<std::mutex> lock(mLock); 212 mUidMapStats.set_snapshots(snapshots); 213} 214 215void StatsdStats::setUidMapChanges(int changes) { 216 lock_guard<std::mutex> lock(mLock); 217 mUidMapStats.set_changes(changes); 218} 219 220void StatsdStats::setCurrentUidMapMemory(int bytes) { 221 lock_guard<std::mutex> lock(mLock); 222 mUidMapStats.set_bytes_used(bytes); 223} 224 225void StatsdStats::noteConditionDimensionSize(const ConfigKey& key, const int64_t& id, int size) { 226 lock_guard<std::mutex> lock(mLock); 227 // if name doesn't exist before, it will create the key with count 0. 228 auto& conditionSizeMap = mConditionStats[key]; 229 if (size > conditionSizeMap[id]) { 230 conditionSizeMap[id] = size; 231 } 232} 233 234void StatsdStats::noteMetricDimensionSize(const ConfigKey& key, const int64_t& id, int size) { 235 lock_guard<std::mutex> lock(mLock); 236 // if name doesn't exist before, it will create the key with count 0. 237 auto& metricsDimensionMap = mMetricsStats[key]; 238 if (size > metricsDimensionMap[id]) { 239 metricsDimensionMap[id] = size; 240 } 241} 242 243void StatsdStats::noteMatcherMatched(const ConfigKey& key, const int64_t& id) { 244 lock_guard<std::mutex> lock(mLock); 245 auto& matcherStats = mMatcherStats[key]; 246 matcherStats[id]++; 247} 248 249void StatsdStats::noteAnomalyDeclared(const ConfigKey& key, const int64_t& id) { 250 lock_guard<std::mutex> lock(mLock); 251 auto& alertStats = mAlertStats[key]; 252 alertStats[id]++; 253} 254 255void StatsdStats::noteRegisteredAnomalyAlarmChanged() { 256 lock_guard<std::mutex> lock(mLock); 257 mAnomalyAlarmRegisteredStats++; 258} 259 260void StatsdStats::updateMinPullIntervalSec(int pullAtomId, long intervalSec) { 261 lock_guard<std::mutex> lock(mLock); 262 mPulledAtomStats[pullAtomId].minPullIntervalSec = intervalSec; 263} 264 265void StatsdStats::notePull(int pullAtomId) { 266 lock_guard<std::mutex> lock(mLock); 267 mPulledAtomStats[pullAtomId].totalPull++; 268} 269 270void StatsdStats::notePullFromCache(int pullAtomId) { 271 lock_guard<std::mutex> lock(mLock); 272 mPulledAtomStats[pullAtomId].totalPullFromCache++; 273} 274 275void StatsdStats::noteAtomLogged(int atomId, int32_t timeSec) { 276 lock_guard<std::mutex> lock(mLock); 277 278 if (timeSec < mStartTimeSec) { 279 return; 280 } 281 282 if (atomId > android::util::kMaxPushedAtomId) { 283 ALOGW("not interested in atom %d", atomId); 284 return; 285 } 286 287 mPushedAtomStats[atomId]++; 288} 289 290void StatsdStats::noteLoggerError(int error) { 291 lock_guard<std::mutex> lock(mLock); 292 // grows strictly one at a time. so it won't > kMaxLoggerErrors 293 if (mLoggerErrors.size() == kMaxLoggerErrors) { 294 mLoggerErrors.pop_front(); 295 } 296 mLoggerErrors.push_back(std::make_pair(time(nullptr), error)); 297} 298 299void StatsdStats::reset() { 300 lock_guard<std::mutex> lock(mLock); 301 resetInternalLocked(); 302} 303 304void StatsdStats::resetInternalLocked() { 305 // Reset the historical data, but keep the active ConfigStats 306 mStartTimeSec = time(nullptr); 307 mIceBox.clear(); 308 mConditionStats.clear(); 309 mMetricsStats.clear(); 310 std::fill(mPushedAtomStats.begin(), mPushedAtomStats.end(), 0); 311 mAlertStats.clear(); 312 mAnomalyAlarmRegisteredStats = 0; 313 mMatcherStats.clear(); 314 mLoggerErrors.clear(); 315 for (auto& config : mConfigStats) { 316 config.second.clear_broadcast_sent_time_sec(); 317 config.second.clear_data_drop_time_sec(); 318 config.second.clear_dump_report_time_sec(); 319 config.second.clear_matcher_stats(); 320 config.second.clear_condition_stats(); 321 config.second.clear_metric_stats(); 322 config.second.clear_alert_stats(); 323 } 324} 325 326void StatsdStats::addSubStatsToConfigLocked(const ConfigKey& key, 327 StatsdStatsReport_ConfigStats& configStats) { 328 // Add matcher stats 329 if (mMatcherStats.find(key) != mMatcherStats.end()) { 330 const auto& matcherStats = mMatcherStats[key]; 331 for (const auto& stats : matcherStats) { 332 auto output = configStats.add_matcher_stats(); 333 output->set_id(stats.first); 334 output->set_matched_times(stats.second); 335 VLOG("matcher %lld matched %d times", 336 (long long)stats.first, stats.second); 337 } 338 } 339 // Add condition stats 340 if (mConditionStats.find(key) != mConditionStats.end()) { 341 const auto& conditionStats = mConditionStats[key]; 342 for (const auto& stats : conditionStats) { 343 auto output = configStats.add_condition_stats(); 344 output->set_id(stats.first); 345 output->set_max_tuple_counts(stats.second); 346 VLOG("condition %lld max output tuple size %d", 347 (long long)stats.first, stats.second); 348 } 349 } 350 // Add metrics stats 351 if (mMetricsStats.find(key) != mMetricsStats.end()) { 352 const auto& conditionStats = mMetricsStats[key]; 353 for (const auto& stats : conditionStats) { 354 auto output = configStats.add_metric_stats(); 355 output->set_id(stats.first); 356 output->set_max_tuple_counts(stats.second); 357 VLOG("metrics %lld max output tuple size %d", 358 (long long)stats.first, stats.second); 359 } 360 } 361 // Add anomaly detection alert stats 362 if (mAlertStats.find(key) != mAlertStats.end()) { 363 const auto& alertStats = mAlertStats[key]; 364 for (const auto& stats : alertStats) { 365 auto output = configStats.add_alert_stats(); 366 output->set_id(stats.first); 367 output->set_alerted_times(stats.second); 368 VLOG("alert %lld declared %d times", (long long)stats.first, stats.second); 369 } 370 } 371} 372 373void StatsdStats::dumpStats(FILE* out) const { 374 lock_guard<std::mutex> lock(mLock); 375 time_t t = mStartTimeSec; 376 struct tm* tm = localtime(&t); 377 char timeBuffer[80]; 378 strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%d %I:%M%p\n", tm); 379 fprintf(out, "Stats collection start second: %s\n", timeBuffer); 380 fprintf(out, "%lu Config in icebox: \n", (unsigned long)mIceBox.size()); 381 for (const auto& configStats : mIceBox) { 382 fprintf(out, 383 "Config {%d-%lld}: creation=%d, deletion=%d, #metric=%d, #condition=%d, " 384 "#matcher=%d, #alert=%d, valid=%d\n", 385 configStats.uid(), (long long)configStats.id(), configStats.creation_time_sec(), 386 configStats.deletion_time_sec(), configStats.metric_count(), 387 configStats.condition_count(), configStats.matcher_count(), 388 configStats.alert_count(), configStats.is_valid()); 389 390 for (const auto& broadcastTime : configStats.broadcast_sent_time_sec()) { 391 fprintf(out, "\tbroadcast time: %d\n", broadcastTime); 392 } 393 394 for (const auto& dataDropTime : configStats.data_drop_time_sec()) { 395 fprintf(out, "\tdata drop time: %d\n", dataDropTime); 396 } 397 } 398 fprintf(out, "%lu Active Configs\n", (unsigned long)mConfigStats.size()); 399 for (auto& pair : mConfigStats) { 400 auto& key = pair.first; 401 auto& configStats = pair.second; 402 403 fprintf(out, 404 "Config {%d-%lld}: creation=%d, deletion=%d, #metric=%d, #condition=%d, " 405 "#matcher=%d, #alert=%d, valid=%d\n", 406 configStats.uid(), (long long)configStats.id(), configStats.creation_time_sec(), 407 configStats.deletion_time_sec(), configStats.metric_count(), 408 configStats.condition_count(), configStats.matcher_count(), 409 configStats.alert_count(), configStats.is_valid()); 410 for (const auto& broadcastTime : configStats.broadcast_sent_time_sec()) { 411 fprintf(out, "\tbroadcast time: %d\n", broadcastTime); 412 } 413 414 for (const auto& dataDropTime : configStats.data_drop_time_sec()) { 415 fprintf(out, "\tdata drop time: %d\n", dataDropTime); 416 } 417 418 for (const auto& dumpTime : configStats.dump_report_time_sec()) { 419 fprintf(out, "\tdump report time: %d\n", dumpTime); 420 } 421 422 // Add matcher stats 423 auto matcherIt = mMatcherStats.find(key); 424 if (matcherIt != mMatcherStats.end()) { 425 const auto& matcherStats = matcherIt->second; 426 for (const auto& stats : matcherStats) { 427 fprintf(out, "matcher %lld matched %d times\n", (long long)stats.first, 428 stats.second); 429 } 430 } 431 // Add condition stats 432 auto conditionIt = mConditionStats.find(key); 433 if (conditionIt != mConditionStats.end()) { 434 const auto& conditionStats = conditionIt->second; 435 for (const auto& stats : conditionStats) { 436 fprintf(out, "condition %lld max output tuple size %d\n", (long long)stats.first, 437 stats.second); 438 } 439 } 440 // Add metrics stats 441 auto metricIt = mMetricsStats.find(key); 442 if (metricIt != mMetricsStats.end()) { 443 const auto& conditionStats = metricIt->second; 444 for (const auto& stats : conditionStats) { 445 fprintf(out, "metrics %lld max output tuple size %d\n", (long long)stats.first, 446 stats.second); 447 } 448 } 449 // Add anomaly detection alert stats 450 auto alertIt = mAlertStats.find(key); 451 if (alertIt != mAlertStats.end()) { 452 const auto& alertStats = alertIt->second; 453 for (const auto& stats : alertStats) { 454 fprintf(out, "alert %lld declared %d times\n", (long long)stats.first, 455 stats.second); 456 } 457 } 458 } 459 fprintf(out, "********Pushed Atom stats***********\n"); 460 const size_t atomCounts = mPushedAtomStats.size(); 461 for (size_t i = 2; i < atomCounts; i++) { 462 if (mPushedAtomStats[i] > 0) { 463 fprintf(out, "Atom %lu->%d\n", (unsigned long)i, mPushedAtomStats[i]); 464 } 465 } 466 467 fprintf(out, "********Pulled Atom stats***********\n"); 468 for (const auto& pair : mPulledAtomStats) { 469 fprintf(out, "Atom %d->%ld, %ld, %ld\n", (int)pair.first, (long)pair.second.totalPull, 470 (long)pair.second.totalPullFromCache, (long)pair.second.minPullIntervalSec); 471 } 472 473 if (mAnomalyAlarmRegisteredStats > 0) { 474 fprintf(out, "********AnomalyAlarmStats stats***********\n"); 475 fprintf(out, "Anomaly alarm registrations: %d\n", mAnomalyAlarmRegisteredStats); 476 } 477 478 fprintf(out, 479 "UID map stats: bytes=%d, snapshots=%d, changes=%d, snapshots lost=%d, changes " 480 "lost=%d\n", 481 mUidMapStats.bytes_used(), mUidMapStats.snapshots(), mUidMapStats.changes(), 482 mUidMapStats.dropped_snapshots(), mUidMapStats.dropped_changes()); 483 484 for (const auto& error : mLoggerErrors) { 485 time_t error_time = error.first; 486 struct tm* error_tm = localtime(&error_time); 487 char buffer[80]; 488 strftime(buffer, sizeof(buffer), "%Y-%m-%d %I:%M%p\n", error_tm); 489 fprintf(out, "Logger error %d at %s\n", error.second, buffer); 490 } 491} 492 493void StatsdStats::dumpStats(std::vector<uint8_t>* output, bool reset) { 494 lock_guard<std::mutex> lock(mLock); 495 496 ProtoOutputStream proto; 497 proto.write(FIELD_TYPE_INT32 | FIELD_ID_BEGIN_TIME, mStartTimeSec); 498 proto.write(FIELD_TYPE_INT32 | FIELD_ID_END_TIME, (int32_t)time(nullptr)); 499 500 for (const auto& configStats : mIceBox) { 501 const int numBytes = configStats.ByteSize(); 502 vector<char> buffer(numBytes); 503 configStats.SerializeToArray(&buffer[0], numBytes); 504 proto.write(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_CONFIG_STATS, &buffer[0], 505 buffer.size()); 506 } 507 508 for (auto& pair : mConfigStats) { 509 auto& configStats = pair.second; 510 addSubStatsToConfigLocked(pair.first, configStats); 511 512 const int numBytes = configStats.ByteSize(); 513 vector<char> buffer(numBytes); 514 configStats.SerializeToArray(&buffer[0], numBytes); 515 proto.write(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_CONFIG_STATS, &buffer[0], 516 buffer.size()); 517 // reset the sub stats, the source of truth is in the individual map 518 // they will be repopulated when dumpStats() is called again. 519 configStats.clear_matcher_stats(); 520 configStats.clear_condition_stats(); 521 configStats.clear_metric_stats(); 522 configStats.clear_alert_stats(); 523 } 524 525 const size_t atomCounts = mPushedAtomStats.size(); 526 for (size_t i = 2; i < atomCounts; i++) { 527 if (mPushedAtomStats[i] > 0) { 528 long long token = 529 proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_ATOM_STATS | FIELD_COUNT_REPEATED); 530 proto.write(FIELD_TYPE_INT32 | FIELD_ID_ATOM_STATS_TAG, (int32_t)i); 531 proto.write(FIELD_TYPE_INT32 | FIELD_ID_ATOM_STATS_COUNT, mPushedAtomStats[i]); 532 proto.end(token); 533 } 534 } 535 536 for (const auto& pair : mPulledAtomStats) { 537 android::os::statsd::writePullerStatsToStream(pair, &proto); 538 } 539 540 if (mAnomalyAlarmRegisteredStats > 0) { 541 long long token = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_ANOMALY_ALARM_STATS); 542 proto.write(FIELD_TYPE_INT32 | FIELD_ID_ANOMALY_ALARMS_REGISTERED, 543 mAnomalyAlarmRegisteredStats); 544 proto.end(token); 545 } 546 547 const int numBytes = mUidMapStats.ByteSize(); 548 vector<char> buffer(numBytes); 549 mUidMapStats.SerializeToArray(&buffer[0], numBytes); 550 proto.write(FIELD_TYPE_MESSAGE | FIELD_ID_UIDMAP_STATS, &buffer[0], buffer.size()); 551 552 for (const auto& error : mLoggerErrors) { 553 long long token = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_LOGGER_ERROR_STATS | 554 FIELD_COUNT_REPEATED); 555 proto.write(FIELD_TYPE_INT32 | FIELD_ID_LOGGER_STATS_TIME, error.first); 556 proto.write(FIELD_TYPE_INT32 | FIELD_ID_LOGGER_STATS_ERROR_CODE, error.second); 557 proto.end(token); 558 } 559 560 output->clear(); 561 size_t bufferSize = proto.size(); 562 output->resize(bufferSize); 563 564 size_t pos = 0; 565 auto it = proto.data(); 566 while (it.readBuffer() != NULL) { 567 size_t toRead = it.currentToRead(); 568 std::memcpy(&((*output)[pos]), it.readBuffer(), toRead); 569 pos += toRead; 570 it.rp()->move(toRead); 571 } 572 573 if (reset) { 574 resetInternalLocked(); 575 } 576 577 VLOG("reset=%d, returned proto size %lu", reset, (unsigned long)bufferSize); 578} 579 580} // namespace statsd 581} // namespace os 582} // namespace android