/* * Copyright 2023, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define STATSD_DEBUG true #include "Log.h" #include "RestrictedEventMetricProducer.h" #include "stats_annotations.h" #include "stats_log_util.h" #include "utils/DbUtils.h" using std::lock_guard; using std::vector; namespace android { namespace os { namespace statsd { #define NS_PER_DAY (24 * 3600 * NS_PER_SEC) RestrictedEventMetricProducer::RestrictedEventMetricProducer( const ConfigKey& key, const EventMetric& metric, const int conditionIndex, const vector& initialConditionCache, const sp& wizard, const uint64_t protoHash, const int64_t startTimeNs, const wp configMetadataProvider, const unordered_map>& eventActivationMap, const unordered_map>>& eventDeactivationMap, const vector& slicedStateAtoms, const unordered_map>& stateGroupMap) : EventMetricProducer(key, metric, conditionIndex, initialConditionCache, wizard, protoHash, startTimeNs, configMetadataProvider, eventActivationMap, eventDeactivationMap, slicedStateAtoms, stateGroupMap), mRestrictedDataCategory(CATEGORY_UNKNOWN) { } void RestrictedEventMetricProducer::onMatchedLogEventInternalLocked( const size_t matcherIndex, const MetricDimensionKey& eventKey, const ConditionKey& conditionKey, bool condition, const LogEvent& event, const std::map& statePrimaryKeys) { if (!condition) { return; } if (mRestrictedDataCategory != CATEGORY_UNKNOWN && mRestrictedDataCategory != event.getRestrictionCategory()) { StatsdStats::getInstance().noteRestrictedMetricCategoryChanged(mConfigKey, mMetricId); deleteMetricTable(); mLogEvents.clear(); mTotalDataSize = 0; } mRestrictedDataCategory = event.getRestrictionCategory(); mLogEvents.push_back(event); mTotalDataSize += getSize(event.getValues()) + sizeof(event); } void RestrictedEventMetricProducer::onDumpReportLocked( const int64_t dumpTimeNs, const bool include_current_partial_bucket, const bool erase_data, const DumpLatency dumpLatency, std::set* str_set, std::set& usedUids, android::util::ProtoOutputStream* protoOutput) { VLOG("Unexpected call to onDumpReportLocked() in RestrictedEventMetricProducer"); } void RestrictedEventMetricProducer::onMetricRemove() { std::lock_guard lock(mMutex); if (!mIsMetricTableCreated) { return; } deleteMetricTable(); } void RestrictedEventMetricProducer::enforceRestrictedDataTtl(sqlite3* db, const int64_t wallClockNs) { int32_t ttlInDays = RestrictedPolicyManager::getInstance().getRestrictedCategoryTtl( mRestrictedDataCategory); int64_t ttlTime = wallClockNs - ttlInDays * NS_PER_DAY; dbutils::flushTtl(db, mMetricId, ttlTime); } void RestrictedEventMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) { VLOG("Unexpected call to clearPastBucketsLocked in RestrictedEventMetricProducer"); } void RestrictedEventMetricProducer::dropDataLocked(const int64_t dropTimeNs) { mLogEvents.clear(); mTotalDataSize = 0; StatsdStats::getInstance().noteBucketDropped(mMetricId); } void RestrictedEventMetricProducer::flushRestrictedData() { std::lock_guard lock(mMutex); if (mLogEvents.empty()) { return; } int64_t flushStartNs = getElapsedRealtimeNs(); if (!mIsMetricTableCreated) { if (!dbutils::isEventCompatible(mConfigKey, mMetricId, mLogEvents[0])) { // Delete old data if schema changes // TODO(b/268150038): report error to statsdstats ALOGD("Detected schema change for metric %lld", (long long)mMetricId); deleteMetricTable(); } // TODO(b/271481944): add retry. if (!dbutils::createTableIfNeeded(mConfigKey, mMetricId, mLogEvents[0])) { ALOGE("Failed to create table for metric %lld", (long long)mMetricId); StatsdStats::getInstance().noteRestrictedMetricTableCreationError(mConfigKey, mMetricId); return; } mIsMetricTableCreated = true; } string err; if (!dbutils::insert(mConfigKey, mMetricId, mLogEvents, err)) { ALOGE("Failed to insert logEvent to table for metric %lld. err=%s", (long long)mMetricId, err.c_str()); StatsdStats::getInstance().noteRestrictedMetricInsertError(mConfigKey, mMetricId); } else { StatsdStats::getInstance().noteRestrictedMetricFlushLatency( mConfigKey, mMetricId, getElapsedRealtimeNs() - flushStartNs); } mLogEvents.clear(); mTotalDataSize = 0; } bool RestrictedEventMetricProducer::writeMetricMetadataToProto( metadata::MetricMetadata* metricMetadata) { metricMetadata->set_metric_id(mMetricId); metricMetadata->set_restricted_category(mRestrictedDataCategory); return true; } void RestrictedEventMetricProducer::loadMetricMetadataFromProto( const metadata::MetricMetadata& metricMetadata) { mRestrictedDataCategory = static_cast(metricMetadata.restricted_category()); } void RestrictedEventMetricProducer::deleteMetricTable() { if (!dbutils::deleteTable(mConfigKey, mMetricId)) { StatsdStats::getInstance().noteRestrictedMetricTableDeletionError(mConfigKey, mMetricId); VLOG("Failed to delete table for metric %lld", (long long)mMetricId); } mIsMetricTableCreated = false; } } // namespace statsd } // namespace os } // namespace android