// Copyright 2020 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.

#pragma once

#include <memory>
#include "aemu/base/files/Stream.h"
#include "android_pipe_common.h"
#include "VmLock.h"

namespace android {

namespace base {
// Forward-declare looper here because it is only used by
// initThreadingForTest.
class Looper;
}  // namespace base

// AndroidPipe is a mostly-abstract base class for Android pipe connections.
// It's important to understand that most pipe operations (onGuestXXX methods)
// are performed with the global VM lock held.
//
// - QEMU1 runs all CPU-related operations and all timers/io events on its
//   main loop. This will be referred as the 'device thread' here.
//
// - QEMU2 has dedicated CPU threads to run guest read/write operations and
//   a different main-loop thread to run timers, check for pending host I/O.
//   It uses a global lock that is held every time virtual device operations
//   are performed. The 'device thread' is whichever CPU thread is holding
//   the lock.
//
// IMPORTANT: Most AndroidPipe methods must be called from a thread that holds
// the global VM state lock (i.e. where VmLock::isLockedBySelf() is true).
// Failure to do so will result in incorrect results, and panics in debug
// builds.
//
// A few methods can be called from any thread though, see signalWake() and
// closeFromHost().
//
// Usage is the following:
//
// 1) At emulation setup time (i.e. before the VM runs), call
//    AndroidPipe::initThreading() from the main loop thread and pass an
//    appropriate VmLock instance.
//
// 2) For each supported pipe service, create a new AndroidPipe::Service
//    instance, and register it globally by calling AndroidPipe::Service::add().
//    This can happen before 1) and in different threads.
//
// 3) Once the VM starts, whenever a guest wants to connect to a specific
//    named service, its instance's 'create' method will be called from the
//    device thread. Alternatively, when resuming from a snapshot, the 'load'
//    method will be called iff 'canLoad()' is overloaded to return true.
//
// 4) During pipe operations, onGuestXXX() methods will be called from the
//    device thread to operate on the pipe.
//
// 5) The signalWake() and closeFromHost() pipe methods can be called from
//    any thread to signal i/o events, or ask for the pipe closure.
//
class AndroidPipe {
public:
    // Call this function in the main loop thread to ensure proper threading
    // support. |vmLock| must be a valid android::VmLock instance that will be
    // used to determine whether the current thread holds the global VM
    // state lock or not (if not, operations are queued).
    static void initThreading(VmLock* vmLock);

    static void initThreadingForTest(VmLock* lock, base::Looper* looper);

    // A base class for all AndroidPipe services, which is in charge
    // of creating new instances when a guest client connects to the
    // service.
    class Service {
    public:
        // Explicit constructor.
        explicit Service(const char* name) : mName(name) {}

        // Default destructor.
        virtual ~Service() = default;

        // Return service name.
        const std::string& name() const { return mName; }

        // Create a new pipe instance. This will be called when a guest
        // client connects to the service identified by its registration
        // name (see add() below). |hwPipe| is the hardware-side
        // view of the pipe, and |args| potential arguments. Must
        // return nullptr on error.
        virtual AndroidPipe* create(void* hwPipe, const char* args,
                                    enum AndroidPipeFlags flags) = 0;

        // Called once per whole vm save/load operation.
        virtual void preLoad(android::base::Stream* stream) {}
        virtual void postLoad(android::base::Stream* stream) {}
        virtual void preSave(android::base::Stream* stream) {}
        virtual void postSave(android::base::Stream* stream) {}

        // Called for each pipe, override to save additional information.
        virtual void savePipe(AndroidPipe* pipe,
                              android::base::Stream* stream) {
            pipe->onSave(stream);
        }

        // Returns true if loading pipe instances from a stream is
        // supported. If true, the load() method will be called to load
        // every pipe instance state from the stream, if false, the
        // method will never be loaded, and the guest pipe channels will
        // be force-closed instead. The default implementation returns
        // false.
        virtual bool canLoad() const { return false; }

        // Load a pipe instance from input |stream|. Only called if
        // canLoad() returns true. Default implementation returns nullptr
        // to indicate an error loading the instance.
        virtual AndroidPipe* load(void* hwPipe,
                                  const char* args,
                                  android::base::Stream* stream) {
            return nullptr;
        }

        // Register a new |service| instance. After the call, the object
        // is owned by the global service manager, and will be destroyed
        // when resetAll() is called.
        static void add(std::unique_ptr<Service> service);

        // Reset the list of registered services. Useful at the start and
        // end of a unit-test.
        static void resetAll();

    protected:
        // No default constructor.
        Service() = delete;

        std::string mName;
    };

    // Default destructor.
    virtual ~AndroidPipe();

