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_host/host_protocol_host.h"
18 
19 #include <inttypes.h>
20 #include <string.h>
21 
22 #include "chre_host/log.h"
23 
24 using flatbuffers::FlatBufferBuilder;
25 using flatbuffers::Offset;
26 
27 // Aliased for consistency with the way these symbols are referenced in
28 // CHRE-side code
29 namespace fbs = ::chre::fbs;
30 
31 namespace android {
32 namespace chre {
33 
34 // This is similar to getStringFromByteVector in host_protocol_chre.h. Ensure
35 // that method's implementation is kept in sync with this.
getStringFromByteVector(const std::vector<int8_t> & vec)36 const char *getStringFromByteVector(const std::vector<int8_t>& vec) {
37   constexpr int8_t kNullChar = static_cast<int8_t>('\0');
38   const char *str = nullptr;
39 
40   // Check that the vector is present, non-empty, and null-terminated
41   if (vec.size() > 0 && vec[vec.size() - 1] == kNullChar) {
42     str = reinterpret_cast<const char *>(vec.data());
43   }
44 
45   return str;
46 }
47 
decodeMessageFromChre(const void * message,size_t messageLen,IChreMessageHandlers & handlers)48 bool HostProtocolHost::decodeMessageFromChre(
49     const void *message, size_t messageLen, IChreMessageHandlers& handlers) {
50   bool success = verifyMessage(message, messageLen);
51   if (success) {
52     std::unique_ptr<fbs::MessageContainerT> container =
53         fbs::UnPackMessageContainer(message);
54     fbs::ChreMessageUnion& msg = container->message;
55 
56     switch (container->message.type) {
57       case fbs::ChreMessage::NanoappMessage:
58         handlers.handleNanoappMessage(*msg.AsNanoappMessage());
59         break;
60 
61       case fbs::ChreMessage::HubInfoResponse:
62         handlers.handleHubInfoResponse(*msg.AsHubInfoResponse());
63         break;
64 
65       case fbs::ChreMessage::NanoappListResponse:
66         handlers.handleNanoappListResponse(*msg.AsNanoappListResponse());
67         break;
68 
69       case fbs::ChreMessage::LoadNanoappResponse:
70         handlers.handleLoadNanoappResponse(*msg.AsLoadNanoappResponse());
71         break;
72 
73       case fbs::ChreMessage::UnloadNanoappResponse:
74         handlers.handleUnloadNanoappResponse(*msg.AsUnloadNanoappResponse());
75         break;
76 
77       case fbs::ChreMessage::DebugDumpData:
78         handlers.handleDebugDumpData(*msg.AsDebugDumpData());
79         break;
80 
81       case fbs::ChreMessage::DebugDumpResponse:
82         handlers.handleDebugDumpResponse(*msg.AsDebugDumpResponse());
83         break;
84 
85       default:
86         LOGW("Got invalid/unexpected message type %" PRIu8,
87              static_cast<uint8_t>(msg.type));
88         success = false;
89     }
90   }
91 
92   return success;
93 }
94 
encodeHubInfoRequest(FlatBufferBuilder & builder)95 void HostProtocolHost::encodeHubInfoRequest(FlatBufferBuilder& builder) {
96   auto request = fbs::CreateHubInfoRequest(builder);
97   finalize(builder, fbs::ChreMessage::HubInfoRequest, request.Union());
98 }
99 
encodeFragmentedLoadNanoappRequest(flatbuffers::FlatBufferBuilder & builder,const FragmentedLoadRequest & request)100 void HostProtocolHost::encodeFragmentedLoadNanoappRequest(
101     flatbuffers::FlatBufferBuilder& builder,
102     const FragmentedLoadRequest& request) {
103   encodeLoadNanoappRequestForBinary(
104       builder, request.transactionId, request.appId, request.appVersion,
105       request.targetApiVersion, request.binary, request.fragmentId,
106       request.appTotalSizeBytes);
107 }
108 
encodeNanoappListRequest(FlatBufferBuilder & builder)109 void HostProtocolHost::encodeNanoappListRequest(FlatBufferBuilder& builder) {
110   auto request = fbs::CreateNanoappListRequest(builder);
111   finalize(builder, fbs::ChreMessage::NanoappListRequest, request.Union());
112 }
113 
encodeUnloadNanoappRequest(FlatBufferBuilder & builder,uint32_t transactionId,uint64_t appId,bool allowSystemNanoappUnload)114 void HostProtocolHost::encodeUnloadNanoappRequest(
115     FlatBufferBuilder& builder, uint32_t transactionId, uint64_t appId,
116     bool allowSystemNanoappUnload) {
117   auto request = fbs::CreateUnloadNanoappRequest(
118       builder, transactionId, appId, allowSystemNanoappUnload);
119   finalize(builder, fbs::ChreMessage::UnloadNanoappRequest, request.Union());
120 }
121 
encodeTimeSyncMessage(FlatBufferBuilder & builder,int64_t offset)122 void HostProtocolHost::encodeTimeSyncMessage(FlatBufferBuilder& builder,
123                                              int64_t offset) {
124   auto request = fbs::CreateTimeSyncMessage(builder, offset);
125   finalize(builder, fbs::ChreMessage::TimeSyncMessage, request.Union());
126 }
127 
encodeDebugDumpRequest(FlatBufferBuilder & builder)128 void HostProtocolHost::encodeDebugDumpRequest(FlatBufferBuilder& builder) {
129   auto request = fbs::CreateDebugDumpRequest(builder);
130   finalize(builder, fbs::ChreMessage::DebugDumpRequest, request.Union());
131 }
132 
extractHostClientIdAndType(const void * message,size_t messageLen,uint16_t * hostClientId,::chre::fbs::ChreMessage * messageType)133 bool HostProtocolHost::extractHostClientIdAndType(
134     const void *message, size_t messageLen, uint16_t *hostClientId,
135     ::chre::fbs::ChreMessage *messageType) {
136   bool success = false;
137   if (hostClientId != nullptr && messageType != nullptr) {
138     success = verifyMessage(message, messageLen);
139 
140     if (success) {
141       const fbs::MessageContainer *container = fbs::GetMessageContainer(message);
142       // host_addr guaranteed to be non-null via verifyMessage (it's a required
143       // field)
144       *hostClientId = container->host_addr()->client_id();
145       *messageType = container->message_type();
146     }
147   }
148 
149   return success;
150 }
151 
mutateHostClientId(void * message,size_t messageLen,uint16_t hostClientId)152 bool HostProtocolHost::mutateHostClientId(void *message, size_t messageLen,
153                                           uint16_t hostClientId) {
154   bool success = verifyMessage(message, messageLen);
155 
156   if (!success) {
157     LOGE("Message verification failed - can't mutate host ID");
158   } else {
159     fbs::MessageContainer *container = fbs::GetMutableMessageContainer(message);
160     // host_addr guaranteed to be non-null via verifyMessage (it's a required
161     // field)
162     container->mutable_host_addr()->mutate_client_id(hostClientId);
163     success = true;
164   }
165 
166   return success;
167 }
168 
encodeLoadNanoappRequestForBinary(FlatBufferBuilder & builder,uint32_t transactionId,uint64_t appId,uint32_t appVersion,uint32_t targetApiVersion,const std::vector<uint8_t> & nanoappBinary,uint32_t fragmentId,size_t appTotalSizeBytes)169 void HostProtocolHost::encodeLoadNanoappRequestForBinary(
170     FlatBufferBuilder& builder, uint32_t transactionId, uint64_t appId,
171     uint32_t appVersion, uint32_t targetApiVersion,
172     const std::vector<uint8_t>& nanoappBinary, uint32_t fragmentId,
173     size_t appTotalSizeBytes) {
174   auto appBinary = builder.CreateVector(nanoappBinary);
175   auto request = fbs::CreateLoadNanoappRequest(
176       builder, transactionId, appId, appVersion, targetApiVersion, appBinary,
177       fragmentId, appTotalSizeBytes);
178   finalize(builder, fbs::ChreMessage::LoadNanoappRequest, request.Union());
179 }
180 
encodeLoadNanoappRequestForFile(flatbuffers::FlatBufferBuilder & builder,uint32_t transactionId,uint64_t appId,uint32_t appVersion,uint32_t targetApiVersion,const char * nanoappBinaryName)181 void HostProtocolHost::encodeLoadNanoappRequestForFile(
182       flatbuffers::FlatBufferBuilder& builder, uint32_t transactionId,
183       uint64_t appId, uint32_t appVersion, uint32_t targetApiVersion,
184       const char *nanoappBinaryName) {
185   const std::vector<uint8_t> emptyAppBinary;
186   auto appBinary = builder.CreateVector(emptyAppBinary);
187   auto appBinaryName = addStringAsByteVector(builder, nanoappBinaryName);
188   auto request = fbs::CreateLoadNanoappRequest(
189       builder, transactionId, appId, appVersion, targetApiVersion, appBinary,
190       0 /* fragmentId */, 0 /* appTotalSizeBytes */, appBinaryName);
191   finalize(builder, fbs::ChreMessage::LoadNanoappRequest, request.Union());
192 }
193 
194 }  // namespace chre
195 }  // namespace android
196