1 /*
2 * Copyright (C) 2023 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 #include "chre_host/metrics_reporter.h"
18 #include <chre_atoms_log.h>
19 #include "chre_host/log.h"
20
21 #include <cinttypes>
22 #include <limits>
23 #include <mutex>
24
25 #include <android/binder_manager.h>
26
27 namespace android::chre {
28
29 using ::aidl::android::frameworks::stats::IStats;
30 using ::aidl::android::frameworks::stats::VendorAtom;
31 using ::aidl::android::frameworks::stats::VendorAtomValue;
32 using ::android::chre::Atoms::CHRE_AP_WAKE_UP_OCCURRED;
33 using ::android::chre::Atoms::CHRE_EVENT_QUEUE_SNAPSHOT_REPORTED;
34 using ::android::chre::Atoms::CHRE_HAL_NANOAPP_LOAD_FAILED;
35 using ::android::chre::Atoms::CHRE_PAL_OPEN_FAILED;
36 using ::android::chre::Atoms::ChreHalNanoappLoadFailed;
37 using ::android::chre::Atoms::ChrePalOpenFailed;
38
getStatsService()39 std::shared_ptr<IStats> MetricsReporter::getStatsService() {
40 const std::string statsServiceName =
41 std::string(IStats::descriptor).append("/default");
42 if (!AServiceManager_isDeclared(statsServiceName.c_str())) {
43 LOGE("Stats service is not declared.");
44 return nullptr;
45 }
46
47 ndk::SpAIBinder statsServiceBinder =
48 ndk::SpAIBinder(AServiceManager_waitForService(statsServiceName.c_str()));
49 if (statsServiceBinder.get() == nullptr) {
50 LOGE("Failed to get the IStats service binder");
51 return nullptr;
52 }
53
54 binder_status_t status = AIBinder_linkToDeath(
55 statsServiceBinder.get(), AIBinder_DeathRecipient_new([](void *cookie) {
56 auto *metricsReporter = static_cast<MetricsReporter *>(cookie);
57 metricsReporter->onBinderDied();
58 }),
59 this);
60 if (status != STATUS_OK) {
61 LOGE("Failed to link to death the stats service binder");
62 return nullptr;
63 }
64
65 std::shared_ptr<IStats> statsService = IStats::fromBinder(statsServiceBinder);
66 if (statsService == nullptr) {
67 LOGE("Failed to get IStats service");
68 return nullptr;
69 }
70 return statsService;
71 }
72
reportMetric(const VendorAtom & atom)73 bool MetricsReporter::reportMetric(const VendorAtom &atom) {
74 ndk::ScopedAStatus ret;
75 {
76 std::lock_guard<std::mutex> lock(mStatsServiceMutex);
77 if (mStatsService == nullptr) {
78 mStatsService = getStatsService();
79 if (mStatsService == nullptr) {
80 return false;
81 }
82 }
83
84 ret = mStatsService->reportVendorAtom(atom);
85 }
86
87 if (!ret.isOk()) {
88 LOGE("Failed to report vendor atom with ID %" PRIi32, atom.atomId);
89 }
90 return ret.isOk();
91 }
92
logApWakeupOccurred(uint64_t nanoappId)93 bool MetricsReporter::logApWakeupOccurred(uint64_t nanoappId) {
94 std::vector<VendorAtomValue> values(1);
95 values[0].set<VendorAtomValue::longValue>(nanoappId);
96
97 const VendorAtom atom{
98 .atomId = CHRE_AP_WAKE_UP_OCCURRED,
99 .values{std::move(values)},
100 };
101
102 return reportMetric(atom);
103 }
104
logNanoappLoadFailed(uint64_t nanoappId,ChreHalNanoappLoadFailed::Type type,ChreHalNanoappLoadFailed::Reason reason)105 bool MetricsReporter::logNanoappLoadFailed(
106 uint64_t nanoappId, ChreHalNanoappLoadFailed::Type type,
107 ChreHalNanoappLoadFailed::Reason reason) {
108 std::vector<VendorAtomValue> values(3);
109 values[0].set<VendorAtomValue::longValue>(nanoappId);
110 values[1].set<VendorAtomValue::intValue>(type);
111 values[2].set<VendorAtomValue::intValue>(reason);
112
113 const VendorAtom atom{
114 .atomId = CHRE_HAL_NANOAPP_LOAD_FAILED,
115 .values{std::move(values)},
116 };
117
118 return reportMetric(atom);
119 }
120
logPalOpenFailed(ChrePalOpenFailed::ChrePalType pal,ChrePalOpenFailed::Type type)121 bool MetricsReporter::logPalOpenFailed(ChrePalOpenFailed::ChrePalType pal,
122 ChrePalOpenFailed::Type type) {
123 std::vector<VendorAtomValue> values(2);
124 values[0].set<VendorAtomValue::intValue>(pal);
125 values[1].set<VendorAtomValue::intValue>(type);
126
127 const VendorAtom atom{
128 .atomId = CHRE_PAL_OPEN_FAILED,
129 .values{std::move(values)},
130 };
131
132 return reportMetric(atom);
133 }
134
logEventQueueSnapshotReported(int32_t snapshotChreGetTimeMs,int32_t maxEventQueueSize,int32_t meanEventQueueSize,int32_t numDroppedEvents)135 bool MetricsReporter::logEventQueueSnapshotReported(
136 int32_t snapshotChreGetTimeMs, int32_t maxEventQueueSize,
137 int32_t meanEventQueueSize, int32_t numDroppedEvents) {
138 std::vector<VendorAtomValue> values(6);
139 values[0].set<VendorAtomValue::intValue>(snapshotChreGetTimeMs);
140 values[1].set<VendorAtomValue::intValue>(maxEventQueueSize);
141 values[2].set<VendorAtomValue::intValue>(meanEventQueueSize);
142 values[3].set<VendorAtomValue::intValue>(numDroppedEvents);
143
144 // TODO(b/298459533): Implement these two values
145 // Last two values are not currently populated and will be implemented
146 // later. To avoid confusion of the interpretation, we use UINT32_MAX
147 // as a placeholder value.
148 values[4].set<VendorAtomValue::longValue>(
149 std::numeric_limits<int64_t>::max());
150 values[5].set<VendorAtomValue::longValue>(
151 std::numeric_limits<int64_t>::max());
152
153 const VendorAtom atom{
154 .atomId = CHRE_EVENT_QUEUE_SNAPSHOT_REPORTED,
155 .values{std::move(values)},
156 };
157
158 return reportMetric(atom);
159 }
160
onBinderDied()161 void MetricsReporter::onBinderDied() {
162 LOGI("MetricsReporter: stats service died - reconnecting");
163
164 std::lock_guard<std::mutex> lock(mStatsServiceMutex);
165 mStatsService.reset();
166 mStatsService = getStatsService();
167 }
168
169 } // namespace android::chre
170