Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bea881c9 authored by Dean Harding's avatar Dean Harding
Browse files

Make the emulated VHAL always listen for socket connections.

Previously, when running under the emulator, it would only connect to
the emulator's qemu pipe and you couldn't script the emulated VHAL.

Also changed the logic of SocketComm so that it supports connections
from more than one client at a time.

Bug: 87643732
Test: tested locally
Change-Id: I504cd806f0a95799a68b75c3515c1f230109f1d0
(cherry picked from commit 8dad67a0148114cb60f3567268bc2cf40ff18f82)
parent e7e45745
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ cc_library_static {
    vendor: true,
    defaults: ["vhal_v2_0_defaults"],
    srcs: [
        "impl/vhal_v2_0/CommConn.cpp",
        "impl/vhal_v2_0/EmulatedVehicleHal.cpp",
        "impl/vhal_v2_0/VehicleEmulator.cpp",
        "impl/vhal_v2_0/PipeComm.cpp",
+80 −0
Original line number Diff line number Diff line
/*
 * 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 <thread>

#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
#include <log/log.h>

#include "CommConn.h"

namespace android {
namespace hardware {
namespace automotive {
namespace vehicle {
namespace V2_0 {

namespace impl {

void CommConn::start() {
    mReadThread = std::make_unique<std::thread>(std::bind(&CommConn::readThread, this));
}

void CommConn::stop() {
    if (mReadThread->joinable()) {
        mReadThread->join();
    }
}

void CommConn::sendMessage(emulator::EmulatorMessage const& msg) {
    int numBytes = msg.ByteSize();
    std::vector<uint8_t> buffer(static_cast<size_t>(numBytes));
    if (!msg.SerializeToArray(buffer.data(), numBytes)) {
        ALOGE("%s: SerializeToString failed!", __func__);
        return;
    }

    write(buffer);
}

void CommConn::readThread() {
    std::vector<uint8_t> buffer;
    while (isOpen()) {
        buffer = read();
        if (buffer.size() == 0) {
            ALOGI("%s: Read returned empty message, exiting read loop.", __func__);
            break;
        }

        emulator::EmulatorMessage rxMsg;
        if (rxMsg.ParseFromArray(buffer.data(), static_cast<int32_t>(buffer.size()))) {
            emulator::EmulatorMessage respMsg;
            mMessageProcessor->processMessage(rxMsg, respMsg);

            sendMessage(respMsg);
        }
    }
}

}  // namespace impl

}  // namespace V2_0
}  // namespace vehicle
}  // namespace automotive
}  // namespace hardware
}  // namespace android
+49 −18
Original line number Diff line number Diff line
@@ -17,9 +17,13 @@
#ifndef android_hardware_automotive_vehicle_V2_0_impl_CommBase_H_
#define android_hardware_automotive_vehicle_V2_0_impl_CommBase_H_

#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
#include <string>
#include <thread>
#include <vector>

#include "VehicleHalProto.pb.h"

namespace android {
namespace hardware {
namespace automotive {
@@ -29,32 +33,45 @@ namespace V2_0 {
namespace impl {

/**
 * This is the communications base class.  It defines the interface used in DefaultVehicleHal to
 * send and receive data to and from the emulator.
 * MessageProcess is an interface implemented by VehicleEmulator to process messages received
 * over a CommConn.
 */
class CommBase {
class MessageProcessor {
   public:
    virtual ~CommBase() = default;
    virtual ~MessageProcessor() = default;

    /**
     * Closes a connection if it is open.
     * Process a single message received over a CommConn. Populate the given respMsg with the reply
     * message we should send.
     */
    virtual void stop() {}
    virtual void processMessage(emulator::EmulatorMessage const& rxMsg,
                                emulator::EmulatorMessage& respMsg) = 0;
};

/**
     * Creates a connection to the other side.
     *
     * @return int Returns fd or socket number if connection is successful.
     *              Otherwise, returns -1 if no connection is availble.
 * 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.
 */
    virtual int connect() { return 0; }
class CommConn {
   public:
    CommConn(MessageProcessor* messageProcessor) : mMessageProcessor(messageProcessor) {}

    virtual ~CommConn() {}

    /**
     * Opens the communications channel.
     *
     * @return int Returns 0 if channel is opened, else -errno if failed.
     * Start the read thread reading messages from this connection.
     */
    virtual void start();

    /**
     * Closes a connection if it is open.
     */
    virtual int open() = 0;
    virtual void stop();

    /**
     * Returns true if the connection is open and available to send/receive.
     */
    virtual bool isOpen() = 0;

    /**
     * Blocking call to read data from the connection.
@@ -72,9 +89,24 @@ public:
     * @return int Number of bytes transmitted, or -1 if failed.
     */
    virtual int write(const std::vector<uint8_t>& data) = 0;

    /**
     * Serialized and send the given message to the other side.
     */
    void sendMessage(emulator::EmulatorMessage const& msg);

   protected:
    std::unique_ptr<std::thread> mReadThread;
    MessageProcessor* mMessageProcessor;

    /**
     * A thread that reads messages in a loop, and responds. You can stop this thread by calling
     * stop().
     */
    void readThread();
};

}  // impl
}  // namespace impl

}  // namespace V2_0
}  // namespace vehicle
@@ -82,5 +114,4 @@ public:
}  // namespace hardware
}  // namespace android


