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#include "chre_interface.h"
17
18#include <android-base/logging.h>
19
20#include <chrono>
21
22#include "chre_host/host_protocol_host.h"
23
24using android::chre::getStringFromByteVector;
25using android::chre::HostProtocolHost;
26using flatbuffers::FlatBufferBuilder;
27
28namespace chre_constants = android::hardware::wifi::offload::V1_0::implementation::chre_constants;
29
30namespace fbs = ::chre::fbs;
31
32namespace android {
33namespace hardware {
34namespace wifi {
35namespace offload {
36namespace V1_0 {
37namespace implementation {
38
39SocketCallbacks::SocketCallbacks(ChreInterface* parent) : mParent(parent) {
40}
41
42void SocketCallbacks::onMessageReceived(const void* data, size_t length) {
43    LOG(VERBOSE) << "Message received from CHRE socket";
44    if (!HostProtocolHost::decodeMessageFromChre(data, length, *this)) {
45        LOG(WARNING) << "Failed to decode message";
46    }
47}
48
49void SocketCallbacks::onConnected() {
50    LOG(INFO) << "Connected to CHRE socket";
51    mParent->reportConnectionEvent(ChreInterfaceCallbacks::CONNECTED);
52}
53
54void SocketCallbacks::onConnectionAborted() {
55    LOG(WARNING) << "Connection to CHRE socket Aborted";
56    mParent->reportConnectionEvent(ChreInterfaceCallbacks::CONNECTION_ABORT);
57}
58
59void SocketCallbacks::onDisconnected() {
60    LOG(WARNING) << "Disconnected from CHRE socket";
61    mParent->reportConnectionEvent(ChreInterfaceCallbacks::DISCONNECTED);
62}
63
64void SocketCallbacks::handleNanoappMessage(const fbs::NanoappMessageT& message) {
65    LOG(VERBOSE) << "handleNanoappMessage from appId: " << message.app_id;
66    LOG(VERBOSE) << "HostEndPoint: " << message.host_endpoint;
67    if (message.app_id == chre_constants::kWifiOffloadNanoAppId) {
68        mParent->handleMessage(message.message_type, message.message.data(), message.message.size());
69    }
70}
71
72void SocketCallbacks::handleHubInfoResponse(const fbs::HubInfoResponseT& response) {
73    LOG(VERBOSE) << "Hub Info response";
74    LOG(VERBOSE) << "Hub Info name: " << getStringFromByteVector(response.name);
75    LOG(VERBOSE) << "Version : " << response.chre_platform_version;
76    LOG(VERBOSE) << "Legacy Platform Version: " << response.platform_version;
77    LOG(VERBOSE) << "Legacy Toolchain Version: " << response.toolchain_version;
78    LOG(VERBOSE) << "Peak Mips: " << response.peak_mips;
79    LOG(VERBOSE) << "Stopped Power: " << response.stopped_power;
80    LOG(VERBOSE) << "Sleep Power: " << response.sleep_power;
81    LOG(VERBOSE) << "Peak Power: " << response.peak_power;
82    LOG(VERBOSE) << "Platform ID: " << response.platform_id;
83    LOG(VERBOSE) << "Vendor : " << getStringFromByteVector(response.vendor);
84    LOG(VERBOSE) << "Toolchain : " << getStringFromByteVector(response.toolchain);
85    LOG(VERBOSE) << "maxMessageLen : " << response.max_msg_len;
86    if (response.max_msg_len < chre_constants::kMaxMessageLen) {
87        LOG(WARNING) << "Incorrect max message length";
88    }
89}
90
91void SocketCallbacks::handleNanoappListResponse(const fbs::NanoappListResponseT& response) {
92    LOG(VERBOSE) << "handleNanoAppListResponse";
93    for (const std::unique_ptr<fbs::NanoappListEntryT>& nanoapp : response.nanoapps) {
94        if (nanoapp == nullptr) {
95            continue;
96        }
97        if (nanoapp->app_id == chre_constants::kWifiOffloadNanoAppId && nanoapp->enabled) {
98            LOG(INFO) << "Wifi Offload Nano app found";
99            LOG(INFO) << "Version: " << nanoapp->version;
100            break;
101        }
102    }
103}
104
105void SocketCallbacks::handleLoadNanoappResponse(const fbs::LoadNanoappResponseT& response) {
106    LOG(VERBOSE) << "Load Nano app response";
107    LOG(VERBOSE) << "Transaction ID: " << response.transaction_id;
108    LOG(VERBOSE) << "Status: " << response.success;
109}
110
111void SocketCallbacks::handleUnloadNanoappResponse(const fbs::UnloadNanoappResponseT& response) {
112    LOG(VERBOSE) << "Unload Nano app response";
113    LOG(VERBOSE) << "Transaction ID: " << response.transaction_id;
114    LOG(VERBOSE) << "Status: " << response.success;
115}
116
117ChreInterface::ChreInterface(ChreInterfaceCallbacks* callback)
118    : mSocketCallbacks(new SocketCallbacks(this)), mServerCallbacks(callback),
119      mSocketConnected(false) {
120    if (!mClient.connectInBackground(chre_constants::kSocketName, mSocketCallbacks)) {
121        LOG(ERROR) << "Offload HAL is not connected to Chre";
122    }
123}
124
125ChreInterface::~ChreInterface() {
126    mClient.disconnect();
127}
128
129bool ChreInterface::isConnected() {
130    std::lock_guard<std::mutex> lock(mChreInterfaceLock);
131    return mSocketConnected;
132}
133
134void ChreInterface::reportConnectionEvent(ChreInterfaceCallbacks::ConnectionEvent event) {
135    bool connectionStatus = false;
136    switch (event) {
137        case ChreInterfaceCallbacks::ConnectionEvent::CONNECTED:
138            connectionStatus = true;
139            if (!getHubInfo() || !getNanoAppList()) {
140                LOG(WARNING) << "Unable to get platform and nano app info";
141            }
142            break;
143        case ChreInterfaceCallbacks::ConnectionEvent::DISCONNECTED:
144        case ChreInterfaceCallbacks::ConnectionEvent::CONNECTION_ABORT:
145            break;
146        default:
147            LOG(WARNING) << "Invalid connection event recieved";
148            return;
149    }
150    {
151        std::lock_guard<std::mutex> lock(mChreInterfaceLock);
152        mSocketConnected = connectionStatus;
153    }
154    mServerCallbacks->handleConnectionEvents(event);
155}
156
157bool ChreInterface::sendCommandToApp(uint32_t messageType, const std::vector<uint8_t>& message) {
158    FlatBufferBuilder builder(chre_constants::kMaxMessageLen);
159    void* messageData = nullptr;
160    size_t messageDataLen = message.size();
161    if (messageDataLen > 0) {
162        messageData = (void*)message.data();
163    }
164    HostProtocolHost::encodeNanoappMessage(builder, chre_constants::kWifiOffloadNanoAppId,
165                                           messageType, 0, messageData, messageDataLen);
166    if (!mClient.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
167        LOG(WARNING) << "Failed to send message to Nano app";
168        return false;
169    }
170    LOG(VERBOSE) << "Command sent " << messageType;
171    return true;
172}
173
174void ChreInterface::handleMessage(uint32_t messageType, const void* messageData,
175                                  size_t messageDataLen) {
176    const uint8_t* messageBuf = reinterpret_cast<const uint8_t*>(messageData);
177    std::vector<uint8_t> message(messageBuf, messageBuf + messageDataLen);
178    mServerCallbacks->handleMessage(messageType, message);
179}
180
181bool ChreInterface::getHubInfo() {
182    LOG(VERBOSE) << "getHubInfo";
183
184    FlatBufferBuilder builder(chre_constants::kHubInfoRequestBufLen);
185    HostProtocolHost::encodeHubInfoRequest(builder);
186    if (!mClient.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
187        LOG(WARNING) << "Failed to send Hub Info request";
188        return false;
189    }
190    return true;
191}
192
193bool ChreInterface::getNanoAppList() {
194    LOG(VERBOSE) << "getNanoAppList";
195    FlatBufferBuilder builder(chre_constants::kNanoAppListRequestBufLen);
196    HostProtocolHost::encodeNanoappListRequest(builder);
197
198    if (!mClient.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
199        LOG(WARNING) << "Unable to send Nano app List request";
200        return false;
201    }
202    return true;
203}
204}  // namespace implementation
205}  // namespace V1_0
206}  // namespace offload
207}  // namespace wifi
208}  // namespace hardware
209}  // namespace android
210