blob: ae832bad15307dc10a57038e3e8856abb2a5f8d5 [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
54#include <media/AudioPolicyHelper.h>
55#include <media/IMediaHTTPService.h>
56#include <media/IRemoteDisplay.h>
57#include <media/IRemoteDisplayClient.h>
58#include <media/MediaPlayerInterface.h>
59#include <media/mediarecorder.h>
60#include <media/MediaMetadataRetrieverInterface.h>
61#include <media/Metadata.h>
62#include <media/AudioTrack.h>
63#include <media/MemoryLeakTrackUtil.h>
64#include <media/stagefright/MediaCodecList.h>
65#include <media/stagefright/MediaErrors.h>
66#include <media/stagefright/Utils.h>
67#include <media/stagefright/foundation/ADebug.h>
68#include <media/stagefright/foundation/ALooperRoster.h>
69#include <mediautils/BatteryNotifier.h>
70
71//#include <memunreachable/memunreachable.h>
72#include <system/audio.h>
73
74#include <private/android_filesystem_config.h>
75
76#include "MediaAnalyticsService.h"
77
Ray Essick3938dc62016-11-01 08:56:56 -070078namespace android {
79
Ray Essickf65f4212017-08-31 11:41:19 -070080 using namespace android::base;
81 using namespace android::content::pm;
82
Ray Essickf65f4212017-08-31 11:41:19 -070083// individual records kept in memory: age or count
Ray Essick72a436b2018-06-14 15:08:13 -070084// age: <= 28 hours (1 1/6 days)
Ray Essickf65f4212017-08-31 11:41:19 -070085// count: hard limit of # records
86// (0 for either of these disables that threshold)
Ray Essick72a436b2018-06-14 15:08:13 -070087//
88static constexpr nsecs_t kMaxRecordAgeNs = 28 * 3600 * (1000*1000*1000ll);
89static constexpr int kMaxRecords = 0;
90
91// max we expire in a single call, to constrain how long we hold the
92// mutex, which also constrains how long a client might wait.
93static constexpr int kMaxExpiredAtOnce = 50;
94
95// TODO: need to look at tuning kMaxRecords and friends for low-memory devices
Ray Essick2e9c63b2017-03-29 15:16:44 -070096
97static const char *kServiceName = "media.metrics";
98
Ray Essick3938dc62016-11-01 08:56:56 -070099void MediaAnalyticsService::instantiate() {
100 defaultServiceManager()->addService(
Ray Essick2e9c63b2017-03-29 15:16:44 -0700101 String16(kServiceName), new MediaAnalyticsService());
Ray Essick3938dc62016-11-01 08:56:56 -0700102}
103
Ray Essick3938dc62016-11-01 08:56:56 -0700104MediaAnalyticsService::MediaAnalyticsService()
Ray Essick2e9c63b2017-03-29 15:16:44 -0700105 : mMaxRecords(kMaxRecords),
Ray Essickf65f4212017-08-31 11:41:19 -0700106 mMaxRecordAgeNs(kMaxRecordAgeNs),
Ray Essick72a436b2018-06-14 15:08:13 -0700107 mMaxRecordsExpiredAtOnce(kMaxExpiredAtOnce),
Ray Essick583a23a2017-11-27 12:49:57 -0800108 mDumpProto(MediaAnalyticsItem::PROTO_V1),
109 mDumpProtoDefault(MediaAnalyticsItem::PROTO_V1) {
Ray Essick3938dc62016-11-01 08:56:56 -0700110
111 ALOGD("MediaAnalyticsService created");
Ray Essick3938dc62016-11-01 08:56:56 -0700112
113 mItemsSubmitted = 0;
114 mItemsFinalized = 0;
115 mItemsDiscarded = 0;
Ray Essickf65f4212017-08-31 11:41:19 -0700116 mItemsDiscardedExpire = 0;
117 mItemsDiscardedCount = 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700118
119 mLastSessionID = 0;
120 // recover any persistency we set up
121 // etc
122}
123
124MediaAnalyticsService::~MediaAnalyticsService() {
125 ALOGD("MediaAnalyticsService destroyed");
126
Ray Essick92d23b42018-01-29 12:10:30 -0800127 while (mItems.size() > 0) {
128 MediaAnalyticsItem * oitem = *(mItems.begin());
129 mItems.erase(mItems.begin());
Ray Essickf65f4212017-08-31 11:41:19 -0700130 delete oitem;
131 mItemsDiscarded++;
132 mItemsDiscardedCount++;
133 }
Ray Essick3938dc62016-11-01 08:56:56 -0700134}
135
136
137MediaAnalyticsItem::SessionID_t MediaAnalyticsService::generateUniqueSessionID() {
138 // generate a new sessionid
139
140 Mutex::Autolock _l(mLock_ids);
141 return (++mLastSessionID);
142}
143
Ray Essickb5fac8e2016-12-12 11:33:56 -0800144// caller surrenders ownership of 'item'
Ray Essick92d23b42018-01-29 12:10:30 -0800145MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem *item, bool forcenew)
146{
147 UNUSED(forcenew);
Ray Essick3938dc62016-11-01 08:56:56 -0700148
Ray Essick92d23b42018-01-29 12:10:30 -0800149 // fill in a sessionID if we do not yet have one
150 if (item->getSessionID() <= MediaAnalyticsItem::SessionIDNone) {
151 item->setSessionID(generateUniqueSessionID());
152 }
Ray Essick3938dc62016-11-01 08:56:56 -0700153
Ray Essickd38e1742017-01-23 15:17:06 -0800154 // we control these, generally not trusting user input
Ray Essick3938dc62016-11-01 08:56:56 -0700155 nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
Ray Essick721b7a02017-09-11 09:33:56 -0700156 // round nsecs to seconds
157 now = ((now + 500000000) / 1000000000) * 1000000000;
Ray Essick3938dc62016-11-01 08:56:56 -0700158 item->setTimestamp(now);
159 int pid = IPCThreadState::self()->getCallingPid();
Ray Essick3938dc62016-11-01 08:56:56 -0700160 int uid = IPCThreadState::self()->getCallingUid();
Ray Essickd38e1742017-01-23 15:17:06 -0800161
162 int uid_given = item->getUid();
163 int pid_given = item->getPid();
164
Ray Essick92d23b42018-01-29 12:10:30 -0800165 // although we do make exceptions for some trusted client uids
Ray Essickd38e1742017-01-23 15:17:06 -0800166 bool isTrusted = false;
167
Ray Essickf65f4212017-08-31 11:41:19 -0700168 ALOGV("caller has uid=%d, embedded uid=%d", uid, uid_given);
169
Ray Essickd38e1742017-01-23 15:17:06 -0800170 switch (uid) {
171 case AID_MEDIA:
172 case AID_MEDIA_CODEC:
173 case AID_MEDIA_EX:
174 case AID_MEDIA_DRM:
175 // trusted source, only override default values
Ray Essickf65f4212017-08-31 11:41:19 -0700176 isTrusted = true;
Ray Essickd38e1742017-01-23 15:17:06 -0800177 if (uid_given == (-1)) {
178 item->setUid(uid);
179 }
180 if (pid_given == (-1)) {
181 item->setPid(pid);
182 }
183 break;
184 default:
185 isTrusted = false;
186 item->setPid(pid);
187 item->setUid(uid);
188 break;
189 }
190
Adam Stone21c72122017-09-05 19:02:06 -0700191 // Overwrite package name and version if the caller was untrusted.
192 if (!isTrusted) {
Ray Essickfa149562017-09-19 09:27:31 -0700193 setPkgInfo(item, item->getUid(), true, true);
Adam Stone21c72122017-09-05 19:02:06 -0700194 } else if (item->getPkgName().empty()) {
Ray Essickfa149562017-09-19 09:27:31 -0700195 // empty, so fill out both parts
196 setPkgInfo(item, item->getUid(), true, true);
197 } else {
198 // trusted, provided a package, do nothing
Adam Stone21c72122017-09-05 19:02:06 -0700199 }
200
201 ALOGV("given uid %d; sanitized uid: %d sanitized pkg: %s "
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800202 "sanitized pkg version: %" PRId64,
Adam Stone21c72122017-09-05 19:02:06 -0700203 uid_given, item->getUid(),
204 item->getPkgName().c_str(),
205 item->getPkgVersionCode());
Ray Essick3938dc62016-11-01 08:56:56 -0700206
207 mItemsSubmitted++;
208
209 // validate the record; we discard if we don't like it
Ray Essickd38e1742017-01-23 15:17:06 -0800210 if (contentValid(item, isTrusted) == false) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800211 delete item;
Ray Essick3938dc62016-11-01 08:56:56 -0700212 return MediaAnalyticsItem::SessionIDInvalid;
213 }
214
Ray Essick92d23b42018-01-29 12:10:30 -0800215 // XXX: if we have a sessionid in the new record, look to make
Ray Essick3938dc62016-11-01 08:56:56 -0700216 // sure it doesn't appear in the finalized list.
217 // XXX: this is for security / DOS prevention.
218 // may also require that we persist the unique sessionIDs
219 // across boots [instead of within a single boot]
220
Ray Essick92d23b42018-01-29 12:10:30 -0800221 if (item->count() == 0) {
222 // drop empty records
223 delete item;
224 item = NULL;
225 return MediaAnalyticsItem::SessionIDInvalid;
Ray Essick3938dc62016-11-01 08:56:56 -0700226 }
Ray Essick92d23b42018-01-29 12:10:30 -0800227
228 // save the new record
229 MediaAnalyticsItem::SessionID_t id = item->getSessionID();
230 saveItem(item);
231 mItemsFinalized++;
Ray Essick3938dc62016-11-01 08:56:56 -0700232 return id;
233}
234
Ray Essickf65f4212017-08-31 11:41:19 -0700235
Ray Essickb5fac8e2016-12-12 11:33:56 -0800236status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
Ray Essick3938dc62016-11-01 08:56:56 -0700237{
Ray Essickb5fac8e2016-12-12 11:33:56 -0800238 const size_t SIZE = 512;
Ray Essick3938dc62016-11-01 08:56:56 -0700239 char buffer[SIZE];
240 String8 result;
241
242 if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
243 snprintf(buffer, SIZE, "Permission Denial: "
244 "can't dump MediaAnalyticsService from pid=%d, uid=%d\n",
245 IPCThreadState::self()->getCallingPid(),
246 IPCThreadState::self()->getCallingUid());
247 result.append(buffer);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800248 write(fd, result.string(), result.size());
249 return NO_ERROR;
Ray Essick3938dc62016-11-01 08:56:56 -0700250 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800251
252 // crack any parameters
Ray Essickf65f4212017-08-31 11:41:19 -0700253 String16 protoOption("-proto");
Ray Essick583a23a2017-11-27 12:49:57 -0800254 int chosenProto = mDumpProtoDefault;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800255 String16 clearOption("-clear");
Ray Essickf65f4212017-08-31 11:41:19 -0700256 bool clear = false;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800257 String16 sinceOption("-since");
Ray Essickf65f4212017-08-31 11:41:19 -0700258 nsecs_t ts_since = 0;
Ray Essick35ad27f2017-01-30 14:04:11 -0800259 String16 helpOption("-help");
Ray Essick2e9c63b2017-03-29 15:16:44 -0700260 String16 onlyOption("-only");
Ray Essick783bd0d2018-01-11 11:10:35 -0800261 std::string only;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800262 int n = args.size();
Ray Essickf65f4212017-08-31 11:41:19 -0700263
Ray Essickb5fac8e2016-12-12 11:33:56 -0800264 for (int i = 0; i < n; i++) {
265 String8 myarg(args[i]);
266 if (args[i] == clearOption) {
267 clear = true;
Ray Essickf65f4212017-08-31 11:41:19 -0700268 } else if (args[i] == protoOption) {
269 i++;
270 if (i < n) {
271 String8 value(args[i]);
Ray Essick583a23a2017-11-27 12:49:57 -0800272 int proto = MediaAnalyticsItem::PROTO_V0;
Ray Essickf65f4212017-08-31 11:41:19 -0700273 char *endp;
274 const char *p = value.string();
275 proto = strtol(p, &endp, 10);
276 if (endp != p || *endp == '\0') {
277 if (proto < MediaAnalyticsItem::PROTO_FIRST) {
278 proto = MediaAnalyticsItem::PROTO_FIRST;
279 } else if (proto > MediaAnalyticsItem::PROTO_LAST) {
280 proto = MediaAnalyticsItem::PROTO_LAST;
281 }
Ray Essick583a23a2017-11-27 12:49:57 -0800282 chosenProto = proto;
283 } else {
284 result.append("unable to parse value for -proto\n\n");
Ray Essickf65f4212017-08-31 11:41:19 -0700285 }
Ray Essick583a23a2017-11-27 12:49:57 -0800286 } else {
287 result.append("missing value for -proto\n\n");
Ray Essickf65f4212017-08-31 11:41:19 -0700288 }
Ray Essickb5fac8e2016-12-12 11:33:56 -0800289 } else if (args[i] == sinceOption) {
290 i++;
291 if (i < n) {
292 String8 value(args[i]);
293 char *endp;
294 const char *p = value.string();
295 ts_since = strtoll(p, &endp, 10);
296 if (endp == p || *endp != '\0') {
297 ts_since = 0;
298 }
299 } else {
300 ts_since = 0;
301 }
Ray Essick35ad27f2017-01-30 14:04:11 -0800302 // command line is milliseconds; internal units are nano-seconds
303 ts_since *= 1000*1000;
Ray Essick2e9c63b2017-03-29 15:16:44 -0700304 } else if (args[i] == onlyOption) {
305 i++;
306 if (i < n) {
307 String8 value(args[i]);
Ray Essickf65f4212017-08-31 11:41:19 -0700308 only = value.string();
Ray Essick2e9c63b2017-03-29 15:16:44 -0700309 }
Ray Essick35ad27f2017-01-30 14:04:11 -0800310 } else if (args[i] == helpOption) {
311 result.append("Recognized parameters:\n");
312 result.append("-help this help message\n");
Ray Essick583a23a2017-11-27 12:49:57 -0800313 result.append("-proto # dump using protocol #");
Ray Essick35ad27f2017-01-30 14:04:11 -0800314 result.append("-clear clears out saved records\n");
Ray Essick2e9c63b2017-03-29 15:16:44 -0700315 result.append("-only X process records for component X\n");
316 result.append("-since X include records since X\n");
317 result.append(" (X is milliseconds since the UNIX epoch)\n");
Ray Essick35ad27f2017-01-30 14:04:11 -0800318 write(fd, result.string(), result.size());
319 return NO_ERROR;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800320 }
321 }
322
323 Mutex::Autolock _l(mLock);
Ray Essick92d23b42018-01-29 12:10:30 -0800324 // mutex between insertion and dumping the contents
Ray Essickb5fac8e2016-12-12 11:33:56 -0800325
Ray Essick583a23a2017-11-27 12:49:57 -0800326 mDumpProto = chosenProto;
327
Ray Essick2e9c63b2017-03-29 15:16:44 -0700328 // we ALWAYS dump this piece
329 snprintf(buffer, SIZE, "Dump of the %s process:\n", kServiceName);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800330 result.append(buffer);
331
Ray Essick2e9c63b2017-03-29 15:16:44 -0700332 dumpHeaders(result, ts_since);
333
Ray Essick813b1b82018-01-16 15:10:06 -0800334 dumpRecent(result, ts_since, only.c_str());
Ray Essick2e9c63b2017-03-29 15:16:44 -0700335
336
337 if (clear) {
338 // remove everything from the finalized queue
Ray Essick92d23b42018-01-29 12:10:30 -0800339 while (mItems.size() > 0) {
340 MediaAnalyticsItem * oitem = *(mItems.begin());
341 mItems.erase(mItems.begin());
Ray Essick2e9c63b2017-03-29 15:16:44 -0700342 delete oitem;
343 mItemsDiscarded++;
344 }
345
346 // shall we clear the summary data too?
347
348 }
349
350 write(fd, result.string(), result.size());
351 return NO_ERROR;
352}
353
354// dump headers
Ray Essick92d23b42018-01-29 12:10:30 -0800355void MediaAnalyticsService::dumpHeaders(String8 &result, nsecs_t ts_since)
356{
Ray Essick2e9c63b2017-03-29 15:16:44 -0700357 const size_t SIZE = 512;
358 char buffer[SIZE];
359
Ray Essickf65f4212017-08-31 11:41:19 -0700360 snprintf(buffer, SIZE, "Protocol Version: %d\n", mDumpProto);
361 result.append(buffer);
362
Ray Essickb5fac8e2016-12-12 11:33:56 -0800363 int enabled = MediaAnalyticsItem::isEnabled();
364 if (enabled) {
Ray Essickd38e1742017-01-23 15:17:06 -0800365 snprintf(buffer, SIZE, "Metrics gathering: enabled\n");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800366 } else {
Ray Essickd38e1742017-01-23 15:17:06 -0800367 snprintf(buffer, SIZE, "Metrics gathering: DISABLED via property\n");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800368 }
369 result.append(buffer);
370
371 snprintf(buffer, SIZE,
Ray Essickf65f4212017-08-31 11:41:19 -0700372 "Since Boot: Submissions: %8" PRId64
Ray Essick92d23b42018-01-29 12:10:30 -0800373 " Accepted: %8" PRId64 "\n",
Ray Essickf65f4212017-08-31 11:41:19 -0700374 mItemsSubmitted, mItemsFinalized);
375 result.append(buffer);
376 snprintf(buffer, SIZE,
377 "Records Discarded: %8" PRId64
378 " (by Count: %" PRId64 " by Expiration: %" PRId64 ")\n",
379 mItemsDiscarded, mItemsDiscardedCount, mItemsDiscardedExpire);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800380 result.append(buffer);
381 if (ts_since != 0) {
382 snprintf(buffer, SIZE,
Ray Essick92d23b42018-01-29 12:10:30 -0800383 "Emitting Queue entries more recent than: %" PRId64 "\n",
Ray Essickb5fac8e2016-12-12 11:33:56 -0800384 (int64_t) ts_since);
385 result.append(buffer);
386 }
Ray Essick2e9c63b2017-03-29 15:16:44 -0700387}
388
Ray Essick2e9c63b2017-03-29 15:16:44 -0700389// the recent, detailed queues
Ray Essick92d23b42018-01-29 12:10:30 -0800390void MediaAnalyticsService::dumpRecent(String8 &result, nsecs_t ts_since, const char * only)
391{
Ray Essick2e9c63b2017-03-29 15:16:44 -0700392 const size_t SIZE = 512;
393 char buffer[SIZE];
Ray Essickb5fac8e2016-12-12 11:33:56 -0800394
Ray Essickf65f4212017-08-31 11:41:19 -0700395 if (only != NULL && *only == '\0') {
396 only = NULL;
397 }
398
Ray Essickb5fac8e2016-12-12 11:33:56 -0800399 // show the recently recorded records
Ray Essickd38e1742017-01-23 15:17:06 -0800400 snprintf(buffer, sizeof(buffer), "\nFinalized Metrics (oldest first):\n");
Ray Essickb5fac8e2016-12-12 11:33:56 -0800401 result.append(buffer);
Ray Essick92d23b42018-01-29 12:10:30 -0800402 result.append(this->dumpQueue(ts_since, only));
Ray Essickb5fac8e2016-12-12 11:33:56 -0800403
404 // show who is connected and injecting records?
405 // talk about # records fed to the 'readers'
406 // talk about # records we discarded, perhaps "discarded w/o reading" too
Ray Essick3938dc62016-11-01 08:56:56 -0700407}
Ray Essick92d23b42018-01-29 12:10:30 -0800408
Ray Essick3938dc62016-11-01 08:56:56 -0700409// caller has locked mLock...
Ray Essick92d23b42018-01-29 12:10:30 -0800410String8 MediaAnalyticsService::dumpQueue() {
411 return dumpQueue((nsecs_t) 0, NULL);
Ray Essickb5fac8e2016-12-12 11:33:56 -0800412}
413
Ray Essick92d23b42018-01-29 12:10:30 -0800414String8 MediaAnalyticsService::dumpQueue(nsecs_t ts_since, const char * only) {
Ray Essick3938dc62016-11-01 08:56:56 -0700415 String8 result;
416 int slot = 0;
417
Ray Essick92d23b42018-01-29 12:10:30 -0800418 if (mItems.empty()) {
Ray Essick3938dc62016-11-01 08:56:56 -0700419 result.append("empty\n");
420 } else {
Ray Essick92d23b42018-01-29 12:10:30 -0800421 List<MediaAnalyticsItem *>::iterator it = mItems.begin();
422 for (; it != mItems.end(); it++) {
Ray Essickb5fac8e2016-12-12 11:33:56 -0800423 nsecs_t when = (*it)->getTimestamp();
424 if (when < ts_since) {
425 continue;
426 }
Ray Essick2e9c63b2017-03-29 15:16:44 -0700427 if (only != NULL &&
428 strcmp(only, (*it)->getKey().c_str()) != 0) {
429 ALOGV("Omit '%s', it's not '%s'", (*it)->getKey().c_str(), only);
430 continue;
431 }
Ray Essick783bd0d2018-01-11 11:10:35 -0800432 std::string entry = (*it)->toString(mDumpProto);
Ray Essick35ad27f2017-01-30 14:04:11 -0800433 result.appendFormat("%5d: %s\n", slot, entry.c_str());
Ray Essickb5fac8e2016-12-12 11:33:56 -0800434 slot++;
Ray Essick3938dc62016-11-01 08:56:56 -0700435 }
436 }
437
438 return result;
439}
440
441//
442// Our Cheap in-core, non-persistent records management.
Ray Essick3938dc62016-11-01 08:56:56 -0700443
Ray Essick72a436b2018-06-14 15:08:13 -0700444
445// we hold mLock when we get here
446// if item != NULL, it's the item we just inserted
447// true == more items eligible to be recovered
448bool MediaAnalyticsService::expirations_l(MediaAnalyticsItem *item)
Ray Essick92d23b42018-01-29 12:10:30 -0800449{
Ray Essick72a436b2018-06-14 15:08:13 -0700450 bool more = false;
451 int handled = 0;
Ray Essicke5db6db2017-11-10 15:54:32 -0800452
Ray Essickf65f4212017-08-31 11:41:19 -0700453 // keep removing old records the front until we're in-bounds (count)
Ray Essick72a436b2018-06-14 15:08:13 -0700454 // since we invoke this with each insertion, it should be 0/1 iterations.
Ray Essick3938dc62016-11-01 08:56:56 -0700455 if (mMaxRecords > 0) {
Ray Essick92d23b42018-01-29 12:10:30 -0800456 while (mItems.size() > (size_t) mMaxRecords) {
457 MediaAnalyticsItem * oitem = *(mItems.begin());
Ray Essicke5db6db2017-11-10 15:54:32 -0800458 if (oitem == item) {
459 break;
460 }
Ray Essick72a436b2018-06-14 15:08:13 -0700461 if (handled >= mMaxRecordsExpiredAtOnce) {
462 // unlikely in this loop
463 more = true;
464 break;
465 }
466 handled++;
Ray Essick92d23b42018-01-29 12:10:30 -0800467 mItems.erase(mItems.begin());
Ray Essickb5fac8e2016-12-12 11:33:56 -0800468 delete oitem;
Ray Essickb5fac8e2016-12-12 11:33:56 -0800469 mItemsDiscarded++;
Ray Essickf65f4212017-08-31 11:41:19 -0700470 mItemsDiscardedCount++;
471 }
472 }
473
Ray Essick72a436b2018-06-14 15:08:13 -0700474 // keep removing old records the front until we're in-bounds (age)
475 // limited to mMaxRecordsExpiredAtOnce items per invocation.
Ray Essickf65f4212017-08-31 11:41:19 -0700476 if (mMaxRecordAgeNs > 0) {
477 nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
Ray Essick92d23b42018-01-29 12:10:30 -0800478 while (mItems.size() > 0) {
479 MediaAnalyticsItem * oitem = *(mItems.begin());
Ray Essickf65f4212017-08-31 11:41:19 -0700480 nsecs_t when = oitem->getTimestamp();
Ray Essicke5db6db2017-11-10 15:54:32 -0800481 if (oitem == item) {
482 break;
483 }
Ray Essickf65f4212017-08-31 11:41:19 -0700484 // careful about timejumps too
485 if ((now > when) && (now-when) <= mMaxRecordAgeNs) {
486 // this (and the rest) are recent enough to keep
487 break;
488 }
Ray Essick72a436b2018-06-14 15:08:13 -0700489 if (handled >= mMaxRecordsExpiredAtOnce) {
490 // this represents "one too many"; tell caller there are
491 // more to be reclaimed.
492 more = true;
493 break;
494 }
495 handled++;
Ray Essick92d23b42018-01-29 12:10:30 -0800496 mItems.erase(mItems.begin());
Ray Essickf65f4212017-08-31 11:41:19 -0700497 delete oitem;
498 mItemsDiscarded++;
499 mItemsDiscardedExpire++;
Ray Essick3938dc62016-11-01 08:56:56 -0700500 }
501 }
Ray Essick72a436b2018-06-14 15:08:13 -0700502
503 // we only indicate whether there's more to clean;
504 // caller chooses whether to schedule further cleanup.
505 return more;
506}
507
508// process expirations in bite sized chunks, allowing new insertions through
509// runs in a pthread specifically started for this (which then exits)
510bool MediaAnalyticsService::processExpirations()
511{
512 bool more;
513 do {
514 sleep(1);
515 {
516 Mutex::Autolock _l(mLock);
517 more = expirations_l(NULL);
518 if (!more) {
519 break;
520 }
521 }
522 } while (more);
523 return true; // value is for std::future thread synchronization
524}
525
526// insert appropriately into queue
527void MediaAnalyticsService::saveItem(MediaAnalyticsItem * item)
528{
529
530 Mutex::Autolock _l(mLock);
531 // mutex between insertion and dumping the contents
532
533 // we want to dump 'in FIFO order', so insert at the end
534 mItems.push_back(item);
535
536 // clean old stuff from the queue
537 bool more = expirations_l(item);
538
539 // consider scheduling some asynchronous cleaning, if not running
540 if (more) {
541 if (!mExpireFuture.valid()
542 || mExpireFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
543
544 mExpireFuture = std::async(std::launch::async, [this]()
545 {return this->processExpirations();});
546 }
547 }
Ray Essick3938dc62016-11-01 08:56:56 -0700548}
549
Ray Essick783bd0d2018-01-11 11:10:35 -0800550static std::string allowedKeys[] =
Ray Essickd38e1742017-01-23 15:17:06 -0800551{
Ray Essick84e84a52018-05-03 18:45:07 -0700552 "audiopolicy",
Ray Essick8c22cb12018-01-24 11:00:36 -0800553 "audiorecord",
Eric Tanbc2a7732018-09-06 12:04:44 -0700554 "audiothread",
Ray Essick8c22cb12018-01-24 11:00:36 -0800555 "audiotrack",
Ray Essickd38e1742017-01-23 15:17:06 -0800556 "codec",
Ray Essick8c22cb12018-01-24 11:00:36 -0800557 "extractor",
558 "nuplayer",
Ray Essickd38e1742017-01-23 15:17:06 -0800559};
Ray Essick3938dc62016-11-01 08:56:56 -0700560
Ray Essickd38e1742017-01-23 15:17:06 -0800561static const int nAllowedKeys = sizeof(allowedKeys) / sizeof(allowedKeys[0]);
562
563// are the contents good
564bool MediaAnalyticsService::contentValid(MediaAnalyticsItem *item, bool isTrusted) {
565
566 // untrusted uids can only send us a limited set of keys
567 if (isTrusted == false) {
568 // restrict to a specific set of keys
Ray Essick783bd0d2018-01-11 11:10:35 -0800569 std::string key = item->getKey();
Ray Essickd38e1742017-01-23 15:17:06 -0800570
571 size_t i;
572 for(i = 0; i < nAllowedKeys; i++) {
573 if (key == allowedKeys[i]) {
574 break;
575 }
576 }
577 if (i == nAllowedKeys) {
578 ALOGD("Ignoring (key): %s", item->toString().c_str());
579 return false;
580 }
581 }
582
Ray Essick3938dc62016-11-01 08:56:56 -0700583 // internal consistency
584
585 return true;
586}
587
588// are we rate limited, normally false
Ray Essickb5fac8e2016-12-12 11:33:56 -0800589bool MediaAnalyticsService::rateLimited(MediaAnalyticsItem *) {
Ray Essick3938dc62016-11-01 08:56:56 -0700590
591 return false;
592}
593
Ray Essickfa149562017-09-19 09:27:31 -0700594// how long we hold package info before we re-fetch it
595#define PKG_EXPIRATION_NS (30*60*1000000000ll) // 30 minutes, in nsecs
Ray Essickf65f4212017-08-31 11:41:19 -0700596
597// give me the package name, perhaps going to find it
Ray Essick92d23b42018-01-29 12:10:30 -0800598// manages its own mutex operations internally
599void MediaAnalyticsService::setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion)
600{
Ray Essickfa149562017-09-19 09:27:31 -0700601 ALOGV("asking for packagename to go with uid=%d", uid);
602
603 if (!setName && !setVersion) {
604 // setting nothing? strange
605 return;
606 }
607
608 nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
609 struct UidToPkgMap mapping;
Ray Essick92d23b42018-01-29 12:10:30 -0800610 mapping.uid = (uid_t)(-1);
Ray Essickfa149562017-09-19 09:27:31 -0700611
Ray Essick92d23b42018-01-29 12:10:30 -0800612 {
613 Mutex::Autolock _l(mLock_mappings);
614 int i = mPkgMappings.indexOfKey(uid);
615 if (i >= 0) {
616 mapping = mPkgMappings.valueAt(i);
617 ALOGV("Expiration? uid %d expiration %" PRId64 " now %" PRId64,
618 uid, mapping.expiration, now);
619 if (mapping.expiration <= now) {
620 // purge the stale entry and fall into re-fetching
621 ALOGV("entry for uid %d expired, now= %" PRId64 "", uid, now);
622 mPkgMappings.removeItemsAt(i);
623 mapping.uid = (uid_t)(-1);
624 }
Ray Essickf65f4212017-08-31 11:41:19 -0700625 }
Ray Essick92d23b42018-01-29 12:10:30 -0800626 }
627
628 // if we did not find it
629 if (mapping.uid == (uid_t)(-1)) {
Ray Essick783bd0d2018-01-11 11:10:35 -0800630 std::string pkg;
Ray Essickfa149562017-09-19 09:27:31 -0700631 std::string installer = "";
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800632 int64_t versionCode = 0;
Ray Essickf65f4212017-08-31 11:41:19 -0700633
Ray Essickfa149562017-09-19 09:27:31 -0700634 struct passwd *pw = getpwuid(uid);
635 if (pw) {
636 pkg = pw->pw_name;
637 }
Ray Essickf65f4212017-08-31 11:41:19 -0700638
Ray Essick92d23b42018-01-29 12:10:30 -0800639 // find the proper value
Ray Essickf65f4212017-08-31 11:41:19 -0700640
Ray Essickfa149562017-09-19 09:27:31 -0700641 sp<IBinder> binder = NULL;
642 sp<IServiceManager> sm = defaultServiceManager();
643 if (sm == NULL) {
644 ALOGE("defaultServiceManager failed");
Ray Essickf65f4212017-08-31 11:41:19 -0700645 } else {
Ray Essickfa149562017-09-19 09:27:31 -0700646 binder = sm->getService(String16("package_native"));
647 if (binder == NULL) {
648 ALOGE("getService package_native failed");
649 }
650 }
651
652 if (binder != NULL) {
653 sp<IPackageManagerNative> package_mgr = interface_cast<IPackageManagerNative>(binder);
654 binder::Status status;
655
656 std::vector<int> uids;
657 std::vector<std::string> names;
658
659 uids.push_back(uid);
660
661 status = package_mgr->getNamesForUids(uids, &names);
662 if (!status.isOk()) {
663 ALOGE("package_native::getNamesForUids failed: %s",
664 status.exceptionMessage().c_str());
665 } else {
666 if (!names[0].empty()) {
667 pkg = names[0].c_str();
668 }
669 }
670
671 // strip any leading "shared:" strings that came back
Ray Essick783bd0d2018-01-11 11:10:35 -0800672 if (pkg.compare(0, 7, "shared:") == 0) {
Ray Essickfa149562017-09-19 09:27:31 -0700673 pkg.erase(0, 7);
674 }
675
676 // determine how pkg was installed and the versionCode
677 //
678 if (pkg.empty()) {
679 // no name for us to manage
680 } else if (strchr(pkg.c_str(), '.') == NULL) {
681 // not of form 'com.whatever...'; assume internal and ok
682 } else if (strncmp(pkg.c_str(), "android.", 8) == 0) {
683 // android.* packages are assumed fine
684 } else {
685 String16 pkgName16(pkg.c_str());
686 status = package_mgr->getInstallerForPackage(pkgName16, &installer);
687 if (!status.isOk()) {
688 ALOGE("package_native::getInstallerForPackage failed: %s",
689 status.exceptionMessage().c_str());
690 }
691
692 // skip if we didn't get an installer
693 if (status.isOk()) {
694 status = package_mgr->getVersionCodeForPackage(pkgName16, &versionCode);
695 if (!status.isOk()) {
696 ALOGE("package_native::getVersionCodeForPackage failed: %s",
697 status.exceptionMessage().c_str());
698 }
699 }
700
701
Dianne Hackborn4e2eeff2017-11-27 14:01:29 -0800702 ALOGV("package '%s' installed by '%s' versioncode %" PRId64 " / %" PRIx64,
Ray Essickfa149562017-09-19 09:27:31 -0700703 pkg.c_str(), installer.c_str(), versionCode, versionCode);
704
705 if (strncmp(installer.c_str(), "com.android.", 12) == 0) {
706 // from play store, we keep info
707 } else if (strncmp(installer.c_str(), "com.google.", 11) == 0) {
708 // some google source, we keep info
709 } else if (strcmp(installer.c_str(), "preload") == 0) {
710 // preloads, we keep the info
711 } else if (installer.c_str()[0] == '\0') {
712 // sideload (no installer); do not report
713 pkg = "";
714 versionCode = 0;
715 } else {
716 // unknown installer; do not report
717 pkg = "";
718 versionCode = 0;
719 }
720 }
721 }
722
723 // add it to the map, to save a subsequent lookup
724 if (!pkg.empty()) {
725 Mutex::Autolock _l(mLock_mappings);
726 ALOGV("Adding uid %d pkg '%s'", uid, pkg.c_str());
727 ssize_t i = mPkgMappings.indexOfKey(uid);
728 if (i < 0) {
729 mapping.uid = uid;
730 mapping.pkg = pkg;
731 mapping.installer = installer.c_str();
732 mapping.versionCode = versionCode;
733 mapping.expiration = now + PKG_EXPIRATION_NS;
734 ALOGV("expiration for uid %d set to %" PRId64 "", uid, mapping.expiration);
735
736 mPkgMappings.add(uid, mapping);
Ray Essickf65f4212017-08-31 11:41:19 -0700737 }
738 }
739 }
740
Ray Essickfa149562017-09-19 09:27:31 -0700741 if (mapping.uid != (uid_t)(-1)) {
742 if (setName) {
743 item->setPkgName(mapping.pkg);
744 }
745 if (setVersion) {
746 item->setPkgVersionCode(mapping.versionCode);
Ray Essickf65f4212017-08-31 11:41:19 -0700747 }
748 }
Ray Essickf65f4212017-08-31 11:41:19 -0700749}
750
Ray Essick3938dc62016-11-01 08:56:56 -0700751} // namespace android