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 "chre/platform/shared/host_protocol_chre.h"
18 
19 #include <inttypes.h>
20 #include <string.h>
21 
22 #include "chre/platform/log.h"
23 #include "chre/platform/shared/host_messages_generated.h"
24 
25 using flatbuffers::FlatBufferBuilder;
26 using flatbuffers::Offset;
27 using flatbuffers::Vector;
28 
29 namespace chre {
30 
31 // This is similar to getStringFromByteVector in host_protocol_host.h. Ensure
32 // that method's implementation is kept in sync with this.
getStringFromByteVector(const flatbuffers::Vector<int8_t> * vec)33 const char *getStringFromByteVector(const flatbuffers::Vector<int8_t> *vec) {
34   constexpr int8_t kNullChar = static_cast<int8_t>('\0');
35   const char *str = nullptr;
36 
37   // Check that the vector is present, non-empty, and null-terminated
38   if (vec != nullptr && vec->size() > 0 && (*vec)[vec->size() - 1] == kNullChar) {
39     str = reinterpret_cast<const char *>(vec->Data());
40   }
41 
42   return str;
43 }
44 
decodeMessageFromHost(const void * message,size_t messageLen)45 bool HostProtocolChre::decodeMessageFromHost(const void *message,
46                                              size_t messageLen) {
47   bool success = verifyMessage(message, messageLen);
48   if (!success) {
49     LOGE("Dropping invalid/corrupted message from host (length %zu)",
50          messageLen);
51   } else {
52     const fbs::MessageContainer *container = fbs::GetMessageContainer(message);
53     uint16_t hostClientId = container->host_addr()->client_id();
54 
55     switch (container->message_type()) {
56       case fbs::ChreMessage::NanoappMessage: {
57         const auto *nanoappMsg = static_cast<const fbs::NanoappMessage *>(
58             container->message());
59         // Required field; verifier ensures that this is not null (though it
60         // may be empty)
61         const flatbuffers::Vector<uint8_t> *msgData = nanoappMsg->message();
62         HostMessageHandlers::handleNanoappMessage(
63             nanoappMsg->app_id(), nanoappMsg->message_type(),
64             nanoappMsg->host_endpoint(), msgData->data(), msgData->size());
65         break;
66       }
67 
68       case fbs::ChreMessage::HubInfoRequest:
69         HostMessageHandlers::handleHubInfoRequest(hostClientId);
70         break;
71 
72       case fbs::ChreMessage::NanoappListRequest:
73         HostMessageHandlers::handleNanoappListRequest(hostClientId);
74         break;
75 
76       case fbs::ChreMessage::LoadNanoappRequest: {
77         const auto *request = static_cast<const fbs::LoadNanoappRequest *>(
78             container->message());
79         const flatbuffers::Vector<uint8_t> *appBinary = request->app_binary();
80         const char *appBinaryFilename = getStringFromByteVector(
81             request->app_binary_file_name());
82         HostMessageHandlers::handleLoadNanoappRequest(
83             hostClientId, request->transaction_id(), request->app_id(),
84             request->app_version(), request->target_api_version(),
85             appBinary->data(), appBinary->size(), appBinaryFilename,
86             request->fragment_id(), request->total_app_size());
87         break;
88       }
89 
90       case fbs::ChreMessage::UnloadNanoappRequest: {
91         const auto *request = static_cast<const fbs::UnloadNanoappRequest *>(
92             container->message());
93         HostMessageHandlers::handleUnloadNanoappRequest(
94             hostClientId, request->transaction_id(), request->app_id(),
95             request->allow_system_nanoapp_unload());
96         break;
97       }
98 
99       case fbs::ChreMessage::TimeSyncMessage: {
100         const auto *request = static_cast<const fbs::TimeSyncMessage *>(
101             container->message());
102         HostMessageHandlers::handleTimeSyncMessage(request->offset());
103         break;
104       }
105 
106       case fbs::ChreMessage::DebugDumpRequest:
107         HostMessageHandlers::handleDebugDumpRequest(hostClientId);
108         break;
109 
110       default:
111         LOGW("Got invalid/unexpected message type %" PRIu8,
112              static_cast<uint8_t>(container->message_type()));
113         success = false;
114     }
115   }
116 
117   return success;
118 }
119 
encodeHubInfoResponse(FlatBufferBuilder & builder,const char * name,const char * vendor,const char * toolchain,uint32_t legacyPlatformVersion,uint32_t legacyToolchainVersion,float peakMips,float stoppedPower,float sleepPower,float peakPower,uint32_t maxMessageLen,uint64_t platformId,uint32_t version,uint16_t hostClientId)120 void HostProtocolChre::encodeHubInfoResponse(
121     FlatBufferBuilder& builder, const char *name, const char *vendor,
122     const char *toolchain, uint32_t legacyPlatformVersion,
123     uint32_t legacyToolchainVersion, float peakMips, float stoppedPower,
124     float sleepPower, float peakPower, uint32_t maxMessageLen,
125     uint64_t platformId, uint32_t version, uint16_t hostClientId) {
126   auto nameOffset = addStringAsByteVector(builder, name);
127   auto vendorOffset = addStringAsByteVector(builder, vendor);
128   auto toolchainOffset = addStringAsByteVector(builder, toolchain);
129 
130   auto response = fbs::CreateHubInfoResponse(
131       builder, nameOffset, vendorOffset, toolchainOffset, legacyPlatformVersion,
132       legacyToolchainVersion, peakMips, stoppedPower, sleepPower, peakPower,
133       maxMessageLen, platformId, version);
134   finalize(builder, fbs::ChreMessage::HubInfoResponse, response.Union(),
135            hostClientId);
136 }
137 
addNanoappListEntry(FlatBufferBuilder & builder,DynamicVector<Offset<fbs::NanoappListEntry>> & offsetVector,uint64_t appId,uint32_t appVersion,bool enabled,bool isSystemNanoapp)138 void HostProtocolChre::addNanoappListEntry(
139     FlatBufferBuilder& builder,
140     DynamicVector<Offset<fbs::NanoappListEntry>>& offsetVector,
141     uint64_t appId, uint32_t appVersion, bool enabled, bool isSystemNanoapp) {
142   auto offset = fbs::CreateNanoappListEntry(
143       builder, appId, appVersion, enabled, isSystemNanoapp);
144   if (!offsetVector.push_back(offset)) {
145     LOGE("Couldn't push nanoapp list entry offset!");
146   }
147 }
148 
finishNanoappListResponse(FlatBufferBuilder & builder,DynamicVector<Offset<fbs::NanoappListEntry>> & offsetVector,uint16_t hostClientId)149 void HostProtocolChre::finishNanoappListResponse(
150     FlatBufferBuilder& builder,
151     DynamicVector<Offset<fbs::NanoappListEntry>>& offsetVector,
152     uint16_t hostClientId) {
153   auto vectorOffset = builder.CreateVector<Offset<fbs::NanoappListEntry>>(
154       offsetVector);
155   auto response = fbs::CreateNanoappListResponse(builder, vectorOffset);
156   finalize(builder, fbs::ChreMessage::NanoappListResponse, response.Union(),
157            hostClientId);
158 }
159 
encodeLoadNanoappResponse(flatbuffers::FlatBufferBuilder & builder,uint16_t hostClientId,uint32_t transactionId,bool success,uint32_t fragmentId)160 void HostProtocolChre::encodeLoadNanoappResponse(
161     flatbuffers::FlatBufferBuilder& builder, uint16_t hostClientId,
162     uint32_t transactionId, bool success, uint32_t fragmentId) {
163   auto response = fbs::CreateLoadNanoappResponse(builder, transactionId,
164                                                  success, fragmentId);
165   finalize(builder, fbs::ChreMessage::LoadNanoappResponse, response.Union(),
166            hostClientId);
167 }
168 
encodeUnloadNanoappResponse(flatbuffers::FlatBufferBuilder & builder,uint16_t hostClientId,uint32_t transactionId,bool success)169 void HostProtocolChre::encodeUnloadNanoappResponse(
170     flatbuffers::FlatBufferBuilder& builder, uint16_t hostClientId,
171     uint32_t transactionId, bool success) {
172   auto response = fbs::CreateUnloadNanoappResponse(builder, transactionId,
173                                                    success);
174   finalize(builder, fbs::ChreMessage::UnloadNanoappResponse, response.Union(),
175            hostClientId);
176 }
177 
encodeLogMessages(flatbuffers::FlatBufferBuilder & builder,const char * logBuffer,size_t bufferSize)178 void HostProtocolChre::encodeLogMessages(
179     flatbuffers::FlatBufferBuilder& builder, const char *logBuffer,
180     size_t bufferSize) {
181   auto logBufferOffset = builder.CreateVector(
182       reinterpret_cast<const int8_t *>(logBuffer), bufferSize);
183   auto message = fbs::CreateLogMessage(builder, logBufferOffset);
184   finalize(builder, fbs::ChreMessage::LogMessage, message.Union());
185 }
186 
encodeDebugDumpData(flatbuffers::FlatBufferBuilder & builder,uint16_t hostClientId,const char * debugStr,size_t debugStrSize)187 void HostProtocolChre::encodeDebugDumpData(
188     flatbuffers::FlatBufferBuilder& builder, uint16_t hostClientId,
189     const char *debugStr, size_t debugStrSize) {
190   auto debugStrOffset = builder.CreateVector(
191       reinterpret_cast<const int8_t *>(debugStr), debugStrSize);
192   auto message = fbs::CreateDebugDumpData(builder, debugStrOffset);
193   finalize(builder, fbs::ChreMessage::DebugDumpData, message.Union(),
194            hostClientId);
195 }
196 
encodeDebugDumpResponse(flatbuffers::FlatBufferBuilder & builder,uint16_t hostClientId,bool success,uint32_t dataCount)197 void HostProtocolChre::encodeDebugDumpResponse(
198       flatbuffers::FlatBufferBuilder& builder, uint16_t hostClientId,
199       bool success, uint32_t dataCount) {
200   auto response = fbs::CreateDebugDumpResponse(builder, success, dataCount);
201   finalize(builder, fbs::ChreMessage::DebugDumpResponse, response.Union(),
202            hostClientId);
203 }
204 
encodeTimeSyncRequest(flatbuffers::FlatBufferBuilder & builder)205 void HostProtocolChre::encodeTimeSyncRequest(
206     flatbuffers::FlatBufferBuilder& builder) {
207   auto request = fbs::CreateTimeSyncRequest(builder);
208   finalize(builder, fbs::ChreMessage::TimeSyncRequest, request.Union());
209 }
210 
encodeLowPowerMicAccessRequest(flatbuffers::FlatBufferBuilder & builder)211 void HostProtocolChre::encodeLowPowerMicAccessRequest(
212     flatbuffers::FlatBufferBuilder& builder) {
213   auto request = fbs::CreateLowPowerMicAccessRequest(builder);
214   finalize(builder, fbs::ChreMessage::LowPowerMicAccessRequest,
215            request.Union());
216 }
217 
encodeLowPowerMicAccessRelease(flatbuffers::FlatBufferBuilder & builder)218 void HostProtocolChre::encodeLowPowerMicAccessRelease(
219     flatbuffers::FlatBufferBuilder& builder) {
220   auto request = fbs::CreateLowPowerMicAccessRelease(builder);
221   finalize(builder, fbs::ChreMessage::LowPowerMicAccessRelease,
222            request.Union());
223 }
224 
225 }  // namespace chre
226