• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  
37  Nanoapp::Nanoapp() {
38    // Push first bucket onto wakeup bucket queue
39    cycleWakeupBuckets(1);
40  }
41  
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  
52  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  
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  
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  
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  
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  
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  
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  
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  
140  void Nanoapp::blameHostWakeup() {
141    if (mWakeupBuckets.back() < UINT16_MAX) ++mWakeupBuckets.back();
142  }
143  
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  
154  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  
175  bool Nanoapp::permitPermissionUse(uint32_t permission) const {
176    return !supportsAppPermissions() ||
177           ((getAppPermissions() & permission) == permission);
178  }
179  
180  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  
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