fix: Add build script and fix manifest
- Add build-apk.sh for easy compilation - Simplify AndroidManifest.xml - Fix themes.xml to use basic Android themes - Enable BuildConfig - Add okhttp-dnsoverhttps dependency
This commit is contained in:
BIN
android-sdk/platforms/android-34/optional/android.car.jar
Normal file
BIN
android-sdk/platforms/android-34/optional/android.car.jar
Normal file
Binary file not shown.
BIN
android-sdk/platforms/android-34/optional/android.test.base.jar
Normal file
BIN
android-sdk/platforms/android-34/optional/android.test.base.jar
Normal file
Binary file not shown.
BIN
android-sdk/platforms/android-34/optional/android.test.mock.jar
Normal file
BIN
android-sdk/platforms/android-34/optional/android.test.mock.jar
Normal file
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,403 @@
|
||||
/*
|
||||
* 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_internal_logging.h>
|
||||
#include <android/binder_parcel.h>
|
||||
#include <android/binder_status.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <iostream>
|
||||
#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* binder) {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(); }
|
||||
};
|
||||
|
||||
/**
|
||||
* Convenience wrapper. See AStatus.
|
||||
*/
|
||||
class ScopedAStatus : public impl::ScopedAResource<AStatus*, AStatus_delete, nullptr> {
|
||||
public:
|
||||
/**
|
||||
* Takes ownership of a.
|
||||
*
|
||||
* WARNING: this constructor is only expected to be used when reading a
|
||||
* status value. Use `ScopedAStatus::ok()` instead.
|
||||
*/
|
||||
explicit ScopedAStatus(AStatus* a = nullptr) : ScopedAResource(a) {}
|
||||
~ScopedAStatus() {}
|
||||
ScopedAStatus(ScopedAStatus&&) = default;
|
||||
ScopedAStatus& operator=(ScopedAStatus&&) = default;
|
||||
|
||||
/**
|
||||
* See AStatus_isOk.
|
||||
*/
|
||||
bool isOk() const { return get() != nullptr && AStatus_isOk(get()); }
|
||||
|
||||
/**
|
||||
* See AStatus_getExceptionCode
|
||||
*/
|
||||
binder_exception_t getExceptionCode() const { return AStatus_getExceptionCode(get()); }
|
||||
|
||||
/**
|
||||
* See AStatus_getServiceSpecificError
|
||||
*/
|
||||
int32_t getServiceSpecificError() const { return AStatus_getServiceSpecificError(get()); }
|
||||
|
||||
/**
|
||||
* See AStatus_getStatus
|
||||
*/
|
||||
binder_status_t getStatus() const { return AStatus_getStatus(get()); }
|
||||
|
||||
/**
|
||||
* See AStatus_getMessage
|
||||
*/
|
||||
const char* getMessage() const { return AStatus_getMessage(get()); }
|
||||
|
||||
std::string getDescription() const {
|
||||
#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
|
||||
if (__builtin_available(android 30, *)) {
|
||||
#endif
|
||||
|
||||
#if defined(__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__) || __ANDROID_API__ >= 30
|
||||
const char* cStr = AStatus_getDescription(get());
|
||||
std::string ret = cStr;
|
||||
AStatus_deleteDescription(cStr);
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
|
||||
}
|
||||
#endif
|
||||
|
||||
binder_exception_t exception = getExceptionCode();
|
||||
std::string desc = std::to_string(exception);
|
||||
if (exception == EX_SERVICE_SPECIFIC) {
|
||||
desc += " (" + std::to_string(getServiceSpecificError()) + ")";
|
||||
} else if (exception == EX_TRANSACTION_FAILED) {
|
||||
desc += " (" + std::to_string(getStatus()) + ")";
|
||||
}
|
||||
if (const char* msg = getMessage(); msg != nullptr) {
|
||||
desc += ": ";
|
||||
desc += msg;
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience methods for creating scoped statuses.
|
||||
*/
|
||||
static ScopedAStatus ok() { return ScopedAStatus(AStatus_newOk()); }
|
||||
static ScopedAStatus fromExceptionCode(binder_exception_t exception) {
|
||||
return ScopedAStatus(AStatus_fromExceptionCode(exception));
|
||||
}
|
||||
static ScopedAStatus fromExceptionCodeWithMessage(binder_exception_t exception,
|
||||
const char* message) {
|
||||
return ScopedAStatus(AStatus_fromExceptionCodeWithMessage(exception, message));
|
||||
}
|
||||
static ScopedAStatus fromServiceSpecificError(int32_t serviceSpecific) {
|
||||
return ScopedAStatus(AStatus_fromServiceSpecificError(serviceSpecific));
|
||||
}
|
||||
static ScopedAStatus fromServiceSpecificErrorWithMessage(int32_t serviceSpecific,
|
||||
const char* message) {
|
||||
return ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(serviceSpecific, message));
|
||||
}
|
||||
static ScopedAStatus fromStatus(binder_status_t status) {
|
||||
return ScopedAStatus(AStatus_fromStatus(status));
|
||||
}
|
||||
};
|
||||
|
||||
static inline std::ostream& operator<<(std::ostream& os, const ScopedAStatus& status) {
|
||||
return os << status.getDescription();
|
||||
return os;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience wrapper. See AIBinder_DeathRecipient.
|
||||
*/
|
||||
class ScopedAIBinder_DeathRecipient
|
||||
: public impl::ScopedAResource<AIBinder_DeathRecipient*, AIBinder_DeathRecipient_delete,
|
||||
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() const { return SpAIBinder(AIBinder_Weak_promote(get())); }
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
static void closeWithError(int fd) {
|
||||
if (fd == -1) return;
|
||||
int ret = close(fd);
|
||||
if (ret != 0) {
|
||||
syslog(LOG_ERR, "Could not close FD %d: %s", fd, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
} // 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
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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_enums.h
|
||||
* @brief Helpers for AIDL enum types.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
namespace ndk {
|
||||
|
||||
namespace internal {
|
||||
/**
|
||||
* Never instantiated. Used as a placeholder for template variables.
|
||||
*/
|
||||
template <typename T>
|
||||
struct invalid_type;
|
||||
|
||||
/**
|
||||
* AIDL generates specializations of this for enums.
|
||||
*/
|
||||
template <typename EnumType, typename = std::enable_if_t<std::is_enum<EnumType>::value>>
|
||||
constexpr invalid_type<EnumType> enum_values;
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Iterable interface to enumerate all values of AIDL enum types.
|
||||
*/
|
||||
template <typename EnumType, typename = std::enable_if_t<std::is_enum<EnumType>::value>>
|
||||
struct enum_range {
|
||||
/**
|
||||
* Return an iterator pointing to the first enum value.
|
||||
*/
|
||||
constexpr auto begin() const { return std::begin(internal::enum_values<EnumType>); }
|
||||
/**
|
||||
* Return an iterator pointing to one past the last enum value.
|
||||
*/
|
||||
constexpr auto end() const { return std::end(internal::enum_values<EnumType>); }
|
||||
};
|
||||
|
||||
} // namespace ndk
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,377 @@
|
||||
/*
|
||||
* 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_interface_utils.h
|
||||
* @brief This provides common C++ classes for common operations and as base classes for C++
|
||||
* interfaces.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <android/binder_auto_utils.h>
|
||||
#include <android/binder_ibinder.h>
|
||||
|
||||
#if __has_include(<android/binder_shell.h>)
|
||||
#include <android/binder_shell.h>
|
||||
#define HAS_BINDER_SHELL_COMMAND
|
||||
#endif //_has_include
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
namespace ndk {
|
||||
|
||||
/**
|
||||
* Binder analog to using std::shared_ptr for an internally held refcount.
|
||||
*
|
||||
* ref must be called at least one time during the lifetime of this object. The recommended way to
|
||||
* construct this object is with SharedRefBase::make.
|
||||
*
|
||||
* If you need a "this" shared reference analogous to shared_from_this, use this->ref().
|
||||
*/
|
||||
class SharedRefBase {
|
||||
public:
|
||||
SharedRefBase() {}
|
||||
virtual ~SharedRefBase() {
|
||||
std::call_once(mFlagThis, [&]() {
|
||||
__assert(__FILE__, __LINE__, "SharedRefBase: no ref created during lifetime");
|
||||
});
|
||||
|
||||
if (ref() != nullptr) {
|
||||
__assert(__FILE__, __LINE__,
|
||||
"SharedRefBase: destructed but still able to lock weak_ptr. Is this object "
|
||||
"double-owned?");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A shared_ptr must be held to this object when this is called. This must be called once during
|
||||
* the lifetime of this object.
|
||||
*/
|
||||
std::shared_ptr<SharedRefBase> ref() {
|
||||
std::shared_ptr<SharedRefBase> thiz = mThis.lock();
|
||||
|
||||
std::call_once(mFlagThis, [&]() { mThis = thiz = std::shared_ptr<SharedRefBase>(this); });
|
||||
|
||||
return thiz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for a ref (see above) which automatically casts to the desired child type.
|
||||
*/
|
||||
template <typename CHILD>
|
||||
std::shared_ptr<CHILD> ref() {
|
||||
return std::static_pointer_cast<CHILD>(ref());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for making an object directly with a reference.
|
||||
*/
|
||||
template <class T, class... Args>
|
||||
static std::shared_ptr<T> make(Args&&... args) {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
T* t = new T(std::forward<Args>(args)...);
|
||||
#pragma clang diagnostic pop
|
||||
// warning: Potential leak of memory pointed to by 't' [clang-analyzer-unix.Malloc]
|
||||
return t->template ref<T>(); // NOLINT(clang-analyzer-unix.Malloc)
|
||||
}
|
||||
|
||||
static void operator delete(void* p) { std::free(p); }
|
||||
|
||||
// Once minSdkVersion is 30, we are guaranteed to be building with the
|
||||
// Android 11 AIDL compiler which supports the SharedRefBase::make API.
|
||||
//
|
||||
// Use 'SharedRefBase::make<T>(...)' to make. SharedRefBase has implicit
|
||||
// ownership. Making this operator private to avoid double-ownership.
|
||||
#if !defined(__ANDROID_API__) || __ANDROID_API__ >= 30 || defined(__ANDROID_APEX__)
|
||||
private:
|
||||
#else
|
||||
[[deprecated("Prefer SharedRefBase::make<T>(...) if possible.")]]
|
||||
#endif
|
||||
static void* operator new(size_t s) { return std::malloc(s); }
|
||||
|
||||
private:
|
||||
std::once_flag mFlagThis;
|
||||
std::weak_ptr<SharedRefBase> mThis;
|
||||
};
|
||||
|
||||
/**
|
||||
* wrapper analog to IInterface
|
||||
*/
|
||||
class ICInterface : public SharedRefBase {
|
||||
public:
|
||||
ICInterface() {}
|
||||
virtual ~ICInterface() {}
|
||||
|
||||
/**
|
||||
* This either returns the single existing implementation or creates a new implementation.
|
||||
*/
|
||||
virtual SpAIBinder asBinder() = 0;
|
||||
|
||||
/**
|
||||
* Returns whether this interface is in a remote process. If it cannot be determined locally,
|
||||
* this will be checked using AIBinder_isRemote.
|
||||
*/
|
||||
virtual bool isRemote() = 0;
|
||||
|
||||
/**
|
||||
* Dumps information about the interface. By default, dumps nothing.
|
||||
*/
|
||||
virtual inline binder_status_t dump(int fd, const char** args, uint32_t numArgs);
|
||||
|
||||
#ifdef HAS_BINDER_SHELL_COMMAND
|
||||
/**
|
||||
* Process shell commands. By default, does nothing.
|
||||
*/
|
||||
virtual inline binder_status_t handleShellCommand(int in, int out, int err, const char** argv,
|
||||
uint32_t argc);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Interprets this binder as this underlying interface if this has stored an ICInterface in the
|
||||
* binder's user data.
|
||||
*
|
||||
* This does not do type checking and should only be used when the binder is known to originate
|
||||
* from ICInterface. Most likely, you want to use I*::fromBinder.
|
||||
*/
|
||||
static inline std::shared_ptr<ICInterface> asInterface(AIBinder* binder);
|
||||
|
||||
/**
|
||||
* Helper method to create a class
|
||||
*/
|
||||
static inline AIBinder_Class* defineClass(const char* interfaceDescriptor,
|
||||
AIBinder_Class_onTransact onTransact);
|
||||
|
||||
private:
|
||||
class ICInterfaceData {
|
||||
public:
|
||||
std::shared_ptr<ICInterface> interface;
|
||||
|
||||
static inline std::shared_ptr<ICInterface> getInterface(AIBinder* binder);
|
||||
|
||||
static inline void* onCreate(void* args);
|
||||
static inline void onDestroy(void* userData);
|
||||
static inline binder_status_t onDump(AIBinder* binder, int fd, const char** args,
|
||||
uint32_t numArgs);
|
||||
|
||||
#ifdef HAS_BINDER_SHELL_COMMAND
|
||||
static inline binder_status_t handleShellCommand(AIBinder* binder, int in, int out, int err,
|
||||
const char** argv, uint32_t argc);
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* implementation of IInterface for server (n = native)
|
||||
*/
|
||||
template <typename INTERFACE>
|
||||
class BnCInterface : public INTERFACE {
|
||||
public:
|
||||
BnCInterface() {}
|
||||
virtual ~BnCInterface() {}
|
||||
|
||||
SpAIBinder asBinder() override final;
|
||||
|
||||
bool isRemote() override final { return false; }
|
||||
|
||||
static std::string makeServiceName(std::string_view instance) {
|
||||
return INTERFACE::descriptor + ("/" + std::string(instance));
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* This function should only be called by asBinder. Otherwise, there is a possibility of
|
||||
* multiple AIBinder* objects being created for the same instance of an object.
|
||||
*/
|
||||
virtual SpAIBinder createBinder() = 0;
|
||||
|
||||
private:
|
||||
std::mutex mMutex; // for asBinder
|
||||
ScopedAIBinder_Weak mWeakBinder;
|
||||
};
|
||||
|
||||
/**
|
||||
* implementation of IInterface for client (p = proxy)
|
||||
*/
|
||||
template <typename INTERFACE>
|
||||
class BpCInterface : public INTERFACE {
|
||||
public:
|
||||
explicit BpCInterface(const SpAIBinder& binder) : mBinder(binder) {}
|
||||
virtual ~BpCInterface() {}
|
||||
|
||||
SpAIBinder asBinder() override final;
|
||||
|
||||
bool isRemote() override final { return AIBinder_isRemote(mBinder.get()); }
|
||||
|
||||
binder_status_t dump(int fd, const char** args, uint32_t numArgs) override {
|
||||
return AIBinder_dump(asBinder().get(), fd, args, numArgs);
|
||||
}
|
||||
|
||||
private:
|
||||
SpAIBinder mBinder;
|
||||
};
|
||||
|
||||
// END OF CLASS DECLARATIONS
|
||||
|
||||
binder_status_t ICInterface::dump(int /*fd*/, const char** /*args*/, uint32_t /*numArgs*/) {
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
#ifdef HAS_BINDER_SHELL_COMMAND
|
||||
binder_status_t ICInterface::handleShellCommand(int /*in*/, int /*out*/, int /*err*/,
|
||||
const char** /*argv*/, uint32_t /*argc*/) {
|
||||
return STATUS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::shared_ptr<ICInterface> ICInterface::asInterface(AIBinder* binder) {
|
||||
return ICInterfaceData::getInterface(binder);
|
||||
}
|
||||
|
||||
AIBinder_Class* ICInterface::defineClass(const char* interfaceDescriptor,
|
||||
AIBinder_Class_onTransact onTransact) {
|
||||
AIBinder_Class* clazz = AIBinder_Class_define(interfaceDescriptor, ICInterfaceData::onCreate,
|
||||
ICInterfaceData::onDestroy, onTransact);
|
||||
if (clazz == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// We can't know if these methods are overridden by a subclass interface, so we must register
|
||||
// ourselves. The defaults are harmless.
|
||||
AIBinder_Class_setOnDump(clazz, ICInterfaceData::onDump);
|
||||
#ifdef HAS_BINDER_SHELL_COMMAND
|
||||
#ifdef __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
|
||||
if (__builtin_available(android 30, *)) {
|
||||
#else
|
||||
if (__ANDROID_API__ >= 30) {
|
||||
#endif
|
||||
AIBinder_Class_setHandleShellCommand(clazz, ICInterfaceData::handleShellCommand);
|
||||
}
|
||||
#endif
|
||||
return clazz;
|
||||
}
|
||||
|
||||
std::shared_ptr<ICInterface> ICInterface::ICInterfaceData::getInterface(AIBinder* binder) {
|
||||
if (binder == nullptr) return nullptr;
|
||||
|
||||
void* userData = AIBinder_getUserData(binder);
|
||||
if (userData == nullptr) return nullptr;
|
||||
|
||||
return static_cast<ICInterfaceData*>(userData)->interface;
|
||||
}
|
||||
|
||||
void* ICInterface::ICInterfaceData::onCreate(void* args) {
|
||||
std::shared_ptr<ICInterface> interface = static_cast<ICInterface*>(args)->ref<ICInterface>();
|
||||
ICInterfaceData* data = new ICInterfaceData{interface};
|
||||
return static_cast<void*>(data);
|
||||
}
|
||||
|
||||
void ICInterface::ICInterfaceData::onDestroy(void* userData) {
|
||||
delete static_cast<ICInterfaceData*>(userData);
|
||||
}
|
||||
|
||||
binder_status_t ICInterface::ICInterfaceData::onDump(AIBinder* binder, int fd, const char** args,
|
||||
uint32_t numArgs) {
|
||||
std::shared_ptr<ICInterface> interface = getInterface(binder);
|
||||
if (interface != nullptr) {
|
||||
return interface->dump(fd, args, numArgs);
|
||||
}
|
||||
return STATUS_DEAD_OBJECT;
|
||||
}
|
||||
|
||||
#ifdef HAS_BINDER_SHELL_COMMAND
|
||||
binder_status_t ICInterface::ICInterfaceData::handleShellCommand(AIBinder* binder, int in, int out,
|
||||
int err, const char** argv,
|
||||
uint32_t argc) {
|
||||
std::shared_ptr<ICInterface> interface = getInterface(binder);
|
||||
if (interface != nullptr) {
|
||||
return interface->handleShellCommand(in, out, err, argv, argc);
|
||||
}
|
||||
return STATUS_DEAD_OBJECT;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename INTERFACE>
|
||||
SpAIBinder BnCInterface<INTERFACE>::asBinder() {
|
||||
std::lock_guard<std::mutex> l(mMutex);
|
||||
|
||||
SpAIBinder binder;
|
||||
if (mWeakBinder.get() != nullptr) {
|
||||
binder.set(AIBinder_Weak_promote(mWeakBinder.get()));
|
||||
}
|
||||
if (binder.get() == nullptr) {
|
||||
binder = createBinder();
|
||||
mWeakBinder.set(AIBinder_Weak_new(binder.get()));
|
||||
}
|
||||
|
||||
return binder;
|
||||
}
|
||||
|
||||
template <typename INTERFACE>
|
||||
SpAIBinder BpCInterface<INTERFACE>::asBinder() {
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
} // namespace ndk
|
||||
|
||||
// Once minSdkVersion is 30, we are guaranteed to be building with the
|
||||
// Android 11 AIDL compiler which supports the SharedRefBase::make API.
|
||||
#if !defined(__ANDROID_API__) || __ANDROID_API__ >= 30 || defined(__ANDROID_APEX__)
|
||||
namespace ndk::internal {
|
||||
template <typename T, typename = void>
|
||||
struct is_complete_type : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};
|
||||
} // namespace ndk::internal
|
||||
|
||||
namespace std {
|
||||
|
||||
// Define `SharedRefBase` specific versions of `std::make_shared` and
|
||||
// `std::make_unique` to block people from using them. Using them to allocate
|
||||
// `ndk::SharedRefBase` objects results in double ownership. Use
|
||||
// `ndk::SharedRefBase::make<T>(...)` instead.
|
||||
//
|
||||
// Note: We exclude incomplete types because `std::is_base_of` is undefined in
|
||||
// that case.
|
||||
|
||||
template <typename T, typename... Args,
|
||||
std::enable_if_t<ndk::internal::is_complete_type<T>::value, bool> = true,
|
||||
std::enable_if_t<std::is_base_of<ndk::SharedRefBase, T>::value, bool> = true>
|
||||
shared_ptr<T> make_shared(Args...) { // SEE COMMENT ABOVE.
|
||||
static_assert(!std::is_base_of<ndk::SharedRefBase, T>::value);
|
||||
}
|
||||
|
||||
template <typename T, typename... Args,
|
||||
std::enable_if_t<ndk::internal::is_complete_type<T>::value, bool> = true,
|
||||
std::enable_if_t<std::is_base_of<ndk::SharedRefBase, T>::value, bool> = true>
|
||||
unique_ptr<T> make_unique(Args...) { // SEE COMMENT ABOVE.
|
||||
static_assert(!std::is_base_of<ndk::SharedRefBase, T>::value);
|
||||
}
|
||||
|
||||
} // namespace std
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup NdkBinder
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file binder_internal_logging.h
|
||||
* @brief This provides the ability to use syslog from binder headers, since
|
||||
* other logging functionality might be inaccessable.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// defined differently by liblog
|
||||
#pragma push_macro("LOG_PRI")
|
||||
#ifdef LOG_PRI
|
||||
#undef LOG_PRI
|
||||
#endif
|
||||
#include <syslog.h>
|
||||
#pragma pop_macro("LOG_PRI")
|
||||
|
||||
/** @} */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (C) 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup NdkBinder
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file binder_parcelable_utils.h
|
||||
* @brief Helper for parcelable.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <android/binder_parcel_utils.h>
|
||||
#include <optional>
|
||||
|
||||
namespace ndk {
|
||||
// Also see Parcelable.h in libbinder.
|
||||
typedef int32_t parcelable_stability_t;
|
||||
enum {
|
||||
STABILITY_LOCAL,
|
||||
STABILITY_VINTF, // corresponds to @VintfStability
|
||||
};
|
||||
#define RETURN_ON_FAILURE(expr) \
|
||||
do { \
|
||||
binder_status_t _status = (expr); \
|
||||
if (_status != STATUS_OK) return _status; \
|
||||
} while (false)
|
||||
|
||||
// AParcelableHolder has been introduced in 31.
|
||||
#if __ANDROID_API__ >= 31
|
||||
class AParcelableHolder {
|
||||
public:
|
||||
AParcelableHolder() = delete;
|
||||
explicit AParcelableHolder(parcelable_stability_t stability)
|
||||
: mParcel(AParcel_create()), mStability(stability) {}
|
||||
|
||||
AParcelableHolder(const AParcelableHolder& other)
|
||||
: mParcel(AParcel_create()), mStability(other.mStability) {
|
||||
AParcel_appendFrom(other.mParcel.get(), this->mParcel.get(), 0,
|
||||
AParcel_getDataSize(other.mParcel.get()));
|
||||
}
|
||||
|
||||
AParcelableHolder(AParcelableHolder&& other) = default;
|
||||
virtual ~AParcelableHolder() = default;
|
||||
|
||||
binder_status_t writeToParcel(AParcel* parcel) const {
|
||||
RETURN_ON_FAILURE(AParcel_writeInt32(parcel, static_cast<int32_t>(this->mStability)));
|
||||
int32_t size = AParcel_getDataSize(this->mParcel.get());
|
||||
RETURN_ON_FAILURE(AParcel_writeInt32(parcel, size));
|
||||
size = AParcel_getDataSize(this->mParcel.get());
|
||||
RETURN_ON_FAILURE(AParcel_appendFrom(this->mParcel.get(), parcel, 0, size));
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
binder_status_t readFromParcel(const AParcel* parcel) {
|
||||
AParcel_reset(mParcel.get());
|
||||
|
||||
parcelable_stability_t wireStability;
|
||||
RETURN_ON_FAILURE(AParcel_readInt32(parcel, &wireStability));
|
||||
if (this->mStability != wireStability) {
|
||||
return STATUS_BAD_VALUE;
|
||||
}
|
||||
|
||||
int32_t dataSize;
|
||||
binder_status_t status = AParcel_readInt32(parcel, &dataSize);
|
||||
|
||||
if (status != STATUS_OK || dataSize < 0) {
|
||||
return status != STATUS_OK ? status : STATUS_BAD_VALUE;
|
||||
}
|
||||
|
||||
int32_t dataStartPos = AParcel_getDataPosition(parcel);
|
||||
|
||||
if (dataStartPos > INT32_MAX - dataSize) {
|
||||
return STATUS_BAD_VALUE;
|
||||
}
|
||||
|
||||
status = AParcel_appendFrom(parcel, mParcel.get(), dataStartPos, dataSize);
|
||||
if (status != STATUS_OK) {
|
||||
return status;
|
||||
}
|
||||
return AParcel_setDataPosition(parcel, dataStartPos + dataSize);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
binder_status_t setParcelable(const T& p) {
|
||||
if (this->mStability > T::_aidl_stability) {
|
||||
return STATUS_BAD_VALUE;
|
||||
}
|
||||
AParcel_reset(mParcel.get());
|
||||
AParcel_writeString(mParcel.get(), T::descriptor, strlen(T::descriptor));
|
||||
p.writeToParcel(mParcel.get());
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
binder_status_t getParcelable(std::optional<T>* ret) const {
|
||||
const std::string parcelableDesc(T::descriptor);
|
||||
AParcel_setDataPosition(mParcel.get(), 0);
|
||||
if (AParcel_getDataSize(mParcel.get()) == 0) {
|
||||
*ret = std::nullopt;
|
||||
return STATUS_OK;
|
||||
}
|
||||
std::string parcelableDescInParcel;
|
||||
binder_status_t status = AParcel_readString(mParcel.get(), &parcelableDescInParcel);
|
||||
if (status != STATUS_OK || parcelableDesc != parcelableDescInParcel) {
|
||||
*ret = std::nullopt;
|
||||
return status;
|
||||
}
|
||||
*ret = std::make_optional<T>();
|
||||
status = (*ret)->readFromParcel(this->mParcel.get());
|
||||
if (status != STATUS_OK) {
|
||||
*ret = std::nullopt;
|
||||
return status;
|
||||
}
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
void reset() { AParcel_reset(mParcel.get()); }
|
||||
|
||||
inline bool operator!=(const AParcelableHolder& rhs) const { return this != &rhs; }
|
||||
inline bool operator<(const AParcelableHolder& rhs) const { return this < &rhs; }
|
||||
inline bool operator<=(const AParcelableHolder& rhs) const { return this <= &rhs; }
|
||||
inline bool operator==(const AParcelableHolder& rhs) const { return this == &rhs; }
|
||||
inline bool operator>(const AParcelableHolder& rhs) const { return this > &rhs; }
|
||||
inline bool operator>=(const AParcelableHolder& rhs) const { return this >= &rhs; }
|
||||
inline AParcelableHolder& operator=(const AParcelableHolder& rhs) {
|
||||
this->reset();
|
||||
if (this->mStability != rhs.mStability) {
|
||||
syslog(LOG_ERR, "AParcelableHolder stability mismatch: this %d rhs %d!",
|
||||
this->mStability, rhs.mStability);
|
||||
abort();
|
||||
}
|
||||
AParcel_appendFrom(rhs.mParcel.get(), this->mParcel.get(), 0,
|
||||
AParcel_getDataSize(rhs.mParcel.get()));
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable ndk::ScopedAParcel mParcel;
|
||||
parcelable_stability_t mStability;
|
||||
};
|
||||
#endif // __ANDROID_API__ >= 31
|
||||
|
||||
#undef RETURN_ON_FAILURE
|
||||
} // namespace ndk
|
||||
|
||||
/** @} */
|
||||
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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_to_string.h
|
||||
* @brief Helper for parcelable.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#if __has_include(<utils/StrongPointer.h>)
|
||||
#include <utils/StrongPointer.h>
|
||||
#define HAS_STRONG_POINTER
|
||||
#endif
|
||||
|
||||
#if __has_include(<utils/String16.h>)
|
||||
#include <utils/String16.h>
|
||||
#define HAS_STRING16
|
||||
#endif
|
||||
|
||||
#if __has_include(<android/binder_ibinder.h>)
|
||||
#include <android/binder_auto_utils.h>
|
||||
#include <android/binder_interface_utils.h>
|
||||
#include <android/binder_parcelable_utils.h>
|
||||
#define HAS_NDK_INTERFACE
|
||||
#endif
|
||||
|
||||
// TODO: some things include libbinder without having access to libbase. This is
|
||||
// due to frameworks/native/include, which symlinks to libbinder headers, so even
|
||||
// though we don't use it here, we detect a different header, so that we are more
|
||||
// confident libbase will be included
|
||||
#if __has_include(<binder/RpcSession.h>)
|
||||
#include <binder/IBinder.h>
|
||||
#include <binder/IInterface.h>
|
||||
#define HAS_CPP_INTERFACE
|
||||
#endif
|
||||
|
||||
namespace android {
|
||||
namespace internal {
|
||||
|
||||
// ToString is a utility to generate string representation for various AIDL-supported types.
|
||||
template <typename _T>
|
||||
std::string ToString(const _T& t);
|
||||
|
||||
namespace details {
|
||||
|
||||
// Truthy if _T has toString() method.
|
||||
template <typename _T>
|
||||
class HasToStringMethod {
|
||||
template <typename _U>
|
||||
static auto _test(int) -> decltype(std::declval<_U>().toString(), std::true_type());
|
||||
template <typename _U>
|
||||
static std::false_type _test(...);
|
||||
|
||||
public:
|
||||
enum { value = decltype(_test<_T>(0))::value };
|
||||
};
|
||||
|
||||
// Truthy if _T has a overloaded toString(T)
|
||||
template <typename _T>
|
||||
class HasToStringFunction {
|
||||
template <typename _U>
|
||||
static auto _test(int) -> decltype(toString(std::declval<_U>()), std::true_type());
|
||||
template <typename _U>
|
||||
static std::false_type _test(...);
|
||||
|
||||
public:
|
||||
enum { value = decltype(_test<_T>(0))::value };
|
||||
};
|
||||
|
||||
template <typename T, template <typename...> typename U>
|
||||
struct IsInstantiationOf : std::false_type {};
|
||||
|
||||
template <template <typename...> typename U, typename... Args>
|
||||
struct IsInstantiationOf<U<Args...>, U> : std::true_type {};
|
||||
|
||||
// Truthy if _T is like a pointer: one of sp/optional/shared_ptr
|
||||
template <typename _T>
|
||||
class IsPointerLike {
|
||||
template <typename _U>
|
||||
static std::enable_if_t<
|
||||
#ifdef HAS_STRONG_POINTER
|
||||
IsInstantiationOf<_U, sp>::value || // for IBinder and interface types in the C++
|
||||
// backend
|
||||
#endif
|
||||
IsInstantiationOf<_U, std::optional>::value || // for @nullable types in the
|
||||
// C++/NDK backends
|
||||
IsInstantiationOf<_U, std::unique_ptr>::value || // for @nullable(heap=true)
|
||||
// in C++/NDK backends
|
||||
IsInstantiationOf<_U, std::shared_ptr>::value, // for interface types in the
|
||||
// NDK backends
|
||||
|
||||
std::true_type>
|
||||
_test(int);
|
||||
template <typename _U>
|
||||
static std::false_type _test(...);
|
||||
|
||||
public:
|
||||
enum { value = decltype(_test<_T>(0))::value };
|
||||
};
|
||||
|
||||
// Truthy if _T is like a container
|
||||
template <typename _T>
|
||||
class IsIterable {
|
||||
template <typename _U>
|
||||
static auto _test(int)
|
||||
-> decltype(begin(std::declval<_U>()), end(std::declval<_U>()), std::true_type());
|
||||
template <typename _U>
|
||||
static std::false_type _test(...);
|
||||
|
||||
public:
|
||||
enum { value = decltype(_test<_T>(0))::value };
|
||||
};
|
||||
|
||||
template <typename _T>
|
||||
struct TypeDependentFalse {
|
||||
enum { value = false };
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
template <typename _T>
|
||||
std::string ToString(const _T& t) {
|
||||
if constexpr (std::is_same_v<bool, _T>) {
|
||||
return t ? "true" : "false";
|
||||
} else if constexpr (std::is_same_v<char16_t, _T>) {
|
||||
// TODO(b/244494451): codecvt is deprecated in C++17 -- suppress the
|
||||
// warnings. There's no replacement in the standard library yet.
|
||||
_Pragma("clang diagnostic push")
|
||||
_Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"");
|
||||
return std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>().to_bytes(t);
|
||||
_Pragma("clang diagnostic pop");
|
||||
} else if constexpr (std::is_arithmetic_v<_T>) {
|
||||
return std::to_string(t);
|
||||
} else if constexpr (std::is_same_v<std::string, _T>) {
|
||||
return t;
|
||||
#ifdef HAS_NDK_INTERFACE
|
||||
} else if constexpr (std::is_same_v<::ndk::SpAIBinder, _T>) {
|
||||
std::stringstream ss;
|
||||
ss << "binder:" << std::hex << t.get();
|
||||
return ss.str();
|
||||
} else if constexpr (std::is_same_v<::ndk::ScopedFileDescriptor, _T>) {
|
||||
return "fd:" + std::to_string(t.get());
|
||||
} else if constexpr (std::is_base_of_v<::ndk::ICInterface, _T>) {
|
||||
// TODO(b/266248339): this format is to make it easy to handle resolv_integration_test
|
||||
// freezing the output format. We would like to print more info.
|
||||
return "<interface>";
|
||||
#if __ANDROID_API__ >= 31
|
||||
} else if constexpr (std::is_same_v<::ndk::AParcelableHolder, _T>) {
|
||||
return "AParcelableHolder";
|
||||
#endif
|
||||
#endif // HAS_NDK_INTERFACE
|
||||
#ifdef HAS_CPP_INTERFACE
|
||||
} else if constexpr (std::is_base_of_v<IInterface, _T>) {
|
||||
std::stringstream ss;
|
||||
ss << "interface:" << std::hex << &t;
|
||||
return ss.str();
|
||||
} else if constexpr (std::is_same_v<IBinder, _T>) {
|
||||
std::stringstream ss;
|
||||
ss << "binder:" << std::hex << &t;
|
||||
return ss.str();
|
||||
#endif
|
||||
#ifdef HAS_STRING16
|
||||
} else if constexpr (std::is_same_v<String16, _T>) {
|
||||
std::stringstream out;
|
||||
out << t;
|
||||
return out.str();
|
||||
#endif
|
||||
} else if constexpr (details::IsPointerLike<_T>::value || std::is_pointer_v<_T>) {
|
||||
if (!t) return "(null)";
|
||||
std::stringstream out;
|
||||
out << ToString(*t);
|
||||
return out.str();
|
||||
} else if constexpr (details::HasToStringMethod<_T>::value) {
|
||||
return t.toString();
|
||||
} else if constexpr (details::HasToStringFunction<_T>::value) {
|
||||
return toString(t);
|
||||
} else if constexpr (details::IsIterable<_T>::value) {
|
||||
std::stringstream out;
|
||||
bool first = true;
|
||||
out << "[";
|
||||
for (const auto& e : t) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
out << ", ";
|
||||
}
|
||||
// Use explicit type parameter in case deref of iterator has different type
|
||||
// e.g. vector<bool>
|
||||
out << ToString<typename _T::value_type>(e);
|
||||
}
|
||||
out << "]";
|
||||
return out.str();
|
||||
} else {
|
||||
static_assert(details::TypeDependentFalse<_T>::value, "no toString implemented, huh?");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace android
|
||||
|
||||
#ifdef HAS_STRONG_POINTER
|
||||
#undef HAS_STRONG_POINTER
|
||||
#endif
|
||||
|
||||
#ifdef HAS_STRING16
|
||||
#undef HAS_STRING16
|
||||
#endif
|
||||
|
||||
#ifdef HAS_NDK_INTERFACE
|
||||
#undef HAS_NDK_INTERFACE
|
||||
#endif
|
||||
|
||||
#ifdef HAS_CPP_INTERFACE
|
||||
#undef HAS_CPP_INTERFACE
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
28
android-sdk/platforms/android-34/optional/optional.json
Normal file
28
android-sdk/platforms/android-34/optional/optional.json
Normal file
@@ -0,0 +1,28 @@
|
||||
[
|
||||
{
|
||||
"name": "org.apache.http.legacy",
|
||||
"jar": "org.apache.http.legacy.jar",
|
||||
"manifest": false
|
||||
},
|
||||
{
|
||||
"name": "android.car",
|
||||
"jar": "android.car.jar",
|
||||
"manifest": false
|
||||
},
|
||||
{
|
||||
"name": "android.test.mock",
|
||||
"jar": "android.test.mock.jar",
|
||||
"manifest": false
|
||||
},
|
||||
{
|
||||
"name": "android.test.base",
|
||||
"jar": "android.test.base.jar",
|
||||
"manifest": false
|
||||
},
|
||||
{
|
||||
"name": "android.test.runner",
|
||||
"jar": "android.test.runner.jar",
|
||||
"manifest": false
|
||||
}
|
||||
]
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user