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 #include "chre/core/nanoapp.h"
18
19 #include "chre/core/event_loop_manager.h"
20 #include "chre/platform/assert.h"
21 #include "chre/platform/fatal_error.h"
22 #include "chre/platform/log.h"
23 #include "chre/util/system/debug_dump.h"
24 #include "chre_api/chre/gnss.h"
25 #include "chre_api/chre/version.h"
26
27 #include <algorithm>
28
29 #if CHRE_FIRST_SUPPORTED_API_VERSION < CHRE_API_VERSION_1_5
30 #define CHRE_GNSS_MEASUREMENT_BACK_COMPAT_ENABLED
31 #endif
32
33 namespace chre {
34
35 constexpr size_t Nanoapp::kMaxSizeWakeupBuckets;
36
Nanoapp()37 Nanoapp::Nanoapp() {
38 // Push first bucket onto wakeup bucket queue
39 cycleWakeupBuckets(1);
40 }
41
~Nanoapp()42 Nanoapp::~Nanoapp() {
43 const size_t totalAllocatedBytes = getTotalAllocatedBytes();
44
45 if (totalAllocatedBytes > 0) {
46 // TODO: Consider asserting here
47 LOGE("Nanoapp ID=0x%016" PRIx64 " still has %zu allocated bytes!",
48 getAppId(), totalAllocatedBytes);
49 }
50 }
51
isRegisteredForBroadcastEvent(uint16_t eventType,uint16_t targetGroupIdMask) const52 bool Nanoapp::isRegisteredForBroadcastEvent(uint16_t eventType,
53 uint16_t targetGroupIdMask) const {
54 bool registered = false;
55 size_t foundIndex = registrationIndex(eventType);
56 if (foundIndex < mRegisteredEvents.size()) {
57 const EventRegistration ® = mRegisteredEvents[foundIndex];
58 if (targetGroupIdMask & reg.groupIdMask) {
59 registered = true;
60 }
61 }
62 return registered;
63 }
64
registerForBroadcastEvent(uint16_t eventType,uint16_t groupIdMask)65 void Nanoapp::registerForBroadcastEvent(uint16_t eventType,
66 uint16_t groupIdMask) {
67 size_t foundIndex = registrationIndex(eventType);
68 if (foundIndex < mRegisteredEvents.size()) {
69 mRegisteredEvents[foundIndex].groupIdMask |= groupIdMask;
70 } else if (!mRegisteredEvents.push_back(
71 EventRegistration(eventType, groupIdMask))) {
72 FATAL_ERROR_OOM();
73 }
74 }
75
unregisterForBroadcastEvent(uint16_t eventType,uint16_t groupIdMask)76 void Nanoapp::unregisterForBroadcastEvent(uint16_t eventType,
77 uint16_t groupIdMask) {
78 size_t foundIndex = registrationIndex(eventType);
79 if (foundIndex < mRegisteredEvents.size()) {
80 EventRegistration ® = mRegisteredEvents[foundIndex];
81 reg.groupIdMask &= ~groupIdMask;
82 if (reg.groupIdMask == 0) {
83 mRegisteredEvents.erase(foundIndex);
84 }
85 }
86 }
87
configureNanoappInfoEvents(bool enable)88 void Nanoapp::configureNanoappInfoEvents(bool enable) {
89 if (enable) {
90 registerForBroadcastEvent(CHRE_EVENT_NANOAPP_STARTED);
91 registerForBroadcastEvent(CHRE_EVENT_NANOAPP_STOPPED);
92 } else {
93 unregisterForBroadcastEvent(CHRE_EVENT_NANOAPP_STARTED);
94 unregisterForBroadcastEvent(CHRE_EVENT_NANOAPP_STOPPED);
95 }
96 }
97
configureHostSleepEvents(bool enable)98 void Nanoapp::configureHostSleepEvents(bool enable) {
99 if (enable) {
100 registerForBroadcastEvent(CHRE_EVENT_HOST_AWAKE);
101 registerForBroadcastEvent(CHRE_EVENT_HOST_ASLEEP);
102 } else {
103 unregisterForBroadcastEvent(CHRE_EVENT_HOST_AWAKE);
104 unregisterForBroadcastEvent(CHRE_EVENT_HOST_ASLEEP);
105 }
106 }
107
configureDebugDumpEvent(bool enable)108 void Nanoapp::configureDebugDumpEvent(bool enable) {
109 if (enable) {
110 registerForBroadcastEvent(CHRE_EVENT_DEBUG_DUMP);
111 } else {
112 unregisterForBroadcastEvent(CHRE_EVENT_DEBUG_DUMP);
113 }
114 }
115
configureUserSettingEvent(uint8_t setting,bool enable)116 void Nanoapp::configureUserSettingEvent(uint8_t setting, bool enable) {
117 if (enable) {
118 registerForBroadcastEvent(CHRE_EVENT_SETTING_CHANGED_FIRST_EVENT + setting);
119 } else {
120 unregisterForBroadcastEvent(CHRE_EVENT_SETTING_CHANGED_FIRST_EVENT +
121 setting);
122 }
123 }
124
processNextEvent()125 Event *Nanoapp::processNextEvent() {
126 Event *event = mEventQueue.pop();
127
128 CHRE_ASSERT_LOG(event != nullptr, "Tried delivering event, but queue empty");
129 if (event != nullptr) {
130 if (event->eventType == CHRE_EVENT_GNSS_DATA) {
131 handleGnssMeasurementDataEvent(event);
132 } else {
133 handleEvent(event->senderInstanceId, event->eventType, event->eventData);
134 }
135 }
136
137 return event;
138 }
139
blameHostWakeup()140 void Nanoapp::blameHostWakeup() {
141 if (mWakeupBuckets.back() < UINT16_MAX) ++mWakeupBuckets.back();
142 }
143
cycleWakeupBuckets(size_t numBuckets)144 void Nanoapp::cycleWakeupBuckets(size_t numBuckets) {
145 numBuckets = std::min(numBuckets, kMaxSizeWakeupBuckets);
146 for (size_t i = 0; i < numBuckets; ++i) {
147 if (mWakeupBuckets.full()) {
148 mWakeupBuckets.erase(0);
149 }
150 mWakeupBuckets.push_back(0);
151 }
152 }
153
logStateToBuffer(DebugDumpWrapper & debugDump) const154 void Nanoapp::logStateToBuffer(DebugDumpWrapper &debugDump) const {
155 debugDump.print(" Id=%" PRIu32 " 0x%016" PRIx64 " ", getInstanceId(),
156 getAppId());
157 PlatformNanoapp::logStateToBuffer(debugDump);
158 debugDump.print(" v%" PRIu32 ".%" PRIu32 ".%" PRIu32 " tgtAPI=%" PRIu32
159 ".%" PRIu32 " curAlloc=%zu peakAlloc=%zu",
160 CHRE_EXTRACT_MAJOR_VERSION(getAppVersion()),
161 CHRE_EXTRACT_MINOR_VERSION(getAppVersion()),
162 CHRE_EXTRACT_PATCH_VERSION(getAppVersion()),
163 CHRE_EXTRACT_MAJOR_VERSION(getTargetApiVersion()),
164 CHRE_EXTRACT_MINOR_VERSION(getTargetApiVersion()),
165 getTotalAllocatedBytes(), getPeakAllocatedBytes());
166 debugDump.print(" hostWakeups=[ cur->");
167 // Get buckets latest -> earliest except last one
168 for (size_t i = mWakeupBuckets.size() - 1; i > 0; --i) {
169 debugDump.print("%" PRIu16 ", ", mWakeupBuckets[i]);
170 }
171 // Earliest bucket gets no comma
172 debugDump.print("%" PRIu16 " ]\n", mWakeupBuckets.front());
173 }
174
permitPermissionUse(uint32_t permission) const175 bool Nanoapp::permitPermissionUse(uint32_t permission) const {
176 return !supportsAppPermissions() ||
177 ((getAppPermissions() & permission) == permission);
178 }
179
registrationIndex(uint16_t eventType) const180 size_t Nanoapp::registrationIndex(uint16_t eventType) const {
181 size_t foundIndex = 0;
182 for (; foundIndex < mRegisteredEvents.size(); ++foundIndex) {
183 const EventRegistration ® = mRegisteredEvents[foundIndex];
184 if (reg.eventType == eventType) {
185 break;
186 }
187 }
188 return foundIndex;
189 }
190
handleGnssMeasurementDataEvent(const Event * event)191 void Nanoapp::handleGnssMeasurementDataEvent(const Event *event) {
192 #ifdef CHRE_GNSS_MEASUREMENT_BACK_COMPAT_ENABLED
193 const struct chreGnssDataEvent *data =
194 static_cast<const struct chreGnssDataEvent *>(event->eventData);
195 if (getTargetApiVersion() < CHRE_API_VERSION_1_5 &&
196 data->measurement_count > CHRE_GNSS_MAX_MEASUREMENT_PRE_1_5) {
197 chreGnssDataEvent localEvent;
198 memcpy(&localEvent, data, sizeof(struct chreGnssDataEvent));
199 localEvent.measurement_count = CHRE_GNSS_MAX_MEASUREMENT_PRE_1_5;
200 handleEvent(event->senderInstanceId, event->eventType, &localEvent);
201 } else
202 #endif // CHRE_GNSS_MEASUREMENT_BACK_COMPAT_ENABLED
203 {
204 handleEvent(event->senderInstanceId, event->eventType, event->eventData);
205 }
206 }
207
208 } // namespace chre
209