blob: ecb248d3aec6e339d6aac23ed4ef40de6d391fa7 [file] [log] [blame]
Ray Essick3938dc62016-11-01 08:56:56 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
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
Ray Essickf27e9872019-12-07 06:28:46 -080017#define LOG_TAG "mediametrics::Item"
Ray Essick3938dc62016-11-01 08:56:56 -070018
Ray Essick3938dc62016-11-01 08:56:56 -070019#include <inttypes.h>
Ray Essickb5fac8e2016-12-12 11:33:56 -080020#include <stdlib.h>
21#include <string.h>
22#include <sys/types.h>
Ray Essick3938dc62016-11-01 08:56:56 -070023
Andy Hunga87e69c2019-10-18 10:07:40 -070024#include <mutex>
Andy Hung3253f2d2019-10-21 14:50:07 -070025#include <set>
Andy Hung5088e1a2021-11-11 09:17:21 -080026#include <unordered_map>
Andy Hunga87e69c2019-10-18 10:07:40 -070027
Ray Essick3938dc62016-11-01 08:56:56 -070028#include <binder/Parcel.h>
Mark Punzalan3ebe1212022-05-17 08:15:49 +000029#include <cutils/multiuser.h>
Andy Hung7d391082020-04-18 15:03:51 -070030#include <cutils/properties.h>
Ray Essick3938dc62016-11-01 08:56:56 -070031#include <utils/Errors.h>
32#include <utils/Log.h>
Ray Essick3938dc62016-11-01 08:56:56 -070033#include <utils/SortedVector.h>
34#include <utils/threads.h>
35
Andy Hung49ca44e2020-11-10 22:14:58 -080036#include <android/media/BnMediaMetricsService.h> // for direct Binder access
37#include <android/media/IMediaMetricsService.h>
Ray Essick3938dc62016-11-01 08:56:56 -070038#include <binder/IServiceManager.h>
Ray Essickf27e9872019-12-07 06:28:46 -080039#include <media/MediaMetricsItem.h>
Ray Essick79a89ef2017-04-24 15:52:54 -070040#include <private/android_filesystem_config.h>
Ray Essick3938dc62016-11-01 08:56:56 -070041
Andy Hung1efc9c62019-12-03 13:43:33 -080042// Max per-property string size before truncation in toString().
43// Do not make too large, as this is used for dumpsys purposes.
44static constexpr size_t kMaxPropertyStringSize = 4096;
45
Ray Essickf27e9872019-12-07 06:28:46 -080046namespace android::mediametrics {
Ray Essick3938dc62016-11-01 08:56:56 -070047
48#define DEBUG_SERVICEACCESS 0
Ray Essickb5fac8e2016-12-12 11:33:56 -080049#define DEBUG_API 0
50#define DEBUG_ALLOCATIONS 0
51
52// after this many failed attempts, we stop trying [from this process] and just say that
53// the service is off.
54#define SVC_TRIES 2
Ray Essick3938dc62016-11-01 08:56:56 -070055
Andy Hung5088e1a2021-11-11 09:17:21 -080056static const std::unordered_map<std::string, int32_t>& getErrorStringMap() {
57 // DO NOT MODIFY VALUES (OK to add new ones).
58 // This may be found in frameworks/av/media/libmediametrics/include/MediaMetricsConstants.h
59 static std::unordered_map<std::string, int32_t> map{
60 {"", NO_ERROR},
Andy Hung73dc2f92021-12-07 21:50:04 -080061 {AMEDIAMETRICS_PROP_STATUS_VALUE_OK, NO_ERROR},
62 {AMEDIAMETRICS_PROP_STATUS_VALUE_ARGUMENT, BAD_VALUE},
63 {AMEDIAMETRICS_PROP_STATUS_VALUE_IO, DEAD_OBJECT},
64 {AMEDIAMETRICS_PROP_STATUS_VALUE_MEMORY, NO_MEMORY},
65 {AMEDIAMETRICS_PROP_STATUS_VALUE_SECURITY, PERMISSION_DENIED},
66 {AMEDIAMETRICS_PROP_STATUS_VALUE_STATE, INVALID_OPERATION},
67 {AMEDIAMETRICS_PROP_STATUS_VALUE_TIMEOUT, WOULD_BLOCK},
68 {AMEDIAMETRICS_PROP_STATUS_VALUE_UNKNOWN, UNKNOWN_ERROR},
Andy Hung5088e1a2021-11-11 09:17:21 -080069 };
70 return map;
71}
72
Andy Hung73dc2f92021-12-07 21:50:04 -080073status_t statusStringToStatus(const char *error) {
Andy Hung5088e1a2021-11-11 09:17:21 -080074 const auto& map = getErrorStringMap();
Greg Kaiser96206632021-11-29 06:52:17 -080075 if (error == nullptr || error[0] == '\0') return NO_ERROR;
Andy Hung5088e1a2021-11-11 09:17:21 -080076 auto it = map.find(error);
77 if (it != map.end()) {
78 return it->second;
79 }
80 return UNKNOWN_ERROR;
81}
82
Ray Essickf27e9872019-12-07 06:28:46 -080083mediametrics::Item* mediametrics::Item::convert(mediametrics_handle_t handle) {
84 mediametrics::Item *item = (android::mediametrics::Item *) handle;
Ray Essickbf536ac2019-08-26 11:04:28 -070085 return item;
86}
87
Ray Essickf27e9872019-12-07 06:28:46 -080088mediametrics_handle_t mediametrics::Item::convert(mediametrics::Item *item ) {
Ray Essickbf536ac2019-08-26 11:04:28 -070089 mediametrics_handle_t handle = (mediametrics_handle_t) item;
90 return handle;
91}
92
Ray Essickf27e9872019-12-07 06:28:46 -080093mediametrics::Item::~Item() {
Ray Essickb5fac8e2016-12-12 11:33:56 -080094 if (DEBUG_ALLOCATIONS) {
Ray Essickf27e9872019-12-07 06:28:46 -080095 ALOGD("Destroy mediametrics::Item @ %p", this);
Ray Essickb5fac8e2016-12-12 11:33:56 -080096 }
Ray Essickb5fac8e2016-12-12 11:33:56 -080097}
98
Ray Essickf27e9872019-12-07 06:28:46 -080099mediametrics::Item &mediametrics::Item::setTimestamp(nsecs_t ts) {
Ray Essick3938dc62016-11-01 08:56:56 -0700100 mTimestamp = ts;
101 return *this;
102}
103
Ray Essickf27e9872019-12-07 06:28:46 -0800104nsecs_t mediametrics::Item::getTimestamp() const {
Ray Essick3938dc62016-11-01 08:56:56 -0700105 return mTimestamp;
106}
107
Ray Essickf27e9872019-12-07 06:28:46 -0800108mediametrics::Item &mediametrics::Item::setPid(pid_t pid) {
Ray Essick3938dc62016-11-01 08:56:56 -0700109 mPid = pid;
110 return *this;
111}
112
Ray Essickf27e9872019-12-07 06:28:46 -0800113pid_t mediametrics::Item::getPid() const {
Ray Essick3938dc62016-11-01 08:56:56 -0700114 return mPid;
115}
116
Ray Essickf27e9872019-12-07 06:28:46 -0800117mediametrics::Item &mediametrics::Item::setUid(uid_t uid) {
Ray Essick3938dc62016-11-01 08:56:56 -0700118 mUid = uid;
119 return *this;
120}
121
Ray Essickf27e9872019-12-07 06:28:46 -0800122uid_t mediametrics::Item::getUid() const {
Ray Essick3938dc62016-11-01 08:56:56 -0700123 return mUid;
124}
125
Ray Essickf27e9872019-12-07 06:28:46 -0800126mediametrics::Item &mediametrics::Item::setPkgName(const std::string &pkgName) {
Ray Essickf65f4212017-08-31 11:41:19 -0700127 mPkgName = pkgName;
128 return *this;
129}
130
Ray Essickf27e9872019-12-07 06:28:46 -0800131mediametrics::Item &mediametrics::Item::setPkgVersionCode(int64_t pkgVersionCode) {
Ray Essickf65f4212017-08-31 11:41:19 -0700132 mPkgVersionCode = pkgVersionCode;
133 return *this;
134}
135
Ray Essickf27e9872019-12-07 06:28:46 -0800136int64_t mediametrics::Item::getPkgVersionCode() const {
Ray Essickf65f4212017-08-31 11:41:19 -0700137 return mPkgVersionCode;
138}
139
Ray Essick3938dc62016-11-01 08:56:56 -0700140// remove indicated keys and their values
141// return value is # keys removed
Ray Essickf27e9872019-12-07 06:28:46 -0800142size_t mediametrics::Item::filter(size_t n, const char *attrs[]) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700143 size_t zapped = 0;
144 for (size_t i = 0; i < n; ++i) {
Andy Hung47e58d62019-12-06 18:40:19 -0800145 zapped += mProps.erase(attrs[i]);
Ray Essick3938dc62016-11-01 08:56:56 -0700146 }
147 return zapped;
148}
149
150// remove any keys NOT in the provided list
151// return value is # keys removed
Ray Essickf27e9872019-12-07 06:28:46 -0800152size_t mediametrics::Item::filterNot(size_t n, const char *attrs[]) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700153 std::set<std::string> check(attrs, attrs + n);
154 size_t zapped = 0;
Andy Hung47e58d62019-12-06 18:40:19 -0800155 for (auto it = mProps.begin(); it != mProps.end();) {
156 if (check.find(it->first) != check.end()) {
157 ++it;
Andy Hung3253f2d2019-10-21 14:50:07 -0700158 } else {
Andy Hung47e58d62019-12-06 18:40:19 -0800159 it = mProps.erase(it);
160 ++zapped;
Ray Essick3938dc62016-11-01 08:56:56 -0700161 }
162 }
163 return zapped;
164}
165
Ray Essick3938dc62016-11-01 08:56:56 -0700166// Parcel / serialize things for binder calls
167//
168
Ray Essickf27e9872019-12-07 06:28:46 -0800169status_t mediametrics::Item::readFromParcel(const Parcel& data) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700170 int32_t version;
171 status_t status = data.readInt32(&version);
172 if (status != NO_ERROR) return status;
Ray Essickba8c4842019-01-18 11:35:33 -0800173
Andy Hung3253f2d2019-10-21 14:50:07 -0700174 switch (version) {
175 case 0:
176 return readFromParcel0(data);
177 default:
178 ALOGE("%s: unsupported parcel version: %d", __func__, version);
179 return INVALID_OPERATION;
Ray Essickba8c4842019-01-18 11:35:33 -0800180 }
181}
182
Ray Essickf27e9872019-12-07 06:28:46 -0800183status_t mediametrics::Item::readFromParcel0(const Parcel& data) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700184 const char *s = data.readCString();
185 mKey = s == nullptr ? "" : s;
186 int32_t pid, uid;
187 status_t status = data.readInt32(&pid) ?: data.readInt32(&uid);
188 if (status != NO_ERROR) return status;
189 mPid = (pid_t)pid;
190 mUid = (uid_t)uid;
191 s = data.readCString();
192 mPkgName = s == nullptr ? "" : s;
193 int32_t count;
194 int64_t version, timestamp;
195 status = data.readInt64(&version) ?: data.readInt64(&timestamp) ?: data.readInt32(&count);
196 if (status != NO_ERROR) return status;
197 if (count < 0) return BAD_VALUE;
198 mPkgVersionCode = version;
199 mTimestamp = timestamp;
Andy Hung47e58d62019-12-06 18:40:19 -0800200 for (int i = 0; i < count; i++) {
201 Prop prop;
202 status_t status = prop.readFromParcel(data);
Andy Hung3253f2d2019-10-21 14:50:07 -0700203 if (status != NO_ERROR) return status;
Andy Hung47e58d62019-12-06 18:40:19 -0800204 mProps[prop.getName()] = std::move(prop);
Ray Essick3938dc62016-11-01 08:56:56 -0700205 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700206 return NO_ERROR;
Ray Essick3938dc62016-11-01 08:56:56 -0700207}
208
Ray Essickf27e9872019-12-07 06:28:46 -0800209status_t mediametrics::Item::writeToParcel(Parcel *data) const {
Andy Hung3253f2d2019-10-21 14:50:07 -0700210 if (data == nullptr) return BAD_VALUE;
Ray Essickba8c4842019-01-18 11:35:33 -0800211
Andy Hung3253f2d2019-10-21 14:50:07 -0700212 const int32_t version = 0;
213 status_t status = data->writeInt32(version);
214 if (status != NO_ERROR) return status;
Ray Essick3938dc62016-11-01 08:56:56 -0700215
Andy Hung3253f2d2019-10-21 14:50:07 -0700216 switch (version) {
217 case 0:
218 return writeToParcel0(data);
219 default:
220 ALOGE("%s: unsupported parcel version: %d", __func__, version);
221 return INVALID_OPERATION;
Ray Essickba8c4842019-01-18 11:35:33 -0800222 }
223}
224
Ray Essickf27e9872019-12-07 06:28:46 -0800225status_t mediametrics::Item::writeToParcel0(Parcel *data) const {
Andy Hung3253f2d2019-10-21 14:50:07 -0700226 status_t status =
227 data->writeCString(mKey.c_str())
228 ?: data->writeInt32(mPid)
229 ?: data->writeInt32(mUid)
230 ?: data->writeCString(mPkgName.c_str())
231 ?: data->writeInt64(mPkgVersionCode)
232 ?: data->writeInt64(mTimestamp);
233 if (status != NO_ERROR) return status;
Ray Essick3938dc62016-11-01 08:56:56 -0700234
Andy Hung47e58d62019-12-06 18:40:19 -0800235 data->writeInt32((int32_t)mProps.size());
236 for (auto &prop : *this) {
237 status = prop.writeToParcel(data);
Andy Hung3253f2d2019-10-21 14:50:07 -0700238 if (status != NO_ERROR) return status;
Ray Essick3938dc62016-11-01 08:56:56 -0700239 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700240 return NO_ERROR;
Ray Essick3938dc62016-11-01 08:56:56 -0700241}
242
Ray Essickf27e9872019-12-07 06:28:46 -0800243const char *mediametrics::Item::toCString() {
Andy Hung3b4c1f02020-01-23 18:58:32 -0800244 std::string val = toString();
Ray Essick20147322018-11-17 09:08:39 -0800245 return strdup(val.c_str());
246}
247
Andy Hung3b4c1f02020-01-23 18:58:32 -0800248/*
249 * Similar to audio_utils/clock.h but customized for displaying mediametrics time.
250 */
251
252void nsToString(int64_t ns, char *buffer, size_t bufferSize, PrintFormat format)
253{
254 if (bufferSize == 0) return;
255
256 const int one_second = 1000000000;
257 const time_t sec = ns / one_second;
258 struct tm tm;
259
260 // Supported on bionic, glibc, and macOS, but not mingw.
261 if (localtime_r(&sec, &tm) == NULL) {
262 buffer[0] = '\0';
263 return;
264 }
265
266 switch (format) {
267 default:
268 case kPrintFormatLong:
269 if (snprintf(buffer, bufferSize, "%02d-%02d %02d:%02d:%02d.%03d",
270 tm.tm_mon + 1, // localtime_r uses months in 0 - 11 range
271 tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
272 (int)(ns % one_second / 1000000)) < 0) {
273 buffer[0] = '\0'; // null terminate on format error, which should not happen
274 }
275 break;
276 case kPrintFormatShort:
277 if (snprintf(buffer, bufferSize, "%02d:%02d:%02d.%03d",
278 tm.tm_hour, tm.tm_min, tm.tm_sec,
279 (int)(ns % one_second / 1000000)) < 0) {
280 buffer[0] = '\0'; // null terminate on format error, which should not happen
281 }
282 break;
283 }
Ray Essickf65f4212017-08-31 11:41:19 -0700284}
Ray Essick3938dc62016-11-01 08:56:56 -0700285
Andy Hung3b4c1f02020-01-23 18:58:32 -0800286std::string mediametrics::Item::toString() const {
Ray Essick783bd0d2018-01-11 11:10:35 -0800287 std::string result;
Andy Hung1efc9c62019-12-03 13:43:33 -0800288 char buffer[kMaxPropertyStringSize];
Ray Essick3938dc62016-11-01 08:56:56 -0700289
Andy Hung3b4c1f02020-01-23 18:58:32 -0800290 snprintf(buffer, sizeof(buffer), "{%s, (%s), (%s, %d, %d)",
291 mKey.c_str(),
292 timeStringFromNs(mTimestamp, kPrintFormatLong).time,
293 mPkgName.c_str(), mPid, mUid
294 );
Ray Essickf65f4212017-08-31 11:41:19 -0700295 result.append(buffer);
Andy Hung3b4c1f02020-01-23 18:58:32 -0800296 bool first = true;
Andy Hung47e58d62019-12-06 18:40:19 -0800297 for (auto &prop : *this) {
Andy Hungb7aadb32019-12-09 19:40:42 -0800298 prop.toStringBuffer(buffer, sizeof(buffer));
Andy Hung3b4c1f02020-01-23 18:58:32 -0800299 result += first ? ", (" : ", ";
300 result += buffer;
301 first = false;
Ray Essick3938dc62016-11-01 08:56:56 -0700302 }
Andy Hung3b4c1f02020-01-23 18:58:32 -0800303 result.append(")}");
Ray Essick3938dc62016-11-01 08:56:56 -0700304 return result;
305}
306
307// for the lazy, we offer methods that finds the service and
308// calls the appropriate daemon
Ray Essickf27e9872019-12-07 06:28:46 -0800309bool mediametrics::Item::selfrecord() {
Andy Hunga87e69c2019-10-18 10:07:40 -0700310 ALOGD_IF(DEBUG_API, "%s: delivering %s", __func__, this->toString().c_str());
Andy Hung49ca44e2020-11-10 22:14:58 -0800311
312 char *str;
313 size_t size;
314 status_t status = writeToByteString(&str, &size);
315 if (status == NO_ERROR) {
316 status = submitBuffer(str, size);
George Burgess IV14dadb12021-02-03 14:04:09 -0800317 free(str);
Andy Hung49ca44e2020-11-10 22:14:58 -0800318 }
319 if (status != NO_ERROR) {
320 ALOGW("%s: failed to record: %s", __func__, this->toString().c_str());
Ray Essick3938dc62016-11-01 08:56:56 -0700321 return false;
322 }
Andy Hung49ca44e2020-11-10 22:14:58 -0800323 return true;
Ray Essick3938dc62016-11-01 08:56:56 -0700324}
325
Ray Essick3938dc62016-11-01 08:56:56 -0700326//static
Andy Hung1efc9c62019-12-03 13:43:33 -0800327bool BaseItem::isEnabled() {
Andy Hunga87e69c2019-10-18 10:07:40 -0700328 // completely skip logging from certain UIDs. We do this here
329 // to avoid the multi-second timeouts while we learn that
330 // sepolicy will not let us find the service.
331 // We do this only for a select set of UIDs
332 // The sepolicy protection is still in place, we just want a faster
333 // response from this specific, small set of uids.
Ray Essick3938dc62016-11-01 08:56:56 -0700334
Andy Hunga87e69c2019-10-18 10:07:40 -0700335 // This is checked only once in the lifetime of the process.
336 const uid_t uid = getuid();
337 switch (uid) {
338 case AID_RADIO: // telephony subsystem, RIL
339 return false;
Ahaan Ugaleb5aee612021-05-26 14:50:13 -0700340 default:
341 // Some isolated processes can access the audio system; see
342 // AudioSystem::setAudioFlingerBinder (currently only the HotwordDetectionService). Instead
343 // of also allowing access to the MediaMetrics service, it's simpler to just disable it for
344 // now.
345 // TODO(b/190151205): Either allow the HotwordDetectionService to access MediaMetrics or
346 // make this disabling specific to that process.
Mark Punzalan3ebe1212022-05-17 08:15:49 +0000347 uid_t appid = multiuser_get_app_id(uid);
348 if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
Ahaan Ugaleb5aee612021-05-26 14:50:13 -0700349 return false;
350 }
351 break;
Andy Hunga87e69c2019-10-18 10:07:40 -0700352 }
353
Ray Essickf27e9872019-12-07 06:28:46 -0800354 int enabled = property_get_int32(Item::EnabledProperty, -1);
Ray Essick3938dc62016-11-01 08:56:56 -0700355 if (enabled == -1) {
Ray Essickf27e9872019-12-07 06:28:46 -0800356 enabled = property_get_int32(Item::EnabledPropertyPersist, -1);
Ray Essick3938dc62016-11-01 08:56:56 -0700357 }
358 if (enabled == -1) {
Ray Essickf27e9872019-12-07 06:28:46 -0800359 enabled = Item::EnabledProperty_default;
Ray Essick3938dc62016-11-01 08:56:56 -0700360 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700361 return enabled > 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700362}
363
Ray Essick2ab3c432017-10-02 09:29:49 -0700364// monitor health of our connection to the metrics service
365class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {
366 virtual void binderDied(const wp<IBinder> &) {
367 ALOGW("Reacquire service connection on next request");
Andy Hung1efc9c62019-12-03 13:43:33 -0800368 BaseItem::dropInstance();
Ray Essick2ab3c432017-10-02 09:29:49 -0700369 }
370};
371
Andy Hunga87e69c2019-10-18 10:07:40 -0700372static sp<MediaMetricsDeathNotifier> sNotifier;
373// static
Andy Hung49ca44e2020-11-10 22:14:58 -0800374sp<media::IMediaMetricsService> BaseItem::sMediaMetricsService;
Andy Hunga87e69c2019-10-18 10:07:40 -0700375static std::mutex sServiceMutex;
376static int sRemainingBindAttempts = SVC_TRIES;
Ray Essick2ab3c432017-10-02 09:29:49 -0700377
378// static
Andy Hung1efc9c62019-12-03 13:43:33 -0800379void BaseItem::dropInstance() {
Andy Hunga87e69c2019-10-18 10:07:40 -0700380 std::lock_guard _l(sServiceMutex);
381 sRemainingBindAttempts = SVC_TRIES;
Ray Essickf27e9872019-12-07 06:28:46 -0800382 sMediaMetricsService = nullptr;
Ray Essick2ab3c432017-10-02 09:29:49 -0700383}
384
Andy Hung1efc9c62019-12-03 13:43:33 -0800385// static
Andy Hung49ca44e2020-11-10 22:14:58 -0800386status_t BaseItem::submitBuffer(const char *buffer, size_t size) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800387 ALOGD_IF(DEBUG_API, "%s: delivering %zu bytes", __func__, size);
Andy Hung49ca44e2020-11-10 22:14:58 -0800388
389 // Validate size
390 if (size > std::numeric_limits<int32_t>::max()) return BAD_VALUE;
391
392 // Do we have the service available?
393 sp<media::IMediaMetricsService> svc = getService();
394 if (svc == nullptr) return NO_INIT;
395
396 ::android::status_t status = NO_ERROR;
397 if constexpr (/* DISABLES CODE */ (false)) {
398 // THIS PATH IS FOR REFERENCE ONLY.
399 // It is compiled so that any changes to IMediaMetricsService::submitBuffer()
400 // will lead here. If this code is changed, the else branch must
401 // be changed as well.
402 //
403 // Use the AIDL calling interface - this is a bit slower as a byte vector must be
404 // constructed. As the call is one-way, the only a transaction error occurs.
405 status = svc->submitBuffer({buffer, buffer + size}).transactionError();
406 } else {
407 // Use the Binder calling interface - this direct implementation avoids
408 // malloc/copy/free for the vector and reduces the overhead for logging.
409 // We based this off of the AIDL generated file:
410 // out/soong/.intermediates/frameworks/av/media/libmediametrics/mediametricsservice-aidl-unstable-cpp-source/gen/android/media/IMediaMetricsService.cpp
411 // TODO: Create an AIDL C++ back end optimized form of vector writing.
412 ::android::Parcel _aidl_data;
413 ::android::Parcel _aidl_reply; // we don't care about this as it is one-way.
414
415 status = _aidl_data.writeInterfaceToken(svc->getInterfaceDescriptor());
416 if (status != ::android::OK) goto _aidl_error;
417
418 status = _aidl_data.writeInt32(static_cast<int32_t>(size));
419 if (status != ::android::OK) goto _aidl_error;
420
421 status = _aidl_data.write(buffer, static_cast<int32_t>(size));
422 if (status != ::android::OK) goto _aidl_error;
423
424 status = ::android::IInterface::asBinder(svc)->transact(
425 ::android::media::BnMediaMetricsService::TRANSACTION_submitBuffer,
426 _aidl_data, &_aidl_reply, ::android::IBinder::FLAG_ONEWAY);
427
428 // AIDL permits setting a default implementation for additional functionality.
429 // See go/aog/713984. This is not used here.
430 // if (status == ::android::UNKNOWN_TRANSACTION
431 // && ::android::media::IMediaMetricsService::getDefaultImpl()) {
432 // status = ::android::media::IMediaMetricsService::getDefaultImpl()
433 // ->submitBuffer(immutableByteVectorFromBuffer(buffer, size))
434 // .transactionError();
435 // }
Andy Hung1efc9c62019-12-03 13:43:33 -0800436 }
Andy Hung49ca44e2020-11-10 22:14:58 -0800437
438 if (status == NO_ERROR) return NO_ERROR;
439
440 _aidl_error:
441 ALOGW("%s: failed(%d) to record: %zu bytes", __func__, status, size);
442 return status;
Andy Hung1efc9c62019-12-03 13:43:33 -0800443}
444
Ray Essick3938dc62016-11-01 08:56:56 -0700445//static
Andy Hung49ca44e2020-11-10 22:14:58 -0800446sp<media::IMediaMetricsService> BaseItem::getService() {
Ray Essickd38e1742017-01-23 15:17:06 -0800447 static const char *servicename = "media.metrics";
Andy Hunga87e69c2019-10-18 10:07:40 -0700448 static const bool enabled = isEnabled(); // singleton initialized
Ray Essick3938dc62016-11-01 08:56:56 -0700449
450 if (enabled == false) {
Andy Hunga87e69c2019-10-18 10:07:40 -0700451 ALOGD_IF(DEBUG_SERVICEACCESS, "disabled");
452 return nullptr;
Ray Essick3938dc62016-11-01 08:56:56 -0700453 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700454 std::lock_guard _l(sServiceMutex);
455 // think of remainingBindAttempts as telling us whether service == nullptr because
456 // (1) we haven't tried to initialize it yet
457 // (2) we've tried to initialize it, but failed.
Ray Essickf27e9872019-12-07 06:28:46 -0800458 if (sMediaMetricsService == nullptr && sRemainingBindAttempts > 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700459 const char *badness = "";
Andy Hunga87e69c2019-10-18 10:07:40 -0700460 sp<IServiceManager> sm = defaultServiceManager();
461 if (sm != nullptr) {
462 sp<IBinder> binder = sm->getService(String16(servicename));
463 if (binder != nullptr) {
Andy Hung49ca44e2020-11-10 22:14:58 -0800464 sMediaMetricsService = interface_cast<media::IMediaMetricsService>(binder);
Andy Hunga87e69c2019-10-18 10:07:40 -0700465 sNotifier = new MediaMetricsDeathNotifier();
466 binder->linkToDeath(sNotifier);
Ray Essick3938dc62016-11-01 08:56:56 -0700467 } else {
Andy Hunga87e69c2019-10-18 10:07:40 -0700468 badness = "did not find service";
Ray Essick3938dc62016-11-01 08:56:56 -0700469 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700470 } else {
471 badness = "No Service Manager access";
Ray Essick3938dc62016-11-01 08:56:56 -0700472 }
Ray Essickf27e9872019-12-07 06:28:46 -0800473 if (sMediaMetricsService == nullptr) {
Andy Hunga87e69c2019-10-18 10:07:40 -0700474 if (sRemainingBindAttempts > 0) {
475 sRemainingBindAttempts--;
476 }
477 ALOGD_IF(DEBUG_SERVICEACCESS, "%s: unable to bind to service %s: %s",
478 __func__, servicename, badness);
479 }
Ray Essick3938dc62016-11-01 08:56:56 -0700480 }
Ray Essickf27e9872019-12-07 06:28:46 -0800481 return sMediaMetricsService;
Ray Essick3938dc62016-11-01 08:56:56 -0700482}
483
Andy Hung1efc9c62019-12-03 13:43:33 -0800484
Ray Essickf27e9872019-12-07 06:28:46 -0800485status_t mediametrics::Item::writeToByteString(char **pbuffer, size_t *plength) const
Andy Hung3253f2d2019-10-21 14:50:07 -0700486{
487 if (pbuffer == nullptr || plength == nullptr)
488 return BAD_VALUE;
489
490 // get size
491 const size_t keySizeZeroTerminated = strlen(mKey.c_str()) + 1;
492 if (keySizeZeroTerminated > UINT16_MAX) {
493 ALOGW("%s: key size %zu too large", __func__, keySizeZeroTerminated);
494 return INVALID_OPERATION;
495 }
496 const uint16_t version = 0;
Andy Hung1efc9c62019-12-03 13:43:33 -0800497 const uint32_t header_size =
498 sizeof(uint32_t) // total size
499 + sizeof(header_size) // header size
500 + sizeof(version) // encoding version
501 + sizeof(uint16_t) // key size
Andy Hung3253f2d2019-10-21 14:50:07 -0700502 + keySizeZeroTerminated // key, zero terminated
Andy Hung1efc9c62019-12-03 13:43:33 -0800503 + sizeof(int32_t) // pid
504 + sizeof(int32_t) // uid
505 + sizeof(int64_t) // timestamp
Andy Hung3253f2d2019-10-21 14:50:07 -0700506 ;
507
Andy Hung1efc9c62019-12-03 13:43:33 -0800508 uint32_t size = header_size
Andy Hung3253f2d2019-10-21 14:50:07 -0700509 + sizeof(uint32_t) // # properties
510 ;
Andy Hung47e58d62019-12-06 18:40:19 -0800511 for (auto &prop : *this) {
512 const size_t propSize = prop.getByteStringSize();
Andy Hung1efc9c62019-12-03 13:43:33 -0800513 if (propSize > UINT16_MAX) {
Andy Hung47e58d62019-12-06 18:40:19 -0800514 ALOGW("%s: prop %s size %zu too large", __func__, prop.getName(), propSize);
Andy Hung3253f2d2019-10-21 14:50:07 -0700515 return INVALID_OPERATION;
516 }
Andy Hung1efc9c62019-12-03 13:43:33 -0800517 if (__builtin_add_overflow(size, propSize, &size)) {
Andy Hung47e58d62019-12-06 18:40:19 -0800518 ALOGW("%s: item size overflow at property %s", __func__, prop.getName());
Andy Hung1efc9c62019-12-03 13:43:33 -0800519 return INVALID_OPERATION;
520 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700521 }
522
Andy Hung1efc9c62019-12-03 13:43:33 -0800523 // since we fill every byte in the buffer (there is no padding),
524 // malloc is used here instead of calloc.
525 char * const build = (char *)malloc(size);
Andy Hung3253f2d2019-10-21 14:50:07 -0700526 if (build == nullptr) return NO_MEMORY;
527
528 char *filling = build;
Andy Hung1efc9c62019-12-03 13:43:33 -0800529 char *buildmax = build + size;
530 if (insert((uint32_t)size, &filling, buildmax) != NO_ERROR
531 || insert(header_size, &filling, buildmax) != NO_ERROR
Andy Hung3253f2d2019-10-21 14:50:07 -0700532 || insert(version, &filling, buildmax) != NO_ERROR
533 || insert((uint16_t)keySizeZeroTerminated, &filling, buildmax) != NO_ERROR
534 || insert(mKey.c_str(), &filling, buildmax) != NO_ERROR
535 || insert((int32_t)mPid, &filling, buildmax) != NO_ERROR
536 || insert((int32_t)mUid, &filling, buildmax) != NO_ERROR
537 || insert((int64_t)mTimestamp, &filling, buildmax) != NO_ERROR
Andy Hung47e58d62019-12-06 18:40:19 -0800538 || insert((uint32_t)mProps.size(), &filling, buildmax) != NO_ERROR) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800539 ALOGE("%s:could not write header", __func__); // shouldn't happen
Andy Hung3253f2d2019-10-21 14:50:07 -0700540 free(build);
541 return INVALID_OPERATION;
542 }
Andy Hung47e58d62019-12-06 18:40:19 -0800543 for (auto &prop : *this) {
544 if (prop.writeToByteString(&filling, buildmax) != NO_ERROR) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700545 free(build);
Andy Hung1efc9c62019-12-03 13:43:33 -0800546 // shouldn't happen
Andy Hung47e58d62019-12-06 18:40:19 -0800547 ALOGE("%s:could not write prop %s", __func__, prop.getName());
Andy Hung3253f2d2019-10-21 14:50:07 -0700548 return INVALID_OPERATION;
549 }
550 }
551
552 if (filling != buildmax) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800553 ALOGE("%s: problems populating; wrote=%d planned=%d",
554 __func__, (int)(filling - build), (int)size);
Andy Hung3253f2d2019-10-21 14:50:07 -0700555 free(build);
556 return INVALID_OPERATION;
557 }
558 *pbuffer = build;
Andy Hung1efc9c62019-12-03 13:43:33 -0800559 *plength = size;
Andy Hung3253f2d2019-10-21 14:50:07 -0700560 return NO_ERROR;
561}
562
Ray Essickf27e9872019-12-07 06:28:46 -0800563status_t mediametrics::Item::readFromByteString(const char *bufferptr, size_t length)
Andy Hung3253f2d2019-10-21 14:50:07 -0700564{
565 if (bufferptr == nullptr) return BAD_VALUE;
566
567 const char *read = bufferptr;
568 const char *readend = bufferptr + length;
569
Andy Hung1efc9c62019-12-03 13:43:33 -0800570 uint32_t size;
571 uint32_t header_size;
572 uint16_t version;
573 uint16_t key_size;
Andy Hungb7aadb32019-12-09 19:40:42 -0800574 std::string key;
Andy Hung3253f2d2019-10-21 14:50:07 -0700575 int32_t pid;
576 int32_t uid;
577 int64_t timestamp;
578 uint32_t propCount;
Andy Hung1efc9c62019-12-03 13:43:33 -0800579 if (extract(&size, &read, readend) != NO_ERROR
580 || extract(&header_size, &read, readend) != NO_ERROR
Andy Hung3253f2d2019-10-21 14:50:07 -0700581 || extract(&version, &read, readend) != NO_ERROR
Andy Hung1efc9c62019-12-03 13:43:33 -0800582 || extract(&key_size, &read, readend) != NO_ERROR
Andy Hung3253f2d2019-10-21 14:50:07 -0700583 || extract(&key, &read, readend) != NO_ERROR
584 || extract(&pid, &read, readend) != NO_ERROR
585 || extract(&uid, &read, readend) != NO_ERROR
586 || extract(&timestamp, &read, readend) != NO_ERROR
Andy Hung1efc9c62019-12-03 13:43:33 -0800587 || size > length
Andy Hungb7aadb32019-12-09 19:40:42 -0800588 || key.size() + 1 != key_size
Andy Hung1efc9c62019-12-03 13:43:33 -0800589 || header_size > size) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800590 ALOGW("%s: invalid header", __func__);
Andy Hung3253f2d2019-10-21 14:50:07 -0700591 return INVALID_OPERATION;
592 }
Andy Hungb7aadb32019-12-09 19:40:42 -0800593 mKey = std::move(key);
Andy Hung3253f2d2019-10-21 14:50:07 -0700594 const size_t pos = read - bufferptr;
Andy Hung1efc9c62019-12-03 13:43:33 -0800595 if (pos > header_size) {
596 ALOGW("%s: invalid header pos:%zu > header_size:%u",
597 __func__, pos, header_size);
Andy Hung3253f2d2019-10-21 14:50:07 -0700598 return INVALID_OPERATION;
Andy Hung1efc9c62019-12-03 13:43:33 -0800599 } else if (pos < header_size) {
600 ALOGW("%s: mismatched header pos:%zu < header_size:%u, advancing",
601 __func__, pos, header_size);
602 read += (header_size - pos);
Andy Hung3253f2d2019-10-21 14:50:07 -0700603 }
604 if (extract(&propCount, &read, readend) != NO_ERROR) {
605 ALOGD("%s: cannot read prop count", __func__);
606 return INVALID_OPERATION;
607 }
608 mPid = pid;
609 mUid = uid;
610 mTimestamp = timestamp;
611 for (size_t i = 0; i < propCount; ++i) {
Andy Hung47e58d62019-12-06 18:40:19 -0800612 Prop prop;
613 if (prop.readFromByteString(&read, readend) != NO_ERROR) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800614 ALOGW("%s: cannot read prop %zu", __func__, i);
Andy Hung3253f2d2019-10-21 14:50:07 -0700615 return INVALID_OPERATION;
616 }
Andy Hung47e58d62019-12-06 18:40:19 -0800617 mProps[prop.getName()] = std::move(prop);
Andy Hung3253f2d2019-10-21 14:50:07 -0700618 }
619 return NO_ERROR;
620}
621
Ray Essickf27e9872019-12-07 06:28:46 -0800622status_t mediametrics::Item::Prop::readFromParcel(const Parcel& data)
Andy Hung3253f2d2019-10-21 14:50:07 -0700623{
624 const char *key = data.readCString();
625 if (key == nullptr) return BAD_VALUE;
626 int32_t type;
627 status_t status = data.readInt32(&type);
628 if (status != NO_ERROR) return status;
629 switch (type) {
Andy Hungb7aadb32019-12-09 19:40:42 -0800630 case mediametrics::kTypeInt32: {
631 int32_t value;
632 status = data.readInt32(&value);
633 if (status != NO_ERROR) return status;
634 mElem = value;
635 } break;
636 case mediametrics::kTypeInt64: {
637 int64_t value;
638 status = data.readInt64(&value);
639 if (status != NO_ERROR) return status;
640 mElem = value;
641 } break;
642 case mediametrics::kTypeDouble: {
643 double value;
644 status = data.readDouble(&value);
645 if (status != NO_ERROR) return status;
646 mElem = value;
647 } break;
Andy Hung47e58d62019-12-06 18:40:19 -0800648 case mediametrics::kTypeCString: {
Andy Hung3253f2d2019-10-21 14:50:07 -0700649 const char *s = data.readCString();
650 if (s == nullptr) return BAD_VALUE;
Andy Hungb7aadb32019-12-09 19:40:42 -0800651 mElem = s;
652 } break;
Andy Hung47e58d62019-12-06 18:40:19 -0800653 case mediametrics::kTypeRate: {
Andy Hung3253f2d2019-10-21 14:50:07 -0700654 std::pair<int64_t, int64_t> rate;
655 status = data.readInt64(&rate.first)
656 ?: data.readInt64(&rate.second);
Andy Hungb7aadb32019-12-09 19:40:42 -0800657 if (status != NO_ERROR) return status;
658 mElem = rate;
659 } break;
660 case mediametrics::kTypeNone: {
661 mElem = std::monostate{};
662 } break;
Andy Hung3253f2d2019-10-21 14:50:07 -0700663 default:
Andy Hungb7aadb32019-12-09 19:40:42 -0800664 ALOGE("%s: reading bad item type: %d", __func__, type);
Andy Hung3253f2d2019-10-21 14:50:07 -0700665 return BAD_VALUE;
666 }
Andy Hungb7aadb32019-12-09 19:40:42 -0800667 setName(key);
668 return NO_ERROR;
Andy Hung3253f2d2019-10-21 14:50:07 -0700669}
670
Ray Essickf27e9872019-12-07 06:28:46 -0800671status_t mediametrics::Item::Prop::readFromByteString(
Andy Hung3253f2d2019-10-21 14:50:07 -0700672 const char **bufferpptr, const char *bufferptrmax)
673{
674 uint16_t len;
Andy Hungb7aadb32019-12-09 19:40:42 -0800675 std::string name;
Andy Hung3253f2d2019-10-21 14:50:07 -0700676 uint8_t type;
677 status_t status = extract(&len, bufferpptr, bufferptrmax)
678 ?: extract(&type, bufferpptr, bufferptrmax)
679 ?: extract(&name, bufferpptr, bufferptrmax);
680 if (status != NO_ERROR) return status;
Andy Hungb7aadb32019-12-09 19:40:42 -0800681 switch (type) {
682 case mediametrics::kTypeInt32: {
683 int32_t value;
684 status = extract(&value, bufferpptr, bufferptrmax);
685 if (status != NO_ERROR) return status;
686 mElem = value;
687 } break;
688 case mediametrics::kTypeInt64: {
689 int64_t value;
690 status = extract(&value, bufferpptr, bufferptrmax);
691 if (status != NO_ERROR) return status;
692 mElem = value;
693 } break;
694 case mediametrics::kTypeDouble: {
695 double value;
696 status = extract(&value, bufferpptr, bufferptrmax);
697 if (status != NO_ERROR) return status;
698 mElem = value;
699 } break;
700 case mediametrics::kTypeRate: {
701 std::pair<int64_t, int64_t> value;
702 status = extract(&value.first, bufferpptr, bufferptrmax)
703 ?: extract(&value.second, bufferpptr, bufferptrmax);
704 if (status != NO_ERROR) return status;
705 mElem = value;
706 } break;
707 case mediametrics::kTypeCString: {
708 std::string value;
709 status = extract(&value, bufferpptr, bufferptrmax);
710 if (status != NO_ERROR) return status;
711 mElem = std::move(value);
712 } break;
713 case mediametrics::kTypeNone: {
714 mElem = std::monostate{};
715 } break;
Andy Hung3253f2d2019-10-21 14:50:07 -0700716 default:
Andy Hung3253f2d2019-10-21 14:50:07 -0700717 ALOGE("%s: found bad prop type: %d, name %s",
Andy Hungb7aadb32019-12-09 19:40:42 -0800718 __func__, (int)type, mName.c_str()); // no payload sent
Andy Hung3253f2d2019-10-21 14:50:07 -0700719 return BAD_VALUE;
720 }
Andy Hungb7aadb32019-12-09 19:40:42 -0800721 mName = name;
722 return NO_ERROR;
Andy Hung3253f2d2019-10-21 14:50:07 -0700723}
724
Ray Essickf27e9872019-12-07 06:28:46 -0800725} // namespace android::mediametrics