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

Commit 57286d9e authored by Matthew Sedam's avatar Matthew Sedam Committed by Android (Google) Code Review
Browse files

Merge "Implement Context Hub HAL v4 for Cuttlefish" into main

parents 0200aec6 92c2bd86
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ cc_library_static {
    shared_libs: [
        "libbase",
        "libbinder_ndk",
        "liblog",
        "android.hardware.contexthub-V4-ndk",
    ],
    export_include_dirs: ["include"],
@@ -51,6 +52,7 @@ cc_binary {
    shared_libs: [
        "libbase",
        "libbinder_ndk",
        "liblog",
        "android.hardware.contexthub-V4-ndk",
    ],
    static_libs: [
+235 −25
Original line number Diff line number Diff line
@@ -16,10 +16,54 @@

#include "contexthub-impl/ContextHub.h"

namespace aidl::android::hardware::contexthub {
#ifndef LOG_TAG
#define LOG_TAG "CHRE"
#endif

#include <inttypes.h>
#include <log/log.h>

using ::ndk::ScopedAStatus;

namespace aidl::android::hardware::contexthub {

namespace {

constexpr uint64_t kMockVendorHubId = 0x1234567812345678;
constexpr uint64_t kMockVendorHub2Id = 0x0EADBEEFDEADBEEF;

// Mock endpoints for the default implementation.
// These endpoints just echo back any messages sent to them.
constexpr size_t kMockEndpointCount = 4;
const EndpointInfo kMockEndpointInfos[kMockEndpointCount] = {
        {
                .id = {.hubId = kMockVendorHubId, .id = UINT64_C(0x1)},
                .type = EndpointInfo::EndpointType::GENERIC,
                .name = "Mock Endpoint 1",
                .version = 1,
        },
        {
                .id = {.hubId = kMockVendorHubId, .id = UINT64_C(0x2)},
                .type = EndpointInfo::EndpointType::GENERIC,
                .name = "Mock Endpoint 2",
                .version = 2,
        },
        {
                .id = {.hubId = kMockVendorHub2Id, .id = UINT64_C(0x1)},
                .type = EndpointInfo::EndpointType::GENERIC,
                .name = "Mock Endpoint 3",
                .version = 1,
        },
        {
                .id = {.hubId = kMockVendorHub2Id, .id = UINT64_C(0x2)},
                .type = EndpointInfo::EndpointType::GENERIC,
                .name = "Mock Endpoint 4",
                .version = 2,
        },
};

}  // anonymous namespace

ScopedAStatus ContextHub::getContextHubs(std::vector<ContextHubInfo>* out_contextHubInfos) {
    ContextHubInfo hub = {};
    hub.name = "Mock Context Hub";
@@ -112,7 +156,13 @@ ScopedAStatus ContextHub::sendMessageToHub(int32_t in_contextHubId,
    }
}

ScopedAStatus ContextHub::setTestMode(bool /* enable */) {
ScopedAStatus ContextHub::setTestMode(bool enable) {
    if (enable) {
        std::unique_lock<std::mutex> lock(mEndpointMutex);
        mEndpoints.clear();
        mEndpointSessions.clear();
        mEndpointCallback = nullptr;
    }
    return ScopedAStatus::ok();
}

@@ -137,6 +187,10 @@ ScopedAStatus ContextHub::sendMessageDeliveryStatusToHub(
}

ScopedAStatus ContextHub::getHubs(std::vector<HubInfo>* _aidl_return) {
    if (_aidl_return == nullptr) {
        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
    }

    ContextHubInfo hub = {};
    hub.name = "Mock Context Hub";
    hub.vendor = "AOSP";
@@ -158,61 +212,217 @@ ScopedAStatus ContextHub::getHubs(std::vector<HubInfo>* _aidl_return) {
    vendorHub.version = 42;

    HubInfo hubInfo2 = {};
    hubInfo2.hubId = UINT64_C(0x1234567812345678);
    hubInfo2.hubId = kMockVendorHubId;
    hubInfo2.hubDetails =
            HubInfo::HubDetails::make<HubInfo::HubDetails::Tag::vendorHubInfo>(vendorHub);

    VendorHubInfo vendorHub2 = {};
    vendorHub2.name = "Mock Vendor Hub 2";
    vendorHub2.version = 24;

    HubInfo hubInfo3 = {};
    hubInfo3.hubId = kMockVendorHub2Id;
    hubInfo3.hubDetails =
            HubInfo::HubDetails::make<HubInfo::HubDetails::Tag::vendorHubInfo>(vendorHub2);

    _aidl_return->push_back(hubInfo1);
    _aidl_return->push_back(hubInfo2);
    _aidl_return->push_back(hubInfo3);

    return ScopedAStatus::ok();
};

ScopedAStatus ContextHub::getEndpoints(std::vector<EndpointInfo>* /* _aidl_return */) {
    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
ScopedAStatus ContextHub::getEndpoints(std::vector<EndpointInfo>* _aidl_return) {
    if (_aidl_return == nullptr) {
        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
    }

    Service echoService;
    echoService.format = Service::RpcFormat::CUSTOM;
    echoService.serviceDescriptor = "ECHO";
    echoService.majorVersion = 1;
    echoService.minorVersion = 0;

    for (const EndpointInfo& endpoint : kMockEndpointInfos) {
        EndpointInfo endpointWithService(endpoint);
        endpointWithService.services.push_back(echoService);
        _aidl_return->push_back(std::move(endpointWithService));
    }

    return ScopedAStatus::ok();
};

ScopedAStatus ContextHub::registerEndpoint(const EndpointInfo& /* in_endpoint */) {
    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
ScopedAStatus ContextHub::registerEndpoint(const EndpointInfo& in_endpoint) {
    std::unique_lock<std::mutex> lock(mEndpointMutex);

    for (const EndpointInfo& endpoint : mEndpoints) {
        if ((endpoint.id.id == in_endpoint.id.id && endpoint.id.hubId == in_endpoint.id.hubId) ||
            endpoint.name == in_endpoint.name) {
            return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
        }
    }
    mEndpoints.push_back(in_endpoint);
    return ScopedAStatus::ok();
};

ScopedAStatus ContextHub::unregisterEndpoint(const EndpointInfo& /* in_endpoint */) {
    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
ScopedAStatus ContextHub::unregisterEndpoint(const EndpointInfo& in_endpoint) {
    std::unique_lock<std::mutex> lock(mEndpointMutex);

    for (auto it = mEndpoints.begin(); it != mEndpoints.end(); ++it) {
        if (it->id.id == in_endpoint.id.id && it->id.hubId == in_endpoint.id.hubId) {
            mEndpoints.erase(it);
            return ScopedAStatus::ok();
        }
    }
    return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
};

ScopedAStatus ContextHub::registerEndpointCallback(
        const std::shared_ptr<IEndpointCallback>& /* in_callback */) {
    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
        const std::shared_ptr<IEndpointCallback>& in_callback) {
    std::unique_lock<std::mutex> lock(mEndpointMutex);

    mEndpointCallback = in_callback;
    return ScopedAStatus::ok();
};

ScopedAStatus ContextHub::requestSessionIdRange(int32_t /* in_size */,
                                                std::vector<int32_t>* /* _aidl_return */) {
    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
ScopedAStatus ContextHub::requestSessionIdRange(int32_t in_size,
                                                std::vector<int32_t>* _aidl_return) {
    constexpr int32_t kMaxSize = 1024;
    if (in_size > kMaxSize || _aidl_return == nullptr) {
        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
    }

    {
        std::lock_guard<std::mutex> lock(mEndpointMutex);
        mMaxValidSessionId = in_size;
    }

    _aidl_return->push_back(0);
    _aidl_return->push_back(in_size);
    return ScopedAStatus::ok();
};

ScopedAStatus ContextHub::openEndpointSession(
        int32_t /* in_sessionId */, const EndpointId& /* in_destination */,
        const EndpointId& /* in_initiator */,
        const std::optional<std::string>& /* in_serviceDescriptor */) {
    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
        int32_t in_sessionId, const EndpointId& in_destination, const EndpointId& in_initiator,
        const std::optional<std::string>& in_serviceDescriptor) {
    // We are not calling onCloseEndpointSession on failure because the remote endpoints (our
    // mock endpoints) always accept the session.

    std::shared_ptr<IEndpointCallback> callback = nullptr;
    {
        std::unique_lock<std::mutex> lock(mEndpointMutex);
        if (in_sessionId > mMaxValidSessionId) {
            ALOGE("openEndpointSession: session ID %" PRId32 " is invalid", in_sessionId);
            return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
        }

        for (const EndpointSession& session : mEndpointSessions) {
            bool sessionAlreadyExists =
                    (session.initiator == in_destination && session.peer == in_initiator) ||
                    (session.peer == in_destination && session.initiator == in_initiator);
            if (sessionAlreadyExists) {
                ALOGD("openEndpointSession: session ID %" PRId32 " already exists", in_sessionId);
                return (session.sessionId == in_sessionId &&
                        session.serviceDescriptor == in_serviceDescriptor)
                               ? ScopedAStatus::ok()
                               : ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
            } else if (session.sessionId == in_sessionId) {
                ALOGE("openEndpointSession: session ID %" PRId32 " is invalid: endpoint mismatch",
                      in_sessionId);
                return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
            }
        }

        // Verify the initiator and destination are valid endpoints
        bool initiatorIsValid = findEndpoint(in_initiator, mEndpoints.begin(), mEndpoints.end());
        if (!initiatorIsValid) {
            ALOGE("openEndpointSession: initiator %" PRIu64 ":%" PRIu64 " is invalid",
                  in_initiator.id, in_initiator.hubId);
            return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
        }
        bool destinationIsValid = findEndpoint(in_destination, &kMockEndpointInfos[0],
                                               &kMockEndpointInfos[kMockEndpointCount]);
        if (!destinationIsValid) {
            ALOGE("openEndpointSession: destination %" PRIu64 ":%" PRIu64 " is invalid",
                  in_destination.id, in_destination.hubId);
            return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
        }

        mEndpointSessions.push_back({
                .sessionId = in_sessionId,
                .initiator = in_initiator,
                .peer = in_destination,
                .serviceDescriptor = in_serviceDescriptor,
        });

        if (mEndpointCallback != nullptr) {
            callback = mEndpointCallback;
        }
    }

    if (callback != nullptr) {
        callback->onEndpointSessionOpenComplete(in_sessionId);
    }
    return ScopedAStatus::ok();
};

ScopedAStatus ContextHub::sendMessageToEndpoint(int32_t /* in_sessionId */,
                                                const Message& /* in_msg */) {
    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
ScopedAStatus ContextHub::sendMessageToEndpoint(int32_t in_sessionId, const Message& in_msg) {
    bool foundSession = false;
    std::shared_ptr<IEndpointCallback> callback = nullptr;
    {
        std::unique_lock<std::mutex> lock(mEndpointMutex);

        for (const EndpointSession& session : mEndpointSessions) {
            if (session.sessionId == in_sessionId) {
                foundSession = true;
                break;
            }
        }

        if (mEndpointCallback != nullptr) {
            callback = mEndpointCallback;
        }
    }

    if (!foundSession) {
        ALOGE("sendMessageToEndpoint: session ID %" PRId32 " is invalid", in_sessionId);
        return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
    }

    if (callback != nullptr) {
        if (in_msg.flags & Message::FLAG_REQUIRES_DELIVERY_STATUS) {
            MessageDeliveryStatus msgStatus = {};
            msgStatus.messageSequenceNumber = in_msg.sequenceNumber;
            msgStatus.errorCode = ErrorCode::OK;
            callback->onMessageDeliveryStatusReceived(in_sessionId, msgStatus);
        }

        // Echo the message back
        callback->onMessageReceived(in_sessionId, in_msg);
    }
    return ScopedAStatus::ok();
};

ScopedAStatus ContextHub::sendMessageDeliveryStatusToEndpoint(
        int32_t /* in_sessionId */, const MessageDeliveryStatus& /* in_msgStatus */) {
    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
    return ScopedAStatus::ok();
};

ScopedAStatus ContextHub::closeEndpointSession(int32_t /* in_sessionId */, Reason /* in_reason */) {
    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
ScopedAStatus ContextHub::closeEndpointSession(int32_t in_sessionId, Reason /* in_reason */) {
    std::unique_lock<std::mutex> lock(mEndpointMutex);

    for (auto it = mEndpointSessions.begin(); it != mEndpointSessions.end(); ++it) {
        if (it->sessionId == in_sessionId) {
            mEndpointSessions.erase(it);
            return ScopedAStatus::ok();
        }
    }
    ALOGE("closeEndpointSession: session ID %" PRId32 " is invalid", in_sessionId);
    return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
};

ScopedAStatus ContextHub::endpointSessionOpenComplete(int32_t /* in_sessionId */) {
    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
    return ScopedAStatus::ok();
};

}  // namespace aidl::android::hardware::contexthub
+28 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

#include <aidl/android/hardware/contexthub/BnContextHub.h>

#include <mutex>
#include <unordered_set>
#include <vector>

@@ -72,10 +73,37 @@ class ContextHub : public BnContextHub {
    ::ndk::ScopedAStatus endpointSessionOpenComplete(int32_t in_sessionId) override;

  private:
    struct EndpointSession {
        int32_t sessionId;
        EndpointId initiator;
        EndpointId peer;
        std::optional<std::string> serviceDescriptor;
    };

    static constexpr uint32_t kMockHubId = 0;

    //! Finds an endpoint in the range defined by the endpoints
    //! @return whether the endpoint was found
    template <typename Iter>
    bool findEndpoint(const EndpointId& target, const Iter& begin, const Iter& end) {
        for (auto iter = begin; iter != end; ++iter) {
            if (iter->id.id == target.id && iter->id.hubId == target.hubId) {
                return true;
            }
        }
        return false;
    }

    std::shared_ptr<IContextHubCallback> mCallback;

    std::unordered_set<char16_t> mConnectedHostEndpoints;

    //! Endpoint storage and information
    std::mutex mEndpointMutex;
    std::vector<EndpointInfo> mEndpoints;
    std::vector<EndpointSession> mEndpointSessions;
    std::shared_ptr<IEndpointCallback> mEndpointCallback;
    int32_t mMaxValidSessionId = 0;
};

}  // namespace contexthub
+1 −1
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@ cc_test {
        "libbinder",
    ],
    static_libs: [
        "android.hardware.contexthub-V3-cpp",
        "android.hardware.contexthub-V4-cpp",
        "VtsHalContexthubUtils",
    ],
    test_suites: [
+299 −0

File changed.

Preview size limit exceeded, changes collapsed.