blob: 485e161bcecca2959d70ebb8befe2db2714ddc53 [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 Hunga87e69c2019-10-18 10:07:40 -070026
Ray Essick3938dc62016-11-01 08:56:56 -070027#include <binder/Parcel.h>
28#include <utils/Errors.h>
29#include <utils/Log.h>
Ray Essick3938dc62016-11-01 08:56:56 -070030#include <utils/SortedVector.h>
31#include <utils/threads.h>
32
Ray Essick3938dc62016-11-01 08:56:56 -070033#include <binder/IServiceManager.h>
Ray Essickf27e9872019-12-07 06:28:46 -080034#include <media/IMediaMetricsService.h>
35#include <media/MediaMetricsItem.h>
Ray Essick79a89ef2017-04-24 15:52:54 -070036#include <private/android_filesystem_config.h>
Ray Essick3938dc62016-11-01 08:56:56 -070037
Andy Hung1efc9c62019-12-03 13:43:33 -080038// Max per-property string size before truncation in toString().
39// Do not make too large, as this is used for dumpsys purposes.
40static constexpr size_t kMaxPropertyStringSize = 4096;
41
Ray Essickf27e9872019-12-07 06:28:46 -080042namespace android::mediametrics {
Ray Essick3938dc62016-11-01 08:56:56 -070043
44#define DEBUG_SERVICEACCESS 0
Ray Essickb5fac8e2016-12-12 11:33:56 -080045#define DEBUG_API 0
46#define DEBUG_ALLOCATIONS 0
47
48// after this many failed attempts, we stop trying [from this process] and just say that
49// the service is off.
50#define SVC_TRIES 2
Ray Essick3938dc62016-11-01 08:56:56 -070051
Ray Essickf27e9872019-12-07 06:28:46 -080052mediametrics::Item* mediametrics::Item::convert(mediametrics_handle_t handle) {
53 mediametrics::Item *item = (android::mediametrics::Item *) handle;
Ray Essickbf536ac2019-08-26 11:04:28 -070054 return item;
55}
56
Ray Essickf27e9872019-12-07 06:28:46 -080057mediametrics_handle_t mediametrics::Item::convert(mediametrics::Item *item ) {
Ray Essickbf536ac2019-08-26 11:04:28 -070058 mediametrics_handle_t handle = (mediametrics_handle_t) item;
59 return handle;
60}
61
Ray Essickf27e9872019-12-07 06:28:46 -080062mediametrics::Item::~Item() {
Ray Essickb5fac8e2016-12-12 11:33:56 -080063 if (DEBUG_ALLOCATIONS) {
Ray Essickf27e9872019-12-07 06:28:46 -080064 ALOGD("Destroy mediametrics::Item @ %p", this);
Ray Essickb5fac8e2016-12-12 11:33:56 -080065 }
Ray Essickb5fac8e2016-12-12 11:33:56 -080066}
67
Ray Essickf27e9872019-12-07 06:28:46 -080068mediametrics::Item &mediametrics::Item::setTimestamp(nsecs_t ts) {
Ray Essick3938dc62016-11-01 08:56:56 -070069 mTimestamp = ts;
70 return *this;
71}
72
Ray Essickf27e9872019-12-07 06:28:46 -080073nsecs_t mediametrics::Item::getTimestamp() const {
Ray Essick3938dc62016-11-01 08:56:56 -070074 return mTimestamp;
75}
76
Ray Essickf27e9872019-12-07 06:28:46 -080077mediametrics::Item &mediametrics::Item::setPid(pid_t pid) {
Ray Essick3938dc62016-11-01 08:56:56 -070078 mPid = pid;
79 return *this;
80}
81
Ray Essickf27e9872019-12-07 06:28:46 -080082pid_t mediametrics::Item::getPid() const {
Ray Essick3938dc62016-11-01 08:56:56 -070083 return mPid;
84}
85
Ray Essickf27e9872019-12-07 06:28:46 -080086mediametrics::Item &mediametrics::Item::setUid(uid_t uid) {
Ray Essick3938dc62016-11-01 08:56:56 -070087 mUid = uid;
88 return *this;
89}
90
Ray Essickf27e9872019-12-07 06:28:46 -080091uid_t mediametrics::Item::getUid() const {
Ray Essick3938dc62016-11-01 08:56:56 -070092 return mUid;
93}
94
Ray Essickf27e9872019-12-07 06:28:46 -080095mediametrics::Item &mediametrics::Item::setPkgName(const std::string &pkgName) {
Ray Essickf65f4212017-08-31 11:41:19 -070096 mPkgName = pkgName;
97 return *this;
98}
99
Ray Essickf27e9872019-12-07 06:28:46 -0800100mediametrics::Item &mediametrics::Item::setPkgVersionCode(int64_t pkgVersionCode) {
Ray Essickf65f4212017-08-31 11:41:19 -0700101 mPkgVersionCode = pkgVersionCode;
102 return *this;
103}
104
Ray Essickf27e9872019-12-07 06:28:46 -0800105int64_t mediametrics::Item::getPkgVersionCode() const {
Ray Essickf65f4212017-08-31 11:41:19 -0700106 return mPkgVersionCode;
107}
108
Ray Essick3938dc62016-11-01 08:56:56 -0700109// remove indicated keys and their values
110// return value is # keys removed
Ray Essickf27e9872019-12-07 06:28:46 -0800111size_t mediametrics::Item::filter(size_t n, const char *attrs[]) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700112 size_t zapped = 0;
113 for (size_t i = 0; i < n; ++i) {
Andy Hung47e58d62019-12-06 18:40:19 -0800114 zapped += mProps.erase(attrs[i]);
Ray Essick3938dc62016-11-01 08:56:56 -0700115 }
116 return zapped;
117}
118
119// remove any keys NOT in the provided list
120// return value is # keys removed
Ray Essickf27e9872019-12-07 06:28:46 -0800121size_t mediametrics::Item::filterNot(size_t n, const char *attrs[]) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700122 std::set<std::string> check(attrs, attrs + n);
123 size_t zapped = 0;
Andy Hung47e58d62019-12-06 18:40:19 -0800124 for (auto it = mProps.begin(); it != mProps.end();) {
125 if (check.find(it->first) != check.end()) {
126 ++it;
Andy Hung3253f2d2019-10-21 14:50:07 -0700127 } else {
Andy Hung47e58d62019-12-06 18:40:19 -0800128 it = mProps.erase(it);
129 ++zapped;
Ray Essick3938dc62016-11-01 08:56:56 -0700130 }
131 }
132 return zapped;
133}
134
Ray Essick3938dc62016-11-01 08:56:56 -0700135// Parcel / serialize things for binder calls
136//
137
Ray Essickf27e9872019-12-07 06:28:46 -0800138status_t mediametrics::Item::readFromParcel(const Parcel& data) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700139 int32_t version;
140 status_t status = data.readInt32(&version);
141 if (status != NO_ERROR) return status;
Ray Essickba8c4842019-01-18 11:35:33 -0800142
Andy Hung3253f2d2019-10-21 14:50:07 -0700143 switch (version) {
144 case 0:
145 return readFromParcel0(data);
146 default:
147 ALOGE("%s: unsupported parcel version: %d", __func__, version);
148 return INVALID_OPERATION;
Ray Essickba8c4842019-01-18 11:35:33 -0800149 }
150}
151
Ray Essickf27e9872019-12-07 06:28:46 -0800152status_t mediametrics::Item::readFromParcel0(const Parcel& data) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700153 const char *s = data.readCString();
154 mKey = s == nullptr ? "" : s;
155 int32_t pid, uid;
156 status_t status = data.readInt32(&pid) ?: data.readInt32(&uid);
157 if (status != NO_ERROR) return status;
158 mPid = (pid_t)pid;
159 mUid = (uid_t)uid;
160 s = data.readCString();
161 mPkgName = s == nullptr ? "" : s;
162 int32_t count;
163 int64_t version, timestamp;
164 status = data.readInt64(&version) ?: data.readInt64(&timestamp) ?: data.readInt32(&count);
165 if (status != NO_ERROR) return status;
166 if (count < 0) return BAD_VALUE;
167 mPkgVersionCode = version;
168 mTimestamp = timestamp;
Andy Hung47e58d62019-12-06 18:40:19 -0800169 for (int i = 0; i < count; i++) {
170 Prop prop;
171 status_t status = prop.readFromParcel(data);
Andy Hung3253f2d2019-10-21 14:50:07 -0700172 if (status != NO_ERROR) return status;
Andy Hung47e58d62019-12-06 18:40:19 -0800173 mProps[prop.getName()] = std::move(prop);
Ray Essick3938dc62016-11-01 08:56:56 -0700174 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700175 return NO_ERROR;
Ray Essick3938dc62016-11-01 08:56:56 -0700176}
177
Ray Essickf27e9872019-12-07 06:28:46 -0800178status_t mediametrics::Item::writeToParcel(Parcel *data) const {
Andy Hung3253f2d2019-10-21 14:50:07 -0700179 if (data == nullptr) return BAD_VALUE;
Ray Essickba8c4842019-01-18 11:35:33 -0800180
Andy Hung3253f2d2019-10-21 14:50:07 -0700181 const int32_t version = 0;
182 status_t status = data->writeInt32(version);
183 if (status != NO_ERROR) return status;
Ray Essick3938dc62016-11-01 08:56:56 -0700184
Andy Hung3253f2d2019-10-21 14:50:07 -0700185 switch (version) {
186 case 0:
187 return writeToParcel0(data);
188 default:
189 ALOGE("%s: unsupported parcel version: %d", __func__, version);
190 return INVALID_OPERATION;
Ray Essickba8c4842019-01-18 11:35:33 -0800191 }
192}
193
Ray Essickf27e9872019-12-07 06:28:46 -0800194status_t mediametrics::Item::writeToParcel0(Parcel *data) const {
Andy Hung3253f2d2019-10-21 14:50:07 -0700195 status_t status =
196 data->writeCString(mKey.c_str())
197 ?: data->writeInt32(mPid)
198 ?: data->writeInt32(mUid)
199 ?: data->writeCString(mPkgName.c_str())
200 ?: data->writeInt64(mPkgVersionCode)
201 ?: data->writeInt64(mTimestamp);
202 if (status != NO_ERROR) return status;
Ray Essick3938dc62016-11-01 08:56:56 -0700203
Andy Hung47e58d62019-12-06 18:40:19 -0800204 data->writeInt32((int32_t)mProps.size());
205 for (auto &prop : *this) {
206 status = prop.writeToParcel(data);
Andy Hung3253f2d2019-10-21 14:50:07 -0700207 if (status != NO_ERROR) return status;
Ray Essick3938dc62016-11-01 08:56:56 -0700208 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700209 return NO_ERROR;
Ray Essick3938dc62016-11-01 08:56:56 -0700210}
211
Ray Essickf27e9872019-12-07 06:28:46 -0800212const char *mediametrics::Item::toCString() {
Ray Essick20147322018-11-17 09:08:39 -0800213 return toCString(PROTO_LAST);
214}
215
Ray Essickf27e9872019-12-07 06:28:46 -0800216const char * mediametrics::Item::toCString(int version) {
Ray Essick20147322018-11-17 09:08:39 -0800217 std::string val = toString(version);
218 return strdup(val.c_str());
219}
220
Ray Essickf27e9872019-12-07 06:28:46 -0800221std::string mediametrics::Item::toString() const {
Ray Essick5b77bd22018-01-23 16:11:06 -0800222 return toString(PROTO_LAST);
Ray Essickf65f4212017-08-31 11:41:19 -0700223}
Ray Essick3938dc62016-11-01 08:56:56 -0700224
Ray Essickf27e9872019-12-07 06:28:46 -0800225std::string mediametrics::Item::toString(int version) const {
Ray Essick783bd0d2018-01-11 11:10:35 -0800226 std::string result;
Andy Hung1efc9c62019-12-03 13:43:33 -0800227 char buffer[kMaxPropertyStringSize];
Ray Essick3938dc62016-11-01 08:56:56 -0700228
Andy Hung1efc9c62019-12-03 13:43:33 -0800229 snprintf(buffer, sizeof(buffer), "[%d:%s:%d:%d:%lld:%s:%zu:",
230 version, mKey.c_str(), mPid, mUid, (long long)mTimestamp,
Andy Hung47e58d62019-12-06 18:40:19 -0800231 mPkgName.c_str(), mProps.size());
Ray Essickf65f4212017-08-31 11:41:19 -0700232 result.append(buffer);
Andy Hung47e58d62019-12-06 18:40:19 -0800233 for (auto &prop : *this) {
234 prop.toString(buffer, sizeof(buffer));
Andy Hungaeef7882019-10-18 15:18:14 -0700235 result.append(buffer);
Ray Essick3938dc62016-11-01 08:56:56 -0700236 }
Andy Hung1efc9c62019-12-03 13:43:33 -0800237 result.append("]");
Ray Essick3938dc62016-11-01 08:56:56 -0700238 return result;
239}
240
241// for the lazy, we offer methods that finds the service and
242// calls the appropriate daemon
Ray Essickf27e9872019-12-07 06:28:46 -0800243bool mediametrics::Item::selfrecord() {
Andy Hunga87e69c2019-10-18 10:07:40 -0700244 ALOGD_IF(DEBUG_API, "%s: delivering %s", __func__, this->toString().c_str());
Andy Hung47e58d62019-12-06 18:40:19 -0800245 sp<IMediaMetricsService> svc = getService();
Ray Essick3938dc62016-11-01 08:56:56 -0700246 if (svc != NULL) {
Andy Hunga87e69c2019-10-18 10:07:40 -0700247 status_t status = svc->submit(this);
248 if (status != NO_ERROR) {
249 ALOGW("%s: failed to record: %s", __func__, this->toString().c_str());
Ray Essick2ab3c432017-10-02 09:29:49 -0700250 return false;
251 }
Ray Essick3938dc62016-11-01 08:56:56 -0700252 return true;
253 } else {
254 return false;
255 }
256}
257
Ray Essick3938dc62016-11-01 08:56:56 -0700258//static
Andy Hung1efc9c62019-12-03 13:43:33 -0800259bool BaseItem::isEnabled() {
Andy Hunga87e69c2019-10-18 10:07:40 -0700260 // completely skip logging from certain UIDs. We do this here
261 // to avoid the multi-second timeouts while we learn that
262 // sepolicy will not let us find the service.
263 // We do this only for a select set of UIDs
264 // The sepolicy protection is still in place, we just want a faster
265 // response from this specific, small set of uids.
Ray Essick3938dc62016-11-01 08:56:56 -0700266
Andy Hunga87e69c2019-10-18 10:07:40 -0700267 // This is checked only once in the lifetime of the process.
268 const uid_t uid = getuid();
269 switch (uid) {
270 case AID_RADIO: // telephony subsystem, RIL
271 return false;
272 }
273
Ray Essickf27e9872019-12-07 06:28:46 -0800274 int enabled = property_get_int32(Item::EnabledProperty, -1);
Ray Essick3938dc62016-11-01 08:56:56 -0700275 if (enabled == -1) {
Ray Essickf27e9872019-12-07 06:28:46 -0800276 enabled = property_get_int32(Item::EnabledPropertyPersist, -1);
Ray Essick3938dc62016-11-01 08:56:56 -0700277 }
278 if (enabled == -1) {
Ray Essickf27e9872019-12-07 06:28:46 -0800279 enabled = Item::EnabledProperty_default;
Ray Essick3938dc62016-11-01 08:56:56 -0700280 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700281 return enabled > 0;
Ray Essick3938dc62016-11-01 08:56:56 -0700282}
283
Ray Essick2ab3c432017-10-02 09:29:49 -0700284// monitor health of our connection to the metrics service
285class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {
286 virtual void binderDied(const wp<IBinder> &) {
287 ALOGW("Reacquire service connection on next request");
Andy Hung1efc9c62019-12-03 13:43:33 -0800288 BaseItem::dropInstance();
Ray Essick2ab3c432017-10-02 09:29:49 -0700289 }
290};
291
Andy Hunga87e69c2019-10-18 10:07:40 -0700292static sp<MediaMetricsDeathNotifier> sNotifier;
293// static
Ray Essickf27e9872019-12-07 06:28:46 -0800294sp<IMediaMetricsService> BaseItem::sMediaMetricsService;
Andy Hunga87e69c2019-10-18 10:07:40 -0700295static std::mutex sServiceMutex;
296static int sRemainingBindAttempts = SVC_TRIES;
Ray Essick2ab3c432017-10-02 09:29:49 -0700297
298// static
Andy Hung1efc9c62019-12-03 13:43:33 -0800299void BaseItem::dropInstance() {
Andy Hunga87e69c2019-10-18 10:07:40 -0700300 std::lock_guard _l(sServiceMutex);
301 sRemainingBindAttempts = SVC_TRIES;
Ray Essickf27e9872019-12-07 06:28:46 -0800302 sMediaMetricsService = nullptr;
Ray Essick2ab3c432017-10-02 09:29:49 -0700303}
304
Andy Hung1efc9c62019-12-03 13:43:33 -0800305// static
306bool BaseItem::submitBuffer(const char *buffer, size_t size) {
307/*
Ray Essickf27e9872019-12-07 06:28:46 -0800308 mediametrics::Item item;
Andy Hung1efc9c62019-12-03 13:43:33 -0800309 status_t status = item.readFromByteString(buffer, size);
310 ALOGD("%s: status:%d, size:%zu, item:%s", __func__, status, size, item.toString().c_str());
311 return item.selfrecord();
312 */
313
314 ALOGD_IF(DEBUG_API, "%s: delivering %zu bytes", __func__, size);
Andy Hung47e58d62019-12-06 18:40:19 -0800315 sp<IMediaMetricsService> svc = getService();
Andy Hung1efc9c62019-12-03 13:43:33 -0800316 if (svc != nullptr) {
317 const status_t status = svc->submitBuffer(buffer, size);
318 if (status != NO_ERROR) {
319 ALOGW("%s: failed(%d) to record: %zu bytes", __func__, status, size);
320 return false;
321 }
322 return true;
323 }
324 return false;
325}
326
Ray Essick3938dc62016-11-01 08:56:56 -0700327//static
Andy Hung47e58d62019-12-06 18:40:19 -0800328sp<IMediaMetricsService> BaseItem::getService() {
Ray Essickd38e1742017-01-23 15:17:06 -0800329 static const char *servicename = "media.metrics";
Andy Hunga87e69c2019-10-18 10:07:40 -0700330 static const bool enabled = isEnabled(); // singleton initialized
Ray Essick3938dc62016-11-01 08:56:56 -0700331
332 if (enabled == false) {
Andy Hunga87e69c2019-10-18 10:07:40 -0700333 ALOGD_IF(DEBUG_SERVICEACCESS, "disabled");
334 return nullptr;
Ray Essick3938dc62016-11-01 08:56:56 -0700335 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700336 std::lock_guard _l(sServiceMutex);
337 // think of remainingBindAttempts as telling us whether service == nullptr because
338 // (1) we haven't tried to initialize it yet
339 // (2) we've tried to initialize it, but failed.
Ray Essickf27e9872019-12-07 06:28:46 -0800340 if (sMediaMetricsService == nullptr && sRemainingBindAttempts > 0) {
Ray Essick3938dc62016-11-01 08:56:56 -0700341 const char *badness = "";
Andy Hunga87e69c2019-10-18 10:07:40 -0700342 sp<IServiceManager> sm = defaultServiceManager();
343 if (sm != nullptr) {
344 sp<IBinder> binder = sm->getService(String16(servicename));
345 if (binder != nullptr) {
Ray Essickf27e9872019-12-07 06:28:46 -0800346 sMediaMetricsService = interface_cast<IMediaMetricsService>(binder);
Andy Hunga87e69c2019-10-18 10:07:40 -0700347 sNotifier = new MediaMetricsDeathNotifier();
348 binder->linkToDeath(sNotifier);
Ray Essick3938dc62016-11-01 08:56:56 -0700349 } else {
Andy Hunga87e69c2019-10-18 10:07:40 -0700350 badness = "did not find service";
Ray Essick3938dc62016-11-01 08:56:56 -0700351 }
Andy Hunga87e69c2019-10-18 10:07:40 -0700352 } else {
353 badness = "No Service Manager access";
Ray Essick3938dc62016-11-01 08:56:56 -0700354 }
Ray Essickf27e9872019-12-07 06:28:46 -0800355 if (sMediaMetricsService == nullptr) {
Andy Hunga87e69c2019-10-18 10:07:40 -0700356 if (sRemainingBindAttempts > 0) {
357 sRemainingBindAttempts--;
358 }
359 ALOGD_IF(DEBUG_SERVICEACCESS, "%s: unable to bind to service %s: %s",
360 __func__, servicename, badness);
361 }
Ray Essick3938dc62016-11-01 08:56:56 -0700362 }
Ray Essickf27e9872019-12-07 06:28:46 -0800363 return sMediaMetricsService;
Ray Essick3938dc62016-11-01 08:56:56 -0700364}
365
Andy Hung1efc9c62019-12-03 13:43:33 -0800366
Andy Hung3253f2d2019-10-21 14:50:07 -0700367namespace {
Ray Essickba8c4842019-01-18 11:35:33 -0800368
Andy Hung3253f2d2019-10-21 14:50:07 -0700369template <typename T>
370status_t insert(const T& val, char **bufferpptr, char *bufferptrmax)
371{
372 const size_t size = sizeof(val);
373 if (*bufferpptr + size > bufferptrmax) {
374 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
375 return BAD_VALUE;
Ray Essickba8c4842019-01-18 11:35:33 -0800376 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700377 memcpy(*bufferpptr, &val, size);
378 *bufferpptr += size;
379 return NO_ERROR;
Ray Essickba8c4842019-01-18 11:35:33 -0800380}
381
Andy Hung3253f2d2019-10-21 14:50:07 -0700382template <>
383status_t insert(const char * const& val, char **bufferpptr, char *bufferptrmax)
Andy Hungaeef7882019-10-18 15:18:14 -0700384{
Andy Hung3253f2d2019-10-21 14:50:07 -0700385 const size_t size = strlen(val) + 1;
386 if (size > UINT16_MAX || *bufferpptr + size > bufferptrmax) {
387 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
388 return BAD_VALUE;
389 }
390 memcpy(*bufferpptr, val, size);
391 *bufferpptr += size;
392 return NO_ERROR;
393}
394
395template <>
396 __unused
397status_t insert(char * const& val, char **bufferpptr, char *bufferptrmax)
398{
399 return insert((const char *)val, bufferpptr, bufferptrmax);
400}
401
402template <typename T>
403status_t extract(T *val, const char **bufferpptr, const char *bufferptrmax)
404{
405 const size_t size = sizeof(*val);
406 if (*bufferpptr + size > bufferptrmax) {
407 ALOGE("%s: buffer exceeded with size %zu", __func__, size);
408 return BAD_VALUE;
409 }
410 memcpy(val, *bufferpptr, size);
411 *bufferpptr += size;
412 return NO_ERROR;
413}
414
415template <>
416status_t extract(char **val, const char **bufferpptr, const char *bufferptrmax)
417{
418 const char *ptr = *bufferpptr;
419 while (*ptr != 0) {
420 if (ptr >= bufferptrmax) {
421 ALOGE("%s: buffer exceeded", __func__);
Andy Hung1efc9c62019-12-03 13:43:33 -0800422 return BAD_VALUE;
Andy Hung3253f2d2019-10-21 14:50:07 -0700423 }
424 ++ptr;
425 }
426 const size_t size = (ptr - *bufferpptr) + 1;
427 *val = (char *)malloc(size);
428 memcpy(*val, *bufferpptr, size);
429 *bufferpptr += size;
430 return NO_ERROR;
431}
432
433} // namespace
434
Ray Essickf27e9872019-12-07 06:28:46 -0800435status_t mediametrics::Item::writeToByteString(char **pbuffer, size_t *plength) const
Andy Hung3253f2d2019-10-21 14:50:07 -0700436{
437 if (pbuffer == nullptr || plength == nullptr)
438 return BAD_VALUE;
439
440 // get size
441 const size_t keySizeZeroTerminated = strlen(mKey.c_str()) + 1;
442 if (keySizeZeroTerminated > UINT16_MAX) {
443 ALOGW("%s: key size %zu too large", __func__, keySizeZeroTerminated);
444 return INVALID_OPERATION;
445 }
446 const uint16_t version = 0;
Andy Hung1efc9c62019-12-03 13:43:33 -0800447 const uint32_t header_size =
448 sizeof(uint32_t) // total size
449 + sizeof(header_size) // header size
450 + sizeof(version) // encoding version
451 + sizeof(uint16_t) // key size
Andy Hung3253f2d2019-10-21 14:50:07 -0700452 + keySizeZeroTerminated // key, zero terminated
Andy Hung1efc9c62019-12-03 13:43:33 -0800453 + sizeof(int32_t) // pid
454 + sizeof(int32_t) // uid
455 + sizeof(int64_t) // timestamp
Andy Hung3253f2d2019-10-21 14:50:07 -0700456 ;
457
Andy Hung1efc9c62019-12-03 13:43:33 -0800458 uint32_t size = header_size
Andy Hung3253f2d2019-10-21 14:50:07 -0700459 + sizeof(uint32_t) // # properties
460 ;
Andy Hung47e58d62019-12-06 18:40:19 -0800461 for (auto &prop : *this) {
462 const size_t propSize = prop.getByteStringSize();
Andy Hung1efc9c62019-12-03 13:43:33 -0800463 if (propSize > UINT16_MAX) {
Andy Hung47e58d62019-12-06 18:40:19 -0800464 ALOGW("%s: prop %s size %zu too large", __func__, prop.getName(), propSize);
Andy Hung3253f2d2019-10-21 14:50:07 -0700465 return INVALID_OPERATION;
466 }
Andy Hung1efc9c62019-12-03 13:43:33 -0800467 if (__builtin_add_overflow(size, propSize, &size)) {
Andy Hung47e58d62019-12-06 18:40:19 -0800468 ALOGW("%s: item size overflow at property %s", __func__, prop.getName());
Andy Hung1efc9c62019-12-03 13:43:33 -0800469 return INVALID_OPERATION;
470 }
Andy Hung3253f2d2019-10-21 14:50:07 -0700471 }
472
Andy Hung1efc9c62019-12-03 13:43:33 -0800473 // since we fill every byte in the buffer (there is no padding),
474 // malloc is used here instead of calloc.
475 char * const build = (char *)malloc(size);
Andy Hung3253f2d2019-10-21 14:50:07 -0700476 if (build == nullptr) return NO_MEMORY;
477
478 char *filling = build;
Andy Hung1efc9c62019-12-03 13:43:33 -0800479 char *buildmax = build + size;
480 if (insert((uint32_t)size, &filling, buildmax) != NO_ERROR
481 || insert(header_size, &filling, buildmax) != NO_ERROR
Andy Hung3253f2d2019-10-21 14:50:07 -0700482 || insert(version, &filling, buildmax) != NO_ERROR
483 || insert((uint16_t)keySizeZeroTerminated, &filling, buildmax) != NO_ERROR
484 || insert(mKey.c_str(), &filling, buildmax) != NO_ERROR
485 || insert((int32_t)mPid, &filling, buildmax) != NO_ERROR
486 || insert((int32_t)mUid, &filling, buildmax) != NO_ERROR
487 || insert((int64_t)mTimestamp, &filling, buildmax) != NO_ERROR
Andy Hung47e58d62019-12-06 18:40:19 -0800488 || insert((uint32_t)mProps.size(), &filling, buildmax) != NO_ERROR) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800489 ALOGE("%s:could not write header", __func__); // shouldn't happen
Andy Hung3253f2d2019-10-21 14:50:07 -0700490 free(build);
491 return INVALID_OPERATION;
492 }
Andy Hung47e58d62019-12-06 18:40:19 -0800493 for (auto &prop : *this) {
494 if (prop.writeToByteString(&filling, buildmax) != NO_ERROR) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700495 free(build);
Andy Hung1efc9c62019-12-03 13:43:33 -0800496 // shouldn't happen
Andy Hung47e58d62019-12-06 18:40:19 -0800497 ALOGE("%s:could not write prop %s", __func__, prop.getName());
Andy Hung3253f2d2019-10-21 14:50:07 -0700498 return INVALID_OPERATION;
499 }
500 }
501
502 if (filling != buildmax) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800503 ALOGE("%s: problems populating; wrote=%d planned=%d",
504 __func__, (int)(filling - build), (int)size);
Andy Hung3253f2d2019-10-21 14:50:07 -0700505 free(build);
506 return INVALID_OPERATION;
507 }
508 *pbuffer = build;
Andy Hung1efc9c62019-12-03 13:43:33 -0800509 *plength = size;
Andy Hung3253f2d2019-10-21 14:50:07 -0700510 return NO_ERROR;
511}
512
Ray Essickf27e9872019-12-07 06:28:46 -0800513status_t mediametrics::Item::readFromByteString(const char *bufferptr, size_t length)
Andy Hung3253f2d2019-10-21 14:50:07 -0700514{
515 if (bufferptr == nullptr) return BAD_VALUE;
516
517 const char *read = bufferptr;
518 const char *readend = bufferptr + length;
519
Andy Hung1efc9c62019-12-03 13:43:33 -0800520 uint32_t size;
521 uint32_t header_size;
522 uint16_t version;
523 uint16_t key_size;
Andy Hung3253f2d2019-10-21 14:50:07 -0700524 char *key = nullptr;
525 int32_t pid;
526 int32_t uid;
527 int64_t timestamp;
528 uint32_t propCount;
Andy Hung1efc9c62019-12-03 13:43:33 -0800529 if (extract(&size, &read, readend) != NO_ERROR
530 || extract(&header_size, &read, readend) != NO_ERROR
Andy Hung3253f2d2019-10-21 14:50:07 -0700531 || extract(&version, &read, readend) != NO_ERROR
Andy Hung1efc9c62019-12-03 13:43:33 -0800532 || extract(&key_size, &read, readend) != NO_ERROR
Andy Hung3253f2d2019-10-21 14:50:07 -0700533 || extract(&key, &read, readend) != NO_ERROR
534 || extract(&pid, &read, readend) != NO_ERROR
535 || extract(&uid, &read, readend) != NO_ERROR
536 || extract(&timestamp, &read, readend) != NO_ERROR
Andy Hung1efc9c62019-12-03 13:43:33 -0800537 || size > length
538 || strlen(key) + 1 != key_size
539 || header_size > size) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700540 free(key);
Andy Hung1efc9c62019-12-03 13:43:33 -0800541 ALOGW("%s: invalid header", __func__);
Andy Hung3253f2d2019-10-21 14:50:07 -0700542 return INVALID_OPERATION;
543 }
544 mKey = key;
545 free(key);
546 const size_t pos = read - bufferptr;
Andy Hung1efc9c62019-12-03 13:43:33 -0800547 if (pos > header_size) {
548 ALOGW("%s: invalid header pos:%zu > header_size:%u",
549 __func__, pos, header_size);
Andy Hung3253f2d2019-10-21 14:50:07 -0700550 return INVALID_OPERATION;
Andy Hung1efc9c62019-12-03 13:43:33 -0800551 } else if (pos < header_size) {
552 ALOGW("%s: mismatched header pos:%zu < header_size:%u, advancing",
553 __func__, pos, header_size);
554 read += (header_size - pos);
Andy Hung3253f2d2019-10-21 14:50:07 -0700555 }
556 if (extract(&propCount, &read, readend) != NO_ERROR) {
557 ALOGD("%s: cannot read prop count", __func__);
558 return INVALID_OPERATION;
559 }
560 mPid = pid;
561 mUid = uid;
562 mTimestamp = timestamp;
563 for (size_t i = 0; i < propCount; ++i) {
Andy Hung47e58d62019-12-06 18:40:19 -0800564 Prop prop;
565 if (prop.readFromByteString(&read, readend) != NO_ERROR) {
Andy Hung1efc9c62019-12-03 13:43:33 -0800566 ALOGW("%s: cannot read prop %zu", __func__, i);
Andy Hung3253f2d2019-10-21 14:50:07 -0700567 return INVALID_OPERATION;
568 }
Andy Hung47e58d62019-12-06 18:40:19 -0800569 mProps[prop.getName()] = std::move(prop);
Andy Hung3253f2d2019-10-21 14:50:07 -0700570 }
571 return NO_ERROR;
572}
573
Ray Essickf27e9872019-12-07 06:28:46 -0800574status_t mediametrics::Item::Prop::writeToParcel(Parcel *data) const
Andy Hung3253f2d2019-10-21 14:50:07 -0700575{
Andy Hungaeef7882019-10-18 15:18:14 -0700576 switch (mType) {
Andy Hung47e58d62019-12-06 18:40:19 -0800577 case mediametrics::kTypeInt32:
578 return data->writeCString(mName.c_str())
Andy Hung3253f2d2019-10-21 14:50:07 -0700579 ?: data->writeInt32(mType)
580 ?: data->writeInt32(u.int32Value);
Andy Hung47e58d62019-12-06 18:40:19 -0800581 case mediametrics::kTypeInt64:
582 return data->writeCString(mName.c_str())
Andy Hung3253f2d2019-10-21 14:50:07 -0700583 ?: data->writeInt32(mType)
584 ?: data->writeInt64(u.int64Value);
Andy Hung47e58d62019-12-06 18:40:19 -0800585 case mediametrics::kTypeDouble:
586 return data->writeCString(mName.c_str())
Andy Hung3253f2d2019-10-21 14:50:07 -0700587 ?: data->writeInt32(mType)
588 ?: data->writeDouble(u.doubleValue);
Andy Hung47e58d62019-12-06 18:40:19 -0800589 case mediametrics::kTypeRate:
590 return data->writeCString(mName.c_str())
Andy Hung3253f2d2019-10-21 14:50:07 -0700591 ?: data->writeInt32(mType)
592 ?: data->writeInt64(u.rate.first)
593 ?: data->writeInt64(u.rate.second);
Andy Hung47e58d62019-12-06 18:40:19 -0800594 case mediametrics::kTypeCString:
595 return data->writeCString(mName.c_str())
Andy Hung3253f2d2019-10-21 14:50:07 -0700596 ?: data->writeInt32(mType)
597 ?: data->writeCString(u.CStringValue);
Andy Hungaeef7882019-10-18 15:18:14 -0700598 default:
Andy Hung47e58d62019-12-06 18:40:19 -0800599 ALOGE("%s: found bad type: %d, name %s", __func__, mType, mName.c_str());
Andy Hung3253f2d2019-10-21 14:50:07 -0700600 return BAD_VALUE;
Andy Hungaeef7882019-10-18 15:18:14 -0700601 }
602}
603
Ray Essickf27e9872019-12-07 06:28:46 -0800604status_t mediametrics::Item::Prop::readFromParcel(const Parcel& data)
Andy Hung3253f2d2019-10-21 14:50:07 -0700605{
606 const char *key = data.readCString();
607 if (key == nullptr) return BAD_VALUE;
608 int32_t type;
609 status_t status = data.readInt32(&type);
610 if (status != NO_ERROR) return status;
611 switch (type) {
Andy Hung47e58d62019-12-06 18:40:19 -0800612 case mediametrics::kTypeInt32:
Andy Hung3253f2d2019-10-21 14:50:07 -0700613 status = data.readInt32(&u.int32Value);
614 break;
Andy Hung47e58d62019-12-06 18:40:19 -0800615 case mediametrics::kTypeInt64:
Andy Hung3253f2d2019-10-21 14:50:07 -0700616 status = data.readInt64(&u.int64Value);
617 break;
Andy Hung47e58d62019-12-06 18:40:19 -0800618 case mediametrics::kTypeDouble:
Andy Hung3253f2d2019-10-21 14:50:07 -0700619 status = data.readDouble(&u.doubleValue);
620 break;
Andy Hung47e58d62019-12-06 18:40:19 -0800621 case mediametrics::kTypeCString: {
Andy Hung3253f2d2019-10-21 14:50:07 -0700622 const char *s = data.readCString();
623 if (s == nullptr) return BAD_VALUE;
624 set(s);
625 break;
626 }
Andy Hung47e58d62019-12-06 18:40:19 -0800627 case mediametrics::kTypeRate: {
Andy Hung3253f2d2019-10-21 14:50:07 -0700628 std::pair<int64_t, int64_t> rate;
629 status = data.readInt64(&rate.first)
630 ?: data.readInt64(&rate.second);
631 if (status == NO_ERROR) {
632 set(rate);
633 }
634 break;
635 }
636 default:
637 ALOGE("%s: reading bad item type: %d", __func__, mType);
638 return BAD_VALUE;
639 }
640 if (status == NO_ERROR) {
641 setName(key);
Andy Hung47e58d62019-12-06 18:40:19 -0800642 mType = (mediametrics::Type)type;
Andy Hung3253f2d2019-10-21 14:50:07 -0700643 }
644 return status;
645}
646
Ray Essickf27e9872019-12-07 06:28:46 -0800647void mediametrics::Item::Prop::toString(char *buffer, size_t length) const
Andy Hung3253f2d2019-10-21 14:50:07 -0700648{
Andy Hungaeef7882019-10-18 15:18:14 -0700649 switch (mType) {
Andy Hung47e58d62019-12-06 18:40:19 -0800650 case mediametrics::kTypeInt32:
651 snprintf(buffer, length, "%s=%d:", mName.c_str(), u.int32Value);
Andy Hungaeef7882019-10-18 15:18:14 -0700652 break;
Andy Hung47e58d62019-12-06 18:40:19 -0800653 case mediametrics::kTypeInt64:
654 snprintf(buffer, length, "%s=%lld:", mName.c_str(), (long long)u.int64Value);
Andy Hungaeef7882019-10-18 15:18:14 -0700655 break;
Andy Hung47e58d62019-12-06 18:40:19 -0800656 case mediametrics::kTypeDouble:
657 snprintf(buffer, length, "%s=%e:", mName.c_str(), u.doubleValue);
Andy Hungaeef7882019-10-18 15:18:14 -0700658 break;
Andy Hung47e58d62019-12-06 18:40:19 -0800659 case mediametrics::kTypeRate:
Andy Hungaeef7882019-10-18 15:18:14 -0700660 snprintf(buffer, length, "%s=%lld/%lld:",
Andy Hung47e58d62019-12-06 18:40:19 -0800661 mName.c_str(), (long long)u.rate.first, (long long)u.rate.second);
Andy Hungaeef7882019-10-18 15:18:14 -0700662 break;
Andy Hung47e58d62019-12-06 18:40:19 -0800663 case mediametrics::kTypeCString:
Andy Hungaeef7882019-10-18 15:18:14 -0700664 // TODO sanitize string for ':' '='
Andy Hung47e58d62019-12-06 18:40:19 -0800665 snprintf(buffer, length, "%s=%s:", mName.c_str(), u.CStringValue);
Andy Hungaeef7882019-10-18 15:18:14 -0700666 break;
667 default:
Andy Hung47e58d62019-12-06 18:40:19 -0800668 ALOGE("%s: bad item type: %d for %s", __func__, mType, mName.c_str());
Andy Hungaeef7882019-10-18 15:18:14 -0700669 if (length > 0) buffer[0] = 0;
670 break;
671 }
672}
673
Ray Essickf27e9872019-12-07 06:28:46 -0800674size_t mediametrics::Item::Prop::getByteStringSize() const
Andy Hung3253f2d2019-10-21 14:50:07 -0700675{
676 const size_t header =
677 sizeof(uint16_t) // length
678 + sizeof(uint8_t) // type
Andy Hung47e58d62019-12-06 18:40:19 -0800679 + mName.size() + 1; // mName + 0 termination
Andy Hung3253f2d2019-10-21 14:50:07 -0700680 size_t payload = 0;
681 switch (mType) {
Andy Hung47e58d62019-12-06 18:40:19 -0800682 case mediametrics::kTypeInt32:
Andy Hung3253f2d2019-10-21 14:50:07 -0700683 payload = sizeof(u.int32Value);
684 break;
Andy Hung47e58d62019-12-06 18:40:19 -0800685 case mediametrics::kTypeInt64:
Andy Hung3253f2d2019-10-21 14:50:07 -0700686 payload = sizeof(u.int64Value);
687 break;
Andy Hung47e58d62019-12-06 18:40:19 -0800688 case mediametrics::kTypeDouble:
Andy Hung3253f2d2019-10-21 14:50:07 -0700689 payload = sizeof(u.doubleValue);
690 break;
Andy Hung47e58d62019-12-06 18:40:19 -0800691 case mediametrics::kTypeRate:
Andy Hung3253f2d2019-10-21 14:50:07 -0700692 payload = sizeof(u.rate.first) + sizeof(u.rate.second);
693 break;
Andy Hung47e58d62019-12-06 18:40:19 -0800694 case mediametrics::kTypeCString:
Andy Hung3253f2d2019-10-21 14:50:07 -0700695 payload = strlen(u.CStringValue) + 1;
696 break;
697 default:
698 ALOGE("%s: found bad prop type: %d, name %s",
Andy Hung47e58d62019-12-06 18:40:19 -0800699 __func__, mType, mName.c_str()); // no payload computed
Andy Hung3253f2d2019-10-21 14:50:07 -0700700 break;
701 }
702 return header + payload;
703}
Ray Essick3938dc62016-11-01 08:56:56 -0700704
Andy Hung1efc9c62019-12-03 13:43:33 -0800705
Andy Hung3253f2d2019-10-21 14:50:07 -0700706// TODO: fold into a template later.
Andy Hung1efc9c62019-12-03 13:43:33 -0800707status_t BaseItem::writeToByteString(
Andy Hung3253f2d2019-10-21 14:50:07 -0700708 const char *name, int32_t value, char **bufferpptr, char *bufferptrmax)
709{
710 const size_t len = 2 + 1 + strlen(name) + 1 + sizeof(value);
711 if (len > UINT16_MAX) return BAD_VALUE;
712 return insert((uint16_t)len, bufferpptr, bufferptrmax)
Andy Hung47e58d62019-12-06 18:40:19 -0800713 ?: insert((uint8_t)mediametrics::kTypeInt32, bufferpptr, bufferptrmax)
Andy Hung3253f2d2019-10-21 14:50:07 -0700714 ?: insert(name, bufferpptr, bufferptrmax)
715 ?: insert(value, bufferpptr, bufferptrmax);
716}
717
Andy Hung1efc9c62019-12-03 13:43:33 -0800718status_t BaseItem::writeToByteString(
Andy Hung3253f2d2019-10-21 14:50:07 -0700719 const char *name, int64_t value, char **bufferpptr, char *bufferptrmax)
720{
721 const size_t len = 2 + 1 + strlen(name) + 1 + sizeof(value);
722 if (len > UINT16_MAX) return BAD_VALUE;
723 return insert((uint16_t)len, bufferpptr, bufferptrmax)
Andy Hung47e58d62019-12-06 18:40:19 -0800724 ?: insert((uint8_t)mediametrics::kTypeInt64, bufferpptr, bufferptrmax)
Andy Hung3253f2d2019-10-21 14:50:07 -0700725 ?: insert(name, bufferpptr, bufferptrmax)
726 ?: insert(value, bufferpptr, bufferptrmax);
727}
728
Andy Hung1efc9c62019-12-03 13:43:33 -0800729status_t BaseItem::writeToByteString(
Andy Hung3253f2d2019-10-21 14:50:07 -0700730 const char *name, double value, char **bufferpptr, char *bufferptrmax)
731{
732 const size_t len = 2 + 1 + strlen(name) + 1 + sizeof(value);
733 if (len > UINT16_MAX) return BAD_VALUE;
734 return insert((uint16_t)len, bufferpptr, bufferptrmax)
Andy Hung47e58d62019-12-06 18:40:19 -0800735 ?: insert((uint8_t)mediametrics::kTypeDouble, bufferpptr, bufferptrmax)
Andy Hung3253f2d2019-10-21 14:50:07 -0700736 ?: insert(name, bufferpptr, bufferptrmax)
737 ?: insert(value, bufferpptr, bufferptrmax);
738}
739
Andy Hung1efc9c62019-12-03 13:43:33 -0800740status_t BaseItem::writeToByteString(
Andy Hung3253f2d2019-10-21 14:50:07 -0700741 const char *name, const std::pair<int64_t, int64_t> &value, char **bufferpptr, char *bufferptrmax)
742{
743 const size_t len = 2 + 1 + strlen(name) + 1 + 8 + 8;
744 if (len > UINT16_MAX) return BAD_VALUE;
745 return insert((uint16_t)len, bufferpptr, bufferptrmax)
Andy Hung47e58d62019-12-06 18:40:19 -0800746 ?: insert((uint8_t)mediametrics::kTypeRate, bufferpptr, bufferptrmax)
Andy Hung3253f2d2019-10-21 14:50:07 -0700747 ?: insert(name, bufferpptr, bufferptrmax)
748 ?: insert(value.first, bufferpptr, bufferptrmax)
749 ?: insert(value.second, bufferpptr, bufferptrmax);
750}
751
Andy Hung1efc9c62019-12-03 13:43:33 -0800752status_t BaseItem::writeToByteString(
Andy Hung3253f2d2019-10-21 14:50:07 -0700753 const char *name, char * const &value, char **bufferpptr, char *bufferptrmax)
754{
Andy Hung1efc9c62019-12-03 13:43:33 -0800755 return writeToByteString(name, (const char *)value, bufferpptr, bufferptrmax);
756}
757
758status_t BaseItem::writeToByteString(
759 const char *name, const char * const &value, char **bufferpptr, char *bufferptrmax)
760{
Andy Hung3253f2d2019-10-21 14:50:07 -0700761 const size_t len = 2 + 1 + strlen(name) + 1 + strlen(value) + 1;
762 if (len > UINT16_MAX) return BAD_VALUE;
763 return insert((uint16_t)len, bufferpptr, bufferptrmax)
Andy Hung47e58d62019-12-06 18:40:19 -0800764 ?: insert((uint8_t)mediametrics::kTypeCString, bufferpptr, bufferptrmax)
Andy Hung3253f2d2019-10-21 14:50:07 -0700765 ?: insert(name, bufferpptr, bufferptrmax)
766 ?: insert(value, bufferpptr, bufferptrmax);
767}
768
Andy Hung1efc9c62019-12-03 13:43:33 -0800769
770status_t BaseItem::writeToByteString(
Andy Hung3253f2d2019-10-21 14:50:07 -0700771 const char *name, const none_t &, char **bufferpptr, char *bufferptrmax)
772{
773 const size_t len = 2 + 1 + strlen(name) + 1;
774 if (len > UINT16_MAX) return BAD_VALUE;
775 return insert((uint16_t)len, bufferpptr, bufferptrmax)
Andy Hung47e58d62019-12-06 18:40:19 -0800776 ?: insert((uint8_t)mediametrics::kTypeCString, bufferpptr, bufferptrmax)
Andy Hung3253f2d2019-10-21 14:50:07 -0700777 ?: insert(name, bufferpptr, bufferptrmax);
778}
779
Andy Hung1efc9c62019-12-03 13:43:33 -0800780
Ray Essickf27e9872019-12-07 06:28:46 -0800781status_t mediametrics::Item::Prop::writeToByteString(
Andy Hung3253f2d2019-10-21 14:50:07 -0700782 char **bufferpptr, char *bufferptrmax) const
783{
784 switch (mType) {
Andy Hung47e58d62019-12-06 18:40:19 -0800785 case mediametrics::kTypeInt32:
786 return BaseItem::writeToByteString(mName.c_str(), u.int32Value, bufferpptr, bufferptrmax);
787 case mediametrics::kTypeInt64:
788 return BaseItem::writeToByteString(mName.c_str(), u.int64Value, bufferpptr, bufferptrmax);
789 case mediametrics::kTypeDouble:
790 return BaseItem::writeToByteString(mName.c_str(), u.doubleValue, bufferpptr, bufferptrmax);
791 case mediametrics::kTypeRate:
792 return BaseItem::writeToByteString(mName.c_str(), u.rate, bufferpptr, bufferptrmax);
793 case mediametrics::kTypeCString:
794 return BaseItem::writeToByteString(
795 mName.c_str(), u.CStringValue, bufferpptr, bufferptrmax);
796 case mediametrics::kTypeNone:
797 return BaseItem::writeToByteString(mName.c_str(), none_t{}, bufferpptr, bufferptrmax);
Andy Hung3253f2d2019-10-21 14:50:07 -0700798 default:
799 ALOGE("%s: found bad prop type: %d, name %s",
Andy Hung47e58d62019-12-06 18:40:19 -0800800 __func__, mType, mName.c_str()); // no payload sent
Andy Hung3253f2d2019-10-21 14:50:07 -0700801 return BAD_VALUE;
802 }
803}
804
Ray Essickf27e9872019-12-07 06:28:46 -0800805status_t mediametrics::Item::Prop::readFromByteString(
Andy Hung3253f2d2019-10-21 14:50:07 -0700806 const char **bufferpptr, const char *bufferptrmax)
807{
808 uint16_t len;
809 char *name;
810 uint8_t type;
811 status_t status = extract(&len, bufferpptr, bufferptrmax)
812 ?: extract(&type, bufferpptr, bufferptrmax)
813 ?: extract(&name, bufferpptr, bufferptrmax);
814 if (status != NO_ERROR) return status;
Andy Hung3253f2d2019-10-21 14:50:07 -0700815 mName = name;
Andy Hung47e58d62019-12-06 18:40:19 -0800816 if (mType == mediametrics::kTypeCString) {
Andy Hung3253f2d2019-10-21 14:50:07 -0700817 free(u.CStringValue);
818 u.CStringValue = nullptr;
819 }
Andy Hung47e58d62019-12-06 18:40:19 -0800820 mType = (mediametrics::Type)type;
Andy Hung3253f2d2019-10-21 14:50:07 -0700821 switch (mType) {
Andy Hung47e58d62019-12-06 18:40:19 -0800822 case mediametrics::kTypeInt32:
Andy Hung3253f2d2019-10-21 14:50:07 -0700823 return extract(&u.int32Value, bufferpptr, bufferptrmax);
Andy Hung47e58d62019-12-06 18:40:19 -0800824 case mediametrics::kTypeInt64:
Andy Hung3253f2d2019-10-21 14:50:07 -0700825 return extract(&u.int64Value, bufferpptr, bufferptrmax);
Andy Hung47e58d62019-12-06 18:40:19 -0800826 case mediametrics::kTypeDouble:
Andy Hung3253f2d2019-10-21 14:50:07 -0700827 return extract(&u.doubleValue, bufferpptr, bufferptrmax);
Andy Hung47e58d62019-12-06 18:40:19 -0800828 case mediametrics::kTypeRate:
Andy Hung3253f2d2019-10-21 14:50:07 -0700829 return extract(&u.rate.first, bufferpptr, bufferptrmax)
830 ?: extract(&u.rate.second, bufferpptr, bufferptrmax);
Andy Hung47e58d62019-12-06 18:40:19 -0800831 case mediametrics::kTypeCString:
Andy Hung3253f2d2019-10-21 14:50:07 -0700832 status = extract(&u.CStringValue, bufferpptr, bufferptrmax);
Andy Hung47e58d62019-12-06 18:40:19 -0800833 if (status != NO_ERROR) mType = mediametrics::kTypeNone;
Andy Hung3253f2d2019-10-21 14:50:07 -0700834 return status;
Andy Hung47e58d62019-12-06 18:40:19 -0800835 case mediametrics::kTypeNone:
Andy Hung3253f2d2019-10-21 14:50:07 -0700836 return NO_ERROR;
837 default:
Andy Hung47e58d62019-12-06 18:40:19 -0800838 mType = mediametrics::kTypeNone;
Andy Hung3253f2d2019-10-21 14:50:07 -0700839 ALOGE("%s: found bad prop type: %d, name %s",
Andy Hung47e58d62019-12-06 18:40:19 -0800840 __func__, mType, mName.c_str()); // no payload sent
Andy Hung3253f2d2019-10-21 14:50:07 -0700841 return BAD_VALUE;
842 }
843}
844
Ray Essickf27e9872019-12-07 06:28:46 -0800845} // namespace android::mediametrics