blob: c7f927040af2d7d68f53fd89d0a9d6f5a6a5acc0 [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);
Ray Essick721b7a02017-09-11 09:33:56 -0700225 // round nsecs to seconds
226 now = ((now + 500000000) / 1000000000) * 1000000000;
Ray Essick3938dc62016-11-01 08:56:56 -0700227 item->setTimestamp(now);
228 int pid = IPCThreadState::self()->getCallingPid();
Ray Essick3938dc62016-11-01 08:56:56 -0700229 int uid = IPCThreadState::self()->getCallingUid();
Ray Essickd38e1742017-01-23 15:17:06 -0800230
231 int uid_given = item->getUid();
232 int pid_given = item->getPid();
233
234 // although we do make exceptions for particular client uids
235 // that we know we trust.
236 //
237 bool isTrusted = false;
238
Ray Essickf65f4212017-08-31 11:41:19 -0700239 ALOGV("caller has uid=%d, embedded uid=%d", uid, uid_given);
240
Ray Essickd38e1742017-01-23 15:17:06 -0800241 switch (uid) {
242 case AID_MEDIA:
243 case AID_MEDIA_CODEC:
244 case AID_MEDIA_EX:
245 case AID_MEDIA_DRM:
246 // trusted source, only override default values
Ray Essickf65f4212017-08-31 11:41:19 -0700247 isTrusted = true;
Ray Essickd38e1742017-01-23 15:17:06 -0800248 if (uid_given == (-1)) {
249 item->setUid(uid);
250 }
251 if (pid_given == (-1)) {
252 item->setPid(pid);
253 }
254 break;
255 default:
256 isTrusted = false;
257 item->setPid(pid);
258 item->setUid(uid);
259 break;
260 }
261
Ray Essickfa149562017-09-19 09:27:31 -0700262
Adam Stone21c72122017-09-05 19:02:06 -0700263 // Overwrite package name and version if the caller was untrusted.
264 if (!isTrusted) {
Ray Essickfa149562017-09-19 09:27:31 -0700265 setPkgInfo(item, item->getUid(), true, true);
Adam Stone21c72122017-09-05 19:02:06 -0700266 } else if (item->getPkgName().empty()) {
Ray Essickfa149562017-09-19 09:27:31 -0700267 // empty, so fill out both parts
268 setPkgInfo(item, item->getUid(), true, true);
269 } else {
270 // trusted, provided a package, do nothing
Adam Stone21c72122017-09-05 19:02:06 -0700271 }
272
273 ALOGV("given uid %d; sanitized uid: %d sanitized pkg: %s "
274 "sanitized pkg version: %d",
275 uid_given, item->getUid(),
276 item->getPkgName().c_str(),
277 item->getPkgVersionCode());
Ray Essick3938dc62016-11-01 08:56:56 -0700278
279 mItemsSubmitted++;
280
281 // validate the record; we discard if we don't like it
Ray Essickd38e1742017-01-23 15:17:06 -0800282 if (contentValid(item, isTrusted) == false) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800283 delete item;
Ray Essick3938dc62016-11-01 08:56:56 -0700284 return MediaAnalyticsItem::SessionIDInvalid;
285 }
286
287
288 // if we have a sesisonid in the new record, look to make
289 // sure it doesn't appear in the finalized list.
290 // XXX: this is for security / DOS prevention.
291 // may also require that we persist the unique sessionIDs
292 // across boots [instead of within a single boot]
293
294
295 // match this new record up against records in the open
296 // list...
297 // if there's a match, merge them together
298 // deal with moving the old / merged record into the finalized que
299
300 bool finalizing = item->getFinalized();
301
302 // if finalizing, we'll remove it
Ray Essickb5fac8e2016-12-12 11:33:56 -0800303 MediaAnalyticsItem *oitem = findItem(mOpen, item, finalizing | forcenew);
Ray Essick3938dc62016-11-01 08:56:56 -0700304 if (oitem != NULL) {
305 if (forcenew) {
306 // old one gets finalized, then we insert the new one
307 // so we'll have 2 records at the end of this.
308 // but don't finalize an empty record
Ray Essickb5fac8e2016-12-12 11:33:56 -0800309 if (oitem->count() == 0) {
310 // we're responsible for disposing of the dead record
311 delete oitem;
312 oitem = NULL;
313 } else {
Ray Essick3938dc62016-11-01 08:56:56 -0700314 oitem->setFinalized(true);
Ray Essick2e9c63b2017-03-29 15:16:44 -0700315 summarize(oitem);
Ray Essick3938dc62016-11-01 08:56:56 -0700316 saveItem(mFinalized, oitem, 0);
317 }
318 // new record could itself be marked finalized...
319 if (finalizing) {
Ray Essick2e9c63b2017-03-29 15:16:44 -0700320 summarize(item);
Ray Essick3938dc62016-11-01 08:56:56 -0700321 saveItem(mFinalized, item, 0);
322 mItemsFinalized++;
323 } else {
324 saveItem(mOpen, item, 1);
325 }
326 id = item->getSessionID();
327 } else {
328 // combine the records, send it to finalized if appropriate
329 oitem->merge(item);
330 if (finalizing) {
Ray Essick2e9c63b2017-03-29 15:16:44 -0700331 summarize(oitem);
Ray Essick3938dc62016-11-01 08:56:56 -0700332 saveItem(mFinalized, oitem, 0);
333 mItemsFinalized++;
334 }
335 id = oitem->getSessionID();
Ray Essickb5fac8e2016-12-12 11:33:56 -0800336
337 // we're responsible for disposing of the dead record
338 delete item;
339 item = NULL;
Ray Essick3938dc62016-11-01 08:56:56 -0700340 }
341 } else {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800342 // nothing to merge, save the new record
343 id = item->getSessionID();
344 if (finalizing) {
345 if (item->count() == 0) {
346 // drop empty records
347 delete item;
348 item = NULL;
Ray Essick3938dc62016-11-01 08:56:56 -0700349 } else {
Ray Essick2e9c63b2017-03-29 15:16:44 -0700350 summarize(item);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800351 saveItem(mFinalized, item, 0);
352 mItemsFinalized++;
Ray Essick3938dc62016-11-01 08:56:56 -0700353 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800354 } else {
355 saveItem(mOpen, item, 1);
356 }
Ray Essick3938dc62016-11-01 08:56:56 -0700357 }
Ray Essick3938dc62016-11-01 08:56:56 -0700358 return id;
359}
360
Ray Essickf65f4212017-08-31 11:41:19 -0700361
Ray Essickb5fac8e2016-12-12 11:33:56 -0800362status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
Ray Essick3938dc62016-11-01 08:56:56 -0700363{
Ray Essickb5fac8e2016-12-12 11:33:56 -0800364 const size_t SIZE = 512;
Ray Essick3938dc62016-11-01 08:56:56 -0700365 char buffer[SIZE];
366 String8 result;
367
368 if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
369 snprintf(buffer, SIZE, "Permission Denial: "
370 "can't dump MediaAnalyticsService from pid=%d, uid=%d\n",
371 IPCThreadState::self()->getCallingPid(),
372 IPCThreadState::self()->getCallingUid());
373 result.append(buffer);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800374 write(fd, result.string(), result.size());
375 return NO_ERROR;
Ray Essick3938dc62016-11-01 08:56:56 -0700376 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800377
378 // crack any parameters
Ray Essick2e9c63b2017-03-29 15:16:44 -0700379 String16 summaryOption("-summary");
Ray Essickf65f4212017-08-31 11:41:19 -0700380 bool summary = false;
381 String16 protoOption("-proto");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800382 String16 clearOption("-clear");
Ray Essickf65f4212017-08-31 11:41:19 -0700383 bool clear = false;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800384 String16 sinceOption("-since");
Ray Essickf65f4212017-08-31 11:41:19 -0700385 nsecs_t ts_since = 0;
Ray Essick35ad27f2017-01-30 14:04:11 -0800386 String16 helpOption("-help");
Ray Essick2e9c63b2017-03-29 15:16:44 -0700387 String16 onlyOption("-only");
Ray Essickf65f4212017-08-31 11:41:19 -0700388 AString only;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800389 int n = args.size();
Ray Essickf65f4212017-08-31 11:41:19 -0700390
Ray Essickb5fac8e2016-12-12 11:33:56 -0800391 for (int i = 0; i < n; i++) {
392 String8 myarg(args[i]);
393 if (args[i] == clearOption) {
394 clear = true;
Ray Essick2e9c63b2017-03-29 15:16:44 -0700395 } else if (args[i] == summaryOption) {
396 summary = true;
Ray Essickf65f4212017-08-31 11:41:19 -0700397 } else if (args[i] == protoOption) {
398 i++;
399 if (i < n) {
400 String8 value(args[i]);
401 int proto = MediaAnalyticsItem::PROTO_V0; // default to original
402 char *endp;
403 const char *p = value.string();
404 proto = strtol(p, &endp, 10);
405 if (endp != p || *endp == '\0') {
406 if (proto < MediaAnalyticsItem::PROTO_FIRST) {
407 proto = MediaAnalyticsItem::PROTO_FIRST;
408 } else if (proto > MediaAnalyticsItem::PROTO_LAST) {
409 proto = MediaAnalyticsItem::PROTO_LAST;
410 }
411 mDumpProto = proto;
412 }
413 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800414 } else if (args[i] == sinceOption) {
415 i++;
416 if (i < n) {
417 String8 value(args[i]);
418 char *endp;
419 const char *p = value.string();
420 ts_since = strtoll(p, &endp, 10);
421 if (endp == p || *endp != '\0') {
422 ts_since = 0;
423 }
424 } else {
425 ts_since = 0;
426 }
Ray Essick35ad27f2017-01-30 14:04:11 -0800427 // command line is milliseconds; internal units are nano-seconds
428 ts_since *= 1000*1000;
Ray Essick2e9c63b2017-03-29 15:16:44 -0700429 } else if (args[i] == onlyOption) {
430 i++;
431 if (i < n) {
432 String8 value(args[i]);
Ray Essickf65f4212017-08-31 11:41:19 -0700433 only = value.string();
Ray Essick2e9c63b2017-03-29 15:16:44 -0700434 }
Ray Essick35ad27f2017-01-30 14:04:11 -0800435 } else if (args[i] == helpOption) {
436 result.append("Recognized parameters:\n");
437 result.append("-help this help message\n");
Ray Essickf65f4212017-08-31 11:41:19 -0700438 result.append("-proto X dump using protocol X (defaults to 1)");
Ray Essick2e9c63b2017-03-29 15:16:44 -0700439 result.append("-summary show summary info\n");
Ray Essick35ad27f2017-01-30 14:04:11 -0800440 result.append("-clear clears out saved records\n");
Ray Essick2e9c63b2017-03-29 15:16:44 -0700441 result.append("-only X process records for component X\n");
442 result.append("-since X include records since X\n");
443 result.append(" (X is milliseconds since the UNIX epoch)\n");
Ray Essick35ad27f2017-01-30 14:04:11 -0800444 write(fd, result.string(), result.size());
445 return NO_ERROR;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800446 }
447 }
448
449 Mutex::Autolock _l(mLock);
450
Ray Essick2e9c63b2017-03-29 15:16:44 -0700451 // we ALWAYS dump this piece
452 snprintf(buffer, SIZE, "Dump of the %s process:\n", kServiceName);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800453 result.append(buffer);
454
Ray Essick2e9c63b2017-03-29 15:16:44 -0700455 dumpHeaders(result, ts_since);
456
Ray Essickf65f4212017-08-31 11:41:19 -0700457 // want exactly 1, to avoid confusing folks that parse the output
Ray Essick2e9c63b2017-03-29 15:16:44 -0700458 if (summary) {
Ray Essickf65f4212017-08-31 11:41:19 -0700459 dumpSummaries(result, ts_since, only.c_str());
Ray Essick2e9c63b2017-03-29 15:16:44 -0700460 } else {
Ray Essickf65f4212017-08-31 11:41:19 -0700461 dumpRecent(result, ts_since, only.c_str());
Ray Essick2e9c63b2017-03-29 15:16:44 -0700462 }
463
464
465 if (clear) {
466 // remove everything from the finalized queue
467 while (mFinalized->size() > 0) {
468 MediaAnalyticsItem * oitem = *(mFinalized->begin());
469 mFinalized->erase(mFinalized->begin());
470 delete oitem;
471 mItemsDiscarded++;
472 }
473
474 // shall we clear the summary data too?
475
476 }
477
478 write(fd, result.string(), result.size());
479 return NO_ERROR;
480}
481
482// dump headers
483void MediaAnalyticsService::dumpHeaders(String8 &result, nsecs_t ts_since) {
484 const size_t SIZE = 512;
485 char buffer[SIZE];
486
Ray Essickf65f4212017-08-31 11:41:19 -0700487 snprintf(buffer, SIZE, "Protocol Version: %d\n", mDumpProto);
488 result.append(buffer);
489
Ray Essickb5fac8e2016-12-12 11:33:56 -0800490 int enabled = MediaAnalyticsItem::isEnabled();
491 if (enabled) {
Ray Essickd38e1742017-01-23 15:17:06 -0800492 snprintf(buffer, SIZE, "Metrics gathering: enabled\n");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800493 } else {
Ray Essickd38e1742017-01-23 15:17:06 -0800494 snprintf(buffer, SIZE, "Metrics gathering: DISABLED via property\n");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800495 }
496 result.append(buffer);
497
498 snprintf(buffer, SIZE,
Ray Essickf65f4212017-08-31 11:41:19 -0700499 "Since Boot: Submissions: %8" PRId64
500 " Finalizations: %8" PRId64 "\n",
501 mItemsSubmitted, mItemsFinalized);
502 result.append(buffer);
503 snprintf(buffer, SIZE,
504 "Records Discarded: %8" PRId64
505 " (by Count: %" PRId64 " by Expiration: %" PRId64 ")\n",
506 mItemsDiscarded, mItemsDiscardedCount, mItemsDiscardedExpire);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800507 result.append(buffer);
Ray Essick2e9c63b2017-03-29 15:16:44 -0700508 snprintf(buffer, SIZE,
509 "Summary Sets Discarded: %" PRId64 "\n", mSetsDiscarded);
510 result.append(buffer);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800511 if (ts_since != 0) {
512 snprintf(buffer, SIZE,
513 "Dumping Queue entries more recent than: %" PRId64 "\n",
514 (int64_t) ts_since);
515 result.append(buffer);
516 }
Ray Essick2e9c63b2017-03-29 15:16:44 -0700517}
518
519// dump summary info
520void MediaAnalyticsService::dumpSummaries(String8 &result, nsecs_t ts_since, const char *only) {
521 const size_t SIZE = 512;
522 char buffer[SIZE];
523 int slot = 0;
524
525 snprintf(buffer, SIZE, "\nSummarized Metrics:\n");
526 result.append(buffer);
527
Ray Essickf65f4212017-08-31 11:41:19 -0700528 if (only != NULL && *only == '\0') {
529 only = NULL;
530 }
531
Ray Essick2e9c63b2017-03-29 15:16:44 -0700532 // have each of the distillers dump records
533 if (mSummarizerSets != NULL) {
534 List<SummarizerSet *>::iterator itSet = mSummarizerSets->begin();
535 for (; itSet != mSummarizerSets->end(); itSet++) {
536 nsecs_t when = (*itSet)->getStarted();
537 if (when < ts_since) {
538 continue;
539 }
540 List<MetricsSummarizer *> *list = (*itSet)->getSummarizers();
541 List<MetricsSummarizer *>::iterator it = list->begin();
542 for (; it != list->end(); it++) {
543 if (only != NULL && strcmp(only, (*it)->getKey()) != 0) {
544 ALOGV("Told to omit '%s'", (*it)->getKey());
545 }
546 AString distilled = (*it)->dumpSummary(slot, only);
547 result.append(distilled.c_str());
548 }
549 }
550 }
551}
552
553// the recent, detailed queues
554void MediaAnalyticsService::dumpRecent(String8 &result, nsecs_t ts_since, const char * only) {
555 const size_t SIZE = 512;
556 char buffer[SIZE];
Ray Essickb5fac8e2016-12-12 11:33:56 -0800557
Ray Essickf65f4212017-08-31 11:41:19 -0700558 if (only != NULL && *only == '\0') {
559 only = NULL;
560 }
561
Ray Essickb5fac8e2016-12-12 11:33:56 -0800562 // show the recently recorded records
Ray Essickd38e1742017-01-23 15:17:06 -0800563 snprintf(buffer, sizeof(buffer), "\nFinalized Metrics (oldest first):\n");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800564 result.append(buffer);
Ray Essick2e9c63b2017-03-29 15:16:44 -0700565 result.append(this->dumpQueue(mFinalized, ts_since, only));
Ray Essickb5fac8e2016-12-12 11:33:56 -0800566
Ray Essickd38e1742017-01-23 15:17:06 -0800567 snprintf(buffer, sizeof(buffer), "\nIn-Progress Metrics (newest first):\n");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800568 result.append(buffer);
Ray Essick2e9c63b2017-03-29 15:16:44 -0700569 result.append(this->dumpQueue(mOpen, ts_since, only));
Ray Essickb5fac8e2016-12-12 11:33:56 -0800570
571 // show who is connected and injecting records?
572 // talk about # records fed to the 'readers'
573 // talk about # records we discarded, perhaps "discarded w/o reading" too
Ray Essick3938dc62016-11-01 08:56:56 -0700574}
Ray Essick3938dc62016-11-01 08:56:56 -0700575// caller has locked mLock...
Ray Essickb5fac8e2016-12-12 11:33:56 -0800576String8 MediaAnalyticsService::dumpQueue(List<MediaAnalyticsItem *> *theList) {
Ray Essick2e9c63b2017-03-29 15:16:44 -0700577 return dumpQueue(theList, (nsecs_t) 0, NULL);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800578}
579
Ray Essick2e9c63b2017-03-29 15:16:44 -0700580String8 MediaAnalyticsService::dumpQueue(List<MediaAnalyticsItem *> *theList, nsecs_t ts_since, const char * only) {
Ray Essick3938dc62016-11-01 08:56:56 -0700581 String8 result;
582 int slot = 0;
583
584 if (theList->empty()) {
585 result.append("empty\n");
586 } else {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800587 List<MediaAnalyticsItem *>::iterator it = theList->begin();
588 for (; it != theList->end(); it++) {
589 nsecs_t when = (*it)->getTimestamp();
590 if (when < ts_since) {
591 continue;
592 }
Ray Essick2e9c63b2017-03-29 15:16:44 -0700593 if (only != NULL &&
594 strcmp(only, (*it)->getKey().c_str()) != 0) {
595 ALOGV("Omit '%s', it's not '%s'", (*it)->getKey().c_str(), only);
596 continue;
597 }
Ray Essickf65f4212017-08-31 11:41:19 -0700598 AString entry = (*it)->toString(mDumpProto);
Ray Essick35ad27f2017-01-30 14:04:11 -0800599 result.appendFormat("%5d: %s\n", slot, entry.c_str());
Ray Essickb5fac8e2016-12-12 11:33:56 -0800600 slot++;
Ray Essick3938dc62016-11-01 08:56:56 -0700601 }
602 }
603
604 return result;
605}
606
607//
608// Our Cheap in-core, non-persistent records management.
609// XXX: rewrite this to manage persistence, etc.
610
611// insert appropriately into queue
Ray Essickb5fac8e2016-12-12 11:33:56 -0800612void MediaAnalyticsService::saveItem(List<MediaAnalyticsItem *> *l, MediaAnalyticsItem * item, int front) {
Ray Essick3938dc62016-11-01 08:56:56 -0700613
614 Mutex::Autolock _l(mLock);
615
Ray Essick3938dc62016-11-01 08:56:56 -0700616 // adding at back of queue (fifo order)
617 if (front) {
618 l->push_front(item);
619 } else {
620 l->push_back(item);
621 }
622
Ray Essickf65f4212017-08-31 11:41:19 -0700623 // keep removing old records the front until we're in-bounds (count)
Ray Essick3938dc62016-11-01 08:56:56 -0700624 if (mMaxRecords > 0) {
625 while (l->size() > (size_t) mMaxRecords) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800626 MediaAnalyticsItem * oitem = *(l->begin());
Ray Essick3938dc62016-11-01 08:56:56 -0700627 l->erase(l->begin());
Ray Essickb5fac8e2016-12-12 11:33:56 -0800628 delete oitem;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800629 mItemsDiscarded++;
Ray Essickf65f4212017-08-31 11:41:19 -0700630 mItemsDiscardedCount++;
631 }
632 }
633
634 // keep removing old records the front until we're in-bounds (count)
635 if (mMaxRecordAgeNs > 0) {
636 nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
637 while (l->size() > 0) {
638 MediaAnalyticsItem * oitem = *(l->begin());
639 nsecs_t when = oitem->getTimestamp();
Ray Essickf65f4212017-08-31 11:41:19 -0700640 // careful about timejumps too
641 if ((now > when) && (now-when) <= mMaxRecordAgeNs) {
642 // this (and the rest) are recent enough to keep
643 break;
644 }
645 l->erase(l->begin());
646 delete oitem;
647 mItemsDiscarded++;
648 mItemsDiscardedExpire++;
Ray Essick3938dc62016-11-01 08:56:56 -0700649 }
650 }
Ray Essick3938dc62016-11-01 08:56:56 -0700651}
652
653// are they alike enough that nitem can be folded into oitem?
Ray Essickb5fac8e2016-12-12 11:33:56 -0800654static bool compatibleItems(MediaAnalyticsItem * oitem, MediaAnalyticsItem * nitem) {
Ray Essick3938dc62016-11-01 08:56:56 -0700655
Ray Essick3938dc62016-11-01 08:56:56 -0700656 // general safety
657 if (nitem->getUid() != oitem->getUid()) {
658 return false;
659 }
660 if (nitem->getPid() != oitem->getPid()) {
661 return false;
662 }
663
664 // key -- needs to match
665 if (nitem->getKey() == oitem->getKey()) {
666 // still in the game.
667 } else {
668 return false;
669 }
670
671 // session id -- empty field in new is allowed
672 MediaAnalyticsItem::SessionID_t osession = oitem->getSessionID();
673 MediaAnalyticsItem::SessionID_t nsession = nitem->getSessionID();
674 if (nsession != osession) {
675 // incoming '0' matches value in osession
676 if (nsession != 0) {
677 return false;
678 }
679 }
680
681 return true;
682}
683
684// find the incomplete record that this will overlay
Ray Essickb5fac8e2016-12-12 11:33:56 -0800685MediaAnalyticsItem *MediaAnalyticsService::findItem(List<MediaAnalyticsItem*> *theList, MediaAnalyticsItem *nitem, bool removeit) {
Ray Essick3938dc62016-11-01 08:56:56 -0700686 if (nitem == NULL) {
687 return NULL;
688 }
689
Ray Essickb5fac8e2016-12-12 11:33:56 -0800690 MediaAnalyticsItem *item = NULL;
691
Ray Essick3938dc62016-11-01 08:56:56 -0700692 Mutex::Autolock _l(mLock);
693
Ray Essickb5fac8e2016-12-12 11:33:56 -0800694 for (List<MediaAnalyticsItem *>::iterator it = theList->begin();
Ray Essick3938dc62016-11-01 08:56:56 -0700695 it != theList->end(); it++) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800696 MediaAnalyticsItem *tmp = (*it);
Ray Essick3938dc62016-11-01 08:56:56 -0700697
698 if (!compatibleItems(tmp, nitem)) {
699 continue;
700 }
701
702 // we match! this is the one I want.
703 if (removeit) {
704 theList->erase(it);
705 }
706 item = tmp;
707 break;
708 }
709 return item;
710}
711
712
713// delete the indicated record
Ray Essickb5fac8e2016-12-12 11:33:56 -0800714void MediaAnalyticsService::deleteItem(List<MediaAnalyticsItem *> *l, MediaAnalyticsItem *item) {
Ray Essick3938dc62016-11-01 08:56:56 -0700715
716 Mutex::Autolock _l(mLock);
717
Ray Essickb5fac8e2016-12-12 11:33:56 -0800718 for (List<MediaAnalyticsItem *>::iterator it = l->begin();
Ray Essick3938dc62016-11-01 08:56:56 -0700719 it != l->end(); it++) {
720 if ((*it)->getSessionID() != item->getSessionID())
721 continue;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800722 delete *it;
Ray Essick3938dc62016-11-01 08:56:56 -0700723 l->erase(it);
724 break;
725 }
Ray Essick3938dc62016-11-01 08:56:56 -0700726}
727
Ray Essickd38e1742017-01-23 15:17:06 -0800728static AString allowedKeys[] =
729{
730 "codec",
731 "extractor"
732};
Ray Essick3938dc62016-11-01 08:56:56 -0700733
Ray Essickd38e1742017-01-23 15:17:06 -0800734static const int nAllowedKeys = sizeof(allowedKeys) / sizeof(allowedKeys[0]);
735
736// are the contents good
737bool MediaAnalyticsService::contentValid(MediaAnalyticsItem *item, bool isTrusted) {
738
739 // untrusted uids can only send us a limited set of keys
740 if (isTrusted == false) {
741 // restrict to a specific set of keys
742 AString key = item->getKey();
743
744 size_t i;
745 for(i = 0; i < nAllowedKeys; i++) {
746 if (key == allowedKeys[i]) {
747 break;
748 }
749 }
750 if (i == nAllowedKeys) {
751 ALOGD("Ignoring (key): %s", item->toString().c_str());
752 return false;
753 }
754 }
755
Ray Essick3938dc62016-11-01 08:56:56 -0700756 // internal consistency
757
758 return true;
759}
760
761// are we rate limited, normally false
Ray Essickb5fac8e2016-12-12 11:33:56 -0800762bool MediaAnalyticsService::rateLimited(MediaAnalyticsItem *) {
Ray Essick3938dc62016-11-01 08:56:56 -0700763
764 return false;
765}
766
Ray Essick2e9c63b2017-03-29 15:16:44 -0700767// insert into the appropriate summarizer.
768// we make our own copy to save/summarize
769void MediaAnalyticsService::summarize(MediaAnalyticsItem *item) {
770
771 ALOGV("MediaAnalyticsService::summarize()");
772
773 if (item == NULL) {
774 return;
775 }
776
777 nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
778 if (mCurrentSet == NULL
779 || (mCurrentSet->getStarted() + mNewSetInterval < now)) {
780 newSummarizerSet();
781 }
782
783 if (mCurrentSet == NULL) {
784 return;
785 }
786
787 List<MetricsSummarizer *> *summarizers = mCurrentSet->getSummarizers();
788 List<MetricsSummarizer *>::iterator it = summarizers->begin();
789 for (; it != summarizers->end(); it++) {
790 if ((*it)->isMine(*item)) {
791 break;
792 }
793 }
794 if (it == summarizers->end()) {
795 ALOGD("no handler for type %s", item->getKey().c_str());
796 return; // no handler
797 }
798
799 // invoke the summarizer. summarizer will make whatever copies
800 // it wants; the caller retains ownership of item.
801
802 (*it)->handleRecord(item);
803
804}
Ray Essick3938dc62016-11-01 08:56:56 -0700805
Ray Essickfa149562017-09-19 09:27:31 -0700806// how long we hold package info before we re-fetch it
807#define PKG_EXPIRATION_NS (30*60*1000000000ll) // 30 minutes, in nsecs
Ray Essickf65f4212017-08-31 11:41:19 -0700808
809// give me the package name, perhaps going to find it
Ray Essickfa149562017-09-19 09:27:31 -0700810void MediaAnalyticsService::setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion) {
811 ALOGV("asking for packagename to go with uid=%d", uid);
812
813 if (!setName && !setVersion) {
814 // setting nothing? strange
815 return;
816 }
817
818 nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
819 struct UidToPkgMap mapping;
820 mapping.uid = (-1);
821
Ray Essickf65f4212017-08-31 11:41:19 -0700822 ssize_t i = mPkgMappings.indexOfKey(uid);
823 if (i >= 0) {
Ray Essickfa149562017-09-19 09:27:31 -0700824 mapping = mPkgMappings.valueAt(i);
825 ALOGV("Expiration? uid %d expiration %" PRId64 " now %" PRId64,
826 uid, mapping.expiration, now);
827 if (mapping.expiration < now) {
828 // purge our current entry and re-query
829 ALOGV("entry for uid %d expired, now= %" PRId64 "", uid, now);
830 mPkgMappings.removeItemsAt(i, 1);
831 // could cheat and use a goto back to the top of the routine.
832 // a good compiler should recognize the local tail recursion...
833 return setPkgInfo(item, uid, setName, setVersion);
Ray Essickf65f4212017-08-31 11:41:19 -0700834 }
Ray Essickfa149562017-09-19 09:27:31 -0700835 } else {
836 AString pkg;
837 std::string installer = "";
838 int32_t versionCode = 0;
Ray Essickf65f4212017-08-31 11:41:19 -0700839
Ray Essickfa149562017-09-19 09:27:31 -0700840 struct passwd *pw = getpwuid(uid);
841 if (pw) {
842 pkg = pw->pw_name;
843 }
Ray Essickf65f4212017-08-31 11:41:19 -0700844
Ray Essickfa149562017-09-19 09:27:31 -0700845 // find the proper value -- should we cache this binder??
Ray Essickf65f4212017-08-31 11:41:19 -0700846
Ray Essickfa149562017-09-19 09:27:31 -0700847 sp<IBinder> binder = NULL;
848 sp<IServiceManager> sm = defaultServiceManager();
849 if (sm == NULL) {
850 ALOGE("defaultServiceManager failed");
Ray Essickf65f4212017-08-31 11:41:19 -0700851 } else {
Ray Essickfa149562017-09-19 09:27:31 -0700852 binder = sm->getService(String16("package_native"));
853 if (binder == NULL) {
854 ALOGE("getService package_native failed");
855 }
856 }
857
858 if (binder != NULL) {
859 sp<IPackageManagerNative> package_mgr = interface_cast<IPackageManagerNative>(binder);
860 binder::Status status;
861
862 std::vector<int> uids;
863 std::vector<std::string> names;
864
865 uids.push_back(uid);
866
867 status = package_mgr->getNamesForUids(uids, &names);
868 if (!status.isOk()) {
869 ALOGE("package_native::getNamesForUids failed: %s",
870 status.exceptionMessage().c_str());
871 } else {
872 if (!names[0].empty()) {
873 pkg = names[0].c_str();
874 }
875 }
876
877 // strip any leading "shared:" strings that came back
878 if (pkg.startsWith("shared:")) {
879 pkg.erase(0, 7);
880 }
881
882 // determine how pkg was installed and the versionCode
883 //
884 if (pkg.empty()) {
885 // no name for us to manage
886 } else if (strchr(pkg.c_str(), '.') == NULL) {
887 // not of form 'com.whatever...'; assume internal and ok
888 } else if (strncmp(pkg.c_str(), "android.", 8) == 0) {
889 // android.* packages are assumed fine
890 } else {
891 String16 pkgName16(pkg.c_str());
892 status = package_mgr->getInstallerForPackage(pkgName16, &installer);
893 if (!status.isOk()) {
894 ALOGE("package_native::getInstallerForPackage failed: %s",
895 status.exceptionMessage().c_str());
896 }
897
898 // skip if we didn't get an installer
899 if (status.isOk()) {
900 status = package_mgr->getVersionCodeForPackage(pkgName16, &versionCode);
901 if (!status.isOk()) {
902 ALOGE("package_native::getVersionCodeForPackage failed: %s",
903 status.exceptionMessage().c_str());
904 }
905 }
906
907
908 ALOGV("package '%s' installed by '%s' versioncode %d / %08x",
909 pkg.c_str(), installer.c_str(), versionCode, versionCode);
910
911 if (strncmp(installer.c_str(), "com.android.", 12) == 0) {
912 // from play store, we keep info
913 } else if (strncmp(installer.c_str(), "com.google.", 11) == 0) {
914 // some google source, we keep info
915 } else if (strcmp(installer.c_str(), "preload") == 0) {
916 // preloads, we keep the info
917 } else if (installer.c_str()[0] == '\0') {
918 // sideload (no installer); do not report
919 pkg = "";
920 versionCode = 0;
921 } else {
922 // unknown installer; do not report
923 pkg = "";
924 versionCode = 0;
925 }
926 }
927 }
928
929 // add it to the map, to save a subsequent lookup
930 if (!pkg.empty()) {
931 Mutex::Autolock _l(mLock_mappings);
932 ALOGV("Adding uid %d pkg '%s'", uid, pkg.c_str());
933 ssize_t i = mPkgMappings.indexOfKey(uid);
934 if (i < 0) {
935 mapping.uid = uid;
936 mapping.pkg = pkg;
937 mapping.installer = installer.c_str();
938 mapping.versionCode = versionCode;
939 mapping.expiration = now + PKG_EXPIRATION_NS;
940 ALOGV("expiration for uid %d set to %" PRId64 "", uid, mapping.expiration);
941
942 mPkgMappings.add(uid, mapping);
Ray Essickf65f4212017-08-31 11:41:19 -0700943 }
944 }
945 }
946
Ray Essickfa149562017-09-19 09:27:31 -0700947 if (mapping.uid != (uid_t)(-1)) {
948 if (setName) {
949 item->setPkgName(mapping.pkg);
950 }
951 if (setVersion) {
952 item->setPkgVersionCode(mapping.versionCode);
Ray Essickf65f4212017-08-31 11:41:19 -0700953 }
954 }
Ray Essickf65f4212017-08-31 11:41:19 -0700955}
956
Ray Essick3938dc62016-11-01 08:56:56 -0700957} // namespace android