blob: 988c06b851f5da0a76d99f655572460a4de7df42 [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
17// Proxy for media player implementations
18
19//#define LOG_NDEBUG 0
20#define LOG_TAG "MediaAnalyticsService"
21#include <utils/Log.h>
22
Ray Essick2e9c63b2017-03-29 15:16:44 -070023#include <stdint.h>
Ray Essick3938dc62016-11-01 08:56:56 -070024#include <inttypes.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <sys/time.h>
28#include <dirent.h>
Ray Essick72a436b2018-06-14 15:08:13 -070029#include <pthread.h>
Ray Essick3938dc62016-11-01 08:56:56 -070030#include <unistd.h>
31
32#include <string.h>
Ray Essickf65f4212017-08-31 11:41:19 -070033#include <pwd.h>
Ray Essick3938dc62016-11-01 08:56:56 -070034
35#include <cutils/atomic.h>
36#include <cutils/properties.h> // for property_get
37
38#include <utils/misc.h>
39
Ray Essickf65f4212017-08-31 11:41:19 -070040#include <android/content/pm/IPackageManagerNative.h>
41
Ray Essick3938dc62016-11-01 08:56:56 -070042#include <binder/IPCThreadState.h>
43#include <binder/IServiceManager.h>
44#include <binder/MemoryHeapBase.h>
45#include <binder/MemoryBase.h>
46#include <gui/Surface.h>
47#include <utils/Errors.h> // for status_t
48#include <utils/List.h>
49#include <utils/String8.h>
50#include <utils/SystemClock.h>
51#include <utils/Timers.h>
52#include <utils/Vector.h>
53
Ray Essick3938dc62016-11-01 08:56:56 -070054#include <media/IMediaHTTPService.h>
55#include <media/IRemoteDisplay.h>
56#include <media/IRemoteDisplayClient.h>
57#include <media/MediaPlayerInterface.h>
58#include <media/mediarecorder.h>
59#include <media/MediaMetadataRetrieverInterface.h>
60#include <media/Metadata.h>
61#include <media/AudioTrack.h>
62#include <media/MemoryLeakTrackUtil.h>
63#include <media/stagefright/MediaCodecList.h>
64#include <media/stagefright/MediaErrors.h>
65#include <media/stagefright/Utils.h>
66#include <media/stagefright/foundation/ADebug.h>
67#include <media/stagefright/foundation/ALooperRoster.h>
68#include <mediautils/BatteryNotifier.h>
69
70//#include <memunreachable/memunreachable.h>
71#include <system/audio.h>
72
73#include <private/android_filesystem_config.h>
74
75#include "MediaAnalyticsService.h"
76
Ray Essick3938dc62016-11-01 08:56:56 -070077namespace android {
78
Ray Essickf65f4212017-08-31 11:41:19 -070079// individual records kept in memory: age or count
Ray Essick72a436b2018-06-14 15:08:13 -070080// age: <= 28 hours (1 1/6 days)
Ray Essickf65f4212017-08-31 11:41:19 -070081// count: hard limit of # records
82// (0 for either of these disables that threshold)
Ray Essick72a436b2018-06-14 15:08:13 -070083//
84static constexpr nsecs_t kMaxRecordAgeNs = 28 * 3600 * (1000*1000*1000ll);
Ray Essick23f4d6c2019-06-20 10:16:37 -070085// 2019/6: average daily per device is currently 375-ish;
86// setting this to 2000 is large enough to catch most devices
87// we'll lose some data on very very media-active devices, but only for
88// the gms collection; statsd will have already covered those for us.
89// This also retains enough information to help with bugreports
90static constexpr int kMaxRecords = 2000;
Ray Essick72a436b2018-06-14 15:08:13 -070091
92// max we expire in a single call, to constrain how long we hold the
93// mutex, which also constrains how long a client might wait.
94static constexpr int kMaxExpiredAtOnce = 50;
95
96// TODO: need to look at tuning kMaxRecords and friends for low-memory devices
Ray Essick2e9c63b2017-03-29 15:16:44 -070097
98static const char *kServiceName = "media.metrics";
99
Ray Essick3938dc62016-11-01 08:56:56 -0700100void MediaAnalyticsService::instantiate() {
101 defaultServiceManager()->addService(
Ray Essick2e9c63b2017-03-29 15:16:44 -0700102 String16(kServiceName), new MediaAnalyticsService());
Ray Essick3938dc62016-11-01 08:56:56 -0700103}
104
Ray Essick3938dc62016-11-01 08:56:56 -0700105MediaAnalyticsService::MediaAnalyticsService()
Ray Essick2e9c63b2017-03-29 15:16:44 -0700106 : mMaxRecords(kMaxRecords),
Ray Essickf65f4212017-08-31 11:41:19 -0700107 mMaxRecordAgeNs(kMaxRecordAgeNs),
Ray Essick72a436b2018-06-14 15:08:13 -0700108 mMaxRecordsExpiredAtOnce(kMaxExpiredAtOnce),
Ray Essick583a23a2017-11-27 12:49:57 -0800109 mDumpProto(MediaAnalyticsItem::PROTO_V1),
110 mDumpProtoDefault(MediaAnalyticsItem::PROTO_V1) {
Ray Essick3938dc62016-11-01 08:56:56 -0700111
112 ALOGD("MediaAnalyticsService created");
Ray Essick3938dc62016-11-01 08:56:56 -0700113
114 mItemsSubmitted = 0;
115 mItemsFinalized = 0;
116 mItemsDiscarded = 0;
Ray Essickf65f4212017-08-31 11:41:19 -0700117 mItemsDiscardedExpire = 0;
118 mItemsDiscardedCount = 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700119
120 mLastSessionID = 0;
121 // recover any persistency we set up
122 // etc
123}
124
125MediaAnalyticsService::~MediaAnalyticsService() {
126 ALOGD("MediaAnalyticsService destroyed");
127
Ray Essick92d23b42018-01-29 12:10:30 -0800128 while (mItems.size() > 0) {
129 MediaAnalyticsItem * oitem = *(mItems.begin());
130 mItems.erase(mItems.begin());
Ray Essickf65f4212017-08-31 11:41:19 -0700131 delete oitem;
132 mItemsDiscarded++;
133 mItemsDiscardedCount++;
134 }
Ray Essick3938dc62016-11-01 08:56:56 -0700135}
136
137
138MediaAnalyticsItem::SessionID_t MediaAnalyticsService::generateUniqueSessionID() {
139 // generate a new sessionid
140
141 Mutex::Autolock _l(mLock_ids);
142 return (++mLastSessionID);
143}
144
Ray Essickb5fac8e2016-12-12 11:33:56 -0800145// caller surrenders ownership of 'item'
Ray Essick92d23b42018-01-29 12:10:30 -0800146MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem *item, bool forcenew)
147{
148 UNUSED(forcenew);
Ray Essick3938dc62016-11-01 08:56:56 -0700149
Ray Essick92d23b42018-01-29 12:10:30 -0800150 // fill in a sessionID if we do not yet have one
151 if (item->getSessionID() <= MediaAnalyticsItem::SessionIDNone) {
152 item->setSessionID(generateUniqueSessionID());
153 }
Ray Essick3938dc62016-11-01 08:56:56 -0700154
Ray Essickd38e1742017-01-23 15:17:06 -0800155 // we control these, generally not trusting user input
Ray Essick3938dc62016-11-01 08:56:56 -0700156 nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
Ray Essick721b7a02017-09-11 09:33:56 -0700157 // round nsecs to seconds
158 now = ((now + 500000000) / 1000000000) * 1000000000;
Ray Essick3938dc62016-11-01 08:56:56 -0700159 item->setTimestamp(now);
160 int pid = IPCThreadState::self()->getCallingPid();
Ray Essick3938dc62016-11-01 08:56:56 -0700161 int uid = IPCThreadState::self()->getCallingUid();
Ray Essickd38e1742017-01-23 15:17:06 -0800162
163 int uid_given = item->getUid();
164 int pid_given = item->getPid();
165
Ray Essick92d23b42018-01-29 12:10:30 -0800166 // although we do make exceptions for some trusted client uids
Ray Essickd38e1742017-01-23 15:17:06 -0800167 bool isTrusted = false;
168
Ray Essickf65f4212017-08-31 11:41:19 -0700169 ALOGV("caller has uid=%d, embedded uid=%d", uid, uid_given);
170
Ray Essickd38e1742017-01-23 15:17:06 -0800171 switch (uid) {
Robert Shiha57869a2019-08-21 22:41:25 -0700172 case AID_DRM:
Ray Essickd38e1742017-01-23 15:17:06 -0800173 case AID_MEDIA:
174 case AID_MEDIA_CODEC:
175 case AID_MEDIA_EX:
176 case AID_MEDIA_DRM:
177 // trusted source, only override default values
Ray Essickf65f4212017-08-31 11:41:19 -0700178 isTrusted = true;
Ray Essickd38e1742017-01-23 15:17:06 -0800179 if (uid_given == (-1)) {
180 item->setUid(uid);
181 }
182 if (pid_given == (-1)) {
183 item->setPid(pid);
184 }
185 break;
186 default:
187 isTrusted = false;
188 item->setPid(pid);
189 item->setUid(uid);
190 break;
191 }
192
Adam Stone21c72122017-09-05 19:02:06 -0700193 // Overwrite package name and version if the caller was untrusted.
194 if (!isTrusted) {
Ray Essickfa149562017-09-19 09:27:31 -0700195 setPkgInfo(item, item->getUid(), true, true);
Adam Stone21c72122017-09-05 19:02:06 -0700196 } else if (item->getPkgName().empty()) {
Ray Essickfa149562017-09-19 09:27:31 -0700197 // empty, so fill out both parts
198 setPkgInfo(item, item->getUid(), true, true);
199 } else {
200 // trusted, provided a package, do nothing
Adam Stone21c72122017-09-05 19:02:06 -0700201 }
202
203 ALOGV("given uid %d; sanitized uid: %d sanitized pkg: %s "
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800204 "sanitized pkg version: %" PRId64,
Adam Stone21c72122017-09-05 19:02:06 -0700205 uid_given, item->getUid(),
206 item->getPkgName().c_str(),
207 item->getPkgVersionCode());
Ray Essick3938dc62016-11-01 08:56:56 -0700208
209 mItemsSubmitted++;
210
211 // validate the record; we discard if we don't like it
Ray Essickd38e1742017-01-23 15:17:06 -0800212 if (contentValid(item, isTrusted) == false) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800213 delete item;
Ray Essick3938dc62016-11-01 08:56:56 -0700214 return MediaAnalyticsItem::SessionIDInvalid;
215 }
216
Ray Essick92d23b42018-01-29 12:10:30 -0800217 // XXX: if we have a sessionid in the new record, look to make
Ray Essick3938dc62016-11-01 08:56:56 -0700218 // sure it doesn't appear in the finalized list.
Ray Essick3938dc62016-11-01 08:56:56 -0700219
Ray Essick92d23b42018-01-29 12:10:30 -0800220 if (item->count() == 0) {
Ray Essick6ce27e52019-02-15 10:58:05 -0800221 ALOGV("dropping empty record...");
Ray Essick92d23b42018-01-29 12:10:30 -0800222 delete item;
223 item = NULL;
224 return MediaAnalyticsItem::SessionIDInvalid;
Ray Essick3938dc62016-11-01 08:56:56 -0700225 }
Ray Essick92d23b42018-01-29 12:10:30 -0800226
227 // save the new record
Ray Essick6ce27e52019-02-15 10:58:05 -0800228 //
229 // send a copy to statsd
230 dump2Statsd(item);
231
232 // and keep our copy for dumpsys
Ray Essick92d23b42018-01-29 12:10:30 -0800233 MediaAnalyticsItem::SessionID_t id = item->getSessionID();
234 saveItem(item);
235 mItemsFinalized++;
Ray Essick6ce27e52019-02-15 10:58:05 -0800236
Ray Essick3938dc62016-11-01 08:56:56 -0700237 return id;
238}
239
Ray Essickf65f4212017-08-31 11:41:19 -0700240
Ray Essickb5fac8e2016-12-12 11:33:56 -0800241status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
Ray Essick3938dc62016-11-01 08:56:56 -0700242{
Ray Essickb5fac8e2016-12-12 11:33:56 -0800243 const size_t SIZE = 512;
Ray Essick3938dc62016-11-01 08:56:56 -0700244 char buffer[SIZE];
245 String8 result;
246
247 if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
248 snprintf(buffer, SIZE, "Permission Denial: "
249 "can't dump MediaAnalyticsService from pid=%d, uid=%d\n",
250 IPCThreadState::self()->getCallingPid(),
251 IPCThreadState::self()->getCallingUid());
252 result.append(buffer);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800253 write(fd, result.string(), result.size());
254 return NO_ERROR;
Ray Essick3938dc62016-11-01 08:56:56 -0700255 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800256
257 // crack any parameters
Ray Essickf65f4212017-08-31 11:41:19 -0700258 String16 protoOption("-proto");
Ray Essick583a23a2017-11-27 12:49:57 -0800259 int chosenProto = mDumpProtoDefault;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800260 String16 clearOption("-clear");
Ray Essickf65f4212017-08-31 11:41:19 -0700261 bool clear = false;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800262 String16 sinceOption("-since");
Ray Essickf65f4212017-08-31 11:41:19 -0700263 nsecs_t ts_since = 0;
Ray Essick35ad27f2017-01-30 14:04:11 -0800264 String16 helpOption("-help");
Ray Essick2e9c63b2017-03-29 15:16:44 -0700265 String16 onlyOption("-only");
Ray Essick783bd0d2018-01-11 11:10:35 -0800266 std::string only;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800267 int n = args.size();
Ray Essickf65f4212017-08-31 11:41:19 -0700268
Ray Essickb5fac8e2016-12-12 11:33:56 -0800269 for (int i = 0; i < n; i++) {
270 String8 myarg(args[i]);
271 if (args[i] == clearOption) {
272 clear = true;
Ray Essickf65f4212017-08-31 11:41:19 -0700273 } else if (args[i] == protoOption) {
274 i++;
275 if (i < n) {
276 String8 value(args[i]);
Ray Essick583a23a2017-11-27 12:49:57 -0800277 int proto = MediaAnalyticsItem::PROTO_V0;
Ray Essickf65f4212017-08-31 11:41:19 -0700278 char *endp;
279 const char *p = value.string();
280 proto = strtol(p, &endp, 10);
281 if (endp != p || *endp == '\0') {
282 if (proto < MediaAnalyticsItem::PROTO_FIRST) {
283 proto = MediaAnalyticsItem::PROTO_FIRST;
284 } else if (proto > MediaAnalyticsItem::PROTO_LAST) {
285 proto = MediaAnalyticsItem::PROTO_LAST;
286 }
Ray Essick583a23a2017-11-27 12:49:57 -0800287 chosenProto = proto;
288 } else {
289 result.append("unable to parse value for -proto\n\n");
Ray Essickf65f4212017-08-31 11:41:19 -0700290 }
Ray Essick583a23a2017-11-27 12:49:57 -0800291 } else {
292 result.append("missing value for -proto\n\n");
Ray Essickf65f4212017-08-31 11:41:19 -0700293 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800294 } else if (args[i] == sinceOption) {
295 i++;
296 if (i < n) {
297 String8 value(args[i]);
298 char *endp;
299 const char *p = value.string();
300 ts_since = strtoll(p, &endp, 10);
301 if (endp == p || *endp != '\0') {
302 ts_since = 0;
303 }
304 } else {
305 ts_since = 0;
306 }
Ray Essick35ad27f2017-01-30 14:04:11 -0800307 // command line is milliseconds; internal units are nano-seconds
308 ts_since *= 1000*1000;
Ray Essick2e9c63b2017-03-29 15:16:44 -0700309 } else if (args[i] == onlyOption) {
310 i++;
311 if (i < n) {
312 String8 value(args[i]);
Ray Essickf65f4212017-08-31 11:41:19 -0700313 only = value.string();
Ray Essick2e9c63b2017-03-29 15:16:44 -0700314 }
Ray Essick35ad27f2017-01-30 14:04:11 -0800315 } else if (args[i] == helpOption) {
316 result.append("Recognized parameters:\n");
317 result.append("-help this help message\n");
Ray Essick583a23a2017-11-27 12:49:57 -0800318 result.append("-proto # dump using protocol #");
Ray Essick35ad27f2017-01-30 14:04:11 -0800319 result.append("-clear clears out saved records\n");
Ray Essick2e9c63b2017-03-29 15:16:44 -0700320 result.append("-only X process records for component X\n");
321 result.append("-since X include records since X\n");
322 result.append(" (X is milliseconds since the UNIX epoch)\n");
Ray Essick35ad27f2017-01-30 14:04:11 -0800323 write(fd, result.string(), result.size());
324 return NO_ERROR;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800325 }
326 }
327
328 Mutex::Autolock _l(mLock);
Ray Essick92d23b42018-01-29 12:10:30 -0800329 // mutex between insertion and dumping the contents
Ray Essickb5fac8e2016-12-12 11:33:56 -0800330
Ray Essick583a23a2017-11-27 12:49:57 -0800331 mDumpProto = chosenProto;
332
Ray Essick2e9c63b2017-03-29 15:16:44 -0700333 // we ALWAYS dump this piece
334 snprintf(buffer, SIZE, "Dump of the %s process:\n", kServiceName);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800335 result.append(buffer);
336
Ray Essick2e9c63b2017-03-29 15:16:44 -0700337 dumpHeaders(result, ts_since);
338
Ray Essick813b1b82018-01-16 15:10:06 -0800339 dumpRecent(result, ts_since, only.c_str());
Ray Essick2e9c63b2017-03-29 15:16:44 -0700340
341
342 if (clear) {
343 // remove everything from the finalized queue
Ray Essick92d23b42018-01-29 12:10:30 -0800344 while (mItems.size() > 0) {
345 MediaAnalyticsItem * oitem = *(mItems.begin());
346 mItems.erase(mItems.begin());
Ray Essick2e9c63b2017-03-29 15:16:44 -0700347 delete oitem;
348 mItemsDiscarded++;
349 }
350
351 // shall we clear the summary data too?
352
353 }
354
355 write(fd, result.string(), result.size());
356 return NO_ERROR;
357}
358
359// dump headers
Ray Essick92d23b42018-01-29 12:10:30 -0800360void MediaAnalyticsService::dumpHeaders(String8 &result, nsecs_t ts_since)
361{
Ray Essick2e9c63b2017-03-29 15:16:44 -0700362 const size_t SIZE = 512;
363 char buffer[SIZE];
364
Ray Essickf65f4212017-08-31 11:41:19 -0700365 snprintf(buffer, SIZE, "Protocol Version: %d\n", mDumpProto);
366 result.append(buffer);
367
Ray Essickb5fac8e2016-12-12 11:33:56 -0800368 int enabled = MediaAnalyticsItem::isEnabled();
369 if (enabled) {
Ray Essickd38e1742017-01-23 15:17:06 -0800370 snprintf(buffer, SIZE, "Metrics gathering: enabled\n");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800371 } else {
Ray Essickd38e1742017-01-23 15:17:06 -0800372 snprintf(buffer, SIZE, "Metrics gathering: DISABLED via property\n");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800373 }
374 result.append(buffer);
375
376 snprintf(buffer, SIZE,
Ray Essickf65f4212017-08-31 11:41:19 -0700377 "Since Boot: Submissions: %8" PRId64
Ray Essick92d23b42018-01-29 12:10:30 -0800378 " Accepted: %8" PRId64 "\n",
Ray Essickf65f4212017-08-31 11:41:19 -0700379 mItemsSubmitted, mItemsFinalized);
380 result.append(buffer);
381 snprintf(buffer, SIZE,
382 "Records Discarded: %8" PRId64
383 " (by Count: %" PRId64 " by Expiration: %" PRId64 ")\n",
384 mItemsDiscarded, mItemsDiscardedCount, mItemsDiscardedExpire);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800385 result.append(buffer);
386 if (ts_since != 0) {
387 snprintf(buffer, SIZE,
Ray Essick92d23b42018-01-29 12:10:30 -0800388 "Emitting Queue entries more recent than: %" PRId64 "\n",
Ray Essickb5fac8e2016-12-12 11:33:56 -0800389 (int64_t) ts_since);
390 result.append(buffer);
391 }
Ray Essick2e9c63b2017-03-29 15:16:44 -0700392}
393
Ray Essick2e9c63b2017-03-29 15:16:44 -0700394// the recent, detailed queues
Ray Essick92d23b42018-01-29 12:10:30 -0800395void MediaAnalyticsService::dumpRecent(String8 &result, nsecs_t ts_since, const char * only)
396{
Ray Essick2e9c63b2017-03-29 15:16:44 -0700397 const size_t SIZE = 512;
398 char buffer[SIZE];
Ray Essickb5fac8e2016-12-12 11:33:56 -0800399
Ray Essickf65f4212017-08-31 11:41:19 -0700400 if (only != NULL && *only == '\0') {
401 only = NULL;
402 }
403
Ray Essickb5fac8e2016-12-12 11:33:56 -0800404 // show the recently recorded records
Ray Essickd38e1742017-01-23 15:17:06 -0800405 snprintf(buffer, sizeof(buffer), "\nFinalized Metrics (oldest first):\n");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800406 result.append(buffer);
Ray Essick92d23b42018-01-29 12:10:30 -0800407 result.append(this->dumpQueue(ts_since, only));
Ray Essickb5fac8e2016-12-12 11:33:56 -0800408
409 // show who is connected and injecting records?
410 // talk about # records fed to the 'readers'
411 // talk about # records we discarded, perhaps "discarded w/o reading" too
Ray Essick3938dc62016-11-01 08:56:56 -0700412}
Ray Essick92d23b42018-01-29 12:10:30 -0800413
Ray Essick3938dc62016-11-01 08:56:56 -0700414// caller has locked mLock...
Ray Essick92d23b42018-01-29 12:10:30 -0800415String8 MediaAnalyticsService::dumpQueue() {
416 return dumpQueue((nsecs_t) 0, NULL);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800417}
418
Ray Essick92d23b42018-01-29 12:10:30 -0800419String8 MediaAnalyticsService::dumpQueue(nsecs_t ts_since, const char * only) {
Ray Essick3938dc62016-11-01 08:56:56 -0700420 String8 result;
421 int slot = 0;
422
Ray Essick92d23b42018-01-29 12:10:30 -0800423 if (mItems.empty()) {
Ray Essick3938dc62016-11-01 08:56:56 -0700424 result.append("empty\n");
425 } else {
Ray Essick92d23b42018-01-29 12:10:30 -0800426 List<MediaAnalyticsItem *>::iterator it = mItems.begin();
427 for (; it != mItems.end(); it++) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800428 nsecs_t when = (*it)->getTimestamp();
429 if (when < ts_since) {
430 continue;
431 }
Ray Essick2e9c63b2017-03-29 15:16:44 -0700432 if (only != NULL &&
433 strcmp(only, (*it)->getKey().c_str()) != 0) {
434 ALOGV("Omit '%s', it's not '%s'", (*it)->getKey().c_str(), only);
435 continue;
436 }
Ray Essick783bd0d2018-01-11 11:10:35 -0800437 std::string entry = (*it)->toString(mDumpProto);
Ray Essick35ad27f2017-01-30 14:04:11 -0800438 result.appendFormat("%5d: %s\n", slot, entry.c_str());
Ray Essickb5fac8e2016-12-12 11:33:56 -0800439 slot++;
Ray Essick3938dc62016-11-01 08:56:56 -0700440 }
441 }
442
443 return result;
444}
445
446//
447// Our Cheap in-core, non-persistent records management.
Ray Essick3938dc62016-11-01 08:56:56 -0700448
Ray Essick72a436b2018-06-14 15:08:13 -0700449
450// we hold mLock when we get here
451// if item != NULL, it's the item we just inserted
452// true == more items eligible to be recovered
453bool MediaAnalyticsService::expirations_l(MediaAnalyticsItem *item)
Ray Essick92d23b42018-01-29 12:10:30 -0800454{
Ray Essick72a436b2018-06-14 15:08:13 -0700455 bool more = false;
456 int handled = 0;
Ray Essicke5db6db2017-11-10 15:54:32 -0800457
Ray Essickf65f4212017-08-31 11:41:19 -0700458 // keep removing old records the front until we're in-bounds (count)
Ray Essick72a436b2018-06-14 15:08:13 -0700459 // since we invoke this with each insertion, it should be 0/1 iterations.
Ray Essick3938dc62016-11-01 08:56:56 -0700460 if (mMaxRecords > 0) {
Ray Essick92d23b42018-01-29 12:10:30 -0800461 while (mItems.size() > (size_t) mMaxRecords) {
462 MediaAnalyticsItem * oitem = *(mItems.begin());
Ray Essicke5db6db2017-11-10 15:54:32 -0800463 if (oitem == item) {
464 break;
465 }
Ray Essick72a436b2018-06-14 15:08:13 -0700466 if (handled >= mMaxRecordsExpiredAtOnce) {
467 // unlikely in this loop
468 more = true;
469 break;
470 }
471 handled++;
Ray Essick92d23b42018-01-29 12:10:30 -0800472 mItems.erase(mItems.begin());
Ray Essickb5fac8e2016-12-12 11:33:56 -0800473 delete oitem;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800474 mItemsDiscarded++;
Ray Essickf65f4212017-08-31 11:41:19 -0700475 mItemsDiscardedCount++;
476 }
477 }
478
Ray Essick72a436b2018-06-14 15:08:13 -0700479 // keep removing old records the front until we're in-bounds (age)
480 // limited to mMaxRecordsExpiredAtOnce items per invocation.
Ray Essickf65f4212017-08-31 11:41:19 -0700481 if (mMaxRecordAgeNs > 0) {
482 nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
Ray Essick92d23b42018-01-29 12:10:30 -0800483 while (mItems.size() > 0) {
484 MediaAnalyticsItem * oitem = *(mItems.begin());
Ray Essickf65f4212017-08-31 11:41:19 -0700485 nsecs_t when = oitem->getTimestamp();
Ray Essicke5db6db2017-11-10 15:54:32 -0800486 if (oitem == item) {
487 break;
488 }
Ray Essickf65f4212017-08-31 11:41:19 -0700489 // careful about timejumps too
490 if ((now > when) && (now-when) <= mMaxRecordAgeNs) {
491 // this (and the rest) are recent enough to keep
492 break;
493 }
Ray Essick72a436b2018-06-14 15:08:13 -0700494 if (handled >= mMaxRecordsExpiredAtOnce) {
495 // this represents "one too many"; tell caller there are
496 // more to be reclaimed.
497 more = true;
498 break;
499 }
500 handled++;
Ray Essick92d23b42018-01-29 12:10:30 -0800501 mItems.erase(mItems.begin());
Ray Essickf65f4212017-08-31 11:41:19 -0700502 delete oitem;
503 mItemsDiscarded++;
504 mItemsDiscardedExpire++;
Ray Essick3938dc62016-11-01 08:56:56 -0700505 }
506 }
Ray Essick72a436b2018-06-14 15:08:13 -0700507
508 // we only indicate whether there's more to clean;
509 // caller chooses whether to schedule further cleanup.
510 return more;
511}
512
513// process expirations in bite sized chunks, allowing new insertions through
514// runs in a pthread specifically started for this (which then exits)
515bool MediaAnalyticsService::processExpirations()
516{
517 bool more;
518 do {
519 sleep(1);
520 {
521 Mutex::Autolock _l(mLock);
522 more = expirations_l(NULL);
523 if (!more) {
524 break;
525 }
526 }
527 } while (more);
528 return true; // value is for std::future thread synchronization
529}
530
531// insert appropriately into queue
532void MediaAnalyticsService::saveItem(MediaAnalyticsItem * item)
533{
534
535 Mutex::Autolock _l(mLock);
536 // mutex between insertion and dumping the contents
537
538 // we want to dump 'in FIFO order', so insert at the end
539 mItems.push_back(item);
540
541 // clean old stuff from the queue
542 bool more = expirations_l(item);
543
544 // consider scheduling some asynchronous cleaning, if not running
545 if (more) {
546 if (!mExpireFuture.valid()
547 || mExpireFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
548
549 mExpireFuture = std::async(std::launch::async, [this]()
550 {return this->processExpirations();});
551 }
552 }
Ray Essick3938dc62016-11-01 08:56:56 -0700553}
554
Ray Essick783bd0d2018-01-11 11:10:35 -0800555static std::string allowedKeys[] =
Ray Essickd38e1742017-01-23 15:17:06 -0800556{
Ray Essick84e84a52018-05-03 18:45:07 -0700557 "audiopolicy",
Ray Essick8c22cb12018-01-24 11:00:36 -0800558 "audiorecord",
Eric Tanbc2a7732018-09-06 12:04:44 -0700559 "audiothread",
Ray Essick8c22cb12018-01-24 11:00:36 -0800560 "audiotrack",
Ray Essickd38e1742017-01-23 15:17:06 -0800561 "codec",
Ray Essick8c22cb12018-01-24 11:00:36 -0800562 "extractor",
563 "nuplayer",
Ray Essickd38e1742017-01-23 15:17:06 -0800564};
Ray Essick3938dc62016-11-01 08:56:56 -0700565
Ray Essickd38e1742017-01-23 15:17:06 -0800566static const int nAllowedKeys = sizeof(allowedKeys) / sizeof(allowedKeys[0]);
567
568// are the contents good
569bool MediaAnalyticsService::contentValid(MediaAnalyticsItem *item, bool isTrusted) {
570
571 // untrusted uids can only send us a limited set of keys
572 if (isTrusted == false) {
573 // restrict to a specific set of keys
Ray Essick783bd0d2018-01-11 11:10:35 -0800574 std::string key = item->getKey();
Ray Essickd38e1742017-01-23 15:17:06 -0800575
576 size_t i;
577 for(i = 0; i < nAllowedKeys; i++) {
578 if (key == allowedKeys[i]) {
579 break;
580 }
581 }
582 if (i == nAllowedKeys) {
583 ALOGD("Ignoring (key): %s", item->toString().c_str());
584 return false;
585 }
586 }
587
Ray Essick3938dc62016-11-01 08:56:56 -0700588 // internal consistency
589
590 return true;
591}
592
593// are we rate limited, normally false
Ray Essickb5fac8e2016-12-12 11:33:56 -0800594bool MediaAnalyticsService::rateLimited(MediaAnalyticsItem *) {
Ray Essick3938dc62016-11-01 08:56:56 -0700595
596 return false;
597}
598
Ray Essickfa149562017-09-19 09:27:31 -0700599// how long we hold package info before we re-fetch it
600#define PKG_EXPIRATION_NS (30*60*1000000000ll) // 30 minutes, in nsecs
Ray Essickf65f4212017-08-31 11:41:19 -0700601
602// give me the package name, perhaps going to find it
Ray Essick92d23b42018-01-29 12:10:30 -0800603// manages its own mutex operations internally
604void MediaAnalyticsService::setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion)
605{
Ray Essickfa149562017-09-19 09:27:31 -0700606 ALOGV("asking for packagename to go with uid=%d", uid);
607
608 if (!setName && !setVersion) {
609 // setting nothing? strange
610 return;
611 }
612
613 nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
614 struct UidToPkgMap mapping;
Ray Essick92d23b42018-01-29 12:10:30 -0800615 mapping.uid = (uid_t)(-1);
Ray Essickfa149562017-09-19 09:27:31 -0700616
Ray Essick92d23b42018-01-29 12:10:30 -0800617 {
618 Mutex::Autolock _l(mLock_mappings);
619 int i = mPkgMappings.indexOfKey(uid);
620 if (i >= 0) {
621 mapping = mPkgMappings.valueAt(i);
622 ALOGV("Expiration? uid %d expiration %" PRId64 " now %" PRId64,
623 uid, mapping.expiration, now);
624 if (mapping.expiration <= now) {
625 // purge the stale entry and fall into re-fetching
626 ALOGV("entry for uid %d expired, now= %" PRId64 "", uid, now);
627 mPkgMappings.removeItemsAt(i);
628 mapping.uid = (uid_t)(-1);
629 }
Ray Essickf65f4212017-08-31 11:41:19 -0700630 }
Ray Essick92d23b42018-01-29 12:10:30 -0800631 }
632
633 // if we did not find it
634 if (mapping.uid == (uid_t)(-1)) {
Ray Essick783bd0d2018-01-11 11:10:35 -0800635 std::string pkg;
Ray Essickfa149562017-09-19 09:27:31 -0700636 std::string installer = "";
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800637 int64_t versionCode = 0;
Ray Essickf65f4212017-08-31 11:41:19 -0700638
Ray Essickfa149562017-09-19 09:27:31 -0700639 struct passwd *pw = getpwuid(uid);
640 if (pw) {
641 pkg = pw->pw_name;
642 }
Ray Essickf65f4212017-08-31 11:41:19 -0700643
Ray Essick92d23b42018-01-29 12:10:30 -0800644 // find the proper value
Ray Essickf65f4212017-08-31 11:41:19 -0700645
Ray Essickfa149562017-09-19 09:27:31 -0700646 sp<IBinder> binder = NULL;
647 sp<IServiceManager> sm = defaultServiceManager();
648 if (sm == NULL) {
649 ALOGE("defaultServiceManager failed");
Ray Essickf65f4212017-08-31 11:41:19 -0700650 } else {
Ray Essickfa149562017-09-19 09:27:31 -0700651 binder = sm->getService(String16("package_native"));
652 if (binder == NULL) {
653 ALOGE("getService package_native failed");
654 }
655 }
656
657 if (binder != NULL) {
Ray Essick4f5d6fd2019-03-14 09:38:22 -0700658 sp<content::pm::IPackageManagerNative> package_mgr =
659 interface_cast<content::pm::IPackageManagerNative>(binder);
Ray Essickfa149562017-09-19 09:27:31 -0700660 binder::Status status;
661
662 std::vector<int> uids;
663 std::vector<std::string> names;
664
665 uids.push_back(uid);
666
667 status = package_mgr->getNamesForUids(uids, &names);
668 if (!status.isOk()) {
669 ALOGE("package_native::getNamesForUids failed: %s",
670 status.exceptionMessage().c_str());
671 } else {
672 if (!names[0].empty()) {
673 pkg = names[0].c_str();
674 }
675 }
676
677 // strip any leading "shared:" strings that came back
Ray Essick783bd0d2018-01-11 11:10:35 -0800678 if (pkg.compare(0, 7, "shared:") == 0) {
Ray Essickfa149562017-09-19 09:27:31 -0700679 pkg.erase(0, 7);
680 }
681
682 // determine how pkg was installed and the versionCode
683 //
684 if (pkg.empty()) {
685 // no name for us to manage
686 } else if (strchr(pkg.c_str(), '.') == NULL) {
687 // not of form 'com.whatever...'; assume internal and ok
688 } else if (strncmp(pkg.c_str(), "android.", 8) == 0) {
689 // android.* packages are assumed fine
690 } else {
691 String16 pkgName16(pkg.c_str());
692 status = package_mgr->getInstallerForPackage(pkgName16, &installer);
693 if (!status.isOk()) {
694 ALOGE("package_native::getInstallerForPackage failed: %s",
695 status.exceptionMessage().c_str());
696 }
697
698 // skip if we didn't get an installer
699 if (status.isOk()) {
700 status = package_mgr->getVersionCodeForPackage(pkgName16, &versionCode);
701 if (!status.isOk()) {
702 ALOGE("package_native::getVersionCodeForPackage failed: %s",
703 status.exceptionMessage().c_str());
704 }
705 }
706
707
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800708 ALOGV("package '%s' installed by '%s' versioncode %" PRId64 " / %" PRIx64,
Ray Essickfa149562017-09-19 09:27:31 -0700709 pkg.c_str(), installer.c_str(), versionCode, versionCode);
710
711 if (strncmp(installer.c_str(), "com.android.", 12) == 0) {
712 // from play store, we keep info
713 } else if (strncmp(installer.c_str(), "com.google.", 11) == 0) {
714 // some google source, we keep info
715 } else if (strcmp(installer.c_str(), "preload") == 0) {
716 // preloads, we keep the info
717 } else if (installer.c_str()[0] == '\0') {
718 // sideload (no installer); do not report
719 pkg = "";
720 versionCode = 0;
721 } else {
722 // unknown installer; do not report
723 pkg = "";
724 versionCode = 0;
725 }
726 }
727 }
728
729 // add it to the map, to save a subsequent lookup
730 if (!pkg.empty()) {
731 Mutex::Autolock _l(mLock_mappings);
732 ALOGV("Adding uid %d pkg '%s'", uid, pkg.c_str());
733 ssize_t i = mPkgMappings.indexOfKey(uid);
734 if (i < 0) {
735 mapping.uid = uid;
736 mapping.pkg = pkg;
737 mapping.installer = installer.c_str();
738 mapping.versionCode = versionCode;
739 mapping.expiration = now + PKG_EXPIRATION_NS;
740 ALOGV("expiration for uid %d set to %" PRId64 "", uid, mapping.expiration);
741
742 mPkgMappings.add(uid, mapping);
Ray Essickf65f4212017-08-31 11:41:19 -0700743 }
744 }
745 }
746
Ray Essickfa149562017-09-19 09:27:31 -0700747 if (mapping.uid != (uid_t)(-1)) {
748 if (setName) {
749 item->setPkgName(mapping.pkg);
750 }
751 if (setVersion) {
752 item->setPkgVersionCode(mapping.versionCode);
Ray Essickf65f4212017-08-31 11:41:19 -0700753 }
754 }
Ray Essickf65f4212017-08-31 11:41:19 -0700755}
756
Ray Essick3938dc62016-11-01 08:56:56 -0700757} // namespace android