1 /*
2 * Copyright (C) 2021 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 #include "EvsStats.h"
17
18 #include "packages/services/Car/cpp/telemetry/proto/evs.pb.h"
19
20 #include <aidl/android/frameworks/automotive/telemetry/CarData.h>
21 #include <aidl/android/frameworks/automotive/telemetry/ICarTelemetry.h>
22 #include <android-base/logging.h>
23 #include <android/binder_manager.h>
24 #include <binder/IServiceManager.h>
25 #include <utils/SystemClock.h>
26
27 #include <vector>
28
29 namespace {
30
31 using ::aidl::android::frameworks::automotive::telemetry::CarData;
32 using ::aidl::android::frameworks::automotive::telemetry::ICarTelemetry;
33 using ::android::automotive::telemetry::EvsFirstFrameLatency;
34
35 // Name of ICarTelemetry service that consumes RVC latency metrics.
36 constexpr const char kCarTelemetryServiceName[] =
37 "android.frameworks.automotive.telemetry.ICarTelemetry/default";
38
39 const int kCollectedDataSizeLimit = 200; // arbitrary chosen
40 // 10kb limit is imposed by ICarTelemetry, the limit if only for
41 // CarData.content vector.
42 const int kCarTelemetryMaxDataSizePerWrite = 10 * 1024;
43
44 // Defined in packages/services/Car/cpp/telemetry/proto/CarData.proto
45 const int kEvsFirstFrameLatencyId = 1;
46 } // namespace
47
48 // static
build()49 EvsStats EvsStats::build() {
50 // No need to enable stats if ICarTelemetry is not available.
51 bool enabled = false;
52 android::sp<android::IServiceManager> mgr = android::defaultServiceManager();
53 if (mgr) {
54 android::Vector<android::String16> services = mgr->listServices();
55 enabled = std::find(services.begin(), services.end(),
56 android::String16(kCarTelemetryServiceName)) != services.end();
57 }
58
59 if (!enabled) {
60 LOG(DEBUG) << "Telemetry service is not available.";
61 }
62 return EvsStats(enabled);
63 }
64
startComputingFirstFrameLatency(int64_t startTimeMillis)65 void EvsStats::startComputingFirstFrameLatency(int64_t startTimeMillis) {
66 mFirstFrameLatencyStartTimeMillis = startTimeMillis;
67 }
68
finishComputingFirstFrameLatency(int64_t finishTimeMillis)69 void EvsStats::finishComputingFirstFrameLatency(int64_t finishTimeMillis) {
70 if (!mEnabled) {
71 return;
72 }
73 if (mFirstFrameLatencyStartTimeMillis == EvsStatsState::NOT_STARTED) {
74 LOG(WARNING) << __func__ << "EvsStats received finishComputingFirstFrameLatency, but "
75 << "startComputingFirstFrameLatency was not called before.";
76 return;
77 }
78 auto firstFrameLatencyMillis = finishTimeMillis - mFirstFrameLatencyStartTimeMillis;
79 mFirstFrameLatencyStartTimeMillis = EvsStatsState::NOT_STARTED;
80
81 LOG(DEBUG) << __func__ << ": firstFrameLatencyMillis = " << firstFrameLatencyMillis;
82
83 EvsFirstFrameLatency latency;
84 latency.set_start_timestamp_millis(mFirstFrameLatencyStartTimeMillis);
85 latency.set_latency_millis(firstFrameLatencyMillis);
86 std::vector<uint8_t> bytes(latency.ByteSizeLong());
87 latency.SerializeToArray(&bytes[0], latency.ByteSizeLong());
88 CarData msg;
89 msg.id = kEvsFirstFrameLatencyId;
90 msg.content = std::move(bytes);
91
92 if (msg.content.size() > kCarTelemetryMaxDataSizePerWrite) {
93 LOG(WARNING) << __func__ << "finishComputingFirstFrameLatency is trying to store data "
94 << "with size " << msg.content.size() << ", which is larger than allowed "
95 << kCarTelemetryMaxDataSizePerWrite;
96 return;
97 }
98
99 mCollectedData.push_back(msg);
100
101 while (mCollectedData.size() > kCollectedDataSizeLimit) {
102 mCollectedData.pop_front();
103 }
104
105 sendCollectedDataUnsafe(/* waitIfNotReady= */ false);
106 }
107
sendCollectedDataBlocking()108 void EvsStats::sendCollectedDataBlocking() {
109 if (!mEnabled || mCollectedData.empty()) {
110 return;
111 }
112 sendCollectedDataUnsafe(/* waitIfNotReady= */ true);
113 }
114
getCarTelemetry(bool waitIfNotReady)115 std::shared_ptr<ICarTelemetry> EvsStats::getCarTelemetry(bool waitIfNotReady) {
116 {
117 const std::scoped_lock<std::mutex> lock(mMutex);
118 if (mCarTelemetry != nullptr) {
119 return mCarTelemetry;
120 }
121 }
122
123 AIBinder* binder;
124 if (waitIfNotReady) {
125 binder = ::AServiceManager_waitForService(kCarTelemetryServiceName);
126 } else {
127 binder = ::AServiceManager_checkService(kCarTelemetryServiceName);
128 }
129
130 if (binder == nullptr) {
131 LOG(WARNING) << __func__ << ": ICarTelemetry is not ready";
132 return nullptr;
133 }
134
135 const std::scoped_lock<std::mutex> lock(mMutex); // locks until the end of the method
136 mCarTelemetry = ICarTelemetry::fromBinder(ndk::SpAIBinder(binder));
137 if (!mCarTelemetry) {
138 LOG(WARNING) << "CarTelemetry service is not available.";
139 return nullptr;
140 }
141
142 auto status = ndk::ScopedAStatus::fromStatus(
143 ::AIBinder_linkToDeath(mCarTelemetry->asBinder().get(), mBinderDeathRecipient.get(),
144 this));
145 if (!status.isOk()) {
146 LOG(WARNING) << __func__
147 << ": Failed to linkToDeath, continuing anyway: " << status.getMessage();
148 }
149 return mCarTelemetry;
150 }
151
sendCollectedDataUnsafe(bool waitIfNotReady)152 void EvsStats::sendCollectedDataUnsafe(bool waitIfNotReady) {
153 std::shared_ptr<ICarTelemetry> telemetry = getCarTelemetry(waitIfNotReady);
154 if (telemetry == nullptr) {
155 LOG(INFO) << __func__ << ": CarTelemetry is not ready, ignoring";
156 return;
157 }
158
159 // Send data chunk by chnk, because Binder has transfer data size limit.
160 // Adds the oldest elements to `sendingData` and tries to push ICarTelemetryService.
161 // If successful, erases then from `mCollectedData`, otherwise leaves them there to try again
162 // later.
163 while (!mCollectedData.empty()) {
164 int sendingDataSizeBytes = 0;
165 std::vector<CarData> sendingData;
166 auto it = mCollectedData.begin();
167 while (it != mCollectedData.end()) {
168 sendingDataSizeBytes += it->content.size();
169 if (sendingDataSizeBytes > kCarTelemetryMaxDataSizePerWrite) {
170 break;
171 }
172 sendingData.push_back(*it);
173 it++;
174 }
175 ndk::ScopedAStatus status = telemetry->write(sendingData);
176 if (!status.isOk()) {
177 LOG(WARNING) << __func__
178 << "Failed to write data to ICarTelemetry: " << status.getMessage();
179 return;
180 }
181 mCollectedData.erase(mCollectedData.begin(), it);
182 }
183 }
184
185 // Removes the listener if its binder dies.
telemetryBinderDiedImpl()186 void EvsStats::telemetryBinderDiedImpl() {
187 LOG(WARNING) << __func__ << "ICarTelemetry service died, resetting the state";
188 const std::scoped_lock<std::mutex> lock(mMutex);
189 mCarTelemetry = nullptr;
190 }
191
192 // static
telemetryBinderDied(void * cookie)193 void EvsStats::telemetryBinderDied(void* cookie) {
194 // We expect the pointer to be alive as there is only a single instance of
195 // EvsStats and if EvsStats is destructed, then the whole evs_app should be dead too.
196 auto thiz = static_cast<EvsStats*>(cookie);
197 thiz->telemetryBinderDiedImpl();
198 }
199