blob: 06baac962df789444d99a02a8e2bea6fab03d52e [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>
Ray Essick72a436b2018-06-14 15:08:13 -070029#include <pthread.h>
Ray Essick3938dc62016-11-01 08:56:56 -070030#include <unistd.h>
31
32#include <string.h>
Ray Essickf65f4212017-08-31 11:41:19 -070033#include <pwd.h>
Ray Essick3938dc62016-11-01 08:56:56 -070034
35#include <cutils/atomic.h>
36#include <cutils/properties.h> // for property_get
37
38#include <utils/misc.h>
39
Ray Essickf65f4212017-08-31 11:41:19 -070040#include <android/content/pm/IPackageManagerNative.h>
41
Ray Essick3938dc62016-11-01 08:56:56 -070042#include <binder/IPCThreadState.h>
43#include <binder/IServiceManager.h>
44#include <binder/MemoryHeapBase.h>
45#include <binder/MemoryBase.h>
46#include <gui/Surface.h>
47#include <utils/Errors.h> // for status_t
48#include <utils/List.h>
49#include <utils/String8.h>
50#include <utils/SystemClock.h>
51#include <utils/Timers.h>
52#include <utils/Vector.h>
53
Ray Essick3938dc62016-11-01 08:56:56 -070054#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// individual records kept in memory: age or count
Ray Essick72a436b2018-06-14 15:08:13 -070080// age: <= 28 hours (1 1/6 days)
Ray Essickf65f4212017-08-31 11:41:19 -070081// count: hard limit of # records
82// (0 for either of these disables that threshold)
Ray Essick72a436b2018-06-14 15:08:13 -070083//
84static constexpr nsecs_t kMaxRecordAgeNs = 28 * 3600 * (1000*1000*1000ll);
85static constexpr int kMaxRecords = 0;
86
87// max we expire in a single call, to constrain how long we hold the
88// mutex, which also constrains how long a client might wait.
89static constexpr int kMaxExpiredAtOnce = 50;
90
91// TODO: need to look at tuning kMaxRecords and friends for low-memory devices
Ray Essick2e9c63b2017-03-29 15:16:44 -070092
93static const char *kServiceName = "media.metrics";
94
Ray Essick3938dc62016-11-01 08:56:56 -070095void MediaAnalyticsService::instantiate() {
96 defaultServiceManager()->addService(
Ray Essick2e9c63b2017-03-29 15:16:44 -070097 String16(kServiceName), new MediaAnalyticsService());
Ray Essick3938dc62016-11-01 08:56:56 -070098}
99
Ray Essick3938dc62016-11-01 08:56:56 -0700100MediaAnalyticsService::MediaAnalyticsService()
Ray Essick2e9c63b2017-03-29 15:16:44 -0700101 : mMaxRecords(kMaxRecords),
Ray Essickf65f4212017-08-31 11:41:19 -0700102 mMaxRecordAgeNs(kMaxRecordAgeNs),
Ray Essick72a436b2018-06-14 15:08:13 -0700103 mMaxRecordsExpiredAtOnce(kMaxExpiredAtOnce),
Ray Essick583a23a2017-11-27 12:49:57 -0800104 mDumpProto(MediaAnalyticsItem::PROTO_V1),
105 mDumpProtoDefault(MediaAnalyticsItem::PROTO_V1) {
Ray Essick3938dc62016-11-01 08:56:56 -0700106
107 ALOGD("MediaAnalyticsService created");
Ray Essick3938dc62016-11-01 08:56:56 -0700108
109 mItemsSubmitted = 0;
110 mItemsFinalized = 0;
111 mItemsDiscarded = 0;
Ray Essickf65f4212017-08-31 11:41:19 -0700112 mItemsDiscardedExpire = 0;
113 mItemsDiscardedCount = 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700114
115 mLastSessionID = 0;
116 // recover any persistency we set up
117 // etc
118}
119
120MediaAnalyticsService::~MediaAnalyticsService() {
121 ALOGD("MediaAnalyticsService destroyed");
122
Ray Essick92d23b42018-01-29 12:10:30 -0800123 while (mItems.size() > 0) {
124 MediaAnalyticsItem * oitem = *(mItems.begin());
125 mItems.erase(mItems.begin());
Ray Essickf65f4212017-08-31 11:41:19 -0700126 delete oitem;
127 mItemsDiscarded++;
128 mItemsDiscardedCount++;
129 }
Ray Essick3938dc62016-11-01 08:56:56 -0700130}
131
132
133MediaAnalyticsItem::SessionID_t MediaAnalyticsService::generateUniqueSessionID() {
134 // generate a new sessionid
135
136 Mutex::Autolock _l(mLock_ids);
137 return (++mLastSessionID);
138}
139
Ray Essickb5fac8e2016-12-12 11:33:56 -0800140// caller surrenders ownership of 'item'
Ray Essick92d23b42018-01-29 12:10:30 -0800141MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem *item, bool forcenew)
142{
143 UNUSED(forcenew);
Ray Essick3938dc62016-11-01 08:56:56 -0700144
Ray Essick92d23b42018-01-29 12:10:30 -0800145 // fill in a sessionID if we do not yet have one
146 if (item->getSessionID() <= MediaAnalyticsItem::SessionIDNone) {
147 item->setSessionID(generateUniqueSessionID());
148 }
Ray Essick3938dc62016-11-01 08:56:56 -0700149
Ray Essickd38e1742017-01-23 15:17:06 -0800150 // we control these, generally not trusting user input
Ray Essick3938dc62016-11-01 08:56:56 -0700151 nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
Ray Essick721b7a02017-09-11 09:33:56 -0700152 // round nsecs to seconds
153 now = ((now + 500000000) / 1000000000) * 1000000000;
Ray Essick3938dc62016-11-01 08:56:56 -0700154 item->setTimestamp(now);
155 int pid = IPCThreadState::self()->getCallingPid();
Ray Essick3938dc62016-11-01 08:56:56 -0700156 int uid = IPCThreadState::self()->getCallingUid();
Ray Essickd38e1742017-01-23 15:17:06 -0800157
158 int uid_given = item->getUid();
159 int pid_given = item->getPid();
160
Ray Essick92d23b42018-01-29 12:10:30 -0800161 // although we do make exceptions for some trusted client uids
Ray Essickd38e1742017-01-23 15:17:06 -0800162 bool isTrusted = false;
163
Ray Essickf65f4212017-08-31 11:41:19 -0700164 ALOGV("caller has uid=%d, embedded uid=%d", uid, uid_given);
165
Ray Essickd38e1742017-01-23 15:17:06 -0800166 switch (uid) {
167 case AID_MEDIA:
168 case AID_MEDIA_CODEC:
169 case AID_MEDIA_EX:
170 case AID_MEDIA_DRM:
171 // trusted source, only override default values
Ray Essickf65f4212017-08-31 11:41:19 -0700172 isTrusted = true;
Ray Essickd38e1742017-01-23 15:17:06 -0800173 if (uid_given == (-1)) {
174 item->setUid(uid);
175 }
176 if (pid_given == (-1)) {
177 item->setPid(pid);
178 }
179 break;
180 default:
181 isTrusted = false;
182 item->setPid(pid);
183 item->setUid(uid);
184 break;
185 }
186
Adam Stone21c72122017-09-05 19:02:06 -0700187 // Overwrite package name and version if the caller was untrusted.
188 if (!isTrusted) {
Ray Essickfa149562017-09-19 09:27:31 -0700189 setPkgInfo(item, item->getUid(), true, true);
Adam Stone21c72122017-09-05 19:02:06 -0700190 } else if (item->getPkgName().empty()) {
Ray Essickfa149562017-09-19 09:27:31 -0700191 // empty, so fill out both parts
192 setPkgInfo(item, item->getUid(), true, true);
193 } else {
194 // trusted, provided a package, do nothing
Adam Stone21c72122017-09-05 19:02:06 -0700195 }
196
197 ALOGV("given uid %d; sanitized uid: %d sanitized pkg: %s "
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800198 "sanitized pkg version: %" PRId64,
Adam Stone21c72122017-09-05 19:02:06 -0700199 uid_given, item->getUid(),
200 item->getPkgName().c_str(),
201 item->getPkgVersionCode());
Ray Essick3938dc62016-11-01 08:56:56 -0700202
203 mItemsSubmitted++;
204
205 // validate the record; we discard if we don't like it
Ray Essickd38e1742017-01-23 15:17:06 -0800206 if (contentValid(item, isTrusted) == false) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800207 delete item;
Ray Essick3938dc62016-11-01 08:56:56 -0700208 return MediaAnalyticsItem::SessionIDInvalid;
209 }
210
Ray Essick92d23b42018-01-29 12:10:30 -0800211 // XXX: if we have a sessionid in the new record, look to make
Ray Essick3938dc62016-11-01 08:56:56 -0700212 // sure it doesn't appear in the finalized list.
213 // XXX: this is for security / DOS prevention.
214 // may also require that we persist the unique sessionIDs
215 // across boots [instead of within a single boot]
216
Ray Essick92d23b42018-01-29 12:10:30 -0800217 if (item->count() == 0) {
218 // drop empty records
219 delete item;
220 item = NULL;
221 return MediaAnalyticsItem::SessionIDInvalid;
Ray Essick3938dc62016-11-01 08:56:56 -0700222 }
Ray Essick92d23b42018-01-29 12:10:30 -0800223
224 // save the new record
225 MediaAnalyticsItem::SessionID_t id = item->getSessionID();
226 saveItem(item);
227 mItemsFinalized++;
Ray Essick3938dc62016-11-01 08:56:56 -0700228 return id;
229}
230
Ray Essickf65f4212017-08-31 11:41:19 -0700231
Ray Essickb5fac8e2016-12-12 11:33:56 -0800232status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
Ray Essick3938dc62016-11-01 08:56:56 -0700233{
Ray Essickb5fac8e2016-12-12 11:33:56 -0800234 const size_t SIZE = 512;
Ray Essick3938dc62016-11-01 08:56:56 -0700235 char buffer[SIZE];
236 String8 result;
237
238 if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
239 snprintf(buffer, SIZE, "Permission Denial: "
240 "can't dump MediaAnalyticsService from pid=%d, uid=%d\n",
241 IPCThreadState::self()->getCallingPid(),
242 IPCThreadState::self()->getCallingUid());
243 result.append(buffer);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800244 write(fd, result.string(), result.size());
245 return NO_ERROR;
Ray Essick3938dc62016-11-01 08:56:56 -0700246 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800247
248 // crack any parameters
Ray Essickf65f4212017-08-31 11:41:19 -0700249 String16 protoOption("-proto");
Ray Essick583a23a2017-11-27 12:49:57 -0800250 int chosenProto = mDumpProtoDefault;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800251 String16 clearOption("-clear");
Ray Essickf65f4212017-08-31 11:41:19 -0700252 bool clear = false;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800253 String16 sinceOption("-since");
Ray Essickf65f4212017-08-31 11:41:19 -0700254 nsecs_t ts_since = 0;
Ray Essick35ad27f2017-01-30 14:04:11 -0800255 String16 helpOption("-help");
Ray Essick2e9c63b2017-03-29 15:16:44 -0700256 String16 onlyOption("-only");
Ray Essick783bd0d2018-01-11 11:10:35 -0800257 std::string only;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800258 int n = args.size();
Ray Essickf65f4212017-08-31 11:41:19 -0700259
Ray Essickb5fac8e2016-12-12 11:33:56 -0800260 for (int i = 0; i < n; i++) {
261 String8 myarg(args[i]);
262 if (args[i] == clearOption) {
263 clear = true;
Ray Essickf65f4212017-08-31 11:41:19 -0700264 } else if (args[i] == protoOption) {
265 i++;
266 if (i < n) {
267 String8 value(args[i]);
Ray Essick583a23a2017-11-27 12:49:57 -0800268 int proto = MediaAnalyticsItem::PROTO_V0;
Ray Essickf65f4212017-08-31 11:41:19 -0700269 char *endp;
270 const char *p = value.string();
271 proto = strtol(p, &endp, 10);
272 if (endp != p || *endp == '\0') {
273 if (proto < MediaAnalyticsItem::PROTO_FIRST) {
274 proto = MediaAnalyticsItem::PROTO_FIRST;
275 } else if (proto > MediaAnalyticsItem::PROTO_LAST) {
276 proto = MediaAnalyticsItem::PROTO_LAST;
277 }
Ray Essick583a23a2017-11-27 12:49:57 -0800278 chosenProto = proto;
279 } else {
280 result.append("unable to parse value for -proto\n\n");
Ray Essickf65f4212017-08-31 11:41:19 -0700281 }
Ray Essick583a23a2017-11-27 12:49:57 -0800282 } else {
283 result.append("missing value for -proto\n\n");
Ray Essickf65f4212017-08-31 11:41:19 -0700284 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800285 } else if (args[i] == sinceOption) {
286 i++;
287 if (i < n) {
288 String8 value(args[i]);
289 char *endp;
290 const char *p = value.string();
291 ts_since = strtoll(p, &endp, 10);
292 if (endp == p || *endp != '\0') {
293 ts_since = 0;
294 }
295 } else {
296 ts_since = 0;
297 }
Ray Essick35ad27f2017-01-30 14:04:11 -0800298 // command line is milliseconds; internal units are nano-seconds
299 ts_since *= 1000*1000;
Ray Essick2e9c63b2017-03-29 15:16:44 -0700300 } else if (args[i] == onlyOption) {
301 i++;
302 if (i < n) {
303 String8 value(args[i]);
Ray Essickf65f4212017-08-31 11:41:19 -0700304 only = value.string();
Ray Essick2e9c63b2017-03-29 15:16:44 -0700305 }
Ray Essick35ad27f2017-01-30 14:04:11 -0800306 } else if (args[i] == helpOption) {
307 result.append("Recognized parameters:\n");
308 result.append("-help this help message\n");
Ray Essick583a23a2017-11-27 12:49:57 -0800309 result.append("-proto # dump using protocol #");
Ray Essick35ad27f2017-01-30 14:04:11 -0800310 result.append("-clear clears out saved records\n");
Ray Essick2e9c63b2017-03-29 15:16:44 -0700311 result.append("-only X process records for component X\n");
312 result.append("-since X include records since X\n");
313 result.append(" (X is milliseconds since the UNIX epoch)\n");
Ray Essick35ad27f2017-01-30 14:04:11 -0800314 write(fd, result.string(), result.size());
315 return NO_ERROR;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800316 }
317 }
318
319 Mutex::Autolock _l(mLock);
Ray Essick92d23b42018-01-29 12:10:30 -0800320 // mutex between insertion and dumping the contents
Ray Essickb5fac8e2016-12-12 11:33:56 -0800321
Ray Essick583a23a2017-11-27 12:49:57 -0800322 mDumpProto = chosenProto;
323
Ray Essick2e9c63b2017-03-29 15:16:44 -0700324 // we ALWAYS dump this piece
325 snprintf(buffer, SIZE, "Dump of the %s process:\n", kServiceName);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800326 result.append(buffer);
327
Ray Essick2e9c63b2017-03-29 15:16:44 -0700328 dumpHeaders(result, ts_since);
329
Ray Essick813b1b82018-01-16 15:10:06 -0800330 dumpRecent(result, ts_since, only.c_str());
Ray Essick2e9c63b2017-03-29 15:16:44 -0700331
332
333 if (clear) {
334 // remove everything from the finalized queue
Ray Essick92d23b42018-01-29 12:10:30 -0800335 while (mItems.size() > 0) {
336 MediaAnalyticsItem * oitem = *(mItems.begin());
337 mItems.erase(mItems.begin());
Ray Essick2e9c63b2017-03-29 15:16:44 -0700338 delete oitem;
339 mItemsDiscarded++;
340 }
341
342 // shall we clear the summary data too?
343
344 }
345
346 write(fd, result.string(), result.size());
347 return NO_ERROR;
348}
349
350// dump headers
Ray Essick92d23b42018-01-29 12:10:30 -0800351void MediaAnalyticsService::dumpHeaders(String8 &result, nsecs_t ts_since)
352{
Ray Essick2e9c63b2017-03-29 15:16:44 -0700353 const size_t SIZE = 512;
354 char buffer[SIZE];
355
Ray Essickf65f4212017-08-31 11:41:19 -0700356 snprintf(buffer, SIZE, "Protocol Version: %d\n", mDumpProto);
357 result.append(buffer);
358
Ray Essickb5fac8e2016-12-12 11:33:56 -0800359 int enabled = MediaAnalyticsItem::isEnabled();
360 if (enabled) {
Ray Essickd38e1742017-01-23 15:17:06 -0800361 snprintf(buffer, SIZE, "Metrics gathering: enabled\n");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800362 } else {
Ray Essickd38e1742017-01-23 15:17:06 -0800363 snprintf(buffer, SIZE, "Metrics gathering: DISABLED via property\n");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800364 }
365 result.append(buffer);
366
367 snprintf(buffer, SIZE,
Ray Essickf65f4212017-08-31 11:41:19 -0700368 "Since Boot: Submissions: %8" PRId64
Ray Essick92d23b42018-01-29 12:10:30 -0800369 " Accepted: %8" PRId64 "\n",
Ray Essickf65f4212017-08-31 11:41:19 -0700370 mItemsSubmitted, mItemsFinalized);
371 result.append(buffer);
372 snprintf(buffer, SIZE,
373 "Records Discarded: %8" PRId64
374 " (by Count: %" PRId64 " by Expiration: %" PRId64 ")\n",
375 mItemsDiscarded, mItemsDiscardedCount, mItemsDiscardedExpire);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800376 result.append(buffer);
377 if (ts_since != 0) {
378 snprintf(buffer, SIZE,
Ray Essick92d23b42018-01-29 12:10:30 -0800379 "Emitting Queue entries more recent than: %" PRId64 "\n",
Ray Essickb5fac8e2016-12-12 11:33:56 -0800380 (int64_t) ts_since);
381 result.append(buffer);
382 }
Ray Essick2e9c63b2017-03-29 15:16:44 -0700383}
384
Ray Essick2e9c63b2017-03-29 15:16:44 -0700385// the recent, detailed queues
Ray Essick92d23b42018-01-29 12:10:30 -0800386void MediaAnalyticsService::dumpRecent(String8 &result, nsecs_t ts_since, const char * only)
387{
Ray Essick2e9c63b2017-03-29 15:16:44 -0700388 const size_t SIZE = 512;
389 char buffer[SIZE];
Ray Essickb5fac8e2016-12-12 11:33:56 -0800390
Ray Essickf65f4212017-08-31 11:41:19 -0700391 if (only != NULL && *only == '\0') {
392 only = NULL;
393 }
394
Ray Essickb5fac8e2016-12-12 11:33:56 -0800395 // show the recently recorded records
Ray Essickd38e1742017-01-23 15:17:06 -0800396 snprintf(buffer, sizeof(buffer), "\nFinalized Metrics (oldest first):\n");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800397 result.append(buffer);
Ray Essick92d23b42018-01-29 12:10:30 -0800398 result.append(this->dumpQueue(ts_since, only));
Ray Essickb5fac8e2016-12-12 11:33:56 -0800399
400 // show who is connected and injecting records?
401 // talk about # records fed to the 'readers'
402 // talk about # records we discarded, perhaps "discarded w/o reading" too
Ray Essick3938dc62016-11-01 08:56:56 -0700403}
Ray Essick92d23b42018-01-29 12:10:30 -0800404
Ray Essick3938dc62016-11-01 08:56:56 -0700405// caller has locked mLock...
Ray Essick92d23b42018-01-29 12:10:30 -0800406String8 MediaAnalyticsService::dumpQueue() {
407 return dumpQueue((nsecs_t) 0, NULL);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800408}
409
Ray Essick92d23b42018-01-29 12:10:30 -0800410String8 MediaAnalyticsService::dumpQueue(nsecs_t ts_since, const char * only) {
Ray Essick3938dc62016-11-01 08:56:56 -0700411 String8 result;
412 int slot = 0;
413
Ray Essick92d23b42018-01-29 12:10:30 -0800414 if (mItems.empty()) {
Ray Essick3938dc62016-11-01 08:56:56 -0700415 result.append("empty\n");
416 } else {
Ray Essick92d23b42018-01-29 12:10:30 -0800417 List<MediaAnalyticsItem *>::iterator it = mItems.begin();
418 for (; it != mItems.end(); it++) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800419 nsecs_t when = (*it)->getTimestamp();
420 if (when < ts_since) {
421 continue;
422 }
Ray Essick2e9c63b2017-03-29 15:16:44 -0700423 if (only != NULL &&
424 strcmp(only, (*it)->getKey().c_str()) != 0) {
425 ALOGV("Omit '%s', it's not '%s'", (*it)->getKey().c_str(), only);
426 continue;
427 }
Ray Essick783bd0d2018-01-11 11:10:35 -0800428 std::string entry = (*it)->toString(mDumpProto);
Ray Essick35ad27f2017-01-30 14:04:11 -0800429 result.appendFormat("%5d: %s\n", slot, entry.c_str());
Ray Essickb5fac8e2016-12-12 11:33:56 -0800430 slot++;
Ray Essick3938dc62016-11-01 08:56:56 -0700431 }
432 }
433
434 return result;
435}
436
437//
438// Our Cheap in-core, non-persistent records management.
Ray Essick3938dc62016-11-01 08:56:56 -0700439
Ray Essick72a436b2018-06-14 15:08:13 -0700440
441// we hold mLock when we get here
442// if item != NULL, it's the item we just inserted
443// true == more items eligible to be recovered
444bool MediaAnalyticsService::expirations_l(MediaAnalyticsItem *item)
Ray Essick92d23b42018-01-29 12:10:30 -0800445{
Ray Essick72a436b2018-06-14 15:08:13 -0700446 bool more = false;
447 int handled = 0;
Ray Essicke5db6db2017-11-10 15:54:32 -0800448
Ray Essickf65f4212017-08-31 11:41:19 -0700449 // keep removing old records the front until we're in-bounds (count)
Ray Essick72a436b2018-06-14 15:08:13 -0700450 // since we invoke this with each insertion, it should be 0/1 iterations.
Ray Essick3938dc62016-11-01 08:56:56 -0700451 if (mMaxRecords > 0) {
Ray Essick92d23b42018-01-29 12:10:30 -0800452 while (mItems.size() > (size_t) mMaxRecords) {
453 MediaAnalyticsItem * oitem = *(mItems.begin());
Ray Essicke5db6db2017-11-10 15:54:32 -0800454 if (oitem == item) {
455 break;
456 }
Ray Essick72a436b2018-06-14 15:08:13 -0700457 if (handled >= mMaxRecordsExpiredAtOnce) {
458 // unlikely in this loop
459 more = true;
460 break;
461 }
462 handled++;
Ray Essick92d23b42018-01-29 12:10:30 -0800463 mItems.erase(mItems.begin());
Ray Essickb5fac8e2016-12-12 11:33:56 -0800464 delete oitem;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800465 mItemsDiscarded++;
Ray Essickf65f4212017-08-31 11:41:19 -0700466 mItemsDiscardedCount++;
467 }
468 }
469
Ray Essick72a436b2018-06-14 15:08:13 -0700470 // keep removing old records the front until we're in-bounds (age)
471 // limited to mMaxRecordsExpiredAtOnce items per invocation.
Ray Essickf65f4212017-08-31 11:41:19 -0700472 if (mMaxRecordAgeNs > 0) {
473 nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
Ray Essick92d23b42018-01-29 12:10:30 -0800474 while (mItems.size() > 0) {
475 MediaAnalyticsItem * oitem = *(mItems.begin());
Ray Essickf65f4212017-08-31 11:41:19 -0700476 nsecs_t when = oitem->getTimestamp();
Ray Essicke5db6db2017-11-10 15:54:32 -0800477 if (oitem == item) {
478 break;
479 }
Ray Essickf65f4212017-08-31 11:41:19 -0700480 // careful about timejumps too
481 if ((now > when) && (now-when) <= mMaxRecordAgeNs) {
482 // this (and the rest) are recent enough to keep
483 break;
484 }
Ray Essick72a436b2018-06-14 15:08:13 -0700485 if (handled >= mMaxRecordsExpiredAtOnce) {
486 // this represents "one too many"; tell caller there are
487 // more to be reclaimed.
488 more = true;
489 break;
490 }
491 handled++;
Ray Essick92d23b42018-01-29 12:10:30 -0800492 mItems.erase(mItems.begin());
Ray Essickf65f4212017-08-31 11:41:19 -0700493 delete oitem;
494 mItemsDiscarded++;
495 mItemsDiscardedExpire++;
Ray Essick3938dc62016-11-01 08:56:56 -0700496 }
497 }
Ray Essick72a436b2018-06-14 15:08:13 -0700498
499 // we only indicate whether there's more to clean;
500 // caller chooses whether to schedule further cleanup.
501 return more;
502}
503
504// process expirations in bite sized chunks, allowing new insertions through
505// runs in a pthread specifically started for this (which then exits)
506bool MediaAnalyticsService::processExpirations()
507{
508 bool more;
509 do {
510 sleep(1);
511 {
512 Mutex::Autolock _l(mLock);
513 more = expirations_l(NULL);
514 if (!more) {
515 break;
516 }
517 }
518 } while (more);
519 return true; // value is for std::future thread synchronization
520}
521
522// insert appropriately into queue
523void MediaAnalyticsService::saveItem(MediaAnalyticsItem * item)
524{
525
526 Mutex::Autolock _l(mLock);
527 // mutex between insertion and dumping the contents
528
529 // we want to dump 'in FIFO order', so insert at the end
530 mItems.push_back(item);
531
532 // clean old stuff from the queue
533 bool more = expirations_l(item);
534
535 // consider scheduling some asynchronous cleaning, if not running
536 if (more) {
537 if (!mExpireFuture.valid()
538 || mExpireFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
539
540 mExpireFuture = std::async(std::launch::async, [this]()
541 {return this->processExpirations();});
542 }
543 }
Ray Essick3938dc62016-11-01 08:56:56 -0700544}
545
Ray Essick783bd0d2018-01-11 11:10:35 -0800546static std::string allowedKeys[] =
Ray Essickd38e1742017-01-23 15:17:06 -0800547{
Ray Essick84e84a52018-05-03 18:45:07 -0700548 "audiopolicy",
Ray Essick8c22cb12018-01-24 11:00:36 -0800549 "audiorecord",
Eric Tanbc2a7732018-09-06 12:04:44 -0700550 "audiothread",
Ray Essick8c22cb12018-01-24 11:00:36 -0800551 "audiotrack",
Ray Essickd38e1742017-01-23 15:17:06 -0800552 "codec",
Ray Essick8c22cb12018-01-24 11:00:36 -0800553 "extractor",
554 "nuplayer",
Ray Essickd38e1742017-01-23 15:17:06 -0800555};
Ray Essick3938dc62016-11-01 08:56:56 -0700556
Ray Essickd38e1742017-01-23 15:17:06 -0800557static const int nAllowedKeys = sizeof(allowedKeys) / sizeof(allowedKeys[0]);
558
559// are the contents good
560bool MediaAnalyticsService::contentValid(MediaAnalyticsItem *item, bool isTrusted) {
561
562 // untrusted uids can only send us a limited set of keys
563 if (isTrusted == false) {
564 // restrict to a specific set of keys
Ray Essick783bd0d2018-01-11 11:10:35 -0800565 std::string key = item->getKey();
Ray Essickd38e1742017-01-23 15:17:06 -0800566
567 size_t i;
568 for(i = 0; i < nAllowedKeys; i++) {
569 if (key == allowedKeys[i]) {
570 break;
571 }
572 }
573 if (i == nAllowedKeys) {
574 ALOGD("Ignoring (key): %s", item->toString().c_str());
575 return false;
576 }
577 }
578
Ray Essick3938dc62016-11-01 08:56:56 -0700579 // internal consistency
580
581 return true;
582}
583
584// are we rate limited, normally false
Ray Essickb5fac8e2016-12-12 11:33:56 -0800585bool MediaAnalyticsService::rateLimited(MediaAnalyticsItem *) {
Ray Essick3938dc62016-11-01 08:56:56 -0700586
587 return false;
588}
589
Ray Essickfa149562017-09-19 09:27:31 -0700590// how long we hold package info before we re-fetch it
591#define PKG_EXPIRATION_NS (30*60*1000000000ll) // 30 minutes, in nsecs
Ray Essickf65f4212017-08-31 11:41:19 -0700592
593// give me the package name, perhaps going to find it
Ray Essick92d23b42018-01-29 12:10:30 -0800594// manages its own mutex operations internally
595void MediaAnalyticsService::setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion)
596{
Ray Essickfa149562017-09-19 09:27:31 -0700597 ALOGV("asking for packagename to go with uid=%d", uid);
598
599 if (!setName && !setVersion) {
600 // setting nothing? strange
601 return;
602 }
603
604 nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
605 struct UidToPkgMap mapping;
Ray Essick92d23b42018-01-29 12:10:30 -0800606 mapping.uid = (uid_t)(-1);
Ray Essickfa149562017-09-19 09:27:31 -0700607
Ray Essick92d23b42018-01-29 12:10:30 -0800608 {
609 Mutex::Autolock _l(mLock_mappings);
610 int i = mPkgMappings.indexOfKey(uid);
611 if (i >= 0) {
612 mapping = mPkgMappings.valueAt(i);
613 ALOGV("Expiration? uid %d expiration %" PRId64 " now %" PRId64,
614 uid, mapping.expiration, now);
615 if (mapping.expiration <= now) {
616 // purge the stale entry and fall into re-fetching
617 ALOGV("entry for uid %d expired, now= %" PRId64 "", uid, now);
618 mPkgMappings.removeItemsAt(i);
619 mapping.uid = (uid_t)(-1);
620 }
Ray Essickf65f4212017-08-31 11:41:19 -0700621 }
Ray Essick92d23b42018-01-29 12:10:30 -0800622 }
623
624 // if we did not find it
625 if (mapping.uid == (uid_t)(-1)) {
Ray Essick783bd0d2018-01-11 11:10:35 -0800626 std::string pkg;
Ray Essickfa149562017-09-19 09:27:31 -0700627 std::string installer = "";
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800628 int64_t versionCode = 0;
Ray Essickf65f4212017-08-31 11:41:19 -0700629
Ray Essickfa149562017-09-19 09:27:31 -0700630 struct passwd *pw = getpwuid(uid);
631 if (pw) {
632 pkg = pw->pw_name;
633 }
Ray Essickf65f4212017-08-31 11:41:19 -0700634
Ray Essick92d23b42018-01-29 12:10:30 -0800635 // find the proper value
Ray Essickf65f4212017-08-31 11:41:19 -0700636
Ray Essickfa149562017-09-19 09:27:31 -0700637 sp<IBinder> binder = NULL;
638 sp<IServiceManager> sm = defaultServiceManager();
639 if (sm == NULL) {
640 ALOGE("defaultServiceManager failed");
Ray Essickf65f4212017-08-31 11:41:19 -0700641 } else {
Ray Essickfa149562017-09-19 09:27:31 -0700642 binder = sm->getService(String16("package_native"));
643 if (binder == NULL) {
644 ALOGE("getService package_native failed");
645 }
646 }
647
648 if (binder != NULL) {
Ray Essick4f5d6fd2019-03-14 09:38:22 -0700649 sp<content::pm::IPackageManagerNative> package_mgr =
650 interface_cast<content::pm::IPackageManagerNative>(binder);
Ray Essickfa149562017-09-19 09:27:31 -0700651 binder::Status status;
652
653 std::vector<int> uids;
654 std::vector<std::string> names;
655
656 uids.push_back(uid);
657
658 status = package_mgr->getNamesForUids(uids, &names);
659 if (!status.isOk()) {
660 ALOGE("package_native::getNamesForUids failed: %s",
661 status.exceptionMessage().c_str());
662 } else {
663 if (!names[0].empty()) {
664 pkg = names[0].c_str();
665 }
666 }
667
668 // strip any leading "shared:" strings that came back
Ray Essick783bd0d2018-01-11 11:10:35 -0800669 if (pkg.compare(0, 7, "shared:") == 0) {
Ray Essickfa149562017-09-19 09:27:31 -0700670 pkg.erase(0, 7);
671 }
672
673 // determine how pkg was installed and the versionCode
674 //
675 if (pkg.empty()) {
676 // no name for us to manage
677 } else if (strchr(pkg.c_str(), '.') == NULL) {
678 // not of form 'com.whatever...'; assume internal and ok
679 } else if (strncmp(pkg.c_str(), "android.", 8) == 0) {
680 // android.* packages are assumed fine
681 } else {
682 String16 pkgName16(pkg.c_str());
683 status = package_mgr->getInstallerForPackage(pkgName16, &installer);
684 if (!status.isOk()) {
685 ALOGE("package_native::getInstallerForPackage failed: %s",
686 status.exceptionMessage().c_str());
687 }
688
689 // skip if we didn't get an installer
690 if (status.isOk()) {
691 status = package_mgr->getVersionCodeForPackage(pkgName16, &versionCode);
692 if (!status.isOk()) {
693 ALOGE("package_native::getVersionCodeForPackage failed: %s",
694 status.exceptionMessage().c_str());
695 }
696 }
697
698
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800699 ALOGV("package '%s' installed by '%s' versioncode %" PRId64 " / %" PRIx64,
Ray Essickfa149562017-09-19 09:27:31 -0700700 pkg.c_str(), installer.c_str(), versionCode, versionCode);
701
702 if (strncmp(installer.c_str(), "com.android.", 12) == 0) {
703 // from play store, we keep info
704 } else if (strncmp(installer.c_str(), "com.google.", 11) == 0) {
705 // some google source, we keep info
706 } else if (strcmp(installer.c_str(), "preload") == 0) {
707 // preloads, we keep the info
708 } else if (installer.c_str()[0] == '\0') {
709 // sideload (no installer); do not report
710 pkg = "";
711 versionCode = 0;
712 } else {
713 // unknown installer; do not report
714 pkg = "";
715 versionCode = 0;
716 }
717 }
718 }
719
720 // add it to the map, to save a subsequent lookup
721 if (!pkg.empty()) {
722 Mutex::Autolock _l(mLock_mappings);
723 ALOGV("Adding uid %d pkg '%s'", uid, pkg.c_str());
724 ssize_t i = mPkgMappings.indexOfKey(uid);
725 if (i < 0) {
726 mapping.uid = uid;
727 mapping.pkg = pkg;
728 mapping.installer = installer.c_str();
729 mapping.versionCode = versionCode;
730 mapping.expiration = now + PKG_EXPIRATION_NS;
731 ALOGV("expiration for uid %d set to %" PRId64 "", uid, mapping.expiration);
732
733 mPkgMappings.add(uid, mapping);
Ray Essickf65f4212017-08-31 11:41:19 -0700734 }
735 }
736 }
737
Ray Essickfa149562017-09-19 09:27:31 -0700738 if (mapping.uid != (uid_t)(-1)) {
739 if (setName) {
740 item->setPkgName(mapping.pkg);
741 }
742 if (setVersion) {
743 item->setPkgVersionCode(mapping.versionCode);
Ray Essickf65f4212017-08-31 11:41:19 -0700744 }
745 }
Ray Essickf65f4212017-08-31 11:41:19 -0700746}
747
Ray Essick3938dc62016-11-01 08:56:56 -0700748} // namespace android