#endif  // android_hardware_automotive_vehicle_V2_0_impl_CommBase_H_
+18 −19
Original line number Diff line number Diff line
@@ -33,23 +33,28 @@ namespace V2_0 {

namespace impl {

PipeComm::PipeComm() {
    // Initialize member vars
    mPipeFd = -1;
}

PipeComm::PipeComm(MessageProcessor* messageProcessor) : CommConn(messageProcessor), mPipeFd(-1) {}

int PipeComm::open() {
void PipeComm::start() {
    int fd = qemu_pipe_open(CAR_SERVICE_NAME);

    if (fd < 0) {
        ALOGE("%s: Could not open connection to service: %s %d", __FUNCTION__, strerror(errno), fd);
        return -errno;
        return;
    }

    ALOGI("%s: OPENED PIPE, fd=%d", __FUNCTION__, fd);
    ALOGI("%s: Starting pipe connection, fd=%d", __FUNCTION__, fd);
    mPipeFd = fd;
    return 0;

    CommConn::start();
}

void PipeComm::stop() {
    if (mPipeFd > 0) {
        ::close(mPipeFd);
        mPipeFd = -1;
    }
    CommConn::stop();
}

std::vector<uint8_t> PipeComm::read() {
@@ -66,11 +71,8 @@ std::vector<uint8_t> PipeComm::read() {
        return msg;
    } else {
        ALOGD("%s: Connection terminated on pipe %d, numBytes=%d", __FUNCTION__, mPipeFd, numBytes);
        {
            std::lock_guard<std::mutex> lock(mMutex);
        mPipeFd = -1;
    }
    }

    return std::vector<uint8_t>();
}
@@ -78,12 +80,9 @@ std::vector<uint8_t> PipeComm::read() {
int PipeComm::write(const std::vector<uint8_t>& data) {
    int retVal = 0;

    {
        std::lock_guard<std::mutex> lock(mMutex);
    if (mPipeFd != -1) {
        retVal = qemu_pipe_frame_send(mPipeFd, data.data(), data.size());
    }
    }

    if (retVal < 0) {
        retVal = -errno;
+14 −27
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@

#include <mutex>
#include <vector>
#include "CommBase.h"
#include "CommConn.h"

namespace android {
namespace hardware {
@@ -30,38 +30,25 @@ namespace V2_0 {
namespace impl {

/**
 * PipeComm uses a qemu pipe interface to connect to the Goldfish Emulator.
 * 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 CommBase {
class PipeComm : public CommConn {
   public:
    PipeComm();
    PipeComm(MessageProcessor* messageProcessor);

    /**
     * Opens a pipe and begins listening.
     *
     * @return int Returns 0 on success.
     */
    int open() override;
    void start() override;
    void stop() override;

    /**
     * Blocking call to read data from the connection.
     *
     * @return std::vector<uint8_t> Serialized protobuf data received from emulator.  This will be
     *              an empty vector if the connection was closed or some other error occurred.
     */
    std::vector<uint8_t> read() override;

    /**
     * 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.
     */
    int write(const std::vector<uint8_t>& data) override;

    inline bool isOpen() override { return mPipeFd > 0; }

   private:
    std::mutex mMutex;
    int mPipeFd;
};

Loading