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 namespace {
35 
36 /**
37  * Checks that a string encapsulated as a byte vector is null-terminated, and
38  * if it is, returns a pointer to the vector's data. Otherwise returns null.
39  *
40  * @param vec Target vector, can be null
41  *
42  * @return Pointer to the vector's data, or null
43  */
getStringFromByteVector(const flatbuffers::Vector<int8_t> * vec)44 const char *getStringFromByteVector(const flatbuffers::Vector<int8_t> *vec) {
45   constexpr int8_t kNullChar = 0;
46   const char *str = nullptr;
47 
48   // Check that the vector is present, non-empty, and null-terminated
49   if (vec != nullptr && vec->size() > 0
50       && (*vec)[vec->size() - 1] == kNullChar) {
51     str = reinterpret_cast<const char *>(vec->data());
52   }
53 
54   return str;
55 }
56 
57 }  // anonymous namespace
58 
decodeMessageFromChre(const void * message,size_t messageLen,IChreMessageHandlers & handlers)59 bool HostProtocolHost::decodeMessageFromChre(
60     const void *message, size_t messageLen, IChreMessageHandlers& handlers) {
61   bool success = verifyMessage(message, messageLen);
62   if (success) {
63     const fbs::MessageContainer *container = fbs::GetMessageContainer(message);
64 
65     switch (container->message_type()) {
66       case fbs::ChreMessage::NanoappMessage: {
67         const auto *nanoappMsg = static_cast<const fbs::NanoappMessage *>(
68             container->message());
69         // Required field; verifier ensures that this is not null (though it
70         // may be empty)
71         const flatbuffers::Vector<uint8_t> *msgData = nanoappMsg->message();
72         handlers.handleNanoappMessage(
73             nanoappMsg->app_id(), nanoappMsg->message_type(),
74             nanoappMsg->host_endpoint(), msgData->data(), msgData->size());
75         break;
76       }
77 
78       case fbs::ChreMessage::HubInfoResponse: {
79         const auto *resp = static_cast<const fbs::HubInfoResponse *>(
80             container->message());
81 
82         const char *name = getStringFromByteVector(resp->name());
83         const char *vendor = getStringFromByteVector(resp->vendor());
84         const char *toolchain = getStringFromByteVector(resp->toolchain());
85 
86         handlers.handleHubInfoResponse(
87             name, vendor, toolchain, resp->platform_version(),
88             resp->toolchain_version(), resp->peak_mips(), resp->stopped_power(),
89             resp->sleep_power(), resp->peak_power(), resp->max_msg_len(),
90             resp->platform_id(), resp->chre_platform_version());
91         break;
92       }
93 
94       case fbs::ChreMessage::NanoappListResponse: {
95         const auto *resp = static_cast<const fbs::NanoappListResponse *>(
96             container->message());
97         fbs::NanoappListResponseT response;
98         resp->UnPackTo(&response);
99         handlers.handleNanoappListResponse(response);
100         break;
101       }
102 
103       case fbs::ChreMessage::LoadNanoappResponse: {
104         const auto *resp = static_cast<const fbs::LoadNanoappResponse *>(
105             container->message());
106         fbs::LoadNanoappResponseT response;
107         resp->UnPackTo(&response);
108         handlers.handleLoadNanoappResponse(response);
109         break;
110       }
111 
112       default:
113         LOGW("Got invalid/unexpected message type %" PRIu8,
114              static_cast<uint8_t>(container->message_type()));
115         success = false;
116     }
117   }
118 
119   return success;
120 }
121 
encodeHubInfoRequest(FlatBufferBuilder & builder)122 void HostProtocolHost::encodeHubInfoRequest(FlatBufferBuilder& builder) {
123   auto request = fbs::CreateHubInfoRequest(builder);
124   finalize(builder, fbs::ChreMessage::HubInfoRequest, request.Union());
125 }
126 
encodeLoadNanoappRequest(FlatBufferBuilder & builder,uint32_t transactionId,uint64_t appId,uint32_t appVersion,uint32_t targetApiVersion,const std::vector<uint8_t> & nanoappBinary)127 void HostProtocolHost::encodeLoadNanoappRequest(
128     FlatBufferBuilder& builder, uint32_t transactionId, uint64_t appId,
129     uint32_t appVersion, uint32_t targetApiVersion,
130     const std::vector<uint8_t>& nanoappBinary) {
131   auto appBinary = builder.CreateVector(nanoappBinary);
132   auto request = fbs::CreateLoadNanoappRequest(
133       builder, transactionId, appId, appVersion, targetApiVersion, appBinary);
134   finalize(builder, fbs::ChreMessage::LoadNanoappRequest, request.Union());
135 }
136 
encodeNanoappListRequest(FlatBufferBuilder & builder)137 void HostProtocolHost::encodeNanoappListRequest(FlatBufferBuilder& builder) {
138   auto request = fbs::CreateNanoappListRequest(builder);
139   finalize(builder, fbs::ChreMessage::NanoappListRequest, request.Union());
140 }
141 
extractHostClientId(const void * message,size_t messageLen,uint16_t * hostClientId)142 bool HostProtocolHost::extractHostClientId(const void *message,
143                                            size_t messageLen,
144                                            uint16_t *hostClientId) {
145   bool success = verifyMessage(message, messageLen);
146 
147   if (success && hostClientId != nullptr) {
148     const fbs::MessageContainer *container = fbs::GetMessageContainer(message);
149     // host_addr guaranteed to be non-null via verifyMessage (it's a required
150     // field)
151     *hostClientId = container->host_addr()->client_id();
152     success = true;
153   }
154 
155   return success;
156 }
157 
mutateHostClientId(void * message,size_t messageLen,uint16_t hostClientId)158 bool HostProtocolHost::mutateHostClientId(void *message, size_t messageLen,
159                                           uint16_t hostClientId) {
160   bool success = verifyMessage(message, messageLen);
161 
162   if (!success) {
163     LOGE("Message verification failed - can't mutate host ID");
164   } else {
165     fbs::MessageContainer *container = fbs::GetMutableMessageContainer(message);
166     // host_addr guaranteed to be non-null via verifyMessage (it's a required
167     // field)
168     container->mutable_host_addr()->mutate_client_id(hostClientId);
169     success = true;
170   }
171 
172   return success;
173 }
174 
175 }  // namespace chre
176 }  // namespace android
177