| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #include "chre_interface.h" |
| |
| #include <android-base/logging.h> |
| |
| #include <chrono> |
| |
| #include "chre_host/host_protocol_host.h" |
| |
| using android::chre::getStringFromByteVector; |
| using android::chre::HostProtocolHost; |
| using flatbuffers::FlatBufferBuilder; |
| |
| namespace chre_constants = android::hardware::wifi::offload::V1_0::implementation::chre_constants; |
| |
| namespace fbs = ::chre::fbs; |
| |
| namespace android { |
| namespace hardware { |
| namespace wifi { |
| namespace offload { |
| namespace V1_0 { |
| namespace implementation { |
| |
| SocketCallbacks::SocketCallbacks(ChreInterface* parent) : mParent(parent) { |
| } |
| |
| void SocketCallbacks::onMessageReceived(const void* data, size_t length) { |
| LOG(VERBOSE) << "Message received from CHRE socket"; |
| if (!HostProtocolHost::decodeMessageFromChre(data, length, *this)) { |
| LOG(WARNING) << "Failed to decode message"; |
| } |
| } |
| |
| void SocketCallbacks::onConnected() { |
| LOG(INFO) << "Connected to CHRE socket"; |
| mParent->reportConnectionEvent(ChreInterfaceCallbacks::CONNECTED); |
| } |
| |
| void SocketCallbacks::onConnectionAborted() { |
| LOG(WARNING) << "Connection to CHRE socket Aborted"; |
| mParent->reportConnectionEvent(ChreInterfaceCallbacks::CONNECTION_ABORT); |
| } |
| |
| void SocketCallbacks::onDisconnected() { |
| LOG(WARNING) << "Disconnected from CHRE socket"; |
| mParent->reportConnectionEvent(ChreInterfaceCallbacks::DISCONNECTED); |
| } |
| |
| void SocketCallbacks::handleNanoappMessage(const fbs::NanoappMessageT& message) { |
| LOG(VERBOSE) << "handleNanoappMessage from appId: " << message.app_id; |
| LOG(VERBOSE) << "HostEndPoint: " << message.host_endpoint; |
| if (message.app_id == chre_constants::kWifiOffloadNanoAppId) { |
| mParent->handleMessage(message.message_type, message.message.data(), message.message.size()); |
| } |
| } |
| |
| void SocketCallbacks::handleHubInfoResponse(const fbs::HubInfoResponseT& response) { |
| LOG(VERBOSE) << "Hub Info response"; |
| LOG(VERBOSE) << "Hub Info name: " << getStringFromByteVector(response.name); |
| LOG(VERBOSE) << "Version : " << response.chre_platform_version; |
| LOG(VERBOSE) << "Legacy Platform Version: " << response.platform_version; |
| LOG(VERBOSE) << "Legacy Toolchain Version: " << response.toolchain_version; |
| LOG(VERBOSE) << "Peak Mips: " << response.peak_mips; |
| LOG(VERBOSE) << "Stopped Power: " << response.stopped_power; |
| LOG(VERBOSE) << "Sleep Power: " << response.sleep_power; |
| LOG(VERBOSE) << "Peak Power: " << response.peak_power; |
| LOG(VERBOSE) << "Platform ID: " << response.platform_id; |
| LOG(VERBOSE) << "Vendor : " << getStringFromByteVector(response.vendor); |
| LOG(VERBOSE) << "Toolchain : " << getStringFromByteVector(response.toolchain); |
| LOG(VERBOSE) << "maxMessageLen : " << response.max_msg_len; |
| if (response.max_msg_len < chre_constants::kMaxMessageLen) { |
| LOG(WARNING) << "Incorrect max message length"; |
| } |
| } |
| |
| void SocketCallbacks::handleNanoappListResponse(const fbs::NanoappListResponseT& response) { |
| LOG(VERBOSE) << "handleNanoAppListResponse"; |
| for (const std::unique_ptr<fbs::NanoappListEntryT>& nanoapp : response.nanoapps) { |
| if (nanoapp == nullptr) { |
| continue; |
| } |
| if (nanoapp->app_id == chre_constants::kWifiOffloadNanoAppId && nanoapp->enabled) { |
| LOG(INFO) << "Wifi Offload Nano app found"; |
| LOG(INFO) << "Version: " << nanoapp->version; |
| break; |
| } |
| } |
| } |
| |
| void SocketCallbacks::handleLoadNanoappResponse(const fbs::LoadNanoappResponseT& response) { |
| LOG(VERBOSE) << "Load Nano app response"; |
| LOG(VERBOSE) << "Transaction ID: " << response.transaction_id; |
| LOG(VERBOSE) << "Status: " << response.success; |
| } |
| |
| void SocketCallbacks::handleUnloadNanoappResponse(const fbs::UnloadNanoappResponseT& response) { |
| LOG(VERBOSE) << "Unload Nano app response"; |
| LOG(VERBOSE) << "Transaction ID: " << response.transaction_id; |
| LOG(VERBOSE) << "Status: " << response.success; |
| } |
| |
| ChreInterface::ChreInterface(ChreInterfaceCallbacks* callback) |
| : mSocketCallbacks(new SocketCallbacks(this)), mServerCallbacks(callback), |
| mSocketConnected(false) { |
| if (!mClient.connectInBackground(chre_constants::kSocketName, mSocketCallbacks)) { |
| LOG(ERROR) << "Offload HAL is not connected to Chre"; |
| } |
| } |
| |
| ChreInterface::~ChreInterface() { |
| mClient.disconnect(); |
| } |
| |
| bool ChreInterface::isConnected() { |
| std::lock_guard<std::mutex> lock(mChreInterfaceLock); |
| return mSocketConnected; |
| } |
| |
| void ChreInterface::reportConnectionEvent(ChreInterfaceCallbacks::ConnectionEvent event) { |
| bool connectionStatus = false; |
| switch (event) { |
| case ChreInterfaceCallbacks::ConnectionEvent::CONNECTED: |
| connectionStatus = true; |
| if (!getHubInfo() || !getNanoAppList()) { |
| LOG(WARNING) << "Unable to get platform and nano app info"; |
| } |
| break; |
| case ChreInterfaceCallbacks::ConnectionEvent::DISCONNECTED: |
| case ChreInterfaceCallbacks::ConnectionEvent::CONNECTION_ABORT: |
| break; |
| default: |
| LOG(WARNING) << "Invalid connection event recieved"; |
| return; |
| } |
| { |
| std::lock_guard<std::mutex> lock(mChreInterfaceLock); |
| mSocketConnected = connectionStatus; |
| } |
| mServerCallbacks->handleConnectionEvents(event); |
| } |
| |
| bool ChreInterface::sendCommandToApp(uint32_t messageType, const std::vector<uint8_t>& message) { |
| FlatBufferBuilder builder(chre_constants::kMaxMessageLen); |
| void* messageData = nullptr; |
| size_t messageDataLen = message.size(); |
| if (messageDataLen > 0) { |
| messageData = (void*)message.data(); |
| } |
| HostProtocolHost::encodeNanoappMessage(builder, chre_constants::kWifiOffloadNanoAppId, |
| messageType, 0, messageData, messageDataLen); |
| if (!mClient.sendMessage(builder.GetBufferPointer(), builder.GetSize())) { |
| LOG(WARNING) << "Failed to send message to Nano app"; |
| return false; |
| } |
| LOG(VERBOSE) << "Command sent " << messageType; |
| return true; |
| } |
| |
| void ChreInterface::handleMessage(uint32_t messageType, const void* messageData, |
| size_t messageDataLen) { |
| const uint8_t* messageBuf = reinterpret_cast<const uint8_t*>(messageData); |
| std::vector<uint8_t> message(messageBuf, messageBuf + messageDataLen); |
| mServerCallbacks->handleMessage(messageType, message); |
| } |
| |
| bool ChreInterface::getHubInfo() { |
| LOG(VERBOSE) << "getHubInfo"; |
| |
| FlatBufferBuilder builder(chre_constants::kHubInfoRequestBufLen); |
| HostProtocolHost::encodeHubInfoRequest(builder); |
| if (!mClient.sendMessage(builder.GetBufferPointer(), builder.GetSize())) { |
| LOG(WARNING) << "Failed to send Hub Info request"; |
| return false; |
| } |
| return true; |
| } |
| |
| bool ChreInterface::getNanoAppList() { |
| LOG(VERBOSE) << "getNanoAppList"; |
| FlatBufferBuilder builder(chre_constants::kNanoAppListRequestBufLen); |
| HostProtocolHost::encodeNanoappListRequest(builder); |
| |
| if (!mClient.sendMessage(builder.GetBufferPointer(), builder.GetSize())) { |
| LOG(WARNING) << "Unable to send Nano app List request"; |
| return false; |
| } |
| return true; |
| } |
| } // namespace implementation |
| } // namespace V1_0 |
| } // namespace offload |
| } // namespace wifi |
| } // namespace hardware |
| } // namespace android |