1 /*
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
17 #define LOG_TAG "mediametrics::Item-Serialization"
18
19 #include <inttypes.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/endian.h>
23 #include <sys/types.h>
24
25 #include <binder/Parcel.h>
26 #include <cutils/multiuser.h>
27 #include <cutils/properties.h>
28 #include <utils/Errors.h>
29 #include <utils/Log.h>
30 #include <utils/SortedVector.h>
31 #include <utils/threads.h>
32
33 #include <android/media/BnMediaMetricsService.h> // for direct Binder access
34 #include <android/media/IMediaMetricsService.h>
35 #include <binder/IServiceManager.h>
36 #include <media/MediaMetricsItem.h>
37 #include <private/android_filesystem_config.h>
38
39 // Max per-property string size before truncation in toString().
40 // Do not make too large, as this is used for dumpsys purposes.
41 static constexpr size_t kMaxPropertyStringSize = 4096;
42
43 namespace android::mediametrics {
44
45 // Parcel / serialize things for binder calls
46 //
47
readFromParcel(const Parcel & data)48 status_t mediametrics::Item::readFromParcel(const Parcel& data) {
49 int32_t version;
50 status_t status = data.readInt32(&version);
51 if (status != NO_ERROR) return status;
52
53 switch (version) {
54 case 0:
55 return readFromParcel0(data);
56 default:
57 ALOGE("%s: unsupported parcel version: %d", __func__, version);
58 return INVALID_OPERATION;
59 }
60 }
61
readFromParcel0(const Parcel & data)62 status_t mediametrics::Item::readFromParcel0(const Parcel& data) {
63 mKey = std::string{data.readString8()};
64 int32_t pid, uid;
65 status_t status = data.readInt32(&pid) ?: data.readInt32(&uid);
66 if (status != NO_ERROR) return status;
67 mPid = (pid_t)pid;
68 mUid = (uid_t)uid;
69 mPkgName = std::string(data.readString8());
70 int32_t count;
71 int64_t version, timestamp;
72 status = data.readInt64(&version) ?: data.readInt64(×tamp) ?: data.readInt32(&count);
73 if (status != NO_ERROR) return status;
74 if (count < 0) return BAD_VALUE;
75 mPkgVersionCode = version;
76 mTimestamp = timestamp;
77 for (int i = 0; i < count; i++) {
78 Prop prop;
79 status_t status = prop.readFromParcel(data);
80 if (status != NO_ERROR) return status;
81 mProps[prop.getName()] = std::move(prop);
82 }
83 return NO_ERROR;
84 }
85
writeToParcel(Parcel * data) const86 status_t mediametrics::Item::writeToParcel(Parcel *data) const {
87 if (data == nullptr) return BAD_VALUE;
88
89 const int32_t version = 0;
90 status_t status = data->writeInt32(version);
91 if (status != NO_ERROR) return status;
92
93 switch (version) {
94 case 0:
95 return writeToParcel0(data);
96 default:
97 ALOGE("%s: unsupported parcel version: %d", __func__, version);
98 return INVALID_OPERATION;
99 }
100 }
101
writeToParcel0(Parcel * data) const102 status_t mediametrics::Item::writeToParcel0(Parcel *data) const {
103 status_t status =
104 data->writeString8(String8{mKey})
105 ?: data->writeInt32(mPid)
106 ?: data->writeInt32(mUid)
107 ?: data->writeString8(String8{mPkgName})
108 ?: data->writeInt64(mPkgVersionCode)
109 ?: data->writeInt64(mTimestamp);
110 if (status != NO_ERROR) return status;
111
112 data->writeInt32((int32_t)mProps.size());
113 for (auto &prop : *this) {
114 status = prop.writeToParcel(data);
115 if (status != NO_ERROR) return status;
116 }
117 return NO_ERROR;
118 }
119
readFromParcel(const Parcel & data)120 status_t mediametrics::Item::Prop::readFromParcel(const Parcel& data)
121 {
122 const std::string key {data.readString8()};
123 int32_t type;
124 status_t status = data.readInt32(&type);
125 if (status != NO_ERROR) return status;
126 switch (type) {
127 case mediametrics::kTypeInt32: {
128 int32_t value;
129 status = data.readInt32(&value);
130 if (status != NO_ERROR) return status;
131 mElem = value;
132 } break;
133 case mediametrics::kTypeInt64: {
134 int64_t value;
135 status = data.readInt64(&value);
136 if (status != NO_ERROR) return status;
137 mElem = value;
138 } break;
139 case mediametrics::kTypeDouble: {
140 double value;
141 status = data.readDouble(&value);
142 if (status != NO_ERROR) return status;
143 mElem = value;
144 } break;
145 case mediametrics::kTypeCString: {
146 mElem = std::string{data.readString8()};
147 } break;
148 case mediametrics::kTypeRate: {
149 std::pair<int64_t, int64_t> rate;
150 status = data.readInt64(&rate.first)
151 ?: data.readInt64(&rate.second);
152 if (status != NO_ERROR) return status;
153 mElem = rate;
154 } break;
155 case mediametrics::kTypeNone: {
156 mElem = std::monostate{};
157 } break;
158 default:
159 ALOGE("%s: reading bad item type: %d", __func__, type);
160 return BAD_VALUE;
161 }
162 setName(key);
163 return NO_ERROR;
164 }
165
166 } // namespace android::mediametrics
167