StatsdStats.cpp revision 330af58f2b8582b855085655fae553cdfaf44e6c
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 = getWallClockSec(); 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 = getWallClockSec(); 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 = getWallClockSec(); 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, getWallClockSec()); 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, getWallClockSec()); 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, getWallClockSec()); 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 (atomId > android::util::kMaxPushedAtomId) { 279 ALOGW("not interested in atom %d", atomId); 280 return; 281 } 282 283 mPushedAtomStats[atomId]++; 284} 285 286void StatsdStats::noteLoggerError(int error) { 287 lock_guard<std::mutex> lock(mLock); 288 // grows strictly one at a time. so it won't > kMaxLoggerErrors 289 if (mLoggerErrors.size() == kMaxLoggerErrors) { 290 mLoggerErrors.pop_front(); 291 } 292 mLoggerErrors.push_back(std::make_pair(getWallClockSec(), error)); 293} 294 295void StatsdStats::reset() { 296 lock_guard<std::mutex> lock(mLock); 297 resetInternalLocked(); 298} 299 300void StatsdStats::resetInternalLocked() { 301 // Reset the historical data, but keep the active ConfigStats 302 mStartTimeSec = getWallClockSec(); 303 mIceBox.clear(); 304 mConditionStats.clear(); 305 mMetricsStats.clear(); 306 std::fill(mPushedAtomStats.begin(), mPushedAtomStats.end(), 0); 307 mAlertStats.clear(); 308 mAnomalyAlarmRegisteredStats = 0; 309 mMatcherStats.clear(); 310 mLoggerErrors.clear(); 311 for (auto& config : mConfigStats) { 312 config.second.clear_broadcast_sent_time_sec(); 313 config.second.clear_data_drop_time_sec(); 314 config.second.clear_dump_report_time_sec(); 315 config.second.clear_matcher_stats(); 316 config.second.clear_condition_stats(); 317 config.second.clear_metric_stats(); 318 config.second.clear_alert_stats(); 319 } 320} 321 322void StatsdStats::addSubStatsToConfigLocked(const ConfigKey& key, 323 StatsdStatsReport_ConfigStats& configStats) { 324 // Add matcher stats 325 if (mMatcherStats.find(key) != mMatcherStats.end()) { 326 const auto& matcherStats = mMatcherStats[key]; 327 for (const auto& stats : matcherStats) { 328 auto output = configStats.add_matcher_stats(); 329 output->set_id(stats.first); 330 output->set_matched_times(stats.second); 331 VLOG("matcher %lld matched %d times", 332 (long long)stats.first, stats.second); 333 } 334 } 335 // Add condition stats 336 if (mConditionStats.find(key) != mConditionStats.end()) { 337 const auto& conditionStats = mConditionStats[key]; 338 for (const auto& stats : conditionStats) { 339 auto output = configStats.add_condition_stats(); 340 output->set_id(stats.first); 341 output->set_max_tuple_counts(stats.second); 342 VLOG("condition %lld max output tuple size %d", 343 (long long)stats.first, stats.second); 344 } 345 } 346 // Add metrics stats 347 if (mMetricsStats.find(key) != mMetricsStats.end()) { 348 const auto& conditionStats = mMetricsStats[key]; 349 for (const auto& stats : conditionStats) { 350 auto output = configStats.add_metric_stats(); 351 output->set_id(stats.first); 352 output->set_max_tuple_counts(stats.second); 353 VLOG("metrics %lld max output tuple size %d", 354 (long long)stats.first, stats.second); 355 } 356 } 357 // Add anomaly detection alert stats 358 if (mAlertStats.find(key) != mAlertStats.end()) { 359 const auto& alertStats = mAlertStats[key]; 360 for (const auto& stats : alertStats) { 361 auto output = configStats.add_alert_stats(); 362 output->set_id(stats.first); 363 output->set_alerted_times(stats.second); 364 VLOG("alert %lld declared %d times", (long long)stats.first, stats.second); 365 } 366 } 367} 368 369void StatsdStats::dumpStats(FILE* out) const { 370 lock_guard<std::mutex> lock(mLock); 371 time_t t = mStartTimeSec; 372 struct tm* tm = localtime(&t); 373 char timeBuffer[80]; 374 strftime(timeBuffer, sizeof(timeBuffer), "%Y-%m-%d %I:%M%p\n", tm); 375 fprintf(out, "Stats collection start second: %s\n", timeBuffer); 376 fprintf(out, "%lu Config in icebox: \n", (unsigned long)mIceBox.size()); 377 for (const auto& configStats : mIceBox) { 378 fprintf(out, 379 "Config {%d-%lld}: creation=%d, deletion=%d, #metric=%d, #condition=%d, " 380 "#matcher=%d, #alert=%d, valid=%d\n", 381 configStats.uid(), (long long)configStats.id(), configStats.creation_time_sec(), 382 configStats.deletion_time_sec(), configStats.metric_count(), 383 configStats.condition_count(), configStats.matcher_count(), 384 configStats.alert_count(), configStats.is_valid()); 385 386 for (const auto& broadcastTime : configStats.broadcast_sent_time_sec()) { 387 fprintf(out, "\tbroadcast time: %d\n", broadcastTime); 388 } 389 390 for (const auto& dataDropTime : configStats.data_drop_time_sec()) { 391 fprintf(out, "\tdata drop time: %d\n", dataDropTime); 392 } 393 } 394 fprintf(out, "%lu Active Configs\n", (unsigned long)mConfigStats.size()); 395 for (auto& pair : mConfigStats) { 396 auto& key = pair.first; 397 auto& configStats = pair.second; 398 399 fprintf(out, 400 "Config {%d-%lld}: creation=%d, deletion=%d, #metric=%d, #condition=%d, " 401 "#matcher=%d, #alert=%d, valid=%d\n", 402 configStats.uid(), (long long)configStats.id(), configStats.creation_time_sec(), 403 configStats.deletion_time_sec(), configStats.metric_count(), 404 configStats.condition_count(), configStats.matcher_count(), 405 configStats.alert_count(), configStats.is_valid()); 406 for (const auto& broadcastTime : configStats.broadcast_sent_time_sec()) { 407 fprintf(out, "\tbroadcast time: %d\n", broadcastTime); 408 } 409 410 for (const auto& dataDropTime : configStats.data_drop_time_sec()) { 411 fprintf(out, "\tdata drop time: %d\n", dataDropTime); 412 } 413 414 for (const auto& dumpTime : configStats.dump_report_time_sec()) { 415 fprintf(out, "\tdump report time: %d\n", dumpTime); 416 } 417 418 // Add matcher stats 419 auto matcherIt = mMatcherStats.find(key); 420 if (matcherIt != mMatcherStats.end()) { 421 const auto& matcherStats = matcherIt->second; 422 for (const auto& stats : matcherStats) { 423 fprintf(out, "matcher %lld matched %d times\n", (long long)stats.first, 424 stats.second); 425 } 426 } 427 // Add condition stats 428 auto conditionIt = mConditionStats.find(key); 429 if (conditionIt != mConditionStats.end()) { 430 const auto& conditionStats = conditionIt->second; 431 for (const auto& stats : conditionStats) { 432 fprintf(out, "condition %lld max output tuple size %d\n", (long long)stats.first, 433 stats.second); 434 } 435 } 436 // Add metrics stats 437 auto metricIt = mMetricsStats.find(key); 438 if (metricIt != mMetricsStats.end()) { 439 const auto& conditionStats = metricIt->second; 440 for (const auto& stats : conditionStats) { 441 fprintf(out, "metrics %lld max output tuple size %d\n", (long long)stats.first, 442 stats.second); 443 } 444 } 445 // Add anomaly detection alert stats 446 auto alertIt = mAlertStats.find(key); 447 if (alertIt != mAlertStats.end()) { 448 const auto& alertStats = alertIt->second; 449 for (const auto& stats : alertStats) { 450 fprintf(out, "alert %lld declared %d times\n", (long long)stats.first, 451 stats.second); 452 } 453 } 454 } 455 fprintf(out, "********Pushed Atom stats***********\n"); 456 const size_t atomCounts = mPushedAtomStats.size(); 457 for (size_t i = 2; i < atomCounts; i++) { 458 if (mPushedAtomStats[i] > 0) { 459 fprintf(out, "Atom %lu->%d\n", (unsigned long)i, mPushedAtomStats[i]); 460 } 461 } 462 463 fprintf(out, "********Pulled Atom stats***********\n"); 464 for (const auto& pair : mPulledAtomStats) { 465 fprintf(out, "Atom %d->%ld, %ld, %ld\n", (int)pair.first, (long)pair.second.totalPull, 466 (long)pair.second.totalPullFromCache, (long)pair.second.minPullIntervalSec); 467 } 468 469 if (mAnomalyAlarmRegisteredStats > 0) { 470 fprintf(out, "********AnomalyAlarmStats stats***********\n"); 471 fprintf(out, "Anomaly alarm registrations: %d\n", mAnomalyAlarmRegisteredStats); 472 } 473 474 fprintf(out, 475 "UID map stats: bytes=%d, snapshots=%d, changes=%d, snapshots lost=%d, changes " 476 "lost=%d\n", 477 mUidMapStats.bytes_used(), mUidMapStats.snapshots(), mUidMapStats.changes(), 478 mUidMapStats.dropped_snapshots(), mUidMapStats.dropped_changes()); 479 480 for (const auto& error : mLoggerErrors) { 481 time_t error_time = error.first; 482 struct tm* error_tm = localtime(&error_time); 483 char buffer[80]; 484 strftime(buffer, sizeof(buffer), "%Y-%m-%d %I:%M%p\n", error_tm); 485 fprintf(out, "Logger error %d at %s\n", error.second, buffer); 486 } 487} 488 489void StatsdStats::dumpStats(std::vector<uint8_t>* output, bool reset) { 490 lock_guard<std::mutex> lock(mLock); 491 492 ProtoOutputStream proto; 493 proto.write(FIELD_TYPE_INT32 | FIELD_ID_BEGIN_TIME, mStartTimeSec); 494 proto.write(FIELD_TYPE_INT32 | FIELD_ID_END_TIME, (int32_t)getWallClockSec()); 495 496 for (const auto& configStats : mIceBox) { 497 const int numBytes = configStats.ByteSize(); 498 vector<char> buffer(numBytes); 499 configStats.SerializeToArray(&buffer[0], numBytes); 500 proto.write(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_CONFIG_STATS, &buffer[0], 501 buffer.size()); 502 } 503 504 for (auto& pair : mConfigStats) { 505 auto& configStats = pair.second; 506 addSubStatsToConfigLocked(pair.first, configStats); 507 508 const int numBytes = configStats.ByteSize(); 509 vector<char> buffer(numBytes); 510 configStats.SerializeToArray(&buffer[0], numBytes); 511 proto.write(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_CONFIG_STATS, &buffer[0], 512 buffer.size()); 513 // reset the sub stats, the source of truth is in the individual map 514 // they will be repopulated when dumpStats() is called again. 515 configStats.clear_matcher_stats(); 516 configStats.clear_condition_stats(); 517 configStats.clear_metric_stats(); 518 configStats.clear_alert_stats(); 519 } 520 521 const size_t atomCounts = mPushedAtomStats.size(); 522 for (size_t i = 2; i < atomCounts; i++) { 523 if (mPushedAtomStats[i] > 0) { 524 long long token = 525 proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_ATOM_STATS | FIELD_COUNT_REPEATED); 526 proto.write(FIELD_TYPE_INT32 | FIELD_ID_ATOM_STATS_TAG, (int32_t)i); 527 proto.write(FIELD_TYPE_INT32 | FIELD_ID_ATOM_STATS_COUNT, mPushedAtomStats[i]); 528 proto.end(token); 529 } 530 } 531 532 for (const auto& pair : mPulledAtomStats) { 533 android::os::statsd::writePullerStatsToStream(pair, &proto); 534 } 535 536 if (mAnomalyAlarmRegisteredStats > 0) { 537 long long token = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_ANOMALY_ALARM_STATS); 538 proto.write(FIELD_TYPE_INT32 | FIELD_ID_ANOMALY_ALARMS_REGISTERED, 539 mAnomalyAlarmRegisteredStats); 540 proto.end(token); 541 } 542 543 const int numBytes = mUidMapStats.ByteSize(); 544 vector<char> buffer(numBytes); 545 mUidMapStats.SerializeToArray(&buffer[0], numBytes); 546 proto.write(FIELD_TYPE_MESSAGE | FIELD_ID_UIDMAP_STATS, &buffer[0], buffer.size()); 547 548 for (const auto& error : mLoggerErrors) { 549 long long token = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_LOGGER_ERROR_STATS | 550 FIELD_COUNT_REPEATED); 551 proto.write(FIELD_TYPE_INT32 | FIELD_ID_LOGGER_STATS_TIME, error.first); 552 proto.write(FIELD_TYPE_INT32 | FIELD_ID_LOGGER_STATS_ERROR_CODE, error.second); 553 proto.end(token); 554 } 555 556 output->clear(); 557 size_t bufferSize = proto.size(); 558 output->resize(bufferSize); 559 560 size_t pos = 0; 561 auto it = proto.data(); 562 while (it.readBuffer() != NULL) { 563 size_t toRead = it.currentToRead(); 564 std::memcpy(&((*output)[pos]), it.readBuffer(), toRead); 565 pos += toRead; 566 it.rp()->move(toRead); 567 } 568 569 if (reset) { 570 resetInternalLocked(); 571 } 572 573 VLOG("reset=%d, returned proto size %lu", reset, (unsigned long)bufferSize); 574} 575 576} // namespace statsd 577} // namespace os 578} // namespace android