xref: /aosp_15_r20/frameworks/av/media/libmediametrics/MediaMetricsItem.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker  * Copyright (C) 2016 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker  *
4*ec779b8eSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker  *
8*ec779b8eSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker  *
10*ec779b8eSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker  * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker  */
16*ec779b8eSAndroid Build Coastguard Worker 
17*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "mediametrics::Item"
18*ec779b8eSAndroid Build Coastguard Worker 
19*ec779b8eSAndroid Build Coastguard Worker #include <inttypes.h>
20*ec779b8eSAndroid Build Coastguard Worker #include <stdlib.h>
21*ec779b8eSAndroid Build Coastguard Worker #include <string.h>
22*ec779b8eSAndroid Build Coastguard Worker #include <sys/types.h>
23*ec779b8eSAndroid Build Coastguard Worker 
24*ec779b8eSAndroid Build Coastguard Worker #include <mutex>
25*ec779b8eSAndroid Build Coastguard Worker #include <set>
26*ec779b8eSAndroid Build Coastguard Worker #include <unordered_map>
27*ec779b8eSAndroid Build Coastguard Worker 
28*ec779b8eSAndroid Build Coastguard Worker #include <binder/Parcel.h>
29*ec779b8eSAndroid Build Coastguard Worker #include <cutils/multiuser.h>
30*ec779b8eSAndroid Build Coastguard Worker #include <cutils/properties.h>
31*ec779b8eSAndroid Build Coastguard Worker #include <utils/Errors.h>
32*ec779b8eSAndroid Build Coastguard Worker #include <utils/Log.h>
33*ec779b8eSAndroid Build Coastguard Worker #include <utils/SortedVector.h>
34*ec779b8eSAndroid Build Coastguard Worker #include <utils/threads.h>
35*ec779b8eSAndroid Build Coastguard Worker 
36*ec779b8eSAndroid Build Coastguard Worker #include <android/media/BnMediaMetricsService.h> // for direct Binder access
37*ec779b8eSAndroid Build Coastguard Worker #include <android/media/IMediaMetricsService.h>
38*ec779b8eSAndroid Build Coastguard Worker #include <binder/IServiceManager.h>
39*ec779b8eSAndroid Build Coastguard Worker #include <media/MediaMetricsItem.h>
40*ec779b8eSAndroid Build Coastguard Worker #include <private/android_filesystem_config.h>
41*ec779b8eSAndroid Build Coastguard Worker 
42*ec779b8eSAndroid Build Coastguard Worker // Max per-property string size before truncation in toString().
43*ec779b8eSAndroid Build Coastguard Worker // Do not make too large, as this is used for dumpsys purposes.
44*ec779b8eSAndroid Build Coastguard Worker static constexpr size_t kMaxPropertyStringSize = 4096;
45*ec779b8eSAndroid Build Coastguard Worker 
46*ec779b8eSAndroid Build Coastguard Worker namespace android::mediametrics {
47*ec779b8eSAndroid Build Coastguard Worker 
48*ec779b8eSAndroid Build Coastguard Worker #define DEBUG_SERVICEACCESS     0
49*ec779b8eSAndroid Build Coastguard Worker #define DEBUG_API               0
50*ec779b8eSAndroid Build Coastguard Worker #define DEBUG_ALLOCATIONS       0
51*ec779b8eSAndroid Build Coastguard Worker 
52*ec779b8eSAndroid Build Coastguard Worker // after this many failed attempts, we stop trying [from this process] and just say that
53*ec779b8eSAndroid Build Coastguard Worker // the service is off.
54*ec779b8eSAndroid Build Coastguard Worker #define SVC_TRIES               2
55*ec779b8eSAndroid Build Coastguard Worker 
getErrorStringMap()56*ec779b8eSAndroid Build Coastguard Worker static const std::unordered_map<std::string, int32_t>& getErrorStringMap() {
57*ec779b8eSAndroid Build Coastguard Worker     // DO NOT MODIFY VALUES (OK to add new ones).
58*ec779b8eSAndroid Build Coastguard Worker     // This may be found in frameworks/av/media/libmediametrics/include/MediaMetricsConstants.h
59*ec779b8eSAndroid Build Coastguard Worker     static std::unordered_map<std::string, int32_t> map{
60*ec779b8eSAndroid Build Coastguard Worker         {"",                                      NO_ERROR},
61*ec779b8eSAndroid Build Coastguard Worker         {AMEDIAMETRICS_PROP_STATUS_VALUE_OK,       NO_ERROR},
62*ec779b8eSAndroid Build Coastguard Worker         {AMEDIAMETRICS_PROP_STATUS_VALUE_ARGUMENT, BAD_VALUE},
63*ec779b8eSAndroid Build Coastguard Worker         {AMEDIAMETRICS_PROP_STATUS_VALUE_IO,       DEAD_OBJECT},
64*ec779b8eSAndroid Build Coastguard Worker         {AMEDIAMETRICS_PROP_STATUS_VALUE_MEMORY,   NO_MEMORY},
65*ec779b8eSAndroid Build Coastguard Worker         {AMEDIAMETRICS_PROP_STATUS_VALUE_SECURITY, PERMISSION_DENIED},
66*ec779b8eSAndroid Build Coastguard Worker         {AMEDIAMETRICS_PROP_STATUS_VALUE_STATE,    INVALID_OPERATION},
67*ec779b8eSAndroid Build Coastguard Worker         {AMEDIAMETRICS_PROP_STATUS_VALUE_TIMEOUT,  WOULD_BLOCK},
68*ec779b8eSAndroid Build Coastguard Worker         {AMEDIAMETRICS_PROP_STATUS_VALUE_UNKNOWN,  UNKNOWN_ERROR},
69*ec779b8eSAndroid Build Coastguard Worker     };
70*ec779b8eSAndroid Build Coastguard Worker     return map;
71*ec779b8eSAndroid Build Coastguard Worker }
72*ec779b8eSAndroid Build Coastguard Worker 
statusStringToStatus(const char * error)73*ec779b8eSAndroid Build Coastguard Worker status_t statusStringToStatus(const char *error) {
74*ec779b8eSAndroid Build Coastguard Worker     const auto& map = getErrorStringMap();
75*ec779b8eSAndroid Build Coastguard Worker     if (error == nullptr || error[0] == '\0') return NO_ERROR;
76*ec779b8eSAndroid Build Coastguard Worker     auto it = map.find(error);
77*ec779b8eSAndroid Build Coastguard Worker     if (it != map.end()) {
78*ec779b8eSAndroid Build Coastguard Worker         return it->second;
79*ec779b8eSAndroid Build Coastguard Worker     }
80*ec779b8eSAndroid Build Coastguard Worker     return UNKNOWN_ERROR;
81*ec779b8eSAndroid Build Coastguard Worker }
82*ec779b8eSAndroid Build Coastguard Worker 
convert(mediametrics_handle_t handle)83*ec779b8eSAndroid Build Coastguard Worker mediametrics::Item* mediametrics::Item::convert(mediametrics_handle_t handle) {
84*ec779b8eSAndroid Build Coastguard Worker     mediametrics::Item *item = (android::mediametrics::Item *) handle;
85*ec779b8eSAndroid Build Coastguard Worker     return item;
86*ec779b8eSAndroid Build Coastguard Worker }
87*ec779b8eSAndroid Build Coastguard Worker 
convert(mediametrics::Item * item)88*ec779b8eSAndroid Build Coastguard Worker mediametrics_handle_t mediametrics::Item::convert(mediametrics::Item *item ) {
89*ec779b8eSAndroid Build Coastguard Worker     mediametrics_handle_t handle = (mediametrics_handle_t) item;
90*ec779b8eSAndroid Build Coastguard Worker     return handle;
91*ec779b8eSAndroid Build Coastguard Worker }
92*ec779b8eSAndroid Build Coastguard Worker 
~Item()93*ec779b8eSAndroid Build Coastguard Worker mediametrics::Item::~Item() {
94*ec779b8eSAndroid Build Coastguard Worker     if (DEBUG_ALLOCATIONS) {
95*ec779b8eSAndroid Build Coastguard Worker         ALOGD("Destroy  mediametrics::Item @ %p", this);
96*ec779b8eSAndroid Build Coastguard Worker     }
97*ec779b8eSAndroid Build Coastguard Worker }
98*ec779b8eSAndroid Build Coastguard Worker 
setTimestamp(nsecs_t ts)99*ec779b8eSAndroid Build Coastguard Worker mediametrics::Item &mediametrics::Item::setTimestamp(nsecs_t ts) {
100*ec779b8eSAndroid Build Coastguard Worker     mTimestamp = ts;
101*ec779b8eSAndroid Build Coastguard Worker     return *this;
102*ec779b8eSAndroid Build Coastguard Worker }
103*ec779b8eSAndroid Build Coastguard Worker 
getTimestamp() const104*ec779b8eSAndroid Build Coastguard Worker nsecs_t mediametrics::Item::getTimestamp() const {
105*ec779b8eSAndroid Build Coastguard Worker     return mTimestamp;
106*ec779b8eSAndroid Build Coastguard Worker }
107*ec779b8eSAndroid Build Coastguard Worker 
setPid(pid_t pid)108*ec779b8eSAndroid Build Coastguard Worker mediametrics::Item &mediametrics::Item::setPid(pid_t pid) {
109*ec779b8eSAndroid Build Coastguard Worker     mPid = pid;
110*ec779b8eSAndroid Build Coastguard Worker     return *this;
111*ec779b8eSAndroid Build Coastguard Worker }
112*ec779b8eSAndroid Build Coastguard Worker 
getPid() const113*ec779b8eSAndroid Build Coastguard Worker pid_t mediametrics::Item::getPid() const {
114*ec779b8eSAndroid Build Coastguard Worker     return mPid;
115*ec779b8eSAndroid Build Coastguard Worker }
116*ec779b8eSAndroid Build Coastguard Worker 
setUid(uid_t uid)117*ec779b8eSAndroid Build Coastguard Worker mediametrics::Item &mediametrics::Item::setUid(uid_t uid) {
118*ec779b8eSAndroid Build Coastguard Worker     mUid = uid;
119*ec779b8eSAndroid Build Coastguard Worker     return *this;
120*ec779b8eSAndroid Build Coastguard Worker }
121*ec779b8eSAndroid Build Coastguard Worker 
getUid() const122*ec779b8eSAndroid Build Coastguard Worker uid_t mediametrics::Item::getUid() const {
123*ec779b8eSAndroid Build Coastguard Worker     return mUid;
124*ec779b8eSAndroid Build Coastguard Worker }
125*ec779b8eSAndroid Build Coastguard Worker 
setPkgName(const std::string & pkgName)126*ec779b8eSAndroid Build Coastguard Worker mediametrics::Item &mediametrics::Item::setPkgName(const std::string &pkgName) {
127*ec779b8eSAndroid Build Coastguard Worker     mPkgName = pkgName;
128*ec779b8eSAndroid Build Coastguard Worker     return *this;
129*ec779b8eSAndroid Build Coastguard Worker }
130*ec779b8eSAndroid Build Coastguard Worker 
setPkgVersionCode(int64_t pkgVersionCode)131*ec779b8eSAndroid Build Coastguard Worker mediametrics::Item &mediametrics::Item::setPkgVersionCode(int64_t pkgVersionCode) {
132*ec779b8eSAndroid Build Coastguard Worker     mPkgVersionCode = pkgVersionCode;
133*ec779b8eSAndroid Build Coastguard Worker     return *this;
134*ec779b8eSAndroid Build Coastguard Worker }
135*ec779b8eSAndroid Build Coastguard Worker 
getPkgVersionCode() const136*ec779b8eSAndroid Build Coastguard Worker int64_t mediametrics::Item::getPkgVersionCode() const {
137*ec779b8eSAndroid Build Coastguard Worker     return mPkgVersionCode;
138*ec779b8eSAndroid Build Coastguard Worker }
139*ec779b8eSAndroid Build Coastguard Worker 
140*ec779b8eSAndroid Build Coastguard Worker // remove indicated keys and their values
141*ec779b8eSAndroid Build Coastguard Worker // return value is # keys removed
filter(size_t n,const char * attrs[])142*ec779b8eSAndroid Build Coastguard Worker size_t mediametrics::Item::filter(size_t n, const char *attrs[]) {
143*ec779b8eSAndroid Build Coastguard Worker     size_t zapped = 0;
144*ec779b8eSAndroid Build Coastguard Worker     for (size_t i = 0; i < n; ++i) {
145*ec779b8eSAndroid Build Coastguard Worker         zapped += mProps.erase(attrs[i]);
146*ec779b8eSAndroid Build Coastguard Worker     }
147*ec779b8eSAndroid Build Coastguard Worker     return zapped;
148*ec779b8eSAndroid Build Coastguard Worker }
149*ec779b8eSAndroid Build Coastguard Worker 
150*ec779b8eSAndroid Build Coastguard Worker // remove any keys NOT in the provided list
151*ec779b8eSAndroid Build Coastguard Worker // return value is # keys removed
filterNot(size_t n,const char * attrs[])152*ec779b8eSAndroid Build Coastguard Worker size_t mediametrics::Item::filterNot(size_t n, const char *attrs[]) {
153*ec779b8eSAndroid Build Coastguard Worker     std::set<std::string> check(attrs, attrs + n);
154*ec779b8eSAndroid Build Coastguard Worker     size_t zapped = 0;
155*ec779b8eSAndroid Build Coastguard Worker     for (auto it = mProps.begin(); it != mProps.end();) {
156*ec779b8eSAndroid Build Coastguard Worker         if (check.find(it->first) != check.end()) {
157*ec779b8eSAndroid Build Coastguard Worker             ++it;
158*ec779b8eSAndroid Build Coastguard Worker         } else {
159*ec779b8eSAndroid Build Coastguard Worker            it = mProps.erase(it);
160*ec779b8eSAndroid Build Coastguard Worker            ++zapped;
161*ec779b8eSAndroid Build Coastguard Worker         }
162*ec779b8eSAndroid Build Coastguard Worker     }
163*ec779b8eSAndroid Build Coastguard Worker     return zapped;
164*ec779b8eSAndroid Build Coastguard Worker }
165*ec779b8eSAndroid Build Coastguard Worker 
166*ec779b8eSAndroid Build Coastguard Worker // Parcel / serialize things for binder calls
167*ec779b8eSAndroid Build Coastguard Worker //
168*ec779b8eSAndroid Build Coastguard Worker 
readFromParcel(const Parcel & data)169*ec779b8eSAndroid Build Coastguard Worker status_t mediametrics::Item::readFromParcel(const Parcel& data) {
170*ec779b8eSAndroid Build Coastguard Worker     int32_t version;
171*ec779b8eSAndroid Build Coastguard Worker     status_t status = data.readInt32(&version);
172*ec779b8eSAndroid Build Coastguard Worker     if (status != NO_ERROR) return status;
173*ec779b8eSAndroid Build Coastguard Worker 
174*ec779b8eSAndroid Build Coastguard Worker     switch (version) {
175*ec779b8eSAndroid Build Coastguard Worker     case 0:
176*ec779b8eSAndroid Build Coastguard Worker       return readFromParcel0(data);
177*ec779b8eSAndroid Build Coastguard Worker     default:
178*ec779b8eSAndroid Build Coastguard Worker       ALOGE("%s: unsupported parcel version: %d", __func__, version);
179*ec779b8eSAndroid Build Coastguard Worker       return INVALID_OPERATION;
180*ec779b8eSAndroid Build Coastguard Worker     }
181*ec779b8eSAndroid Build Coastguard Worker }
182*ec779b8eSAndroid Build Coastguard Worker 
readFromParcel0(const Parcel & data)183*ec779b8eSAndroid Build Coastguard Worker status_t mediametrics::Item::readFromParcel0(const Parcel& data) {
184*ec779b8eSAndroid Build Coastguard Worker     const char *s = data.readCString();
185*ec779b8eSAndroid Build Coastguard Worker     mKey = s == nullptr ? "" : s;
186*ec779b8eSAndroid Build Coastguard Worker     int32_t pid, uid;
187*ec779b8eSAndroid Build Coastguard Worker     status_t status = data.readInt32(&pid) ?: data.readInt32(&uid);
188*ec779b8eSAndroid Build Coastguard Worker     if (status != NO_ERROR) return status;
189*ec779b8eSAndroid Build Coastguard Worker     mPid = (pid_t)pid;
190*ec779b8eSAndroid Build Coastguard Worker     mUid = (uid_t)uid;
191*ec779b8eSAndroid Build Coastguard Worker     s = data.readCString();
192*ec779b8eSAndroid Build Coastguard Worker     mPkgName = s == nullptr ? "" : s;
193*ec779b8eSAndroid Build Coastguard Worker     int32_t count;
194*ec779b8eSAndroid Build Coastguard Worker     int64_t version, timestamp;
195*ec779b8eSAndroid Build Coastguard Worker     status = data.readInt64(&version) ?: data.readInt64(&timestamp) ?: data.readInt32(&count);
196*ec779b8eSAndroid Build Coastguard Worker     if (status != NO_ERROR) return status;
197*ec779b8eSAndroid Build Coastguard Worker     if (count < 0) return BAD_VALUE;
198*ec779b8eSAndroid Build Coastguard Worker     mPkgVersionCode = version;
199*ec779b8eSAndroid Build Coastguard Worker     mTimestamp = timestamp;
200*ec779b8eSAndroid Build Coastguard Worker     for (int i = 0; i < count; i++) {
201*ec779b8eSAndroid Build Coastguard Worker         Prop prop;
202*ec779b8eSAndroid Build Coastguard Worker         status_t status = prop.readFromParcel(data);
203*ec779b8eSAndroid Build Coastguard Worker         if (status != NO_ERROR) return status;
204*ec779b8eSAndroid Build Coastguard Worker         mProps[prop.getName()] = std::move(prop);
205*ec779b8eSAndroid Build Coastguard Worker     }
206*ec779b8eSAndroid Build Coastguard Worker     return NO_ERROR;
207*ec779b8eSAndroid Build Coastguard Worker }
208*ec779b8eSAndroid Build Coastguard Worker 
writeToParcel(Parcel * data) const209*ec779b8eSAndroid Build Coastguard Worker status_t mediametrics::Item::writeToParcel(Parcel *data) const {
210*ec779b8eSAndroid Build Coastguard Worker     if (data == nullptr) return BAD_VALUE;
211*ec779b8eSAndroid Build Coastguard Worker 
212*ec779b8eSAndroid Build Coastguard Worker     const int32_t version = 0;
213*ec779b8eSAndroid Build Coastguard Worker     status_t status = data->writeInt32(version);
214*ec779b8eSAndroid Build Coastguard Worker     if (status != NO_ERROR) return status;
215*ec779b8eSAndroid Build Coastguard Worker 
216*ec779b8eSAndroid Build Coastguard Worker     switch (version) {
217*ec779b8eSAndroid Build Coastguard Worker     case 0:
218*ec779b8eSAndroid Build Coastguard Worker       return writeToParcel0(data);
219*ec779b8eSAndroid Build Coastguard Worker     default:
220*ec779b8eSAndroid Build Coastguard Worker       ALOGE("%s: unsupported parcel version: %d", __func__, version);
221*ec779b8eSAndroid Build Coastguard Worker       return INVALID_OPERATION;
222*ec779b8eSAndroid Build Coastguard Worker     }
223*ec779b8eSAndroid Build Coastguard Worker }
224*ec779b8eSAndroid Build Coastguard Worker 
writeToParcel0(Parcel * data) const225*ec779b8eSAndroid Build Coastguard Worker status_t mediametrics::Item::writeToParcel0(Parcel *data) const {
226*ec779b8eSAndroid Build Coastguard Worker     status_t status =
227*ec779b8eSAndroid Build Coastguard Worker         data->writeCString(mKey.c_str())
228*ec779b8eSAndroid Build Coastguard Worker         ?: data->writeInt32(mPid)
229*ec779b8eSAndroid Build Coastguard Worker         ?: data->writeInt32(mUid)
230*ec779b8eSAndroid Build Coastguard Worker         ?: data->writeCString(mPkgName.c_str())
231*ec779b8eSAndroid Build Coastguard Worker         ?: data->writeInt64(mPkgVersionCode)
232*ec779b8eSAndroid Build Coastguard Worker         ?: data->writeInt64(mTimestamp);
233*ec779b8eSAndroid Build Coastguard Worker     if (status != NO_ERROR) return status;
234*ec779b8eSAndroid Build Coastguard Worker 
235*ec779b8eSAndroid Build Coastguard Worker     data->writeInt32((int32_t)mProps.size());
236*ec779b8eSAndroid Build Coastguard Worker     for (auto &prop : *this) {
237*ec779b8eSAndroid Build Coastguard Worker         status = prop.writeToParcel(data);
238*ec779b8eSAndroid Build Coastguard Worker         if (status != NO_ERROR) return status;
239*ec779b8eSAndroid Build Coastguard Worker     }
240*ec779b8eSAndroid Build Coastguard Worker     return NO_ERROR;
241*ec779b8eSAndroid Build Coastguard Worker }
242*ec779b8eSAndroid Build Coastguard Worker 
toCString()243*ec779b8eSAndroid Build Coastguard Worker const char *mediametrics::Item::toCString() {
244*ec779b8eSAndroid Build Coastguard Worker     std::string val = toString();
245*ec779b8eSAndroid Build Coastguard Worker     return strdup(val.c_str());
246*ec779b8eSAndroid Build Coastguard Worker }
247*ec779b8eSAndroid Build Coastguard Worker 
248*ec779b8eSAndroid Build Coastguard Worker /*
249*ec779b8eSAndroid Build Coastguard Worker  * Similar to audio_utils/clock.h but customized for displaying mediametrics time.
250*ec779b8eSAndroid Build Coastguard Worker  */
251*ec779b8eSAndroid Build Coastguard Worker 
nsToString(int64_t ns,char * buffer,size_t bufferSize,PrintFormat format)252*ec779b8eSAndroid Build Coastguard Worker void nsToString(int64_t ns, char *buffer, size_t bufferSize, PrintFormat format)
253*ec779b8eSAndroid Build Coastguard Worker {
254*ec779b8eSAndroid Build Coastguard Worker     if (bufferSize == 0) return;
255*ec779b8eSAndroid Build Coastguard Worker 
256*ec779b8eSAndroid Build Coastguard Worker     const int one_second = 1000000000;
257*ec779b8eSAndroid Build Coastguard Worker     const time_t sec = ns / one_second;
258*ec779b8eSAndroid Build Coastguard Worker     struct tm tm;
259*ec779b8eSAndroid Build Coastguard Worker 
260*ec779b8eSAndroid Build Coastguard Worker     // Supported on bionic, glibc, and macOS, but not mingw.
261*ec779b8eSAndroid Build Coastguard Worker     if (localtime_r(&sec, &tm) == NULL) {
262*ec779b8eSAndroid Build Coastguard Worker         buffer[0] = '\0';
263*ec779b8eSAndroid Build Coastguard Worker         return;
264*ec779b8eSAndroid Build Coastguard Worker     }
265*ec779b8eSAndroid Build Coastguard Worker 
266*ec779b8eSAndroid Build Coastguard Worker     switch (format) {
267*ec779b8eSAndroid Build Coastguard Worker     default:
268*ec779b8eSAndroid Build Coastguard Worker     case kPrintFormatLong:
269*ec779b8eSAndroid Build Coastguard Worker         if (snprintf(buffer, bufferSize, "%02d-%02d %02d:%02d:%02d.%03d",
270*ec779b8eSAndroid Build Coastguard Worker             tm.tm_mon + 1, // localtime_r uses months in 0 - 11 range
271*ec779b8eSAndroid Build Coastguard Worker             tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
272*ec779b8eSAndroid Build Coastguard Worker             (int)(ns % one_second / 1000000)) < 0) {
273*ec779b8eSAndroid Build Coastguard Worker             buffer[0] = '\0'; // null terminate on format error, which should not happen
274*ec779b8eSAndroid Build Coastguard Worker         }
275*ec779b8eSAndroid Build Coastguard Worker         break;
276*ec779b8eSAndroid Build Coastguard Worker     case kPrintFormatShort:
277*ec779b8eSAndroid Build Coastguard Worker         if (snprintf(buffer, bufferSize, "%02d:%02d:%02d.%03d",
278*ec779b8eSAndroid Build Coastguard Worker             tm.tm_hour, tm.tm_min, tm.tm_sec,
279*ec779b8eSAndroid Build Coastguard Worker             (int)(ns % one_second / 1000000)) < 0) {
280*ec779b8eSAndroid Build Coastguard Worker             buffer[0] = '\0'; // null terminate on format error, which should not happen
281*ec779b8eSAndroid Build Coastguard Worker         }
282*ec779b8eSAndroid Build Coastguard Worker         break;
283*ec779b8eSAndroid Build Coastguard Worker     }
284*ec779b8eSAndroid Build Coastguard Worker }
285*ec779b8eSAndroid Build Coastguard Worker 
toString() const286*ec779b8eSAndroid Build Coastguard Worker std::string mediametrics::Item::toString() const {
287*ec779b8eSAndroid Build Coastguard Worker     std::string result;
288*ec779b8eSAndroid Build Coastguard Worker     char buffer[kMaxPropertyStringSize];
289*ec779b8eSAndroid Build Coastguard Worker 
290*ec779b8eSAndroid Build Coastguard Worker     snprintf(buffer, sizeof(buffer), "{%s, (%s), (%s, %d, %d)",
291*ec779b8eSAndroid Build Coastguard Worker             mKey.c_str(),
292*ec779b8eSAndroid Build Coastguard Worker             timeStringFromNs(mTimestamp, kPrintFormatLong).time,
293*ec779b8eSAndroid Build Coastguard Worker             mPkgName.c_str(), mPid, mUid
294*ec779b8eSAndroid Build Coastguard Worker            );
295*ec779b8eSAndroid Build Coastguard Worker     result.append(buffer);
296*ec779b8eSAndroid Build Coastguard Worker     bool first = true;
297*ec779b8eSAndroid Build Coastguard Worker     for (auto &prop : *this) {
298*ec779b8eSAndroid Build Coastguard Worker         prop.toStringBuffer(buffer, sizeof(buffer));
299*ec779b8eSAndroid Build Coastguard Worker         result += first ? ", (" : ", ";
300*ec779b8eSAndroid Build Coastguard Worker         result += buffer;
301*ec779b8eSAndroid Build Coastguard Worker         first = false;
302*ec779b8eSAndroid Build Coastguard Worker     }
303*ec779b8eSAndroid Build Coastguard Worker     result.append(")}");
304*ec779b8eSAndroid Build Coastguard Worker     return result;
305*ec779b8eSAndroid Build Coastguard Worker }
306*ec779b8eSAndroid Build Coastguard Worker 
307*ec779b8eSAndroid Build Coastguard Worker // for the lazy, we offer methods that finds the service and
308*ec779b8eSAndroid Build Coastguard Worker // calls the appropriate daemon
selfrecord()309*ec779b8eSAndroid Build Coastguard Worker bool mediametrics::Item::selfrecord() {
310*ec779b8eSAndroid Build Coastguard Worker     ALOGD_IF(DEBUG_API, "%s: delivering %s", __func__, this->toString().c_str());
311*ec779b8eSAndroid Build Coastguard Worker 
312*ec779b8eSAndroid Build Coastguard Worker     char *str;
313*ec779b8eSAndroid Build Coastguard Worker     size_t size;
314*ec779b8eSAndroid Build Coastguard Worker     status_t status = writeToByteString(&str, &size);
315*ec779b8eSAndroid Build Coastguard Worker     if (status == NO_ERROR) {
316*ec779b8eSAndroid Build Coastguard Worker         status = submitBuffer(str, size);
317*ec779b8eSAndroid Build Coastguard Worker         free(str);
318*ec779b8eSAndroid Build Coastguard Worker     }
319*ec779b8eSAndroid Build Coastguard Worker     if (status != NO_ERROR) {
320*ec779b8eSAndroid Build Coastguard Worker         ALOGW("%s: failed to record: %s", __func__, this->toString().c_str());
321*ec779b8eSAndroid Build Coastguard Worker         return false;
322*ec779b8eSAndroid Build Coastguard Worker     }
323*ec779b8eSAndroid Build Coastguard Worker     return true;
324*ec779b8eSAndroid Build Coastguard Worker }
325*ec779b8eSAndroid Build Coastguard Worker 
326*ec779b8eSAndroid Build Coastguard Worker //static
isEnabled()327*ec779b8eSAndroid Build Coastguard Worker bool BaseItem::isEnabled() {
328*ec779b8eSAndroid Build Coastguard Worker     // completely skip logging from certain UIDs. We do this here
329*ec779b8eSAndroid Build Coastguard Worker     // to avoid the multi-second timeouts while we learn that
330*ec779b8eSAndroid Build Coastguard Worker     // sepolicy will not let us find the service.
331*ec779b8eSAndroid Build Coastguard Worker     // We do this only for a select set of UIDs
332*ec779b8eSAndroid Build Coastguard Worker     // The sepolicy protection is still in place, we just want a faster
333*ec779b8eSAndroid Build Coastguard Worker     // response from this specific, small set of uids.
334*ec779b8eSAndroid Build Coastguard Worker 
335*ec779b8eSAndroid Build Coastguard Worker     // This is checked only once in the lifetime of the process.
336*ec779b8eSAndroid Build Coastguard Worker     const uid_t uid = getuid();
337*ec779b8eSAndroid Build Coastguard Worker     const uid_t appid = multiuser_get_app_id(uid);
338*ec779b8eSAndroid Build Coastguard Worker 
339*ec779b8eSAndroid Build Coastguard Worker     if (appid == AID_RADIO) {
340*ec779b8eSAndroid Build Coastguard Worker         // telephony subsystem, RIL
341*ec779b8eSAndroid Build Coastguard Worker         return false;
342*ec779b8eSAndroid Build Coastguard Worker     }
343*ec779b8eSAndroid Build Coastguard Worker 
344*ec779b8eSAndroid Build Coastguard Worker     if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
345*ec779b8eSAndroid Build Coastguard Worker         // Some isolated processes can access the audio system; see
346*ec779b8eSAndroid Build Coastguard Worker         // AudioSystem::setAudioFlingerBinder (currently only the HotwordDetectionService). Instead
347*ec779b8eSAndroid Build Coastguard Worker         // of also allowing access to the MediaMetrics service, it's simpler to just disable it for
348*ec779b8eSAndroid Build Coastguard Worker         // now.
349*ec779b8eSAndroid Build Coastguard Worker         // TODO(b/190151205): Either allow the HotwordDetectionService to access MediaMetrics or
350*ec779b8eSAndroid Build Coastguard Worker         // make this disabling specific to that process.
351*ec779b8eSAndroid Build Coastguard Worker         return false;
352*ec779b8eSAndroid Build Coastguard Worker     }
353*ec779b8eSAndroid Build Coastguard Worker 
354*ec779b8eSAndroid Build Coastguard Worker     int enabled = property_get_int32(Item::EnabledProperty, -1);
355*ec779b8eSAndroid Build Coastguard Worker     if (enabled == -1) {
356*ec779b8eSAndroid Build Coastguard Worker         enabled = property_get_int32(Item::EnabledPropertyPersist, -1);
357*ec779b8eSAndroid Build Coastguard Worker     }
358*ec779b8eSAndroid Build Coastguard Worker     if (enabled == -1) {
359*ec779b8eSAndroid Build Coastguard Worker         enabled = Item::EnabledProperty_default;
360*ec779b8eSAndroid Build Coastguard Worker     }
361*ec779b8eSAndroid Build Coastguard Worker     return enabled > 0;
362*ec779b8eSAndroid Build Coastguard Worker }
363*ec779b8eSAndroid Build Coastguard Worker 
364*ec779b8eSAndroid Build Coastguard Worker // monitor health of our connection to the metrics service
365*ec779b8eSAndroid Build Coastguard Worker class MediaMetricsDeathNotifier : public IBinder::DeathRecipient {
binderDied(const wp<IBinder> &)366*ec779b8eSAndroid Build Coastguard Worker         virtual void binderDied(const wp<IBinder> &) {
367*ec779b8eSAndroid Build Coastguard Worker             ALOGW("Reacquire service connection on next request");
368*ec779b8eSAndroid Build Coastguard Worker             BaseItem::dropInstance();
369*ec779b8eSAndroid Build Coastguard Worker         }
370*ec779b8eSAndroid Build Coastguard Worker };
371*ec779b8eSAndroid Build Coastguard Worker 
372*ec779b8eSAndroid Build Coastguard Worker static sp<MediaMetricsDeathNotifier> sNotifier;
373*ec779b8eSAndroid Build Coastguard Worker // static
374*ec779b8eSAndroid Build Coastguard Worker sp<media::IMediaMetricsService> BaseItem::sMediaMetricsService;
375*ec779b8eSAndroid Build Coastguard Worker static std::mutex sServiceMutex;
376*ec779b8eSAndroid Build Coastguard Worker static int sRemainingBindAttempts = SVC_TRIES;
377*ec779b8eSAndroid Build Coastguard Worker 
378*ec779b8eSAndroid Build Coastguard Worker // static
dropInstance()379*ec779b8eSAndroid Build Coastguard Worker void BaseItem::dropInstance() {
380*ec779b8eSAndroid Build Coastguard Worker     std::lock_guard  _l(sServiceMutex);
381*ec779b8eSAndroid Build Coastguard Worker     sRemainingBindAttempts = SVC_TRIES;
382*ec779b8eSAndroid Build Coastguard Worker     sMediaMetricsService = nullptr;
383*ec779b8eSAndroid Build Coastguard Worker }
384*ec779b8eSAndroid Build Coastguard Worker 
385*ec779b8eSAndroid Build Coastguard Worker // static
submitBuffer(const char * buffer,size_t size)386*ec779b8eSAndroid Build Coastguard Worker status_t BaseItem::submitBuffer(const char *buffer, size_t size) {
387*ec779b8eSAndroid Build Coastguard Worker     ALOGD_IF(DEBUG_API, "%s: delivering %zu bytes", __func__, size);
388*ec779b8eSAndroid Build Coastguard Worker 
389*ec779b8eSAndroid Build Coastguard Worker     // Validate size
390*ec779b8eSAndroid Build Coastguard Worker     if (size > std::numeric_limits<int32_t>::max()) return BAD_VALUE;
391*ec779b8eSAndroid Build Coastguard Worker 
392*ec779b8eSAndroid Build Coastguard Worker     // Do we have the service available?
393*ec779b8eSAndroid Build Coastguard Worker     sp<media::IMediaMetricsService> svc = getService();
394*ec779b8eSAndroid Build Coastguard Worker     if (svc == nullptr)  return NO_INIT;
395*ec779b8eSAndroid Build Coastguard Worker 
396*ec779b8eSAndroid Build Coastguard Worker     ::android::status_t status = NO_ERROR;
397*ec779b8eSAndroid Build Coastguard Worker     if constexpr (/* DISABLES CODE */ (false)) {
398*ec779b8eSAndroid Build Coastguard Worker         // THIS PATH IS FOR REFERENCE ONLY.
399*ec779b8eSAndroid Build Coastguard Worker         // It is compiled so that any changes to IMediaMetricsService::submitBuffer()
400*ec779b8eSAndroid Build Coastguard Worker         // will lead here.  If this code is changed, the else branch must
401*ec779b8eSAndroid Build Coastguard Worker         // be changed as well.
402*ec779b8eSAndroid Build Coastguard Worker         //
403*ec779b8eSAndroid Build Coastguard Worker         // Use the AIDL calling interface - this is a bit slower as a byte vector must be
404*ec779b8eSAndroid Build Coastguard Worker         // constructed. As the call is one-way, the only a transaction error occurs.
405*ec779b8eSAndroid Build Coastguard Worker         status = svc->submitBuffer({buffer, buffer + size}).transactionError();
406*ec779b8eSAndroid Build Coastguard Worker     } else {
407*ec779b8eSAndroid Build Coastguard Worker         // Use the Binder calling interface - this direct implementation avoids
408*ec779b8eSAndroid Build Coastguard Worker         // malloc/copy/free for the vector and reduces the overhead for logging.
409*ec779b8eSAndroid Build Coastguard Worker         // We based this off of the AIDL generated file:
410*ec779b8eSAndroid Build Coastguard Worker         // out/soong/.intermediates/frameworks/av/media/libmediametrics/mediametricsservice-aidl-unstable-cpp-source/gen/android/media/IMediaMetricsService.cpp
411*ec779b8eSAndroid Build Coastguard Worker         // TODO: Create an AIDL C++ back end optimized form of vector writing.
412*ec779b8eSAndroid Build Coastguard Worker         ::android::Parcel _aidl_data;
413*ec779b8eSAndroid Build Coastguard Worker         ::android::Parcel _aidl_reply; // we don't care about this as it is one-way.
414*ec779b8eSAndroid Build Coastguard Worker 
415*ec779b8eSAndroid Build Coastguard Worker         status = _aidl_data.writeInterfaceToken(svc->getInterfaceDescriptor());
416*ec779b8eSAndroid Build Coastguard Worker         if (status != ::android::OK) goto _aidl_error;
417*ec779b8eSAndroid Build Coastguard Worker 
418*ec779b8eSAndroid Build Coastguard Worker         status = _aidl_data.writeInt32(static_cast<int32_t>(size));
419*ec779b8eSAndroid Build Coastguard Worker         if (status != ::android::OK) goto _aidl_error;
420*ec779b8eSAndroid Build Coastguard Worker 
421*ec779b8eSAndroid Build Coastguard Worker         status = _aidl_data.write(buffer, static_cast<int32_t>(size));
422*ec779b8eSAndroid Build Coastguard Worker         if (status != ::android::OK) goto _aidl_error;
423*ec779b8eSAndroid Build Coastguard Worker 
424*ec779b8eSAndroid Build Coastguard Worker         status = ::android::IInterface::asBinder(svc)->transact(
425*ec779b8eSAndroid Build Coastguard Worker                 ::android::media::BnMediaMetricsService::TRANSACTION_submitBuffer,
426*ec779b8eSAndroid Build Coastguard Worker                 _aidl_data, &_aidl_reply, ::android::IBinder::FLAG_ONEWAY);
427*ec779b8eSAndroid Build Coastguard Worker 
428*ec779b8eSAndroid Build Coastguard Worker         // AIDL permits setting a default implementation for additional functionality.
429*ec779b8eSAndroid Build Coastguard Worker         // See go/aog/713984. This is not used here.
430*ec779b8eSAndroid Build Coastguard Worker         // if (status == ::android::UNKNOWN_TRANSACTION
431*ec779b8eSAndroid Build Coastguard Worker         //         && ::android::media::IMediaMetricsService::getDefaultImpl()) {
432*ec779b8eSAndroid Build Coastguard Worker         //     status = ::android::media::IMediaMetricsService::getDefaultImpl()
433*ec779b8eSAndroid Build Coastguard Worker         //             ->submitBuffer(immutableByteVectorFromBuffer(buffer, size))
434*ec779b8eSAndroid Build Coastguard Worker         //             .transactionError();
435*ec779b8eSAndroid Build Coastguard Worker         // }
436*ec779b8eSAndroid Build Coastguard Worker     }
437*ec779b8eSAndroid Build Coastguard Worker 
438*ec779b8eSAndroid Build Coastguard Worker     if (status == NO_ERROR) return NO_ERROR;
439*ec779b8eSAndroid Build Coastguard Worker 
440*ec779b8eSAndroid Build Coastguard Worker     _aidl_error:
441*ec779b8eSAndroid Build Coastguard Worker     ALOGW("%s: failed(%d) to record: %zu bytes", __func__, status, size);
442*ec779b8eSAndroid Build Coastguard Worker     return status;
443*ec779b8eSAndroid Build Coastguard Worker }
444*ec779b8eSAndroid Build Coastguard Worker 
445*ec779b8eSAndroid Build Coastguard Worker //static
getService()446*ec779b8eSAndroid Build Coastguard Worker sp<media::IMediaMetricsService> BaseItem::getService() {
447*ec779b8eSAndroid Build Coastguard Worker     static const char *servicename = "media.metrics";
448*ec779b8eSAndroid Build Coastguard Worker     static const bool enabled = isEnabled(); // singleton initialized
449*ec779b8eSAndroid Build Coastguard Worker 
450*ec779b8eSAndroid Build Coastguard Worker     if (enabled == false) {
451*ec779b8eSAndroid Build Coastguard Worker         ALOGD_IF(DEBUG_SERVICEACCESS, "disabled");
452*ec779b8eSAndroid Build Coastguard Worker         return nullptr;
453*ec779b8eSAndroid Build Coastguard Worker     }
454*ec779b8eSAndroid Build Coastguard Worker     std::lock_guard _l(sServiceMutex);
455*ec779b8eSAndroid Build Coastguard Worker     // think of remainingBindAttempts as telling us whether service == nullptr because
456*ec779b8eSAndroid Build Coastguard Worker     // (1) we haven't tried to initialize it yet
457*ec779b8eSAndroid Build Coastguard Worker     // (2) we've tried to initialize it, but failed.
458*ec779b8eSAndroid Build Coastguard Worker     if (sMediaMetricsService == nullptr && sRemainingBindAttempts > 0) {
459*ec779b8eSAndroid Build Coastguard Worker         const char *badness = "";
460*ec779b8eSAndroid Build Coastguard Worker         sp<IServiceManager> sm = defaultServiceManager();
461*ec779b8eSAndroid Build Coastguard Worker         if (sm != nullptr) {
462*ec779b8eSAndroid Build Coastguard Worker             sp<IBinder> binder = sm->getService(String16(servicename));
463*ec779b8eSAndroid Build Coastguard Worker             if (binder != nullptr) {
464*ec779b8eSAndroid Build Coastguard Worker                 sMediaMetricsService = interface_cast<media::IMediaMetricsService>(binder);
465*ec779b8eSAndroid Build Coastguard Worker                 sNotifier = new MediaMetricsDeathNotifier();
466*ec779b8eSAndroid Build Coastguard Worker                 binder->linkToDeath(sNotifier);
467*ec779b8eSAndroid Build Coastguard Worker             } else {
468*ec779b8eSAndroid Build Coastguard Worker                 badness = "did not find service";
469*ec779b8eSAndroid Build Coastguard Worker             }
470*ec779b8eSAndroid Build Coastguard Worker         } else {
471*ec779b8eSAndroid Build Coastguard Worker             badness = "No Service Manager access";
472*ec779b8eSAndroid Build Coastguard Worker         }
473*ec779b8eSAndroid Build Coastguard Worker         if (sMediaMetricsService == nullptr) {
474*ec779b8eSAndroid Build Coastguard Worker             if (sRemainingBindAttempts > 0) {
475*ec779b8eSAndroid Build Coastguard Worker                 sRemainingBindAttempts--;
476*ec779b8eSAndroid Build Coastguard Worker             }
477*ec779b8eSAndroid Build Coastguard Worker             ALOGD_IF(DEBUG_SERVICEACCESS, "%s: unable to bind to service %s: %s",
478*ec779b8eSAndroid Build Coastguard Worker                     __func__, servicename, badness);
479*ec779b8eSAndroid Build Coastguard Worker         }
480*ec779b8eSAndroid Build Coastguard Worker     }
481*ec779b8eSAndroid Build Coastguard Worker     return sMediaMetricsService;
482*ec779b8eSAndroid Build Coastguard Worker }
483*ec779b8eSAndroid Build Coastguard Worker 
484*ec779b8eSAndroid Build Coastguard Worker 
writeToByteString(char ** pbuffer,size_t * plength) const485*ec779b8eSAndroid Build Coastguard Worker status_t mediametrics::Item::writeToByteString(char **pbuffer, size_t *plength) const
486*ec779b8eSAndroid Build Coastguard Worker {
487*ec779b8eSAndroid Build Coastguard Worker     if (pbuffer == nullptr || plength == nullptr)
488*ec779b8eSAndroid Build Coastguard Worker         return BAD_VALUE;
489*ec779b8eSAndroid Build Coastguard Worker 
490*ec779b8eSAndroid Build Coastguard Worker     // get size
491*ec779b8eSAndroid Build Coastguard Worker     const size_t keySizeZeroTerminated = strlen(mKey.c_str()) + 1;
492*ec779b8eSAndroid Build Coastguard Worker     if (keySizeZeroTerminated > UINT16_MAX) {
493*ec779b8eSAndroid Build Coastguard Worker         ALOGW("%s: key size %zu too large", __func__, keySizeZeroTerminated);
494*ec779b8eSAndroid Build Coastguard Worker         return INVALID_OPERATION;
495*ec779b8eSAndroid Build Coastguard Worker     }
496*ec779b8eSAndroid Build Coastguard Worker     const uint16_t version = 0;
497*ec779b8eSAndroid Build Coastguard Worker     const uint32_t header_size =
498*ec779b8eSAndroid Build Coastguard Worker         sizeof(uint32_t)      // total size
499*ec779b8eSAndroid Build Coastguard Worker         + sizeof(header_size) // header size
500*ec779b8eSAndroid Build Coastguard Worker         + sizeof(version)     // encoding version
501*ec779b8eSAndroid Build Coastguard Worker         + sizeof(uint16_t)    // key size
502*ec779b8eSAndroid Build Coastguard Worker         + keySizeZeroTerminated // key, zero terminated
503*ec779b8eSAndroid Build Coastguard Worker         + sizeof(int32_t)     // pid
504*ec779b8eSAndroid Build Coastguard Worker         + sizeof(int32_t)     // uid
505*ec779b8eSAndroid Build Coastguard Worker         + sizeof(int64_t)     // timestamp
506*ec779b8eSAndroid Build Coastguard Worker         ;
507*ec779b8eSAndroid Build Coastguard Worker 
508*ec779b8eSAndroid Build Coastguard Worker     uint32_t size = header_size
509*ec779b8eSAndroid Build Coastguard Worker         + sizeof(uint32_t) // # properties
510*ec779b8eSAndroid Build Coastguard Worker         ;
511*ec779b8eSAndroid Build Coastguard Worker     for (auto &prop : *this) {
512*ec779b8eSAndroid Build Coastguard Worker         const size_t propSize = prop.getByteStringSize();
513*ec779b8eSAndroid Build Coastguard Worker         if (propSize > UINT16_MAX) {
514*ec779b8eSAndroid Build Coastguard Worker             ALOGW("%s: prop %s size %zu too large", __func__, prop.getName(), propSize);
515*ec779b8eSAndroid Build Coastguard Worker             return INVALID_OPERATION;
516*ec779b8eSAndroid Build Coastguard Worker         }
517*ec779b8eSAndroid Build Coastguard Worker         if (__builtin_add_overflow(size, propSize, &size)) {
518*ec779b8eSAndroid Build Coastguard Worker             ALOGW("%s: item size overflow at property %s", __func__, prop.getName());
519*ec779b8eSAndroid Build Coastguard Worker             return INVALID_OPERATION;
520*ec779b8eSAndroid Build Coastguard Worker         }
521*ec779b8eSAndroid Build Coastguard Worker     }
522*ec779b8eSAndroid Build Coastguard Worker 
523*ec779b8eSAndroid Build Coastguard Worker     // since we fill every byte in the buffer (there is no padding),
524*ec779b8eSAndroid Build Coastguard Worker     // malloc is used here instead of calloc.
525*ec779b8eSAndroid Build Coastguard Worker     char * const build = (char *)malloc(size);
526*ec779b8eSAndroid Build Coastguard Worker     if (build == nullptr) return NO_MEMORY;
527*ec779b8eSAndroid Build Coastguard Worker 
528*ec779b8eSAndroid Build Coastguard Worker     char *filling = build;
529*ec779b8eSAndroid Build Coastguard Worker     char *buildmax = build + size;
530*ec779b8eSAndroid Build Coastguard Worker     if (insert((uint32_t)size, &filling, buildmax) != NO_ERROR
531*ec779b8eSAndroid Build Coastguard Worker             || insert(header_size, &filling, buildmax) != NO_ERROR
532*ec779b8eSAndroid Build Coastguard Worker             || insert(version, &filling, buildmax) != NO_ERROR
533*ec779b8eSAndroid Build Coastguard Worker             || insert((uint16_t)keySizeZeroTerminated, &filling, buildmax) != NO_ERROR
534*ec779b8eSAndroid Build Coastguard Worker             || insert(mKey.c_str(), &filling, buildmax) != NO_ERROR
535*ec779b8eSAndroid Build Coastguard Worker             || insert((int32_t)mPid, &filling, buildmax) != NO_ERROR
536*ec779b8eSAndroid Build Coastguard Worker             || insert((int32_t)mUid, &filling, buildmax) != NO_ERROR
537*ec779b8eSAndroid Build Coastguard Worker             || insert((int64_t)mTimestamp, &filling, buildmax) != NO_ERROR
538*ec779b8eSAndroid Build Coastguard Worker             || insert((uint32_t)mProps.size(), &filling, buildmax) != NO_ERROR) {
539*ec779b8eSAndroid Build Coastguard Worker         ALOGE("%s:could not write header", __func__);  // shouldn't happen
540*ec779b8eSAndroid Build Coastguard Worker         free(build);
541*ec779b8eSAndroid Build Coastguard Worker         return INVALID_OPERATION;
542*ec779b8eSAndroid Build Coastguard Worker     }
543*ec779b8eSAndroid Build Coastguard Worker     for (auto &prop : *this) {
544*ec779b8eSAndroid Build Coastguard Worker         if (prop.writeToByteString(&filling, buildmax) != NO_ERROR) {
545*ec779b8eSAndroid Build Coastguard Worker             free(build);
546*ec779b8eSAndroid Build Coastguard Worker             // shouldn't happen
547*ec779b8eSAndroid Build Coastguard Worker             ALOGE("%s:could not write prop %s", __func__, prop.getName());
548*ec779b8eSAndroid Build Coastguard Worker             return INVALID_OPERATION;
549*ec779b8eSAndroid Build Coastguard Worker         }
550*ec779b8eSAndroid Build Coastguard Worker     }
551*ec779b8eSAndroid Build Coastguard Worker 
552*ec779b8eSAndroid Build Coastguard Worker     if (filling != buildmax) {
553*ec779b8eSAndroid Build Coastguard Worker         ALOGE("%s: problems populating; wrote=%d planned=%d",
554*ec779b8eSAndroid Build Coastguard Worker                 __func__, (int)(filling - build), (int)size);
555*ec779b8eSAndroid Build Coastguard Worker         free(build);
556*ec779b8eSAndroid Build Coastguard Worker         return INVALID_OPERATION;
557*ec779b8eSAndroid Build Coastguard Worker     }
558*ec779b8eSAndroid Build Coastguard Worker     *pbuffer = build;
559*ec779b8eSAndroid Build Coastguard Worker     *plength = size;
560*ec779b8eSAndroid Build Coastguard Worker     return NO_ERROR;
561*ec779b8eSAndroid Build Coastguard Worker }
562*ec779b8eSAndroid Build Coastguard Worker 
readFromByteString(const char * bufferptr,size_t length)563*ec779b8eSAndroid Build Coastguard Worker status_t mediametrics::Item::readFromByteString(const char *bufferptr, size_t length)
564*ec779b8eSAndroid Build Coastguard Worker {
565*ec779b8eSAndroid Build Coastguard Worker     if (bufferptr == nullptr) return BAD_VALUE;
566*ec779b8eSAndroid Build Coastguard Worker 
567*ec779b8eSAndroid Build Coastguard Worker     const char *read = bufferptr;
568*ec779b8eSAndroid Build Coastguard Worker     const char *readend = bufferptr + length;
569*ec779b8eSAndroid Build Coastguard Worker 
570*ec779b8eSAndroid Build Coastguard Worker     uint32_t size;
571*ec779b8eSAndroid Build Coastguard Worker     uint32_t header_size;
572*ec779b8eSAndroid Build Coastguard Worker     uint16_t version;
573*ec779b8eSAndroid Build Coastguard Worker     uint16_t key_size;
574*ec779b8eSAndroid Build Coastguard Worker     std::string key;
575*ec779b8eSAndroid Build Coastguard Worker     int32_t pid;
576*ec779b8eSAndroid Build Coastguard Worker     int32_t uid;
577*ec779b8eSAndroid Build Coastguard Worker     int64_t timestamp;
578*ec779b8eSAndroid Build Coastguard Worker     uint32_t propCount;
579*ec779b8eSAndroid Build Coastguard Worker     if (extract(&size, &read, readend) != NO_ERROR
580*ec779b8eSAndroid Build Coastguard Worker             || extract(&header_size, &read, readend) != NO_ERROR
581*ec779b8eSAndroid Build Coastguard Worker             || extract(&version, &read, readend) != NO_ERROR
582*ec779b8eSAndroid Build Coastguard Worker             || extract(&key_size, &read, readend) != NO_ERROR
583*ec779b8eSAndroid Build Coastguard Worker             || extract(&key, &read, readend) != NO_ERROR
584*ec779b8eSAndroid Build Coastguard Worker             || extract(&pid, &read, readend) != NO_ERROR
585*ec779b8eSAndroid Build Coastguard Worker             || extract(&uid, &read, readend) != NO_ERROR
586*ec779b8eSAndroid Build Coastguard Worker             || extract(&timestamp, &read, readend) != NO_ERROR
587*ec779b8eSAndroid Build Coastguard Worker             || size > length
588*ec779b8eSAndroid Build Coastguard Worker             || key.size() + 1 != key_size
589*ec779b8eSAndroid Build Coastguard Worker             || header_size > size) {
590*ec779b8eSAndroid Build Coastguard Worker         ALOGW("%s: invalid header", __func__);
591*ec779b8eSAndroid Build Coastguard Worker         return INVALID_OPERATION;
592*ec779b8eSAndroid Build Coastguard Worker     }
593*ec779b8eSAndroid Build Coastguard Worker     mKey = std::move(key);
594*ec779b8eSAndroid Build Coastguard Worker     const size_t pos = read - bufferptr;
595*ec779b8eSAndroid Build Coastguard Worker     if (pos > header_size) {
596*ec779b8eSAndroid Build Coastguard Worker         ALOGW("%s: invalid header pos:%zu > header_size:%u",
597*ec779b8eSAndroid Build Coastguard Worker                 __func__, pos, header_size);
598*ec779b8eSAndroid Build Coastguard Worker         return INVALID_OPERATION;
599*ec779b8eSAndroid Build Coastguard Worker     } else if (pos < header_size) {
600*ec779b8eSAndroid Build Coastguard Worker         ALOGW("%s: mismatched header pos:%zu < header_size:%u, advancing",
601*ec779b8eSAndroid Build Coastguard Worker                 __func__, pos, header_size);
602*ec779b8eSAndroid Build Coastguard Worker         read += (header_size - pos);
603*ec779b8eSAndroid Build Coastguard Worker     }
604*ec779b8eSAndroid Build Coastguard Worker     if (extract(&propCount, &read, readend) != NO_ERROR) {
605*ec779b8eSAndroid Build Coastguard Worker         ALOGD("%s: cannot read prop count", __func__);
606*ec779b8eSAndroid Build Coastguard Worker         return INVALID_OPERATION;
607*ec779b8eSAndroid Build Coastguard Worker     }
608*ec779b8eSAndroid Build Coastguard Worker     mPid = pid;
609*ec779b8eSAndroid Build Coastguard Worker     mUid = uid;
610*ec779b8eSAndroid Build Coastguard Worker     mTimestamp = timestamp;
611*ec779b8eSAndroid Build Coastguard Worker     for (size_t i = 0; i < propCount; ++i) {
612*ec779b8eSAndroid Build Coastguard Worker         Prop prop;
613*ec779b8eSAndroid Build Coastguard Worker         if (prop.readFromByteString(&read, readend) != NO_ERROR) {
614*ec779b8eSAndroid Build Coastguard Worker             ALOGW("%s: cannot read prop %zu", __func__, i);
615*ec779b8eSAndroid Build Coastguard Worker             return INVALID_OPERATION;
616*ec779b8eSAndroid Build Coastguard Worker         }
617*ec779b8eSAndroid Build Coastguard Worker         mProps[prop.getName()] = std::move(prop);
618*ec779b8eSAndroid Build Coastguard Worker     }
619*ec779b8eSAndroid Build Coastguard Worker     return NO_ERROR;
620*ec779b8eSAndroid Build Coastguard Worker }
621*ec779b8eSAndroid Build Coastguard Worker 
readFromParcel(const Parcel & data)622*ec779b8eSAndroid Build Coastguard Worker status_t mediametrics::Item::Prop::readFromParcel(const Parcel& data)
623*ec779b8eSAndroid Build Coastguard Worker {
624*ec779b8eSAndroid Build Coastguard Worker     const char *key = data.readCString();
625*ec779b8eSAndroid Build Coastguard Worker     if (key == nullptr) return BAD_VALUE;
626*ec779b8eSAndroid Build Coastguard Worker     int32_t type;
627*ec779b8eSAndroid Build Coastguard Worker     status_t status = data.readInt32(&type);
628*ec779b8eSAndroid Build Coastguard Worker     if (status != NO_ERROR) return status;
629*ec779b8eSAndroid Build Coastguard Worker     switch (type) {
630*ec779b8eSAndroid Build Coastguard Worker     case mediametrics::kTypeInt32: {
631*ec779b8eSAndroid Build Coastguard Worker         int32_t value;
632*ec779b8eSAndroid Build Coastguard Worker         status = data.readInt32(&value);
633*ec779b8eSAndroid Build Coastguard Worker         if (status != NO_ERROR) return status;
634*ec779b8eSAndroid Build Coastguard Worker         mElem = value;
635*ec779b8eSAndroid Build Coastguard Worker     } break;
636*ec779b8eSAndroid Build Coastguard Worker     case mediametrics::kTypeInt64: {
637*ec779b8eSAndroid Build Coastguard Worker         int64_t value;
638*ec779b8eSAndroid Build Coastguard Worker         status = data.readInt64(&value);
639*ec779b8eSAndroid Build Coastguard Worker         if (status != NO_ERROR) return status;
640*ec779b8eSAndroid Build Coastguard Worker         mElem = value;
641*ec779b8eSAndroid Build Coastguard Worker     } break;
642*ec779b8eSAndroid Build Coastguard Worker     case mediametrics::kTypeDouble: {
643*ec779b8eSAndroid Build Coastguard Worker         double value;
644*ec779b8eSAndroid Build Coastguard Worker         status = data.readDouble(&value);
645*ec779b8eSAndroid Build Coastguard Worker         if (status != NO_ERROR) return status;
646*ec779b8eSAndroid Build Coastguard Worker         mElem = value;
647*ec779b8eSAndroid Build Coastguard Worker     } break;
648*ec779b8eSAndroid Build Coastguard Worker     case mediametrics::kTypeCString: {
649*ec779b8eSAndroid Build Coastguard Worker         const char *s = data.readCString();
650*ec779b8eSAndroid Build Coastguard Worker         if (s == nullptr) return BAD_VALUE;
651*ec779b8eSAndroid Build Coastguard Worker         mElem = s;
652*ec779b8eSAndroid Build Coastguard Worker     } break;
653*ec779b8eSAndroid Build Coastguard Worker     case mediametrics::kTypeRate: {
654*ec779b8eSAndroid Build Coastguard Worker         std::pair<int64_t, int64_t> rate;
655*ec779b8eSAndroid Build Coastguard Worker         status = data.readInt64(&rate.first)
656*ec779b8eSAndroid Build Coastguard Worker                 ?: data.readInt64(&rate.second);
657*ec779b8eSAndroid Build Coastguard Worker         if (status != NO_ERROR) return status;
658*ec779b8eSAndroid Build Coastguard Worker         mElem = rate;
659*ec779b8eSAndroid Build Coastguard Worker     } break;
660*ec779b8eSAndroid Build Coastguard Worker     case mediametrics::kTypeNone: {
661*ec779b8eSAndroid Build Coastguard Worker         mElem = std::monostate{};
662*ec779b8eSAndroid Build Coastguard Worker     } break;
663*ec779b8eSAndroid Build Coastguard Worker     default:
664*ec779b8eSAndroid Build Coastguard Worker         ALOGE("%s: reading bad item type: %d", __func__, type);
665*ec779b8eSAndroid Build Coastguard Worker         return BAD_VALUE;
666*ec779b8eSAndroid Build Coastguard Worker     }
667*ec779b8eSAndroid Build Coastguard Worker     setName(key);
668*ec779b8eSAndroid Build Coastguard Worker     return NO_ERROR;
669*ec779b8eSAndroid Build Coastguard Worker }
670*ec779b8eSAndroid Build Coastguard Worker 
readFromByteString(const char ** bufferpptr,const char * bufferptrmax)671*ec779b8eSAndroid Build Coastguard Worker status_t mediametrics::Item::Prop::readFromByteString(
672*ec779b8eSAndroid Build Coastguard Worker         const char **bufferpptr, const char *bufferptrmax)
673*ec779b8eSAndroid Build Coastguard Worker {
674*ec779b8eSAndroid Build Coastguard Worker     uint16_t len;
675*ec779b8eSAndroid Build Coastguard Worker     std::string name;
676*ec779b8eSAndroid Build Coastguard Worker     uint8_t type;
677*ec779b8eSAndroid Build Coastguard Worker     status_t status = extract(&len, bufferpptr, bufferptrmax)
678*ec779b8eSAndroid Build Coastguard Worker             ?: extract(&type, bufferpptr, bufferptrmax)
679*ec779b8eSAndroid Build Coastguard Worker             ?: extract(&name, bufferpptr, bufferptrmax);
680*ec779b8eSAndroid Build Coastguard Worker     if (status != NO_ERROR) return status;
681*ec779b8eSAndroid Build Coastguard Worker     switch (type) {
682*ec779b8eSAndroid Build Coastguard Worker     case mediametrics::kTypeInt32: {
683*ec779b8eSAndroid Build Coastguard Worker         int32_t value;
684*ec779b8eSAndroid Build Coastguard Worker         status = extract(&value, bufferpptr, bufferptrmax);
685*ec779b8eSAndroid Build Coastguard Worker         if (status != NO_ERROR) return status;
686*ec779b8eSAndroid Build Coastguard Worker         mElem = value;
687*ec779b8eSAndroid Build Coastguard Worker     } break;
688*ec779b8eSAndroid Build Coastguard Worker     case mediametrics::kTypeInt64: {
689*ec779b8eSAndroid Build Coastguard Worker         int64_t value;
690*ec779b8eSAndroid Build Coastguard Worker         status = extract(&value, bufferpptr, bufferptrmax);
691*ec779b8eSAndroid Build Coastguard Worker         if (status != NO_ERROR) return status;
692*ec779b8eSAndroid Build Coastguard Worker         mElem = value;
693*ec779b8eSAndroid Build Coastguard Worker     } break;
694*ec779b8eSAndroid Build Coastguard Worker     case mediametrics::kTypeDouble: {
695*ec779b8eSAndroid Build Coastguard Worker         double value;
696*ec779b8eSAndroid Build Coastguard Worker         status = extract(&value, bufferpptr, bufferptrmax);
697*ec779b8eSAndroid Build Coastguard Worker         if (status != NO_ERROR) return status;
698*ec779b8eSAndroid Build Coastguard Worker         mElem = value;
699*ec779b8eSAndroid Build Coastguard Worker     } break;
700*ec779b8eSAndroid Build Coastguard Worker     case mediametrics::kTypeRate: {
701*ec779b8eSAndroid Build Coastguard Worker         std::pair<int64_t, int64_t> value;
702*ec779b8eSAndroid Build Coastguard Worker         status = extract(&value.first, bufferpptr, bufferptrmax)
703*ec779b8eSAndroid Build Coastguard Worker                 ?: extract(&value.second, bufferpptr, bufferptrmax);
704*ec779b8eSAndroid Build Coastguard Worker         if (status != NO_ERROR) return status;
705*ec779b8eSAndroid Build Coastguard Worker         mElem = value;
706*ec779b8eSAndroid Build Coastguard Worker     } break;
707*ec779b8eSAndroid Build Coastguard Worker     case mediametrics::kTypeCString: {
708*ec779b8eSAndroid Build Coastguard Worker         std::string value;
709*ec779b8eSAndroid Build Coastguard Worker         status = extract(&value, bufferpptr, bufferptrmax);
710*ec779b8eSAndroid Build Coastguard Worker         if (status != NO_ERROR) return status;
711*ec779b8eSAndroid Build Coastguard Worker         mElem = std::move(value);
712*ec779b8eSAndroid Build Coastguard Worker     } break;
713*ec779b8eSAndroid Build Coastguard Worker     case mediametrics::kTypeNone: {
714*ec779b8eSAndroid Build Coastguard Worker         mElem = std::monostate{};
715*ec779b8eSAndroid Build Coastguard Worker     } break;
716*ec779b8eSAndroid Build Coastguard Worker     default:
717*ec779b8eSAndroid Build Coastguard Worker         ALOGE("%s: found bad prop type: %d, name %s",
718*ec779b8eSAndroid Build Coastguard Worker                 __func__, (int)type, mName.c_str());  // no payload sent
719*ec779b8eSAndroid Build Coastguard Worker         return BAD_VALUE;
720*ec779b8eSAndroid Build Coastguard Worker     }
721*ec779b8eSAndroid Build Coastguard Worker     mName = name;
722*ec779b8eSAndroid Build Coastguard Worker     return NO_ERROR;
723*ec779b8eSAndroid Build Coastguard Worker }
724*ec779b8eSAndroid Build Coastguard Worker 
725*ec779b8eSAndroid Build Coastguard Worker } // namespace android::mediametrics
726