1e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie/*
2e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie * Copyright (C) 2016 The Android Open Source Project
3e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie *
4e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie * Licensed under the Apache License, Version 2.0 (the "License");
5e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie * you may not use this file except in compliance with the License.
6e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie * You may obtain a copy of the License at
7e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie *
8e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie *      http://www.apache.org/licenses/LICENSE-2.0
9e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie *
10e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie * Unless required by applicable law or agreed to in writing, software
11e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie * distributed under the License is distributed on an "AS IS" BASIS,
12e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie * See the License for the specific language governing permissions and
14e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie * limitations under the License.
15e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie */
16e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie
17e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie#include "chre/core/event_loop.h"
18e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie
19e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie#include "chre/core/event.h"
20341292509cfde0f859d89bda4ca5d55fc9772e64Brian Duddie#include "chre/core/event_loop_manager.h"
21e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie#include "chre/core/nanoapp.h"
22977321d9ad051d4d6519a5fa8c2ca914f4d1424fBrian Duddie#include "chre/platform/context.h"
23e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie#include "chre/platform/log.h"
24f1694b5b8abc93de4e187a78c096977ad6cf4b56Brian Duddie#include "chre/util/conditional_lock_guard.h"
25f1694b5b8abc93de4e187a78c096977ad6cf4b56Brian Duddie#include "chre/util/lock_guard.h"
26d0530f420d8bdaee755ec2834af407424de195e0Arthur Ishiguro#include "chre/util/system/debug_dump.h"
27a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie#include "chre_api/chre/version.h"
28e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie
29e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddienamespace chre {
30e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie
3162f187d9d736346275492e916f6001576b68bb00Brian Duddienamespace {
3262f187d9d736346275492e916f6001576b68bb00Brian Duddie
3362f187d9d736346275492e916f6001576b68bb00Brian Duddie/**
3462f187d9d736346275492e916f6001576b68bb00Brian Duddie * Populates a chreNanoappInfo structure using info from the given Nanoapp
3562f187d9d736346275492e916f6001576b68bb00Brian Duddie * instance.
3662f187d9d736346275492e916f6001576b68bb00Brian Duddie *
3762f187d9d736346275492e916f6001576b68bb00Brian Duddie * @param app A potentially null pointer to the Nanoapp to read from
3862f187d9d736346275492e916f6001576b68bb00Brian Duddie * @param info The structure to populate - should not be null, but this function
3962f187d9d736346275492e916f6001576b68bb00Brian Duddie *        will handle that input
4062f187d9d736346275492e916f6001576b68bb00Brian Duddie *
4162f187d9d736346275492e916f6001576b68bb00Brian Duddie * @return true if neither app nor info were null, and info was populated
4262f187d9d736346275492e916f6001576b68bb00Brian Duddie */
4362f187d9d736346275492e916f6001576b68bb00Brian Duddiebool populateNanoappInfo(const Nanoapp *app, struct chreNanoappInfo *info) {
4462f187d9d736346275492e916f6001576b68bb00Brian Duddie  bool success = false;
4562f187d9d736346275492e916f6001576b68bb00Brian Duddie
4662f187d9d736346275492e916f6001576b68bb00Brian Duddie  if (app != nullptr && info != nullptr) {
4762f187d9d736346275492e916f6001576b68bb00Brian Duddie    info->appId      = app->getAppId();
4862f187d9d736346275492e916f6001576b68bb00Brian Duddie    info->version    = app->getAppVersion();
4962f187d9d736346275492e916f6001576b68bb00Brian Duddie    info->instanceId = app->getInstanceId();
5062f187d9d736346275492e916f6001576b68bb00Brian Duddie    success = true;
5162f187d9d736346275492e916f6001576b68bb00Brian Duddie  }
5262f187d9d736346275492e916f6001576b68bb00Brian Duddie
5362f187d9d736346275492e916f6001576b68bb00Brian Duddie  return success;
5462f187d9d736346275492e916f6001576b68bb00Brian Duddie}
5562f187d9d736346275492e916f6001576b68bb00Brian Duddie
5662f187d9d736346275492e916f6001576b68bb00Brian Duddie}  // anonymous namespace
5762f187d9d736346275492e916f6001576b68bb00Brian Duddie
58fbb213b072fec0a14f437ad55685c4d95eec829eAndrew RossignolEventLoop::EventLoop()
59fbb213b072fec0a14f437ad55685c4d95eec829eAndrew Rossignol    : mTimerPool(*this) {}
60fbb213b072fec0a14f437ad55685c4d95eec829eAndrew Rossignol
61977321d9ad051d4d6519a5fa8c2ca914f4d1424fBrian Duddiebool EventLoop::findNanoappInstanceIdByAppId(uint64_t appId,
622fce52a25d14fcdcba888f8ff7892dffe3f55abaBrian Duddie                                             uint32_t *instanceId) const {
63977321d9ad051d4d6519a5fa8c2ca914f4d1424fBrian Duddie  CHRE_ASSERT(instanceId != nullptr);
649526b7b52ed3e6cb198c649f582877acb27f1c56Andrew Rossignol  ConditionalLockGuard<Mutex> lock(mNanoappsLock, !inEventLoopThread());
65977321d9ad051d4d6519a5fa8c2ca914f4d1424fBrian Duddie
66977321d9ad051d4d6519a5fa8c2ca914f4d1424fBrian Duddie  bool found = false;
675d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie  for (const UniquePtr<Nanoapp>& app : mNanoapps) {
68977321d9ad051d4d6519a5fa8c2ca914f4d1424fBrian Duddie    if (app->getAppId() == appId) {
69977321d9ad051d4d6519a5fa8c2ca914f4d1424fBrian Duddie      *instanceId = app->getInstanceId();
70977321d9ad051d4d6519a5fa8c2ca914f4d1424fBrian Duddie      found = true;
71977321d9ad051d4d6519a5fa8c2ca914f4d1424fBrian Duddie      break;
72977321d9ad051d4d6519a5fa8c2ca914f4d1424fBrian Duddie    }
73977321d9ad051d4d6519a5fa8c2ca914f4d1424fBrian Duddie  }
74977321d9ad051d4d6519a5fa8c2ca914f4d1424fBrian Duddie
75977321d9ad051d4d6519a5fa8c2ca914f4d1424fBrian Duddie  return found;
76977321d9ad051d4d6519a5fa8c2ca914f4d1424fBrian Duddie}
77977321d9ad051d4d6519a5fa8c2ca914f4d1424fBrian Duddie
78a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddievoid EventLoop::forEachNanoapp(NanoappCallbackFunction *callback, void *data) {
799526b7b52ed3e6cb198c649f582877acb27f1c56Andrew Rossignol  ConditionalLockGuard<Mutex> lock(mNanoappsLock, !inEventLoopThread());
80a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie
815d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie  for (const UniquePtr<Nanoapp>& nanoapp : mNanoapps) {
82a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie    callback(nanoapp.get(), data);
83a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie  }
84a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie}
85a2f5add27054c406f36528cf8a5cbc6d4c79d246Brian Duddie
8609a4783208b5ba1e14d0f0102eb31e688caca28dBrian Duddievoid EventLoop::invokeMessageFreeFunction(
8709a4783208b5ba1e14d0f0102eb31e688caca28dBrian Duddie    uint64_t appId, chreMessageFreeFunction *freeFunction, void *message,
8809a4783208b5ba1e14d0f0102eb31e688caca28dBrian Duddie    size_t messageSize) {
8909a4783208b5ba1e14d0f0102eb31e688caca28dBrian Duddie  Nanoapp *nanoapp = lookupAppByAppId(appId);
9009a4783208b5ba1e14d0f0102eb31e688caca28dBrian Duddie  if (nanoapp == nullptr) {
9109a4783208b5ba1e14d0f0102eb31e688caca28dBrian Duddie    LOGE("Couldn't find app 0x%016" PRIx64 " for message free callback", appId);
9209a4783208b5ba1e14d0f0102eb31e688caca28dBrian Duddie  } else {
9309a4783208b5ba1e14d0f0102eb31e688caca28dBrian Duddie    auto prevCurrentApp = mCurrentApp;
9409a4783208b5ba1e14d0f0102eb31e688caca28dBrian Duddie    mCurrentApp = nanoapp;
9509a4783208b5ba1e14d0f0102eb31e688caca28dBrian Duddie    freeFunction(message, messageSize);
9609a4783208b5ba1e14d0f0102eb31e688caca28dBrian Duddie    mCurrentApp = prevCurrentApp;
9709a4783208b5ba1e14d0f0102eb31e688caca28dBrian Duddie  }
9809a4783208b5ba1e14d0f0102eb31e688caca28dBrian Duddie}
9909a4783208b5ba1e14d0f0102eb31e688caca28dBrian Duddie
100e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddievoid EventLoop::run() {
101e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie  LOGI("EventLoop start");
102e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie
103e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie  bool havePendingEvents = false;
104e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie  while (mRunning) {
10599f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie    // Events are delivered in two stages: first they arrive in the inbound
10699f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie    // event queue mEvents (potentially posted from another thread), then within
10799f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie    // this context these events are distributed to smaller event queues
10899f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie    // associated with each Nanoapp that should receive the event. Once the
10999f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie    // event is delivered to all interested Nanoapps, its free callback is
11099f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie    // invoked.
111e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie    if (!havePendingEvents || !mEvents.empty()) {
11288f21c7ca23d96f6ef568a06c98f3a5c4538140fAndrew Rossignol      if (mEvents.size() > mMaxEventPoolUsage) {
11388f21c7ca23d96f6ef568a06c98f3a5c4538140fAndrew Rossignol        mMaxEventPoolUsage = mEvents.size();
11488f21c7ca23d96f6ef568a06c98f3a5c4538140fAndrew Rossignol      }
11588f21c7ca23d96f6ef568a06c98f3a5c4538140fAndrew Rossignol
11699f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie      // mEvents.pop() will be a blocking call if mEvents.empty()
11799f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie      distributeEvent(mEvents.pop());
118e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie    }
119e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie
12099f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie    havePendingEvents = deliverEvents();
121ff1c1a2ab3ff2614bb6cea1f1d6f6e9c44a87464Arthur Ishiguro
122ff1c1a2ab3ff2614bb6cea1f1d6f6e9c44a87464Arthur Ishiguro    mPowerControlManager.postEventLoopProcess(mEvents.size());
123e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie  }
124e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie
12599f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie  // Deliver any events sitting in Nanoapps' own queues (we could drop them to
12699f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie  // exit faster, but this is less code and should complete quickly under normal
12799f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie  // conditions), then purge the main queue of events pending distribution. All
12899f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie  // nanoapps should be prevented from sending events or messages at this point
12999f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie  // via currentNanoappIsStopping() returning true.
13099f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie  flushNanoappEventQueues();
1315d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie  while (!mEvents.empty()) {
1325d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie    freeEvent(mEvents.pop());
1335d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie  }
1345d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie
13599f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie  // Unload all running nanoapps
1362de17c9c5c541d72248f8371dfb4d7e402dc93e8Andrew Rossignol  while (!mNanoapps.empty()) {
13799f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie    unloadNanoappAtIndex(mNanoapps.size() - 1);
1382de17c9c5c541d72248f8371dfb4d7e402dc93e8Andrew Rossignol  }
139e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie
1402de17c9c5c541d72248f8371dfb4d7e402dc93e8Andrew Rossignol  LOGI("Exiting EventLoop");
141e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie}
142e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie
1439d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddiebool EventLoop::startNanoapp(UniquePtr<Nanoapp>& nanoapp) {
1449d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie  CHRE_ASSERT(!nanoapp.isNull());
1452de17c9c5c541d72248f8371dfb4d7e402dc93e8Andrew Rossignol  bool success = false;
1465d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie  auto *eventLoopManager = EventLoopManagerSingleton::get();
14750d7d95f1d8cae0e9c6202086b9bd432adff7bf1Andrew Rossignol  EventLoop& eventLoop = eventLoopManager->getEventLoop();
1485d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie  uint32_t existingInstanceId;
1495d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie
1505d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie  if (nanoapp.isNull()) {
1515d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie    // no-op, invalid argument
15250d7d95f1d8cae0e9c6202086b9bd432adff7bf1Andrew Rossignol  } else if (eventLoop.findNanoappInstanceIdByAppId(nanoapp->getAppId(),
15350d7d95f1d8cae0e9c6202086b9bd432adff7bf1Andrew Rossignol                                                    &existingInstanceId)) {
1545d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie    LOGE("App with ID 0x%016" PRIx64 " already exists as instance ID 0x%"
1555d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie         PRIx32, nanoapp->getAppId(), existingInstanceId);
1565d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie  } else if (!mNanoapps.prepareForPush()) {
1572de17c9c5c541d72248f8371dfb4d7e402dc93e8Andrew Rossignol    LOGE("Failed to allocate space for new nanoapp");
1582de17c9c5c541d72248f8371dfb4d7e402dc93e8Andrew Rossignol  } else {
1595d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie    nanoapp->setInstanceId(eventLoopManager->getNextInstanceId());
1606f7ee70aab8a27c9c6ec431dc12b71a2b2bb9babBrian Duddie    LOGD("Instance ID %" PRIu32 " assigned to app ID 0x%016" PRIx64,
1616f7ee70aab8a27c9c6ec431dc12b71a2b2bb9babBrian Duddie         nanoapp->getInstanceId(), nanoapp->getAppId());
16282f7498d84fc3631b7631d32994318ad16f0b24dBrian Duddie
16382f7498d84fc3631b7631d32994318ad16f0b24dBrian Duddie    Nanoapp *newNanoapp = nanoapp.get();
16482f7498d84fc3631b7631d32994318ad16f0b24dBrian Duddie    {
16582f7498d84fc3631b7631d32994318ad16f0b24dBrian Duddie      LockGuard<Mutex> lock(mNanoappsLock);
16682f7498d84fc3631b7631d32994318ad16f0b24dBrian Duddie      mNanoapps.push_back(std::move(nanoapp));
16782f7498d84fc3631b7631d32994318ad16f0b24dBrian Duddie      // After this point, nanoapp is null as we've transferred ownership into
16882f7498d84fc3631b7631d32994318ad16f0b24dBrian Duddie      // mNanoapps.back() - use newNanoapp to reference it
16982f7498d84fc3631b7631d32994318ad16f0b24dBrian Duddie    }
17082f7498d84fc3631b7631d32994318ad16f0b24dBrian Duddie
17182f7498d84fc3631b7631d32994318ad16f0b24dBrian Duddie    mCurrentApp = newNanoapp;
17282f7498d84fc3631b7631d32994318ad16f0b24dBrian Duddie    success = newNanoapp->start();
1739d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie    mCurrentApp = nullptr;
1749d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie    if (!success) {
17582f7498d84fc3631b7631d32994318ad16f0b24dBrian Duddie      // TODO: to be fully safe, need to purge/flush any events and messages
17682f7498d84fc3631b7631d32994318ad16f0b24dBrian Duddie      // sent by the nanoapp here (but don't call nanoappEnd). For now, we just
17782f7498d84fc3631b7631d32994318ad16f0b24dBrian Duddie      // destroy the Nanoapp instance.
17882f7498d84fc3631b7631d32994318ad16f0b24dBrian Duddie      LOGE("Nanoapp %" PRIu32 " failed to start", newNanoapp->getInstanceId());
17982f7498d84fc3631b7631d32994318ad16f0b24dBrian Duddie
18082f7498d84fc3631b7631d32994318ad16f0b24dBrian Duddie      // Note that this lock protects against concurrent read and modification
18182f7498d84fc3631b7631d32994318ad16f0b24dBrian Duddie      // of mNanoapps, but we are assured that no new nanoapps were added since
18282f7498d84fc3631b7631d32994318ad16f0b24dBrian Duddie      // we pushed the new nanoapp
1839d5b500a223ef73560f0dce38f50b809bde5dd0dBrian Duddie      LockGuard<Mutex> lock(mNanoappsLock);
18482f7498d84fc3631b7631d32994318ad16f0b24dBrian Duddie      mNanoapps.pop_back();
18565d679851a2c062c26f685afb450f17bce177d29Brian Duddie    } else {
18665d679851a2c062c26f685afb450f17bce177d29Brian Duddie      notifyAppStatusChange(CHRE_EVENT_NANOAPP_STARTED, *newNanoapp);
1872de17c9c5c541d72248f8371dfb4d7e402dc93e8Andrew Rossignol    }
188e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie  }
189e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie
1902de17c9c5c541d72248f8371dfb4d7e402dc93e8Andrew Rossignol  return success;
191e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie}
192e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie
19399f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddiebool EventLoop::unloadNanoapp(uint32_t instanceId,
19499f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie                              bool allowSystemNanoappUnload) {
19599f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie  bool unloaded = false;
19699f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie
197e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie  for (size_t i = 0; i < mNanoapps.size(); i++) {
19899f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie    if (instanceId == mNanoapps[i]->getInstanceId()) {
19999f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie      if (!allowSystemNanoappUnload && mNanoapps[i]->isSystemNanoapp()) {
20099f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie        LOGE("Refusing to unload system nanoapp");
20199f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie      } else {
20299f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie        // Make sure all messages sent by this nanoapp at least have their
20399f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie        // associated free callback processing pending in the event queue (i.e.
20499f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie        // there are no messages pending delivery to the host)
20599f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie        EventLoopManagerSingleton::get()->getHostCommsManager()
20699f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie            .flushMessagesSentByNanoapp(mNanoapps[i]->getAppId());
20799f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie
20899f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie        // Distribute all inbound events we have at this time - here we're
20999f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie        // interested in handling any message free callbacks generated by
21099f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie        // flushMessagesSentByNanoapp()
21199f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie        flushInboundEventQueue();
21299f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie
21399f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie        // Mark that this nanoapp is stopping early, so it can't send events or
21499f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie        // messages during the nanoapp event queue flush
21599f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie        mStoppingNanoapp = mNanoapps[i].get();
21699f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie
21799f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie        // Process any pending events, with the intent of ensuring that we free
21899f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie        // all events generated by this nanoapp
21999f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie        flushNanoappEventQueues();
22099f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie
22165d679851a2c062c26f685afb450f17bce177d29Brian Duddie        // Post the unload event now (so we can reference the Nanoapp instance
22265d679851a2c062c26f685afb450f17bce177d29Brian Duddie        // directly), but nanoapps won't get it until after the unload completes
22365d679851a2c062c26f685afb450f17bce177d29Brian Duddie        notifyAppStatusChange(CHRE_EVENT_NANOAPP_STOPPED, *mStoppingNanoapp);
22465d679851a2c062c26f685afb450f17bce177d29Brian Duddie
22599f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie        // Finally, we are at a point where there should not be any pending
22699f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie        // events or messages sent by the app that could potentially reference
22799f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie        // the nanoapp's memory, so we are safe to unload it
22899f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie        unloadNanoappAtIndex(i);
22999f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie        mStoppingNanoapp = nullptr;
23099f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie
23199f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie        // TODO: right now we assume that the nanoapp will clean up all of its
23299f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie        // resource allocations in its nanoappEnd callback (memory, sensor
23399f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie        // subscriptions, etc.), otherwise we're leaking resources. We should
23499f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie        // perform resource cleanup automatically here to avoid these types of
23599f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie        // potential leaks.
23699f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie
23799f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie        LOGD("Unloaded nanoapp with instanceId %" PRIu32, instanceId);
23899f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie        unloaded = true;
23999f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie      }
24099f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie      break;
241e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie    }
242e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie  }
243e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie
24499f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie  return unloaded;
245e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie}
246e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie
247042f73e3b7f019c818f69b2c097c4b6f9db839b5Brian Duddiebool EventLoop::postEvent(uint16_t eventType, void *eventData,
2484927ee586656424c827920876673228fbdcf27c3Andrew Rossignol    chreEventCompleteFunction *freeCallback, uint32_t senderInstanceId,
2494927ee586656424c827920876673228fbdcf27c3Andrew Rossignol    uint32_t targetInstanceId) {
250042f73e3b7f019c818f69b2c097c4b6f9db839b5Brian Duddie  bool success = false;
2515d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie
2525d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie  if (mRunning) {
2535d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie    Event *event = mEventPool.allocate(eventType, eventData, freeCallback,
2545d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie        senderInstanceId, targetInstanceId);
2555d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie    if (event != nullptr) {
2565d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie      success = mEvents.push(event);
2575d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie    } else {
2585d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie      LOGE("Failed to allocate event");
2595d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie    }
2604927ee586656424c827920876673228fbdcf27c3Andrew Rossignol  }
2615d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie
262042f73e3b7f019c818f69b2c097c4b6f9db839b5Brian Duddie  return success;
263e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie}
264e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie
265e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddievoid EventLoop::stop() {
2664927ee586656424c827920876673228fbdcf27c3Andrew Rossignol  postEvent(0, nullptr, nullptr, kSystemInstanceId, kSystemInstanceId);
2675d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie  // Stop accepting new events and tell the main loop to finish
2686a8dd884cbc430594135c5d4801cea224f77d6e9Andrew Rossignol  mRunning = false;
269e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie}
270e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie
2712fce52a25d14fcdcba888f8ff7892dffe3f55abaBrian DuddieNanoapp *EventLoop::findNanoappByInstanceId(uint32_t instanceId) const {
2729526b7b52ed3e6cb198c649f582877acb27f1c56Andrew Rossignol  ConditionalLockGuard<Mutex> lock(mNanoappsLock, !inEventLoopThread());
273f1694b5b8abc93de4e187a78c096977ad6cf4b56Brian Duddie  return lookupAppByInstanceId(instanceId);
27430f18903edc1dfe46e12b9989760ef7a56cb31d3Andrew Rossignol}
27530f18903edc1dfe46e12b9989760ef7a56cb31d3Andrew Rossignol
27662f187d9d736346275492e916f6001576b68bb00Brian Duddiebool EventLoop::populateNanoappInfoForAppId(
27762f187d9d736346275492e916f6001576b68bb00Brian Duddie    uint64_t appId, struct chreNanoappInfo *info) const {
2789526b7b52ed3e6cb198c649f582877acb27f1c56Andrew Rossignol  ConditionalLockGuard<Mutex> lock(mNanoappsLock, !inEventLoopThread());
27962f187d9d736346275492e916f6001576b68bb00Brian Duddie  Nanoapp *app = lookupAppByAppId(appId);
28062f187d9d736346275492e916f6001576b68bb00Brian Duddie  return populateNanoappInfo(app, info);
28162f187d9d736346275492e916f6001576b68bb00Brian Duddie}
28262f187d9d736346275492e916f6001576b68bb00Brian Duddie
28362f187d9d736346275492e916f6001576b68bb00Brian Duddiebool EventLoop::populateNanoappInfoForInstanceId(
28462f187d9d736346275492e916f6001576b68bb00Brian Duddie    uint32_t instanceId, struct chreNanoappInfo *info) const {
2859526b7b52ed3e6cb198c649f582877acb27f1c56Andrew Rossignol  ConditionalLockGuard<Mutex> lock(mNanoappsLock, !inEventLoopThread());
28662f187d9d736346275492e916f6001576b68bb00Brian Duddie  Nanoapp *app = lookupAppByInstanceId(instanceId);
28762f187d9d736346275492e916f6001576b68bb00Brian Duddie  return populateNanoappInfo(app, info);
28862f187d9d736346275492e916f6001576b68bb00Brian Duddie}
28962f187d9d736346275492e916f6001576b68bb00Brian Duddie
2902fce52a25d14fcdcba888f8ff7892dffe3f55abaBrian Duddiebool EventLoop::currentNanoappIsStopping() const {
29199f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie  return (mCurrentApp == mStoppingNanoapp || !mRunning);
29299f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie}
29399f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie
294d0530f420d8bdaee755ec2834af407424de195e0Arthur Ishigurobool EventLoop::logStateToBuffer(char *buffer, size_t *bufferPos,
295d0530f420d8bdaee755ec2834af407424de195e0Arthur Ishiguro                                 size_t bufferSize) const {
296d0530f420d8bdaee755ec2834af407424de195e0Arthur Ishiguro  bool success = debugDumpPrint(buffer, bufferPos, bufferSize, "\nNanoapps:\n");
297d0530f420d8bdaee755ec2834af407424de195e0Arthur Ishiguro  for (const UniquePtr<Nanoapp>& app : mNanoapps) {
298d0530f420d8bdaee755ec2834af407424de195e0Arthur Ishiguro    success &= app->logStateToBuffer(buffer, bufferPos, bufferSize);
299d0530f420d8bdaee755ec2834af407424de195e0Arthur Ishiguro  }
30088f21c7ca23d96f6ef568a06c98f3a5c4538140fAndrew Rossignol
30188f21c7ca23d96f6ef568a06c98f3a5c4538140fAndrew Rossignol  success &= debugDumpPrint(buffer, bufferPos, bufferSize,
30288f21c7ca23d96f6ef568a06c98f3a5c4538140fAndrew Rossignol                            "\nEvent Loop:\n");
30388f21c7ca23d96f6ef568a06c98f3a5c4538140fAndrew Rossignol  success &= debugDumpPrint(buffer, bufferPos, bufferSize,
30488f21c7ca23d96f6ef568a06c98f3a5c4538140fAndrew Rossignol                            "  Max event pool usage: %zu/%zu\n",
30588f21c7ca23d96f6ef568a06c98f3a5c4538140fAndrew Rossignol                            mMaxEventPoolUsage, kMaxEventCount);
306d0530f420d8bdaee755ec2834af407424de195e0Arthur Ishiguro  return success;
307d0530f420d8bdaee755ec2834af407424de195e0Arthur Ishiguro}
308d0530f420d8bdaee755ec2834af407424de195e0Arthur Ishiguro
30999f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddiebool EventLoop::deliverEvents() {
31099f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie  bool havePendingEvents = false;
31199f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie
31299f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie  // Do one loop of round-robin. We might want to have some kind of priority or
31399f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie  // time sharing in the future, but this should be good enough for now.
31499f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie  for (const UniquePtr<Nanoapp>& app : mNanoapps) {
31599f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie    if (app->hasPendingEvent()) {
31699f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie      havePendingEvents |= deliverNextEvent(app);
31799f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie    }
3185d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie  }
319529f5218422862fdbddc1500e6ae033e8867751eBrian Duddie
32099f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie  return havePendingEvents;
3215d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie}
3225d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie
3235d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddiebool EventLoop::deliverNextEvent(const UniquePtr<Nanoapp>& app) {
3245d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie  // TODO: cleaner way to set/clear this? RAII-style?
3255d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie  mCurrentApp = app.get();
3265d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie  Event *event = app->processNextEvent();
3275d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie  mCurrentApp = nullptr;
3285d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie
3295d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie  if (event->isUnreferenced()) {
3305d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie    freeEvent(event);
3315d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie  }
3325d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie
3335d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie  return app->hasPendingEvent();
3345d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie}
3355d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie
33699f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddievoid EventLoop::distributeEvent(Event *event) {
33799f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie  for (const UniquePtr<Nanoapp>& app : mNanoapps) {
33899f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie    if ((event->targetInstanceId == chre::kBroadcastInstanceId
33999f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie            && app->isRegisteredForBroadcastEvent(event->eventType))
34099f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie        || event->targetInstanceId == app->getInstanceId()) {
34199f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie      app->postEvent(event);
34299f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie    }
34399f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie  }
34499f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie
34599f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie  if (event->isUnreferenced()) {
34699f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie    // Events sent to the system instance ID are processed via the free callback
34799f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie    // and are not expected to be delivered to any nanoapp, so no need to log a
34899f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie    // warning in that case
34999f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie    if (event->senderInstanceId != kSystemInstanceId) {
35099f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie      LOGW("Dropping event 0x%" PRIx16, event->eventType);
35199f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie    }
35299f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie    freeEvent(event);
35399f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie  }
35499f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie}
35599f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie
35699f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddievoid EventLoop::flushInboundEventQueue() {
35799f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie  while (!mEvents.empty()) {
35899f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie    distributeEvent(mEvents.pop());
35999f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie  }
36099f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie}
36199f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie
36299f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddievoid EventLoop::flushNanoappEventQueues() {
36399f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie  while (deliverEvents());
36499f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie}
36599f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie
36699f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddievoid EventLoop::freeEvent(Event *event) {
36799f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie  if (event->freeCallback != nullptr) {
36899f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie    // TODO: find a better way to set the context to the creator of the event
36999f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie    mCurrentApp = lookupAppByInstanceId(event->senderInstanceId);
37099f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie    event->freeCallback(event->eventType, event->eventData);
37199f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie    mCurrentApp = nullptr;
37299f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie  }
37399f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie
37499f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie  mEventPool.deallocate(event);
37599f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie}
37699f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddie
3772fce52a25d14fcdcba888f8ff7892dffe3f55abaBrian DuddieNanoapp *EventLoop::lookupAppByAppId(uint64_t appId) const {
37809a4783208b5ba1e14d0f0102eb31e688caca28dBrian Duddie  for (const UniquePtr<Nanoapp>& app : mNanoapps) {
37909a4783208b5ba1e14d0f0102eb31e688caca28dBrian Duddie    if (app->getAppId() == appId) {
38009a4783208b5ba1e14d0f0102eb31e688caca28dBrian Duddie      return app.get();
38109a4783208b5ba1e14d0f0102eb31e688caca28dBrian Duddie    }
38209a4783208b5ba1e14d0f0102eb31e688caca28dBrian Duddie  }
38309a4783208b5ba1e14d0f0102eb31e688caca28dBrian Duddie
38409a4783208b5ba1e14d0f0102eb31e688caca28dBrian Duddie  return nullptr;
38509a4783208b5ba1e14d0f0102eb31e688caca28dBrian Duddie}
38609a4783208b5ba1e14d0f0102eb31e688caca28dBrian Duddie
3872fce52a25d14fcdcba888f8ff7892dffe3f55abaBrian DuddieNanoapp *EventLoop::lookupAppByInstanceId(uint32_t instanceId) const {
388042f73e3b7f019c818f69b2c097c4b6f9db839b5Brian Duddie  // The system instance ID always has nullptr as its Nanoapp pointer, so can
389042f73e3b7f019c818f69b2c097c4b6f9db839b5Brian Duddie  // skip iterating through the nanoapp list for that case
390042f73e3b7f019c818f69b2c097c4b6f9db839b5Brian Duddie  if (instanceId != kSystemInstanceId) {
3915d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie    for (const UniquePtr<Nanoapp>& app : mNanoapps) {
392042f73e3b7f019c818f69b2c097c4b6f9db839b5Brian Duddie      if (app->getInstanceId() == instanceId) {
3932de17c9c5c541d72248f8371dfb4d7e402dc93e8Andrew Rossignol        return app.get();
394042f73e3b7f019c818f69b2c097c4b6f9db839b5Brian Duddie      }
395e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie    }
396e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie  }
397e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie
398e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie  return nullptr;
399e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie}
400e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie
40165d679851a2c062c26f685afb450f17bce177d29Brian Duddievoid EventLoop::notifyAppStatusChange(uint16_t eventType,
40265d679851a2c062c26f685afb450f17bce177d29Brian Duddie                                      const Nanoapp& nanoapp) {
40365d679851a2c062c26f685afb450f17bce177d29Brian Duddie  auto *info = memoryAlloc<chreNanoappInfo>();
40465d679851a2c062c26f685afb450f17bce177d29Brian Duddie  if (info == nullptr) {
40565d679851a2c062c26f685afb450f17bce177d29Brian Duddie    LOGE("Couldn't alloc app status change event");
40665d679851a2c062c26f685afb450f17bce177d29Brian Duddie  } else {
40765d679851a2c062c26f685afb450f17bce177d29Brian Duddie    info->appId      = nanoapp.getAppId();
40865d679851a2c062c26f685afb450f17bce177d29Brian Duddie    info->version    = nanoapp.getAppVersion();
40965d679851a2c062c26f685afb450f17bce177d29Brian Duddie    info->instanceId = nanoapp.getInstanceId();
41065d679851a2c062c26f685afb450f17bce177d29Brian Duddie
41150d7d95f1d8cae0e9c6202086b9bd432adff7bf1Andrew Rossignol    if (!postEvent(eventType, info, freeEventDataCallback)) {
41265d679851a2c062c26f685afb450f17bce177d29Brian Duddie      LOGE("Couldn't post app status change event");
41365d679851a2c062c26f685afb450f17bce177d29Brian Duddie      memoryFree(info);
41465d679851a2c062c26f685afb450f17bce177d29Brian Duddie    }
41565d679851a2c062c26f685afb450f17bce177d29Brian Duddie  }
41665d679851a2c062c26f685afb450f17bce177d29Brian Duddie}
41765d679851a2c062c26f685afb450f17bce177d29Brian Duddie
41899f01ac9bd6e351538cb8922ef15d9e838e7339aBrian Duddievoid EventLoop::unloadNanoappAtIndex(size_t index) {
4195d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie  const UniquePtr<Nanoapp>& nanoapp = mNanoapps[index];
420e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie
4215d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie  // Let the app know it's going away
4225d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie  mCurrentApp = nanoapp.get();
4235d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie  nanoapp->end();
4245d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie  mCurrentApp = nullptr;
4255d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie
4265d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie  // Destroy the Nanoapp instance
4275d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie  {
4285d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie    LockGuard<Mutex> lock(mNanoappsLock);
4295d9b2d68940f7dac47bf2fbad6f6069ed3b2faaaBrian Duddie    mNanoapps.erase(index);
430e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie  }
431e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie}
432e64f180233e64c40b56993cfea3696c5b4b16395Brian Duddie
4336851c47f6eecf75c66f7df0b1331b0e392201e14Andrew Rossignol}  // namespace chre
434