blob: a132e25fe9475d9cfc874904165927b6cff10d94 [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 Essick3938dc62016-11-01 08:56:56 -070077namespace android {
78
Ray Essickf65f4212017-08-31 11:41:19 -070079 using namespace android::base;
80 using namespace android::content::pm;
81
Ray Essickf65f4212017-08-31 11:41:19 -070082// individual records kept in memory: age or count
83// age: <= 36 hours (1.5 days)
84// count: hard limit of # records
85// (0 for either of these disables that threshold)
86static const nsecs_t kMaxRecordAgeNs = 36 * 3600 * (1000*1000*1000ll);
87static const int kMaxRecords = 0;
Ray Essick2e9c63b2017-03-29 15:16:44 -070088
89static const char *kServiceName = "media.metrics";
90
Ray Essick3938dc62016-11-01 08:56:56 -070091void MediaAnalyticsService::instantiate() {
92 defaultServiceManager()->addService(
Ray Essick2e9c63b2017-03-29 15:16:44 -070093 String16(kServiceName), new MediaAnalyticsService());
Ray Essick3938dc62016-11-01 08:56:56 -070094}
95
Ray Essick3938dc62016-11-01 08:56:56 -070096MediaAnalyticsService::MediaAnalyticsService()
Ray Essick2e9c63b2017-03-29 15:16:44 -070097 : mMaxRecords(kMaxRecords),
Ray Essickf65f4212017-08-31 11:41:19 -070098 mMaxRecordAgeNs(kMaxRecordAgeNs),
Ray Essick583a23a2017-11-27 12:49:57 -080099 mDumpProto(MediaAnalyticsItem::PROTO_V1),
100 mDumpProtoDefault(MediaAnalyticsItem::PROTO_V1) {
Ray Essick3938dc62016-11-01 08:56:56 -0700101
102 ALOGD("MediaAnalyticsService created");
103 // clear our queues
Ray Essickb5fac8e2016-12-12 11:33:56 -0800104 mOpen = new List<MediaAnalyticsItem *>();
105 mFinalized = new List<MediaAnalyticsItem *>();
Ray Essick3938dc62016-11-01 08:56:56 -0700106
107 mItemsSubmitted = 0;
108 mItemsFinalized = 0;
109 mItemsDiscarded = 0;
Ray Essickf65f4212017-08-31 11:41:19 -0700110 mItemsDiscardedExpire = 0;
111 mItemsDiscardedCount = 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700112
113 mLastSessionID = 0;
114 // recover any persistency we set up
115 // etc
116}
117
118MediaAnalyticsService::~MediaAnalyticsService() {
119 ALOGD("MediaAnalyticsService destroyed");
120
Ray Essick2e9c63b2017-03-29 15:16:44 -0700121 // clean out mOpen and mFinalized
Ray Essickf65f4212017-08-31 11:41:19 -0700122 while (mOpen->size() > 0) {
123 MediaAnalyticsItem * oitem = *(mOpen->begin());
124 mOpen->erase(mOpen->begin());
125 delete oitem;
126 mItemsDiscarded++;
127 mItemsDiscardedCount++;
128 }
Ray Essick2e9c63b2017-03-29 15:16:44 -0700129 delete mOpen;
130 mOpen = NULL;
Ray Essickf65f4212017-08-31 11:41:19 -0700131
132 while (mFinalized->size() > 0) {
133 MediaAnalyticsItem * oitem = *(mFinalized->begin());
134 mFinalized->erase(mFinalized->begin());
135 delete oitem;
136 mItemsDiscarded++;
137 mItemsDiscardedCount++;
138 }
Ray Essick2e9c63b2017-03-29 15:16:44 -0700139 delete mFinalized;
140 mFinalized = NULL;
Ray Essick3938dc62016-11-01 08:56:56 -0700141}
142
143
144MediaAnalyticsItem::SessionID_t MediaAnalyticsService::generateUniqueSessionID() {
145 // generate a new sessionid
146
147 Mutex::Autolock _l(mLock_ids);
148 return (++mLastSessionID);
149}
150
Ray Essickb5fac8e2016-12-12 11:33:56 -0800151// caller surrenders ownership of 'item'
152MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem *item, bool forcenew) {
Ray Essick3938dc62016-11-01 08:56:56 -0700153
154 MediaAnalyticsItem::SessionID_t id = MediaAnalyticsItem::SessionIDInvalid;
155
Ray Essickd38e1742017-01-23 15:17:06 -0800156 // we control these, generally not trusting user input
Ray Essick3938dc62016-11-01 08:56:56 -0700157 nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
Ray Essick721b7a02017-09-11 09:33:56 -0700158 // round nsecs to seconds
159 now = ((now + 500000000) / 1000000000) * 1000000000;
Ray Essick3938dc62016-11-01 08:56:56 -0700160 item->setTimestamp(now);
161 int pid = IPCThreadState::self()->getCallingPid();
Ray Essick3938dc62016-11-01 08:56:56 -0700162 int uid = IPCThreadState::self()->getCallingUid();
Ray Essickd38e1742017-01-23 15:17:06 -0800163
164 int uid_given = item->getUid();
165 int pid_given = item->getPid();
166
167 // although we do make exceptions for particular client uids
168 // that we know we trust.
169 //
170 bool isTrusted = false;
171
Ray Essickf65f4212017-08-31 11:41:19 -0700172 ALOGV("caller has uid=%d, embedded uid=%d", uid, uid_given);
173
Ray Essickd38e1742017-01-23 15:17:06 -0800174 switch (uid) {
175 case AID_MEDIA:
176 case AID_MEDIA_CODEC:
177 case AID_MEDIA_EX:
178 case AID_MEDIA_DRM:
179 // trusted source, only override default values
Ray Essickf65f4212017-08-31 11:41:19 -0700180 isTrusted = true;
Ray Essickd38e1742017-01-23 15:17:06 -0800181 if (uid_given == (-1)) {
182 item->setUid(uid);
183 }
184 if (pid_given == (-1)) {
185 item->setPid(pid);
186 }
187 break;
188 default:
189 isTrusted = false;
190 item->setPid(pid);
191 item->setUid(uid);
192 break;
193 }
194
Ray Essickfa149562017-09-19 09:27:31 -0700195
Adam Stone21c72122017-09-05 19:02:06 -0700196 // Overwrite package name and version if the caller was untrusted.
197 if (!isTrusted) {
Ray Essickfa149562017-09-19 09:27:31 -0700198 setPkgInfo(item, item->getUid(), true, true);
Adam Stone21c72122017-09-05 19:02:06 -0700199 } else if (item->getPkgName().empty()) {
Ray Essickfa149562017-09-19 09:27:31 -0700200 // empty, so fill out both parts
201 setPkgInfo(item, item->getUid(), true, true);
202 } else {
203 // trusted, provided a package, do nothing
Adam Stone21c72122017-09-05 19:02:06 -0700204 }
205
206 ALOGV("given uid %d; sanitized uid: %d sanitized pkg: %s "
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800207 "sanitized pkg version: %" PRId64,
Adam Stone21c72122017-09-05 19:02:06 -0700208 uid_given, item->getUid(),
209 item->getPkgName().c_str(),
210 item->getPkgVersionCode());
Ray Essick3938dc62016-11-01 08:56:56 -0700211
212 mItemsSubmitted++;
213
214 // validate the record; we discard if we don't like it
Ray Essickd38e1742017-01-23 15:17:06 -0800215 if (contentValid(item, isTrusted) == false) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800216 delete item;
Ray Essick3938dc62016-11-01 08:56:56 -0700217 return MediaAnalyticsItem::SessionIDInvalid;
218 }
219
220
221 // if we have a sesisonid in the new record, look to make
222 // sure it doesn't appear in the finalized list.
223 // XXX: this is for security / DOS prevention.
224 // may also require that we persist the unique sessionIDs
225 // across boots [instead of within a single boot]
226
227
228 // match this new record up against records in the open
229 // list...
230 // if there's a match, merge them together
231 // deal with moving the old / merged record into the finalized que
232
233 bool finalizing = item->getFinalized();
234
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700235 Mutex::Autolock _l(mLock);
236
Ray Essick3938dc62016-11-01 08:56:56 -0700237 // if finalizing, we'll remove it
Ray Essickb5fac8e2016-12-12 11:33:56 -0800238 MediaAnalyticsItem *oitem = findItem(mOpen, item, finalizing | forcenew);
Ray Essick3938dc62016-11-01 08:56:56 -0700239 if (oitem != NULL) {
240 if (forcenew) {
241 // old one gets finalized, then we insert the new one
242 // so we'll have 2 records at the end of this.
243 // but don't finalize an empty record
Ray Essickb5fac8e2016-12-12 11:33:56 -0800244 if (oitem->count() == 0) {
245 // we're responsible for disposing of the dead record
246 delete oitem;
247 oitem = NULL;
248 } else {
Ray Essick3938dc62016-11-01 08:56:56 -0700249 oitem->setFinalized(true);
250 saveItem(mFinalized, oitem, 0);
251 }
252 // new record could itself be marked finalized...
Ray Essicke5db6db2017-11-10 15:54:32 -0800253 id = item->getSessionID();
Ray Essick3938dc62016-11-01 08:56:56 -0700254 if (finalizing) {
255 saveItem(mFinalized, item, 0);
256 mItemsFinalized++;
257 } else {
258 saveItem(mOpen, item, 1);
259 }
Ray Essick3938dc62016-11-01 08:56:56 -0700260 } else {
261 // combine the records, send it to finalized if appropriate
262 oitem->merge(item);
Ray Essicke5db6db2017-11-10 15:54:32 -0800263 id = oitem->getSessionID();
Ray Essick3938dc62016-11-01 08:56:56 -0700264 if (finalizing) {
265 saveItem(mFinalized, oitem, 0);
266 mItemsFinalized++;
267 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800268
269 // we're responsible for disposing of the dead record
270 delete item;
271 item = NULL;
Ray Essick3938dc62016-11-01 08:56:56 -0700272 }
273 } else {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800274 // nothing to merge, save the new record
275 id = item->getSessionID();
276 if (finalizing) {
277 if (item->count() == 0) {
278 // drop empty records
279 delete item;
280 item = NULL;
Ray Essick3938dc62016-11-01 08:56:56 -0700281 } else {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800282 saveItem(mFinalized, item, 0);
283 mItemsFinalized++;
Ray Essick3938dc62016-11-01 08:56:56 -0700284 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800285 } else {
286 saveItem(mOpen, item, 1);
287 }
Ray Essick3938dc62016-11-01 08:56:56 -0700288 }
Ray Essick3938dc62016-11-01 08:56:56 -0700289 return id;
290}
291
Ray Essickf65f4212017-08-31 11:41:19 -0700292
Ray Essickb5fac8e2016-12-12 11:33:56 -0800293status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
Ray Essick3938dc62016-11-01 08:56:56 -0700294{
Ray Essickb5fac8e2016-12-12 11:33:56 -0800295 const size_t SIZE = 512;
Ray Essick3938dc62016-11-01 08:56:56 -0700296 char buffer[SIZE];
297 String8 result;
298
299 if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
300 snprintf(buffer, SIZE, "Permission Denial: "
301 "can't dump MediaAnalyticsService from pid=%d, uid=%d\n",
302 IPCThreadState::self()->getCallingPid(),
303 IPCThreadState::self()->getCallingUid());
304 result.append(buffer);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800305 write(fd, result.string(), result.size());
306 return NO_ERROR;
Ray Essick3938dc62016-11-01 08:56:56 -0700307 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800308
309 // crack any parameters
Ray Essickf65f4212017-08-31 11:41:19 -0700310 String16 protoOption("-proto");
Ray Essick583a23a2017-11-27 12:49:57 -0800311 int chosenProto = mDumpProtoDefault;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800312 String16 clearOption("-clear");
Ray Essickf65f4212017-08-31 11:41:19 -0700313 bool clear = false;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800314 String16 sinceOption("-since");
Ray Essickf65f4212017-08-31 11:41:19 -0700315 nsecs_t ts_since = 0;
Ray Essick35ad27f2017-01-30 14:04:11 -0800316 String16 helpOption("-help");
Ray Essick2e9c63b2017-03-29 15:16:44 -0700317 String16 onlyOption("-only");
Ray Essick783bd0d2018-01-11 11:10:35 -0800318 std::string only;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800319 int n = args.size();
Ray Essickf65f4212017-08-31 11:41:19 -0700320
Ray Essickb5fac8e2016-12-12 11:33:56 -0800321 for (int i = 0; i < n; i++) {
322 String8 myarg(args[i]);
323 if (args[i] == clearOption) {
324 clear = true;
Ray Essickf65f4212017-08-31 11:41:19 -0700325 } else if (args[i] == protoOption) {
326 i++;
327 if (i < n) {
328 String8 value(args[i]);
Ray Essick583a23a2017-11-27 12:49:57 -0800329 int proto = MediaAnalyticsItem::PROTO_V0;
Ray Essickf65f4212017-08-31 11:41:19 -0700330 char *endp;
331 const char *p = value.string();
332 proto = strtol(p, &endp, 10);
333 if (endp != p || *endp == '\0') {
334 if (proto < MediaAnalyticsItem::PROTO_FIRST) {
335 proto = MediaAnalyticsItem::PROTO_FIRST;
336 } else if (proto > MediaAnalyticsItem::PROTO_LAST) {
337 proto = MediaAnalyticsItem::PROTO_LAST;
338 }
Ray Essick583a23a2017-11-27 12:49:57 -0800339 chosenProto = proto;
340 } else {
341 result.append("unable to parse value for -proto\n\n");
Ray Essickf65f4212017-08-31 11:41:19 -0700342 }
Ray Essick583a23a2017-11-27 12:49:57 -0800343 } else {
344 result.append("missing value for -proto\n\n");
Ray Essickf65f4212017-08-31 11:41:19 -0700345 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800346 } else if (args[i] == sinceOption) {
347 i++;
348 if (i < n) {
349 String8 value(args[i]);
350 char *endp;
351 const char *p = value.string();
352 ts_since = strtoll(p, &endp, 10);
353 if (endp == p || *endp != '\0') {
354 ts_since = 0;
355 }
356 } else {
357 ts_since = 0;
358 }
Ray Essick35ad27f2017-01-30 14:04:11 -0800359 // command line is milliseconds; internal units are nano-seconds
360 ts_since *= 1000*1000;
Ray Essick2e9c63b2017-03-29 15:16:44 -0700361 } else if (args[i] == onlyOption) {
362 i++;
363 if (i < n) {
364 String8 value(args[i]);
Ray Essickf65f4212017-08-31 11:41:19 -0700365 only = value.string();
Ray Essick2e9c63b2017-03-29 15:16:44 -0700366 }
Ray Essick35ad27f2017-01-30 14:04:11 -0800367 } else if (args[i] == helpOption) {
368 result.append("Recognized parameters:\n");
369 result.append("-help this help message\n");
Ray Essick583a23a2017-11-27 12:49:57 -0800370 result.append("-proto # dump using protocol #");
Ray Essick35ad27f2017-01-30 14:04:11 -0800371 result.append("-clear clears out saved records\n");
Ray Essick2e9c63b2017-03-29 15:16:44 -0700372 result.append("-only X process records for component X\n");
373 result.append("-since X include records since X\n");
374 result.append(" (X is milliseconds since the UNIX epoch)\n");
Ray Essick35ad27f2017-01-30 14:04:11 -0800375 write(fd, result.string(), result.size());
376 return NO_ERROR;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800377 }
378 }
379
380 Mutex::Autolock _l(mLock);
381
Ray Essick583a23a2017-11-27 12:49:57 -0800382 mDumpProto = chosenProto;
383
Ray Essick2e9c63b2017-03-29 15:16:44 -0700384 // we ALWAYS dump this piece
385 snprintf(buffer, SIZE, "Dump of the %s process:\n", kServiceName);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800386 result.append(buffer);
387
Ray Essick2e9c63b2017-03-29 15:16:44 -0700388 dumpHeaders(result, ts_since);
389
Ray Essick813b1b82018-01-16 15:10:06 -0800390 dumpRecent(result, ts_since, only.c_str());
Ray Essick2e9c63b2017-03-29 15:16:44 -0700391
392
393 if (clear) {
394 // remove everything from the finalized queue
395 while (mFinalized->size() > 0) {
396 MediaAnalyticsItem * oitem = *(mFinalized->begin());
397 mFinalized->erase(mFinalized->begin());
398 delete oitem;
399 mItemsDiscarded++;
400 }
401
402 // shall we clear the summary data too?
403
404 }
405
406 write(fd, result.string(), result.size());
407 return NO_ERROR;
408}
409
410// dump headers
411void MediaAnalyticsService::dumpHeaders(String8 &result, nsecs_t ts_since) {
412 const size_t SIZE = 512;
413 char buffer[SIZE];
414
Ray Essickf65f4212017-08-31 11:41:19 -0700415 snprintf(buffer, SIZE, "Protocol Version: %d\n", mDumpProto);
416 result.append(buffer);
417
Ray Essickb5fac8e2016-12-12 11:33:56 -0800418 int enabled = MediaAnalyticsItem::isEnabled();
419 if (enabled) {
Ray Essickd38e1742017-01-23 15:17:06 -0800420 snprintf(buffer, SIZE, "Metrics gathering: enabled\n");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800421 } else {
Ray Essickd38e1742017-01-23 15:17:06 -0800422 snprintf(buffer, SIZE, "Metrics gathering: DISABLED via property\n");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800423 }
424 result.append(buffer);
425
426 snprintf(buffer, SIZE,
Ray Essickf65f4212017-08-31 11:41:19 -0700427 "Since Boot: Submissions: %8" PRId64
428 " Finalizations: %8" PRId64 "\n",
429 mItemsSubmitted, mItemsFinalized);
430 result.append(buffer);
431 snprintf(buffer, SIZE,
432 "Records Discarded: %8" PRId64
433 " (by Count: %" PRId64 " by Expiration: %" PRId64 ")\n",
434 mItemsDiscarded, mItemsDiscardedCount, mItemsDiscardedExpire);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800435 result.append(buffer);
Ray Essick2e9c63b2017-03-29 15:16:44 -0700436 snprintf(buffer, SIZE,
437 "Summary Sets Discarded: %" PRId64 "\n", mSetsDiscarded);
438 result.append(buffer);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800439 if (ts_since != 0) {
440 snprintf(buffer, SIZE,
441 "Dumping Queue entries more recent than: %" PRId64 "\n",
442 (int64_t) ts_since);
443 result.append(buffer);
444 }
Ray Essick2e9c63b2017-03-29 15:16:44 -0700445}
446
Ray Essick2e9c63b2017-03-29 15:16:44 -0700447// the recent, detailed queues
448void MediaAnalyticsService::dumpRecent(String8 &result, nsecs_t ts_since, const char * only) {
449 const size_t SIZE = 512;
450 char buffer[SIZE];
Ray Essickb5fac8e2016-12-12 11:33:56 -0800451
Ray Essickf65f4212017-08-31 11:41:19 -0700452 if (only != NULL && *only == '\0') {
453 only = NULL;
454 }
455
Ray Essickb5fac8e2016-12-12 11:33:56 -0800456 // show the recently recorded records
Ray Essickd38e1742017-01-23 15:17:06 -0800457 snprintf(buffer, sizeof(buffer), "\nFinalized Metrics (oldest first):\n");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800458 result.append(buffer);
Ray Essick2e9c63b2017-03-29 15:16:44 -0700459 result.append(this->dumpQueue(mFinalized, ts_since, only));
Ray Essickb5fac8e2016-12-12 11:33:56 -0800460
Ray Essickd38e1742017-01-23 15:17:06 -0800461 snprintf(buffer, sizeof(buffer), "\nIn-Progress Metrics (newest first):\n");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800462 result.append(buffer);
Ray Essick2e9c63b2017-03-29 15:16:44 -0700463 result.append(this->dumpQueue(mOpen, ts_since, only));
Ray Essickb5fac8e2016-12-12 11:33:56 -0800464
465 // show who is connected and injecting records?
466 // talk about # records fed to the 'readers'
467 // talk about # records we discarded, perhaps "discarded w/o reading" too
Ray Essick3938dc62016-11-01 08:56:56 -0700468}
Ray Essick3938dc62016-11-01 08:56:56 -0700469// caller has locked mLock...
Ray Essickb5fac8e2016-12-12 11:33:56 -0800470String8 MediaAnalyticsService::dumpQueue(List<MediaAnalyticsItem *> *theList) {
Ray Essick2e9c63b2017-03-29 15:16:44 -0700471 return dumpQueue(theList, (nsecs_t) 0, NULL);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800472}
473
Ray Essick2e9c63b2017-03-29 15:16:44 -0700474String8 MediaAnalyticsService::dumpQueue(List<MediaAnalyticsItem *> *theList, nsecs_t ts_since, const char * only) {
Ray Essick3938dc62016-11-01 08:56:56 -0700475 String8 result;
476 int slot = 0;
477
478 if (theList->empty()) {
479 result.append("empty\n");
480 } else {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800481 List<MediaAnalyticsItem *>::iterator it = theList->begin();
482 for (; it != theList->end(); it++) {
483 nsecs_t when = (*it)->getTimestamp();
484 if (when < ts_since) {
485 continue;
486 }
Ray Essick2e9c63b2017-03-29 15:16:44 -0700487 if (only != NULL &&
488 strcmp(only, (*it)->getKey().c_str()) != 0) {
489 ALOGV("Omit '%s', it's not '%s'", (*it)->getKey().c_str(), only);
490 continue;
491 }
Ray Essick783bd0d2018-01-11 11:10:35 -0800492 std::string entry = (*it)->toString(mDumpProto);
Ray Essick35ad27f2017-01-30 14:04:11 -0800493 result.appendFormat("%5d: %s\n", slot, entry.c_str());
Ray Essickb5fac8e2016-12-12 11:33:56 -0800494 slot++;
Ray Essick3938dc62016-11-01 08:56:56 -0700495 }
496 }
497
498 return result;
499}
500
501//
502// Our Cheap in-core, non-persistent records management.
503// XXX: rewrite this to manage persistence, etc.
504
505// insert appropriately into queue
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700506// caller should hold mLock
Ray Essickb5fac8e2016-12-12 11:33:56 -0800507void MediaAnalyticsService::saveItem(List<MediaAnalyticsItem *> *l, MediaAnalyticsItem * item, int front) {
Ray Essick3938dc62016-11-01 08:56:56 -0700508
Ray Essick3938dc62016-11-01 08:56:56 -0700509 if (front) {
Ray Essicke5db6db2017-11-10 15:54:32 -0800510 // for non-finalized stuff, since we expect to reference it again soon,
511 // make it quicker to find (nearer the front of our list)
Ray Essick3938dc62016-11-01 08:56:56 -0700512 l->push_front(item);
513 } else {
Ray Essicke5db6db2017-11-10 15:54:32 -0800514 // for finalized records, which we want to dump 'in sequence order'
Ray Essick3938dc62016-11-01 08:56:56 -0700515 l->push_back(item);
516 }
517
Ray Essicke5db6db2017-11-10 15:54:32 -0800518 // our reclaim process is for oldest-first queues
519 if (front) {
520 return;
521 }
522
523
Ray Essickf65f4212017-08-31 11:41:19 -0700524 // keep removing old records the front until we're in-bounds (count)
Ray Essick3938dc62016-11-01 08:56:56 -0700525 if (mMaxRecords > 0) {
526 while (l->size() > (size_t) mMaxRecords) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800527 MediaAnalyticsItem * oitem = *(l->begin());
Ray Essicke5db6db2017-11-10 15:54:32 -0800528 if (oitem == item) {
529 break;
530 }
Ray Essick3938dc62016-11-01 08:56:56 -0700531 l->erase(l->begin());
Ray Essickb5fac8e2016-12-12 11:33:56 -0800532 delete oitem;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800533 mItemsDiscarded++;
Ray Essickf65f4212017-08-31 11:41:19 -0700534 mItemsDiscardedCount++;
535 }
536 }
537
538 // keep removing old records the front until we're in-bounds (count)
539 if (mMaxRecordAgeNs > 0) {
540 nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
541 while (l->size() > 0) {
542 MediaAnalyticsItem * oitem = *(l->begin());
543 nsecs_t when = oitem->getTimestamp();
Ray Essicke5db6db2017-11-10 15:54:32 -0800544 if (oitem == item) {
545 break;
546 }
Ray Essickf65f4212017-08-31 11:41:19 -0700547 // careful about timejumps too
548 if ((now > when) && (now-when) <= mMaxRecordAgeNs) {
549 // this (and the rest) are recent enough to keep
550 break;
551 }
552 l->erase(l->begin());
553 delete oitem;
554 mItemsDiscarded++;
555 mItemsDiscardedExpire++;
Ray Essick3938dc62016-11-01 08:56:56 -0700556 }
557 }
Ray Essick3938dc62016-11-01 08:56:56 -0700558}
559
560// are they alike enough that nitem can be folded into oitem?
Ray Essickb5fac8e2016-12-12 11:33:56 -0800561static bool compatibleItems(MediaAnalyticsItem * oitem, MediaAnalyticsItem * nitem) {
Ray Essick3938dc62016-11-01 08:56:56 -0700562
Ray Essick3938dc62016-11-01 08:56:56 -0700563 // general safety
564 if (nitem->getUid() != oitem->getUid()) {
565 return false;
566 }
567 if (nitem->getPid() != oitem->getPid()) {
568 return false;
569 }
570
571 // key -- needs to match
572 if (nitem->getKey() == oitem->getKey()) {
573 // still in the game.
574 } else {
575 return false;
576 }
577
578 // session id -- empty field in new is allowed
579 MediaAnalyticsItem::SessionID_t osession = oitem->getSessionID();
580 MediaAnalyticsItem::SessionID_t nsession = nitem->getSessionID();
581 if (nsession != osession) {
582 // incoming '0' matches value in osession
583 if (nsession != 0) {
584 return false;
585 }
586 }
587
588 return true;
589}
590
591// find the incomplete record that this will overlay
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700592// caller should hold mLock
Ray Essickb5fac8e2016-12-12 11:33:56 -0800593MediaAnalyticsItem *MediaAnalyticsService::findItem(List<MediaAnalyticsItem*> *theList, MediaAnalyticsItem *nitem, bool removeit) {
Ray Essick3938dc62016-11-01 08:56:56 -0700594 if (nitem == NULL) {
595 return NULL;
596 }
597
Ray Essickb5fac8e2016-12-12 11:33:56 -0800598 MediaAnalyticsItem *item = NULL;
599
Ray Essickb5fac8e2016-12-12 11:33:56 -0800600 for (List<MediaAnalyticsItem *>::iterator it = theList->begin();
Ray Essick3938dc62016-11-01 08:56:56 -0700601 it != theList->end(); it++) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800602 MediaAnalyticsItem *tmp = (*it);
Ray Essick3938dc62016-11-01 08:56:56 -0700603
604 if (!compatibleItems(tmp, nitem)) {
605 continue;
606 }
607
608 // we match! this is the one I want.
609 if (removeit) {
610 theList->erase(it);
611 }
612 item = tmp;
613 break;
614 }
615 return item;
616}
617
618
619// delete the indicated record
Ray Essick9bb7e3b2017-10-23 13:01:48 -0700620// caller should hold mLock
Ray Essickb5fac8e2016-12-12 11:33:56 -0800621void MediaAnalyticsService::deleteItem(List<MediaAnalyticsItem *> *l, MediaAnalyticsItem *item) {
Ray Essick3938dc62016-11-01 08:56:56 -0700622
Ray Essickb5fac8e2016-12-12 11:33:56 -0800623 for (List<MediaAnalyticsItem *>::iterator it = l->begin();
Ray Essick3938dc62016-11-01 08:56:56 -0700624 it != l->end(); it++) {
625 if ((*it)->getSessionID() != item->getSessionID())
626 continue;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800627 delete *it;
Ray Essick3938dc62016-11-01 08:56:56 -0700628 l->erase(it);
629 break;
630 }
Ray Essick3938dc62016-11-01 08:56:56 -0700631}
632
Ray Essick783bd0d2018-01-11 11:10:35 -0800633static std::string allowedKeys[] =
Ray Essickd38e1742017-01-23 15:17:06 -0800634{
Ray Essick8c22cb12018-01-24 11:00:36 -0800635 "audiorecord",
636 "audiotrack",
Ray Essickd38e1742017-01-23 15:17:06 -0800637 "codec",
Ray Essick8c22cb12018-01-24 11:00:36 -0800638 "extractor",
639 "nuplayer",
Ray Essickd38e1742017-01-23 15:17:06 -0800640};
Ray Essick3938dc62016-11-01 08:56:56 -0700641
Ray Essickd38e1742017-01-23 15:17:06 -0800642static const int nAllowedKeys = sizeof(allowedKeys) / sizeof(allowedKeys[0]);
643
644// are the contents good
645bool MediaAnalyticsService::contentValid(MediaAnalyticsItem *item, bool isTrusted) {
646
647 // untrusted uids can only send us a limited set of keys
648 if (isTrusted == false) {
649 // restrict to a specific set of keys
Ray Essick783bd0d2018-01-11 11:10:35 -0800650 std::string key = item->getKey();
Ray Essickd38e1742017-01-23 15:17:06 -0800651
652 size_t i;
653 for(i = 0; i < nAllowedKeys; i++) {
654 if (key == allowedKeys[i]) {
655 break;
656 }
657 }
658 if (i == nAllowedKeys) {
659 ALOGD("Ignoring (key): %s", item->toString().c_str());
660 return false;
661 }
662 }
663
Ray Essick3938dc62016-11-01 08:56:56 -0700664 // internal consistency
665
666 return true;
667}
668
669// are we rate limited, normally false
Ray Essickb5fac8e2016-12-12 11:33:56 -0800670bool MediaAnalyticsService::rateLimited(MediaAnalyticsItem *) {
Ray Essick3938dc62016-11-01 08:56:56 -0700671
672 return false;
673}
674
Ray Essickfa149562017-09-19 09:27:31 -0700675// how long we hold package info before we re-fetch it
676#define PKG_EXPIRATION_NS (30*60*1000000000ll) // 30 minutes, in nsecs
Ray Essickf65f4212017-08-31 11:41:19 -0700677
678// give me the package name, perhaps going to find it
Ray Essickfa149562017-09-19 09:27:31 -0700679void MediaAnalyticsService::setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion) {
680 ALOGV("asking for packagename to go with uid=%d", uid);
681
682 if (!setName && !setVersion) {
683 // setting nothing? strange
684 return;
685 }
686
687 nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
688 struct UidToPkgMap mapping;
689 mapping.uid = (-1);
690
Ray Essickf65f4212017-08-31 11:41:19 -0700691 ssize_t i = mPkgMappings.indexOfKey(uid);
692 if (i >= 0) {
Ray Essickfa149562017-09-19 09:27:31 -0700693 mapping = mPkgMappings.valueAt(i);
694 ALOGV("Expiration? uid %d expiration %" PRId64 " now %" PRId64,
695 uid, mapping.expiration, now);
696 if (mapping.expiration < now) {
697 // purge our current entry and re-query
698 ALOGV("entry for uid %d expired, now= %" PRId64 "", uid, now);
699 mPkgMappings.removeItemsAt(i, 1);
700 // could cheat and use a goto back to the top of the routine.
701 // a good compiler should recognize the local tail recursion...
702 return setPkgInfo(item, uid, setName, setVersion);
Ray Essickf65f4212017-08-31 11:41:19 -0700703 }
Ray Essickfa149562017-09-19 09:27:31 -0700704 } else {
Ray Essick783bd0d2018-01-11 11:10:35 -0800705 std::string pkg;
Ray Essickfa149562017-09-19 09:27:31 -0700706 std::string installer = "";
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800707 int64_t versionCode = 0;
Ray Essickf65f4212017-08-31 11:41:19 -0700708
Ray Essickfa149562017-09-19 09:27:31 -0700709 struct passwd *pw = getpwuid(uid);
710 if (pw) {
711 pkg = pw->pw_name;
712 }
Ray Essickf65f4212017-08-31 11:41:19 -0700713
Ray Essickfa149562017-09-19 09:27:31 -0700714 // find the proper value -- should we cache this binder??
Ray Essickf65f4212017-08-31 11:41:19 -0700715
Ray Essickfa149562017-09-19 09:27:31 -0700716 sp<IBinder> binder = NULL;
717 sp<IServiceManager> sm = defaultServiceManager();
718 if (sm == NULL) {
719 ALOGE("defaultServiceManager failed");
Ray Essickf65f4212017-08-31 11:41:19 -0700720 } else {
Ray Essickfa149562017-09-19 09:27:31 -0700721 binder = sm->getService(String16("package_native"));
722 if (binder == NULL) {
723 ALOGE("getService package_native failed");
724 }
725 }
726
727 if (binder != NULL) {
728 sp<IPackageManagerNative> package_mgr = interface_cast<IPackageManagerNative>(binder);
729 binder::Status status;
730
731 std::vector<int> uids;
732 std::vector<std::string> names;
733
734 uids.push_back(uid);
735
736 status = package_mgr->getNamesForUids(uids, &names);
737 if (!status.isOk()) {
738 ALOGE("package_native::getNamesForUids failed: %s",
739 status.exceptionMessage().c_str());
740 } else {
741 if (!names[0].empty()) {
742 pkg = names[0].c_str();
743 }
744 }
745
746 // strip any leading "shared:" strings that came back
Ray Essick783bd0d2018-01-11 11:10:35 -0800747 if (pkg.compare(0, 7, "shared:") == 0) {
Ray Essickfa149562017-09-19 09:27:31 -0700748 pkg.erase(0, 7);
749 }
750
751 // determine how pkg was installed and the versionCode
752 //
753 if (pkg.empty()) {
754 // no name for us to manage
755 } else if (strchr(pkg.c_str(), '.') == NULL) {
756 // not of form 'com.whatever...'; assume internal and ok
757 } else if (strncmp(pkg.c_str(), "android.", 8) == 0) {
758 // android.* packages are assumed fine
759 } else {
760 String16 pkgName16(pkg.c_str());
761 status = package_mgr->getInstallerForPackage(pkgName16, &installer);
762 if (!status.isOk()) {
763 ALOGE("package_native::getInstallerForPackage failed: %s",
764 status.exceptionMessage().c_str());
765 }
766
767 // skip if we didn't get an installer
768 if (status.isOk()) {
769 status = package_mgr->getVersionCodeForPackage(pkgName16, &versionCode);
770 if (!status.isOk()) {
771 ALOGE("package_native::getVersionCodeForPackage failed: %s",
772 status.exceptionMessage().c_str());
773 }
774 }
775
776
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800777 ALOGV("package '%s' installed by '%s' versioncode %" PRId64 " / %" PRIx64,
Ray Essickfa149562017-09-19 09:27:31 -0700778 pkg.c_str(), installer.c_str(), versionCode, versionCode);
779
780 if (strncmp(installer.c_str(), "com.android.", 12) == 0) {
781 // from play store, we keep info
782 } else if (strncmp(installer.c_str(), "com.google.", 11) == 0) {
783 // some google source, we keep info
784 } else if (strcmp(installer.c_str(), "preload") == 0) {
785 // preloads, we keep the info
786 } else if (installer.c_str()[0] == '\0') {
787 // sideload (no installer); do not report
788 pkg = "";
789 versionCode = 0;
790 } else {
791 // unknown installer; do not report
792 pkg = "";
793 versionCode = 0;
794 }
795 }
796 }
797
798 // add it to the map, to save a subsequent lookup
799 if (!pkg.empty()) {
800 Mutex::Autolock _l(mLock_mappings);
801 ALOGV("Adding uid %d pkg '%s'", uid, pkg.c_str());
802 ssize_t i = mPkgMappings.indexOfKey(uid);
803 if (i < 0) {
804 mapping.uid = uid;
805 mapping.pkg = pkg;
806 mapping.installer = installer.c_str();
807 mapping.versionCode = versionCode;
808 mapping.expiration = now + PKG_EXPIRATION_NS;
809 ALOGV("expiration for uid %d set to %" PRId64 "", uid, mapping.expiration);
810
811 mPkgMappings.add(uid, mapping);
Ray Essickf65f4212017-08-31 11:41:19 -0700812 }
813 }
814 }
815
Ray Essickfa149562017-09-19 09:27:31 -0700816 if (mapping.uid != (uid_t)(-1)) {
817 if (setName) {
818 item->setPkgName(mapping.pkg);
819 }
820 if (setVersion) {
821 item->setPkgVersionCode(mapping.versionCode);
Ray Essickf65f4212017-08-31 11:41:19 -0700822 }
823 }
Ray Essickf65f4212017-08-31 11:41:19 -0700824}
825
Ray Essick3938dc62016-11-01 08:56:56 -0700826} // namespace android