blob: 8d0b1cfc1694b561bba5331db5a88fe2eeb42e05 [file] [log] [blame]
Ray Essick3938dc62016-11-01 08:56:56 -07001/*
Ray Essick2e9c63b2017-03-29 15:16:44 -07002 * Copyright (C) 2017 The Android Open Source Project
Ray Essick3938dc62016-11-01 08:56:56 -07003 *
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
Andy Hung17dbaf22019-10-11 14:06:31 -070017#pragma once
Ray Essick3938dc62016-11-01 08:56:56 -070018
Andy Hung17dbaf22019-10-11 14:06:31 -070019#include <atomic>
20#include <deque>
Ray Essick72a436b2018-06-14 15:08:13 -070021#include <future>
Andy Hung17dbaf22019-10-11 14:06:31 -070022#include <mutex>
23#include <unordered_map>
Ray Essick72a436b2018-06-14 15:08:13 -070024
Ray Essickf27e9872019-12-07 06:28:46 -080025// IMediaMetricsService must include Vector, String16, Errors
Andy Hungf7c14102020-04-18 14:54:08 -070026#include <android-base/thread_annotations.h>
Andy Hung49ca44e2020-11-10 22:14:58 -080027#include <android/media/BnMediaMetricsService.h>
Andy Hunga85efab2019-12-23 11:41:29 -080028#include <mediautils/ServiceUtilities.h>
Robert Shih2e15aed2021-03-16 18:30:35 -070029#include <stats_pull_atom_callback.h>
Andy Hung17dbaf22019-10-11 14:06:31 -070030#include <utils/String8.h>
Ray Essick3938dc62016-11-01 08:56:56 -070031
Andy Hung06f3aba2019-12-03 16:36:42 -080032#include "AudioAnalytics.h"
33
Ray Essick3938dc62016-11-01 08:56:56 -070034namespace android {
35
Andy Hung49ca44e2020-11-10 22:14:58 -080036class MediaMetricsService : public media::BnMediaMetricsService
Ray Essick3938dc62016-11-01 08:56:56 -070037{
Andy Hung17dbaf22019-10-11 14:06:31 -070038public:
Ray Essickf27e9872019-12-07 06:28:46 -080039 MediaMetricsService();
40 ~MediaMetricsService() override;
Ray Essick3938dc62016-11-01 08:56:56 -070041
Andy Hung49ca44e2020-11-10 22:14:58 -080042 // AIDL interface
43 binder::Status submitBuffer(const std::vector<uint8_t>& buffer) override {
44 status_t status = submitBuffer((char *)buffer.data(), buffer.size());
45 return binder::Status::fromStatusT(status);
46 }
47
Andy Hungc89c8dc2019-10-16 17:48:21 -070048 /**
Andy Hunga87e69c2019-10-18 10:07:40 -070049 * Submits the indicated record to the mediaanalytics service.
Andy Hungc89c8dc2019-10-16 17:48:21 -070050 *
51 * \param item the item to submit.
Andy Hunga87e69c2019-10-18 10:07:40 -070052 * \return status failure, which is negative on binder transaction failure.
53 * As the transaction is one-way, remote failures will not be reported.
Andy Hungc89c8dc2019-10-16 17:48:21 -070054 */
Andy Hung49ca44e2020-11-10 22:14:58 -080055 status_t submit(mediametrics::Item *item) {
Andy Hunga87e69c2019-10-18 10:07:40 -070056 return submitInternal(item, false /* release */);
57 }
Ray Essick3938dc62016-11-01 08:56:56 -070058
Andy Hung49ca44e2020-11-10 22:14:58 -080059 status_t submitBuffer(const char *buffer, size_t length) {
Ray Essickf27e9872019-12-07 06:28:46 -080060 mediametrics::Item *item = new mediametrics::Item();
Andy Hung1efc9c62019-12-03 13:43:33 -080061 return item->readFromByteString(buffer, length)
62 ?: submitInternal(item, true /* release */);
63 }
64
Andy Hung17dbaf22019-10-11 14:06:31 -070065 status_t dump(int fd, const Vector<String16>& args) override;
Ray Essick3938dc62016-11-01 08:56:56 -070066
Andy Hung17dbaf22019-10-11 14:06:31 -070067 static constexpr const char * const kServiceName = "media.metrics";
Ray Essick3938dc62016-11-01 08:56:56 -070068
Andy Hung55aaf522019-12-03 15:07:51 -080069 /**
70 * Rounds time to the nearest second.
71 */
72 static nsecs_t roundTime(nsecs_t timeNs);
73
Andy Hunga85efab2019-12-23 11:41:29 -080074 /**
Muhammad Qureshi087b37c2020-06-16 16:37:36 -070075 * Returns true if we should use uid for package name when uploading to statsd.
Andy Hunga85efab2019-12-23 11:41:29 -080076 */
77 static bool useUidForPackage(const std::string& package, const std::string& installer);
78
Andy Hungce9b6632020-04-28 20:15:17 -070079 /**
80 * Returns a std::pair of packageName and versionCode for a given uid.
81 *
82 * The value is sanitized - i.e. if the result is not approved to send,
83 * we use the uid as a string and a version code of 0.
84 */
85 static std::pair<std::string, int64_t> getSanitizedPackageNameAndVersionCode(uid_t uid);
86
Andy Hunga87e69c2019-10-18 10:07:40 -070087protected:
88
89 // Internal call where release is true if ownership of item is transferred
90 // to the service (that is, the service will eventually delete the item).
Andy Hung49ca44e2020-11-10 22:14:58 -080091 status_t submitInternal(mediametrics::Item *item, bool release);
Andy Hunga87e69c2019-10-18 10:07:40 -070092
Andy Hung17dbaf22019-10-11 14:06:31 -070093private:
94 void processExpirations();
Andy Hung17dbaf22019-10-11 14:06:31 -070095 // input validation after arrival from client
Ray Essickf27e9872019-12-07 06:28:46 -080096 static bool isContentValid(const mediametrics::Item *item, bool isTrusted);
97 bool isRateLimited(mediametrics::Item *) const;
98 void saveItem(const std::shared_ptr<const mediametrics::Item>& item);
Ray Essick3938dc62016-11-01 08:56:56 -070099
Andy Hungf7c14102020-04-18 14:54:08 -0700100 bool expirations(const std::shared_ptr<const mediametrics::Item>& item) REQUIRES(mLock);
Ray Essick3938dc62016-11-01 08:56:56 -0700101
Andy Hung17dbaf22019-10-11 14:06:31 -0700102 // support for generating output
Andy Hung54c73ce2021-03-30 14:25:54 -0700103 std::string dumpQueue(int64_t sinceNs, const char* prefix) REQUIRES(mLock);
104 std::string dumpHeaders(int64_t sinceNs, const char* prefix) REQUIRES(mLock);
Andy Hung17dbaf22019-10-11 14:06:31 -0700105
Robert Shih2e15aed2021-03-16 18:30:35 -0700106 // support statsd pushed atoms
107 static bool isPullable(const std::string &key);
108 static std::string atomTagToKey(int32_t atomTag);
109 static AStatsManager_PullAtomCallbackReturn pullAtomCallback(
110 int32_t atomTag, AStatsEventList* data, void* cookie);
111 AStatsManager_PullAtomCallbackReturn pullItems(int32_t atomTag, AStatsEventList* data);
112 void registerStatsdCallbacksIfNeeded();
113 std::atomic_flag mStatsdRegistered = ATOMIC_FLAG_INIT;
114
Andy Hung17dbaf22019-10-11 14:06:31 -0700115 // The following variables accessed without mLock
Ray Essick3938dc62016-11-01 08:56:56 -0700116
Ray Essickf65f4212017-08-31 11:41:19 -0700117 // limit how many records we'll retain
118 // by count (in each queue (open, finalized))
Andy Hung17dbaf22019-10-11 14:06:31 -0700119 const size_t mMaxRecords;
120 // by time (none older than this)
121 const nsecs_t mMaxRecordAgeNs;
Ray Essick72a436b2018-06-14 15:08:13 -0700122 // max to expire per expirations_l() invocation
Andy Hung17dbaf22019-10-11 14:06:31 -0700123 const size_t mMaxRecordsExpiredAtOnce;
Ray Essick3938dc62016-11-01 08:56:56 -0700124
Andy Hung17dbaf22019-10-11 14:06:31 -0700125 std::atomic<int64_t> mItemsSubmitted{}; // accessed outside of lock.
Ray Essickf65f4212017-08-31 11:41:19 -0700126
Andy Hung5be90c82021-03-30 14:30:20 -0700127 // mStatsdLog is locked internally (thread-safe) and shows the last atoms logged
128 static constexpr size_t STATSD_LOG_LINES_MAX = 30; // recent log lines to keep
129 static constexpr size_t STATSD_LOG_LINES_DUMP = 4; // normal amount of lines to dump
130 const std::shared_ptr<mediametrics::StatsdLog> mStatsdLog{
131 std::make_shared<mediametrics::StatsdLog>(STATSD_LOG_LINES_MAX)};
132
133 // mAudioAnalytics is locked internally.
134 mediametrics::AudioAnalytics mAudioAnalytics{mStatsdLog};
Andy Hung06f3aba2019-12-03 16:36:42 -0800135
Andy Hung17dbaf22019-10-11 14:06:31 -0700136 std::mutex mLock;
137 // statistics about our analytics
Andy Hungf7c14102020-04-18 14:54:08 -0700138 int64_t mItemsFinalized GUARDED_BY(mLock) = 0;
139 int64_t mItemsDiscarded GUARDED_BY(mLock) = 0;
140 int64_t mItemsDiscardedExpire GUARDED_BY(mLock) = 0;
141 int64_t mItemsDiscardedCount GUARDED_BY(mLock) = 0;
Ray Essickf65f4212017-08-31 11:41:19 -0700142
Andy Hung17dbaf22019-10-11 14:06:31 -0700143 // If we have a worker thread to garbage collect
Andy Hungf7c14102020-04-18 14:54:08 -0700144 std::future<void> mExpireFuture GUARDED_BY(mLock);
Andy Hung17dbaf22019-10-11 14:06:31 -0700145
146 // Our item queue, generally (oldest at front)
147 // TODO: Make separate class, use segmented queue, write lock only end.
148 // Note: Another analytics module might have ownership of an item longer than the log.
Andy Hungf7c14102020-04-18 14:54:08 -0700149 std::deque<std::shared_ptr<const mediametrics::Item>> mItems GUARDED_BY(mLock);
Robert Shih2e15aed2021-03-16 18:30:35 -0700150
151 // Queues per item key, pending to be pulled by statsd.
152 // Use weak_ptr such that a pullable item can still expire.
153 using ItemKey = std::string;
154 using WeakItemQueue = std::deque<std::weak_ptr<const mediametrics::Item>>;
155 std::unordered_map<ItemKey, WeakItemQueue> mPullableItems GUARDED_BY(mLock);
Ray Essick3938dc62016-11-01 08:56:56 -0700156};
157
Andy Hung17dbaf22019-10-11 14:06:31 -0700158} // namespace android