1/*
2 * Copyright (C) 2017 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 <cinttypes>
18
19#include "chre_api/chre.h"
20#include "chre/core/event_loop.h"
21#include "chre/core/event_loop_manager.h"
22#include "chre/platform/assert.h"
23#include "chre/platform/log.h"
24#include "chre/platform/static_nanoapp_init.h"
25#include "chre/util/nanoapp/app_id.h"
26#include "chre/util/time.h"
27
28/**
29 * @file
30 * A nanoapp exclusively for testing, which unloads the spammer nanoapp after a
31 * short delay. Must only be compiled as a static/internal nanoapp.
32 */
33
34namespace chre {
35namespace {
36
37constexpr uint32_t kAppVersion = 99;
38
39void handleUnload(uint16_t /* eventType */, void * /* data */) {
40  EventLoop& eventLoop = EventLoopManagerSingleton::get()->getEventLoop();
41  uint32_t instanceId;
42
43  LOGD("About to unload spammer nanoapp");
44  if (!eventLoop.findNanoappInstanceIdByAppId(kSpammerAppId, &instanceId)) {
45    LOGE("Couldn't unload nanoapp: not found");
46  } else if (!eventLoop.unloadNanoapp(instanceId, true)) {
47    LOGE("Failed to unload nanoapp");
48  }
49}
50
51bool nanoappStart() {
52  LOGI("Unload tester started as instance %" PRIu32, chreGetInstanceId());
53
54  constexpr uint64_t kTimerDuration = Seconds(2).toRawNanoseconds();
55  uint32_t timerHandle = chreTimerSet(kTimerDuration,
56      nullptr, true /* oneShot */);
57  CHRE_ASSERT_LOG(timerHandle != CHRE_TIMER_INVALID, "Couldn't start timer!");
58
59  bool eventSent = chreSendEvent(CHRE_EVENT_FIRST_USER_VALUE, nullptr, nullptr,
60                                 chreGetInstanceId());
61  CHRE_ASSERT_LOG(eventSent, "Couldn't send event to self!");
62
63  struct chreNanoappInfo info;
64  bool gotInfo = chreGetNanoappInfoByInstanceId(chreGetInstanceId(), &info);
65  CHRE_ASSERT(gotInfo);
66  CHRE_ASSERT(info.appId == chreGetAppId());
67  CHRE_ASSERT(info.appId == kUnloadTesterAppId);
68  CHRE_ASSERT(info.version == kAppVersion);
69  CHRE_ASSERT(info.instanceId == chreGetInstanceId());
70
71  chreConfigureNanoappInfoEvents(true);
72  return true;
73}
74
75void nanoappHandleEvent(uint32_t senderInstanceId,
76                        uint16_t eventType,
77                        const void *eventData) {
78  if (eventType == CHRE_EVENT_FIRST_USER_VALUE
79      && senderInstanceId == chreGetInstanceId()) {
80    struct chreNanoappInfo info;
81    if (!chreGetNanoappInfoByAppId(kSpammerAppId, &info)) {
82      LOGW("Couldn't get spammer's app info - not running?");
83    }
84  } else if (eventType == CHRE_EVENT_TIMER) {
85    // We can't do the unload from the context of another nanoapp's handle
86    // event callback, so get into the system context
87    if (!EventLoopManagerSingleton::get()->deferCallback(
88            SystemCallbackType::HandleUnloadNanoapp, nullptr, handleUnload)) {
89      LOGE("Couldn't defer callback");
90    }
91  } else if (eventType == CHRE_EVENT_NANOAPP_STARTED
92      || eventType == CHRE_EVENT_NANOAPP_STOPPED) {
93    const auto *info = static_cast<const chreNanoappInfo *>(eventData);
94    if (info->appId == kSpammerAppId) {
95      LOGD("Received %s event for spammer instance %" PRIu32,
96           (eventType == CHRE_EVENT_NANOAPP_STARTED) ? "start" : "stop",
97           info->instanceId);
98    }
99  }
100}
101
102void nanoappEnd() {}
103
104}  // anonymous namespace
105}  // namespace chre
106
107CHRE_STATIC_NANOAPP_INIT(UnloadTester, chre::kUnloadTesterAppId, kAppVersion);
108