    // Called from the device thread to close the pipe entirely.
    // The pipe management code will never access the instance after this call,
    // which means the method is free to delete it before returning.
    virtual void onGuestClose(PipeCloseReason reason) = 0;

    // Called from the device thread to poll the pipe state. Must return a
    // combination of PIPE_POLL_IN, PIPE_POLL_OUT and PIPE_POLL_HUP.
    virtual unsigned onGuestPoll() const = 0;

    // Called from the device thread when the guest wants to receive data
    // from the pipe. |buffers| points to an array of |numBuffers| descriptors
    // that specify where to copy the data to. Return the number of bytes that
    // were actually transferred, 0 for EOF status, or a negative error
    // value otherwise, including PIPE_ERROR_AGAIN which indicates there
    // is no data yet to read.
    virtual int onGuestRecv(AndroidPipeBuffer* buffers, int numBuffers) = 0;

    // A blocking call that waits until guest is able to receive data from the pipe.
    // This can be used if a previous call to |onGuestRecv| returns PIPE_ERROR_AGAIN.
    virtual void waitGuestRecv() const {};

    // Called from the device thread when the guest wants to send data to
    // the pipe. |buffers| points to an array of |numBuffers| descriptors that
    // specify where to copy the data from. Return the number of bytes that
    // were actually transferred, 0 for EOF status, or a negative error
    // value otherwise, including PIPE_ERROR_AGAIN which indicates the pipe
    // is not ready to receive any data yet.
    virtual int onGuestSend(const AndroidPipeBuffer* buffers,
                            int numBuffers,
                            void** newPipePtr) = 0;

    // A blocking call that waits until guest is able to send data to the pipe.
    // This can be used if a previous call to |onGuestSend| returns PIPE_ERROR_AGAIN.
    virtual void waitGuestSend() const {}

    // Called from the device thread when the guest wants to indicate it
    // wants to be woken up when the set of PIPE_WAKE_XXX event bits in |flags|
    // will occur. The pipe implementation should call the wake() method to
    // signal the guest.
    virtual void onGuestWantWakeOn(int flags) = 0;

    // Called to save the pipe state to a |stream|, i.e. when saving snapshots.
    // Note that this is never called if the service's canLoad() method returns
    // false. TODO(digit): Is this always called from the device thread?
    virtual void onSave(android::base::Stream* stream){};

    // Method used to signal the guest that the events corresponding to the
    // PIPE_WAKE_XXX bits in |flags| occurred. NOTE: This can be called from
    // any thread.
    void signalWake(int flags);

    // Method used to signal the guest that the pipe instance wants to close
    // the pipe. NOTE: This can be called from any thread.
    void closeFromHost();

    // Method for canceling any pending wake() or close() that's scheduled for
    // this pipe.
    void abortPendingOperation();

    // Return the name of the AndroidPipe service.
    const char* name() const {
        return mService ? mService->name().c_str() : "<null>";
    }

    // The following functions are implementation details. They are in the
    // public scope to make the implementation of android_pipe_guest_save()
    // and android_pipe_guest_load() easier. DO NOT CALL THEM DIRECTLY.

    // Save an AndroidPipe instance state to a file |stream|.
    void saveToStream(android::base::Stream* stream);

    // Load an AndroidPipe instance from its saved state from |stream|.
    // |hwPipe| is the hardware-side view of the pipe. On success, return
    // a new instance pointer and sets |*pForceClose| to 0 or 1. A value
    // of 1 means that the guest pipe connection should be forcibly closed
    // because the implementation doesn't allow the state to be saved/loaded
    // (e.g. network pipes).
    static AndroidPipe* loadFromStream(android::base::Stream* stream,
                                       void* hwPipe,
                                       char* pForceClose);

    // A variant of loadFromStream() that is only used to support legacy
    // snapshot format for pipes. On success, sets |*pChannel|, |*pWakes| and
    // |*pClosed|, as well as |*pForceClose|. Only used by the QEMU1 virtual
    // pipe device, and will probably be removed in the future.
    static AndroidPipe* loadFromStreamLegacy(android::base::Stream* stream,
                                             void* hwPipe,
                                             uint64_t* pChannel,
                                             unsigned char* pWakes,
                                             unsigned char* pClosed,
                                             char* pForceClose);

    // Flags accessor
    void setFlags(AndroidPipeFlags flags) { mFlags = flags; }
    AndroidPipeFlags getFlags() const { return mFlags; }

protected:
    // No default constructor.
    AndroidPipe() = delete;

    // Constructor used by derived classes only.
    AndroidPipe(void* hwPipe, Service* service)
        : mHwPipe(hwPipe), mService(service) {}

    void* const mHwPipe = nullptr;
    Service* mService = nullptr;
    std::string mArgs;
    AndroidPipeFlags mFlags = ANDROID_PIPE_DEFAULT;
};

}  // namespace android
