diff --git a/vehicle/Conn/CommConn/Android.bp b/vehicle/Conn/CommConn/Android.bp new file mode 100644 index 0000000..3eb6ca0 --- /dev/null +++ b/vehicle/Conn/CommConn/Android.bp @@ -0,0 +1,33 @@ +// Copyright (C) 2022 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. + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_library { + name: "VhalCommConn", + vendor: true, + srcs: [ + "*.cpp", + ], + shared_libs: [ + "liblog", + "libprotobuf-cpp-lite", + ], + export_include_dirs: ["include"], + static_libs: [ + "android.hardware.automotive.vehicle.intel@2.0-libproto-native", + ], +} diff --git a/vehicle/Conn/CommConn/CommConn.cpp b/vehicle/Conn/CommConn/CommConn.cpp new file mode 100644 index 0000000..7f0ddfd --- /dev/null +++ b/vehicle/Conn/CommConn/CommConn.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2018 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. + */ + +#define LOG_TAG "CommConn" + +#include + +#include + +#include "CommConn.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +void CommConn::start() { + mReadThread = std::make_unique(std::bind(&CommConn::readThread, this)); +} + +void CommConn::stop() { + if (mReadThread->joinable()) { + mReadThread->join(); + } +} + +void CommConn::sendMessage(vhal_proto::VmcuMessage const& msg) { + int numBytes = msg.ByteSize(); + std::vector buffer(static_cast(numBytes)); + if (!msg.SerializeToArray(buffer.data(), numBytes)) { + ALOGE("%s: SerializeToString failed!", __func__); + return; + } + + std::lock_guard lock(mSendMessageLock); + + write(buffer); +} + +void CommConn::readThread() { + std::vector buffer; + while (isOpen()) { + buffer = read(); + if (buffer.size() == 0) { + ALOGI("%s: Read returned empty message, exiting read loop.", __func__); + break; + } + + vhal_proto::VmcuMessage rxMsg; + if (rxMsg.ParseFromArray(buffer.data(), static_cast(buffer.size()))) { + vhal_proto::VmcuMessage respMsg; + mMessageProcessor->processMessage(rxMsg, &respMsg); + + sendMessage(respMsg); + } + } +} + +} // namespace impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/vehicle/Conn/CommConn/include/CommConn.h b/vehicle/Conn/CommConn/include/CommConn.h new file mode 100644 index 0000000..44cf02e --- /dev/null +++ b/vehicle/Conn/CommConn/include/CommConn.h @@ -0,0 +1,143 @@ +/* + * 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. + */ + +#ifndef ANDROID_EMULATORCOMMCONN_COMMCONN_H +#define ANDROID_EMULATORCOMMCONN_COMMCONN_H + +#include +#include +#include + +#include "VehicleHalProto.pb.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +/** + * MessageProcess is an interface implemented by VehicleVmcu to process messages received + * over a CommConn. + */ +class MessageProcessor { + public: + virtual ~MessageProcessor() = default; + + /** + * Process a single message received over a CommConn. Populate the given respMsg with the reply + * message we should send. + */ + virtual void processMessage(const vhal_proto::VmcuMessage& rxMsg, + vhal_proto::VmcuMessage* respMsg) = 0; +}; + +/** + * This is a pure virtual interface that could start/stop and send message. + * This is implemented by CommConn and SocketComm. + */ +class MessageSender { + public: + virtual ~MessageSender() {} + + /** + * Starts the read thread reading messages from this connection. + */ + virtual void start() = 0; + + /** + * Closes a connection if it is open. + */ + virtual void stop() = 0; + + /** + * Serializes and sends the given message to the other side. + */ + virtual void sendMessage(const vhal_proto::VmcuMessage& msg) = 0; +}; + +/** + * This is the interface that both PipeComm and SocketComm use to represent a connection. The + * connection will listen for commands on a separate 'read' thread. + */ +class CommConn : public MessageSender { + public: + CommConn(MessageProcessor* messageProcessor) : mMessageProcessor(messageProcessor) {} + + virtual ~CommConn() {} + + /** + * Start the read thread reading messages from this connection. + */ + void start() override; + + /** + * Closes a connection if it is open. + */ + void stop() override; + + /** + * Returns true if the connection is open and available to send/receive. + */ + virtual bool isOpen() = 0; + + /** + * Serialized and send the given message to the other side. + */ + void sendMessage(const vhal_proto::VmcuMessage& msg) final; + + protected: + MessageProcessor* mMessageProcessor; + + private: + std::unique_ptr mReadThread; + std::mutex mSendMessageLock; + + /** + * A thread that reads messages in a loop, and responds. You can stop this thread by calling + * stop(). + */ + void readThread(); + + /** + * Blocking call to read data from the connection. + * + * @return std::vector Serialized protobuf data received from emulator. This will be + * an empty vector if the connection was closed or some other error occurred. + */ + virtual std::vector read() = 0; + + /** + * Transmits a string of data to the emulator. + * + * @param data Serialized protobuf data to transmit. + * + * @return int Number of bytes transmitted, or -1 if failed. + */ + virtual int write(const std::vector& data) = 0; +}; + +} // namespace impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // ANDROID_EMULATORCOMMCONN_COMMCONN_H diff --git a/vehicle/Conn/PipeComm/Android.bp b/vehicle/Conn/PipeComm/Android.bp new file mode 100644 index 0000000..e8aa4b9 --- /dev/null +++ b/vehicle/Conn/PipeComm/Android.bp @@ -0,0 +1,38 @@ +// Copyright (C) 2022 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. + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_library { + name: "VhalPipeComm", + vendor: true, + srcs: [ + "*.cpp", + ], + shared_libs: [ + "libbase", + "liblog", + "libprotobuf-cpp-lite", + ], + export_include_dirs: ["include"], + static_libs: [ + "android.hardware.automotive.vehicle.intel@2.0-libproto-native", + "VhalCommConn", + ], + whole_static_libs: [ + "//device/generic/goldfish:libqemud.ranchu", + ], +} diff --git a/vehicle/Conn/PipeComm/PipeComm.cpp b/vehicle/Conn/PipeComm/PipeComm.cpp new file mode 100644 index 0000000..789cffb --- /dev/null +++ b/vehicle/Conn/PipeComm/PipeComm.cpp @@ -0,0 +1,105 @@ +/* + * 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. + */ + +#define LOG_TAG "PipeComm" + +#include + +#include "qemud.h" + +#include "PipeComm.h" + +#define CAR_SERVICE_NAME "car" + + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +PipeComm::PipeComm(MessageProcessor* messageProcessor) : CommConn(messageProcessor), mPipeFd(-1) {} + +void PipeComm::start() { + int fd = qemud_channel_open(CAR_SERVICE_NAME); + + if (fd < 0) { + ALOGE("%s: Could not open connection to service: %s %d", __FUNCTION__, strerror(errno), fd); + return; + } + + ALOGI("%s: Starting pipe connection, fd=%d", __FUNCTION__, fd); + mPipeFd = fd; + + CommConn::start(); +} + +void PipeComm::stop() { + if (mPipeFd > 0) { + ::close(mPipeFd); + mPipeFd = -1; + } + CommConn::stop(); +} + +std::vector PipeComm::read() { + static constexpr int MAX_RX_MSG_SZ = 2048; + std::vector msg = std::vector(MAX_RX_MSG_SZ); + int numBytes; + + numBytes = qemud_channel_recv(mPipeFd, msg.data(), msg.size()); + + if (numBytes == MAX_RX_MSG_SZ) { + ALOGE("%s: Received max size = %d", __FUNCTION__, MAX_RX_MSG_SZ); + } else if (numBytes > 0) { + msg.resize(numBytes); + return msg; + } else { + ALOGD("%s: Connection terminated on pipe %d, numBytes=%d", __FUNCTION__, mPipeFd, numBytes); + mPipeFd = -1; + } + + return std::vector(); +} + +int PipeComm::write(const std::vector& data) { + int retVal = 0; + + if (mPipeFd != -1) { + retVal = qemud_channel_send(mPipeFd, data.data(), data.size()); + } + + if (retVal < 0) { + retVal = -errno; + ALOGE("%s: send_cmd: (fd=%d): ERROR: %s", __FUNCTION__, mPipeFd, strerror(errno)); + } + + return retVal; +} + + +} // impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + + + diff --git a/vehicle/Conn/PipeComm/include/PipeComm.h b/vehicle/Conn/PipeComm/include/PipeComm.h new file mode 100644 index 0000000..2043ac4 --- /dev/null +++ b/vehicle/Conn/PipeComm/include/PipeComm.h @@ -0,0 +1,64 @@ +/* + * 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. + */ + +#ifndef ANDROID_EMULATORPIPECOMM_PIPECOMM_H +#define ANDROID_EMULATORPIPECOMM_PIPECOMM_H + +#include +#include + +#include "CommConn.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +/** + * PipeComm opens a qemu pipe to connect to the emulator, allowing the emulator UI to access the + * Vehicle HAL and simulate changing properties. + * + * Since the pipe is a client, it directly implements CommConn, and only one PipeComm can be open + * at a time. + */ +class PipeComm : public CommConn { + public: + PipeComm(MessageProcessor* messageProcessor); + + void start() override; + void stop() override; + + inline bool isOpen() override { return mPipeFd > 0; } + + private: + int mPipeFd; + + std::vector read() override; + int write(const std::vector& data) override; +}; + +} // namespace impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // ANDROID_EMULATORPIPECOMM_PIPECOMM_H diff --git a/vehicle/Conn/SocketComm/Android.bp b/vehicle/Conn/SocketComm/Android.bp new file mode 100644 index 0000000..43e1969 --- /dev/null +++ b/vehicle/Conn/SocketComm/Android.bp @@ -0,0 +1,34 @@ +// Copyright (C) 2022 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. + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_library { + name: "VhalSocketComm", + vendor: true, + srcs: [ + "*.cpp", + ], + shared_libs: [ + "liblog", + "libprotobuf-cpp-lite", + ], + export_include_dirs: ["include"], + static_libs: [ + "android.hardware.automotive.vehicle.intel@2.0-libproto-native", + "VhalCommConn", + ], +} diff --git a/vehicle/Conn/SocketComm/SocketComm.cpp b/vehicle/Conn/SocketComm/SocketComm.cpp new file mode 100644 index 0000000..4a0b14c --- /dev/null +++ b/vehicle/Conn/SocketComm/SocketComm.cpp @@ -0,0 +1,225 @@ +/* + * 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. + */ + +#define LOG_TAG "SocketComm" + +#include +#include +#include +#include +#include + +#include "SocketComm.h" + +// Socket to use when communicating with Host PC +static constexpr int DEBUG_SOCKET = 33452; + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +SocketComm::SocketComm(MessageProcessor* messageProcessor) + : mListenFd(-1), mMessageProcessor(messageProcessor) {} + +SocketComm::~SocketComm() { +} + +void SocketComm::start() { + if (!listen()) { + return; + } + + mListenThread = std::make_unique(std::bind(&SocketComm::listenThread, this)); +} + +void SocketComm::stop() { + if (mListenFd > 0) { + ::close(mListenFd); + if (mListenThread->joinable()) { + mListenThread->join(); + } + mListenFd = -1; + } +} + +void SocketComm::sendMessage(vhal_proto::VmcuMessage const& msg) { + std::lock_guard lock(mMutex); + for (std::unique_ptr const& conn : mOpenConnections) { + conn->sendMessage(msg); + } +} + +bool SocketComm::listen() { + int retVal; + struct sockaddr_in servAddr; + + mListenFd = socket(AF_INET, SOCK_STREAM, 0); + if (mListenFd < 0) { + ALOGE("%s: socket() failed, mSockFd=%d, errno=%d", __FUNCTION__, mListenFd, errno); + mListenFd = -1; + return false; + } + + memset(&servAddr, 0, sizeof(servAddr)); + servAddr.sin_family = AF_INET; + servAddr.sin_addr.s_addr = INADDR_ANY; + servAddr.sin_port = htons(DEBUG_SOCKET); + + retVal = bind(mListenFd, reinterpret_cast(&servAddr), sizeof(servAddr)); + if(retVal < 0) { + ALOGE("%s: Error on binding: retVal=%d, errno=%d", __FUNCTION__, retVal, errno); + close(mListenFd); + mListenFd = -1; + return false; + } + + ALOGI("%s: Listening for connections on port %d", __FUNCTION__, DEBUG_SOCKET); + if (::listen(mListenFd, 1) == -1) { + ALOGE("%s: Error on listening: errno: %d: %s", __FUNCTION__, errno, strerror(errno)); + return false; + } + return true; +} + +SocketConn* SocketComm::accept() { + sockaddr_in cliAddr; + socklen_t cliLen = sizeof(cliAddr); + int sfd = ::accept(mListenFd, reinterpret_cast(&cliAddr), &cliLen); + + if (sfd > 0) { + char addr[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &cliAddr.sin_addr, addr, INET_ADDRSTRLEN); + + ALOGD("%s: Incoming connection received from %s:%d", __FUNCTION__, addr, cliAddr.sin_port); + return new SocketConn(mMessageProcessor, sfd); + } + + return nullptr; +} + +void SocketComm::listenThread() { + while (true) { + SocketConn* conn = accept(); + if (conn == nullptr) { + return; + } + + conn->start(); + { + std::lock_guard lock(mMutex); + mOpenConnections.push_back(std::unique_ptr(conn)); + } + } +} + +/** + * Called occasionally to clean up connections that have been closed. + */ +void SocketComm::removeClosedConnections() { + std::lock_guard lock(mMutex); + std::remove_if(mOpenConnections.begin(), mOpenConnections.end(), + [](std::unique_ptr const& c) { return !c->isOpen(); }); +} + +SocketConn::SocketConn(MessageProcessor* messageProcessor, int sfd) + : CommConn(messageProcessor), mSockFd(sfd) {} + +/** + * Reads, in a loop, exactly numBytes from the given fd. If the connection is closed, returns + * an empty buffer, otherwise will return exactly the given number of bytes. + */ +std::vector readExactly(int fd, int numBytes) { + std::vector buffer(numBytes); + int totalRead = 0; + int offset = 0; + while (totalRead < numBytes) { + int numRead = ::read(fd, &buffer.data()[offset], numBytes - offset); + if (numRead == 0) { + buffer.resize(0); + return buffer; + } + + totalRead += numRead; + } + return buffer; +} + +/** + * Reads an int, guaranteed to be non-zero, from the given fd. If the connection is closed, returns + * -1. + */ +int32_t readInt(int fd) { + std::vector buffer = readExactly(fd, sizeof(int32_t)); + if (buffer.size() == 0) { + return -1; + } + + int32_t value = *reinterpret_cast(buffer.data()); + return ntohl(value); +} + +std::vector SocketConn::read() { + int32_t msgSize = readInt(mSockFd); + if (msgSize <= 0) { + ALOGD("%s: Connection terminated on socket %d", __FUNCTION__, mSockFd); + return std::vector(); + } + + return readExactly(mSockFd, msgSize); +} + +void SocketConn::stop() { + if (mSockFd > 0) { + close(mSockFd); + mSockFd = -1; + } +} + +int SocketConn::write(const std::vector& data) { + static constexpr int MSG_HEADER_LEN = 4; + int retVal = 0; + union { + uint32_t msgLen; + uint8_t msgLenBytes[MSG_HEADER_LEN]; + }; + + // Prepare header for the message + msgLen = static_cast(data.size()); + msgLen = htonl(msgLen); + + if (mSockFd > 0) { + retVal = ::write(mSockFd, msgLenBytes, MSG_HEADER_LEN); + + if (retVal == MSG_HEADER_LEN) { + retVal = ::write(mSockFd, data.data(), data.size()); + } + } + + return retVal; +} + +} // impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + diff --git a/vehicle/Conn/SocketComm/include/SocketComm.h b/vehicle/Conn/SocketComm/include/SocketComm.h new file mode 100644 index 0000000..33ec297 --- /dev/null +++ b/vehicle/Conn/SocketComm/include/SocketComm.h @@ -0,0 +1,107 @@ +/* + * 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. + */ + +#ifndef ANDROID_EMULATORSOCKETCOMM_SOCKETCOMM_H +#define ANDROID_EMULATORSOCKETCOMM_SOCKETCOMM_H + +#include +#include +#include +#include "CommConn.h" + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace V2_0 { + +namespace impl { + +class SocketConn; + +/** + * SocketComm opens a socket, and listens for connections from clients. Typically the client will be + * adb's TCP port-forwarding to enable a host PC to connect to the VehicleHAL. + */ +class SocketComm : public MessageSender { + public: + SocketComm(MessageProcessor* messageProcessor); + virtual ~SocketComm(); + + void start() override; + void stop() override ; + + /** + * Serialized and send the given message to all connected clients. + */ + void sendMessage(vhal_proto::VmcuMessage const& msg) override; + + private: + int mListenFd; + std::unique_ptr mListenThread; + std::vector> mOpenConnections; + MessageProcessor* mMessageProcessor; + std::mutex mMutex; + + /** + * Opens the socket and begins listening. + * + * @return bool Returns true on success. + */ + bool listen(); + + /** + * Blocks and waits for a connection from a client, returns a new SocketConn with the connection + * or null, if the connection has been closed. + * + * @return int Returns fd or socket number if connection is successful. + * Otherwise, returns -1 if no connection is available. + */ + SocketConn* accept(); + + void listenThread(); + + void removeClosedConnections(); +}; + +/** + * SocketConn represents a single connection to a client. + */ +class SocketConn : public CommConn { + public: + SocketConn(MessageProcessor* messageProcessor, int sfd); + virtual ~SocketConn() = default; + + void stop() override; + + inline bool isOpen() override { return mSockFd > 0; } + + private: + int mSockFd; + + std::vector read() override; + int write(const std::vector& data) override; +}; + +} // impl + +} // namespace V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // ANDROID_EMULATORSOCKETCOMM_SOCKETCOMM_H diff --git a/vehicle/aidl/Android.bp b/vehicle/aidl/Android.bp new file mode 100644 index 0000000..6c4bb19 --- /dev/null +++ b/vehicle/aidl/Android.bp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2022 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. + */ + +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_binary { + name: "android.hardware.automotive.vehicle@intel-aidl-service", + vendor: true, + defaults: [ + "FakeVehicleHardwareDefaults", + "VehicleHalDefaults", + "android-automotive-large-parcelable-defaults", + ], + vintf_fragments: ["vhal-intel-service.xml"], + init_rc: ["vhal-intel-service.rc"], + relative_install_path: "hw", + cflags: ["-DENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING"], + srcs: ["VirtVehicleService.cpp"], + static_libs: [ + "DefaultVehicleHal", + "android.hardware.automotive.vehicle.intel@aidl-default-impl-lib", + "VehicleHalUtils", + "VhalCommConn", + "VhalPipeComm", + "VhalSocketComm", + "FakeVehicleHardware", + "VehicleHalProtos", + "android.hardware.automotive.vehicle.intel@2.0-libproto-native", + "android-automotive-large-parcelable-lib", + ], + header_libs: [ + "IVehicleHardware", + ], + shared_libs: [ + "libbase", + "liblog", + "libutils", + "libprotobuf-cpp-lite", + "libbinder_ndk", + ], +} diff --git a/vehicle/aidl/VirtVehicleService.cpp b/vehicle/aidl/VirtVehicleService.cpp new file mode 100644 index 0000000..5fdb3b8 --- /dev/null +++ b/vehicle/aidl/VirtVehicleService.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2022 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. + */ + +#define LOG_TAG "VirtVehicleService" + +#include +#include + +#include +#include +#include + +using ::android::hardware::automotive::vehicle::DefaultVehicleHal; +using ::android::hardware::automotive::vehicle::fake::VirtVehicleHardware; + +int main(int /* argc */, char* /* argv */[]) { + ALOGI("Starting thread pool..."); + if (!ABinderProcess_setThreadPoolMaxThreadCount(4)) { + ALOGE("%s", "failed to set thread pool max thread count"); + return 1; + } + ABinderProcess_startThreadPool(); + + std::unique_ptr hardware = std::make_unique(); + std::shared_ptr vhal = + ::ndk::SharedRefBase::make(std::move(hardware)); + + ALOGI("Virtual Vehicle Service: Registering as service..."); + binder_exception_t err = AServiceManager_addService( + vhal->asBinder().get(), "android.hardware.automotive.vehicle.IVehicle/default"); + if (err != EX_NONE) { + ALOGE("failed to register android.hardware.automotive.vehicle service, exception: %d", err); + return 1; + } + + ALOGI("Virtual Vehicle Service Ready"); + + ABinderProcess_joinThreadPool(); + + ALOGI("Virtual Vehicle Service Exiting"); + + return 0; +} diff --git a/vehicle/aidl/impl/Android.bp b/vehicle/aidl/impl/Android.bp new file mode 100644 index 0000000..6383757 --- /dev/null +++ b/vehicle/aidl/impl/Android.bp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2022 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. + */ + +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "hardware_interfaces_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + // default_applicable_licenses: ["hardware_interfaces_license"], +} + +cc_library { + name: "android.hardware.automotive.vehicle.intel@aidl-default-impl-lib", + vendor: true, + cflags: ["-DENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING"], + srcs: ["*.cpp"], + static_libs: [ + "VehicleHalUtils", + "VhalCommConn", + "VhalPipeComm", + "VhalSocketComm", + "FakeVehicleHardware", + "VehicleHalProtos", + "android.hardware.automotive.vehicle.intel@2.0-libproto-native", + ], + shared_libs: [ + "libbase", + "liblog", + "libutils", + "libprotobuf-cpp-lite", + "libbinder_ndk", + ], + local_include_dirs: ["include"], + export_include_dirs: ["include"], + defaults: [ + "VehicleHalDefaults", + "FakeVehicleHardwareDefaults", + ], +} diff --git a/vehicle/aidl/impl/VehicleVmcu.cpp b/vehicle/aidl/impl/VehicleVmcu.cpp new file mode 100644 index 0000000..d04e119 --- /dev/null +++ b/vehicle/aidl/impl/VehicleVmcu.cpp @@ -0,0 +1,354 @@ +/* + * Copyright (C) 2022 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. + */ +#define LOG_TAG "VehicleVmcu" + +#include "VehicleVmcu.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace fake { + +using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue; +using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig; +using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus; +using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType; + +using ::android::hardware::automotive::vehicle::V2_0::impl::SocketComm; +using ::android::hardware::automotive::vehicle::V2_0::impl::PipeComm; +using ::android::hardware::automotive::vehicle::V2_0::impl::MessageSender; + +VehicleVmcu::VehicleVmcu(VirtVehicleHardware* hal) : mHal(hal) { + ALOGI("Starting SocketComm"); + mSocketComm = std::make_unique(this); + mSocketComm->start(); + + if (hal->isInQemu()) { + ALOGI("Starting PipeComm"); + mPipeComm = std::make_unique(this); + mPipeComm->start(); + } +} + +VehicleVmcu::VehicleVmcu( + std::unique_ptr socketComm, + std::unique_ptr pipeComm, + VirtVehicleHardware* hal) : mHal(hal), mSocketComm(std::move(socketComm)), + mPipeComm(std::move(pipeComm)) {}; + +VehicleVmcu::~VehicleVmcu() { + mSocketComm->stop(); + if (mPipeComm) { + mPipeComm->stop(); + } +} + +/** + * This is called by the HAL when a property changes. We need to notify our clients that it has + * changed. + */ +void VehicleVmcu::doSetValueFromClient(const VehiclePropValue& propValue) { + vhal_proto::VmcuMessage msg; + vhal_proto::VehiclePropValue* val = msg.add_value(); + populateProtoVehiclePropValue(propValue, val); + msg.set_status(vhal_proto::RESULT_OK); + msg.set_msg_type(vhal_proto::SET_PROPERTY_ASYNC); + + mSocketComm->sendMessage(msg); + if (mPipeComm) { + mPipeComm->sendMessage(msg); + } +} + +void VehicleVmcu::doGetConfig(const VehicleVmcu::VmcuMessage& rxMsg, + VehicleVmcu::VmcuMessage* respMsg) { + respMsg->set_msg_type(vhal_proto::GET_CONFIG_RESP); + + if (rxMsg.prop_size() < 1) { + ALOGE("Invalid GET_CONFIG_CMD msg, missing prop"); + respMsg->set_status(vhal_proto::ERROR_INVALID_OPERATION); + return; + } + + vhal_proto::VehiclePropGet getProp = rxMsg.prop(0); + + int32_t propId = getProp.prop(); + auto result = mHal->getPropConfig(propId); + if (!result.ok()) { + ALOGE("No config for property: %d\n", propId); + respMsg->set_status(vhal_proto::ERROR_INVALID_PROPERTY); + return; + } + + vhal_proto::VehiclePropConfig* protoCfg = respMsg->add_config(); + populateProtoVehicleConfig(*result.value(), protoCfg); + respMsg->set_status(vhal_proto::RESULT_OK); +} + +void VehicleVmcu::doGetConfigAll(const VehicleVmcu::VmcuMessage& /* rxMsg */, + VehicleVmcu::VmcuMessage* respMsg) { + respMsg->set_msg_type(vhal_proto::GET_CONFIG_ALL_RESP); + + std::vector configs = mHal->getAllPropertyConfigs(); + respMsg->set_status(vhal_proto::RESULT_OK); + + for (auto& config : configs) { + vhal_proto::VehiclePropConfig* protoCfg = respMsg->add_config(); + populateProtoVehicleConfig(config, protoCfg); + } +} + +void VehicleVmcu::doGetProperty(const VehicleVmcu::VmcuMessage& rxMsg, + VehicleVmcu::VmcuMessage* respMsg) { + respMsg->set_msg_type(vhal_proto::GET_PROPERTY_RESP); + + if (rxMsg.prop_size() < 1) { + ALOGE("Invalid GET_PROPERTY_CMD msg, missing prop"); + respMsg->set_status(vhal_proto::ERROR_INVALID_OPERATION); + return; + } + + vhal_proto::VehiclePropGet getProp = rxMsg.prop(0); + int32_t propId = getProp.prop(); + vhal_proto::Status status; + + ALOGD("get property: %d", propId); + + int32_t areaId = 0; + if (getProp.has_area_id()) { + areaId = getProp.area_id(); + } + + VehiclePropValue request = { + .areaId = areaId, + .prop = propId, + }; + auto result = mHal->getValue(request); + if (result.ok()) { + vhal_proto::VehiclePropValue* protoVal = respMsg->add_value(); + populateProtoVehiclePropValue(*result.value(), protoVal); + status = vhal_proto::RESULT_OK; + } else { + ALOGW("Failed to get value, error: %s", getErrorMsg(result).c_str()); + status = vhal_proto::ERROR_INVALID_PROPERTY; + } + + respMsg->set_status(status); +} + +void VehicleVmcu::doGetPropertyAll(const VehicleVmcu::VmcuMessage& /* rxMsg */, + VehicleVmcu::VmcuMessage* respMsg) { + respMsg->set_msg_type(vhal_proto::GET_PROPERTY_ALL_RESP); + + respMsg->set_status(vhal_proto::RESULT_OK); + + { + for (const auto& prop : mHal->getAllProperties()) { + vhal_proto::VehiclePropValue* protoVal = respMsg->add_value(); + populateProtoVehiclePropValue(*prop, protoVal); + } + } +} + +void VehicleVmcu::doSetProperty(const VehicleVmcu::VmcuMessage& rxMsg, + VehicleVmcu::VmcuMessage* respMsg) { + respMsg->set_msg_type(vhal_proto::SET_PROPERTY_RESP); + + if (rxMsg.value_size() < 1) { + ALOGE("Invalid SET_PROPERTY_CMD msg, missing value"); + respMsg->set_status(vhal_proto::ERROR_INVALID_OPERATION); + return; + } + + vhal_proto::VehiclePropValue protoVal = rxMsg.value(0); + VehiclePropValue val = { + .timestamp = elapsedRealtimeNano(), + .areaId = protoVal.area_id(), + .prop = protoVal.prop(), + .status = static_cast(protoVal.status()), + }; + + ALOGD("set property: %d", protoVal.prop()); + + // Copy value data if it is set. This automatically handles complex data types if needed. + if (protoVal.has_string_value()) { + val.value.stringValue = protoVal.string_value().c_str(); + } + + if (protoVal.has_bytes_value()) { + val.value.byteValues = std::vector { protoVal.bytes_value().begin(), + protoVal.bytes_value().end() }; + } + + if (protoVal.int32_values_size() > 0) { + val.value.int32Values = std::vector { protoVal.int32_values().begin(), + protoVal.int32_values().end() }; + } + + if (protoVal.int64_values_size() > 0) { + val.value.int64Values = std::vector { protoVal.int64_values().begin(), + protoVal.int64_values().end() }; + } + + if (protoVal.float_values_size() > 0) { + val.value.floatValues = std::vector { protoVal.float_values().begin(), + protoVal.float_values().end() }; + } + + auto result = mHal->setValue(val); + respMsg->set_status(result.ok() ? vhal_proto::RESULT_OK : vhal_proto::ERROR_INVALID_PROPERTY); +} + +void VehicleVmcu::doDebug(const vhal_proto::VmcuMessage& rxMsg, + vhal_proto::VmcuMessage* respMsg) { + respMsg->set_msg_type(vhal_proto::DEBUG_RESP); + + auto protoCommands = rxMsg.debug_commands(); + std::vector commands = std::vector( + protoCommands.begin(), protoCommands.end()); + DumpResult msg = mHal->dump(commands); + respMsg->set_status(vhal_proto::RESULT_OK); + respMsg->set_debug_result(msg.buffer); +} + +void VehicleVmcu::processMessage(const vhal_proto::VmcuMessage& rxMsg, + vhal_proto::VmcuMessage* respMsg) { + switch (rxMsg.msg_type()) { + case vhal_proto::GET_CONFIG_CMD: + doGetConfig(rxMsg, respMsg); + break; + case vhal_proto::GET_CONFIG_ALL_CMD: + doGetConfigAll(rxMsg, respMsg); + break; + case vhal_proto::GET_PROPERTY_CMD: + doGetProperty(rxMsg, respMsg); + break; + case vhal_proto::GET_PROPERTY_ALL_CMD: + doGetPropertyAll(rxMsg, respMsg); + break; + case vhal_proto::SET_PROPERTY_CMD: + doSetProperty(rxMsg, respMsg); + break; + case vhal_proto::DEBUG_CMD: + doDebug(rxMsg, respMsg); + break; + default: + ALOGW("%s: Unknown message received, type = %d", __func__, rxMsg.msg_type()); + respMsg->set_status(vhal_proto::ERROR_UNIMPLEMENTED_CMD); + break; + } +} + +void VehicleVmcu::populateProtoVehicleConfig(const VehiclePropConfig& cfg, + vhal_proto::VehiclePropConfig* protoCfg) { + protoCfg->set_prop(cfg.prop); + protoCfg->set_access(toInt(cfg.access)); + protoCfg->set_change_mode(toInt(cfg.changeMode)); + protoCfg->set_value_type(toInt(getPropType(cfg.prop))); + + for (auto& configElement : cfg.configArray) { + protoCfg->add_config_array(configElement); + } + + if (cfg.configString.size() > 0) { + protoCfg->set_config_string(cfg.configString.c_str(), cfg.configString.size()); + } + + protoCfg->clear_area_configs(); + for (auto& areaConfig : cfg.areaConfigs) { + auto* protoACfg = protoCfg->add_area_configs(); + protoACfg->set_area_id(areaConfig.areaId); + + switch (getPropType(cfg.prop)) { + case VehiclePropertyType::STRING: + case VehiclePropertyType::BOOLEAN: + case VehiclePropertyType::INT32_VEC: + case VehiclePropertyType::INT64_VEC: + case VehiclePropertyType::FLOAT_VEC: + case VehiclePropertyType::BYTES: + case VehiclePropertyType::MIXED: + // Do nothing. These types don't have min/max values + break; + case VehiclePropertyType::INT64: + protoACfg->set_min_int64_value(areaConfig.minInt64Value); + protoACfg->set_max_int64_value(areaConfig.maxInt64Value); + break; + case VehiclePropertyType::FLOAT: + protoACfg->set_min_float_value(areaConfig.minFloatValue); + protoACfg->set_max_float_value(areaConfig.maxFloatValue); + break; + case VehiclePropertyType::INT32: + protoACfg->set_min_int32_value(areaConfig.minInt32Value); + protoACfg->set_max_int32_value(areaConfig.maxInt32Value); + break; + default: + ALOGW("%s: Unknown property type: 0x%x", __func__, toInt(getPropType(cfg.prop))); + break; + } + } + + protoCfg->set_min_sample_rate(cfg.minSampleRate); + protoCfg->set_max_sample_rate(cfg.maxSampleRate); +} + +void VehicleVmcu::populateProtoVehiclePropValue(const VehiclePropValue& val, + vhal_proto::VehiclePropValue* protoVal) { + protoVal->set_prop(val.prop); + protoVal->set_value_type(toInt(getPropType(val.prop))); + protoVal->set_timestamp(val.timestamp); + protoVal->set_status(static_cast(val.status)); + protoVal->set_area_id(val.areaId); + + // Copy value data if it is set. + // - for bytes and strings, this is indicated by size > 0 + // - for int32, int64, and float, copy the values if vectors have data + if (val.value.stringValue.size() > 0) { + protoVal->set_string_value(val.value.stringValue.c_str(), val.value.stringValue.size()); + } + + if (val.value.byteValues.size() > 0) { + protoVal->set_bytes_value(val.value.byteValues.data(), val.value.byteValues.size()); + } + + for (auto& int32Value : val.value.int32Values) { + protoVal->add_int32_values(int32Value); + } + + for (auto& int64Value : val.value.int64Values) { + protoVal->add_int64_values(int64Value); + } + + for (auto& floatValue : val.value.floatValues) { + protoVal->add_float_values(floatValue); + } +} + +} // namespace fake +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android diff --git a/vehicle/aidl/impl/VirtVehicleHardware.cpp b/vehicle/aidl/impl/VirtVehicleHardware.cpp new file mode 100644 index 0000000..e3d2862 --- /dev/null +++ b/vehicle/aidl/impl/VirtVehicleHardware.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2022 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. + */ + +#define LOG_TAG "VirtVehicleHardware" + +#include "VirtVehicleHardware.h" +#include "VehicleVmcu.h" + +#include +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace fake { + +using ::aidl::android::hardware::automotive::vehicle::StatusCode; +using ::aidl::android::hardware::automotive::vehicle::SetValueRequest; +using ::aidl::android::hardware::automotive::vehicle::SetValueResult; +using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig; +using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue; +using ::aidl::android::hardware::automotive::vehicle::VehicleProperty; + +using ::android::base::Result; +using ::android::hardware::automotive::vehicle::V2_0::impl::MessageSender; + +VirtVehicleHardware::VirtVehicleHardware() { + mInQemu = isInQemu(); + ALOGD("mInQemu=%s", mInQemu ? "true" : "false"); + + mVmcu = std::make_unique(this); +} + +VirtVehicleHardware::VirtVehicleHardware( + bool inQemu, + std::unique_ptr socketComm, + std::unique_ptr pipeComm) { + mInQemu = inQemu; + mVmcu = std::make_unique(std::move(socketComm), std::move(pipeComm), this); +} + +VehicleVmcu* VirtVehicleHardware::getVmcu() { + return mVmcu.get(); +} + +VirtVehicleHardware::~VirtVehicleHardware() { + mVmcu.reset(); +} + +StatusCode VirtVehicleHardware::setValues( + std::shared_ptr callback, + const std::vector& requests) { + std::vector results; + + for (const auto& request: requests) { + const VehiclePropValue& value = request.value; + int propId = value.prop; + + ALOGD("Set value for property ID: %d", propId); + + if (mInQemu && propId == toInt(VehicleProperty::DISPLAY_BRIGHTNESS)) { + ALOGD("Return OKAY for DISPLAY_BRIGHTNESS in QEMU"); + + // Emulator does not support remote brightness control, b/139959479 + // do not send it down so that it does not bring unnecessary property change event + // return other error code, such NOT_AVAILABLE, causes Emulator to be freezing + // TODO: return StatusCode::NOT_AVAILABLE once the above issue is fixed + results.push_back({ + .requestId = request.requestId, + .status = StatusCode::OK, + }); + continue; + } + + SetValueResult setValueResult; + setValueResult.requestId = request.requestId; + + if (auto result = setValue(value); !result.ok()) { + ALOGE("failed to set value, error: %s, code: %d", getErrorMsg(result).c_str(), + getIntErrorCode(result)); + setValueResult.status = getErrorCode(result); + } else { + setValueResult.status = StatusCode::OK; + // Inform the emulator about a new value change. + mVmcu->doSetValueFromClient(value); + } + + results.push_back(std::move(setValueResult)); + } + // In real Vehicle HAL, the values would be sent to vehicle bus. But here, we just assume + // it is done and notify the client. + (*callback)(std::move(results)); + + return StatusCode::OK; +} + +std::vector VirtVehicleHardware::getAllProperties() + const { + return mServerSidePropStore->readAllValues(); +} + +VirtVehicleHardware::ConfigResultType VirtVehicleHardware::getPropConfig(int32_t propId) + const { + return mServerSidePropStore->getConfig(propId); +} + +bool VirtVehicleHardware::isInQemu() { + return android::base::GetBoolProperty("ro.boot.qemu", false); +} + +} // namespace fake +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + diff --git a/vehicle/aidl/impl/include/VehicleVmcu.h b/vehicle/aidl/impl/include/VehicleVmcu.h new file mode 100644 index 0000000..5b70616 --- /dev/null +++ b/vehicle/aidl/impl/include/VehicleVmcu.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2022 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. + */ + +#ifndef ANDROID_VEHICLEVMCU_VEHICLEVMCU_H +#define ANDROID_VEHICLEVMCU_VEHICLEVMCU_H + +#include "VirtVehicleHardware.h" + +#include +#include +#include + +#include + +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace fake { +/** + * Emulates vehicle by providing controlling interface from host side either through ADB or Pipe. + */ +class VehicleVmcu final : public V2_0::impl::MessageProcessor { + public: + explicit VehicleVmcu(VirtVehicleHardware* hal); + // For testing only. + VehicleVmcu( + std::unique_ptr socketComm, + std::unique_ptr pipeComm, + VirtVehicleHardware* mHal); + virtual ~VehicleVmcu(); + + void doSetValueFromClient(const aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue); + void processMessage(const vhal_proto::VmcuMessage& rxMsg, + vhal_proto::VmcuMessage* respMsg) override; + + private: + friend class ConnectionThread; + using VmcuMessage = vhal_proto::VmcuMessage; + + void doGetConfig(const VmcuMessage& rxMsg, VmcuMessage* respMsg); + void doGetConfigAll(const VmcuMessage& rxMsg, VmcuMessage* respMsg); + void doGetProperty(const VmcuMessage& rxMsg, VmcuMessage* respMsg); + void doGetPropertyAll(const VmcuMessage& rxMsg, VmcuMessage* respMsg); + void doSetProperty(const VmcuMessage& rxMsg, VmcuMessage* respMsg); + void doDebug(const VmcuMessage& rxMsg, VmcuMessage* respMsg); + void populateProtoVehicleConfig( + const aidl::android::hardware::automotive::vehicle::VehiclePropConfig& cfg, + vhal_proto::VehiclePropConfig* protoCfg); + void populateProtoVehiclePropValue( + const aidl::android::hardware::automotive::vehicle::VehiclePropValue& val, + vhal_proto::VehiclePropValue* protoVal); + + private: + VirtVehicleHardware* mHal; + std::unique_ptr mSocketComm; + std::unique_ptr mPipeComm; +}; + +} // namespace fake +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // ANDROID_VEHICLEVMCU_VEHICLEVMCU_H diff --git a/vehicle/aidl/impl/include/VirtVehicleHardware.h b/vehicle/aidl/impl/include/VirtVehicleHardware.h new file mode 100644 index 0000000..66261c4 --- /dev/null +++ b/vehicle/aidl/impl/include/VirtVehicleHardware.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2022 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. + */ + +#ifndef ANDROID_VEHICLEVMCU_VIRTVEHICLEHARDWARE_H +#define ANDROID_VEHICLEVMCU_VIRTVEHICLEHARDWARE_H + +#include +#include +#include + +namespace android { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace fake { + +class VehicleVmcu; +class VehicleVmcuTest; + +class VirtVehicleHardware final : public FakeVehicleHardware { + public: + using AidlVehiclePropValue = aidl::android::hardware::automotive::vehicle::VehiclePropValue; + using ConfigResultType = android::base::Result; + + VirtVehicleHardware(); + + ~VirtVehicleHardware(); + + aidl::android::hardware::automotive::vehicle::StatusCode setValues( + std::shared_ptr callback, + const std::vector& + requests) override; + + std::vector getAllProperties() const; + + ConfigResultType getPropConfig(int32_t propId) const; + + private: + friend class VehicleVmcu; + friend class VehicleVmcuTest; + + bool mInQemu; + + std::unique_ptr mVmcu; + + // determine if it's running inside Android Emulator + static bool isInQemu(); + + // For testing only. + VirtVehicleHardware( + bool inQEMU, + std::unique_ptr socketComm, + std::unique_ptr pipeComm); + + // For testing only. + VehicleVmcu* getVmcu(); +}; + +} // namespace fake +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android + +#endif // ANDROID_VEHICLEVMCU_VIRTVEHICLEHARDWARE_H diff --git a/vehicle/aidl/vhal-intel-service.rc b/vehicle/aidl/vhal-intel-service.rc new file mode 100644 index 0000000..6381338 --- /dev/null +++ b/vehicle/aidl/vhal-intel-service.rc @@ -0,0 +1,4 @@ +service vendor.vehicle-hal-aidl /vendor/bin/hw/android.hardware.automotive.vehicle@intel-aidl-service + class early_hal + user vehicle_network + group system inet \ No newline at end of file diff --git a/vehicle/aidl/vhal-intel-service.xml b/vehicle/aidl/vhal-intel-service.xml new file mode 100644 index 0000000..c0fffd3 --- /dev/null +++ b/vehicle/aidl/vhal-intel-service.xml @@ -0,0 +1,10 @@ + + + android.hardware.automotive.vehicle + 2 + + IVehicle + default + + + diff --git a/vehicle/proto/Android.bp b/vehicle/proto/Android.bp new file mode 100644 index 0000000..994bf86 --- /dev/null +++ b/vehicle/proto/Android.bp @@ -0,0 +1,75 @@ +// 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. + +// Vehicle HAL Protobuf library +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +cc_library_static { + name: "android.hardware.automotive.vehicle.intel@2.0-libproto-native", + vendor: true, + host_supported: true, + proto: { + export_proto_headers: true, + type: "lite", + }, + strip: { + keep_symbols: true, + }, + cflags: [ + "-Wall", + "-Werror", + ], + srcs: ["VehicleHalProto.proto"], +} + +filegroup { + name: "vhal-proto-src-intel", + srcs: [ + "VehicleHalProto.proto", + ], +} + +genrule { + name: "IntelDefaultVehicleHalProtoStub_h", + tools: [ + "aprotoc", + "protoc-gen-grpc-cpp-plugin", + ], + cmd: "$(location aprotoc) -I$$(dirname $(in)) -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)", + srcs: [ + "VehicleHalProto.proto", + ], + out: [ + "VehicleHalProto.pb.h", + "VehicleHalProto.grpc.pb.h", + ], +} + +genrule { + name: "IntelDefaultVehicleHalProtoStub_cc", + tools: [ + "aprotoc", + "protoc-gen-grpc-cpp-plugin", + ], + cmd: "$(location aprotoc) -I$$(dirname $(in)) -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)", + srcs: [ + "VehicleHalProto.proto", + ], + out: [ + "VehicleHalProto.pb.cc", + "VehicleHalProto.grpc.pb.cc", + ], +} diff --git a/vehicle/proto/VehicleHalProto.proto b/vehicle/proto/VehicleHalProto.proto new file mode 100644 index 0000000..1feda8e --- /dev/null +++ b/vehicle/proto/VehicleHalProto.proto @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2015 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. + */ + +syntax = "proto2"; + +package vhal_proto; + +// CMD messages are from workstation --> VHAL +// RESP messages are from VHAL --> workstation +enum MsgType { + GET_CONFIG_CMD = 0; + GET_CONFIG_RESP = 1; + GET_CONFIG_ALL_CMD = 2; + GET_CONFIG_ALL_RESP = 3; + GET_PROPERTY_CMD = 4; + GET_PROPERTY_RESP = 5; + GET_PROPERTY_ALL_CMD = 6; + GET_PROPERTY_ALL_RESP = 7; + SET_PROPERTY_CMD = 8; + SET_PROPERTY_RESP = 9; + SET_PROPERTY_ASYNC = 10; + DEBUG_CMD = 11; + DEBUG_RESP = 12; +} +enum Status { + RESULT_OK = 0; + ERROR_UNKNOWN = 1; + ERROR_UNIMPLEMENTED_CMD = 2; + ERROR_INVALID_PROPERTY = 3; + ERROR_INVALID_AREA_ID = 4; + ERROR_PROPERTY_UNINITIALIZED = 5; + ERROR_WRITE_ONLY_PROPERTY = 6; + ERROR_MEMORY_ALLOC_FAILED = 7; + ERROR_INVALID_OPERATION = 8; +} + +enum VehiclePropStatus { + AVAILABLE = 0; + UNAVAILABLE = 1; + ERROR = 2; +} + +message VehicleAreaConfig { + required int32 area_id = 1; + optional sint32 min_int32_value = 2; + optional sint32 max_int32_value = 3; + optional sint64 min_int64_value = 4; + optional sint64 max_int64_value = 5; + optional float min_float_value = 6; + optional float max_float_value = 7; +} + +message VehiclePropConfig { + required int32 prop = 1; + optional int32 access = 2; + optional int32 change_mode = 3; + optional int32 value_type = 4; + optional int32 supported_areas = 5; // Deprecated - DO NOT USE + repeated VehicleAreaConfig area_configs = 6; + optional int32 config_flags = 7; + repeated int32 config_array = 8; + optional string config_string = 9; + optional float min_sample_rate = 10; + optional float max_sample_rate = 11; +}; + +message VehiclePropValue { + // common data + required int32 prop = 1; + optional int32 value_type = 2; + optional int64 timestamp = 3; // required for valid data from HAL, skipped for set + optional VehiclePropStatus status = 10; // required for valid data from HAL, skipped for set + + // values + optional int32 area_id = 4; + repeated sint32 int32_values = 5; // this also covers boolean value. + repeated sint64 int64_values = 6; + repeated float float_values = 7; + optional string string_value = 8; + optional bytes bytes_value = 9; +}; + +// This structure is used to notify what values to get from the Vehicle HAL +message VehiclePropGet { + required int32 prop = 1; + optional int32 area_id = 2; +}; + +message VmcuMessage { + required MsgType msg_type = 1; + optional Status status = 2; // Only for RESP messages + repeated VehiclePropGet prop = 3; // Provided for getConfig, getProperty commands + repeated VehiclePropConfig config = 4; + repeated VehiclePropValue value = 5; + repeated string debug_commands = 6; // Required for debug command + optional string debug_result = 7; // Required for debug RESP messages +};