blob: 844444431caf44980c03b78ecbfc53370ed2862e [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),
Ray Essick583a23a2017-11-27 12:49:57 -0800162 mDumpProto(MediaAnalyticsItem::PROTO_V1),
163 mDumpProtoDefault(MediaAnalyticsItem::PROTO_V1) {
Ray Essick3938dc62016-11-01 08:56:56 -0700164
165 ALOGD("MediaAnalyticsService created");
166 // clear our queues
Ray Essickb5fac8e2016-12-12 11:33:56 -0800167 mOpen = new List<MediaAnalyticsItem *>();
168 mFinalized = new List<MediaAnalyticsItem *>();
Ray Essick3938dc62016-11-01 08:56:56 -0700169
Ray Essick2e9c63b2017-03-29 15:16:44 -0700170 mSummarizerSets = new List<MediaAnalyticsService::SummarizerSet *>();
171 newSummarizerSet();
172
Ray Essick3938dc62016-11-01 08:56:56 -0700173 mItemsSubmitted = 0;
174 mItemsFinalized = 0;
175 mItemsDiscarded = 0;
Ray Essickf65f4212017-08-31 11:41:19 -0700176 mItemsDiscardedExpire = 0;
177 mItemsDiscardedCount = 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700178
179 mLastSessionID = 0;
180 // recover any persistency we set up
181 // etc
182}
183
184MediaAnalyticsService::~MediaAnalyticsService() {
185 ALOGD("MediaAnalyticsService destroyed");
186
Ray Essick2e9c63b2017-03-29 15:16:44 -0700187 // clean out mOpen and mFinalized
Ray Essickf65f4212017-08-31 11:41:19 -0700188 while (mOpen->size() > 0) {
189 MediaAnalyticsItem * oitem = *(mOpen->begin());
190 mOpen->erase(mOpen->begin());
191 delete oitem;
192 mItemsDiscarded++;
193 mItemsDiscardedCount++;
194 }
Ray Essick2e9c63b2017-03-29 15:16:44 -0700195 delete mOpen;
196 mOpen = NULL;
Ray Essickf65f4212017-08-31 11:41:19 -0700197
198 while (mFinalized->size() > 0) {
199 MediaAnalyticsItem * oitem = *(mFinalized->begin());
200 mFinalized->erase(mFinalized->begin());
201 delete oitem;
202 mItemsDiscarded++;
203 mItemsDiscardedCount++;
204 }
Ray Essick2e9c63b2017-03-29 15:16:44 -0700205 delete mFinalized;
206 mFinalized = NULL;
207
208 // XXX: clean out the summaries
Ray Essick3938dc62016-11-01 08:56:56 -0700209}
210
211
212MediaAnalyticsItem::SessionID_t MediaAnalyticsService::generateUniqueSessionID() {
213 // generate a new sessionid
214
215 Mutex::Autolock _l(mLock_ids);
216 return (++mLastSessionID);
217}
218
Ray Essickb5fac8e2016-12-12 11:33:56 -0800219// caller surrenders ownership of 'item'
220MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem *item, bool forcenew) {
Ray Essick3938dc62016-11-01 08:56:56 -0700221
222 MediaAnalyticsItem::SessionID_t id = MediaAnalyticsItem::SessionIDInvalid;
223
Ray Essickd38e1742017-01-23 15:17:06 -0800224 // we control these, generally not trusting user input
Ray Essick3938dc62016-11-01 08:56:56 -0700225 nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
Ray Essick721b7a02017-09-11 09:33:56 -0700226 // round nsecs to seconds
227 now = ((now + 500000000) / 1000000000) * 1000000000;
Ray Essick3938dc62016-11-01 08:56:56 -0700228 item->setTimestamp(now);
229 int pid = IPCThreadState::self()->getCallingPid();
Ray Essick3938dc62016-11-01 08:56:56 -0700230 int uid = IPCThreadState::self()->getCallingUid();
Ray Essickd38e1742017-01-23 15:17:06 -0800231
232 int uid_given = item->getUid();
233 int pid_given = item->getPid();
234
235 // although we do make exceptions for particular client uids
236 // that we know we trust.
237 //
238 bool isTrusted = false;
239
Ray Essickf65f4212017-08-31 11:41:19 -0700240 ALOGV("caller has uid=%d, embedded uid=%d", uid, uid_given);
241
Ray Essickd38e1742017-01-23 15:17:06 -0800242 switch (uid) {
243 case AID_MEDIA:
244 case AID_MEDIA_CODEC:
245 case AID_MEDIA_EX:
246 case AID_MEDIA_DRM:
247 // trusted source, only override default values
Ray Essickf65f4212017-08-31 11:41:19 -0700248 isTrusted = true;
Ray Essickd38e1742017-01-23 15:17:06 -0800249 if (uid_given == (-1)) {
250 item->setUid(uid);
251 }
252 if (pid_given == (-1)) {
253 item->setPid(pid);
254 }
255 break;
256 default:
257 isTrusted = false;
258 item->setPid(pid);
259 item->setUid(uid);
260 break;
261 }
262
Ray Essickfa149562017-09-19 09:27:31 -0700263
Adam Stone21c72122017-09-05 19:02:06 -0700264 // Overwrite package name and version if the caller was untrusted.
265 if (!isTrusted) {
Ray Essickfa149562017-09-19 09:27:31 -0700266 setPkgInfo(item, item->getUid(), true, true);
Adam Stone21c72122017-09-05 19:02:06 -0700267 } else if (item->getPkgName().empty()) {
Ray Essickfa149562017-09-19 09:27:31 -0700268 // empty, so fill out both parts
269 setPkgInfo(item, item->getUid(), true, true);
270 } else {
271 // trusted, provided a package, do nothing
Adam Stone21c72122017-09-05 19:02:06 -0700272 }
273
274 ALOGV("given uid %d; sanitized uid: %d sanitized pkg: %s "
275 "sanitized pkg version: %d",
276 uid_given, item->getUid(),
277 item->getPkgName().c_str(),
278 item->getPkgVersionCode());
Ray Essick3938dc62016-11-01 08:56:56 -0700279
280 mItemsSubmitted++;
281
282 // validate the record; we discard if we don't like it
Ray Essickd38e1742017-01-23 15:17:06 -0800283 if (contentValid(item, isTrusted) == false) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800284 delete item;
Ray Essick3938dc62016-11-01 08:56:56 -0700285 return MediaAnalyticsItem::SessionIDInvalid;
286 }
287
288
289 // if we have a sesisonid in the new record, look to make
290 // sure it doesn't appear in the finalized list.
291 // XXX: this is for security / DOS prevention.
292 // may also require that we persist the unique sessionIDs
293 // across boots [instead of within a single boot]
294
295
296 // match this new record up against records in the open
297 // list...
298 // if there's a match, merge them together
299 // deal with moving the old / merged record into the finalized que
300
301 bool finalizing = item->getFinalized();
302
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700303 Mutex::Autolock _l(mLock);
304
Ray Essick3938dc62016-11-01 08:56:56 -0700305 // if finalizing, we'll remove it
Ray Essickb5fac8e2016-12-12 11:33:56 -0800306 MediaAnalyticsItem *oitem = findItem(mOpen, item, finalizing | forcenew);
Ray Essick3938dc62016-11-01 08:56:56 -0700307 if (oitem != NULL) {
308 if (forcenew) {
309 // old one gets finalized, then we insert the new one
310 // so we'll have 2 records at the end of this.
311 // but don't finalize an empty record
Ray Essickb5fac8e2016-12-12 11:33:56 -0800312 if (oitem->count() == 0) {
313 // we're responsible for disposing of the dead record
314 delete oitem;
315 oitem = NULL;
316 } else {
Ray Essick3938dc62016-11-01 08:56:56 -0700317 oitem->setFinalized(true);
Ray Essick2e9c63b2017-03-29 15:16:44 -0700318 summarize(oitem);
Ray Essick3938dc62016-11-01 08:56:56 -0700319 saveItem(mFinalized, oitem, 0);
320 }
321 // new record could itself be marked finalized...
Ray Essicke5db6db2017-11-10 15:54:32 -0800322 id = item->getSessionID();
Ray Essick3938dc62016-11-01 08:56:56 -0700323 if (finalizing) {
Ray Essick2e9c63b2017-03-29 15:16:44 -0700324 summarize(item);
Ray Essick3938dc62016-11-01 08:56:56 -0700325 saveItem(mFinalized, item, 0);
326 mItemsFinalized++;
327 } else {
328 saveItem(mOpen, item, 1);
329 }
Ray Essick3938dc62016-11-01 08:56:56 -0700330 } else {
331 // combine the records, send it to finalized if appropriate
332 oitem->merge(item);
Ray Essicke5db6db2017-11-10 15:54:32 -0800333 id = oitem->getSessionID();
Ray Essick3938dc62016-11-01 08:56:56 -0700334 if (finalizing) {
Ray Essick2e9c63b2017-03-29 15:16:44 -0700335 summarize(oitem);
Ray Essick3938dc62016-11-01 08:56:56 -0700336 saveItem(mFinalized, oitem, 0);
337 mItemsFinalized++;
338 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800339
340 // we're responsible for disposing of the dead record
341 delete item;
342 item = NULL;
Ray Essick3938dc62016-11-01 08:56:56 -0700343 }
344 } else {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800345 // nothing to merge, save the new record
346 id = item->getSessionID();
347 if (finalizing) {
348 if (item->count() == 0) {
349 // drop empty records
350 delete item;
351 item = NULL;
Ray Essick3938dc62016-11-01 08:56:56 -0700352 } else {
Ray Essick2e9c63b2017-03-29 15:16:44 -0700353 summarize(item);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800354 saveItem(mFinalized, item, 0);
355 mItemsFinalized++;
Ray Essick3938dc62016-11-01 08:56:56 -0700356 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800357 } else {
358 saveItem(mOpen, item, 1);
359 }
Ray Essick3938dc62016-11-01 08:56:56 -0700360 }
Ray Essick3938dc62016-11-01 08:56:56 -0700361 return id;
362}
363
Ray Essickf65f4212017-08-31 11:41:19 -0700364
Ray Essickb5fac8e2016-12-12 11:33:56 -0800365status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
Ray Essick3938dc62016-11-01 08:56:56 -0700366{
Ray Essickb5fac8e2016-12-12 11:33:56 -0800367 const size_t SIZE = 512;
Ray Essick3938dc62016-11-01 08:56:56 -0700368 char buffer[SIZE];
369 String8 result;
370
371 if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
372 snprintf(buffer, SIZE, "Permission Denial: "
373 "can't dump MediaAnalyticsService from pid=%d, uid=%d\n",
374 IPCThreadState::self()->getCallingPid(),
375 IPCThreadState::self()->getCallingUid());
376 result.append(buffer);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800377 write(fd, result.string(), result.size());
378 return NO_ERROR;
Ray Essick3938dc62016-11-01 08:56:56 -0700379 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800380
381 // crack any parameters
Ray Essick2e9c63b2017-03-29 15:16:44 -0700382 String16 summaryOption("-summary");
Ray Essickf65f4212017-08-31 11:41:19 -0700383 bool summary = false;
384 String16 protoOption("-proto");
Ray Essick583a23a2017-11-27 12:49:57 -0800385 int chosenProto = mDumpProtoDefault;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800386 String16 clearOption("-clear");
Ray Essickf65f4212017-08-31 11:41:19 -0700387 bool clear = false;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800388 String16 sinceOption("-since");
Ray Essickf65f4212017-08-31 11:41:19 -0700389 nsecs_t ts_since = 0;
Ray Essick35ad27f2017-01-30 14:04:11 -0800390 String16 helpOption("-help");
Ray Essick2e9c63b2017-03-29 15:16:44 -0700391 String16 onlyOption("-only");
Ray Essickf65f4212017-08-31 11:41:19 -0700392 AString only;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800393 int n = args.size();
Ray Essickf65f4212017-08-31 11:41:19 -0700394
Ray Essickb5fac8e2016-12-12 11:33:56 -0800395 for (int i = 0; i < n; i++) {
396 String8 myarg(args[i]);
397 if (args[i] == clearOption) {
398 clear = true;
Ray Essick2e9c63b2017-03-29 15:16:44 -0700399 } else if (args[i] == summaryOption) {
400 summary = true;
Ray Essickf65f4212017-08-31 11:41:19 -0700401 } else if (args[i] == protoOption) {
402 i++;
403 if (i < n) {
404 String8 value(args[i]);
Ray Essick583a23a2017-11-27 12:49:57 -0800405 int proto = MediaAnalyticsItem::PROTO_V0;
Ray Essickf65f4212017-08-31 11:41:19 -0700406 char *endp;
407 const char *p = value.string();
408 proto = strtol(p, &endp, 10);
409 if (endp != p || *endp == '\0') {
410 if (proto < MediaAnalyticsItem::PROTO_FIRST) {
411 proto = MediaAnalyticsItem::PROTO_FIRST;
412 } else if (proto > MediaAnalyticsItem::PROTO_LAST) {
413 proto = MediaAnalyticsItem::PROTO_LAST;
414 }
Ray Essick583a23a2017-11-27 12:49:57 -0800415 chosenProto = proto;
416 } else {
417 result.append("unable to parse value for -proto\n\n");
Ray Essickf65f4212017-08-31 11:41:19 -0700418 }
Ray Essick583a23a2017-11-27 12:49:57 -0800419 } else {
420 result.append("missing value for -proto\n\n");
Ray Essickf65f4212017-08-31 11:41:19 -0700421 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800422 } else if (args[i] == sinceOption) {
423 i++;
424 if (i < n) {
425 String8 value(args[i]);
426 char *endp;
427 const char *p = value.string();
428 ts_since = strtoll(p, &endp, 10);
429 if (endp == p || *endp != '\0') {
430 ts_since = 0;
431 }
432 } else {
433 ts_since = 0;
434 }
Ray Essick35ad27f2017-01-30 14:04:11 -0800435 // command line is milliseconds; internal units are nano-seconds
436 ts_since *= 1000*1000;
Ray Essick2e9c63b2017-03-29 15:16:44 -0700437 } else if (args[i] == onlyOption) {
438 i++;
439 if (i < n) {
440 String8 value(args[i]);
Ray Essickf65f4212017-08-31 11:41:19 -0700441 only = value.string();
Ray Essick2e9c63b2017-03-29 15:16:44 -0700442 }
Ray Essick35ad27f2017-01-30 14:04:11 -0800443 } else if (args[i] == helpOption) {
444 result.append("Recognized parameters:\n");
445 result.append("-help this help message\n");
Ray Essick583a23a2017-11-27 12:49:57 -0800446 result.append("-proto # dump using protocol #");
Ray Essick2e9c63b2017-03-29 15:16:44 -0700447 result.append("-summary show summary info\n");
Ray Essick35ad27f2017-01-30 14:04:11 -0800448 result.append("-clear clears out saved records\n");
Ray Essick2e9c63b2017-03-29 15:16:44 -0700449 result.append("-only X process records for component X\n");
450 result.append("-since X include records since X\n");
451 result.append(" (X is milliseconds since the UNIX epoch)\n");
Ray Essick35ad27f2017-01-30 14:04:11 -0800452 write(fd, result.string(), result.size());
453 return NO_ERROR;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800454 }
455 }
456
457 Mutex::Autolock _l(mLock);
458
Ray Essick583a23a2017-11-27 12:49:57 -0800459 mDumpProto = chosenProto;
460
Ray Essick2e9c63b2017-03-29 15:16:44 -0700461 // we ALWAYS dump this piece
462 snprintf(buffer, SIZE, "Dump of the %s process:\n", kServiceName);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800463 result.append(buffer);
464
Ray Essick2e9c63b2017-03-29 15:16:44 -0700465 dumpHeaders(result, ts_since);
466
Ray Essickf65f4212017-08-31 11:41:19 -0700467 // want exactly 1, to avoid confusing folks that parse the output
Ray Essick2e9c63b2017-03-29 15:16:44 -0700468 if (summary) {
Ray Essickf65f4212017-08-31 11:41:19 -0700469 dumpSummaries(result, ts_since, only.c_str());
Ray Essick2e9c63b2017-03-29 15:16:44 -0700470 } else {
Ray Essickf65f4212017-08-31 11:41:19 -0700471 dumpRecent(result, ts_since, only.c_str());
Ray Essick2e9c63b2017-03-29 15:16:44 -0700472 }
473
474
475 if (clear) {
476 // remove everything from the finalized queue
477 while (mFinalized->size() > 0) {
478 MediaAnalyticsItem * oitem = *(mFinalized->begin());
479 mFinalized->erase(mFinalized->begin());
480 delete oitem;
481 mItemsDiscarded++;
482 }
483
484 // shall we clear the summary data too?
485
486 }
487
488 write(fd, result.string(), result.size());
489 return NO_ERROR;
490}
491
492// dump headers
493void MediaAnalyticsService::dumpHeaders(String8 &result, nsecs_t ts_since) {
494 const size_t SIZE = 512;
495 char buffer[SIZE];
496
Ray Essickf65f4212017-08-31 11:41:19 -0700497 snprintf(buffer, SIZE, "Protocol Version: %d\n", mDumpProto);
498 result.append(buffer);
499
Ray Essickb5fac8e2016-12-12 11:33:56 -0800500 int enabled = MediaAnalyticsItem::isEnabled();
501 if (enabled) {
Ray Essickd38e1742017-01-23 15:17:06 -0800502 snprintf(buffer, SIZE, "Metrics gathering: enabled\n");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800503 } else {
Ray Essickd38e1742017-01-23 15:17:06 -0800504 snprintf(buffer, SIZE, "Metrics gathering: DISABLED via property\n");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800505 }
506 result.append(buffer);
507
508 snprintf(buffer, SIZE,
Ray Essickf65f4212017-08-31 11:41:19 -0700509 "Since Boot: Submissions: %8" PRId64
510 " Finalizations: %8" PRId64 "\n",
511 mItemsSubmitted, mItemsFinalized);
512 result.append(buffer);
513 snprintf(buffer, SIZE,
514 "Records Discarded: %8" PRId64
515 " (by Count: %" PRId64 " by Expiration: %" PRId64 ")\n",
516 mItemsDiscarded, mItemsDiscardedCount, mItemsDiscardedExpire);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800517 result.append(buffer);
Ray Essick2e9c63b2017-03-29 15:16:44 -0700518 snprintf(buffer, SIZE,
519 "Summary Sets Discarded: %" PRId64 "\n", mSetsDiscarded);
520 result.append(buffer);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800521 if (ts_since != 0) {
522 snprintf(buffer, SIZE,
523 "Dumping Queue entries more recent than: %" PRId64 "\n",
524 (int64_t) ts_since);
525 result.append(buffer);
526 }
Ray Essick2e9c63b2017-03-29 15:16:44 -0700527}
528
529// dump summary info
530void MediaAnalyticsService::dumpSummaries(String8 &result, nsecs_t ts_since, const char *only) {
531 const size_t SIZE = 512;
532 char buffer[SIZE];
533 int slot = 0;
534
535 snprintf(buffer, SIZE, "\nSummarized Metrics:\n");
536 result.append(buffer);
537
Ray Essickf65f4212017-08-31 11:41:19 -0700538 if (only != NULL && *only == '\0') {
539 only = NULL;
540 }
541
Ray Essick2e9c63b2017-03-29 15:16:44 -0700542 // have each of the distillers dump records
543 if (mSummarizerSets != NULL) {
544 List<SummarizerSet *>::iterator itSet = mSummarizerSets->begin();
545 for (; itSet != mSummarizerSets->end(); itSet++) {
546 nsecs_t when = (*itSet)->getStarted();
547 if (when < ts_since) {
548 continue;
549 }
550 List<MetricsSummarizer *> *list = (*itSet)->getSummarizers();
551 List<MetricsSummarizer *>::iterator it = list->begin();
552 for (; it != list->end(); it++) {
553 if (only != NULL && strcmp(only, (*it)->getKey()) != 0) {
554 ALOGV("Told to omit '%s'", (*it)->getKey());
555 }
556 AString distilled = (*it)->dumpSummary(slot, only);
557 result.append(distilled.c_str());
558 }
559 }
560 }
561}
562
563// the recent, detailed queues
564void MediaAnalyticsService::dumpRecent(String8 &result, nsecs_t ts_since, const char * only) {
565 const size_t SIZE = 512;
566 char buffer[SIZE];
Ray Essickb5fac8e2016-12-12 11:33:56 -0800567
Ray Essickf65f4212017-08-31 11:41:19 -0700568 if (only != NULL && *only == '\0') {
569 only = NULL;
570 }
571
Ray Essickb5fac8e2016-12-12 11:33:56 -0800572 // show the recently recorded records
Ray Essickd38e1742017-01-23 15:17:06 -0800573 snprintf(buffer, sizeof(buffer), "\nFinalized Metrics (oldest first):\n");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800574 result.append(buffer);
Ray Essick2e9c63b2017-03-29 15:16:44 -0700575 result.append(this->dumpQueue(mFinalized, ts_since, only));
Ray Essickb5fac8e2016-12-12 11:33:56 -0800576
Ray Essickd38e1742017-01-23 15:17:06 -0800577 snprintf(buffer, sizeof(buffer), "\nIn-Progress Metrics (newest first):\n");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800578 result.append(buffer);
Ray Essick2e9c63b2017-03-29 15:16:44 -0700579 result.append(this->dumpQueue(mOpen, ts_since, only));
Ray Essickb5fac8e2016-12-12 11:33:56 -0800580
581 // show who is connected and injecting records?
582 // talk about # records fed to the 'readers'
583 // talk about # records we discarded, perhaps "discarded w/o reading" too
Ray Essick3938dc62016-11-01 08:56:56 -0700584}
Ray Essick3938dc62016-11-01 08:56:56 -0700585// caller has locked mLock...
Ray Essickb5fac8e2016-12-12 11:33:56 -0800586String8 MediaAnalyticsService::dumpQueue(List<MediaAnalyticsItem *> *theList) {
Ray Essick2e9c63b2017-03-29 15:16:44 -0700587 return dumpQueue(theList, (nsecs_t) 0, NULL);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800588}
589
Ray Essick2e9c63b2017-03-29 15:16:44 -0700590String8 MediaAnalyticsService::dumpQueue(List<MediaAnalyticsItem *> *theList, nsecs_t ts_since, const char * only) {
Ray Essick3938dc62016-11-01 08:56:56 -0700591 String8 result;
592 int slot = 0;
593
594 if (theList->empty()) {
595 result.append("empty\n");
596 } else {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800597 List<MediaAnalyticsItem *>::iterator it = theList->begin();
598 for (; it != theList->end(); it++) {
599 nsecs_t when = (*it)->getTimestamp();
600 if (when < ts_since) {
601 continue;
602 }
Ray Essick2e9c63b2017-03-29 15:16:44 -0700603 if (only != NULL &&
604 strcmp(only, (*it)->getKey().c_str()) != 0) {
605 ALOGV("Omit '%s', it's not '%s'", (*it)->getKey().c_str(), only);
606 continue;
607 }
Ray Essickf65f4212017-08-31 11:41:19 -0700608 AString entry = (*it)->toString(mDumpProto);
Ray Essick35ad27f2017-01-30 14:04:11 -0800609 result.appendFormat("%5d: %s\n", slot, entry.c_str());
Ray Essickb5fac8e2016-12-12 11:33:56 -0800610 slot++;
Ray Essick3938dc62016-11-01 08:56:56 -0700611 }
612 }
613
614 return result;
615}
616
617//
618// Our Cheap in-core, non-persistent records management.
619// XXX: rewrite this to manage persistence, etc.
620
621// insert appropriately into queue
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700622// caller should hold mLock
Ray Essickb5fac8e2016-12-12 11:33:56 -0800623void MediaAnalyticsService::saveItem(List<MediaAnalyticsItem *> *l, MediaAnalyticsItem * item, int front) {
Ray Essick3938dc62016-11-01 08:56:56 -0700624
Ray Essick3938dc62016-11-01 08:56:56 -0700625 if (front) {
Ray Essicke5db6db2017-11-10 15:54:32 -0800626 // for non-finalized stuff, since we expect to reference it again soon,
627 // make it quicker to find (nearer the front of our list)
Ray Essick3938dc62016-11-01 08:56:56 -0700628 l->push_front(item);
629 } else {
Ray Essicke5db6db2017-11-10 15:54:32 -0800630 // for finalized records, which we want to dump 'in sequence order'
Ray Essick3938dc62016-11-01 08:56:56 -0700631 l->push_back(item);
632 }
633
Ray Essicke5db6db2017-11-10 15:54:32 -0800634 // our reclaim process is for oldest-first queues
635 if (front) {
636 return;
637 }
638
639
Ray Essickf65f4212017-08-31 11:41:19 -0700640 // keep removing old records the front until we're in-bounds (count)
Ray Essick3938dc62016-11-01 08:56:56 -0700641 if (mMaxRecords > 0) {
642 while (l->size() > (size_t) mMaxRecords) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800643 MediaAnalyticsItem * oitem = *(l->begin());
Ray Essicke5db6db2017-11-10 15:54:32 -0800644 if (oitem == item) {
645 break;
646 }
Ray Essick3938dc62016-11-01 08:56:56 -0700647 l->erase(l->begin());
Ray Essickb5fac8e2016-12-12 11:33:56 -0800648 delete oitem;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800649 mItemsDiscarded++;
Ray Essickf65f4212017-08-31 11:41:19 -0700650 mItemsDiscardedCount++;
651 }
652 }
653
654 // keep removing old records the front until we're in-bounds (count)
655 if (mMaxRecordAgeNs > 0) {
656 nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
657 while (l->size() > 0) {
658 MediaAnalyticsItem * oitem = *(l->begin());
659 nsecs_t when = oitem->getTimestamp();
Ray Essicke5db6db2017-11-10 15:54:32 -0800660 if (oitem == item) {
661 break;
662 }
Ray Essickf65f4212017-08-31 11:41:19 -0700663 // careful about timejumps too
664 if ((now > when) && (now-when) <= mMaxRecordAgeNs) {
665 // this (and the rest) are recent enough to keep
666 break;
667 }
668 l->erase(l->begin());
669 delete oitem;
670 mItemsDiscarded++;
671 mItemsDiscardedExpire++;
Ray Essick3938dc62016-11-01 08:56:56 -0700672 }
673 }
Ray Essick3938dc62016-11-01 08:56:56 -0700674}
675
676// are they alike enough that nitem can be folded into oitem?
Ray Essickb5fac8e2016-12-12 11:33:56 -0800677static bool compatibleItems(MediaAnalyticsItem * oitem, MediaAnalyticsItem * nitem) {
Ray Essick3938dc62016-11-01 08:56:56 -0700678
Ray Essick3938dc62016-11-01 08:56:56 -0700679 // general safety
680 if (nitem->getUid() != oitem->getUid()) {
681 return false;
682 }
683 if (nitem->getPid() != oitem->getPid()) {
684 return false;
685 }
686
687 // key -- needs to match
688 if (nitem->getKey() == oitem->getKey()) {
689 // still in the game.
690 } else {
691 return false;
692 }
693
694 // session id -- empty field in new is allowed
695 MediaAnalyticsItem::SessionID_t osession = oitem->getSessionID();
696 MediaAnalyticsItem::SessionID_t nsession = nitem->getSessionID();
697 if (nsession != osession) {
698 // incoming '0' matches value in osession
699 if (nsession != 0) {
700 return false;
701 }
702 }
703
704 return true;
705}
706
707// find the incomplete record that this will overlay
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700708// caller should hold mLock
Ray Essickb5fac8e2016-12-12 11:33:56 -0800709MediaAnalyticsItem *MediaAnalyticsService::findItem(List<MediaAnalyticsItem*> *theList, MediaAnalyticsItem *nitem, bool removeit) {
Ray Essick3938dc62016-11-01 08:56:56 -0700710 if (nitem == NULL) {
711 return NULL;
712 }
713
Ray Essickb5fac8e2016-12-12 11:33:56 -0800714 MediaAnalyticsItem *item = NULL;
715
Ray Essickb5fac8e2016-12-12 11:33:56 -0800716 for (List<MediaAnalyticsItem *>::iterator it = theList->begin();
Ray Essick3938dc62016-11-01 08:56:56 -0700717 it != theList->end(); it++) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800718 MediaAnalyticsItem *tmp = (*it);
Ray Essick3938dc62016-11-01 08:56:56 -0700719
720 if (!compatibleItems(tmp, nitem)) {
721 continue;
722 }
723
724 // we match! this is the one I want.
725 if (removeit) {
726 theList->erase(it);
727 }
728 item = tmp;
729 break;
730 }
731 return item;
732}
733
734
735// delete the indicated record
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700736// caller should hold mLock
Ray Essickb5fac8e2016-12-12 11:33:56 -0800737void MediaAnalyticsService::deleteItem(List<MediaAnalyticsItem *> *l, MediaAnalyticsItem *item) {
Ray Essick3938dc62016-11-01 08:56:56 -0700738
Ray Essickb5fac8e2016-12-12 11:33:56 -0800739 for (List<MediaAnalyticsItem *>::iterator it = l->begin();
Ray Essick3938dc62016-11-01 08:56:56 -0700740 it != l->end(); it++) {
741 if ((*it)->getSessionID() != item->getSessionID())
742 continue;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800743 delete *it;
Ray Essick3938dc62016-11-01 08:56:56 -0700744 l->erase(it);
745 break;
746 }
Ray Essick3938dc62016-11-01 08:56:56 -0700747}
748
Ray Essickd38e1742017-01-23 15:17:06 -0800749static AString allowedKeys[] =
750{
751 "codec",
752 "extractor"
753};
Ray Essick3938dc62016-11-01 08:56:56 -0700754
Ray Essickd38e1742017-01-23 15:17:06 -0800755static const int nAllowedKeys = sizeof(allowedKeys) / sizeof(allowedKeys[0]);
756
757// are the contents good
758bool MediaAnalyticsService::contentValid(MediaAnalyticsItem *item, bool isTrusted) {
759
760 // untrusted uids can only send us a limited set of keys
761 if (isTrusted == false) {
762 // restrict to a specific set of keys
763 AString key = item->getKey();
764
765 size_t i;
766 for(i = 0; i < nAllowedKeys; i++) {
767 if (key == allowedKeys[i]) {
768 break;
769 }
770 }
771 if (i == nAllowedKeys) {
772 ALOGD("Ignoring (key): %s", item->toString().c_str());
773 return false;
774 }
775 }
776
Ray Essick3938dc62016-11-01 08:56:56 -0700777 // internal consistency
778
779 return true;
780}
781
782// are we rate limited, normally false
Ray Essickb5fac8e2016-12-12 11:33:56 -0800783bool MediaAnalyticsService::rateLimited(MediaAnalyticsItem *) {
Ray Essick3938dc62016-11-01 08:56:56 -0700784
785 return false;
786}
787
Ray Essick2e9c63b2017-03-29 15:16:44 -0700788// insert into the appropriate summarizer.
789// we make our own copy to save/summarize
790void MediaAnalyticsService::summarize(MediaAnalyticsItem *item) {
791
792 ALOGV("MediaAnalyticsService::summarize()");
793
794 if (item == NULL) {
795 return;
796 }
797
798 nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
799 if (mCurrentSet == NULL
800 || (mCurrentSet->getStarted() + mNewSetInterval < now)) {
801 newSummarizerSet();
802 }
803
804 if (mCurrentSet == NULL) {
805 return;
806 }
807
808 List<MetricsSummarizer *> *summarizers = mCurrentSet->getSummarizers();
809 List<MetricsSummarizer *>::iterator it = summarizers->begin();
810 for (; it != summarizers->end(); it++) {
811 if ((*it)->isMine(*item)) {
812 break;
813 }
814 }
815 if (it == summarizers->end()) {
816 ALOGD("no handler for type %s", item->getKey().c_str());
817 return; // no handler
818 }
819
820 // invoke the summarizer. summarizer will make whatever copies
821 // it wants; the caller retains ownership of item.
822
823 (*it)->handleRecord(item);
824
825}
Ray Essick3938dc62016-11-01 08:56:56 -0700826
Ray Essickfa149562017-09-19 09:27:31 -0700827// how long we hold package info before we re-fetch it
828#define PKG_EXPIRATION_NS (30*60*1000000000ll) // 30 minutes, in nsecs
Ray Essickf65f4212017-08-31 11:41:19 -0700829
830// give me the package name, perhaps going to find it
Ray Essickfa149562017-09-19 09:27:31 -0700831void MediaAnalyticsService::setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion) {
832 ALOGV("asking for packagename to go with uid=%d", uid);
833
834 if (!setName && !setVersion) {
835 // setting nothing? strange
836 return;
837 }
838
839 nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
840 struct UidToPkgMap mapping;
841 mapping.uid = (-1);
842
Ray Essickf65f4212017-08-31 11:41:19 -0700843 ssize_t i = mPkgMappings.indexOfKey(uid);
844 if (i >= 0) {
Ray Essickfa149562017-09-19 09:27:31 -0700845 mapping = mPkgMappings.valueAt(i);
846 ALOGV("Expiration? uid %d expiration %" PRId64 " now %" PRId64,
847 uid, mapping.expiration, now);
848 if (mapping.expiration < now) {
849 // purge our current entry and re-query
850 ALOGV("entry for uid %d expired, now= %" PRId64 "", uid, now);
851 mPkgMappings.removeItemsAt(i, 1);
852 // could cheat and use a goto back to the top of the routine.
853 // a good compiler should recognize the local tail recursion...
854 return setPkgInfo(item, uid, setName, setVersion);
Ray Essickf65f4212017-08-31 11:41:19 -0700855 }
Ray Essickfa149562017-09-19 09:27:31 -0700856 } else {
857 AString pkg;
858 std::string installer = "";
859 int32_t versionCode = 0;
Ray Essickf65f4212017-08-31 11:41:19 -0700860
Ray Essickfa149562017-09-19 09:27:31 -0700861 struct passwd *pw = getpwuid(uid);
862 if (pw) {
863 pkg = pw->pw_name;
864 }
Ray Essickf65f4212017-08-31 11:41:19 -0700865
Ray Essickfa149562017-09-19 09:27:31 -0700866 // find the proper value -- should we cache this binder??
Ray Essickf65f4212017-08-31 11:41:19 -0700867
Ray Essickfa149562017-09-19 09:27:31 -0700868 sp<IBinder> binder = NULL;
869 sp<IServiceManager> sm = defaultServiceManager();
870 if (sm == NULL) {
871 ALOGE("defaultServiceManager failed");
Ray Essickf65f4212017-08-31 11:41:19 -0700872 } else {
Ray Essickfa149562017-09-19 09:27:31 -0700873 binder = sm->getService(String16("package_native"));
874 if (binder == NULL) {
875 ALOGE("getService package_native failed");
876 }
877 }
878
879 if (binder != NULL) {
880 sp<IPackageManagerNative> package_mgr = interface_cast<IPackageManagerNative>(binder);
881 binder::Status status;
882
883 std::vector<int> uids;
884 std::vector<std::string> names;
885
886 uids.push_back(uid);
887
888 status = package_mgr->getNamesForUids(uids, &names);
889 if (!status.isOk()) {
890 ALOGE("package_native::getNamesForUids failed: %s",
891 status.exceptionMessage().c_str());
892 } else {
893 if (!names[0].empty()) {
894 pkg = names[0].c_str();
895 }
896 }
897
898 // strip any leading "shared:" strings that came back
899 if (pkg.startsWith("shared:")) {
900 pkg.erase(0, 7);
901 }
902
903 // determine how pkg was installed and the versionCode
904 //
905 if (pkg.empty()) {
906 // no name for us to manage
907 } else if (strchr(pkg.c_str(), '.') == NULL) {
908 // not of form 'com.whatever...'; assume internal and ok
909 } else if (strncmp(pkg.c_str(), "android.", 8) == 0) {
910 // android.* packages are assumed fine
911 } else {
912 String16 pkgName16(pkg.c_str());
913 status = package_mgr->getInstallerForPackage(pkgName16, &installer);
914 if (!status.isOk()) {
915 ALOGE("package_native::getInstallerForPackage failed: %s",
916 status.exceptionMessage().c_str());
917 }
918
919 // skip if we didn't get an installer
920 if (status.isOk()) {
921 status = package_mgr->getVersionCodeForPackage(pkgName16, &versionCode);
922 if (!status.isOk()) {
923 ALOGE("package_native::getVersionCodeForPackage failed: %s",
924 status.exceptionMessage().c_str());
925 }
926 }
927
928
929 ALOGV("package '%s' installed by '%s' versioncode %d / %08x",
930 pkg.c_str(), installer.c_str(), versionCode, versionCode);
931
932 if (strncmp(installer.c_str(), "com.android.", 12) == 0) {
933 // from play store, we keep info
934 } else if (strncmp(installer.c_str(), "com.google.", 11) == 0) {
935 // some google source, we keep info
936 } else if (strcmp(installer.c_str(), "preload") == 0) {
937 // preloads, we keep the info
938 } else if (installer.c_str()[0] == '\0') {
939 // sideload (no installer); do not report
940 pkg = "";
941 versionCode = 0;
942 } else {
943 // unknown installer; do not report
944 pkg = "";
945 versionCode = 0;
946 }
947 }
948 }
949
950 // add it to the map, to save a subsequent lookup
951 if (!pkg.empty()) {
952 Mutex::Autolock _l(mLock_mappings);
953 ALOGV("Adding uid %d pkg '%s'", uid, pkg.c_str());
954 ssize_t i = mPkgMappings.indexOfKey(uid);
955 if (i < 0) {
956 mapping.uid = uid;
957 mapping.pkg = pkg;
958 mapping.installer = installer.c_str();
959 mapping.versionCode = versionCode;
960 mapping.expiration = now + PKG_EXPIRATION_NS;
961 ALOGV("expiration for uid %d set to %" PRId64 "", uid, mapping.expiration);
962
963 mPkgMappings.add(uid, mapping);
Ray Essickf65f4212017-08-31 11:41:19 -0700964 }
965 }
966 }
967
Ray Essickfa149562017-09-19 09:27:31 -0700968 if (mapping.uid != (uid_t)(-1)) {
969 if (setName) {
970 item->setPkgName(mapping.pkg);
971 }
972 if (setVersion) {
973 item->setPkgVersionCode(mapping.versionCode);
Ray Essickf65f4212017-08-31 11:41:19 -0700974 }
975 }
Ray Essickf65f4212017-08-31 11:41:19 -0700976}
977
Ray Essick3938dc62016-11-01 08:56:56 -0700978} // namespace android