1 /*
2 * Copyright (C) 2022 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/event_loop_manager.h"
18 #include "chre/platform/shared/host_protocol_chre.h"
19 #include "chre/platform/shared/nanoapp_load_manager.h"
20
21 namespace chre {
22
23 NanoappLoadManager gLoadManager;
24
getLoadManager()25 inline NanoappLoadManager &getLoadManager() {
26 return gLoadManager;
27 }
28
handleDebugConfiguration(const fbs::DebugConfiguration * debugConfiguration)29 void HostMessageHandlers::handleDebugConfiguration(
30 const fbs::DebugConfiguration *debugConfiguration) {
31 EventLoopManagerSingleton::get()
32 ->getSystemHealthMonitor()
33 .setFatalErrorOnCheckFailure(
34 debugConfiguration->health_monitor_failure_crash());
35 }
36
finishLoadingNanoappCallback(SystemCallbackType,UniquePtr<LoadNanoappCallbackData> && cbData)37 void HostMessageHandlers::finishLoadingNanoappCallback(
38 SystemCallbackType /*type*/, UniquePtr<LoadNanoappCallbackData> &&cbData) {
39 constexpr size_t kInitialBufferSize = 48;
40 ChreFlatBufferBuilder builder(kInitialBufferSize);
41
42 CHRE_ASSERT(cbData != nullptr);
43
44 EventLoop &eventLoop = EventLoopManagerSingleton::get()->getEventLoop();
45 bool success = false;
46
47 if (cbData->nanoapp->isLoaded()) {
48 success = eventLoop.startNanoapp(cbData->nanoapp);
49 } else {
50 LOGE("Nanoapp is not loaded");
51 }
52
53 if (cbData->sendFragmentResponse) {
54 sendFragmentResponse(cbData->hostClientId, cbData->transactionId,
55 cbData->fragmentId, success);
56 }
57 }
58
loadNanoappData(uint16_t hostClientId,uint32_t transactionId,uint64_t appId,uint32_t appVersion,uint32_t appFlags,uint32_t targetApiVersion,const void * buffer,size_t bufferLen,uint32_t fragmentId,size_t appBinaryLen,bool respondBeforeStart)59 void HostMessageHandlers::loadNanoappData(
60 uint16_t hostClientId, uint32_t transactionId, uint64_t appId,
61 uint32_t appVersion, uint32_t appFlags, uint32_t targetApiVersion,
62 const void *buffer, size_t bufferLen, uint32_t fragmentId,
63 size_t appBinaryLen, bool respondBeforeStart) {
64 bool success = true;
65
66 if (fragmentId == 0 || fragmentId == 1) {
67 size_t totalAppBinaryLen = (fragmentId == 0) ? bufferLen : appBinaryLen;
68 LOGD("Load nanoapp request for app ID 0x%016" PRIx64 " ver 0x%" PRIx32
69 " flags 0x%" PRIx32 " target API 0x%08" PRIx32
70 " size %zu (txnId %" PRIu32 " client %" PRIu16 ")",
71 appId, appVersion, appFlags, targetApiVersion, totalAppBinaryLen,
72 transactionId, hostClientId);
73
74 if (getLoadManager().hasPendingLoadTransaction()) {
75 FragmentedLoadInfo info = getLoadManager().getTransactionInfo();
76 LOGW("A pending load transaction already exists (clientId=%" PRIu16
77 ", txnId=%" PRIu32 ", nextFragmentId=%" PRIu32 "). Overriding it",
78 info.hostClientId, info.transactionId, info.nextFragmentId);
79 // Send a failure response to host where nextFragmentId is either current
80 // or future to the host.
81 sendFragmentResponse(info.hostClientId, info.transactionId,
82 info.nextFragmentId, /* success= */ false);
83 getLoadManager().markFailure();
84 }
85
86 success = getLoadManager().prepareForLoad(
87 hostClientId, transactionId, appId, appVersion, appFlags,
88 totalAppBinaryLen, targetApiVersion);
89 }
90
91 if (success) {
92 success = getLoadManager().copyNanoappFragment(
93 hostClientId, transactionId, (fragmentId == 0) ? 1 : fragmentId, buffer,
94 bufferLen);
95 } else {
96 LOGE("Failed to prepare for load");
97 }
98
99 if (getLoadManager().isLoadComplete()) {
100 LOGD("Load manager load complete...");
101 auto cbData = MakeUnique<LoadNanoappCallbackData>();
102 if (cbData.isNull()) {
103 LOG_OOM();
104 } else {
105 cbData->transactionId = transactionId;
106 cbData->hostClientId = hostClientId;
107 cbData->appId = appId;
108 cbData->fragmentId = fragmentId;
109 cbData->nanoapp = getLoadManager().releaseNanoapp();
110 cbData->sendFragmentResponse = !respondBeforeStart;
111
112 LOGD("Instance ID %" PRIu16 " assigned to app ID 0x%" PRIx64,
113 cbData->nanoapp->getInstanceId(), appId);
114
115 // Note that if this fails, we'll generate the error response in
116 // the normal deferred callback
117 EventLoopManagerSingleton::get()->deferCallback(
118 SystemCallbackType::FinishLoadingNanoapp, std::move(cbData),
119 finishLoadingNanoappCallback);
120 if (respondBeforeStart) {
121 sendFragmentResponse(hostClientId, transactionId, fragmentId, success);
122 } // else the response will be sent in finishLoadingNanoappCallback
123 }
124 } else {
125 // send a response for this fragment
126 sendFragmentResponse(hostClientId, transactionId, fragmentId, success);
127 }
128 }
129
130 } // namespace chre
131