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
24using flatbuffers::FlatBufferBuilder;
25using flatbuffers::Offset;
26
27// Aliased for consistency with the way these symbols are referenced in
28// CHRE-side code
29namespace fbs = ::chre::fbs;
30
31namespace android {
32namespace chre {
33
34namespace {
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 */
44const 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
59bool 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
122void HostProtocolHost::encodeHubInfoRequest(FlatBufferBuilder& builder) {
123  auto request = fbs::CreateHubInfoRequest(builder);
124  finalize(builder, fbs::ChreMessage::HubInfoRequest, request.Union());
125}
126
127void 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
137void HostProtocolHost::encodeNanoappListRequest(FlatBufferBuilder& builder) {
138  auto request = fbs::CreateNanoappListRequest(builder);
139  finalize(builder, fbs::ChreMessage::NanoappListRequest, request.Union());
140}
141
142bool 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
158bool 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