blob: 2443301b2a059185a6a6159589f0c32616ee3307 [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>
29#include <unistd.h>
30
31#include <string.h>
Ray Essickf65f4212017-08-31 11:41:19 -070032#include <pwd.h>
Ray Essick3938dc62016-11-01 08:56:56 -070033
34#include <cutils/atomic.h>
35#include <cutils/properties.h> // for property_get
36
37#include <utils/misc.h>
38
Ray Essickf65f4212017-08-31 11:41:19 -070039#include <android/content/pm/IPackageManagerNative.h>
40
Ray Essick3938dc62016-11-01 08:56:56 -070041#include <binder/IPCThreadState.h>
42#include <binder/IServiceManager.h>
43#include <binder/MemoryHeapBase.h>
44#include <binder/MemoryBase.h>
45#include <gui/Surface.h>
46#include <utils/Errors.h> // for status_t
47#include <utils/List.h>
48#include <utils/String8.h>
49#include <utils/SystemClock.h>
50#include <utils/Timers.h>
51#include <utils/Vector.h>
52
53#include <media/AudioPolicyHelper.h>
54#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 Essick2e9c63b2017-03-29 15:16:44 -070077#include "MetricsSummarizer.h"
78#include "MetricsSummarizerCodec.h"
79#include "MetricsSummarizerExtractor.h"
80#include "MetricsSummarizerPlayer.h"
81#include "MetricsSummarizerRecorder.h"
82
Ray Essick3938dc62016-11-01 08:56:56 -070083
84namespace android {
85
Ray Essickf65f4212017-08-31 11:41:19 -070086 using namespace android::base;
87 using namespace android::content::pm;
88
Ray Essick3938dc62016-11-01 08:56:56 -070089
Ray Essick2e9c63b2017-03-29 15:16:44 -070090
91// summarized records
Ray Essickf65f4212017-08-31 11:41:19 -070092// up to 36 sets, each covering an hour -- so at least 1.5 days
Ray Essick2e9c63b2017-03-29 15:16:44 -070093// (will be longer if there are hours without any media action)
94static const nsecs_t kNewSetIntervalNs = 3600*(1000*1000*1000ll);
Ray Essickf65f4212017-08-31 11:41:19 -070095static const int kMaxRecordSets = 36;
Ray Essick2e9c63b2017-03-29 15:16:44 -070096
Ray Essickf65f4212017-08-31 11:41:19 -070097// individual records kept in memory: age or count
98// age: <= 36 hours (1.5 days)
99// count: hard limit of # records
100// (0 for either of these disables that threshold)
101static const nsecs_t kMaxRecordAgeNs = 36 * 3600 * (1000*1000*1000ll);
102static const int kMaxRecords = 0;
Ray Essick2e9c63b2017-03-29 15:16:44 -0700103
104static const char *kServiceName = "media.metrics";
105
Ray Essick3938dc62016-11-01 08:56:56 -0700106void MediaAnalyticsService::instantiate() {
107 defaultServiceManager()->addService(
Ray Essick2e9c63b2017-03-29 15:16:44 -0700108 String16(kServiceName), new MediaAnalyticsService());
Ray Essick3938dc62016-11-01 08:56:56 -0700109}
110
Ray Essick2e9c63b2017-03-29 15:16:44 -0700111// handle sets of summarizers
112MediaAnalyticsService::SummarizerSet::SummarizerSet() {
113 mSummarizers = new List<MetricsSummarizer *>();
114}
Ray Essickf65f4212017-08-31 11:41:19 -0700115
Ray Essick2e9c63b2017-03-29 15:16:44 -0700116MediaAnalyticsService::SummarizerSet::~SummarizerSet() {
117 // empty the list
118 List<MetricsSummarizer *> *l = mSummarizers;
119 while (l->size() > 0) {
120 MetricsSummarizer *summarizer = *(l->begin());
121 l->erase(l->begin());
122 delete summarizer;
123 }
124}
125
126void MediaAnalyticsService::newSummarizerSet() {
127 ALOGD("MediaAnalyticsService::newSummarizerSet");
128 MediaAnalyticsService::SummarizerSet *set = new MediaAnalyticsService::SummarizerSet();
129 nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
130 set->setStarted(now);
131
132 set->appendSummarizer(new MetricsSummarizerExtractor("extractor"));
133 set->appendSummarizer(new MetricsSummarizerCodec("codec"));
134 set->appendSummarizer(new MetricsSummarizerPlayer("nuplayer"));
135 set->appendSummarizer(new MetricsSummarizerRecorder("recorder"));
136
137 // ALWAYS at the end, since it catches everything
138 set->appendSummarizer(new MetricsSummarizer(NULL));
139
140 // inject this set at the BACK of the list.
141 mSummarizerSets->push_back(set);
142 mCurrentSet = set;
143
144 // limit the # that we have
145 if (mMaxRecordSets > 0) {
146 List<SummarizerSet *> *l = mSummarizerSets;
147 while (l->size() > (size_t) mMaxRecordSets) {
148 ALOGD("Deleting oldest record set....");
149 MediaAnalyticsService::SummarizerSet *oset = *(l->begin());
150 l->erase(l->begin());
151 delete oset;
152 mSetsDiscarded++;
153 }
154 }
155}
156
Ray Essick3938dc62016-11-01 08:56:56 -0700157MediaAnalyticsService::MediaAnalyticsService()
Ray Essick2e9c63b2017-03-29 15:16:44 -0700158 : mMaxRecords(kMaxRecords),
Ray Essickf65f4212017-08-31 11:41:19 -0700159 mMaxRecordAgeNs(kMaxRecordAgeNs),
Ray Essick2e9c63b2017-03-29 15:16:44 -0700160 mMaxRecordSets(kMaxRecordSets),
Ray Essickf65f4212017-08-31 11:41:19 -0700161 mNewSetInterval(kNewSetIntervalNs),
162 mDumpProto(MediaAnalyticsItem::PROTO_V0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700163
164 ALOGD("MediaAnalyticsService created");
165 // clear our queues
Ray Essickb5fac8e2016-12-12 11:33:56 -0800166 mOpen = new List<MediaAnalyticsItem *>();
167 mFinalized = new List<MediaAnalyticsItem *>();
Ray Essick3938dc62016-11-01 08:56:56 -0700168
Ray Essick2e9c63b2017-03-29 15:16:44 -0700169 mSummarizerSets = new List<MediaAnalyticsService::SummarizerSet *>();
170 newSummarizerSet();
171
Ray Essick3938dc62016-11-01 08:56:56 -0700172 mItemsSubmitted = 0;
173 mItemsFinalized = 0;
174 mItemsDiscarded = 0;
Ray Essickf65f4212017-08-31 11:41:19 -0700175 mItemsDiscardedExpire = 0;
176 mItemsDiscardedCount = 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700177
178 mLastSessionID = 0;
179 // recover any persistency we set up
180 // etc
181}
182
183MediaAnalyticsService::~MediaAnalyticsService() {
184 ALOGD("MediaAnalyticsService destroyed");
185
Ray Essick2e9c63b2017-03-29 15:16:44 -0700186 // clean out mOpen and mFinalized
Ray Essickf65f4212017-08-31 11:41:19 -0700187 while (mOpen->size() > 0) {
188 MediaAnalyticsItem * oitem = *(mOpen->begin());
189 mOpen->erase(mOpen->begin());
190 delete oitem;
191 mItemsDiscarded++;
192 mItemsDiscardedCount++;
193 }
Ray Essick2e9c63b2017-03-29 15:16:44 -0700194 delete mOpen;
195 mOpen = NULL;
Ray Essickf65f4212017-08-31 11:41:19 -0700196
197 while (mFinalized->size() > 0) {
198 MediaAnalyticsItem * oitem = *(mFinalized->begin());
199 mFinalized->erase(mFinalized->begin());
200 delete oitem;
201 mItemsDiscarded++;
202 mItemsDiscardedCount++;
203 }
Ray Essick2e9c63b2017-03-29 15:16:44 -0700204 delete mFinalized;
205 mFinalized = NULL;
206
207 // XXX: clean out the summaries
Ray Essick3938dc62016-11-01 08:56:56 -0700208}
209
210
211MediaAnalyticsItem::SessionID_t MediaAnalyticsService::generateUniqueSessionID() {
212 // generate a new sessionid
213
214 Mutex::Autolock _l(mLock_ids);
215 return (++mLastSessionID);
216}
217
Ray Essickb5fac8e2016-12-12 11:33:56 -0800218// caller surrenders ownership of 'item'
219MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem *item, bool forcenew) {
Ray Essick3938dc62016-11-01 08:56:56 -0700220
221 MediaAnalyticsItem::SessionID_t id = MediaAnalyticsItem::SessionIDInvalid;
222
Ray Essickd38e1742017-01-23 15:17:06 -0800223 // we control these, generally not trusting user input
Ray Essick3938dc62016-11-01 08:56:56 -0700224 nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
225 item->setTimestamp(now);
226 int pid = IPCThreadState::self()->getCallingPid();
Ray Essick3938dc62016-11-01 08:56:56 -0700227 int uid = IPCThreadState::self()->getCallingUid();
Ray Essickd38e1742017-01-23 15:17:06 -0800228
229 int uid_given = item->getUid();
230 int pid_given = item->getPid();
231
232 // although we do make exceptions for particular client uids
233 // that we know we trust.
234 //
235 bool isTrusted = false;
236
Ray Essickf65f4212017-08-31 11:41:19 -0700237 ALOGV("caller has uid=%d, embedded uid=%d", uid, uid_given);
238
Ray Essickd38e1742017-01-23 15:17:06 -0800239 switch (uid) {
240 case AID_MEDIA:
241 case AID_MEDIA_CODEC:
242 case AID_MEDIA_EX:
243 case AID_MEDIA_DRM:
244 // trusted source, only override default values
Ray Essickf65f4212017-08-31 11:41:19 -0700245 isTrusted = true;
Ray Essickd38e1742017-01-23 15:17:06 -0800246 if (uid_given == (-1)) {
247 item->setUid(uid);
248 }
249 if (pid_given == (-1)) {
250 item->setPid(pid);
251 }
252 break;
253 default:
254 isTrusted = false;
255 item->setPid(pid);
256 item->setUid(uid);
257 break;
258 }
259
Adam Stone21c72122017-09-05 19:02:06 -0700260 // Overwrite package name and version if the caller was untrusted.
261 if (!isTrusted) {
262 item->setPkgName(getPkgName(item->getUid(), true));
263 item->setPkgVersionCode(0);
264 } else if (item->getPkgName().empty()) {
265 // Only overwrite the package name if it was empty. Trust whatever
266 // version code was provided by the trusted caller.
267 item->setPkgName(getPkgName(uid, true));
268 }
269
270 ALOGV("given uid %d; sanitized uid: %d sanitized pkg: %s "
271 "sanitized pkg version: %d",
272 uid_given, item->getUid(),
273 item->getPkgName().c_str(),
274 item->getPkgVersionCode());
Ray Essick3938dc62016-11-01 08:56:56 -0700275
276 mItemsSubmitted++;
277
278 // validate the record; we discard if we don't like it
Ray Essickd38e1742017-01-23 15:17:06 -0800279 if (contentValid(item, isTrusted) == false) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800280 delete item;
Ray Essick3938dc62016-11-01 08:56:56 -0700281 return MediaAnalyticsItem::SessionIDInvalid;
282 }
283
284
285 // if we have a sesisonid in the new record, look to make
286 // sure it doesn't appear in the finalized list.
287 // XXX: this is for security / DOS prevention.
288 // may also require that we persist the unique sessionIDs
289 // across boots [instead of within a single boot]
290
291
292 // match this new record up against records in the open
293 // list...
294 // if there's a match, merge them together
295 // deal with moving the old / merged record into the finalized que
296
297 bool finalizing = item->getFinalized();
298
299 // if finalizing, we'll remove it
Ray Essickb5fac8e2016-12-12 11:33:56 -0800300 MediaAnalyticsItem *oitem = findItem(mOpen, item, finalizing | forcenew);
Ray Essick3938dc62016-11-01 08:56:56 -0700301 if (oitem != NULL) {
302 if (forcenew) {
303 // old one gets finalized, then we insert the new one
304 // so we'll have 2 records at the end of this.
305 // but don't finalize an empty record
Ray Essickb5fac8e2016-12-12 11:33:56 -0800306 if (oitem->count() == 0) {
307 // we're responsible for disposing of the dead record
308 delete oitem;
309 oitem = NULL;
310 } else {
Ray Essick3938dc62016-11-01 08:56:56 -0700311 oitem->setFinalized(true);
Ray Essick2e9c63b2017-03-29 15:16:44 -0700312 summarize(oitem);
Ray Essick3938dc62016-11-01 08:56:56 -0700313 saveItem(mFinalized, oitem, 0);
314 }
315 // new record could itself be marked finalized...
316 if (finalizing) {
Ray Essick2e9c63b2017-03-29 15:16:44 -0700317 summarize(item);
Ray Essick3938dc62016-11-01 08:56:56 -0700318 saveItem(mFinalized, item, 0);
319 mItemsFinalized++;
320 } else {
321 saveItem(mOpen, item, 1);
322 }
323 id = item->getSessionID();
324 } else {
325 // combine the records, send it to finalized if appropriate
326 oitem->merge(item);
327 if (finalizing) {
Ray Essick2e9c63b2017-03-29 15:16:44 -0700328 summarize(oitem);
Ray Essick3938dc62016-11-01 08:56:56 -0700329 saveItem(mFinalized, oitem, 0);
330 mItemsFinalized++;
331 }
332 id = oitem->getSessionID();
Ray Essickb5fac8e2016-12-12 11:33:56 -0800333
334 // we're responsible for disposing of the dead record
335 delete item;
336 item = NULL;
Ray Essick3938dc62016-11-01 08:56:56 -0700337 }
338 } else {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800339 // nothing to merge, save the new record
340 id = item->getSessionID();
341 if (finalizing) {
342 if (item->count() == 0) {
343 // drop empty records
344 delete item;
345 item = NULL;
Ray Essick3938dc62016-11-01 08:56:56 -0700346 } else {
Ray Essick2e9c63b2017-03-29 15:16:44 -0700347 summarize(item);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800348 saveItem(mFinalized, item, 0);
349 mItemsFinalized++;
Ray Essick3938dc62016-11-01 08:56:56 -0700350 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800351 } else {
352 saveItem(mOpen, item, 1);
353 }
Ray Essick3938dc62016-11-01 08:56:56 -0700354 }
Ray Essick3938dc62016-11-01 08:56:56 -0700355 return id;
356}
357
Ray Essickf65f4212017-08-31 11:41:19 -0700358
Ray Essickb5fac8e2016-12-12 11:33:56 -0800359status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
Ray Essick3938dc62016-11-01 08:56:56 -0700360{
Ray Essickb5fac8e2016-12-12 11:33:56 -0800361 const size_t SIZE = 512;
Ray Essick3938dc62016-11-01 08:56:56 -0700362 char buffer[SIZE];
363 String8 result;
364
365 if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
366 snprintf(buffer, SIZE, "Permission Denial: "
367 "can't dump MediaAnalyticsService from pid=%d, uid=%d\n",
368 IPCThreadState::self()->getCallingPid(),
369 IPCThreadState::self()->getCallingUid());
370 result.append(buffer);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800371 write(fd, result.string(), result.size());
372 return NO_ERROR;
Ray Essick3938dc62016-11-01 08:56:56 -0700373 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800374
375 // crack any parameters
Ray Essick2e9c63b2017-03-29 15:16:44 -0700376 String16 summaryOption("-summary");
Ray Essickf65f4212017-08-31 11:41:19 -0700377 bool summary = false;
378 String16 protoOption("-proto");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800379 String16 clearOption("-clear");
Ray Essickf65f4212017-08-31 11:41:19 -0700380 bool clear = false;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800381 String16 sinceOption("-since");
Ray Essickf65f4212017-08-31 11:41:19 -0700382 nsecs_t ts_since = 0;
Ray Essick35ad27f2017-01-30 14:04:11 -0800383 String16 helpOption("-help");
Ray Essick2e9c63b2017-03-29 15:16:44 -0700384 String16 onlyOption("-only");
Ray Essickf65f4212017-08-31 11:41:19 -0700385 AString only;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800386 int n = args.size();
Ray Essickf65f4212017-08-31 11:41:19 -0700387
Ray Essickb5fac8e2016-12-12 11:33:56 -0800388 for (int i = 0; i < n; i++) {
389 String8 myarg(args[i]);
390 if (args[i] == clearOption) {
391 clear = true;
Ray Essick2e9c63b2017-03-29 15:16:44 -0700392 } else if (args[i] == summaryOption) {
393 summary = true;
Ray Essickf65f4212017-08-31 11:41:19 -0700394 } else if (args[i] == protoOption) {
395 i++;
396 if (i < n) {
397 String8 value(args[i]);
398 int proto = MediaAnalyticsItem::PROTO_V0; // default to original
399 char *endp;
400 const char *p = value.string();
401 proto = strtol(p, &endp, 10);
402 if (endp != p || *endp == '\0') {
403 if (proto < MediaAnalyticsItem::PROTO_FIRST) {
404 proto = MediaAnalyticsItem::PROTO_FIRST;
405 } else if (proto > MediaAnalyticsItem::PROTO_LAST) {
406 proto = MediaAnalyticsItem::PROTO_LAST;
407 }
408 mDumpProto = proto;
409 }
410 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800411 } else if (args[i] == sinceOption) {
412 i++;
413 if (i < n) {
414 String8 value(args[i]);
415 char *endp;
416 const char *p = value.string();
417 ts_since = strtoll(p, &endp, 10);
418 if (endp == p || *endp != '\0') {
419 ts_since = 0;
420 }
421 } else {
422 ts_since = 0;
423 }
Ray Essick35ad27f2017-01-30 14:04:11 -0800424 // command line is milliseconds; internal units are nano-seconds
425 ts_since *= 1000*1000;
Ray Essick2e9c63b2017-03-29 15:16:44 -0700426 } else if (args[i] == onlyOption) {
427 i++;
428 if (i < n) {
429 String8 value(args[i]);
Ray Essickf65f4212017-08-31 11:41:19 -0700430 only = value.string();
Ray Essick2e9c63b2017-03-29 15:16:44 -0700431 }
Ray Essick35ad27f2017-01-30 14:04:11 -0800432 } else if (args[i] == helpOption) {
433 result.append("Recognized parameters:\n");
434 result.append("-help this help message\n");
Ray Essickf65f4212017-08-31 11:41:19 -0700435 result.append("-proto X dump using protocol X (defaults to 1)");
Ray Essick2e9c63b2017-03-29 15:16:44 -0700436 result.append("-summary show summary info\n");
Ray Essick35ad27f2017-01-30 14:04:11 -0800437 result.append("-clear clears out saved records\n");
Ray Essick2e9c63b2017-03-29 15:16:44 -0700438 result.append("-only X process records for component X\n");
439 result.append("-since X include records since X\n");
440 result.append(" (X is milliseconds since the UNIX epoch)\n");
Ray Essick35ad27f2017-01-30 14:04:11 -0800441 write(fd, result.string(), result.size());
442 return NO_ERROR;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800443 }
444 }
445
446 Mutex::Autolock _l(mLock);
447
Ray Essick2e9c63b2017-03-29 15:16:44 -0700448 // we ALWAYS dump this piece
449 snprintf(buffer, SIZE, "Dump of the %s process:\n", kServiceName);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800450 result.append(buffer);
451
Ray Essick2e9c63b2017-03-29 15:16:44 -0700452 dumpHeaders(result, ts_since);
453
Ray Essickf65f4212017-08-31 11:41:19 -0700454 // want exactly 1, to avoid confusing folks that parse the output
Ray Essick2e9c63b2017-03-29 15:16:44 -0700455 if (summary) {
Ray Essickf65f4212017-08-31 11:41:19 -0700456 dumpSummaries(result, ts_since, only.c_str());
Ray Essick2e9c63b2017-03-29 15:16:44 -0700457 } else {
Ray Essickf65f4212017-08-31 11:41:19 -0700458 dumpRecent(result, ts_since, only.c_str());
Ray Essick2e9c63b2017-03-29 15:16:44 -0700459 }
460
461
462 if (clear) {
463 // remove everything from the finalized queue
464 while (mFinalized->size() > 0) {
465 MediaAnalyticsItem * oitem = *(mFinalized->begin());
466 mFinalized->erase(mFinalized->begin());
467 delete oitem;
468 mItemsDiscarded++;
469 }
470
471 // shall we clear the summary data too?
472
473 }
474
475 write(fd, result.string(), result.size());
476 return NO_ERROR;
477}
478
479// dump headers
480void MediaAnalyticsService::dumpHeaders(String8 &result, nsecs_t ts_since) {
481 const size_t SIZE = 512;
482 char buffer[SIZE];
483
Ray Essickf65f4212017-08-31 11:41:19 -0700484 snprintf(buffer, SIZE, "Protocol Version: %d\n", mDumpProto);
485 result.append(buffer);
486
Ray Essickb5fac8e2016-12-12 11:33:56 -0800487 int enabled = MediaAnalyticsItem::isEnabled();
488 if (enabled) {
Ray Essickd38e1742017-01-23 15:17:06 -0800489 snprintf(buffer, SIZE, "Metrics gathering: enabled\n");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800490 } else {
Ray Essickd38e1742017-01-23 15:17:06 -0800491 snprintf(buffer, SIZE, "Metrics gathering: DISABLED via property\n");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800492 }
493 result.append(buffer);
494
495 snprintf(buffer, SIZE,
Ray Essickf65f4212017-08-31 11:41:19 -0700496 "Since Boot: Submissions: %8" PRId64
497 " Finalizations: %8" PRId64 "\n",
498 mItemsSubmitted, mItemsFinalized);
499 result.append(buffer);
500 snprintf(buffer, SIZE,
501 "Records Discarded: %8" PRId64
502 " (by Count: %" PRId64 " by Expiration: %" PRId64 ")\n",
503 mItemsDiscarded, mItemsDiscardedCount, mItemsDiscardedExpire);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800504 result.append(buffer);
Ray Essick2e9c63b2017-03-29 15:16:44 -0700505 snprintf(buffer, SIZE,
506 "Summary Sets Discarded: %" PRId64 "\n", mSetsDiscarded);
507 result.append(buffer);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800508 if (ts_since != 0) {
509 snprintf(buffer, SIZE,
510 "Dumping Queue entries more recent than: %" PRId64 "\n",
511 (int64_t) ts_since);
512 result.append(buffer);
513 }
Ray Essick2e9c63b2017-03-29 15:16:44 -0700514}
515
516// dump summary info
517void MediaAnalyticsService::dumpSummaries(String8 &result, nsecs_t ts_since, const char *only) {
518 const size_t SIZE = 512;
519 char buffer[SIZE];
520 int slot = 0;
521
522 snprintf(buffer, SIZE, "\nSummarized Metrics:\n");
523 result.append(buffer);
524
Ray Essickf65f4212017-08-31 11:41:19 -0700525 if (only != NULL && *only == '\0') {
526 only = NULL;
527 }
528
Ray Essick2e9c63b2017-03-29 15:16:44 -0700529 // have each of the distillers dump records
530 if (mSummarizerSets != NULL) {
531 List<SummarizerSet *>::iterator itSet = mSummarizerSets->begin();
532 for (; itSet != mSummarizerSets->end(); itSet++) {
533 nsecs_t when = (*itSet)->getStarted();
534 if (when < ts_since) {
535 continue;
536 }
537 List<MetricsSummarizer *> *list = (*itSet)->getSummarizers();
538 List<MetricsSummarizer *>::iterator it = list->begin();
539 for (; it != list->end(); it++) {
540 if (only != NULL && strcmp(only, (*it)->getKey()) != 0) {
541 ALOGV("Told to omit '%s'", (*it)->getKey());
542 }
543 AString distilled = (*it)->dumpSummary(slot, only);
544 result.append(distilled.c_str());
545 }
546 }
547 }
548}
549
550// the recent, detailed queues
551void MediaAnalyticsService::dumpRecent(String8 &result, nsecs_t ts_since, const char * only) {
552 const size_t SIZE = 512;
553 char buffer[SIZE];
Ray Essickb5fac8e2016-12-12 11:33:56 -0800554
Ray Essickf65f4212017-08-31 11:41:19 -0700555 if (only != NULL && *only == '\0') {
556 only = NULL;
557 }
558
Ray Essickb5fac8e2016-12-12 11:33:56 -0800559 // show the recently recorded records
Ray Essickd38e1742017-01-23 15:17:06 -0800560 snprintf(buffer, sizeof(buffer), "\nFinalized Metrics (oldest first):\n");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800561 result.append(buffer);
Ray Essick2e9c63b2017-03-29 15:16:44 -0700562 result.append(this->dumpQueue(mFinalized, ts_since, only));
Ray Essickb5fac8e2016-12-12 11:33:56 -0800563
Ray Essickd38e1742017-01-23 15:17:06 -0800564 snprintf(buffer, sizeof(buffer), "\nIn-Progress Metrics (newest first):\n");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800565 result.append(buffer);
Ray Essick2e9c63b2017-03-29 15:16:44 -0700566 result.append(this->dumpQueue(mOpen, ts_since, only));
Ray Essickb5fac8e2016-12-12 11:33:56 -0800567
568 // show who is connected and injecting records?
569 // talk about # records fed to the 'readers'
570 // talk about # records we discarded, perhaps "discarded w/o reading" too
Ray Essick3938dc62016-11-01 08:56:56 -0700571}
Ray Essick3938dc62016-11-01 08:56:56 -0700572// caller has locked mLock...
Ray Essickb5fac8e2016-12-12 11:33:56 -0800573String8 MediaAnalyticsService::dumpQueue(List<MediaAnalyticsItem *> *theList) {
Ray Essick2e9c63b2017-03-29 15:16:44 -0700574 return dumpQueue(theList, (nsecs_t) 0, NULL);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800575}
576
Ray Essick2e9c63b2017-03-29 15:16:44 -0700577String8 MediaAnalyticsService::dumpQueue(List<MediaAnalyticsItem *> *theList, nsecs_t ts_since, const char * only) {
Ray Essick3938dc62016-11-01 08:56:56 -0700578 String8 result;
579 int slot = 0;
580
581 if (theList->empty()) {
582 result.append("empty\n");
583 } else {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800584 List<MediaAnalyticsItem *>::iterator it = theList->begin();
585 for (; it != theList->end(); it++) {
586 nsecs_t when = (*it)->getTimestamp();
587 if (when < ts_since) {
588 continue;
589 }
Ray Essick2e9c63b2017-03-29 15:16:44 -0700590 if (only != NULL &&
591 strcmp(only, (*it)->getKey().c_str()) != 0) {
592 ALOGV("Omit '%s', it's not '%s'", (*it)->getKey().c_str(), only);
593 continue;
594 }
Ray Essickf65f4212017-08-31 11:41:19 -0700595 AString entry = (*it)->toString(mDumpProto);
Ray Essick35ad27f2017-01-30 14:04:11 -0800596 result.appendFormat("%5d: %s\n", slot, entry.c_str());
Ray Essickb5fac8e2016-12-12 11:33:56 -0800597 slot++;
Ray Essick3938dc62016-11-01 08:56:56 -0700598 }
599 }
600
601 return result;
602}
603
604//
605// Our Cheap in-core, non-persistent records management.
606// XXX: rewrite this to manage persistence, etc.
607
608// insert appropriately into queue
Ray Essickb5fac8e2016-12-12 11:33:56 -0800609void MediaAnalyticsService::saveItem(List<MediaAnalyticsItem *> *l, MediaAnalyticsItem * item, int front) {
Ray Essick3938dc62016-11-01 08:56:56 -0700610
611 Mutex::Autolock _l(mLock);
612
Ray Essick3938dc62016-11-01 08:56:56 -0700613 // adding at back of queue (fifo order)
614 if (front) {
615 l->push_front(item);
616 } else {
617 l->push_back(item);
618 }
619
Ray Essickf65f4212017-08-31 11:41:19 -0700620 // keep removing old records the front until we're in-bounds (count)
Ray Essick3938dc62016-11-01 08:56:56 -0700621 if (mMaxRecords > 0) {
622 while (l->size() > (size_t) mMaxRecords) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800623 MediaAnalyticsItem * oitem = *(l->begin());
Ray Essick3938dc62016-11-01 08:56:56 -0700624 l->erase(l->begin());
Ray Essickb5fac8e2016-12-12 11:33:56 -0800625 delete oitem;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800626 mItemsDiscarded++;
Ray Essickf65f4212017-08-31 11:41:19 -0700627 mItemsDiscardedCount++;
628 }
629 }
630
631 // keep removing old records the front until we're in-bounds (count)
632 if (mMaxRecordAgeNs > 0) {
633 nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
634 while (l->size() > 0) {
635 MediaAnalyticsItem * oitem = *(l->begin());
636 nsecs_t when = oitem->getTimestamp();
Ray Essickf65f4212017-08-31 11:41:19 -0700637 // careful about timejumps too
638 if ((now > when) && (now-when) <= mMaxRecordAgeNs) {
639 // this (and the rest) are recent enough to keep
640 break;
641 }
642 l->erase(l->begin());
643 delete oitem;
644 mItemsDiscarded++;
645 mItemsDiscardedExpire++;
Ray Essick3938dc62016-11-01 08:56:56 -0700646 }
647 }
Ray Essick3938dc62016-11-01 08:56:56 -0700648}
649
650// are they alike enough that nitem can be folded into oitem?
Ray Essickb5fac8e2016-12-12 11:33:56 -0800651static bool compatibleItems(MediaAnalyticsItem * oitem, MediaAnalyticsItem * nitem) {
Ray Essick3938dc62016-11-01 08:56:56 -0700652
Ray Essick3938dc62016-11-01 08:56:56 -0700653 // general safety
654 if (nitem->getUid() != oitem->getUid()) {
655 return false;
656 }
657 if (nitem->getPid() != oitem->getPid()) {
658 return false;
659 }
660
661 // key -- needs to match
662 if (nitem->getKey() == oitem->getKey()) {
663 // still in the game.
664 } else {
665 return false;
666 }
667
668 // session id -- empty field in new is allowed
669 MediaAnalyticsItem::SessionID_t osession = oitem->getSessionID();
670 MediaAnalyticsItem::SessionID_t nsession = nitem->getSessionID();
671 if (nsession != osession) {
672 // incoming '0' matches value in osession
673 if (nsession != 0) {
674 return false;
675 }
676 }
677
678 return true;
679}
680
681// find the incomplete record that this will overlay
Ray Essickb5fac8e2016-12-12 11:33:56 -0800682MediaAnalyticsItem *MediaAnalyticsService::findItem(List<MediaAnalyticsItem*> *theList, MediaAnalyticsItem *nitem, bool removeit) {
Ray Essick3938dc62016-11-01 08:56:56 -0700683 if (nitem == NULL) {
684 return NULL;
685 }
686
Ray Essickb5fac8e2016-12-12 11:33:56 -0800687 MediaAnalyticsItem *item = NULL;
688
Ray Essick3938dc62016-11-01 08:56:56 -0700689 Mutex::Autolock _l(mLock);
690
Ray Essickb5fac8e2016-12-12 11:33:56 -0800691 for (List<MediaAnalyticsItem *>::iterator it = theList->begin();
Ray Essick3938dc62016-11-01 08:56:56 -0700692 it != theList->end(); it++) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800693 MediaAnalyticsItem *tmp = (*it);
Ray Essick3938dc62016-11-01 08:56:56 -0700694
695 if (!compatibleItems(tmp, nitem)) {
696 continue;
697 }
698
699 // we match! this is the one I want.
700 if (removeit) {
701 theList->erase(it);
702 }
703 item = tmp;
704 break;
705 }
706 return item;
707}
708
709
710// delete the indicated record
Ray Essickb5fac8e2016-12-12 11:33:56 -0800711void MediaAnalyticsService::deleteItem(List<MediaAnalyticsItem *> *l, MediaAnalyticsItem *item) {
Ray Essick3938dc62016-11-01 08:56:56 -0700712
713 Mutex::Autolock _l(mLock);
714
Ray Essickb5fac8e2016-12-12 11:33:56 -0800715 for (List<MediaAnalyticsItem *>::iterator it = l->begin();
Ray Essick3938dc62016-11-01 08:56:56 -0700716 it != l->end(); it++) {
717 if ((*it)->getSessionID() != item->getSessionID())
718 continue;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800719 delete *it;
Ray Essick3938dc62016-11-01 08:56:56 -0700720 l->erase(it);
721 break;
722 }
Ray Essick3938dc62016-11-01 08:56:56 -0700723}
724
Ray Essickd38e1742017-01-23 15:17:06 -0800725static AString allowedKeys[] =
726{
727 "codec",
728 "extractor"
729};
Ray Essick3938dc62016-11-01 08:56:56 -0700730
Ray Essickd38e1742017-01-23 15:17:06 -0800731static const int nAllowedKeys = sizeof(allowedKeys) / sizeof(allowedKeys[0]);
732
733// are the contents good
734bool MediaAnalyticsService::contentValid(MediaAnalyticsItem *item, bool isTrusted) {
735
736 // untrusted uids can only send us a limited set of keys
737 if (isTrusted == false) {
738 // restrict to a specific set of keys
739 AString key = item->getKey();
740
741 size_t i;
742 for(i = 0; i < nAllowedKeys; i++) {
743 if (key == allowedKeys[i]) {
744 break;
745 }
746 }
747 if (i == nAllowedKeys) {
748 ALOGD("Ignoring (key): %s", item->toString().c_str());
749 return false;
750 }
751 }
752
Ray Essick3938dc62016-11-01 08:56:56 -0700753 // internal consistency
754
755 return true;
756}
757
758// are we rate limited, normally false
Ray Essickb5fac8e2016-12-12 11:33:56 -0800759bool MediaAnalyticsService::rateLimited(MediaAnalyticsItem *) {
Ray Essick3938dc62016-11-01 08:56:56 -0700760
761 return false;
762}
763
Ray Essick2e9c63b2017-03-29 15:16:44 -0700764// insert into the appropriate summarizer.
765// we make our own copy to save/summarize
766void MediaAnalyticsService::summarize(MediaAnalyticsItem *item) {
767
768 ALOGV("MediaAnalyticsService::summarize()");
769
770 if (item == NULL) {
771 return;
772 }
773
774 nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
775 if (mCurrentSet == NULL
776 || (mCurrentSet->getStarted() + mNewSetInterval < now)) {
777 newSummarizerSet();
778 }
779
780 if (mCurrentSet == NULL) {
781 return;
782 }
783
784 List<MetricsSummarizer *> *summarizers = mCurrentSet->getSummarizers();
785 List<MetricsSummarizer *>::iterator it = summarizers->begin();
786 for (; it != summarizers->end(); it++) {
787 if ((*it)->isMine(*item)) {
788 break;
789 }
790 }
791 if (it == summarizers->end()) {
792 ALOGD("no handler for type %s", item->getKey().c_str());
793 return; // no handler
794 }
795
796 // invoke the summarizer. summarizer will make whatever copies
797 // it wants; the caller retains ownership of item.
798
799 (*it)->handleRecord(item);
800
801}
Ray Essick3938dc62016-11-01 08:56:56 -0700802
Ray Essickf65f4212017-08-31 11:41:19 -0700803// mapping uids to package names
804
805// give me the package name, perhaps going to find it
806AString MediaAnalyticsService::getPkgName(uid_t uid, bool addIfMissing) {
807 ssize_t i = mPkgMappings.indexOfKey(uid);
808 if (i >= 0) {
809 AString pkg = mPkgMappings.valueAt(i);
810 ALOGV("returning pkg '%s' for uid %d", pkg.c_str(), uid);
811 return pkg;
812 }
813
814 AString pkg;
815
816 if (addIfMissing == false) {
817 return pkg;
818 }
819
820 struct passwd *pw = getpwuid(uid);
821 if (pw) {
822 pkg = pw->pw_name;
823 } else {
824 pkg = "-";
825 }
826
827 // find the proper value
828
829 sp<IBinder> binder = NULL;
830 sp<IServiceManager> sm = defaultServiceManager();
831 if (sm == NULL) {
832 ALOGE("defaultServiceManager failed");
833 } else {
834 binder = sm->getService(String16("package_native"));
835 if (binder == NULL) {
836 ALOGE("getService package_native failed");
837 }
838 }
839
840 if (binder != NULL) {
841 sp<IPackageManagerNative> package_mgr = interface_cast<IPackageManagerNative>(binder);
842
843 std::vector<int> uids;
844 std::vector<std::string> names;
845
846 uids.push_back(uid);
847
848 binder::Status status = package_mgr->getNamesForUids(uids, &names);
849 if (!status.isOk()) {
850 ALOGE("package_native::getNamesForUids failed: %s",
851 status.exceptionMessage().c_str());
852 } else {
853 if (!names[0].empty()) {
854 pkg = names[0].c_str();
855 }
856 }
857 }
858
859 // XXX determine whether package was side-loaded or from playstore.
860 // for privacy, we only list apps loaded from playstore.
861
862 // Sanitize the package name for ":"
863 // as an example, we get "shared:android.uid.systemui"
864 // replace : with something benign (I'm going to use !)
865 if (!pkg.empty()) {
866 int n = pkg.size();
867 char *p = (char *) pkg.c_str();
868 for (int i = 0 ; i < n; i++) {
869 if (p[i] == ':') {
870 p[i] = '!';
871 }
872 }
873 }
874
875 // add it to the map, to save a subsequent lookup
876 if (!pkg.empty()) {
877 ALOGV("Adding uid %d pkg '%s'", uid, pkg.c_str());
878 mPkgMappings.add(uid, pkg);
879 }
880
881 return pkg;
882}
883
Ray Essick3938dc62016-11-01 08:56:56 -0700884} // namespace android