• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.ByteSize());
87     latency.SerializeToArray(&bytes[0], latency.ByteSize());
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_getService(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     auto status = ndk::ScopedAStatus::fromStatus(
138             ::AIBinder_linkToDeath(mCarTelemetry->asBinder().get(), mBinderDeathRecipient.get(),
139                                    this));
140     if (!status.isOk()) {
141         LOG(WARNING) << __func__
142                      << ": Failed to linkToDeath, continuing anyway: " << status.getMessage();
143     }
144     return mCarTelemetry;
145 }
146 
sendCollectedDataUnsafe(bool waitIfNotReady)147 void EvsStats::sendCollectedDataUnsafe(bool waitIfNotReady) {
148     std::shared_ptr<ICarTelemetry> telemetry = getCarTelemetry(waitIfNotReady);
149     if (telemetry == nullptr) {
150         LOG(INFO) << __func__ << ": CarTelemetry is not ready, ignoring";
151         return;
152     }
153 
154     // Send data chunk by chnk, because Binder has transfer data size limit.
155     // Adds the oldest elements to `sendingData` and tries to push ICarTelemetryService.
156     // If successful, erases then from `mCollectedData`, otherwise leaves them there to try again
157     // later.
158     while (!mCollectedData.empty()) {
159         int sendingDataSizeBytes = 0;
160         std::vector<CarData> sendingData;
161         auto it = mCollectedData.begin();
162         while (it != mCollectedData.end()) {
163             sendingDataSizeBytes += it->content.size();
164             if (sendingDataSizeBytes > kCarTelemetryMaxDataSizePerWrite) {
165                 break;
166             }
167             sendingData.push_back(*it);
168             it++;
169         }
170         ndk::ScopedAStatus status = telemetry->write(sendingData);
171         if (!status.isOk()) {
172             LOG(WARNING) << __func__
173                          << "Failed to write data to ICarTelemetry: " << status.getMessage();
174             return;
175         }
176         mCollectedData.erase(mCollectedData.begin(), it);
177     }
178 }
179 
180 // Removes the listener if its binder dies.
telemetryBinderDiedImpl()181 void EvsStats::telemetryBinderDiedImpl() {
182     LOG(WARNING) << __func__ << "ICarTelemetry service died, resetting the state";
183     const std::scoped_lock<std::mutex> lock(mMutex);
184     mCarTelemetry = nullptr;
185 }
186 
187 // static
telemetryBinderDied(void * cookie)188 void EvsStats::telemetryBinderDied(void* cookie) {
189     // We expect the pointer to be alive as there is only a single instance of
190     // EvsStats and if EvsStats is destructed, then the whole evs_app should be dead too.
191     auto thiz = static_cast<EvsStats*>(cookie);
192     thiz->telemetryBinderDiedImpl();
193 }
194