blob: 45da56a84e9e4353b48af783b428a6d6b472609e [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");
Ray Essick3938dc62016-11-01 08:56:56 -0700103
104 mItemsSubmitted = 0;
105 mItemsFinalized = 0;
106 mItemsDiscarded = 0;
Ray Essickf65f4212017-08-31 11:41:19 -0700107 mItemsDiscardedExpire = 0;
108 mItemsDiscardedCount = 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700109
110 mLastSessionID = 0;
111 // recover any persistency we set up
112 // etc
113}
114
115MediaAnalyticsService::~MediaAnalyticsService() {
116 ALOGD("MediaAnalyticsService destroyed");
117
Ray Essick92d23b42018-01-29 12:10:30 -0800118 while (mItems.size() > 0) {
119 MediaAnalyticsItem * oitem = *(mItems.begin());
120 mItems.erase(mItems.begin());
Ray Essickf65f4212017-08-31 11:41:19 -0700121 delete oitem;
122 mItemsDiscarded++;
123 mItemsDiscardedCount++;
124 }
Ray Essick3938dc62016-11-01 08:56:56 -0700125}
126
127
128MediaAnalyticsItem::SessionID_t MediaAnalyticsService::generateUniqueSessionID() {
129 // generate a new sessionid
130
131 Mutex::Autolock _l(mLock_ids);
132 return (++mLastSessionID);
133}
134
Ray Essickb5fac8e2016-12-12 11:33:56 -0800135// caller surrenders ownership of 'item'
Ray Essick92d23b42018-01-29 12:10:30 -0800136MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem *item, bool forcenew)
137{
138 UNUSED(forcenew);
Ray Essick3938dc62016-11-01 08:56:56 -0700139
Ray Essick92d23b42018-01-29 12:10:30 -0800140 // fill in a sessionID if we do not yet have one
141 if (item->getSessionID() <= MediaAnalyticsItem::SessionIDNone) {
142 item->setSessionID(generateUniqueSessionID());
143 }
Ray Essick3938dc62016-11-01 08:56:56 -0700144
Ray Essickd38e1742017-01-23 15:17:06 -0800145 // we control these, generally not trusting user input
Ray Essick3938dc62016-11-01 08:56:56 -0700146 nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
Ray Essick721b7a02017-09-11 09:33:56 -0700147 // round nsecs to seconds
148 now = ((now + 500000000) / 1000000000) * 1000000000;
Ray Essick3938dc62016-11-01 08:56:56 -0700149 item->setTimestamp(now);
150 int pid = IPCThreadState::self()->getCallingPid();
Ray Essick3938dc62016-11-01 08:56:56 -0700151 int uid = IPCThreadState::self()->getCallingUid();
Ray Essickd38e1742017-01-23 15:17:06 -0800152
153 int uid_given = item->getUid();
154 int pid_given = item->getPid();
155
Ray Essick92d23b42018-01-29 12:10:30 -0800156 // although we do make exceptions for some trusted client uids
Ray Essickd38e1742017-01-23 15:17:06 -0800157 bool isTrusted = false;
158
Ray Essickf65f4212017-08-31 11:41:19 -0700159 ALOGV("caller has uid=%d, embedded uid=%d", uid, uid_given);
160
Ray Essickd38e1742017-01-23 15:17:06 -0800161 switch (uid) {
162 case AID_MEDIA:
163 case AID_MEDIA_CODEC:
164 case AID_MEDIA_EX:
165 case AID_MEDIA_DRM:
166 // trusted source, only override default values
Ray Essickf65f4212017-08-31 11:41:19 -0700167 isTrusted = true;
Ray Essickd38e1742017-01-23 15:17:06 -0800168 if (uid_given == (-1)) {
169 item->setUid(uid);
170 }
171 if (pid_given == (-1)) {
172 item->setPid(pid);
173 }
174 break;
175 default:
176 isTrusted = false;
177 item->setPid(pid);
178 item->setUid(uid);
179 break;
180 }
181
Adam Stone21c72122017-09-05 19:02:06 -0700182 // Overwrite package name and version if the caller was untrusted.
183 if (!isTrusted) {
Ray Essickfa149562017-09-19 09:27:31 -0700184 setPkgInfo(item, item->getUid(), true, true);
Adam Stone21c72122017-09-05 19:02:06 -0700185 } else if (item->getPkgName().empty()) {
Ray Essickfa149562017-09-19 09:27:31 -0700186 // empty, so fill out both parts
187 setPkgInfo(item, item->getUid(), true, true);
188 } else {
189 // trusted, provided a package, do nothing
Adam Stone21c72122017-09-05 19:02:06 -0700190 }
191
192 ALOGV("given uid %d; sanitized uid: %d sanitized pkg: %s "
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800193 "sanitized pkg version: %" PRId64,
Adam Stone21c72122017-09-05 19:02:06 -0700194 uid_given, item->getUid(),
195 item->getPkgName().c_str(),
196 item->getPkgVersionCode());
Ray Essick3938dc62016-11-01 08:56:56 -0700197
198 mItemsSubmitted++;
199
200 // validate the record; we discard if we don't like it
Ray Essickd38e1742017-01-23 15:17:06 -0800201 if (contentValid(item, isTrusted) == false) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800202 delete item;
Ray Essick3938dc62016-11-01 08:56:56 -0700203 return MediaAnalyticsItem::SessionIDInvalid;
204 }
205
Ray Essick92d23b42018-01-29 12:10:30 -0800206 // XXX: if we have a sessionid in the new record, look to make
Ray Essick3938dc62016-11-01 08:56:56 -0700207 // sure it doesn't appear in the finalized list.
208 // XXX: this is for security / DOS prevention.
209 // may also require that we persist the unique sessionIDs
210 // across boots [instead of within a single boot]
211
Ray Essick92d23b42018-01-29 12:10:30 -0800212 if (item->count() == 0) {
213 // drop empty records
214 delete item;
215 item = NULL;
216 return MediaAnalyticsItem::SessionIDInvalid;
Ray Essick3938dc62016-11-01 08:56:56 -0700217 }
Ray Essick92d23b42018-01-29 12:10:30 -0800218
219 // save the new record
220 MediaAnalyticsItem::SessionID_t id = item->getSessionID();
221 saveItem(item);
222 mItemsFinalized++;
Ray Essick3938dc62016-11-01 08:56:56 -0700223 return id;
224}
225
Ray Essickf65f4212017-08-31 11:41:19 -0700226
Ray Essickb5fac8e2016-12-12 11:33:56 -0800227status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
Ray Essick3938dc62016-11-01 08:56:56 -0700228{
Ray Essickb5fac8e2016-12-12 11:33:56 -0800229 const size_t SIZE = 512;
Ray Essick3938dc62016-11-01 08:56:56 -0700230 char buffer[SIZE];
231 String8 result;
232
233 if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
234 snprintf(buffer, SIZE, "Permission Denial: "
235 "can't dump MediaAnalyticsService from pid=%d, uid=%d\n",
236 IPCThreadState::self()->getCallingPid(),
237 IPCThreadState::self()->getCallingUid());
238 result.append(buffer);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800239 write(fd, result.string(), result.size());
240 return NO_ERROR;
Ray Essick3938dc62016-11-01 08:56:56 -0700241 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800242
243 // crack any parameters
Ray Essickf65f4212017-08-31 11:41:19 -0700244 String16 protoOption("-proto");
Ray Essick583a23a2017-11-27 12:49:57 -0800245 int chosenProto = mDumpProtoDefault;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800246 String16 clearOption("-clear");
Ray Essickf65f4212017-08-31 11:41:19 -0700247 bool clear = false;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800248 String16 sinceOption("-since");
Ray Essickf65f4212017-08-31 11:41:19 -0700249 nsecs_t ts_since = 0;
Ray Essick35ad27f2017-01-30 14:04:11 -0800250 String16 helpOption("-help");
Ray Essick2e9c63b2017-03-29 15:16:44 -0700251 String16 onlyOption("-only");
Ray Essick783bd0d2018-01-11 11:10:35 -0800252 std::string only;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800253 int n = args.size();
Ray Essickf65f4212017-08-31 11:41:19 -0700254
Ray Essickb5fac8e2016-12-12 11:33:56 -0800255 for (int i = 0; i < n; i++) {
256 String8 myarg(args[i]);
257 if (args[i] == clearOption) {
258 clear = true;
Ray Essickf65f4212017-08-31 11:41:19 -0700259 } else if (args[i] == protoOption) {
260 i++;
261 if (i < n) {
262 String8 value(args[i]);
Ray Essick583a23a2017-11-27 12:49:57 -0800263 int proto = MediaAnalyticsItem::PROTO_V0;
Ray Essickf65f4212017-08-31 11:41:19 -0700264 char *endp;
265 const char *p = value.string();
266 proto = strtol(p, &endp, 10);
267 if (endp != p || *endp == '\0') {
268 if (proto < MediaAnalyticsItem::PROTO_FIRST) {
269 proto = MediaAnalyticsItem::PROTO_FIRST;
270 } else if (proto > MediaAnalyticsItem::PROTO_LAST) {
271 proto = MediaAnalyticsItem::PROTO_LAST;
272 }
Ray Essick583a23a2017-11-27 12:49:57 -0800273 chosenProto = proto;
274 } else {
275 result.append("unable to parse value for -proto\n\n");
Ray Essickf65f4212017-08-31 11:41:19 -0700276 }
Ray Essick583a23a2017-11-27 12:49:57 -0800277 } else {
278 result.append("missing value for -proto\n\n");
Ray Essickf65f4212017-08-31 11:41:19 -0700279 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800280 } else if (args[i] == sinceOption) {
281 i++;
282 if (i < n) {
283 String8 value(args[i]);
284 char *endp;
285 const char *p = value.string();
286 ts_since = strtoll(p, &endp, 10);
287 if (endp == p || *endp != '\0') {
288 ts_since = 0;
289 }
290 } else {
291 ts_since = 0;
292 }
Ray Essick35ad27f2017-01-30 14:04:11 -0800293 // command line is milliseconds; internal units are nano-seconds
294 ts_since *= 1000*1000;
Ray Essick2e9c63b2017-03-29 15:16:44 -0700295 } else if (args[i] == onlyOption) {
296 i++;
297 if (i < n) {
298 String8 value(args[i]);
Ray Essickf65f4212017-08-31 11:41:19 -0700299 only = value.string();
Ray Essick2e9c63b2017-03-29 15:16:44 -0700300 }
Ray Essick35ad27f2017-01-30 14:04:11 -0800301 } else if (args[i] == helpOption) {
302 result.append("Recognized parameters:\n");
303 result.append("-help this help message\n");
Ray Essick583a23a2017-11-27 12:49:57 -0800304 result.append("-proto # dump using protocol #");
Ray Essick35ad27f2017-01-30 14:04:11 -0800305 result.append("-clear clears out saved records\n");
Ray Essick2e9c63b2017-03-29 15:16:44 -0700306 result.append("-only X process records for component X\n");
307 result.append("-since X include records since X\n");
308 result.append(" (X is milliseconds since the UNIX epoch)\n");
Ray Essick35ad27f2017-01-30 14:04:11 -0800309 write(fd, result.string(), result.size());
310 return NO_ERROR;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800311 }
312 }
313
314 Mutex::Autolock _l(mLock);
Ray Essick92d23b42018-01-29 12:10:30 -0800315 // mutex between insertion and dumping the contents
Ray Essickb5fac8e2016-12-12 11:33:56 -0800316
Ray Essick583a23a2017-11-27 12:49:57 -0800317 mDumpProto = chosenProto;
318
Ray Essick2e9c63b2017-03-29 15:16:44 -0700319 // we ALWAYS dump this piece
320 snprintf(buffer, SIZE, "Dump of the %s process:\n", kServiceName);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800321 result.append(buffer);
322
Ray Essick2e9c63b2017-03-29 15:16:44 -0700323 dumpHeaders(result, ts_since);
324
Ray Essick813b1b82018-01-16 15:10:06 -0800325 dumpRecent(result, ts_since, only.c_str());
Ray Essick2e9c63b2017-03-29 15:16:44 -0700326
327
328 if (clear) {
329 // remove everything from the finalized queue
Ray Essick92d23b42018-01-29 12:10:30 -0800330 while (mItems.size() > 0) {
331 MediaAnalyticsItem * oitem = *(mItems.begin());
332 mItems.erase(mItems.begin());
Ray Essick2e9c63b2017-03-29 15:16:44 -0700333 delete oitem;
334 mItemsDiscarded++;
335 }
336
337 // shall we clear the summary data too?
338
339 }
340
341 write(fd, result.string(), result.size());
342 return NO_ERROR;
343}
344
345// dump headers
Ray Essick92d23b42018-01-29 12:10:30 -0800346void MediaAnalyticsService::dumpHeaders(String8 &result, nsecs_t ts_since)
347{
Ray Essick2e9c63b2017-03-29 15:16:44 -0700348 const size_t SIZE = 512;
349 char buffer[SIZE];
350
Ray Essickf65f4212017-08-31 11:41:19 -0700351 snprintf(buffer, SIZE, "Protocol Version: %d\n", mDumpProto);
352 result.append(buffer);
353
Ray Essickb5fac8e2016-12-12 11:33:56 -0800354 int enabled = MediaAnalyticsItem::isEnabled();
355 if (enabled) {
Ray Essickd38e1742017-01-23 15:17:06 -0800356 snprintf(buffer, SIZE, "Metrics gathering: enabled\n");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800357 } else {
Ray Essickd38e1742017-01-23 15:17:06 -0800358 snprintf(buffer, SIZE, "Metrics gathering: DISABLED via property\n");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800359 }
360 result.append(buffer);
361
362 snprintf(buffer, SIZE,
Ray Essickf65f4212017-08-31 11:41:19 -0700363 "Since Boot: Submissions: %8" PRId64
Ray Essick92d23b42018-01-29 12:10:30 -0800364 " Accepted: %8" PRId64 "\n",
Ray Essickf65f4212017-08-31 11:41:19 -0700365 mItemsSubmitted, mItemsFinalized);
366 result.append(buffer);
367 snprintf(buffer, SIZE,
368 "Records Discarded: %8" PRId64
369 " (by Count: %" PRId64 " by Expiration: %" PRId64 ")\n",
370 mItemsDiscarded, mItemsDiscardedCount, mItemsDiscardedExpire);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800371 result.append(buffer);
372 if (ts_since != 0) {
373 snprintf(buffer, SIZE,
Ray Essick92d23b42018-01-29 12:10:30 -0800374 "Emitting Queue entries more recent than: %" PRId64 "\n",
Ray Essickb5fac8e2016-12-12 11:33:56 -0800375 (int64_t) ts_since);
376 result.append(buffer);
377 }
Ray Essick2e9c63b2017-03-29 15:16:44 -0700378}
379
Ray Essick2e9c63b2017-03-29 15:16:44 -0700380// the recent, detailed queues
Ray Essick92d23b42018-01-29 12:10:30 -0800381void MediaAnalyticsService::dumpRecent(String8 &result, nsecs_t ts_since, const char * only)
382{
Ray Essick2e9c63b2017-03-29 15:16:44 -0700383 const size_t SIZE = 512;
384 char buffer[SIZE];
Ray Essickb5fac8e2016-12-12 11:33:56 -0800385
Ray Essickf65f4212017-08-31 11:41:19 -0700386 if (only != NULL && *only == '\0') {
387 only = NULL;
388 }
389
Ray Essickb5fac8e2016-12-12 11:33:56 -0800390 // show the recently recorded records
Ray Essickd38e1742017-01-23 15:17:06 -0800391 snprintf(buffer, sizeof(buffer), "\nFinalized Metrics (oldest first):\n");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800392 result.append(buffer);
Ray Essick92d23b42018-01-29 12:10:30 -0800393 result.append(this->dumpQueue(ts_since, only));
Ray Essickb5fac8e2016-12-12 11:33:56 -0800394
395 // show who is connected and injecting records?
396 // talk about # records fed to the 'readers'
397 // talk about # records we discarded, perhaps "discarded w/o reading" too
Ray Essick3938dc62016-11-01 08:56:56 -0700398}
Ray Essick92d23b42018-01-29 12:10:30 -0800399
Ray Essick3938dc62016-11-01 08:56:56 -0700400// caller has locked mLock...
Ray Essick92d23b42018-01-29 12:10:30 -0800401String8 MediaAnalyticsService::dumpQueue() {
402 return dumpQueue((nsecs_t) 0, NULL);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800403}
404
Ray Essick92d23b42018-01-29 12:10:30 -0800405String8 MediaAnalyticsService::dumpQueue(nsecs_t ts_since, const char * only) {
Ray Essick3938dc62016-11-01 08:56:56 -0700406 String8 result;
407 int slot = 0;
408
Ray Essick92d23b42018-01-29 12:10:30 -0800409 if (mItems.empty()) {
Ray Essick3938dc62016-11-01 08:56:56 -0700410 result.append("empty\n");
411 } else {
Ray Essick92d23b42018-01-29 12:10:30 -0800412 List<MediaAnalyticsItem *>::iterator it = mItems.begin();
413 for (; it != mItems.end(); it++) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800414 nsecs_t when = (*it)->getTimestamp();
415 if (when < ts_since) {
416 continue;
417 }
Ray Essick2e9c63b2017-03-29 15:16:44 -0700418 if (only != NULL &&
419 strcmp(only, (*it)->getKey().c_str()) != 0) {
420 ALOGV("Omit '%s', it's not '%s'", (*it)->getKey().c_str(), only);
421 continue;
422 }
Ray Essick783bd0d2018-01-11 11:10:35 -0800423 std::string entry = (*it)->toString(mDumpProto);
Ray Essick35ad27f2017-01-30 14:04:11 -0800424 result.appendFormat("%5d: %s\n", slot, entry.c_str());
Ray Essickb5fac8e2016-12-12 11:33:56 -0800425 slot++;
Ray Essick3938dc62016-11-01 08:56:56 -0700426 }
427 }
428
429 return result;
430}
431
432//
433// Our Cheap in-core, non-persistent records management.
Ray Essick3938dc62016-11-01 08:56:56 -0700434
435// insert appropriately into queue
Ray Essick92d23b42018-01-29 12:10:30 -0800436void MediaAnalyticsService::saveItem(MediaAnalyticsItem * item)
437{
Ray Essick3938dc62016-11-01 08:56:56 -0700438
Ray Essick92d23b42018-01-29 12:10:30 -0800439 Mutex::Autolock _l(mLock);
440 // mutex between insertion and dumping the contents
Ray Essick3938dc62016-11-01 08:56:56 -0700441
Ray Essick92d23b42018-01-29 12:10:30 -0800442 // we want to dump 'in FIFO order', so insert at the end
443 mItems.push_back(item);
Ray Essicke5db6db2017-11-10 15:54:32 -0800444
Ray Essickf65f4212017-08-31 11:41:19 -0700445 // keep removing old records the front until we're in-bounds (count)
Ray Essick3938dc62016-11-01 08:56:56 -0700446 if (mMaxRecords > 0) {
Ray Essick92d23b42018-01-29 12:10:30 -0800447 while (mItems.size() > (size_t) mMaxRecords) {
448 MediaAnalyticsItem * oitem = *(mItems.begin());
Ray Essicke5db6db2017-11-10 15:54:32 -0800449 if (oitem == item) {
450 break;
451 }
Ray Essick92d23b42018-01-29 12:10:30 -0800452 mItems.erase(mItems.begin());
Ray Essickb5fac8e2016-12-12 11:33:56 -0800453 delete oitem;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800454 mItemsDiscarded++;
Ray Essickf65f4212017-08-31 11:41:19 -0700455 mItemsDiscardedCount++;
456 }
457 }
458
459 // keep removing old records the front until we're in-bounds (count)
Ray Essick92d23b42018-01-29 12:10:30 -0800460 // NB: expired entries aren't removed until the next insertion, which could be a while
Ray Essickf65f4212017-08-31 11:41:19 -0700461 if (mMaxRecordAgeNs > 0) {
462 nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
Ray Essick92d23b42018-01-29 12:10:30 -0800463 while (mItems.size() > 0) {
464 MediaAnalyticsItem * oitem = *(mItems.begin());
Ray Essickf65f4212017-08-31 11:41:19 -0700465 nsecs_t when = oitem->getTimestamp();
Ray Essicke5db6db2017-11-10 15:54:32 -0800466 if (oitem == item) {
467 break;
468 }
Ray Essickf65f4212017-08-31 11:41:19 -0700469 // careful about timejumps too
470 if ((now > when) && (now-when) <= mMaxRecordAgeNs) {
471 // this (and the rest) are recent enough to keep
472 break;
473 }
Ray Essick92d23b42018-01-29 12:10:30 -0800474 mItems.erase(mItems.begin());
Ray Essickf65f4212017-08-31 11:41:19 -0700475 delete oitem;
476 mItemsDiscarded++;
477 mItemsDiscardedExpire++;
Ray Essick3938dc62016-11-01 08:56:56 -0700478 }
479 }
Ray Essick3938dc62016-11-01 08:56:56 -0700480}
481
Ray Essick783bd0d2018-01-11 11:10:35 -0800482static std::string allowedKeys[] =
Ray Essickd38e1742017-01-23 15:17:06 -0800483{
Ray Essick84e84a52018-05-03 18:45:07 -0700484 "audiopolicy",
Ray Essick8c22cb12018-01-24 11:00:36 -0800485 "audiorecord",
Eric Tanbc2a7732018-09-06 12:04:44 -0700486 "audiothread",
Ray Essick8c22cb12018-01-24 11:00:36 -0800487 "audiotrack",
Ray Essickd38e1742017-01-23 15:17:06 -0800488 "codec",
Ray Essick8c22cb12018-01-24 11:00:36 -0800489 "extractor",
490 "nuplayer",
Ray Essickd38e1742017-01-23 15:17:06 -0800491};
Ray Essick3938dc62016-11-01 08:56:56 -0700492
Ray Essickd38e1742017-01-23 15:17:06 -0800493static const int nAllowedKeys = sizeof(allowedKeys) / sizeof(allowedKeys[0]);
494
495// are the contents good
496bool MediaAnalyticsService::contentValid(MediaAnalyticsItem *item, bool isTrusted) {
497
498 // untrusted uids can only send us a limited set of keys
499 if (isTrusted == false) {
500 // restrict to a specific set of keys
Ray Essick783bd0d2018-01-11 11:10:35 -0800501 std::string key = item->getKey();
Ray Essickd38e1742017-01-23 15:17:06 -0800502
503 size_t i;
504 for(i = 0; i < nAllowedKeys; i++) {
505 if (key == allowedKeys[i]) {
506 break;
507 }
508 }
509 if (i == nAllowedKeys) {
510 ALOGD("Ignoring (key): %s", item->toString().c_str());
511 return false;
512 }
513 }
514
Ray Essick3938dc62016-11-01 08:56:56 -0700515 // internal consistency
516
517 return true;
518}
519
520// are we rate limited, normally false
Ray Essickb5fac8e2016-12-12 11:33:56 -0800521bool MediaAnalyticsService::rateLimited(MediaAnalyticsItem *) {
Ray Essick3938dc62016-11-01 08:56:56 -0700522
523 return false;
524}
525
Ray Essickfa149562017-09-19 09:27:31 -0700526// how long we hold package info before we re-fetch it
527#define PKG_EXPIRATION_NS (30*60*1000000000ll) // 30 minutes, in nsecs
Ray Essickf65f4212017-08-31 11:41:19 -0700528
529// give me the package name, perhaps going to find it
Ray Essick92d23b42018-01-29 12:10:30 -0800530// manages its own mutex operations internally
531void MediaAnalyticsService::setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion)
532{
Ray Essickfa149562017-09-19 09:27:31 -0700533 ALOGV("asking for packagename to go with uid=%d", uid);
534
535 if (!setName && !setVersion) {
536 // setting nothing? strange
537 return;
538 }
539
540 nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
541 struct UidToPkgMap mapping;
Ray Essick92d23b42018-01-29 12:10:30 -0800542 mapping.uid = (uid_t)(-1);
Ray Essickfa149562017-09-19 09:27:31 -0700543
Ray Essick92d23b42018-01-29 12:10:30 -0800544 {
545 Mutex::Autolock _l(mLock_mappings);
546 int i = mPkgMappings.indexOfKey(uid);
547 if (i >= 0) {
548 mapping = mPkgMappings.valueAt(i);
549 ALOGV("Expiration? uid %d expiration %" PRId64 " now %" PRId64,
550 uid, mapping.expiration, now);
551 if (mapping.expiration <= now) {
552 // purge the stale entry and fall into re-fetching
553 ALOGV("entry for uid %d expired, now= %" PRId64 "", uid, now);
554 mPkgMappings.removeItemsAt(i);
555 mapping.uid = (uid_t)(-1);
556 }
Ray Essickf65f4212017-08-31 11:41:19 -0700557 }
Ray Essick92d23b42018-01-29 12:10:30 -0800558 }
559
560 // if we did not find it
561 if (mapping.uid == (uid_t)(-1)) {
Ray Essick783bd0d2018-01-11 11:10:35 -0800562 std::string pkg;
Ray Essickfa149562017-09-19 09:27:31 -0700563 std::string installer = "";
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800564 int64_t versionCode = 0;
Ray Essickf65f4212017-08-31 11:41:19 -0700565
Ray Essickfa149562017-09-19 09:27:31 -0700566 struct passwd *pw = getpwuid(uid);
567 if (pw) {
568 pkg = pw->pw_name;
569 }
Ray Essickf65f4212017-08-31 11:41:19 -0700570
Ray Essick92d23b42018-01-29 12:10:30 -0800571 // find the proper value
Ray Essickf65f4212017-08-31 11:41:19 -0700572
Ray Essickfa149562017-09-19 09:27:31 -0700573 sp<IBinder> binder = NULL;
574 sp<IServiceManager> sm = defaultServiceManager();
575 if (sm == NULL) {
576 ALOGE("defaultServiceManager failed");
Ray Essickf65f4212017-08-31 11:41:19 -0700577 } else {
Ray Essickfa149562017-09-19 09:27:31 -0700578 binder = sm->getService(String16("package_native"));
579 if (binder == NULL) {
580 ALOGE("getService package_native failed");
581 }
582 }
583
584 if (binder != NULL) {
585 sp<IPackageManagerNative> package_mgr = interface_cast<IPackageManagerNative>(binder);
586 binder::Status status;
587
588 std::vector<int> uids;
589 std::vector<std::string> names;
590
591 uids.push_back(uid);
592
593 status = package_mgr->getNamesForUids(uids, &names);
594 if (!status.isOk()) {
595 ALOGE("package_native::getNamesForUids failed: %s",
596 status.exceptionMessage().c_str());
597 } else {
598 if (!names[0].empty()) {
599 pkg = names[0].c_str();
600 }
601 }
602
603 // strip any leading "shared:" strings that came back
Ray Essick783bd0d2018-01-11 11:10:35 -0800604 if (pkg.compare(0, 7, "shared:") == 0) {
Ray Essickfa149562017-09-19 09:27:31 -0700605 pkg.erase(0, 7);
606 }
607
608 // determine how pkg was installed and the versionCode
609 //
610 if (pkg.empty()) {
611 // no name for us to manage
612 } else if (strchr(pkg.c_str(), '.') == NULL) {
613 // not of form 'com.whatever...'; assume internal and ok
614 } else if (strncmp(pkg.c_str(), "android.", 8) == 0) {
615 // android.* packages are assumed fine
616 } else {
617 String16 pkgName16(pkg.c_str());
618 status = package_mgr->getInstallerForPackage(pkgName16, &installer);
619 if (!status.isOk()) {
620 ALOGE("package_native::getInstallerForPackage failed: %s",
621 status.exceptionMessage().c_str());
622 }
623
624 // skip if we didn't get an installer
625 if (status.isOk()) {
626 status = package_mgr->getVersionCodeForPackage(pkgName16, &versionCode);
627 if (!status.isOk()) {
628 ALOGE("package_native::getVersionCodeForPackage failed: %s",
629 status.exceptionMessage().c_str());
630 }
631 }
632
633
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800634 ALOGV("package '%s' installed by '%s' versioncode %" PRId64 " / %" PRIx64,
Ray Essickfa149562017-09-19 09:27:31 -0700635 pkg.c_str(), installer.c_str(), versionCode, versionCode);
636
637 if (strncmp(installer.c_str(), "com.android.", 12) == 0) {
638 // from play store, we keep info
639 } else if (strncmp(installer.c_str(), "com.google.", 11) == 0) {
640 // some google source, we keep info
641 } else if (strcmp(installer.c_str(), "preload") == 0) {
642 // preloads, we keep the info
643 } else if (installer.c_str()[0] == '\0') {
644 // sideload (no installer); do not report
645 pkg = "";
646 versionCode = 0;
647 } else {
648 // unknown installer; do not report
649 pkg = "";
650 versionCode = 0;
651 }
652 }
653 }
654
655 // add it to the map, to save a subsequent lookup
656 if (!pkg.empty()) {
657 Mutex::Autolock _l(mLock_mappings);
658 ALOGV("Adding uid %d pkg '%s'", uid, pkg.c_str());
659 ssize_t i = mPkgMappings.indexOfKey(uid);
660 if (i < 0) {
661 mapping.uid = uid;
662 mapping.pkg = pkg;
663 mapping.installer = installer.c_str();
664 mapping.versionCode = versionCode;
665 mapping.expiration = now + PKG_EXPIRATION_NS;
666 ALOGV("expiration for uid %d set to %" PRId64 "", uid, mapping.expiration);
667
668 mPkgMappings.add(uid, mapping);
Ray Essickf65f4212017-08-31 11:41:19 -0700669 }
670 }
671 }
672
Ray Essickfa149562017-09-19 09:27:31 -0700673 if (mapping.uid != (uid_t)(-1)) {
674 if (setName) {
675 item->setPkgName(mapping.pkg);
676 }
677 if (setVersion) {
678 item->setPkgVersionCode(mapping.versionCode);
Ray Essickf65f4212017-08-31 11:41:19 -0700679 }
680 }
Ray Essickf65f4212017-08-31 11:41:19 -0700681}
682
Ray Essick3938dc62016-11-01 08:56:56 -0700683} // namespace android