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 &reg = 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 &reg = 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 &reg = 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