blob: 76261dffd5f5dd233daca77f51bb4cc9eda6caef [file]
// This code is taken from
// src/aosp/frameworks/native/libs/binder/ndk/include_cpp/android/
//
// This file provides the pieces of the Binder framework
// that are referenced from within the generated AIDL code.
//
// Changes have been made to enable compilation within ChromeOS,
// look for 'NNAPI_CHROMEOS'. ScopedAStatus is also heavily
// modified.
//
// This is done to avoid making changes to the generated
// AIDL code so that we can easily reproduce that code
// if necessary.
/*
* 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.
*/
/**
* @addtogroup NdkBinder
* @{
*/
/**
* @file binder_auto_utils.h
* @brief These objects provide a more C++-like thin interface to the binder.
*/
#pragma once
#include <android/binder_ibinder.h>
#include <android/binder_parcel.h>
#include <android/binder_status.h>
#include <utils/Errors.h>
#include <assert.h>
#include <unistd.h>
#include <cstddef>
#include <string>
namespace ndk {
/**
* Represents one strong pointer to an AIBinder object.
*/
class SpAIBinder {
public:
/**
* Default constructor.
*/
SpAIBinder() : mBinder(nullptr) {}
/**
* Takes ownership of one strong refcount of binder.
*/
explicit SpAIBinder(AIBinder* binder) : mBinder(binder) {}
/**
* Convenience operator for implicitly constructing an SpAIBinder from nullptr. This is not
* explicit because it is not taking ownership of anything.
*/
SpAIBinder(std::nullptr_t) : SpAIBinder() {} // NOLINT(google-explicit-constructor)
/**
* This will delete the underlying object if it exists. See operator=.
*/
SpAIBinder(const SpAIBinder& other) { *this = other; }
/**
* This deletes the underlying object if it exists. See set.
*/
~SpAIBinder() { set(nullptr); }
/**
* This takes ownership of a binder from another AIBinder object but it does not affect the
* ownership of that other object.
*/
SpAIBinder& operator=(const SpAIBinder& other) {
if (this == &other) {
return *this;
}
AIBinder_incStrong(other.mBinder);
set(other.mBinder);
return *this;
}
/**
* Takes ownership of one strong refcount of binder
*/
void set(AIBinder*) {
#if !defined(NNAPI_CHROMEOS)
AIBinder* old = *const_cast<AIBinder* volatile*>(&mBinder);
if (old != nullptr) AIBinder_decStrong(old);
if (old != *const_cast<AIBinder* volatile*>(&mBinder)) {
__assert(__FILE__, __LINE__, "Race detected.");
}
mBinder = binder;
#endif // NNAPI_CHROMEOS (removing binder references)
}
/**
* This returns the underlying binder object for transactions. If it is used to create another
* SpAIBinder object, it should first be incremented.
*/
AIBinder* get() const { return mBinder; }
/**
* This allows the value in this class to be set from beneath it. If you call this method and
* then change the value of T*, you must take ownership of the value you are replacing and add
* ownership to the object that is put in here.
*
* Recommended use is like this:
* SpAIBinder a; // will be nullptr
* SomeInitFunction(a.getR()); // value is initialized with refcount
*
* Other usecases are discouraged.
*
*/
AIBinder** getR() { return &mBinder; }
bool operator!=(const SpAIBinder& rhs) const { return get() != rhs.get(); }
bool operator<(const SpAIBinder& rhs) const { return get() < rhs.get(); }
bool operator<=(const SpAIBinder& rhs) const { return get() <= rhs.get(); }
bool operator==(const SpAIBinder& rhs) const { return get() == rhs.get(); }
bool operator>(const SpAIBinder& rhs) const { return get() > rhs.get(); }
bool operator>=(const SpAIBinder& rhs) const { return get() >= rhs.get(); }
private:
AIBinder* mBinder = nullptr;
};
namespace impl {
/**
* This baseclass owns a single object, used to make various classes RAII.
*/
template <typename T, void (*Destroy)(T), T DEFAULT>
class ScopedAResource {
public:
/**
* Takes ownership of t.
*/
explicit ScopedAResource(T t = DEFAULT) : mT(t) {}
/**
* This deletes the underlying object if it exists. See set.
*/
~ScopedAResource() { set(DEFAULT); }
/**
* Takes ownership of t.
*/
void set(T t) {
Destroy(mT);
mT = t;
}
/**
* This returns the underlying object to be modified but does not affect ownership.
*/
T get() { return mT; }
/**
* This returns the const underlying object but does not affect ownership.
*/
const T get() const { return mT; }
/**
* Release the underlying resource.
*/
[[nodiscard]] T release() {
T a = mT;
mT = DEFAULT;
return a;
}
/**
* This allows the value in this class to be set from beneath it. If you call this method and
* then change the value of T*, you must take ownership of the value you are replacing and add
* ownership to the object that is put in here.
*
* Recommended use is like this:
* ScopedAResource<T> a; // will be nullptr
* SomeInitFunction(a.getR()); // value is initialized with refcount
*
* Other usecases are discouraged.
*
*/
T* getR() { return &mT; }
// copy-constructing/assignment is disallowed
ScopedAResource(const ScopedAResource&) = delete;
ScopedAResource& operator=(const ScopedAResource&) = delete;
// move-constructing/assignment is okay
ScopedAResource(ScopedAResource&& other) noexcept : mT(std::move(other.mT)) {
other.mT = DEFAULT;
}
ScopedAResource& operator=(ScopedAResource&& other) noexcept {
set(other.mT);
other.mT = DEFAULT;
return *this;
}
private:
T mT;
};
} // namespace impl
/**
* Convenience wrapper. See AParcel.
*/
class ScopedAParcel : public impl::ScopedAResource<AParcel*, AParcel_delete, nullptr> {
public:
/**
* Takes ownership of a.
*/
explicit ScopedAParcel(AParcel* a = nullptr) : ScopedAResource(a) {}
~ScopedAParcel() {}
ScopedAParcel(ScopedAParcel&&) = default;
ScopedAParcel& operator=(ScopedAParcel&&) = default;
bool operator!=(const ScopedAParcel& rhs) const { return get() != rhs.get(); }
bool operator<(const ScopedAParcel& rhs) const { return get() < rhs.get(); }
bool operator<=(const ScopedAParcel& rhs) const { return get() <= rhs.get(); }
bool operator==(const ScopedAParcel& rhs) const { return get() == rhs.get(); }
bool operator>(const ScopedAParcel& rhs) const { return get() > rhs.get(); }
bool operator>=(const ScopedAParcel& rhs) const { return get() >= rhs.get(); }
};
// Heavily modified to not use the binder status interface
class ScopedAStatus {
public:
ScopedAStatus(binder_exception_t exceptionCode, int32_t errorCode)
: exception_(exceptionCode), error_code_(errorCode) {}
ScopedAStatus(AStatus*) {}
ScopedAStatus() = default;
~ScopedAStatus() {}
ScopedAStatus(ScopedAStatus&&) = default;
ScopedAStatus& operator=(ScopedAStatus&&) = default;
AStatus* get() { return nullptr; }
AStatus** getR() { return nullptr; }
void set(AStatus *) { }
bool isOk() const { return exception_ == EX_NONE; }
binder_exception_t getExceptionCode() const { return exception_; }
int32_t getServiceSpecificError() const {
return exception_ == EX_SERVICE_SPECIFIC ? error_code_ : android::OK;
}
binder_status_t getStatus() const {
return exception_ == EX_TRANSACTION_FAILED ? error_code_ : STATUS_OK;
}
const char* getMessage() const { return ""; }
std::string getDescription() const { return ""; }
/**
* Convenience methods for creating scoped statuses.
*/
static ScopedAStatus ok() { return ScopedAStatus(); }
static ScopedAStatus fromExceptionCode(binder_exception_t exception) {
if (exception == EX_TRANSACTION_FAILED) {
return ScopedAStatus(exception, STATUS_FAILED_TRANSACTION);
}
return ScopedAStatus(exception, android::OK);
}
static ScopedAStatus fromExceptionCodeWithMessage(binder_exception_t exception,
const char* /*message*/) {
return fromExceptionCode(exception);
}
static ScopedAStatus fromServiceSpecificError(int32_t serviceSpecific) {
return ScopedAStatus(EX_SERVICE_SPECIFIC, serviceSpecific);
}
static ScopedAStatus fromServiceSpecificErrorWithMessage(int32_t serviceSpecific,
const char* /*message*/) {
return fromServiceSpecificError(serviceSpecific);
}
static ScopedAStatus fromStatus(binder_status_t status) {
ScopedAStatus ret;
ret.exception_ = (status == STATUS_OK) ? EX_NONE : EX_TRANSACTION_FAILED;
ret.error_code_ = status;
return ret;
}
private:
binder_exception_t exception_ = EX_NONE;
int32_t error_code_ = android::OK;
};
/**
* Convenience wrapper. See AIBinder_DeathRecipient.
*/
class ScopedAIBinder_DeathRecipient
: public impl::ScopedAResource<AIBinder_DeathRecipient*,
/*AIBinder_DeathRecipient_delete*/ nullptr,
nullptr> {
public:
/**
* Takes ownership of a.
*/
explicit ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient* a = nullptr)
: ScopedAResource(a) {}
~ScopedAIBinder_DeathRecipient() {}
ScopedAIBinder_DeathRecipient(ScopedAIBinder_DeathRecipient&&) = default;
ScopedAIBinder_DeathRecipient& operator=(ScopedAIBinder_DeathRecipient&&) = default;
};
/**
* Convenience wrapper. See AIBinder_Weak.
*/
class ScopedAIBinder_Weak
: public impl::ScopedAResource<AIBinder_Weak*, AIBinder_Weak_delete, nullptr> {
public:
/**
* Takes ownership of a.
*/
explicit ScopedAIBinder_Weak(AIBinder_Weak* a = nullptr) : ScopedAResource(a) {}
~ScopedAIBinder_Weak() {}
ScopedAIBinder_Weak(ScopedAIBinder_Weak&&) = default;
ScopedAIBinder_Weak& operator=(ScopedAIBinder_Weak&&) = default;
/**
* See AIBinder_Weak_promote.
*/
SpAIBinder promote() { return SpAIBinder(AIBinder_Weak_promote(get())); }
};
namespace internal {
static void closeWithError(int fd) {
if (fd == -1) return;
int ret = close(fd);
if (ret != 0) {
#if !defined(NNAPI_CHROMEOS)
syslog(LOG_ERR, "Could not close FD %d: %s", fd, strerror(errno));
#endif // NNAPI_CHROMEOS (syslog not defined)
}
}
} // namespace internal
/**
* Convenience wrapper for a file descriptor.
*/
class ScopedFileDescriptor : public impl::ScopedAResource<int, internal::closeWithError, -1> {
public:
/**
* Takes ownership of a.
*/
ScopedFileDescriptor() : ScopedFileDescriptor(-1) {}
explicit ScopedFileDescriptor(int a) : ScopedAResource(a) {}
~ScopedFileDescriptor() {}
ScopedFileDescriptor(ScopedFileDescriptor&&) = default;
ScopedFileDescriptor& operator=(ScopedFileDescriptor&&) = default;
ScopedFileDescriptor dup() const { return ScopedFileDescriptor(::dup(get())); }
bool operator!=(const ScopedFileDescriptor& rhs) const { return get() != rhs.get(); }
bool operator<(const ScopedFileDescriptor& rhs) const { return get() < rhs.get(); }
bool operator<=(const ScopedFileDescriptor& rhs) const { return get() <= rhs.get(); }
bool operator==(const ScopedFileDescriptor& rhs) const { return get() == rhs.get(); }
bool operator>(const ScopedFileDescriptor& rhs) const { return get() > rhs.get(); }
bool operator>=(const ScopedFileDescriptor& rhs) const { return get() >= rhs.get(); }
};
} // namespace ndk
/** @} */