Merge "Fix binderLibTest flakiness" into main
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 6576ffd..c407f48 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -170,6 +170,7 @@
#define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
#define BLK_DEV_SYS_DIR "/sys/block"
+#define AFLAGS "/system/bin/aflags"
#define RECOVERY_DIR "/cache/recovery"
#define RECOVERY_DATA_DIR "/data/misc/recovery"
#define UPDATE_ENGINE_LOG_DIR "/data/misc/update_engine_log"
@@ -1785,6 +1786,10 @@
RunCommand("ACONFIG FLAGS", {PRINT_FLAGS},
CommandOptions::WithTimeout(10).Always().DropRoot().Build());
+ RunCommand("ACONFIG FLAGS DUMP", {AFLAGS, "list"},
+ CommandOptions::WithTimeout(10).Always().AsRootIfAvailable().Build());
+ RunCommand("WHICH ACONFIG FLAG STORAGE", {AFLAGS, "which-backing"},
+ CommandOptions::WithTimeout(10).Always().AsRootIfAvailable().Build());
RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"});
diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp
index 319716e..cbba711 100644
--- a/libs/arect/Android.bp
+++ b/libs/arect/Android.bp
@@ -40,6 +40,7 @@
cc_library_headers {
name: "libarect_headers",
+ host_supported: true,
vendor_available: true,
min_sdk_version: "29",
// TODO(b/153609531): remove when no longer needed.
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 379b609..6903cb5 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -489,6 +489,7 @@
"ProcessState.cpp",
"Static.cpp",
":libbinder_aidl",
+ ":libbinder_accessor_aidl",
":libbinder_device_interface_sources",
],
target: {
@@ -801,7 +802,6 @@
"aidl/android/os/IServiceManager.aidl",
"aidl/android/os/Service.aidl",
"aidl/android/os/ServiceDebugInfo.aidl",
- ":libbinder_accessor_aidl",
],
path: "aidl",
}
@@ -812,26 +812,7 @@
"aidl/android/os/IAccessor.aidl",
],
path: "aidl",
-}
-
-// TODO(b/353492849): Make this interface private to libbinder.
-aidl_interface {
- name: "android.os.accessor",
- srcs: [":libbinder_accessor_aidl"],
- unstable: true,
- backend: {
- rust: {
- enabled: true,
- apex_available: [
- "com.android.virt",
- ],
- },
- },
- visibility: [
- ":__subpackages__",
- "//system/tools/aidl:__subpackages__",
- "//packages/modules/Virtualization:__subpackages__",
- ],
+ visibility: [":__subpackages__"],
}
aidl_interface {
diff --git a/libs/binder/BackendUnifiedServiceManager.cpp b/libs/binder/BackendUnifiedServiceManager.cpp
index 5680798..52b485a 100644
--- a/libs/binder/BackendUnifiedServiceManager.cpp
+++ b/libs/binder/BackendUnifiedServiceManager.cpp
@@ -34,37 +34,47 @@
using IAccessor = android::os::IAccessor;
static const char* kStaticCachableList[] = {
+ // go/keep-sorted start
+ "accessibility",
+ "account",
"activity",
- "android.hardware.thermal.IThermal/default",
- "android.hardware.power.IPower/default",
- "android.frameworks.stats.IStats/default",
- "android.system.suspend.ISystemSuspend/default",
+ "alarm",
+ "android.system.keystore2.IKeystoreService/default",
"appops",
"audio",
"batterystats",
"carrier_config",
"connectivity",
+ "content",
"content_capture",
"device_policy",
"display",
"dropbox",
"econtroller",
+ "graphicsstats",
+ "input",
+ "input_method",
"isub",
+ "jobscheduler",
"legacy_permission",
"location",
"media.extractor",
"media.metrics",
"media.player",
"media.resource_manager",
+ "media_resource_monitor",
+ "mount",
"netd_listener",
"netstats",
"network_management",
"nfc",
+ "notification",
+ "package",
"package_native",
"performance_hint",
"permission",
- "permissionmgr",
"permission_checker",
+ "permissionmgr",
"phone",
"platform_compat",
"power",
@@ -76,9 +86,12 @@
"time_detector",
"trust",
"uimode",
+ "user",
"virtualdevice",
"virtualdevice_native",
"webviewupdate",
+ "window",
+ // go/keep-sorted end
};
bool BinderCacheWithInvalidation::isClientSideCachingEnabled(const std::string& serviceName) {
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 1d26d85..6698d0c 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -232,6 +232,15 @@
return cmd;
}
+static void printReturnCommandParcel(std::ostream& out, const Parcel& parcel) {
+ const void* cmds = parcel.data();
+ out << "\t" << HexDump(cmds, parcel.dataSize()) << "\n";
+ IF_LOG_COMMANDS() {
+ const void* end = parcel.data() + parcel.dataSize();
+ while (cmds < end) cmds = printReturnCommand(out, cmds);
+ }
+}
+
static const void* printCommand(std::ostream& out, const void* _cmd) {
static const size_t N = sizeof(kCommandStrings)/sizeof(kCommandStrings[0]);
const int32_t* cmd = (const int32_t*)_cmd;
@@ -1235,13 +1244,15 @@
if (err >= NO_ERROR) {
if (bwr.write_consumed > 0) {
- if (bwr.write_consumed < mOut.dataSize())
+ if (bwr.write_consumed < mOut.dataSize()) {
+ std::ostringstream logStream;
+ printReturnCommandParcel(logStream, mIn);
LOG_ALWAYS_FATAL("Driver did not consume write buffer. "
- "err: %s consumed: %zu of %zu",
- statusToString(err).c_str(),
- (size_t)bwr.write_consumed,
- mOut.dataSize());
- else {
+ "err: %s consumed: %zu of %zu.\n"
+ "Return command: %s",
+ statusToString(err).c_str(), (size_t)bwr.write_consumed,
+ mOut.dataSize(), logStream.str().c_str());
+ } else {
mOut.setDataSize(0);
processPostWriteDerefs();
}
@@ -1252,14 +1263,8 @@
}
IF_LOG_COMMANDS() {
std::ostringstream logStream;
- logStream << "Remaining data size: " << mOut.dataSize() << "\n";
- logStream << "Received commands from driver: ";
- const void* cmds = mIn.data();
- const void* end = mIn.data() + mIn.dataSize();
- logStream << "\t" << HexDump(cmds, mIn.dataSize()) << "\n";
- while (cmds < end) cmds = printReturnCommand(logStream, cmds);
- std::string message = logStream.str();
- ALOGI("%s", message.c_str());
+ printReturnCommandParcel(logStream, mIn);
+ ALOGI("%s", logStream.str().c_str());
}
return NO_ERROR;
}
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 88761d7..32388db 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -157,12 +157,21 @@
class AccessorProvider {
public:
- AccessorProvider(RpcAccessorProvider&& provider) : mProvider(std::move(provider)) {}
- sp<IBinder> provide(const String16& name) { return mProvider(name); }
+ AccessorProvider(std::set<std::string>&& instances, RpcAccessorProvider&& provider)
+ : mInstances(std::move(instances)), mProvider(std::move(provider)) {}
+ sp<IBinder> provide(const String16& name) {
+ if (mInstances.count(String8(name).c_str()) > 0) {
+ return mProvider(name);
+ } else {
+ return nullptr;
+ }
+ }
+ const std::set<std::string>& instances() { return mInstances; }
private:
AccessorProvider() = delete;
+ std::set<std::string> mInstances;
RpcAccessorProvider mProvider;
};
@@ -318,10 +327,32 @@
return sp<CppBackendShim>::make(sp<BackendUnifiedServiceManager>::make(sm));
}
-std::weak_ptr<AccessorProvider> addAccessorProvider(RpcAccessorProvider&& providerCallback) {
+// gAccessorProvidersMutex must be locked already
+static bool isInstanceProvidedLocked(const std::string& instance) {
+ return gAccessorProviders.end() !=
+ std::find_if(gAccessorProviders.begin(), gAccessorProviders.end(),
+ [&instance](const AccessorProviderEntry& entry) {
+ return entry.mProvider->instances().count(instance) > 0;
+ });
+}
+
+std::weak_ptr<AccessorProvider> addAccessorProvider(std::set<std::string>&& instances,
+ RpcAccessorProvider&& providerCallback) {
+ if (instances.empty()) {
+ ALOGE("Set of instances is empty! Need a non empty set of instances to provide for.");
+ return std::weak_ptr<AccessorProvider>();
+ }
std::lock_guard<std::mutex> lock(gAccessorProvidersMutex);
+ for (const auto& instance : instances) {
+ if (isInstanceProvidedLocked(instance)) {
+ ALOGE("The instance %s is already provided for by a previously added "
+ "RpcAccessorProvider.",
+ instance.c_str());
+ return std::weak_ptr<AccessorProvider>();
+ }
+ }
std::shared_ptr<AccessorProvider> provider =
- std::make_shared<AccessorProvider>(std::move(providerCallback));
+ std::make_shared<AccessorProvider>(std::move(instances), std::move(providerCallback));
std::weak_ptr<AccessorProvider> receipt = provider;
gAccessorProviders.push_back(AccessorProviderEntry(std::move(provider)));
@@ -331,8 +362,9 @@
status_t removeAccessorProvider(std::weak_ptr<AccessorProvider> wProvider) {
std::shared_ptr<AccessorProvider> provider = wProvider.lock();
if (provider == nullptr) {
- ALOGE("The provider supplied to removeAccessorProvider has already been removed.");
- return NAME_NOT_FOUND;
+ ALOGE("The provider supplied to removeAccessorProvider has already been removed or the "
+ "argument to this function was nullptr.");
+ return BAD_VALUE;
}
std::lock_guard<std::mutex> lock(gAccessorProvidersMutex);
size_t sizeBefore = gAccessorProviders.size();
@@ -354,7 +386,7 @@
ALOGE("Binder is null");
return BAD_VALUE;
}
- sp<IAccessor> accessor = interface_cast<IAccessor>(binder);
+ sp<IAccessor> accessor = checked_interface_cast<IAccessor>(binder);
if (accessor == nullptr) {
ALOGE("This binder for %s is not an IAccessor binder", String8(instance).c_str());
return BAD_TYPE;
@@ -388,6 +420,28 @@
return binder;
}
+status_t delegateAccessor(const String16& name, const sp<IBinder>& accessor,
+ sp<IBinder>* delegator) {
+ LOG_ALWAYS_FATAL_IF(delegator == nullptr, "delegateAccessor called with a null out param");
+ if (accessor == nullptr) {
+ ALOGW("Accessor argument to delegateAccessor is null.");
+ *delegator = nullptr;
+ return OK;
+ }
+ status_t status = validateAccessor(name, accessor);
+ if (status != OK) {
+ ALOGE("The provided accessor binder is not an IAccessor for instance %s. Status: "
+ "%s",
+ String8(name).c_str(), statusToString(status).c_str());
+ return status;
+ }
+ // validateAccessor already called checked_interface_cast and made sure this
+ // is a valid accessor object.
+ *delegator = sp<android::os::IAccessorDelegator>::make(interface_cast<IAccessor>(accessor));
+
+ return OK;
+}
+
#if !defined(__ANDROID_VNDK__)
// IPermissionController is not accessible to vendors
diff --git a/libs/binder/OS.h b/libs/binder/OS.h
index 04869a1..64b1fd4 100644
--- a/libs/binder/OS.h
+++ b/libs/binder/OS.h
@@ -27,6 +27,7 @@
LIBBINDER_EXPORTED void trace_begin(uint64_t tag, const char* name);
LIBBINDER_EXPORTED void trace_end(uint64_t tag);
LIBBINDER_EXPORTED void trace_int(uint64_t tag, const char* name, int32_t value);
+LIBBINDER_EXPORTED uint64_t get_trace_enabled_tags();
status_t setNonBlocking(borrowed_fd fd);
diff --git a/libs/binder/OS_android.cpp b/libs/binder/OS_android.cpp
index 893ee15..4e9230c 100644
--- a/libs/binder/OS_android.cpp
+++ b/libs/binder/OS_android.cpp
@@ -48,6 +48,10 @@
atrace_int(tag, name, value);
}
+uint64_t get_trace_enabled_tags() {
+ return atrace_enabled_tags;
+}
+
} // namespace os
// Legacy trace symbol. To be removed once all of downstream rebuilds.
diff --git a/libs/binder/OS_non_android_linux.cpp b/libs/binder/OS_non_android_linux.cpp
index 0c64eb6..6bba823 100644
--- a/libs/binder/OS_non_android_linux.cpp
+++ b/libs/binder/OS_non_android_linux.cpp
@@ -41,6 +41,10 @@
void trace_int(uint64_t, const char*, int32_t) {}
+uint64_t get_trace_enabled_tags() {
+ return 0;
+}
+
uint64_t GetThreadId() {
return syscall(__NR_gettid);
}
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 4b7af45..3711362 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -683,7 +683,7 @@
return err;
}
-int Parcel::compareData(const Parcel& other) {
+int Parcel::compareData(const Parcel& other) const {
size_t size = dataSize();
if (size != other.dataSize()) {
return size < other.dataSize() ? -1 : 1;
diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp
index dba6587..9a98097 100644
--- a/libs/binder/Status.cpp
+++ b/libs/binder/Status.cpp
@@ -99,27 +99,28 @@
return status;
}
+ if (mException == EX_HAS_NOTED_APPOPS_REPLY_HEADER) {
+ status = skipUnusedHeader(parcel);
+ if (status != OK) {
+ setFromStatusT(status);
+ return status;
+ }
+ // Read next exception code.
+ status = parcel.readInt32(&mException);
+ if (status != OK) {
+ setFromStatusT(status);
+ return status;
+ }
+ }
+
// Skip over fat response headers. Not used (or propagated) in native code.
if (mException == EX_HAS_REPLY_HEADER) {
- // Note that the header size includes the 4 byte size field.
- const size_t header_start = parcel.dataPosition();
- // Get available size before reading more
- const size_t header_avail = parcel.dataAvail();
-
- int32_t header_size;
- status = parcel.readInt32(&header_size);
+ status = skipUnusedHeader(parcel);
if (status != OK) {
setFromStatusT(status);
return status;
}
- if (header_size < 0 || static_cast<size_t>(header_size) > header_avail) {
- android_errorWriteLog(0x534e4554, "132650049");
- setFromStatusT(UNKNOWN_ERROR);
- return UNKNOWN_ERROR;
- }
-
- parcel.setDataPosition(header_start + header_size);
// And fat response headers are currently only used when there are no
// exceptions, so act like there was no error.
mException = EX_NONE;
@@ -257,5 +258,28 @@
return ret;
}
+status_t Status::skipUnusedHeader(const Parcel& parcel) {
+ // Note that the header size includes the 4 byte size field.
+ const size_t header_start = parcel.dataPosition();
+ // Get available size before reading more
+ const size_t header_avail = parcel.dataAvail();
+
+ int32_t header_size;
+ status_t status = parcel.readInt32(&header_size);
+ ALOGD("Skip unused header. exception code: %d, start: %zu, size: %d.",
+ mException, header_start, header_size);
+ if (status != OK) {
+ return status;
+ }
+
+ if (header_size < 0 || static_cast<size_t>(header_size) > header_avail) {
+ android_errorWriteLog(0x534e4554, "132650049");
+ return UNKNOWN_ERROR;
+ }
+
+ parcel.setDataPosition(header_start + header_size);
+ return OK;
+}
+
} // namespace binder
} // namespace android
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 879f319..81f7cdb 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -24,6 +24,7 @@
#include <utils/String16.h>
#include <utils/Vector.h>
#include <optional>
+#include <set>
namespace android {
@@ -224,20 +225,36 @@
typedef std::function<status_t(const String16& name, sockaddr* outAddr, socklen_t addrSize)>
RpcSocketAddressProvider;
-typedef std::function<sp<IBinder>(const String16& name)> RpcAccessorProvider;
+/**
+ * This callback provides a way for clients to get access to remote services by
+ * providing an Accessor object from libbinder that can connect to the remote
+ * service over sockets.
+ *
+ * \param instance name of the service that the callback will provide an
+ * Accessor for. The provided accessor will be used to set up a client
+ * RPC connection in libbinder in order to return a binder for the
+ * associated remote service.
+ *
+ * \return IBinder of the Accessor object that libbinder implements.
+ * nullptr if the provider callback doesn't know how to reach the
+ * service or doesn't want to provide access for any other reason.
+ */
+typedef std::function<sp<IBinder>(const String16& instance)> RpcAccessorProvider;
class AccessorProvider;
/**
- * Register an accessor provider for the service manager APIs.
+ * Register a RpcAccessorProvider for the service manager APIs.
*
+ * \param instances that the RpcAccessorProvider knows about and can provide an
+ * Accessor for.
* \param provider callback that generates Accessors.
*
* \return A pointer used as a recept for the successful addition of the
* AccessorProvider. This is needed to unregister it later.
*/
[[nodiscard]] LIBBINDER_EXPORTED std::weak_ptr<AccessorProvider> addAccessorProvider(
- RpcAccessorProvider&& providerCallback);
+ std::set<std::string>&& instances, RpcAccessorProvider&& providerCallback);
/**
* Remove an accessor provider using the pointer provided by addAccessorProvider
@@ -274,6 +291,28 @@
* \return OK if the binder is an IAccessor for `instance`
*/
LIBBINDER_EXPORTED status_t validateAccessor(const String16& instance, const sp<IBinder>& binder);
+
+/**
+ * Have libbinder wrap this IAccessor binder in an IAccessorDelegator and return
+ * it.
+ *
+ * This is required only in very specific situations when the process that has
+ * permissions to connect the to RPC service's socket and create the FD for it
+ * is in a separate process from this process that wants to service the Accessor
+ * binder and the communication between these two processes is binder RPC. This
+ * is needed because the binder passed over the binder RPC connection can not be
+ * used as a kernel binder, and needs to be wrapped by a kernel binder that can
+ * then be registered with service manager.
+ *
+ * \param instance name of the Accessor.
+ * \param binder to wrap in a Delegator and register with service manager.
+ * \param outDelegator the wrapped kernel binder for IAccessorDelegator
+ *
+ * \return OK if the binder is an IAccessor for `instance` and the delegator was
+ * successfully created.
+ */
+LIBBINDER_EXPORTED status_t delegateAccessor(const String16& name, const sp<IBinder>& accessor,
+ sp<IBinder>* delegator);
#endif // __TRUSTY__
#ifndef __ANDROID__
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 5cc0830..15a0da7 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -92,7 +92,7 @@
LIBBINDER_EXPORTED status_t appendFrom(const Parcel* parcel, size_t start, size_t len);
- LIBBINDER_EXPORTED int compareData(const Parcel& other);
+ LIBBINDER_EXPORTED int compareData(const Parcel& other) const;
LIBBINDER_EXPORTED status_t compareDataInRange(size_t thisOffset, const Parcel& other,
size_t otherOffset, size_t length,
int* result) const;
@@ -637,9 +637,6 @@
LIBBINDER_EXPORTED const flat_binder_object* readObject(bool nullMetaData) const;
- // Explicitly close all file descriptors in the parcel.
- LIBBINDER_EXPORTED void closeFileDescriptors();
-
// Debugging: get metrics on current allocations.
LIBBINDER_EXPORTED static size_t getGlobalAllocSize();
LIBBINDER_EXPORTED static size_t getGlobalAllocCount();
@@ -652,6 +649,9 @@
LIBBINDER_EXPORTED void print(std::ostream& to, uint32_t flags = 0) const;
private:
+ // Explicitly close all file descriptors in the parcel.
+ void closeFileDescriptors();
+
// `objects` and `objectsSize` always 0 for RPC Parcels.
typedef void (*release_func)(const uint8_t* data, size_t dataSize, const binder_size_t* objects,
size_t objectsSize);
@@ -1240,7 +1240,7 @@
if (__builtin_mul_overflow(size, sizeof(T), &dataLen)) {
return -EOVERFLOW;
}
- auto data = reinterpret_cast<const T*>(readInplace(dataLen));
+ auto data = readInplace(dataLen);
if (data == nullptr) return BAD_VALUE;
// std::vector::insert and similar methods will require type-dependent
// byte alignment when inserting from a const iterator such as `data`,
diff --git a/libs/binder/include/binder/Status.h b/libs/binder/include/binder/Status.h
index 49ccf7c..d69f662 100644
--- a/libs/binder/include/binder/Status.h
+++ b/libs/binder/include/binder/Status.h
@@ -67,6 +67,9 @@
EX_SERVICE_SPECIFIC = -8,
EX_PARCELABLE = -9,
+ // See android/os/Parcel.java. We need to handle this in native code.
+ EX_HAS_NOTED_APPOPS_REPLY_HEADER = -127,
+
// This is special and Java specific; see Parcel.java.
EX_HAS_REPLY_HEADER = -128,
// This is special, and indicates to C++ binder proxies that the
@@ -150,6 +153,8 @@
Status(int32_t exceptionCode, int32_t errorCode);
Status(int32_t exceptionCode, int32_t errorCode, const String8& message);
+ status_t skipUnusedHeader(const Parcel& parcel);
+
// If |mException| == EX_TRANSACTION_FAILED, generated code will return
// |mErrorCode| as the result of the transaction rather than write an
// exception to the reply parcel.
diff --git a/libs/binder/include/binder/Trace.h b/libs/binder/include/binder/Trace.h
index 2f450cb..a3e6c8a 100644
--- a/libs/binder/include/binder/Trace.h
+++ b/libs/binder/include/binder/Trace.h
@@ -42,6 +42,7 @@
void trace_begin(uint64_t tag, const char* name);
void trace_end(uint64_t tag);
void trace_int(uint64_t tag, const char* name, int32_t value);
+uint64_t get_trace_enabled_tags();
} // namespace os
class LIBBINDER_EXPORTED ScopedTrace {
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 5f45cb2..a7423b3 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -95,6 +95,7 @@
"persistable_bundle.cpp",
"process.cpp",
"service_manager.cpp",
+ "binder_rpc.cpp",
],
static_libs: [
diff --git a/libs/binder/ndk/binder_rpc.cpp b/libs/binder/ndk/binder_rpc.cpp
new file mode 100644
index 0000000..07b8c40
--- /dev/null
+++ b/libs/binder/ndk/binder_rpc.cpp
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#include <android/binder_rpc.h>
+#include <arpa/inet.h>
+#include <binder/IServiceManager.h>
+#include <linux/vm_sockets.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <variant>
+
+#include "ibinder_internal.h"
+#include "status_internal.h"
+
+using ::android::defaultServiceManager;
+using ::android::IBinder;
+using ::android::IServiceManager;
+using ::android::OK;
+using ::android::sp;
+using ::android::status_t;
+using ::android::String16;
+using ::android::String8;
+using ::android::binder::Status;
+
+#define LOG_ACCESSOR_DEBUG(...)
+// #define LOG_ACCESSOR_DEBUG(...) ALOGW(__VA_ARGS__)
+
+struct ABinderRpc_ConnectionInfo {
+ std::variant<sockaddr_vm, sockaddr_un, sockaddr_in> addr;
+};
+
+struct ABinderRpc_Accessor final : public ::android::RefBase {
+ static ABinderRpc_Accessor* make(const char* instance, const sp<IBinder>& binder) {
+ LOG_ALWAYS_FATAL_IF(binder == nullptr, "ABinderRpc_Accessor requires a non-null binder");
+ status_t status = android::validateAccessor(String16(instance), binder);
+ if (status != OK) {
+ ALOGE("The given binder is not a valid IAccessor for %s. Status: %s", instance,
+ android::statusToString(status).c_str());
+ return nullptr;
+ }
+ return new ABinderRpc_Accessor(binder);
+ }
+
+ sp<IBinder> asBinder() { return mAccessorBinder; }
+
+ ~ABinderRpc_Accessor() { LOG_ACCESSOR_DEBUG("ABinderRpc_Accessor dtor"); }
+
+ private:
+ ABinderRpc_Accessor(sp<IBinder> accessor) : mAccessorBinder(accessor) {}
+ ABinderRpc_Accessor() = delete;
+ sp<IBinder> mAccessorBinder;
+};
+
+struct ABinderRpc_AccessorProvider {
+ public:
+ static ABinderRpc_AccessorProvider* make(std::weak_ptr<android::AccessorProvider> cookie) {
+ if (cookie.expired()) {
+ ALOGE("Null AccessorProvider cookie from libbinder");
+ return nullptr;
+ }
+ return new ABinderRpc_AccessorProvider(cookie);
+ }
+ std::weak_ptr<android::AccessorProvider> mProviderCookie;
+
+ private:
+ ABinderRpc_AccessorProvider() = delete;
+
+ ABinderRpc_AccessorProvider(std::weak_ptr<android::AccessorProvider> provider)
+ : mProviderCookie(provider) {}
+};
+
+struct OnDeleteProviderHolder {
+ OnDeleteProviderHolder(void* data, ABinderRpc_AccessorProviderUserData_deleteCallback onDelete)
+ : mData(data), mOnDelete(onDelete) {}
+ ~OnDeleteProviderHolder() {
+ if (mOnDelete) {
+ mOnDelete(mData);
+ }
+ }
+ void* mData;
+ ABinderRpc_AccessorProviderUserData_deleteCallback mOnDelete;
+ // needs to be copy-able for std::function, but we will never copy it
+ OnDeleteProviderHolder(const OnDeleteProviderHolder&) {
+ LOG_ALWAYS_FATAL("This object can't be copied!");
+ }
+
+ private:
+ OnDeleteProviderHolder() = delete;
+};
+
+ABinderRpc_AccessorProvider* ABinderRpc_registerAccessorProvider(
+ ABinderRpc_AccessorProvider_getAccessorCallback provider, const char** instances,
+ size_t numInstances, void* data,
+ ABinderRpc_AccessorProviderUserData_deleteCallback onDelete) {
+ if (provider == nullptr) {
+ ALOGE("Null provider passed to ABinderRpc_registerAccessorProvider");
+ return nullptr;
+ }
+ if (data && onDelete == nullptr) {
+ ALOGE("If a non-null data ptr is passed to ABinderRpc_registerAccessorProvider, then a "
+ "ABinderRpc_AccessorProviderUserData_deleteCallback must also be passed to delete "
+ "the data object once the ABinderRpc_AccessorProvider is removed.");
+ return nullptr;
+ }
+ if (numInstances == 0 || instances == nullptr) {
+ ALOGE("No instances passed to ABinderRpc_registerAccessorProvider. numInstances: %zu",
+ numInstances);
+ return nullptr;
+ }
+ std::set<std::string> instanceStrings;
+ for (size_t i = 0; i < numInstances; i++) {
+ instanceStrings.emplace(instances[i]);
+ }
+ // call the onDelete when the last reference of this goes away (when the
+ // last reference to the generate std::function goes away).
+ std::shared_ptr<OnDeleteProviderHolder> onDeleteHolder =
+ std::make_shared<OnDeleteProviderHolder>(data, onDelete);
+ android::RpcAccessorProvider generate = [provider,
+ onDeleteHolder](const String16& name) -> sp<IBinder> {
+ ABinderRpc_Accessor* accessor = provider(String8(name).c_str(), onDeleteHolder->mData);
+ if (accessor == nullptr) {
+ ALOGE("The supplied ABinderRpc_AccessorProvider_getAccessorCallback returned nullptr");
+ return nullptr;
+ }
+ sp<IBinder> binder = accessor->asBinder();
+ ABinderRpc_Accessor_delete(accessor);
+ return binder;
+ };
+
+ std::weak_ptr<android::AccessorProvider> cookie =
+ android::addAccessorProvider(std::move(instanceStrings), std::move(generate));
+ return ABinderRpc_AccessorProvider::make(cookie);
+}
+
+void ABinderRpc_unregisterAccessorProvider(ABinderRpc_AccessorProvider* provider) {
+ if (provider == nullptr) {
+ LOG_ALWAYS_FATAL("Attempting to remove a null ABinderRpc_AccessorProvider");
+ }
+
+ status_t status = android::removeAccessorProvider(provider->mProviderCookie);
+ // There shouldn't be a way to get here because the caller won't have a
+ // ABinderRpc_AccessorProvider* without calling ABinderRpc_registerAccessorProvider
+ LOG_ALWAYS_FATAL_IF(status == android::BAD_VALUE, "Provider (%p) is not valid. Status: %s",
+ provider, android::statusToString(status).c_str());
+ LOG_ALWAYS_FATAL_IF(status == android::NAME_NOT_FOUND,
+ "Provider (%p) was already unregistered. Status: %s", provider,
+ android::statusToString(status).c_str());
+ LOG_ALWAYS_FATAL_IF(status != OK,
+ "Unknown error when attempting to unregister ABinderRpc_AccessorProvider "
+ "(%p). Status: %s",
+ provider, android::statusToString(status).c_str());
+
+ delete provider;
+}
+
+struct OnDeleteConnectionInfoHolder {
+ OnDeleteConnectionInfoHolder(void* data,
+ ABinderRpc_ConnectionInfoProviderUserData_delete onDelete)
+ : mData(data), mOnDelete(onDelete) {}
+ ~OnDeleteConnectionInfoHolder() {
+ if (mOnDelete) {
+ mOnDelete(mData);
+ }
+ }
+ void* mData;
+ ABinderRpc_ConnectionInfoProviderUserData_delete mOnDelete;
+ // needs to be copy-able for std::function, but we will never copy it
+ OnDeleteConnectionInfoHolder(const OnDeleteConnectionInfoHolder&) {
+ LOG_ALWAYS_FATAL("This object can't be copied!");
+ }
+
+ private:
+ OnDeleteConnectionInfoHolder() = delete;
+};
+
+ABinderRpc_Accessor* ABinderRpc_Accessor_new(
+ const char* instance, ABinderRpc_ConnectionInfoProvider provider, void* data,
+ ABinderRpc_ConnectionInfoProviderUserData_delete onDelete) {
+ if (instance == nullptr) {
+ ALOGE("Instance argument must be valid when calling ABinderRpc_Accessor_new");
+ return nullptr;
+ }
+ if (data && onDelete == nullptr) {
+ ALOGE("If a non-null data ptr is passed to ABinderRpc_Accessor_new, then a "
+ "ABinderRpc_ConnectionInfoProviderUserData_delete callback must also be passed to "
+ "delete "
+ "the data object once the ABinderRpc_Accessor is deleted.");
+ return nullptr;
+ }
+ std::shared_ptr<OnDeleteConnectionInfoHolder> onDeleteHolder =
+ std::make_shared<OnDeleteConnectionInfoHolder>(data, onDelete);
+ if (provider == nullptr) {
+ ALOGE("Can't create a new ABinderRpc_Accessor without a ABinderRpc_ConnectionInfoProvider "
+ "and it is "
+ "null");
+ return nullptr;
+ }
+ android::RpcSocketAddressProvider generate = [provider, onDeleteHolder](
+ const String16& name, sockaddr* outAddr,
+ size_t addrLen) -> status_t {
+ std::unique_ptr<ABinderRpc_ConnectionInfo> info(
+ provider(String8(name).c_str(), onDeleteHolder->mData));
+ if (info == nullptr) {
+ ALOGE("The supplied ABinderRpc_ConnectionInfoProvider returned nullptr");
+ return android::NAME_NOT_FOUND;
+ }
+ if (auto addr = std::get_if<sockaddr_vm>(&info->addr)) {
+ LOG_ALWAYS_FATAL_IF(addr->svm_family != AF_VSOCK,
+ "ABinderRpc_ConnectionInfo invalid family");
+ if (addrLen < sizeof(sockaddr_vm)) {
+ ALOGE("Provided outAddr is too small! Expecting %zu, got %zu", sizeof(sockaddr_vm),
+ addrLen);
+ return android::BAD_VALUE;
+ }
+ LOG_ACCESSOR_DEBUG(
+ "Connection info provider found AF_VSOCK. family %d, port %d, cid %d",
+ addr->svm_family, addr->svm_port, addr->svm_cid);
+ *reinterpret_cast<sockaddr_vm*>(outAddr) = *addr;
+ } else if (auto addr = std::get_if<sockaddr_un>(&info->addr)) {
+ LOG_ALWAYS_FATAL_IF(addr->sun_family != AF_UNIX,
+ "ABinderRpc_ConnectionInfo invalid family");
+ if (addrLen < sizeof(sockaddr_un)) {
+ ALOGE("Provided outAddr is too small! Expecting %zu, got %zu", sizeof(sockaddr_un),
+ addrLen);
+ return android::BAD_VALUE;
+ }
+ *reinterpret_cast<sockaddr_un*>(outAddr) = *addr;
+ } else if (auto addr = std::get_if<sockaddr_in>(&info->addr)) {
+ LOG_ALWAYS_FATAL_IF(addr->sin_family != AF_INET,
+ "ABinderRpc_ConnectionInfo invalid family");
+ if (addrLen < sizeof(sockaddr_in)) {
+ ALOGE("Provided outAddr is too small! Expecting %zu, got %zu", sizeof(sockaddr_in),
+ addrLen);
+ return android::BAD_VALUE;
+ }
+ *reinterpret_cast<sockaddr_in*>(outAddr) = *addr;
+ } else {
+ LOG_ALWAYS_FATAL(
+ "Unsupported address family type when trying to get ARpcConnection info. A "
+ "new variant was added to the ABinderRpc_ConnectionInfo and this needs to be "
+ "updated.");
+ }
+ return OK;
+ };
+ sp<IBinder> accessorBinder = android::createAccessor(String16(instance), std::move(generate));
+ if (accessorBinder == nullptr) {
+ ALOGE("service manager did not get us an accessor");
+ return nullptr;
+ }
+ LOG_ACCESSOR_DEBUG("service manager found an accessor, so returning one now from _new");
+ return ABinderRpc_Accessor::make(instance, accessorBinder);
+}
+
+void ABinderRpc_Accessor_delete(ABinderRpc_Accessor* accessor) {
+ delete accessor;
+}
+
+AIBinder* ABinderRpc_Accessor_asBinder(ABinderRpc_Accessor* accessor) {
+ if (!accessor) {
+ ALOGE("ABinderRpc_Accessor argument is null.");
+ return nullptr;
+ }
+
+ sp<IBinder> binder = accessor->asBinder();
+ sp<AIBinder> aBinder = ABpBinder::lookupOrCreateFromBinder(binder);
+ AIBinder* ptr = aBinder.get();
+ if (ptr == nullptr) {
+ LOG_ALWAYS_FATAL("Failed to lookupOrCreateFromBinder");
+ }
+ ptr->incStrong(nullptr);
+ return ptr;
+}
+
+ABinderRpc_Accessor* ABinderRpc_Accessor_fromBinder(const char* instance, AIBinder* binder) {
+ if (!binder) {
+ ALOGE("binder argument is null");
+ return nullptr;
+ }
+ sp<IBinder> accessorBinder = binder->getBinder();
+ if (accessorBinder) {
+ return ABinderRpc_Accessor::make(instance, accessorBinder);
+ } else {
+ ALOGE("Attempting to get an ABinderRpc_Accessor for %s but AIBinder::getBinder returned "
+ "null",
+ instance);
+ return nullptr;
+ }
+}
+
+binder_status_t ABinderRpc_Accessor_delegateAccessor(const char* instance, AIBinder* accessor,
+ AIBinder** outDelegator) {
+ LOG_ALWAYS_FATAL_IF(outDelegator == nullptr, "The outDelegator argument is null");
+ if (instance == nullptr || accessor == nullptr) {
+ ALOGW("instance or accessor arguments to ABinderRpc_Accessor_delegateBinder are null");
+ *outDelegator = nullptr;
+ return STATUS_UNEXPECTED_NULL;
+ }
+ sp<IBinder> accessorBinder = accessor->getBinder();
+
+ sp<IBinder> delegator;
+ status_t status = android::delegateAccessor(String16(instance), accessorBinder, &delegator);
+ if (status != OK) {
+ return PruneStatusT(status);
+ }
+ sp<AIBinder> binder = ABpBinder::lookupOrCreateFromBinder(delegator);
+ // This AIBinder needs a strong ref to pass ownership to the caller
+ binder->incStrong(nullptr);
+ *outDelegator = binder.get();
+ return OK;
+}
+
+ABinderRpc_ConnectionInfo* ABinderRpc_ConnectionInfo_new(const sockaddr* addr, socklen_t len) {
+ if (addr == nullptr || len < 0 || static_cast<size_t>(len) < sizeof(sa_family_t)) {
+ ALOGE("Invalid arguments in ABinderRpc_Connection_new");
+ return nullptr;
+ }
+ // socklen_t was int32_t on 32-bit and uint32_t on 64 bit.
+ size_t socklen = len < 0 || static_cast<uintmax_t>(len) > SIZE_MAX ? 0 : len;
+
+ if (addr->sa_family == AF_VSOCK) {
+ if (len != sizeof(sockaddr_vm)) {
+ ALOGE("Incorrect size of %zu for AF_VSOCK sockaddr_vm. Expecting %zu", socklen,
+ sizeof(sockaddr_vm));
+ return nullptr;
+ }
+ sockaddr_vm vm = *reinterpret_cast<const sockaddr_vm*>(addr);
+ LOG_ACCESSOR_DEBUG(
+ "ABinderRpc_ConnectionInfo_new found AF_VSOCK. family %d, port %d, cid %d",
+ vm.svm_family, vm.svm_port, vm.svm_cid);
+ return new ABinderRpc_ConnectionInfo(vm);
+ } else if (addr->sa_family == AF_UNIX) {
+ if (len != sizeof(sockaddr_un)) {
+ ALOGE("Incorrect size of %zu for AF_UNIX sockaddr_un. Expecting %zu", socklen,
+ sizeof(sockaddr_un));
+ return nullptr;
+ }
+ sockaddr_un un = *reinterpret_cast<const sockaddr_un*>(addr);
+ LOG_ACCESSOR_DEBUG("ABinderRpc_ConnectionInfo_new found AF_UNIX. family %d, path %s",
+ un.sun_family, un.sun_path);
+ return new ABinderRpc_ConnectionInfo(un);
+ } else if (addr->sa_family == AF_INET) {
+ if (len != sizeof(sockaddr_in)) {
+ ALOGE("Incorrect size of %zu for AF_INET sockaddr_in. Expecting %zu", socklen,
+ sizeof(sockaddr_in));
+ return nullptr;
+ }
+ sockaddr_in in = *reinterpret_cast<const sockaddr_in*>(addr);
+ LOG_ACCESSOR_DEBUG(
+ "ABinderRpc_ConnectionInfo_new found AF_INET. family %d, address %s, port %d",
+ in.sin_family, inet_ntoa(in.sin_addr), ntohs(in.sin_port));
+ return new ABinderRpc_ConnectionInfo(in);
+ }
+
+ ALOGE("ABinderRpc APIs only support AF_VSOCK right now but the supplied sockaddr::sa_family "
+ "is: %hu",
+ addr->sa_family);
+ return nullptr;
+}
+
+void ABinderRpc_ConnectionInfo_delete(ABinderRpc_ConnectionInfo* info) {
+ delete info;
+}
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index af280d3..ff31dd0 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -18,8 +18,10 @@
#include <android/binder_ibinder_platform.h>
#include <android/binder_stability.h>
#include <android/binder_status.h>
+#include <binder/Functional.h>
#include <binder/IPCThreadState.h>
#include <binder/IResultReceiver.h>
+#include <binder/Trace.h>
#if __has_include(<private/android_filesystem_config.h>)
#include <private/android_filesystem_config.h>
#endif
@@ -40,6 +42,23 @@
using ::android::String16;
using ::android::String8;
using ::android::wp;
+using ::android::binder::impl::make_scope_guard;
+using ::android::binder::impl::scope_guard;
+using ::android::binder::os::get_trace_enabled_tags;
+using ::android::binder::os::trace_begin;
+using ::android::binder::os::trace_end;
+
+// transaction codes for getInterfaceHash and getInterfaceVersion are defined
+// in file : system/tools/aidl/aidl.cpp
+static constexpr int kGetInterfaceVersionId = 0x00fffffe;
+static const char* kInterfaceVersion = "getInterfaceVersion";
+static constexpr int kGetInterfaceHashId = 0x00fffffd;
+static const char* kInterfaceHash = "getInterfaceHash";
+static const char* kNdkTrace = "AIDL::ndk::";
+static const char* kServerTrace = "::server";
+static const char* kClientTrace = "::client";
+static const char* kSeparator = "::";
+static const char* kUnknownCode = "Unknown_Transaction_Code:";
namespace ABBinderTag {
@@ -90,6 +109,51 @@
return sanitized;
}
+const std::string getMethodName(const AIBinder_Class* clazz, transaction_code_t code) {
+ // TODO(b/150155678) - Move getInterfaceHash and getInterfaceVersion to libbinder and remove
+ // hardcoded cases.
+ if (code <= clazz->getTransactionCodeToFunctionLength() && code >= FIRST_CALL_TRANSACTION) {
+ // Codes have FIRST_CALL_TRANSACTION as added offset. Subtract to access function name
+ return clazz->getFunctionName(code);
+ } else if (code == kGetInterfaceVersionId) {
+ return kInterfaceVersion;
+ } else if (code == kGetInterfaceHashId) {
+ return kInterfaceHash;
+ }
+ return kUnknownCode + std::to_string(code);
+}
+
+const std::string getTraceSectionName(const AIBinder_Class* clazz, transaction_code_t code,
+ bool isServer) {
+ if (clazz == nullptr) {
+ ALOGE("class associated with binder is null. Class is needed to add trace with interface "
+ "name and function name");
+ return kNdkTrace;
+ }
+
+ const std::string descriptor = clazz->getInterfaceDescriptorUtf8();
+ const std::string methodName = getMethodName(clazz, code);
+
+ size_t traceSize =
+ strlen(kNdkTrace) + descriptor.size() + strlen(kSeparator) + methodName.size();
+ traceSize += isServer ? strlen(kServerTrace) : strlen(kClientTrace);
+
+ std::string trace;
+ // reserve to avoid repeated allocations
+ trace.reserve(traceSize);
+
+ trace += kNdkTrace;
+ trace += clazz->getInterfaceDescriptorUtf8();
+ trace += kSeparator;
+ trace += methodName;
+ trace += isServer ? kServerTrace : kClientTrace;
+
+ LOG_ALWAYS_FATAL_IF(trace.size() != traceSize, "Trace size mismatch. Expected %zu, got %zu",
+ traceSize, trace.size());
+
+ return trace;
+}
+
bool AIBinder::associateClass(const AIBinder_Class* clazz) {
if (clazz == nullptr) return false;
@@ -203,6 +267,17 @@
status_t ABBinder::onTransact(transaction_code_t code, const Parcel& data, Parcel* reply,
binder_flags_t flags) {
+ std::string sectionName;
+ bool tracingEnabled = get_trace_enabled_tags() & ATRACE_TAG_AIDL;
+ if (tracingEnabled) {
+ sectionName = getTraceSectionName(getClass(), code, true /*isServer*/);
+ trace_begin(ATRACE_TAG_AIDL, sectionName.c_str());
+ }
+
+ scope_guard guard = make_scope_guard([&]() {
+ if (tracingEnabled) trace_end(ATRACE_TAG_AIDL);
+ });
+
if (isUserCommand(code)) {
if (getClass()->writeHeader && !data.checkInterface(this)) {
return STATUS_BAD_TYPE;
@@ -385,6 +460,31 @@
mInterfaceDescriptor(interfaceDescriptor),
mWideInterfaceDescriptor(interfaceDescriptor) {}
+bool AIBinder_Class::setTransactionCodeMap(const char** transactionCodeMap, size_t length) {
+ if (mTransactionCodeToFunction != nullptr) {
+ ALOGE("mTransactionCodeToFunction is already set!");
+ return false;
+ }
+ mTransactionCodeToFunction = transactionCodeMap;
+ mTransactionCodeToFunctionLength = length;
+ return true;
+}
+
+const char* AIBinder_Class::getFunctionName(transaction_code_t code) const {
+ if (mTransactionCodeToFunction == nullptr) {
+ ALOGE("mTransactionCodeToFunction is not set!");
+ return nullptr;
+ }
+
+ if (code < FIRST_CALL_TRANSACTION ||
+ code - FIRST_CALL_TRANSACTION >= mTransactionCodeToFunctionLength) {
+ ALOGE("Function name for requested code not found!");
+ return nullptr;
+ }
+
+ return mTransactionCodeToFunction[code - FIRST_CALL_TRANSACTION];
+}
+
AIBinder_Class* AIBinder_Class_define(const char* interfaceDescriptor,
AIBinder_Class_onCreate onCreate,
AIBinder_Class_onDestroy onDestroy,
@@ -404,6 +504,24 @@
clazz->onDump = onDump;
}
+void AIBinder_Class_setTransactionCodeToFunctionNameMap(AIBinder_Class* clazz,
+ const char** transactionCodeToFunction,
+ size_t length) {
+ LOG_ALWAYS_FATAL_IF(clazz == nullptr || transactionCodeToFunction == nullptr,
+ "Valid clazz and transactionCodeToFunction are needed to set code to "
+ "function mapping.");
+ LOG_ALWAYS_FATAL_IF(!clazz->setTransactionCodeMap(transactionCodeToFunction, length),
+ "Failed to set transactionCodeToFunction to clazz! Is "
+ "transactionCodeToFunction already set?");
+}
+
+const char* AIBinder_Class_getFunctionName(AIBinder_Class* clazz, transaction_code_t code) {
+ LOG_ALWAYS_FATAL_IF(
+ clazz == nullptr,
+ "Valid clazz is needed to get function name for requested transaction code");
+ return clazz->getFunctionName(code);
+}
+
void AIBinder_Class_disableInterfaceTokenHeader(AIBinder_Class* clazz) {
LOG_ALWAYS_FATAL_IF(clazz == nullptr, "disableInterfaceTokenHeader requires non-null clazz");
@@ -734,6 +852,19 @@
binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, AParcel** in,
AParcel** out, binder_flags_t flags) {
+ const AIBinder_Class* clazz = binder ? binder->getClass() : nullptr;
+
+ std::string sectionName;
+ bool tracingEnabled = get_trace_enabled_tags() & ATRACE_TAG_AIDL;
+ if (tracingEnabled) {
+ sectionName = getTraceSectionName(clazz, code, false /*isServer*/);
+ trace_begin(ATRACE_TAG_AIDL, sectionName.c_str());
+ }
+
+ scope_guard guard = make_scope_guard([&]() {
+ if (tracingEnabled) trace_end(ATRACE_TAG_AIDL);
+ });
+
if (in == nullptr) {
ALOGE("%s: requires non-null in parameter", __func__);
return STATUS_UNEXPECTED_NULL;
@@ -872,4 +1003,4 @@
"AIBinder_setInheritRt must be called on a local binder");
localBinder->setInheritRt(inheritRt);
-}
+}
\ No newline at end of file
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index f5b738c..a93dc1f 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -132,6 +132,9 @@
const ::android::String16& getInterfaceDescriptor() const { return mWideInterfaceDescriptor; }
const char* getInterfaceDescriptorUtf8() const { return mInterfaceDescriptor.c_str(); }
+ bool setTransactionCodeMap(const char** transactionCodeMap, size_t transactionCodeMapSize);
+ const char* getFunctionName(transaction_code_t code) const;
+ size_t getTransactionCodeToFunctionLength() const { return mTransactionCodeToFunctionLength; }
// whether a transaction header should be written
bool writeHeader = true;
@@ -151,6 +154,10 @@
// This must be a String16 since BBinder virtual getInterfaceDescriptor returns a reference to
// one.
const ::android::String16 mWideInterfaceDescriptor;
+ // Array which holds names of the functions
+ const char** mTransactionCodeToFunction = nullptr;
+ // length of mmTransactionCodeToFunctionLength array
+ size_t mTransactionCodeToFunctionLength = 0;
};
// Ownership is like this (when linked to death):
diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
index af56bf0..0ad110e 100644
--- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -30,6 +30,17 @@
#include <android/binder_auto_utils.h>
#include <android/binder_ibinder.h>
+#if defined(__ANDROID_VENDOR_API__)
+#include <android/llndk-versioning.h>
+#elif !defined(API_LEVEL_AT_LEAST)
+#if defined(__BIONIC__)
+#define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) \
+ (__builtin_available(android sdk_api_level, *))
+#else
+#define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) (true)
+#endif // __BIONIC__
+#endif // __ANDROID_VENDOR_API__
+
#if __has_include(<android/binder_shell.h>)
#include <android/binder_shell.h>
#define HAS_BINDER_SHELL_COMMAND
@@ -164,6 +175,10 @@
* Helper method to create a class
*/
static inline AIBinder_Class* defineClass(const char* interfaceDescriptor,
+ AIBinder_Class_onTransact onTransact,
+ const char** codeToFunction, size_t functionCount);
+
+ static inline AIBinder_Class* defineClass(const char* interfaceDescriptor,
AIBinder_Class_onTransact onTransact);
private:
@@ -256,6 +271,13 @@
AIBinder_Class* ICInterface::defineClass(const char* interfaceDescriptor,
AIBinder_Class_onTransact onTransact) {
+
+ return defineClass(interfaceDescriptor, onTransact, nullptr, 0);
+}
+
+AIBinder_Class* ICInterface::defineClass(const char* interfaceDescriptor,
+ AIBinder_Class_onTransact onTransact,
+ const char** codeToFunction, size_t functionCount) {
AIBinder_Class* clazz = AIBinder_Class_define(interfaceDescriptor, ICInterfaceData::onCreate,
ICInterfaceData::onDestroy, onTransact);
if (clazz == nullptr) {
@@ -274,6 +296,19 @@
AIBinder_Class_setHandleShellCommand(clazz, ICInterfaceData::handleShellCommand);
}
#endif
+
+#if defined(__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__) || __ANDROID_API__ >= 36
+ if API_LEVEL_AT_LEAST (36, 202504) {
+ if (codeToFunction != nullptr &&
+ (&AIBinder_Class_setTransactionCodeToFunctionNameMap != nullptr)) {
+ AIBinder_Class_setTransactionCodeToFunctionNameMap(clazz, codeToFunction,
+ functionCount);
+ }
+ }
+#else
+ (void)codeToFunction;
+ (void)functionCount;
+#endif // defined(__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__) || __ANDROID_API__ >= 36
return clazz;
}
diff --git a/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h b/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h
index c1d0e9f..83976b3 100644
--- a/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h
+++ b/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h
@@ -22,8 +22,8 @@
#include <set>
#include <sstream>
-// Include llndk-versioning.h only for vendor build as it is not available for NDK headers.
-#if defined(__ANDROID_VENDOR__)
+// Include llndk-versioning.h only for non-system build as it is not available for NDK headers.
+#if defined(__ANDROID_VENDOR_API__)
#include <android/llndk-versioning.h>
#elif !defined(API_LEVEL_AT_LEAST)
#if defined(__BIONIC__)
@@ -32,7 +32,7 @@
#else
#define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) (true)
#endif // __BIONIC__
-#endif // __ANDROID_VENDOR__
+#endif // __ANDROID_VENDOR_API__
namespace aidl::android::os {
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index 72d255e..bd46c47 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -219,6 +219,50 @@
void AIBinder_Class_setOnDump(AIBinder_Class* clazz, AIBinder_onDump onDump) __INTRODUCED_IN(29);
/**
+ * Associates a mapping of transaction codes(transaction_code_t) to function names for the given
+ * class.
+ *
+ * Trace messages will use the provided names instead of bare integer codes when set. If not set by
+ * this function, trace messages will only be identified by the bare code. This should be called one
+ * time during clazz initialization. clazz is defined using AIBinder_Class_define and
+ * transactionCodeToFunctionMap should have same scope as clazz. Resetting/clearing the
+ * transactionCodeToFunctionMap is not allowed. Passing null for either clazz or
+ * transactionCodeToFunctionMap will abort.
+ *
+ * Available since API level 36.
+ *
+ * \param clazz class which should use this transaction to code function map.
+ * \param transactionCodeToFunctionMap array of function names indexed by transaction code.
+ * Transaction codes start from 1, functions with transaction code 1 will correspond to index 0 in
+ * transactionCodeToFunctionMap. When defining methods, transaction codes are expected to be
+ * contiguous, and this is required for maximum memory efficiency.
+ * You can use nullptr if certain transaction codes are not used. Lifetime should be same as clazz.
+ * \param length number of elements in the transactionCodeToFunctionMap
+ */
+void AIBinder_Class_setTransactionCodeToFunctionNameMap(AIBinder_Class* clazz,
+ const char** transactionCodeToFunctionMap,
+ size_t length) __INTRODUCED_IN(36);
+
+/**
+ * Get function name associated with transaction code for given class
+ *
+ * This function returns function name associated with provided transaction code for given class.
+ * AIBinder_Class_setTransactionCodeToFunctionNameMap should be called first to associate function
+ * to transaction code mapping.
+ *
+ * Available since API level 36.
+ *
+ * \param clazz class for which function name is requested
+ * \param transactionCode transaction_code_t for which function name is requested.
+ *
+ * \return function name in form of const char* if transaction code is valid for given class.
+ * The value returned is valid for the lifetime of clazz. if transaction code is invalid or
+ * transactionCodeToFunctionMap is not set, nullptr is returned.
+ */
+const char* AIBinder_Class_getFunctionName(AIBinder_Class* clazz, transaction_code_t code)
+ __INTRODUCED_IN(36);
+
+/**
* This tells users of this class not to use a transaction header. By default, libbinder_ndk users
* read/write transaction headers implicitly (in the SDK, this must be manually written by
* android.os.Parcel#writeInterfaceToken, and it is read/checked with
diff --git a/libs/binder/ndk/include_ndk/android/persistable_bundle.h b/libs/binder/ndk/include_ndk/android/persistable_bundle.h
index 5e0d4da..1d516ae 100644
--- a/libs/binder/ndk/include_ndk/android/persistable_bundle.h
+++ b/libs/binder/ndk/include_ndk/android/persistable_bundle.h
@@ -17,13 +17,6 @@
#pragma once
#include <android/binder_parcel.h>
-#if defined(__ANDROID_VENDOR__)
-#include <android/llndk-versioning.h>
-#else
-#if !defined(__INTRODUCED_IN_LLNDK)
-#define __INTRODUCED_IN_LLNDK(level) __attribute__((annotate("introduced_in_llndk=" #level)))
-#endif
-#endif // __ANDROID_VENDOR__
#include <stdbool.h>
#include <stdint.h>
#include <sys/cdefs.h>
@@ -83,8 +76,7 @@
*
* \return Pointer to a new APersistableBundle
*/
-APersistableBundle* _Nullable APersistableBundle_new() __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+APersistableBundle* _Nullable APersistableBundle_new() __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Create a new APersistableBundle based off an existing APersistableBundle.
@@ -98,7 +90,7 @@
* \return Pointer to a new APersistableBundle
*/
APersistableBundle* _Nullable APersistableBundle_dup(const APersistableBundle* _Nonnull pBundle)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Delete an APersistableBundle. This must always be called when finished using
@@ -109,7 +101,7 @@
* Available since API level 202404.
*/
void APersistableBundle_delete(APersistableBundle* _Nullable pBundle)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Check for equality of APersistableBundles.
@@ -123,7 +115,7 @@
*/
bool APersistableBundle_isEqual(const APersistableBundle* _Nonnull lhs,
const APersistableBundle* _Nonnull rhs)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Read an APersistableBundle from an AParcel.
@@ -142,7 +134,7 @@
*/
binder_status_t APersistableBundle_readFromParcel(
const AParcel* _Nonnull parcel, APersistableBundle* _Nullable* _Nonnull outPBundle)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Write an APersistableBundle to an AParcel.
@@ -162,7 +154,7 @@
*/
binder_status_t APersistableBundle_writeToParcel(const APersistableBundle* _Nonnull pBundle,
AParcel* _Nonnull parcel)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get the size of an APersistableBundle. This is the number of mappings in the
@@ -175,7 +167,7 @@
* \return number of mappings in the object
*/
int32_t APersistableBundle_size(const APersistableBundle* _Nonnull pBundle)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Erase any entries added with the provided key.
@@ -188,7 +180,7 @@
* \return number of entries erased. Either 0 or 1.
*/
int32_t APersistableBundle_erase(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Put a boolean associated with the provided key.
@@ -201,8 +193,7 @@
* Available since API level 202404.
*/
void APersistableBundle_putBoolean(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key,
- bool val) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ bool val) __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Put an int32_t associated with the provided key.
@@ -215,8 +206,7 @@
* Available since API level 202404.
*/
void APersistableBundle_putInt(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key,
- int32_t val) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ int32_t val) __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Put an int64_t associated with the provided key.
@@ -229,8 +219,7 @@
* Available since API level 202404.
*/
void APersistableBundle_putLong(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key,
- int64_t val) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ int64_t val) __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Put a double associated with the provided key.
@@ -243,8 +232,7 @@
* Available since API level 202404.
*/
void APersistableBundle_putDouble(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key,
- double val) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ double val) __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Put a string associated with the provided key.
@@ -258,8 +246,7 @@
* Available since API level 202404.
*/
void APersistableBundle_putString(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key,
- const char* _Nonnull val) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ const char* _Nonnull val) __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Put a boolean vector associated with the provided key.
@@ -275,8 +262,7 @@
*/
void APersistableBundle_putBooleanVector(APersistableBundle* _Nonnull pBundle,
const char* _Nonnull key, const bool* _Nonnull vec,
- int32_t num) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ int32_t num) __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Put an int32_t vector associated with the provided key.
@@ -292,7 +278,7 @@
*/
void APersistableBundle_putIntVector(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key,
const int32_t* _Nonnull vec, int32_t num)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Put an int64_t vector associated with the provided key.
@@ -308,8 +294,7 @@
*/
void APersistableBundle_putLongVector(APersistableBundle* _Nonnull pBundle,
const char* _Nonnull key, const int64_t* _Nonnull vec,
- int32_t num) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ int32_t num) __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Put a double vector associated with the provided key.
@@ -325,8 +310,7 @@
*/
void APersistableBundle_putDoubleVector(APersistableBundle* _Nonnull pBundle,
const char* _Nonnull key, const double* _Nonnull vec,
- int32_t num) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ int32_t num) __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Put a string vector associated with the provided key.
@@ -343,7 +327,7 @@
void APersistableBundle_putStringVector(APersistableBundle* _Nonnull pBundle,
const char* _Nonnull key,
const char* _Nullable const* _Nullable vec, int32_t num)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Put an APersistableBundle associated with the provided key.
@@ -359,7 +343,7 @@
void APersistableBundle_putPersistableBundle(APersistableBundle* _Nonnull pBundle,
const char* _Nonnull key,
const APersistableBundle* _Nonnull val)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get a boolean associated with the provided key.
@@ -374,7 +358,7 @@
*/
bool APersistableBundle_getBoolean(const APersistableBundle* _Nonnull pBundle,
const char* _Nonnull key, bool* _Nonnull val)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get an int32_t associated with the provided key.
@@ -388,8 +372,7 @@
* \return true if a value exists for the provided key
*/
bool APersistableBundle_getInt(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key,
- int32_t* _Nonnull val) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ int32_t* _Nonnull val) __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get an int64_t associated with the provided key.
@@ -404,7 +387,7 @@
*/
bool APersistableBundle_getLong(const APersistableBundle* _Nonnull pBundle,
const char* _Nonnull key, int64_t* _Nonnull val)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get a double associated with the provided key.
@@ -419,7 +402,7 @@
*/
bool APersistableBundle_getDouble(const APersistableBundle* _Nonnull pBundle,
const char* _Nonnull key, double* _Nonnull val)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get a string associated with the provided key.
@@ -440,8 +423,7 @@
int32_t APersistableBundle_getString(const APersistableBundle* _Nonnull pBundle,
const char* _Nonnull key, char* _Nullable* _Nonnull val,
APersistableBundle_stringAllocator stringAllocator,
- void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get a boolean vector associated with the provided key and place it in the
@@ -468,7 +450,7 @@
int32_t APersistableBundle_getBooleanVector(const APersistableBundle* _Nonnull pBundle,
const char* _Nonnull key, bool* _Nullable buffer,
int32_t bufferSizeBytes)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get an int32_t vector associated with the provided key and place it in the
@@ -494,8 +476,7 @@
*/
int32_t APersistableBundle_getIntVector(const APersistableBundle* _Nonnull pBundle,
const char* _Nonnull key, int32_t* _Nullable buffer,
- int32_t bufferSizeBytes) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ int32_t bufferSizeBytes) __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get an int64_t vector associated with the provided key and place it in the
@@ -521,8 +502,8 @@
*/
int32_t APersistableBundle_getLongVector(const APersistableBundle* _Nonnull pBundle,
const char* _Nonnull key, int64_t* _Nullable buffer,
- int32_t bufferSizeBytes) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ int32_t bufferSizeBytes)
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get a double vector associated with the provided key and place it in the
@@ -549,7 +530,7 @@
int32_t APersistableBundle_getDoubleVector(const APersistableBundle* _Nonnull pBundle,
const char* _Nonnull key, double* _Nullable buffer,
int32_t bufferSizeBytes)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get a string vector associated with the provided key and place it in the
@@ -586,7 +567,7 @@
int32_t bufferSizeBytes,
APersistableBundle_stringAllocator stringAllocator,
void* _Nullable context)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get an APersistableBundle* associated with the provided key.
@@ -605,7 +586,7 @@
bool APersistableBundle_getPersistableBundle(const APersistableBundle* _Nonnull pBundle,
const char* _Nonnull key,
APersistableBundle* _Nullable* _Nonnull outBundle)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get all of the keys associated with this specific type and place it in the
@@ -638,7 +619,7 @@
int32_t bufferSizeBytes,
APersistableBundle_stringAllocator stringAllocator,
void* _Nullable context)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get all of the keys associated with this specific type and place it in the
@@ -669,8 +650,7 @@
int32_t APersistableBundle_getIntKeys(const APersistableBundle* _Nonnull pBundle,
char* _Nullable* _Nullable outKeys, int32_t bufferSizeBytes,
APersistableBundle_stringAllocator stringAllocator,
- void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get all of the keys associated with this specific type and place it in the
@@ -701,8 +681,7 @@
int32_t APersistableBundle_getLongKeys(const APersistableBundle* _Nonnull pBundle,
char* _Nullable* _Nullable outKeys, int32_t bufferSizeBytes,
APersistableBundle_stringAllocator stringAllocator,
- void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get all of the keys associated with this specific type and place it in the
@@ -734,8 +713,8 @@
char* _Nullable* _Nullable outKeys,
int32_t bufferSizeBytes,
APersistableBundle_stringAllocator stringAllocator,
- void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ void* _Nullable context)
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get all of the keys associated with this specific type and place it in the
@@ -767,8 +746,8 @@
char* _Nullable* _Nullable outKeys,
int32_t bufferSizeBytes,
APersistableBundle_stringAllocator stringAllocator,
- void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ void* _Nullable context)
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get all of the keys associated with this specific type and place it in the
@@ -801,7 +780,7 @@
int32_t bufferSizeBytes,
APersistableBundle_stringAllocator stringAllocator,
void* _Nullable context)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get all of the keys associated with this specific type and place it in the
@@ -834,7 +813,7 @@
int32_t bufferSizeBytes,
APersistableBundle_stringAllocator stringAllocator,
void* _Nullable context)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get all of the keys associated with this specific type and place it in the
@@ -867,7 +846,7 @@
int32_t bufferSizeBytes,
APersistableBundle_stringAllocator stringAllocator,
void* _Nullable context)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get all of the keys associated with this specific type and place it in the
@@ -899,7 +878,7 @@
int32_t bufferSizeBytes,
APersistableBundle_stringAllocator stringAllocator,
void* _Nullable context)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get all of the keys associated with this specific type and place it in the
@@ -932,7 +911,7 @@
int32_t bufferSizeBytes,
APersistableBundle_stringAllocator stringAllocator,
void* _Nullable context)
- __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Get all of the keys associated with this specific type and place it in the
@@ -963,6 +942,6 @@
int32_t APersistableBundle_getPersistableBundleKeys(
const APersistableBundle* _Nonnull pBundle, char* _Nullable* _Nullable outKeys,
int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator,
- void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404);
+ void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__);
__END_DECLS
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index 41b30a0..cc4943b 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -18,7 +18,6 @@
#include <android/binder_ibinder.h>
#include <android/binder_status.h>
-#include <android/llndk-versioning.h>
#include <sys/cdefs.h>
__BEGIN_DECLS
@@ -257,8 +256,7 @@
* \return the result of dlopen of the specified HAL
*/
void* AServiceManager_openDeclaredPassthroughHal(const char* interface, const char* instance,
- int flag) __INTRODUCED_IN(__ANDROID_API_V__)
- __INTRODUCED_IN_LLNDK(202404);
+ int flag) __INTRODUCED_IN(__ANDROID_API_V__);
/**
* Prevent lazy services without client from shutting down their process
diff --git a/libs/binder/ndk/include_platform/android/binder_rpc.h b/libs/binder/ndk/include_platform/android/binder_rpc.h
new file mode 100644
index 0000000..9fe5d78
--- /dev/null
+++ b/libs/binder/ndk/include_platform/android/binder_rpc.h
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2024 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 <android/binder_ibinder.h>
+#include <sys/socket.h>
+
+__BEGIN_DECLS
+
+/**
+ * @defgroup ABinderRpc Binder RPC
+ *
+ * This set of APIs makes it possible for a process to use the AServiceManager
+ * APIs to get binder objects for services that are available over sockets
+ * instead of the traditional kernel binder with the extra ServiceManager
+ * process.
+ *
+ * These APIs are used to supply libbinder with enough information to create
+ * and manage the socket connections underneath the ServiceManager APIs so the
+ * clients do not need to know the service implementation details or what
+ * transport they use for communication.
+ *
+ * @{
+ */
+
+/**
+ * This represents an IAccessor implementation from libbinder that is
+ * responsible for providing a pre-connected socket file descriptor for a
+ * specific service. The service is an RpcServer and the pre-connected socket is
+ * used to set up a client RpcSession underneath libbinder's IServiceManager APIs
+ * to provide the client with the service's binder for remote communication.
+ */
+typedef struct ABinderRpc_Accessor ABinderRpc_Accessor;
+
+/**
+ * This represents an object that supplies ABinderRpc_Accessors to libbinder
+ * when they are requested. They are requested any time a client is attempting
+ * to get a service through IServiceManager APIs when the services aren't known by
+ * servicemanager.
+ */
+typedef struct ABinderRpc_AccessorProvider ABinderRpc_AccessorProvider;
+
+/**
+ * This represents information necessary for libbinder to be able to connect to a
+ * remote service.
+ * It supports connecting to linux sockets and is created using sockaddr
+ * types for sockets supported by libbinder like sockaddr_in, sockaddr_un,
+ * sockaddr_vm.
+ */
+typedef struct ABinderRpc_ConnectionInfo ABinderRpc_ConnectionInfo;
+
+/**
+ * These APIs provide a way for clients of binder services to be able to get a
+ * binder object of that service through the existing libbinder/libbinder_ndk
+ * Service Manager APIs when that service is using RPC Binder over sockets
+ * instead kernel binder.
+ *
+ * Some of these APIs are used on Android hosts when kernel binder is supported
+ * and the usual servicemanager process is available. Some of these APIs are
+ * only required when there is no kernel binder or extra servicemanager process
+ * such as the case of microdroid or similar VMs.
+ */
+
+/**
+ * This callback is responsible for returning ABinderRpc_Accessor objects for a given
+ * service instance. These ABinderRpc_Accessor objects are implemented by
+ * libbinder_ndk and backed by implementations of android::os::IAccessor in
+ * libbinder.
+ *
+ * \param instance name of the service like
+ * `android.hardware.vibrator.IVibrator/default`. This string must remain
+ * valid and unchanged for the duration of this function call.
+ * \param data the data that was associated with this instance when the callback
+ * was registered.
+ * \return The ABinderRpc_Accessor associated with the service `instance`. This
+ * callback gives up ownership of the object once it returns it. The
+ * caller of this callback (libbinder_ndk) is responsible for deleting it
+ * with ABinderRpc_Accessor_delete.
+ */
+typedef ABinderRpc_Accessor* _Nullable (*ABinderRpc_AccessorProvider_getAccessorCallback)(
+ const char* _Nonnull instance, void* _Nullable data);
+
+/**
+ * This callback is responsible deleting the `void* data` object that is passed
+ * in to ABinderRpc_registerAccessorProvider for the ABinderRpc_AccessorProvider_getAccessorCallback
+ * to use. That object is owned by the ABinderRpc_AccessorProvider and must remain valid for the
+ * lifetime of the callback because it may be called and use the object.
+ * This _delete callback is called after the ABinderRpc_AccessorProvider is remove and
+ * is guaranteed never to be called again.
+ *
+ * \param data a pointer to data that the ABinderRpc_AccessorProvider_getAccessorCallback uses which
+ * is to be deleted by this call.
+ */
+typedef void (*ABinderRpc_AccessorProviderUserData_deleteCallback)(void* _Nullable data);
+
+/**
+ * Inject an ABinderRpc_AccessorProvider_getAccessorCallback into the process for
+ * the Service Manager APIs to use to retrieve ABinderRpc_Accessor objects associated
+ * with different RPC Binder services.
+ *
+ * \param provider callback that returns ABinderRpc_Accessors for libbinder to set up
+ * RPC clients with.
+ * \param instances array of instances that are supported by this provider. It
+ * will only be called if the client is looking for an instance that is
+ * in this list. These instances must be unique per-process. If an
+ * instance is being registered that was previously registered, this call
+ * will fail and the ABinderRpc_AccessorProviderUserData_deleteCallback
+ * will be called to clean up the data.
+ * This array of strings must remain valid and unchanged for the duration
+ * of this function call.
+ * \param number of instances in the instances array.
+ * \param data pointer that is passed to the ABinderRpc_AccessorProvider callback.
+ * IMPORTANT: The ABinderRpc_AccessorProvider now OWNS that object that data
+ * points to. It can be used as necessary in the callback. The data MUST
+ * remain valid for the lifetime of the provider callback.
+ * Do not attempt to give ownership of the same object to different
+ * providers through multiple calls to this function because the first
+ * one to be deleted will call the onDelete callback.
+ * \param onDelete callback used to delete the objects that `data` points to.
+ * This is called after ABinderRpc_AccessorProvider is guaranteed to never be
+ * called again. Before this callback is called, `data` must remain
+ * valid.
+ * \return nullptr on error if the data pointer is non-null and the onDelete
+ * callback is null or if an instance in the instances list was previously
+ * registered. In the error case of duplicate instances, if data was
+ * provided with a ABinderRpc_AccessorProviderUserData_deleteCallback,
+ * the callback will be called to delete the data.
+ * Otherwise returns a pointer to the ABinderRpc_AccessorProvider that
+ * can be used to remove with ABinderRpc_unregisterAccessorProvider.
+ */
+ABinderRpc_AccessorProvider* _Nullable ABinderRpc_registerAccessorProvider(
+ ABinderRpc_AccessorProvider_getAccessorCallback _Nonnull provider,
+ const char* _Nullable* _Nonnull instances, size_t numInstances, void* _Nullable data,
+ ABinderRpc_AccessorProviderUserData_deleteCallback _Nullable onDelete) __INTRODUCED_IN(36);
+
+/**
+ * Remove an ABinderRpc_AccessorProvider from libbinder. This will remove references
+ * from the ABinderRpc_AccessorProvider and will no longer call the
+ * ABinderRpc_AccessorProvider_getAccessorCallback.
+ *
+ * Note: The `data` object that was used when adding the accessor will be
+ * deleted by the ABinderRpc_AccessorProviderUserData_deleteCallback at some
+ * point after this call. Do not use the object and do not try to delete
+ * it through any other means.
+ * Note: This will abort when used incorrectly if this provider was never
+ * registered or if it were already unregistered.
+ *
+ * \param provider to be removed and deleted
+ *
+ */
+void ABinderRpc_unregisterAccessorProvider(ABinderRpc_AccessorProvider* _Nonnull provider)
+ __INTRODUCED_IN(36);
+
+/**
+ * Callback which returns the RPC connection information for libbinder to use to
+ * connect to a socket that a given service is listening on. This is needed to
+ * create an ABinderRpc_Accessor so it can connect to these services.
+ *
+ * \param instance name of the service to connect to. This string must remain
+ * valid and unchanged for the duration of this function call.
+ * \param data user data for this callback. The pointer is provided in
+ * ABinderRpc_Accessor_new.
+ * \return ABinderRpc_ConnectionInfo with socket connection information for `instance`
+ */
+typedef ABinderRpc_ConnectionInfo* _Nullable (*ABinderRpc_ConnectionInfoProvider)(
+ const char* _Nonnull instance, void* _Nullable data) __INTRODUCED_IN(36);
+/**
+ * This callback is responsible deleting the `void* data` object that is passed
+ * in to ABinderRpc_Accessor_new for the ABinderRpc_ConnectionInfoProvider to use. That
+ * object is owned by the ABinderRpc_Accessor and must remain valid for the
+ * lifetime the Accessor because it may be used by the connection info provider
+ * callback.
+ * This _delete callback is called after the ABinderRpc_Accessor is removed and
+ * is guaranteed never to be called again.
+ *
+ * \param data a pointer to data that the ABinderRpc_AccessorProvider uses which is to
+ * be deleted by this call.
+ */
+typedef void (*ABinderRpc_ConnectionInfoProviderUserData_delete)(void* _Nullable data);
+
+/**
+ * Create a new ABinderRpc_Accessor. This creates an IAccessor object in libbinder
+ * that can use the info from the ABinderRpc_ConnectionInfoProvider to connect to a
+ * socket that the service with `instance` name is listening to.
+ *
+ * \param instance name of the service that is listening on the socket. This
+ * string must remain valid and unchanged for the duration of this
+ * function call.
+ * \param provider callback that can get the socket connection information for the
+ * instance. This connection information may be dynamic, so the
+ * provider will be called any time a new connection is required.
+ * \param data pointer that is passed to the ABinderRpc_ConnectionInfoProvider callback.
+ * IMPORTANT: The ABinderRpc_ConnectionInfoProvider now OWNS that object that data
+ * points to. It can be used as necessary in the callback. The data MUST
+ * remain valid for the lifetime of the provider callback.
+ * Do not attempt to give ownership of the same object to different
+ * providers through multiple calls to this function because the first
+ * one to be deleted will call the onDelete callback.
+ * \param onDelete callback used to delete the objects that `data` points to.
+ * This is called after ABinderRpc_ConnectionInfoProvider is guaranteed to never be
+ * called again. Before this callback is called, `data` must remain
+ * valid.
+ * \return an ABinderRpc_Accessor instance. This is deleted by the caller once it is
+ * no longer needed.
+ */
+ABinderRpc_Accessor* _Nullable ABinderRpc_Accessor_new(
+ const char* _Nonnull instance, ABinderRpc_ConnectionInfoProvider _Nonnull provider,
+ void* _Nullable data, ABinderRpc_ConnectionInfoProviderUserData_delete _Nullable onDelete)
+ __INTRODUCED_IN(36);
+
+/**
+ * Delete an ABinderRpc_Accessor
+ *
+ * \param accessor to delete
+ */
+void ABinderRpc_Accessor_delete(ABinderRpc_Accessor* _Nonnull accessor) __INTRODUCED_IN(36);
+
+/**
+ * Return the AIBinder associated with an ABinderRpc_Accessor. This can be used to
+ * send the Accessor to another process or even register it with servicemanager.
+ *
+ * \param accessor to get the AIBinder for
+ * \return binder of the supplied accessor with one strong ref count
+ */
+AIBinder* _Nullable ABinderRpc_Accessor_asBinder(ABinderRpc_Accessor* _Nonnull accessor)
+ __INTRODUCED_IN(36);
+
+/**
+ * Return the ABinderRpc_Accessor associated with an AIBinder. The instance must match
+ * the ABinderRpc_Accessor implementation.
+ * This can be used when receiving an AIBinder from another process that the
+ * other process obtained from ABinderRpc_Accessor_asBinder.
+ *
+ * \param instance name of the service that the Accessor is responsible for.
+ * This string must remain valid and unchanged for the duration of this
+ * function call.
+ * \param accessorBinder proxy binder from another process's ABinderRpc_Accessor.
+ * This function preserves the refcount of this binder object and the
+ * caller still owns it.
+ * \return ABinderRpc_Accessor representing the other processes ABinderRpc_Accessor
+ * implementation. The caller owns this ABinderRpc_Accessor instance and
+ * is responsible for deleting it with ABinderRpc_Accessor_delete or
+ * passing ownership of it elsewhere, like returning it through
+ * ABinderRpc_AccessorProvider_getAccessorCallback.
+ * nullptr on error when the accessorBinder is not a valid binder from
+ * an IAccessor implementation or the IAccessor implementation is not
+ * associated with the provided instance.
+ */
+ABinderRpc_Accessor* _Nullable ABinderRpc_Accessor_fromBinder(const char* _Nonnull instance,
+ AIBinder* _Nonnull accessorBinder)
+ __INTRODUCED_IN(36);
+
+/**
+ * Wrap an ABinderRpc_Accessor proxy binder with a delegator binder.
+ *
+ * The IAccessorDelegator binder delegates all calls to the proxy binder.
+ *
+ * This is required only in very specific situations when the process that has
+ * permissions to connect the to RPC service's socket and create the FD for it
+ * is in a separate process from this process that wants to serve the Accessor
+ * binder and the communication between these two processes is binder RPC. This
+ * is needed because the binder passed over the binder RPC connection can not be
+ * used as a kernel binder, and needs to be wrapped by a kernel binder that can
+ * then be registered with service manager.
+ *
+ * \param instance name of the service associated with the Accessor
+ * \param binder the AIBinder* from the ABinderRpc_Accessor from the
+ * ABinderRpc_Accessor_asBinder. The other process across the binder RPC
+ * connection will have called this and passed the AIBinder* across a
+ * binder interface to the process calling this function.
+ * \param outDelegator the AIBinder* for the kernel binder that wraps the
+ * 'binder' argument and delegates all calls to it. The caller now owns
+ * this object with one strong ref count and is responsible for removing
+ * that ref count with with AIBinder_decStrong when the caller wishes to
+ * drop the reference.
+ */
+binder_status_t ABinderRpc_Accessor_delegateAccessor(const char* _Nonnull instance,
+ AIBinder* _Nonnull binder,
+ AIBinder* _Nullable* _Nonnull outDelegator)
+ __INTRODUCED_IN(36);
+
+/**
+ * Create a new ABinderRpc_ConnectionInfo with sockaddr. This can be supported socket
+ * types like sockaddr_vm (vsock) and sockaddr_un (Unix Domain Sockets).
+ *
+ * \param addr sockaddr pointer that can come from supported socket
+ * types like sockaddr_vm (vsock) and sockaddr_un (Unix Domain Sockets).
+ * \param len length of the concrete sockaddr type being used. Like
+ * sizeof(sockaddr_vm) when sockaddr_vm is used.
+ * \return the connection info based on the given sockaddr
+ */
+ABinderRpc_ConnectionInfo* _Nullable ABinderRpc_ConnectionInfo_new(const sockaddr* _Nonnull addr,
+ socklen_t len)
+ __INTRODUCED_IN(36);
+
+/**
+ * Delete an ABinderRpc_ConnectionInfo object that was created with
+ * ABinderRpc_ConnectionInfo_new.
+ *
+ * \param info object to be deleted
+ */
+void ABinderRpc_ConnectionInfo_delete(ABinderRpc_ConnectionInfo* _Nonnull info) __INTRODUCED_IN(36);
+
+/** @} */
+
+__END_DECLS
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 826e199..4d691f8 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -248,6 +248,23 @@
AServiceManager_openDeclaredPassthroughHal; # systemapi llndk=202404
};
+LIBBINDER_NDK36 { # introduced=36
+ global:
+ AIBinder_Class_setTransactionCodeToFunctionNameMap;
+ AIBinder_Class_setTransactionCodeToFunctionNameMap; # llndk=202504
+ AIBinder_Class_getFunctionName;
+ AIBinder_Class_getFunctionName; # llndk=202504
+ ABinderRpc_registerAccessorProvider; # systemapi
+ ABinderRpc_unregisterAccessorProvider; # systemapi
+ ABinderRpc_Accessor_new; # systemapi
+ ABinderRpc_Accessor_delegateAccessor; #systemapi
+ ABinderRpc_Accessor_delete; # systemapi
+ ABinderRpc_Accessor_asBinder; # systemapi
+ ABinderRpc_Accessor_fromBinder; # systemapi
+ ABinderRpc_ConnectionInfo_new; # systemapi
+ ABinderRpc_ConnectionInfo_delete; # systemapi
+};
+
LIBBINDER_NDK_PLATFORM {
global:
AParcel_getAllowFds;
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index f518a22..e5a3da4 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -46,6 +46,7 @@
#include "android/binder_ibinder.h"
using namespace android;
+using namespace std::chrono_literals;
constexpr char kExistingNonNdkService[] = "SurfaceFlinger";
constexpr char kBinderNdkUnitTestService[] = "BinderNdkUnitTest";
@@ -54,7 +55,7 @@
constexpr char kActiveServicesNdkUnitTestService[] = "ActiveServicesNdkUnitTestService";
constexpr char kBinderNdkUnitTestServiceFlagged[] = "BinderNdkUnitTestFlagged";
-constexpr unsigned int kShutdownWaitTime = 11;
+constexpr auto kShutdownWaitTime = 30s;
constexpr uint64_t kContextTestValue = 0xb4e42fb4d9a1d715;
class MyTestFoo : public IFoo {
@@ -253,12 +254,22 @@
}
bool isServiceRunning(const char* serviceName) {
- AIBinder* binder = AServiceManager_checkService(serviceName);
- if (binder == nullptr) {
- return false;
+ static const sp<android::IServiceManager> sm(android::defaultServiceManager());
+ const Vector<String16> services = sm->listServices();
+ for (const auto service : services) {
+ if (service == String16(serviceName)) return true;
}
- AIBinder_decStrong(binder);
+ return false;
+}
+bool isServiceShutdownWithWait(const char* serviceName) {
+ LOG(INFO) << "About to check and wait for shutdown of " << std::string(serviceName);
+ const auto before = std::chrono::steady_clock::now();
+ while (isServiceRunning(serviceName)) {
+ sleep(1);
+ const auto after = std::chrono::steady_clock::now();
+ if (after - before >= kShutdownWaitTime) return false;
+ }
return true;
}
@@ -450,8 +461,8 @@
service = nullptr;
IPCThreadState::self()->flushCommands();
// Make sure the service is dead after some time of no use
- sleep(kShutdownWaitTime);
- ASSERT_EQ(nullptr, AServiceManager_checkService(kLazyBinderNdkUnitTestService));
+ ASSERT_TRUE(isServiceShutdownWithWait(kLazyBinderNdkUnitTestService))
+ << "Service failed to shut down";
}
TEST(NdkBinder, ForcedPersistenceTest) {
@@ -466,14 +477,12 @@
service = nullptr;
IPCThreadState::self()->flushCommands();
- sleep(kShutdownWaitTime);
-
- bool isRunning = isServiceRunning(kForcePersistNdkUnitTestService);
-
if (i == 0) {
- ASSERT_TRUE(isRunning) << "Service shut down when it shouldn't have.";
+ ASSERT_TRUE(isServiceRunning(kForcePersistNdkUnitTestService))
+ << "Service shut down when it shouldn't have.";
} else {
- ASSERT_FALSE(isRunning) << "Service failed to shut down.";
+ ASSERT_TRUE(isServiceShutdownWithWait(kForcePersistNdkUnitTestService))
+ << "Service failed to shut down";
}
}
}
@@ -491,10 +500,7 @@
service = nullptr;
IPCThreadState::self()->flushCommands();
- LOG(INFO) << "ActiveServicesCallbackTest about to sleep";
- sleep(kShutdownWaitTime);
-
- ASSERT_FALSE(isServiceRunning(kActiveServicesNdkUnitTestService))
+ ASSERT_TRUE(isServiceShutdownWithWait(kActiveServicesNdkUnitTestService))
<< "Service failed to shut down.";
}
@@ -1102,6 +1108,37 @@
EXPECT_EQ(deleteCount, 0);
}
+void* EmptyOnCreate(void* args) {
+ return args;
+}
+void EmptyOnDestroy(void* /*userData*/) {}
+binder_status_t EmptyOnTransact(AIBinder* /*binder*/, transaction_code_t /*code*/,
+ const AParcel* /*in*/, AParcel* /*out*/) {
+ return STATUS_OK;
+}
+
+TEST(NdkBinder_DeathTest, SetCodeMapTwice) {
+ const char* codeToFunction1[] = {"function-1", "function-2", "function-3"};
+ const char* codeToFunction2[] = {"function-4", "function-5"};
+ const char* interfaceName = "interface_descriptor";
+ AIBinder_Class* clazz =
+ AIBinder_Class_define(interfaceName, EmptyOnCreate, EmptyOnDestroy, EmptyOnTransact);
+ AIBinder_Class_setTransactionCodeToFunctionNameMap(clazz, codeToFunction1, 3);
+ // Reset/clear is not allowed
+ EXPECT_DEATH(AIBinder_Class_setTransactionCodeToFunctionNameMap(clazz, codeToFunction2, 2), "");
+}
+
+TEST(NdkBinder_DeathTest, SetNullCodeMap) {
+ const char* codeToFunction[] = {"function-1", "function-2", "function-3"};
+ const char* interfaceName = "interface_descriptor";
+ AIBinder_Class* clazz =
+ AIBinder_Class_define(interfaceName, EmptyOnCreate, EmptyOnDestroy, EmptyOnTransact);
+ EXPECT_DEATH(AIBinder_Class_setTransactionCodeToFunctionNameMap(nullptr, codeToFunction, 3),
+ "");
+ EXPECT_DEATH(AIBinder_Class_setTransactionCodeToFunctionNameMap(clazz, nullptr, 0), "");
+ EXPECT_DEATH(AIBinder_Class_setTransactionCodeToFunctionNameMap(nullptr, nullptr, 0), "");
+}
+
int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index 2deb254..4545d7b 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -15,6 +15,8 @@
"libbinder_ndk_sys",
"libdowncast_rs",
"liblibc",
+ "liblog_rust",
+ "libnix",
],
host_supported: true,
vendor_available: true,
@@ -79,6 +81,9 @@
shared_libs: [
"libbinder_ndk",
],
+ rustlibs: [
+ "liblibc",
+ ],
host_supported: true,
vendor_available: true,
product_available: true,
@@ -129,9 +134,18 @@
// rustified
"libbinder_ndk_bindgen_flags.txt",
],
+ bindgen_flags: [
+ "--blocklist-type",
+ "sockaddr",
+ "--raw-line",
+ "use libc::sockaddr;",
+ ],
shared_libs: [
"libbinder_ndk",
],
+ rustlibs: [
+ "liblibc",
+ ],
host_supported: true,
vendor_available: true,
product_available: true,
@@ -185,6 +199,8 @@
"libbinder_ndk_sys",
"libdowncast_rs",
"liblibc",
+ "liblog_rust",
+ "libnix",
],
}
@@ -196,4 +212,7 @@
auto_gen_config: true,
clippy_lints: "none",
lints: "none",
+ rustlibs: [
+ "liblibc",
+ ],
}
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 9a252b8..23026e5 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -136,6 +136,31 @@
}
}
+/// Same as `Stability`, but in the form of a trait. Used when the stability should be encoded in
+/// the type.
+///
+/// When/if the `adt_const_params` Rust feature is stabilized, this could be replace by using
+/// `Stability` directly with const generics.
+pub trait StabilityType {
+ /// The `Stability` represented by this type.
+ const VALUE: Stability;
+}
+
+/// `Stability::Local`.
+#[derive(Debug)]
+pub enum LocalStabilityType {}
+/// `Stability::Vintf`.
+#[derive(Debug)]
+pub enum VintfStabilityType {}
+
+impl StabilityType for LocalStabilityType {
+ const VALUE: Stability = Stability::Local;
+}
+
+impl StabilityType for VintfStabilityType {
+ const VALUE: Stability = Stability::Vintf;
+}
+
/// A local service that can be remotable via Binder.
///
/// An object that implement this interface made be made into a Binder service
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index e70f4f0..f7f3f35 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -104,6 +104,8 @@
mod service;
#[cfg(not(trusty))]
mod state;
+#[cfg(not(any(android_vendor, android_vndk)))]
+mod system_only;
use binder_ndk_sys as sys;
@@ -120,6 +122,8 @@
};
#[cfg(not(trusty))]
pub use state::{ProcessState, ThreadState};
+#[cfg(not(any(android_vendor, android_vndk)))]
+pub use system_only::{delegate_accessor, Accessor, ConnectionInfo};
/// Binder result containing a [`Status`] on error.
pub type Result<T> = std::result::Result<T, Status>;
@@ -128,9 +132,10 @@
/// without AIDL.
pub mod binder_impl {
pub use crate::binder::{
- IBinderInternal, InterfaceClass, Remotable, Stability, ToAsyncInterface, ToSyncInterface,
- TransactionCode, TransactionFlags, FIRST_CALL_TRANSACTION, FLAG_CLEAR_BUF, FLAG_ONEWAY,
- FLAG_PRIVATE_LOCAL, LAST_CALL_TRANSACTION,
+ IBinderInternal, InterfaceClass, LocalStabilityType, Remotable, Stability, StabilityType,
+ ToAsyncInterface, ToSyncInterface, TransactionCode, TransactionFlags, VintfStabilityType,
+ FIRST_CALL_TRANSACTION, FLAG_CLEAR_BUF, FLAG_ONEWAY, FLAG_PRIVATE_LOCAL,
+ LAST_CALL_TRANSACTION,
};
pub use crate::binder_async::BinderAsyncRuntime;
pub use crate::error::status_t;
diff --git a/libs/binder/rust/src/parcel/parcelable_holder.rs b/libs/binder/rust/src/parcel/parcelable_holder.rs
index f906113..87b42ab 100644
--- a/libs/binder/rust/src/parcel/parcelable_holder.rs
+++ b/libs/binder/rust/src/parcel/parcelable_holder.rs
@@ -15,6 +15,7 @@
*/
use crate::binder::Stability;
+use crate::binder::StabilityType;
use crate::error::StatusCode;
use crate::parcel::{
BorrowedParcel, Deserialize, Parcel, Parcelable, Serialize, NON_NULL_PARCELABLE_FLAG,
@@ -60,7 +61,7 @@
/// `Send` nor `Sync`), mainly because it internally contains
/// a `Parcel` which in turn is not thread-safe.
#[derive(Debug)]
-pub struct ParcelableHolder {
+pub struct ParcelableHolder<STABILITY: StabilityType> {
// This is a `Mutex` because of `get_parcelable`
// which takes `&self` for consistency with C++.
// We could make `get_parcelable` take a `&mut self`
@@ -68,13 +69,17 @@
// improvement, but then callers would require a mutable
// `ParcelableHolder` even for that getter method.
data: Mutex<ParcelableHolderData>,
- stability: Stability,
+
+ _stability_phantom: std::marker::PhantomData<STABILITY>,
}
-impl ParcelableHolder {
+impl<STABILITY: StabilityType> ParcelableHolder<STABILITY> {
/// Construct a new `ParcelableHolder` with the given stability.
- pub fn new(stability: Stability) -> Self {
- Self { data: Mutex::new(ParcelableHolderData::Empty), stability }
+ pub fn new() -> Self {
+ Self {
+ data: Mutex::new(ParcelableHolderData::Empty),
+ _stability_phantom: Default::default(),
+ }
}
/// Reset the contents of this `ParcelableHolder`.
@@ -91,7 +96,7 @@
where
T: Any + Parcelable + ParcelableMetadata + std::fmt::Debug + Send + Sync,
{
- if self.stability > p.get_stability() {
+ if STABILITY::VALUE > p.get_stability() {
return Err(StatusCode::BAD_VALUE);
}
@@ -157,30 +162,36 @@
/// Return the stability value of this object.
pub fn get_stability(&self) -> Stability {
- self.stability
+ STABILITY::VALUE
}
}
-impl Clone for ParcelableHolder {
- fn clone(&self) -> ParcelableHolder {
+impl<STABILITY: StabilityType> Default for ParcelableHolder<STABILITY> {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl<STABILITY: StabilityType> Clone for ParcelableHolder<STABILITY> {
+ fn clone(&self) -> Self {
ParcelableHolder {
data: Mutex::new(self.data.lock().unwrap().clone()),
- stability: self.stability,
+ _stability_phantom: Default::default(),
}
}
}
-impl Serialize for ParcelableHolder {
+impl<STABILITY: StabilityType> Serialize for ParcelableHolder<STABILITY> {
fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<(), StatusCode> {
parcel.write(&NON_NULL_PARCELABLE_FLAG)?;
self.write_to_parcel(parcel)
}
}
-impl Deserialize for ParcelableHolder {
+impl<STABILITY: StabilityType> Deserialize for ParcelableHolder<STABILITY> {
type UninitType = Self;
fn uninit() -> Self::UninitType {
- Self::new(Default::default())
+ Self::new()
}
fn from_init(value: Self) -> Self::UninitType {
value
@@ -191,16 +202,16 @@
if status == NULL_PARCELABLE_FLAG {
Err(StatusCode::UNEXPECTED_NULL)
} else {
- let mut parcelable = ParcelableHolder::new(Default::default());
+ let mut parcelable = Self::new();
parcelable.read_from_parcel(parcel)?;
Ok(parcelable)
}
}
}
-impl Parcelable for ParcelableHolder {
+impl<STABILITY: StabilityType> Parcelable for ParcelableHolder<STABILITY> {
fn write_to_parcel(&self, parcel: &mut BorrowedParcel<'_>) -> Result<(), StatusCode> {
- parcel.write(&self.stability)?;
+ parcel.write(&STABILITY::VALUE)?;
let mut data = self.data.lock().unwrap();
match *data {
@@ -236,7 +247,7 @@
}
fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<(), StatusCode> {
- if self.stability != parcel.read()? {
+ if self.get_stability() != parcel.read()? {
return Err(StatusCode::BAD_VALUE);
}
diff --git a/libs/binder/rust/src/system_only.rs b/libs/binder/rust/src/system_only.rs
new file mode 100644
index 0000000..08582ab
--- /dev/null
+++ b/libs/binder/rust/src/system_only.rs
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+use crate::binder::AsNative;
+use crate::error::{status_result, Result};
+use crate::proxy::SpIBinder;
+use crate::sys;
+
+use std::ffi::{c_void, CStr, CString};
+use std::os::raw::c_char;
+
+use libc::sockaddr;
+use nix::sys::socket::{SockaddrLike, UnixAddr, VsockAddr};
+use std::sync::Arc;
+use std::{fmt, ptr};
+
+/// Rust wrapper around ABinderRpc_Accessor objects for RPC binder service management.
+///
+/// Dropping the `Accessor` will drop the underlying object and the binder it owns.
+pub struct Accessor {
+ accessor: *mut sys::ABinderRpc_Accessor,
+}
+
+impl fmt::Debug for Accessor {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "ABinderRpc_Accessor({:p})", self.accessor)
+ }
+}
+
+/// Socket connection info required for libbinder to connect to a service.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum ConnectionInfo {
+ /// For vsock connection
+ Vsock(VsockAddr),
+ /// For unix domain socket connection
+ Unix(UnixAddr),
+}
+
+/// Safety: A `Accessor` is a wrapper around `ABinderRpc_Accessor` which is
+/// `Sync` and `Send`. As
+/// `ABinderRpc_Accessor` is threadsafe, this structure is too.
+/// The Fn owned the Accessor has `Sync` and `Send` properties
+unsafe impl Send for Accessor {}
+
+/// Safety: A `Accessor` is a wrapper around `ABinderRpc_Accessor` which is
+/// `Sync` and `Send`. As `ABinderRpc_Accessor` is threadsafe, this structure is too.
+/// The Fn owned the Accessor has `Sync` and `Send` properties
+unsafe impl Sync for Accessor {}
+
+impl Accessor {
+ /// Create a new accessor that will call the given callback when its
+ /// connection info is required.
+ /// The callback object and all objects it captures are owned by the Accessor
+ /// and will be deleted some time after the Accessor is Dropped. If the callback
+ /// is being called when the Accessor is Dropped, the callback will not be deleted
+ /// immediately.
+ pub fn new<F>(instance: &str, callback: F) -> Accessor
+ where
+ F: Fn(&str) -> Option<ConnectionInfo> + Send + Sync + 'static,
+ {
+ let callback: *mut c_void = Arc::into_raw(Arc::new(callback)) as *mut c_void;
+ let inst = CString::new(instance).unwrap();
+
+ // Safety: The function pointer is a valid connection_info callback.
+ // This call returns an owned `ABinderRpc_Accessor` pointer which
+ // must be destroyed via `ABinderRpc_Accessor_delete` when no longer
+ // needed.
+ // When the underlying ABinderRpc_Accessor is deleted, it will call
+ // the cookie_decr_refcount callback to release its strong ref.
+ let accessor = unsafe {
+ sys::ABinderRpc_Accessor_new(
+ inst.as_ptr(),
+ Some(Self::connection_info::<F>),
+ callback,
+ Some(Self::cookie_decr_refcount::<F>),
+ )
+ };
+
+ Accessor { accessor }
+ }
+
+ /// Get the underlying binder for this Accessor for when it needs to be either
+ /// registered with service manager or sent to another process.
+ pub fn as_binder(&self) -> Option<SpIBinder> {
+ // Safety: `ABinderRpc_Accessor_asBinder` returns either a null pointer or a
+ // valid pointer to an owned `AIBinder`. Either of these values is safe to
+ // pass to `SpIBinder::from_raw`.
+ unsafe { SpIBinder::from_raw(sys::ABinderRpc_Accessor_asBinder(self.accessor)) }
+ }
+
+ /// Callback invoked from C++ when the connection info is needed.
+ ///
+ /// # Safety
+ ///
+ /// The `instance` parameter must be a non-null pointer to a valid C string for
+ /// CStr::from_ptr. The memory must contain a valid null terminator at the end of
+ /// the string within isize::MAX from the pointer. The memory must not be mutated for
+ /// the duration of this function call and must be valid for reads from the pointer
+ /// to the null terminator.
+ /// The `cookie` parameter must be the cookie for an `Arc<F>` and
+ /// the caller must hold a ref-count to it.
+ unsafe extern "C" fn connection_info<F>(
+ instance: *const c_char,
+ cookie: *mut c_void,
+ ) -> *mut binder_ndk_sys::ABinderRpc_ConnectionInfo
+ where
+ F: Fn(&str) -> Option<ConnectionInfo> + Send + Sync + 'static,
+ {
+ if cookie.is_null() || instance.is_null() {
+ log::error!("Cookie({cookie:p}) or instance({instance:p}) is null!");
+ return ptr::null_mut();
+ }
+ // Safety: The caller promises that `cookie` is for an Arc<F>.
+ let callback = unsafe { (cookie as *const F).as_ref().unwrap() };
+
+ // Safety: The caller in libbinder_ndk will have already verified this is a valid
+ // C string
+ let inst = unsafe {
+ match CStr::from_ptr(instance).to_str() {
+ Ok(s) => s,
+ Err(err) => {
+ log::error!("Failed to get a valid C string! {err:?}");
+ return ptr::null_mut();
+ }
+ }
+ };
+
+ let connection = match callback(inst) {
+ Some(con) => con,
+ None => {
+ return ptr::null_mut();
+ }
+ };
+
+ match connection {
+ ConnectionInfo::Vsock(addr) => {
+ // Safety: The sockaddr is being copied in the NDK API
+ unsafe { sys::ABinderRpc_ConnectionInfo_new(addr.as_ptr(), addr.len()) }
+ }
+ ConnectionInfo::Unix(addr) => {
+ // Safety: The sockaddr is being copied in the NDK API
+ // The cast is from sockaddr_un* to sockaddr*.
+ unsafe {
+ sys::ABinderRpc_ConnectionInfo_new(addr.as_ptr() as *const sockaddr, addr.len())
+ }
+ }
+ }
+ }
+
+ /// Callback that decrements the ref-count.
+ /// This is invoked from C++ when a binder is unlinked.
+ ///
+ /// # Safety
+ ///
+ /// The `cookie` parameter must be the cookie for an `Arc<F>` and
+ /// the owner must give up a ref-count to it.
+ unsafe extern "C" fn cookie_decr_refcount<F>(cookie: *mut c_void)
+ where
+ F: Fn(&str) -> Option<ConnectionInfo> + Send + Sync + 'static,
+ {
+ // Safety: The caller promises that `cookie` is for an Arc<F>.
+ unsafe { Arc::decrement_strong_count(cookie as *const F) };
+ }
+}
+
+impl Drop for Accessor {
+ fn drop(&mut self) {
+ // Safety: `self.accessor` is always a valid, owned
+ // `ABinderRpc_Accessor` pointer returned by
+ // `ABinderRpc_Accessor_new` when `self` was created. This delete
+ // method can only be called once when `self` is dropped.
+ unsafe {
+ sys::ABinderRpc_Accessor_delete(self.accessor);
+ }
+ }
+}
+
+/// Register a new service with the default service manager.
+///
+/// Registers the given binder object with the given identifier. If successful,
+/// this service can then be retrieved using that identifier.
+///
+/// This function will panic if the identifier contains a 0 byte (NUL).
+pub fn delegate_accessor(name: &str, mut binder: SpIBinder) -> Result<SpIBinder> {
+ let instance = CString::new(name).unwrap();
+ let mut delegator = ptr::null_mut();
+ let status =
+ // Safety: `AServiceManager_addService` expects valid `AIBinder` and C
+ // string pointers. Caller retains ownership of both pointers.
+ // `AServiceManager_addService` creates a new strong reference and copies
+ // the string, so both pointers need only be valid until the call returns.
+ unsafe { sys::ABinderRpc_Accessor_delegateAccessor(instance.as_ptr(),
+ binder.as_native_mut(), &mut delegator) };
+
+ status_result(status)?;
+
+ // Safety: `delegator` is either null or a valid, owned pointer at this
+ // point, so can be safely passed to `SpIBinder::from_raw`.
+ Ok(unsafe { SpIBinder::from_raw(delegator).expect("Expected valid binder at this point") })
+}
diff --git a/libs/binder/rust/sys/BinderBindings.hpp b/libs/binder/rust/sys/BinderBindings.hpp
index 65fa2ca..bd666fe 100644
--- a/libs/binder/rust/sys/BinderBindings.hpp
+++ b/libs/binder/rust/sys/BinderBindings.hpp
@@ -20,6 +20,7 @@
#include <android/binder_parcel.h>
#include <android/binder_parcel_platform.h>
#include <android/binder_process.h>
+#include <android/binder_rpc.h>
#include <android/binder_shell.h>
#include <android/binder_stability.h>
#include <android/binder_status.h>
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index 5359832..489fa0a 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -384,8 +384,8 @@
use std::time::Duration;
use binder::{
- BinderFeatures, DeathRecipient, FromIBinder, IBinder, Interface, SpIBinder, StatusCode,
- Strong,
+ Accessor, BinderFeatures, DeathRecipient, FromIBinder, IBinder, Interface, SpIBinder,
+ StatusCode, Strong,
};
// Import from impl API for testing only, should not be necessary as long as
// you are using AIDL.
@@ -908,6 +908,80 @@
assert_eq!(service.test().unwrap(), service_name);
}
+ struct ToBeDeleted {
+ deleted: Arc<AtomicBool>,
+ }
+
+ impl Drop for ToBeDeleted {
+ fn drop(&mut self) {
+ assert!(!self.deleted.load(Ordering::Relaxed));
+ self.deleted.store(true, Ordering::Relaxed);
+ }
+ }
+
+ #[test]
+ fn test_accessor_callback_destruction() {
+ let deleted: Arc<AtomicBool> = Arc::new(AtomicBool::new(false));
+ {
+ let accessor: Accessor;
+ {
+ let helper = ToBeDeleted { deleted: deleted.clone() };
+ let get_connection_info = move |_instance: &str| {
+ // Capture this object so we can see it get destructed
+ // after the parent scope
+ let _ = &helper;
+ None
+ };
+ accessor = Accessor::new("foo.service", get_connection_info);
+ }
+
+ match accessor.as_binder() {
+ Some(_) => {
+ assert!(!deleted.load(Ordering::Relaxed));
+ }
+ None => panic!("failed to get that accessor binder"),
+ }
+ }
+ assert!(deleted.load(Ordering::Relaxed));
+ }
+
+ #[test]
+ fn test_accessor_delegator_new_each_time() {
+ let get_connection_info = move |_instance: &str| None;
+ let accessor = Accessor::new("foo.service", get_connection_info);
+ let delegator_binder =
+ binder::delegate_accessor("foo.service", accessor.as_binder().unwrap());
+ let delegator_binder2 =
+ binder::delegate_accessor("foo.service", accessor.as_binder().unwrap());
+
+ // The delegate_accessor creates new delegators each time
+ assert!(delegator_binder != delegator_binder2);
+ }
+
+ #[test]
+ fn test_accessor_delegate_the_delegator() {
+ let get_connection_info = move |_instance: &str| None;
+ let accessor = Accessor::new("foo.service", get_connection_info);
+ let delegator_binder =
+ binder::delegate_accessor("foo.service", accessor.as_binder().unwrap());
+ let delegator_binder2 =
+ binder::delegate_accessor("foo.service", delegator_binder.clone().unwrap());
+
+ assert!(delegator_binder.clone() == delegator_binder);
+ // The delegate_accessor creates new delegators each time. Even when they are delegators
+ // of delegators.
+ assert!(delegator_binder != delegator_binder2);
+ }
+
+ #[test]
+ fn test_accessor_delegator_wrong_name() {
+ let get_connection_info = move |_instance: &str| None;
+ let accessor = Accessor::new("foo.service", get_connection_info);
+ let delegator_binder =
+ binder::delegate_accessor("NOT.foo.service", accessor.as_binder().unwrap());
+ assert_eq!(delegator_binder, Err(StatusCode::NAME_NOT_FOUND));
+ }
+
#[tokio::test]
async fn reassociate_rust_binder_async() {
let service_name = "testing_service";
diff --git a/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs b/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs
index ce0f742..ee20a22 100644
--- a/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs
+++ b/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs
@@ -21,7 +21,8 @@
use crate::read_utils::READ_FUNCS;
use binder::binder_impl::{
- Binder, BorrowedParcel, IBinderInternal, Parcel, Stability, TransactionCode,
+ Binder, BorrowedParcel, IBinderInternal, LocalStabilityType, Parcel, TransactionCode,
+ VintfStabilityType,
};
use binder::{
declare_binder_interface, BinderFeatures, Interface, Parcelable, ParcelableHolder, SpIBinder,
@@ -121,13 +122,15 @@
}
ReadOperation::ReadParcelableHolder { is_vintf } => {
- let stability = if is_vintf { Stability::Vintf } else { Stability::Local };
- let mut holder: ParcelableHolder = ParcelableHolder::new(stability);
- match holder.read_from_parcel(parcel.borrowed_ref()) {
- Ok(result) => result,
- Err(err) => {
- println!("error occurred while reading from parcel: {:?}", err)
- }
+ let result = if is_vintf {
+ ParcelableHolder::<VintfStabilityType>::new()
+ .read_from_parcel(parcel.borrowed_ref())
+ } else {
+ ParcelableHolder::<LocalStabilityType>::new()
+ .read_from_parcel(parcel.borrowed_ref())
+ };
+ if let Err(e) = result {
+ println!("error occurred while reading from parcel: {e:?}")
}
}
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 0e653af..8b0dda3 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -532,6 +532,9 @@
static_libs: [
"libbinder_rpc_single_threaded",
],
+ shared_libs: [
+ "libbinder_ndk",
+ ],
}
cc_test {
diff --git a/libs/binder/tests/binderCacheUnitTest.cpp b/libs/binder/tests/binderCacheUnitTest.cpp
index 92dab19..c5ad793 100644
--- a/libs/binder/tests/binderCacheUnitTest.cpp
+++ b/libs/binder/tests/binderCacheUnitTest.cpp
@@ -137,9 +137,9 @@
ASSERT_EQ(binder1, result);
// Kill the server, this should remove from cache.
- foo.killServer(binder1);
pid_t pid;
ASSERT_EQ(OK, binder1->getDebugPid(&pid));
+ foo.killServer(binder1);
system(("kill -9 " + std::to_string(pid)).c_str());
sp<IBinder> binder2 = sp<BBinder>::make();
@@ -149,7 +149,16 @@
EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder2));
// Confirm that new service is returned instead of old.
- sp<IBinder> result2 = mServiceManager->checkService(kCachedServiceName);
+ int retry_count = 20;
+ sp<IBinder> result2;
+ do {
+ std::this_thread::sleep_for(std::chrono::milliseconds(50));
+ if (retry_count-- == 0) {
+ break;
+ }
+ result2 = mServiceManager->checkService(kCachedServiceName);
+ } while (result2 != binder2);
+
ASSERT_EQ(binder2, result2);
}
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index fbca35e..506fc71 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -46,6 +46,13 @@
#include "binderRpcTestCommon.h"
#include "binderRpcTestFixture.h"
+// TODO need to add IServiceManager.cpp/.h to libbinder_no_kernel
+#ifdef BINDER_WITH_KERNEL_IPC
+#include "android-base/logging.h"
+#include "android/binder_manager.h"
+#include "android/binder_rpc.h"
+#endif // BINDER_WITH_KERNEL_IPC
+
using namespace std::chrono_literals;
using namespace std::placeholders;
using android::binder::borrowed_fd;
@@ -68,6 +75,8 @@
constexpr char kTrustyIpcDevice[] = "/dev/trusty-ipc-dev0";
#endif
+constexpr char kKnownAidlService[] = "activity";
+
static std::string WaitStatusToString(int wstatus) {
if (WIFEXITED(wstatus)) {
return "exit status " + std::to_string(WEXITSTATUS(wstatus));
@@ -454,7 +463,7 @@
GTEST_SKIP() << "This test requires multiple threads";
}
- constexpr size_t kNumThreads = 10;
+ constexpr size_t kNumThreads = 5;
auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
@@ -499,11 +508,11 @@
EXPECT_GE(epochMsAfter, epochMsBefore + 2 * sleepMs);
- // Potential flake, but make sure calls are handled in parallel. Due
- // to past flakes, this only checks that the amount of time taken has
- // some parallelism. Other tests such as ThreadPoolGreaterThanEqualRequested
- // check this more exactly.
- EXPECT_LE(epochMsAfter, epochMsBefore + (numCalls - 1) * sleepMs);
+ // b/272429574, b/365294257
+ // This flakes too much to test. Parallelization is tested
+ // in ThreadPoolGreaterThanEqualRequested and other tests.
+ // Test to make sure calls are handled in parallel.
+ // EXPECT_LE(epochMsAfter, epochMsBefore + (numCalls - 1) * sleepMs);
}
TEST_P(BinderRpc, ThreadPoolOverSaturated) {
@@ -515,8 +524,7 @@
constexpr size_t kNumCalls = kNumThreads + 3;
auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
- // b/272429574 - below 500ms, the test fails
- testThreadPoolOverSaturated(proc.rootIface, kNumCalls, 500 /*ms*/);
+ testThreadPoolOverSaturated(proc.rootIface, kNumCalls, 200 /*ms*/);
}
TEST_P(BinderRpc, ThreadPoolLimitOutgoing) {
@@ -530,8 +538,7 @@
auto proc = createRpcTestSocketServerProcess(
{.numThreads = kNumThreads, .numOutgoingConnections = kNumOutgoingConnections});
- // b/272429574 - below 500ms, the test fails
- testThreadPoolOverSaturated(proc.rootIface, kNumCalls, 500 /*ms*/);
+ testThreadPoolOverSaturated(proc.rootIface, kNumCalls, 200 /*ms*/);
}
TEST_P(BinderRpc, ThreadingStressTest) {
@@ -1206,27 +1213,29 @@
auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
EXPECT_EQ(OK, proc.rootBinder->pingBinder());
- auto receipt = addAccessorProvider([&](const String16& name) -> sp<IBinder> {
- return createAccessor(name,
- [&](const String16& name, sockaddr* outAddr,
- socklen_t addrSize) -> status_t {
- if (outAddr == nullptr ||
- addrSize < proc.proc->sessions[0].addrLen) {
- return BAD_VALUE;
- }
- if (name == kInstanceName) {
- if (proc.proc->sessions[0].addr.ss_family == AF_UNIX) {
- sockaddr_un* un = reinterpret_cast<sockaddr_un*>(
- &proc.proc->sessions[0].addr);
- ALOGE("inside callback: %s", un->sun_path);
- }
- std::memcpy(outAddr, &proc.proc->sessions[0].addr,
- proc.proc->sessions[0].addrLen);
- return OK;
- }
- return NAME_NOT_FOUND;
- });
- });
+ auto receipt = addAccessorProvider(
+ {String8(kInstanceName).c_str()}, [&](const String16& name) -> sp<IBinder> {
+ return createAccessor(name,
+ [&](const String16& name, sockaddr* outAddr,
+ socklen_t addrSize) -> status_t {
+ if (outAddr == nullptr ||
+ addrSize < proc.proc->sessions[0].addrLen) {
+ return BAD_VALUE;
+ }
+ if (name == kInstanceName) {
+ if (proc.proc->sessions[0].addr.ss_family ==
+ AF_UNIX) {
+ sockaddr_un* un = reinterpret_cast<sockaddr_un*>(
+ &proc.proc->sessions[0].addr);
+ ALOGE("inside callback: %s", un->sun_path);
+ }
+ std::memcpy(outAddr, &proc.proc->sessions[0].addr,
+ proc.proc->sessions[0].addrLen);
+ return OK;
+ }
+ return NAME_NOT_FOUND;
+ });
+ });
EXPECT_FALSE(receipt.expired());
@@ -1253,7 +1262,8 @@
bool isProviderDeleted = false;
- auto receipt = addAccessorProvider([&](const String16&) -> sp<IBinder> { return nullptr; });
+ auto receipt = addAccessorProvider({String8(kInstanceName).c_str()},
+ [&](const String16&) -> sp<IBinder> { return nullptr; });
EXPECT_FALSE(receipt.expired());
sp<IBinder> binder = defaultServiceManager()->checkService(kInstanceName);
@@ -1263,6 +1273,32 @@
EXPECT_EQ(status, OK);
}
+TEST_P(BinderRpcAccessor, InjectDuplicateAccessorProvider) {
+ const String16 kInstanceName("super.cool.service/better_than_default");
+ const String16 kInstanceName2("super.cool.service/better_than_default2");
+
+ auto receipt =
+ addAccessorProvider({String8(kInstanceName).c_str(), String8(kInstanceName2).c_str()},
+ [&](const String16&) -> sp<IBinder> { return nullptr; });
+ EXPECT_FALSE(receipt.expired());
+ // reject this because it's associated with an already used instance name
+ auto receipt2 = addAccessorProvider({String8(kInstanceName).c_str()},
+ [&](const String16&) -> sp<IBinder> { return nullptr; });
+ EXPECT_TRUE(receipt2.expired());
+
+ // the first provider should still be usable
+ sp<IBinder> binder = defaultServiceManager()->checkService(kInstanceName);
+ EXPECT_EQ(binder, nullptr);
+
+ status_t status = removeAccessorProvider(receipt);
+ EXPECT_EQ(status, OK);
+}
+
+TEST_P(BinderRpcAccessor, InjectAccessorProviderNoInstance) {
+ auto receipt = addAccessorProvider({}, [&](const String16&) -> sp<IBinder> { return nullptr; });
+ EXPECT_TRUE(receipt.expired());
+}
+
TEST_P(BinderRpcAccessor, InjectNoSockaddrProvided) {
constexpr size_t kNumThreads = 10;
const String16 kInstanceName("super.cool.service/better_than_default");
@@ -1273,12 +1309,15 @@
bool isProviderDeleted = false;
bool isAccessorDeleted = false;
- auto receipt = addAccessorProvider([&](const String16& name) -> sp<IBinder> {
- return createAccessor(name, [&](const String16&, sockaddr*, socklen_t) -> status_t {
- // don't fill in outAddr
- return NAME_NOT_FOUND;
- });
- });
+ auto receipt = addAccessorProvider({String8(kInstanceName).c_str()},
+ [&](const String16& name) -> sp<IBinder> {
+ return createAccessor(name,
+ [&](const String16&, sockaddr*,
+ socklen_t) -> status_t {
+ // don't fill in outAddr
+ return NAME_NOT_FOUND;
+ });
+ });
EXPECT_FALSE(receipt.expired());
@@ -1289,6 +1328,324 @@
EXPECT_EQ(status, OK);
}
+constexpr const char* kARpcInstance = "some.instance.name.IFoo/default";
+const char* kARpcSupportedServices[] = {
+ kARpcInstance,
+};
+const uint32_t kARpcNumSupportedServices = 1;
+
+struct ConnectionInfoData {
+ sockaddr_storage addr;
+ socklen_t len;
+ bool* isDeleted;
+ ~ConnectionInfoData() {
+ if (isDeleted) *isDeleted = true;
+ }
+};
+
+struct AccessorProviderData {
+ sockaddr_storage addr;
+ socklen_t len;
+ bool* isDeleted;
+ ~AccessorProviderData() {
+ if (isDeleted) *isDeleted = true;
+ }
+};
+
+void accessorProviderDataOnDelete(void* data) {
+ delete reinterpret_cast<AccessorProviderData*>(data);
+}
+void infoProviderDataOnDelete(void* data) {
+ delete reinterpret_cast<ConnectionInfoData*>(data);
+}
+
+ABinderRpc_ConnectionInfo* infoProvider(const char* instance, void* cookie) {
+ if (instance == nullptr || cookie == nullptr) return nullptr;
+ ConnectionInfoData* data = reinterpret_cast<ConnectionInfoData*>(cookie);
+ return ABinderRpc_ConnectionInfo_new(reinterpret_cast<const sockaddr*>(&data->addr), data->len);
+}
+
+ABinderRpc_Accessor* getAccessor(const char* instance, void* cookie) {
+ if (instance == nullptr || cookie == nullptr) return nullptr;
+ if (0 != strcmp(instance, kARpcInstance)) return nullptr;
+
+ AccessorProviderData* data = reinterpret_cast<AccessorProviderData*>(cookie);
+
+ ConnectionInfoData* info = new ConnectionInfoData{
+ .addr = data->addr,
+ .len = data->len,
+ .isDeleted = nullptr,
+ };
+
+ return ABinderRpc_Accessor_new(instance, infoProvider, info, infoProviderDataOnDelete);
+}
+
+class BinderARpcNdk : public ::testing::Test {};
+
+TEST_F(BinderARpcNdk, ARpcProviderNewDelete) {
+ bool isDeleted = false;
+
+ AccessorProviderData* data = new AccessorProviderData{{}, 0, &isDeleted};
+
+ ABinderRpc_AccessorProvider* provider =
+ ABinderRpc_registerAccessorProvider(getAccessor, kARpcSupportedServices,
+ kARpcNumSupportedServices, data,
+ accessorProviderDataOnDelete);
+
+ ASSERT_NE(provider, nullptr);
+ EXPECT_FALSE(isDeleted);
+
+ ABinderRpc_unregisterAccessorProvider(provider);
+
+ EXPECT_TRUE(isDeleted);
+}
+
+TEST_F(BinderARpcNdk, ARpcProviderDuplicateInstance) {
+ const char* instance = "some.instance.name.IFoo/default";
+ const uint32_t numInstances = 2;
+ const char* instances[numInstances] = {
+ instance,
+ "some.other.instance/default",
+ };
+
+ bool isDeleted = false;
+
+ AccessorProviderData* data = new AccessorProviderData{{}, 0, &isDeleted};
+
+ ABinderRpc_AccessorProvider* provider =
+ ABinderRpc_registerAccessorProvider(getAccessor, instances, numInstances, data,
+ accessorProviderDataOnDelete);
+
+ ASSERT_NE(provider, nullptr);
+ EXPECT_FALSE(isDeleted);
+
+ const uint32_t numInstances2 = 1;
+ const char* instances2[numInstances2] = {
+ instance,
+ };
+ bool isDeleted2 = false;
+ AccessorProviderData* data2 = new AccessorProviderData{{}, 0, &isDeleted2};
+ ABinderRpc_AccessorProvider* provider2 =
+ ABinderRpc_registerAccessorProvider(getAccessor, instances2, numInstances2, data2,
+ accessorProviderDataOnDelete);
+
+ EXPECT_EQ(provider2, nullptr);
+ // If it fails to be registered, the data is still cleaned up with
+ // accessorProviderDataOnDelete
+ EXPECT_TRUE(isDeleted2);
+
+ ABinderRpc_unregisterAccessorProvider(provider);
+
+ EXPECT_TRUE(isDeleted);
+}
+
+TEST_F(BinderARpcNdk, ARpcProviderRegisterNoInstance) {
+ const uint32_t numInstances = 0;
+ const char* instances[numInstances] = {};
+
+ bool isDeleted = false;
+ AccessorProviderData* data = new AccessorProviderData{{}, 0, &isDeleted};
+
+ ABinderRpc_AccessorProvider* provider =
+ ABinderRpc_registerAccessorProvider(getAccessor, instances, numInstances, data,
+ accessorProviderDataOnDelete);
+ ASSERT_EQ(provider, nullptr);
+}
+
+TEST_F(BinderARpcNdk, ARpcAccessorNewDelete) {
+ bool isDeleted = false;
+
+ ConnectionInfoData* data = new ConnectionInfoData{{}, 0, &isDeleted};
+
+ ABinderRpc_Accessor* accessor =
+ ABinderRpc_Accessor_new("gshoe_service", infoProvider, data, infoProviderDataOnDelete);
+ ASSERT_NE(accessor, nullptr);
+ EXPECT_FALSE(isDeleted);
+
+ ABinderRpc_Accessor_delete(accessor);
+ EXPECT_TRUE(isDeleted);
+}
+
+TEST_F(BinderARpcNdk, ARpcConnectionInfoNewDelete) {
+ sockaddr_vm addr{
+ .svm_family = AF_VSOCK,
+ .svm_port = VMADDR_PORT_ANY,
+ .svm_cid = VMADDR_CID_ANY,
+ };
+
+ ABinderRpc_ConnectionInfo* info =
+ ABinderRpc_ConnectionInfo_new(reinterpret_cast<sockaddr*>(&addr), sizeof(sockaddr_vm));
+ EXPECT_NE(info, nullptr);
+
+ ABinderRpc_ConnectionInfo_delete(info);
+}
+
+TEST_F(BinderARpcNdk, ARpcAsFromBinderAsBinder) {
+ bool isDeleted = false;
+
+ ConnectionInfoData* data = new ConnectionInfoData{{}, 0, &isDeleted};
+
+ ABinderRpc_Accessor* accessor =
+ ABinderRpc_Accessor_new("gshoe_service", infoProvider, data, infoProviderDataOnDelete);
+ ASSERT_NE(accessor, nullptr);
+ EXPECT_FALSE(isDeleted);
+
+ {
+ ndk::SpAIBinder binder = ndk::SpAIBinder(ABinderRpc_Accessor_asBinder(accessor));
+ EXPECT_NE(binder.get(), nullptr);
+
+ ABinderRpc_Accessor* accessor2 =
+ ABinderRpc_Accessor_fromBinder("wrong_service_name", binder.get());
+ // The API checks for the expected service name that is associated with
+ // the accessor!
+ EXPECT_EQ(accessor2, nullptr);
+
+ accessor2 = ABinderRpc_Accessor_fromBinder("gshoe_service", binder.get());
+ EXPECT_NE(accessor2, nullptr);
+
+ // this is a new ABinderRpc_Accessor object that wraps the underlying
+ // libbinder object.
+ EXPECT_NE(accessor, accessor2);
+
+ ndk::SpAIBinder binder2 = ndk::SpAIBinder(ABinderRpc_Accessor_asBinder(accessor2));
+ EXPECT_EQ(binder.get(), binder2.get());
+
+ ABinderRpc_Accessor_delete(accessor2);
+ }
+
+ EXPECT_FALSE(isDeleted);
+ ABinderRpc_Accessor_delete(accessor);
+ EXPECT_TRUE(isDeleted);
+}
+
+TEST_F(BinderARpcNdk, ARpcRequireProviderOnDeleteCallback) {
+ EXPECT_EQ(nullptr,
+ ABinderRpc_registerAccessorProvider(getAccessor, kARpcSupportedServices,
+ kARpcNumSupportedServices,
+ reinterpret_cast<void*>(1), nullptr));
+}
+
+TEST_F(BinderARpcNdk, ARpcRequireInfoOnDeleteCallback) {
+ EXPECT_EQ(nullptr,
+ ABinderRpc_Accessor_new("the_best_service_name", infoProvider,
+ reinterpret_cast<void*>(1), nullptr));
+}
+
+TEST_F(BinderARpcNdk, ARpcNoDataNoProviderOnDeleteCallback) {
+ ABinderRpc_AccessorProvider* provider =
+ ABinderRpc_registerAccessorProvider(getAccessor, kARpcSupportedServices,
+ kARpcNumSupportedServices, nullptr, nullptr);
+ ASSERT_NE(nullptr, provider);
+ ABinderRpc_unregisterAccessorProvider(provider);
+}
+
+TEST_F(BinderARpcNdk, ARpcNoDataNoInfoOnDeleteCallback) {
+ ABinderRpc_Accessor* accessor =
+ ABinderRpc_Accessor_new("the_best_service_name", infoProvider, nullptr, nullptr);
+ ASSERT_NE(nullptr, accessor);
+ ABinderRpc_Accessor_delete(accessor);
+}
+
+TEST_F(BinderARpcNdk, ARpcNullArgs_ConnectionInfo_new) {
+ sockaddr_storage addr;
+ EXPECT_EQ(nullptr, ABinderRpc_ConnectionInfo_new(reinterpret_cast<const sockaddr*>(&addr), 0));
+}
+
+TEST_F(BinderARpcNdk, ARpcDelegateAccessorWrongInstance) {
+ AccessorProviderData* data = new AccessorProviderData();
+ ABinderRpc_Accessor* accessor = getAccessor(kARpcInstance, data);
+ ASSERT_NE(accessor, nullptr);
+ AIBinder* localAccessorBinder = ABinderRpc_Accessor_asBinder(accessor);
+ EXPECT_NE(localAccessorBinder, nullptr);
+
+ AIBinder* delegatorBinder = nullptr;
+ binder_status_t status =
+ ABinderRpc_Accessor_delegateAccessor("bar", localAccessorBinder, &delegatorBinder);
+ EXPECT_EQ(status, NAME_NOT_FOUND);
+
+ AIBinder_decStrong(localAccessorBinder);
+ ABinderRpc_Accessor_delete(accessor);
+ delete data;
+}
+
+TEST_F(BinderARpcNdk, ARpcDelegateNonAccessor) {
+ auto service = defaultServiceManager()->checkService(String16(kKnownAidlService));
+ ASSERT_NE(nullptr, service);
+ ndk::SpAIBinder binder = ndk::SpAIBinder(AIBinder_fromPlatformBinder(service));
+
+ AIBinder* delegatorBinder = nullptr;
+ binder_status_t status =
+ ABinderRpc_Accessor_delegateAccessor("bar", binder.get(), &delegatorBinder);
+
+ EXPECT_EQ(status, BAD_TYPE);
+}
+
+inline void getServiceTest(BinderRpcTestProcessSession& proc,
+ ABinderRpc_AccessorProvider_getAccessorCallback getAccessor) {
+ constexpr size_t kNumThreads = 10;
+ bool isDeleted = false;
+
+ AccessorProviderData* data =
+ new AccessorProviderData{proc.proc->sessions[0].addr, proc.proc->sessions[0].addrLen,
+ &isDeleted};
+ ABinderRpc_AccessorProvider* provider =
+ ABinderRpc_registerAccessorProvider(getAccessor, kARpcSupportedServices,
+ kARpcNumSupportedServices, data,
+ accessorProviderDataOnDelete);
+ EXPECT_NE(provider, nullptr);
+ EXPECT_FALSE(isDeleted);
+
+ {
+ ndk::SpAIBinder binder = ndk::SpAIBinder(AServiceManager_checkService(kARpcInstance));
+ ASSERT_NE(binder.get(), nullptr);
+ EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
+ }
+
+ ABinderRpc_unregisterAccessorProvider(provider);
+ EXPECT_TRUE(isDeleted);
+
+ waitForExtraSessionCleanup(proc);
+}
+
+TEST_P(BinderRpcAccessor, ARpcGetService) {
+ constexpr size_t kNumThreads = 10;
+ auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
+ EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+
+ getServiceTest(proc, getAccessor);
+}
+
+// Create accessors and wrap each of the accessors in a delegator
+ABinderRpc_Accessor* getDelegatedAccessor(const char* instance, void* cookie) {
+ ABinderRpc_Accessor* accessor = getAccessor(instance, cookie);
+ AIBinder* accessorBinder = ABinderRpc_Accessor_asBinder(accessor);
+ // Once we have a handle to the AIBinder which holds a reference to the
+ // underlying accessor IBinder, we can get rid of the ABinderRpc_Accessor
+ ABinderRpc_Accessor_delete(accessor);
+
+ AIBinder* delegatorBinder = nullptr;
+ binder_status_t status =
+ ABinderRpc_Accessor_delegateAccessor(instance, accessorBinder, &delegatorBinder);
+ // No longer need this AIBinder. The delegator has a reference to the
+ // underlying IBinder on success, and on failure we are done here.
+ AIBinder_decStrong(accessorBinder);
+ if (status != OK || delegatorBinder == nullptr) {
+ ALOGE("Unexpected behavior. Status: %s, delegator ptr: %p", statusToString(status).c_str(),
+ delegatorBinder);
+ return nullptr;
+ }
+
+ return ABinderRpc_Accessor_fromBinder(instance, delegatorBinder);
+}
+
+TEST_P(BinderRpcAccessor, ARpcGetServiceWithDelegator) {
+ constexpr size_t kNumThreads = 10;
+ auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
+ EXPECT_EQ(OK, proc.rootBinder->pingBinder());
+
+ getServiceTest(proc, getDelegatedAccessor);
+}
+
#endif // BINDER_WITH_KERNEL_IPC
#ifdef BINDER_RPC_TO_TRUSTY_TEST
@@ -1554,7 +1911,7 @@
ASSERT_NE(nullptr, sm);
// Any Java service with non-empty getInterfaceDescriptor() would do.
// Let's pick activity.
- auto binder = sm->checkService(String16("activity"));
+ auto binder = sm->checkService(String16(kKnownAidlService));
ASSERT_NE(nullptr, binder);
auto descriptor = binder->getInterfaceDescriptor();
ASSERT_GE(descriptor.size(), 0u);
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index fbab8f0..cac054e 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -39,6 +39,7 @@
"smoreland@google.com",
"waghpawan@google.com",
],
+ triage_assignee: "smoreland@google.com",
use_for_presubmit: true,
},
diff --git a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
index 3a1471e..e3a3371 100644
--- a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
@@ -49,7 +49,8 @@
return STATUS_UNKNOWN_TRANSACTION;
}
-static AIBinder_Class* g_class = ::ndk::ICInterface::defineClass("ISomeInterface", onTransact);
+static AIBinder_Class* g_class =
+ ::ndk::ICInterface::defineClass("ISomeInterface", onTransact, nullptr, 0);
class BpSomeInterface : public ::ndk::BpCInterface<ISomeInterface> {
public:
diff --git a/libs/binder/trusty/OS.cpp b/libs/binder/trusty/OS.cpp
index 157ab3c..ba9e457 100644
--- a/libs/binder/trusty/OS.cpp
+++ b/libs/binder/trusty/OS.cpp
@@ -42,6 +42,10 @@
void trace_int(uint64_t, const char*, int32_t) {}
+uint64_t get_trace_enabled_tags() {
+ return 0;
+}
+
uint64_t GetThreadId() {
return 0;
}
diff --git a/libs/binder/trusty/ndk/include/android/llndk-versioning.h b/libs/binder/trusty/ndk/include/android/llndk-versioning.h
index 3ae3d8f..e955a34 100644
--- a/libs/binder/trusty/ndk/include/android/llndk-versioning.h
+++ b/libs/binder/trusty/ndk/include/android/llndk-versioning.h
@@ -15,4 +15,5 @@
*/
#pragma once
-#define __INTRODUCED_IN_LLNDK(x) /* nothing on Trusty */
+// TODO(b/349936395): set to true for Trusty
+#define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) (false)
diff --git a/libs/binder/trusty/rust/binder_rpc_test/main.rs b/libs/binder/trusty/rust/binder_rpc_test/main.rs
index baea5a8..da1a86f 100644
--- a/libs/binder/trusty/rust/binder_rpc_test/main.rs
+++ b/libs/binder/trusty/rust/binder_rpc_test/main.rs
@@ -19,7 +19,7 @@
use binder_rpc_test_aidl::aidl::IBinderRpcSession::{BnBinderRpcSession, IBinderRpcSession};
use binder_rpc_test_aidl::aidl::IBinderRpcTest::{BnBinderRpcTest, IBinderRpcTest};
use binder_rpc_test_session::MyBinderRpcSession;
-use libc::{clock_gettime, CLOCK_REALTIME};
+use libc::{clock_gettime, CLOCK_BOOTTIME};
use rpcbinder::RpcSession;
use trusty_std::ffi::{CString, FallibleCString};
@@ -56,7 +56,7 @@
let mut ts = libc::timespec { tv_sec: 0, tv_nsec: 0 };
// Safety: Passing valid pointer to variable ts which lives past end of call
- assert_eq!(unsafe { clock_gettime(CLOCK_REALTIME, &mut ts) }, 0);
+ assert_eq!(unsafe { clock_gettime(CLOCK_BOOTTIME, &mut ts) }, 0);
ts.tv_sec as u64 * 1_000_000_000u64 + ts.tv_nsec as u64
}
diff --git a/libs/binder/trusty/rust/rpcbinder/rules.mk b/libs/binder/trusty/rust/rpcbinder/rules.mk
index 97f5c03..04c63f7 100644
--- a/libs/binder/trusty/rust/rpcbinder/rules.mk
+++ b/libs/binder/trusty/rust/rpcbinder/rules.mk
@@ -29,8 +29,8 @@
$(LIBBINDER_DIR)/trusty/rust/binder_ndk_sys \
$(LIBBINDER_DIR)/trusty/rust/binder_rpc_unstable_bindgen \
$(LIBBINDER_DIR)/trusty/rust/binder_rpc_server_bindgen \
- external/rust/crates/cfg-if \
- external/rust/crates/foreign-types \
+ $(call FIND_CRATE,cfg-if) \
+ $(call FIND_CRATE,foreign-types) \
trusty/user/base/lib/tipc/rust \
trusty/user/base/lib/trusty-sys \
diff --git a/libs/binder/trusty/rust/rules.mk b/libs/binder/trusty/rust/rules.mk
index 36bd3a2..e622b22 100644
--- a/libs/binder/trusty/rust/rules.mk
+++ b/libs/binder/trusty/rust/rules.mk
@@ -27,8 +27,8 @@
$(LIBBINDER_DIR)/trusty/ndk \
$(LIBBINDER_DIR)/trusty/rust/binder_ndk_sys \
$(LIBBINDER_DIR)/trusty/rust/binder_rpc_unstable_bindgen \
- external/rust/crates/downcast-rs \
- external/rust/crates/libc \
+ $(call FIND_CRATE,downcast-rs) \
+ $(call FIND_CRATE,libc) \
trusty/user/base/lib/trusty-sys \
MODULE_RUSTFLAGS += \
diff --git a/libs/debugstore/OWNERS b/libs/debugstore/OWNERS
index 428a1a2..c8e22b7 100644
--- a/libs/debugstore/OWNERS
+++ b/libs/debugstore/OWNERS
@@ -1,3 +1,2 @@
benmiles@google.com
-gaillard@google.com
mohamadmahmoud@google.com
diff --git a/libs/debugstore/rust/Android.bp b/libs/debugstore/rust/Android.bp
index 55ba3c3..9475333 100644
--- a/libs/debugstore/rust/Android.bp
+++ b/libs/debugstore/rust/Android.bp
@@ -23,7 +23,6 @@
rustlibs: [
"libcrossbeam_queue",
"libparking_lot",
- "libonce_cell",
"libcxx",
],
shared_libs: ["libutils"],
diff --git a/libs/debugstore/rust/src/core.rs b/libs/debugstore/rust/src/core.rs
index 1dfa512..6bf79d4 100644
--- a/libs/debugstore/rust/src/core.rs
+++ b/libs/debugstore/rust/src/core.rs
@@ -17,12 +17,14 @@
use super::event_type::EventType;
use super::storage::Storage;
use crate::cxxffi::uptimeMillis;
-use once_cell::sync::Lazy;
use std::fmt;
-use std::sync::atomic::{AtomicU64, Ordering};
+use std::sync::{
+ atomic::{AtomicU64, Ordering},
+ LazyLock,
+};
// Lazily initialized static instance of DebugStore.
-static INSTANCE: Lazy<DebugStore> = Lazy::new(DebugStore::new);
+static INSTANCE: LazyLock<DebugStore> = LazyLock::new(DebugStore::new);
/// The `DebugStore` struct is responsible for managing debug events and data.
pub struct DebugStore {
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 739c3c2..044170c 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -1096,6 +1096,17 @@
AsyncWorker::getInstance().post(
[listener = mListener, slots = slots]() { listener->onBuffersDiscarded(slots); });
}
+
+ void onBufferDetached(int slot) override {
+ AsyncWorker::getInstance().post(
+ [listener = mListener, slot = slot]() { listener->onBufferDetached(slot); });
+ }
+
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
+ void onBufferAttached() override {
+ AsyncWorker::getInstance().post([listener = mListener]() { listener->onBufferAttached(); });
+ }
+#endif
};
// Extends the BufferQueueProducer to create a wrapper around the listener so the listener calls
diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp
index 7700795..8b9b090 100644
--- a/libs/gui/IProducerListener.cpp
+++ b/libs/gui/IProducerListener.cpp
@@ -184,4 +184,10 @@
void BnProducerListener::onBuffersDiscarded(const std::vector<int32_t>& /*discardedSlots*/) {
}
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
+bool BnProducerListener::needsAttachNotify() {
+ return true;
+}
+#endif
+
} // namespace android
diff --git a/libs/gui/include/gui/IProducerListener.h b/libs/gui/include/gui/IProducerListener.h
index 3dcc6b6..43bf6a7 100644
--- a/libs/gui/include/gui/IProducerListener.h
+++ b/libs/gui/include/gui/IProducerListener.h
@@ -90,6 +90,9 @@
Parcel* reply, uint32_t flags = 0);
virtual bool needsReleaseNotify();
virtual void onBuffersDiscarded(const std::vector<int32_t>& slots);
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
+ virtual bool needsAttachNotify();
+#endif
};
#else
@@ -103,6 +106,9 @@
virtual ~StubProducerListener();
virtual void onBufferReleased() {}
virtual bool needsReleaseNotify() { return false; }
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
+ virtual bool needsAttachNotify() { return false; }
+#endif
};
} // namespace android
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index e9d799e..9c0a41e 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -91,6 +91,7 @@
},
},
},
+ native_coverage: false,
}
// NOTE: This is a compile time test, and does not need to be
diff --git a/libs/nativewindow/rust/Android.bp b/libs/nativewindow/rust/Android.bp
index d68d6ba..c572ee7 100644
--- a/libs/nativewindow/rust/Android.bp
+++ b/libs/nativewindow/rust/Android.bp
@@ -26,6 +26,7 @@
source_stem: "bindings",
bindgen_flags: [
"--constified-enum-module=AHardwareBuffer_Format",
+ "--bitfield-enum=ADataSpace",
"--bitfield-enum=AHardwareBuffer_UsageFlags",
"--allowlist-file=.*/nativewindow/include/.*\\.h",
@@ -110,6 +111,7 @@
srcs: ["src/lib.rs"],
rustlibs: [
"libbinder_rs",
+ "libbitflags",
"libnativewindow_bindgen",
],
}
diff --git a/libs/nativewindow/rust/src/handle.rs b/libs/nativewindow/rust/src/handle.rs
index a3a9dc6..c41ab8d 100644
--- a/libs/nativewindow/rust/src/handle.rs
+++ b/libs/nativewindow/rust/src/handle.rs
@@ -12,7 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-use std::{mem::forget, ptr::NonNull};
+use std::{
+ ffi::c_int,
+ mem::forget,
+ os::fd::{BorrowedFd, FromRawFd, IntoRawFd, OwnedFd},
+ ptr::NonNull,
+};
/// Rust wrapper around `native_handle_t`.
///
@@ -22,6 +27,108 @@
pub struct NativeHandle(NonNull<ffi::native_handle_t>);
impl NativeHandle {
+ /// Creates a new `NativeHandle` with the given file descriptors and integer values.
+ ///
+ /// The `NativeHandle` will take ownership of the file descriptors and close them when it is
+ /// dropped.
+ pub fn new(fds: Vec<OwnedFd>, ints: &[c_int]) -> Option<Self> {
+ let fd_count = fds.len();
+ // SAFETY: native_handle_create doesn't have any safety requirements.
+ let handle = unsafe {
+ ffi::native_handle_create(fd_count.try_into().unwrap(), ints.len().try_into().unwrap())
+ };
+ let handle = NonNull::new(handle)?;
+ for (i, fd) in fds.into_iter().enumerate() {
+ // SAFETY: `handle` must be valid because it was just created, and the array offset is
+ // within the bounds of what we allocated above.
+ unsafe {
+ *(*handle.as_ptr()).data.as_mut_ptr().add(i) = fd.into_raw_fd();
+ }
+ }
+ for (i, value) in ints.iter().enumerate() {
+ // SAFETY: `handle` must be valid because it was just created, and the array offset is
+ // within the bounds of what we allocated above. Note that `data` is uninitialized
+ // until after this so we can't use `slice::from_raw_parts_mut` or similar to create a
+ // reference to it so we use raw pointers arithmetic instead.
+ unsafe {
+ *(*handle.as_ptr()).data.as_mut_ptr().add(fd_count + i) = *value;
+ }
+ }
+ // SAFETY: `handle` must be valid because it was just created.
+ unsafe {
+ ffi::native_handle_set_fdsan_tag(handle.as_ptr());
+ }
+ Some(Self(handle))
+ }
+
+ /// Returns a borrowed view of all the file descriptors in this native handle.
+ pub fn fds(&self) -> Vec<BorrowedFd> {
+ self.data()[..self.fd_count()]
+ .iter()
+ .map(|fd| {
+ // SAFETY: The `native_handle_t` maintains ownership of the file descriptor so it
+ // won't be closed until this `NativeHandle` is destroyed. The `BorrowedFd` will
+ // have a lifetime constrained to that of `&self`, so it can't outlive it.
+ unsafe { BorrowedFd::borrow_raw(*fd) }
+ })
+ .collect()
+ }
+
+ /// Returns the integer values in this native handle.
+ pub fn ints(&self) -> &[c_int] {
+ &self.data()[self.fd_count()..]
+ }
+
+ /// Destroys the `NativeHandle`, taking ownership of the file descriptors it contained.
+ pub fn into_fds(self) -> Vec<OwnedFd> {
+ let fds = self.data()[..self.fd_count()]
+ .iter()
+ .map(|fd| {
+ // SAFETY: The `native_handle_t` has ownership of the file descriptor, and
+ // after this we destroy it without closing the file descriptor so we can take over
+ // ownership of it.
+ unsafe { OwnedFd::from_raw_fd(*fd) }
+ })
+ .collect();
+
+ // SAFETY: Our wrapped `native_handle_t` pointer is always valid, and it won't be accessed
+ // after this because we own it and forget it.
+ unsafe {
+ assert_eq!(ffi::native_handle_delete(self.0.as_ptr()), 0);
+ }
+ // Don't drop self, as that would cause `native_handle_close` to be called and close the
+ // file descriptors.
+ forget(self);
+ fds
+ }
+
+ /// Returns a reference to the underlying `native_handle_t`.
+ fn as_ref(&self) -> &ffi::native_handle_t {
+ // SAFETY: All the ways of creating a `NativeHandle` ensure that the `native_handle_t` is
+ // valid and initialised, and lives as long as the `NativeHandle`. We enforce Rust's
+ // aliasing rules by giving the reference a lifetime matching that of `&self`.
+ unsafe { self.0.as_ref() }
+ }
+
+ /// Returns the number of file descriptors included in the native handle.
+ fn fd_count(&self) -> usize {
+ self.as_ref().numFds.try_into().unwrap()
+ }
+
+ /// Returns the number of integer values included in the native handle.
+ fn int_count(&self) -> usize {
+ self.as_ref().numInts.try_into().unwrap()
+ }
+
+ /// Returns a slice reference for all the used `data` field of the native handle, including both
+ /// file descriptors and integers.
+ fn data(&self) -> &[c_int] {
+ let total_count = self.fd_count() + self.int_count();
+ // SAFETY: The data must have been initialised with this number of elements when the
+ // `NativeHandle` was created.
+ unsafe { self.as_ref().data.as_slice(total_count) }
+ }
+
/// Wraps a raw `native_handle_t` pointer, taking ownership of it.
///
/// # Safety
@@ -90,3 +197,47 @@
// SAFETY: A `NativeHandle` can be used from different threads simultaneously, as is is just
// integers and file descriptors.
unsafe impl Sync for NativeHandle {}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use std::fs::File;
+
+ #[test]
+ fn create_empty() {
+ let handle = NativeHandle::new(vec![], &[]).unwrap();
+ assert_eq!(handle.fds().len(), 0);
+ assert_eq!(handle.ints(), &[]);
+ }
+
+ #[test]
+ fn create_with_ints() {
+ let handle = NativeHandle::new(vec![], &[1, 2, 42]).unwrap();
+ assert_eq!(handle.fds().len(), 0);
+ assert_eq!(handle.ints(), &[1, 2, 42]);
+ }
+
+ #[test]
+ fn create_with_fd() {
+ let file = File::open("/dev/null").unwrap();
+ let handle = NativeHandle::new(vec![file.into()], &[]).unwrap();
+ assert_eq!(handle.fds().len(), 1);
+ assert_eq!(handle.ints(), &[]);
+ }
+
+ #[test]
+ fn clone() {
+ let file = File::open("/dev/null").unwrap();
+ let original = NativeHandle::new(vec![file.into()], &[42]).unwrap();
+ assert_eq!(original.ints(), &[42]);
+ assert_eq!(original.fds().len(), 1);
+
+ let cloned = original.clone();
+ drop(original);
+
+ assert_eq!(cloned.ints(), &[42]);
+ assert_eq!(cloned.fds().len(), 1);
+
+ drop(cloned);
+ }
+}
diff --git a/libs/nativewindow/rust/src/surface.rs b/libs/nativewindow/rust/src/surface.rs
index 25fea80..9eddfcd 100644
--- a/libs/nativewindow/rust/src/surface.rs
+++ b/libs/nativewindow/rust/src/surface.rs
@@ -20,10 +20,14 @@
unstable_api::{status_result, AsNative},
StatusCode,
};
+use bitflags::bitflags;
use nativewindow_bindgen::{
- AHardwareBuffer_Format, ANativeWindow, ANativeWindow_acquire, ANativeWindow_getFormat,
- ANativeWindow_getHeight, ANativeWindow_getWidth, ANativeWindow_readFromParcel,
- ANativeWindow_release, ANativeWindow_writeToParcel,
+ ADataSpace, AHardwareBuffer_Format, ANativeWindow, ANativeWindow_acquire,
+ ANativeWindow_getBuffersDataSpace, ANativeWindow_getBuffersDefaultDataSpace,
+ ANativeWindow_getFormat, ANativeWindow_getHeight, ANativeWindow_getWidth,
+ ANativeWindow_readFromParcel, ANativeWindow_release, ANativeWindow_setBuffersDataSpace,
+ ANativeWindow_setBuffersGeometry, ANativeWindow_setBuffersTransform,
+ ANativeWindow_writeToParcel,
};
use std::error::Error;
use std::fmt::{self, Debug, Display, Formatter};
@@ -60,6 +64,95 @@
let format = unsafe { ANativeWindow_getFormat(self.0.as_ptr()) };
format.try_into().map_err(|_| ErrorCode(format))
}
+
+ /// Changes the format and size of the window buffers.
+ ///
+ /// The width and height control the number of pixels in the buffers, not the dimensions of the
+ /// window on screen. If these are different than the window's physical size, then its buffer
+ /// will be scaled to match that size when compositing it to the screen. The width and height
+ /// must be either both zero or both non-zero. If both are 0 then the window's base value will
+ /// come back in force.
+ pub fn set_buffers_geometry(
+ &mut self,
+ width: i32,
+ height: i32,
+ format: AHardwareBuffer_Format::Type,
+ ) -> Result<(), ErrorCode> {
+ // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
+ // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
+ // and we have not yet released it.
+ let status = unsafe {
+ ANativeWindow_setBuffersGeometry(
+ self.0.as_ptr(),
+ width,
+ height,
+ format.try_into().expect("Invalid format"),
+ )
+ };
+
+ if status == 0 {
+ Ok(())
+ } else {
+ Err(ErrorCode(status))
+ }
+ }
+
+ /// Sets a transfom that will be applied to future buffers posted to the window.
+ pub fn set_buffers_transform(&mut self, transform: Transform) -> Result<(), ErrorCode> {
+ // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
+ // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
+ // and we have not yet released it.
+ let status =
+ unsafe { ANativeWindow_setBuffersTransform(self.0.as_ptr(), transform.bits() as i32) };
+
+ if status == 0 {
+ Ok(())
+ } else {
+ Err(ErrorCode(status))
+ }
+ }
+
+ /// Sets the data space that will be applied to future buffers posted to the window.
+ pub fn set_buffers_data_space(&mut self, data_space: ADataSpace) -> Result<(), ErrorCode> {
+ // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
+ // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
+ // and we have not yet released it.
+ let status = unsafe { ANativeWindow_setBuffersDataSpace(self.0.as_ptr(), data_space.0) };
+
+ if status == 0 {
+ Ok(())
+ } else {
+ Err(ErrorCode(status))
+ }
+ }
+
+ /// Gets the data space of the buffers in the window.
+ pub fn get_buffers_data_space(&mut self) -> Result<ADataSpace, ErrorCode> {
+ // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
+ // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
+ // and we have not yet released it.
+ let data_space = unsafe { ANativeWindow_getBuffersDataSpace(self.0.as_ptr()) };
+
+ if data_space < 0 {
+ Err(ErrorCode(data_space))
+ } else {
+ Ok(ADataSpace(data_space))
+ }
+ }
+
+ /// Gets the default data space of the buffers in the window as set by the consumer.
+ pub fn get_buffers_default_data_space(&mut self) -> Result<ADataSpace, ErrorCode> {
+ // SAFETY: The ANativeWindow pointer we pass is guaranteed to be non-null and valid because
+ // it must have been allocated by `ANativeWindow_allocate` or `ANativeWindow_readFromParcel`
+ // and we have not yet released it.
+ let data_space = unsafe { ANativeWindow_getBuffersDefaultDataSpace(self.0.as_ptr()) };
+
+ if data_space < 0 {
+ Err(ErrorCode(data_space))
+ } else {
+ Ok(ADataSpace(data_space))
+ }
+ }
}
impl Drop for Surface {
@@ -141,3 +234,19 @@
write!(f, "Error {}", self.0)
}
}
+
+bitflags! {
+ /// Transforms that can be applied to buffers as they are displayed to a window.
+ #[derive(Copy, Clone, Debug, Eq, PartialEq)]
+ pub struct Transform: u32 {
+ const MIRROR_HORIZONTAL = 0x01;
+ const MIRROR_VERTICAL = 0x02;
+ const ROTATE_90 = 0x04;
+ }
+}
+
+impl Transform {
+ pub const IDENTITY: Self = Self::empty();
+ pub const ROTATE_180: Self = Self::MIRROR_HORIZONTAL.union(Self::MIRROR_VERTICAL);
+ pub const ROTATE_270: Self = Self::ROTATE_180.union(Self::ROTATE_90);
+}
diff --git a/libs/renderengine/OWNERS b/libs/renderengine/OWNERS
index 66e1aa1..17ab29f 100644
--- a/libs/renderengine/OWNERS
+++ b/libs/renderengine/OWNERS
@@ -5,4 +5,6 @@
djsollen@google.com
jreck@google.com
lpy@google.com
+nscobie@google.com
+sallyqi@google.com
scroggo@google.com
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index ffb6cdb..b0c6e44 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -388,8 +388,8 @@
}
}
- const uint64_t usage = static_cast<uint64_t>(
- android_convertGralloc1To0Usage(inProducerUsage, inConsumerUsage));
+ const uint64_t usage = static_cast<uint64_t>(ANDROID_NATIVE_UNSIGNED_CAST(
+ android_convertGralloc1To0Usage(inProducerUsage, inConsumerUsage)));
auto result = getBufferMapper().lock(handle, usage, rect, base::unique_fd{fenceFd});
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index b6ab2f5..7b5a27d 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -208,8 +208,10 @@
status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle, uint64_t producerUsage,
uint64_t consumerUsage, const Rect& bounds, void** vaddr,
int fenceFd) {
- return lockAsync(handle, android_convertGralloc1To0Usage(producerUsage, consumerUsage), bounds,
- vaddr, fenceFd);
+ return lockAsync(handle,
+ ANDROID_NATIVE_UNSIGNED_CAST(
+ android_convertGralloc1To0Usage(producerUsage, consumerUsage)),
+ bounds, vaddr, fenceFd);
}
status_t GraphicBufferMapper::lockAsyncYCbCr(buffer_handle_t handle, uint32_t usage,
diff --git a/libs/ultrahdr/Android.bp b/libs/ultrahdr/Android.bp
deleted file mode 100644
index eda5ea4..0000000
--- a/libs/ultrahdr/Android.bp
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2022 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.
-
-package {
- // See: http://go/android-license-faq
- default_applicable_licenses: [
- "frameworks_native_license",
- "adobe_hdr_gain_map_license",
- ],
-}
-
-cc_library {
- name: "libultrahdr-deprecated",
- enabled: false,
- host_supported: true,
- vendor_available: true,
- export_include_dirs: ["include"],
- local_include_dirs: ["include"],
-
- srcs: [
- "icc.cpp",
- "jpegr.cpp",
- "gainmapmath.cpp",
- "jpegrutils.cpp",
- "multipictureformat.cpp",
- ],
-
- shared_libs: [
- "libimage_io",
- "libjpeg",
- "libjpegencoder",
- "libjpegdecoder",
- "liblog",
- "libutils",
- ],
-}
-
-cc_library {
- name: "libjpegencoder-deprecated",
- enabled: false,
- host_supported: true,
- vendor_available: true,
-
- shared_libs: [
- "libjpeg",
- "liblog",
- "libutils",
- ],
-
- export_include_dirs: ["include"],
-
- srcs: [
- "jpegencoderhelper.cpp",
- ],
-}
-
-cc_library {
- name: "libjpegdecoder-deprecated",
- enabled: false,
- host_supported: true,
- vendor_available: true,
-
- shared_libs: [
- "libjpeg",
- "liblog",
- "libutils",
- ],
-
- export_include_dirs: ["include"],
-
- srcs: [
- "jpegdecoderhelper.cpp",
- ],
-}
diff --git a/libs/ultrahdr/fuzzer/Android.bp b/libs/ultrahdr/fuzzer/Android.bp
deleted file mode 100644
index 8d9132f..0000000
--- a/libs/ultrahdr/fuzzer/Android.bp
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2023 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.
-
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_native_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_native_license"],
-}
-
-cc_defaults {
- name: "ultrahdr_fuzzer_defaults-deprecated",
- enabled: false,
- host_supported: true,
- shared_libs: [
- "libimage_io",
- "libjpeg",
- ],
- static_libs: [
- "libjpegdecoder",
- "libjpegencoder",
- "libultrahdr",
- "libutils",
- "liblog",
- ],
- target: {
- darwin: {
- enabled: false,
- },
- },
- fuzz_config: {
- cc: [
- "android-media-fuzzing-reports@google.com",
- ],
- description: "The fuzzers target the APIs of jpeg hdr",
- service_privilege: "constrained",
- users: "multi_user",
- fuzzed_code_usage: "future_version",
- vector: "local_no_privileges_required",
- },
-}
-
-cc_fuzz {
- name: "ultrahdr_enc_fuzzer-deprecated",
- enabled: false,
- defaults: ["ultrahdr_fuzzer_defaults"],
- srcs: [
- "ultrahdr_enc_fuzzer.cpp",
- ],
-}
-
-cc_fuzz {
- name: "ultrahdr_dec_fuzzer-deprecated",
- enabled: false,
- defaults: ["ultrahdr_fuzzer_defaults"],
- srcs: [
- "ultrahdr_dec_fuzzer.cpp",
- ],
-}
diff --git a/libs/ultrahdr/tests/Android.bp b/libs/ultrahdr/tests/Android.bp
deleted file mode 100644
index 00cc797..0000000
--- a/libs/ultrahdr/tests/Android.bp
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2022 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.
-
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_native_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_native_license"],
-}
-
-cc_test {
- name: "ultrahdr_unit_test-deprecated",
- enabled: false,
- test_suites: ["device-tests"],
- srcs: [
- "gainmapmath_test.cpp",
- "icchelper_test.cpp",
- "jpegr_test.cpp",
- "jpegencoderhelper_test.cpp",
- "jpegdecoderhelper_test.cpp",
- ],
- shared_libs: [
- "libimage_io",
- "libjpeg",
- "liblog",
- ],
- static_libs: [
- "libgmock",
- "libgtest",
- "libjpegdecoder",
- "libjpegencoder",
- "libultrahdr",
- "libutils",
- ],
- data: [
- "./data/*.*",
- ],
-}
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index a6af713..0bfefd6 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -2111,6 +2111,10 @@
}
egl_surface_t const* const s = get_surface(surface);
+ if (!s->getNativeWindow()) {
+ setError(EGL_BAD_SURFACE, EGL_FALSE);
+ return EGL_FALSE;
+ }
native_window_set_buffers_timestamp(s->getNativeWindow(), time);
return EGL_TRUE;
@@ -2375,7 +2379,7 @@
case 0:
return EGL_TRUE;
case -ENOENT:
- return setError(EGL_BAD_ACCESS, (EGLBoolean)EGL_FALSE);
+ return setErrorQuiet(EGL_BAD_ACCESS, (EGLBoolean)EGL_FALSE);
case -ENOSYS:
return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
case -EINVAL:
diff --git a/services/inputflinger/PointerChoreographer.cpp b/services/inputflinger/PointerChoreographer.cpp
index 00dd6ba..ed77146 100644
--- a/services/inputflinger/PointerChoreographer.cpp
+++ b/services/inputflinger/PointerChoreographer.cpp
@@ -367,7 +367,8 @@
const uint8_t actionIndex = MotionEvent::getActionIndex(args.action);
std::array<uint32_t, MAX_POINTER_ID + 1> idToIndex;
BitSet32 idBits;
- if (maskedAction != AMOTION_EVENT_ACTION_UP && maskedAction != AMOTION_EVENT_ACTION_CANCEL) {
+ if (maskedAction != AMOTION_EVENT_ACTION_UP && maskedAction != AMOTION_EVENT_ACTION_CANCEL &&
+ maskedAction != AMOTION_EVENT_ACTION_HOVER_EXIT) {
for (size_t i = 0; i < args.getPointerCount(); i++) {
if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP && actionIndex == i) {
continue;
diff --git a/services/inputflinger/dispatcher/DragState.h b/services/inputflinger/dispatcher/DragState.h
index 9809148..1ed6c29 100644
--- a/services/inputflinger/dispatcher/DragState.h
+++ b/services/inputflinger/dispatcher/DragState.h
@@ -17,6 +17,7 @@
#pragma once
#include <gui/WindowInfo.h>
+#include <input/Input.h>
#include <utils/StrongPointer.h>
#include <string>
@@ -25,8 +26,9 @@
namespace inputdispatcher {
struct DragState {
- DragState(const sp<android::gui::WindowInfoHandle>& windowHandle, int32_t pointerId)
- : dragWindow(windowHandle), pointerId(pointerId) {}
+ DragState(const sp<android::gui::WindowInfoHandle>& windowHandle, DeviceId deviceId,
+ int32_t pointerId)
+ : dragWindow(windowHandle), deviceId(deviceId), pointerId(pointerId) {}
void dump(std::string& dump, const char* prefix = "");
// The window being dragged.
@@ -37,6 +39,8 @@
bool isStartDrag = false;
// Indicate if the stylus button is down at the start of the drag.
bool isStylusButtonDownAtStart = false;
+ // Indicate which device started this drag and drop.
+ const DeviceId deviceId;
// Indicate which pointer id is tracked by the drag and drop.
const int32_t pointerId;
};
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index f9fbfef..2161e09 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -2870,7 +2870,8 @@
}
void InputDispatcher::addDragEventLocked(const MotionEntry& entry) {
- if (!mDragState || mDragState->dragWindow->getInfo()->displayId != entry.displayId) {
+ if (!mDragState || mDragState->dragWindow->getInfo()->displayId != entry.displayId ||
+ mDragState->deviceId != entry.deviceId) {
return;
}
@@ -5758,7 +5759,7 @@
}
// Track the pointer id for drag window and generate the drag state.
const size_t id = pointers.begin()->id;
- mDragState = std::make_unique<DragState>(toWindowHandle, id);
+ mDragState = std::make_unique<DragState>(toWindowHandle, deviceId, id);
}
// Synthesize cancel for old window and down for new window.
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index cf0d46a..18b6c5e 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -116,4 +116,5 @@
unit_test: true,
},
test_suites: ["device-tests"],
+ native_coverage: false,
}
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 2056372..73ab0da 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -12192,6 +12192,87 @@
<< "Drag and drop should not work with a hovering pointer";
}
+/**
+ * Two devices, we use the second pointer of Device A to start the drag, during the drag process, if
+ * we perform a click using Device B, the dispatcher should work well.
+ */
+TEST_F(InputDispatcherDragTests, DragAndDropWhenSplitTouchAndMultiDevice) {
+ const DeviceId deviceA = 1;
+ const DeviceId deviceB = 2;
+ // First down on second window with deviceA.
+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .deviceId(deviceA)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
+ .build());
+ mSecondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA),
+ WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
+
+ // Second down on first window with deviceA
+ mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .deviceId(deviceA)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
+ .pointer(PointerBuilder(1, ToolType::FINGER).x(50).y(50))
+ .build());
+ mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA),
+ WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
+ mSecondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceA),
+ WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
+
+ // Perform drag and drop from first window.
+ ASSERT_TRUE(startDrag(/*sendDown=*/false));
+
+ // Click first window with device B, we should ensure dispatcher work well.
+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
+ .deviceId(deviceB)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
+ .build());
+ mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB),
+ WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
+
+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE)
+ .deviceId(deviceB)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
+ .build());
+ mWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDeviceId(deviceB),
+ WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
+
+ // Move with device A.
+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
+ .deviceId(deviceA)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(51))
+ .pointer(PointerBuilder(1, ToolType::FINGER).x(51).y(51))
+ .build());
+
+ mDragWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceA),
+ WithDisplayId(ui::LogicalDisplayId::DEFAULT),
+ WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
+ mWindow->consumeDragEvent(false, 51, 51);
+ mSecondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceA),
+ WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
+
+ // Releasing the drag pointer should cause drop.
+ mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
+ .deviceId(deviceA)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(51))
+ .pointer(PointerBuilder(1, ToolType::FINGER).x(51).y(51))
+ .build());
+ mDragWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDeviceId(deviceA),
+ WithDisplayId(ui::LogicalDisplayId::DEFAULT),
+ WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE)));
+ mFakePolicy->assertDropTargetEquals(*mDispatcher, mWindow->getToken());
+ mSecondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_MOVE), WithDeviceId(deviceA),
+ WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
+
+ // Release all pointers.
+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
+ .deviceId(deviceA)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(151).y(51))
+ .build());
+ mSecondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDeviceId(deviceA),
+ WithDisplayId(ui::LogicalDisplayId::DEFAULT)));
+ mWindow->assertNoEvents();
+}
+
class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {};
TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) {
diff --git a/services/inputflinger/tests/PointerChoreographer_test.cpp b/services/inputflinger/tests/PointerChoreographer_test.cpp
index 9a5b6a7..a1279ff 100644
--- a/services/inputflinger/tests/PointerChoreographer_test.cpp
+++ b/services/inputflinger/tests/PointerChoreographer_test.cpp
@@ -830,15 +830,20 @@
pc->assertSpotCount(DISPLAY_ID, 0);
}
+/**
+ * In this test, we simulate the complete event of the stylus approaching and clicking on the
+ * screen, and then leaving the screen. We should ensure that spots are displayed correctly.
+ */
TEST_F(PointerChoreographerTest, TouchSetsSpotsForStylusEvent) {
mChoreographer.setShowTouchesEnabled(true);
+ mChoreographer.setStylusPointerIconEnabled(false);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS,
DISPLAY_ID)}});
- // Emit down event with stylus properties.
- mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN,
+ // First, the stylus begin to approach the screen.
+ mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS)
.pointer(STYLUS_POINTER)
.deviceId(DEVICE_ID)
@@ -846,6 +851,72 @@
.build());
auto pc = assertPointerControllerCreated(ControllerType::TOUCH);
pc->assertSpotCount(DISPLAY_ID, 1);
+
+ mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
+ AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS)
+ .pointer(STYLUS_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(DISPLAY_ID)
+ .build());
+ pc->assertSpotCount(DISPLAY_ID, 1);
+
+ mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_EXIT,
+ AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS)
+ .pointer(STYLUS_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(DISPLAY_ID)
+ .build());
+ pc->assertSpotCount(DISPLAY_ID, 0);
+
+ // Now, use stylus touch the screen.
+ mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN,
+ AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS)
+ .pointer(STYLUS_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(DISPLAY_ID)
+ .build());
+ pc->assertSpotCount(DISPLAY_ID, 1);
+
+ mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE,
+ AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS)
+ .pointer(STYLUS_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(DISPLAY_ID)
+ .build());
+ pc->assertSpotCount(DISPLAY_ID, 1);
+
+ mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP,
+ AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS)
+ .pointer(STYLUS_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(DISPLAY_ID)
+ .build());
+ pc->assertSpotCount(DISPLAY_ID, 0);
+
+ // Then, the stylus start leave from the screen.
+ mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
+ AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS)
+ .pointer(STYLUS_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(DISPLAY_ID)
+ .build());
+ pc->assertSpotCount(DISPLAY_ID, 1);
+
+ mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
+ AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS)
+ .pointer(STYLUS_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(DISPLAY_ID)
+ .build());
+ pc->assertSpotCount(DISPLAY_ID, 1);
+
+ mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_EXIT,
+ AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS)
+ .pointer(STYLUS_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(DISPLAY_ID)
+ .build());
+ pc->assertSpotCount(DISPLAY_ID, 0);
}
TEST_F(PointerChoreographerTest, TouchSetsSpotsForTwoDisplays) {
diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS
index ffc1dd7..fa0ecee 100644
--- a/services/surfaceflinger/OWNERS
+++ b/services/surfaceflinger/OWNERS
@@ -5,6 +5,8 @@
domlaskowski@google.com
jreck@google.com
lpy@google.com
+mattbuckley@google.com
+melodymhsu@google.com
pdwilliams@google.com
racarr@google.com
ramindani@google.com
@@ -12,3 +14,4 @@
sallyqi@google.com
scroggo@google.com
vishnun@google.com
+xwxw@google.com
diff --git a/services/surfaceflinger/PowerAdvisor/OWNERS b/services/surfaceflinger/PowerAdvisor/OWNERS
new file mode 100644
index 0000000..9f40e27
--- /dev/null
+++ b/services/surfaceflinger/PowerAdvisor/OWNERS
@@ -0,0 +1 @@
+file:platform/frameworks/base:/ADPF_OWNERS
\ No newline at end of file
diff --git a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index dd86e4f..a4368a6 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -841,7 +841,8 @@
return score.overallScore == 0;
});
- if (policy->primaryRangeIsSingleRate()) {
+ // TODO(b/364651864): Evaluate correctness of primaryRangeIsSingleRate.
+ if (!isVrrDevice() && policy->primaryRangeIsSingleRate()) {
// If we never scored any layers, then choose the rate from the primary
// range instead of picking a random score from the app range.
if (noLayerScore) {
@@ -887,10 +888,10 @@
const auto touchRefreshRates = rankFrameRates(anchorGroup, RefreshRateOrder::Descending);
using fps_approx_ops::operator<;
- if (scores.front().frameRateMode.fps < touchRefreshRates.front().frameRateMode.fps) {
- ALOGV("Touch Boost");
+ if (scores.front().frameRateMode.fps <= touchRefreshRates.front().frameRateMode.fps) {
+ ALOGV("Touch Boost [late]");
ATRACE_FORMAT_INSTANT("%s (Touch Boost [late])",
- to_string(touchRefreshRates.front().frameRateMode.fps).c_str());
+ to_string(touchRefreshRates.front().frameRateMode.fps).c_str());
return {touchRefreshRates, GlobalSignals{.touch = true}};
}
}
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h b/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h
index 2c397bd..a54d435 100644
--- a/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h
@@ -134,8 +134,11 @@
}
size_t getPresentFenceShift(Period minFramePeriod) const {
- const bool isTwoVsyncsAhead = targetsVsyncsAhead<2>(minFramePeriod);
size_t shift = 0;
+ if (minFramePeriod.ns() == 0) {
+ return shift;
+ }
+ const bool isTwoVsyncsAhead = targetsVsyncsAhead<2>(minFramePeriod);
if (isTwoVsyncsAhead) {
shift = static_cast<size_t>(expectedFrameDuration().ns() / minFramePeriod.ns());
if (shift >= mPresentFences.size()) {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 1aaa128..d4d32aa 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2334,7 +2334,7 @@
if (flushTransactions) {
needsTraversal |= commitMirrorDisplays(vsyncId);
needsTraversal |= commitCreatedLayers(vsyncId, update.layerCreatedStates);
- needsTraversal |= applyTransactions(update.transactions, vsyncId);
+ needsTraversal |= applyTransactions(update.transactions);
}
outTransactionsAreEmpty = !needsTraversal;
const bool shouldCommit = (getTransactionFlags() & ~eTransactionFlushNeeded) || needsTraversal;
@@ -2515,7 +2515,7 @@
bool newDataLatched = false;
ATRACE_NAME("DisplayCallbackAndStatsUpdates");
- mustComposite |= applyTransactionsLocked(update.transactions, vsyncId);
+ mustComposite |= applyTransactionsLocked(update.transactions);
traverseLegacyLayers([&](Layer* layer) { layer->commitTransaction(); });
const nsecs_t latchTime = systemTime();
bool unused = false;
@@ -5090,20 +5090,18 @@
}
// For tests only
-bool SurfaceFlinger::flushTransactionQueues(VsyncId vsyncId) {
+bool SurfaceFlinger::flushTransactionQueues() {
mTransactionHandler.collectTransactions();
std::vector<TransactionState> transactions = mTransactionHandler.flushTransactions();
- return applyTransactions(transactions, vsyncId);
+ return applyTransactions(transactions);
}
-bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactions,
- VsyncId vsyncId) {
+bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactions) {
Mutex::Autolock lock(mStateLock);
- return applyTransactionsLocked(transactions, vsyncId);
+ return applyTransactionsLocked(transactions);
}
-bool SurfaceFlinger::applyTransactionsLocked(std::vector<TransactionState>& transactions,
- VsyncId vsyncId) {
+bool SurfaceFlinger::applyTransactionsLocked(std::vector<TransactionState>& transactions) {
bool needsTraversal = false;
// Now apply all transactions.
for (auto& transaction : transactions) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index a3534b5..2369043 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -814,9 +814,9 @@
REQUIRES(mStateLock, kMainThreadContext);
// Flush pending transactions that were presented after desiredPresentTime.
// For test only
- bool flushTransactionQueues(VsyncId) REQUIRES(kMainThreadContext);
+ bool flushTransactionQueues() REQUIRES(kMainThreadContext);
- bool applyTransactions(std::vector<TransactionState>&, VsyncId) REQUIRES(kMainThreadContext);
+ bool applyTransactions(std::vector<TransactionState>&) REQUIRES(kMainThreadContext);
bool applyAndCommitDisplayTransactionStatesLocked(std::vector<TransactionState>& transactions)
REQUIRES(kMainThreadContext, mStateLock);
@@ -854,7 +854,7 @@
static LatchUnsignaledConfig getLatchUnsignaledConfig();
bool shouldLatchUnsignaled(const layer_state_t&, size_t numStates, bool firstTransaction) const;
- bool applyTransactionsLocked(std::vector<TransactionState>& transactions, VsyncId)
+ bool applyTransactionsLocked(std::vector<TransactionState>& transactions)
REQUIRES(mStateLock, kMainThreadContext);
uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock);
uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands)
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
index cf9a7d3..d64cf2f 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
@@ -100,7 +100,9 @@
const std::vector<Fps>& knownFrameRates() const { return mKnownFrameRates; }
using RefreshRateSelector::GetRankedFrameRatesCache;
- auto& mutableGetRankedRefreshRatesCache() { return mGetRankedFrameRatesCache; }
+ auto& mutableGetRankedRefreshRatesCache() NO_THREAD_SAFETY_ANALYSIS {
+ return mGetRankedFrameRatesCache;
+ }
auto getRankedFrameRates(const std::vector<LayerRequirement>& layers,
GlobalSignals signals = {}, Fps pacesetterFps = {}) const {
@@ -138,7 +140,9 @@
return setPolicy(policy);
}
- const auto& getPrimaryFrameRates() const { return mPrimaryFrameRates; }
+ const auto& getPrimaryFrameRates() const NO_THREAD_SAFETY_ANALYSIS {
+ return mPrimaryFrameRates;
+ }
};
class RefreshRateSelectorTest : public testing::TestWithParam<Config::FrameRateOverride> {
@@ -1766,6 +1770,43 @@
}
}
+TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_vrrHighHintTouch_primaryRangeIsSingleRate) {
+ if (GetParam() != Config::FrameRateOverride::Enabled) {
+ return;
+ }
+
+ SET_FLAG_FOR_TEST(flags::vrr_config, true);
+
+ auto selector = createSelector(kVrrMode_120, kModeId120);
+ selector.setActiveMode(kModeId120, 60_Hz);
+
+ // Change primary physical range to be single rate, which on VRR device should not affect
+ // fps scoring.
+ EXPECT_EQ(SetPolicyResult::Changed,
+ selector.setDisplayManagerPolicy({kModeId120, {120_Hz, 120_Hz}}));
+
+ std::vector<LayerRequirement> layers = {{.weight = 1.f}, {.weight = 1.f}};
+ layers[0].vote = LayerVoteType::ExplicitCategory;
+ layers[0].frameRateCategory = FrameRateCategory::HighHint;
+ layers[0].name = "ExplicitCategory HighHint";
+
+ auto actualRankedFrameRates = selector.getRankedFrameRates(layers);
+ // Expect late touch boost from HighHint.
+ EXPECT_EQ(120_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps);
+ EXPECT_EQ(kModeId120, actualRankedFrameRates.ranking.front().frameRateMode.modePtr->getId());
+ EXPECT_TRUE(actualRankedFrameRates.consideredSignals.touch);
+
+ layers[1].vote = LayerVoteType::ExplicitExactOrMultiple;
+ layers[1].desiredRefreshRate = 30_Hz;
+ layers[1].name = "ExplicitExactOrMultiple 30Hz";
+
+ actualRankedFrameRates = selector.getRankedFrameRates(layers);
+ // Expect late touch boost from HighHint.
+ EXPECT_EQ(120_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps);
+ EXPECT_EQ(kModeId120, actualRankedFrameRates.ranking.front().frameRateMode.modePtr->getId());
+ EXPECT_TRUE(actualRankedFrameRates.consideredSignals.touch);
+}
+
TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_HighHint) {
auto selector = createSelector(makeModes(kMode24, kMode30, kMode60, kMode120), kModeId60);
@@ -1884,7 +1925,7 @@
// Gets touch boost
EXPECT_EQ(120_Hz, actualRankedFrameRates.ranking.front().frameRateMode.fps);
EXPECT_EQ(kModeId120, actualRankedFrameRates.ranking.front().frameRateMode.modePtr->getId());
- EXPECT_FALSE(actualRankedFrameRates.consideredSignals.touch);
+ EXPECT_TRUE(actualRankedFrameRates.consideredSignals.touch);
}
TEST_P(RefreshRateSelectorTest, getBestFrameRateMode_withFrameRateCategory_TouchBoost) {
@@ -1978,7 +2019,7 @@
lr2.name = "Max";
actualRankedFrameRates = selector.getRankedFrameRates(layers, {.touch = true});
EXPECT_FRAME_RATE_MODE(kMode120, 120_Hz, actualRankedFrameRates.ranking.front().frameRateMode);
- EXPECT_FALSE(actualRankedFrameRates.consideredSignals.touch);
+ EXPECT_TRUE(actualRankedFrameRates.consideredSignals.touch);
lr1.vote = LayerVoteType::ExplicitCategory;
lr1.frameRateCategory = FrameRateCategory::Normal;
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index f063809..1f7bf5f 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -133,7 +133,9 @@
using Scheduler::resyncAllToHardwareVsync;
auto& mutableLayerHistory() { return mLayerHistory; }
- auto& mutableAttachedChoreographers() { return mAttachedChoreographers; }
+ auto& mutableAttachedChoreographers() NO_THREAD_SAFETY_ANALYSIS {
+ return mAttachedChoreographers;
+ }
size_t layerHistorySize() NO_THREAD_SAFETY_ANALYSIS {
return mLayerHistory.mActiveLayerInfos.size() + mLayerHistory.mInactiveLayerInfos.size();
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 4197cbd..0d13dc5 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -516,8 +516,10 @@
return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries);
}
- auto& getTransactionQueue() { return mFlinger->mTransactionHandler.mLocklessTransactionQueue; }
- auto& getPendingTransactionQueue() {
+ auto& getTransactionQueue() NO_THREAD_SAFETY_ANALYSIS {
+ return mFlinger->mTransactionHandler.mLocklessTransactionQueue;
+ }
+ auto& getPendingTransactionQueue() NO_THREAD_SAFETY_ANALYSIS {
ftl::FakeGuard guard(kMainThreadContext);
return mFlinger->mTransactionHandler.mPendingTransactionQueues;
}
@@ -547,7 +549,7 @@
}
auto flushTransactionQueues() {
- return FTL_FAKE_GUARD(kMainThreadContext, mFlinger->flushTransactionQueues(kVsyncId));
+ return FTL_FAKE_GUARD(kMainThreadContext, mFlinger->flushTransactionQueues());
}
auto onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
@@ -663,8 +665,10 @@
* post-conditions.
*/
- const auto& displays() const { return mFlinger->mDisplays; }
- const auto& physicalDisplays() const { return mFlinger->mPhysicalDisplays; }
+ const auto& displays() const NO_THREAD_SAFETY_ANALYSIS { return mFlinger->mDisplays; }
+ const auto& physicalDisplays() const NO_THREAD_SAFETY_ANALYSIS {
+ return mFlinger->mPhysicalDisplays;
+ }
const auto& currentState() const { return mFlinger->mCurrentState; }
const auto& drawingState() const { return mFlinger->mDrawingState; }
const auto& transactionFlags() const { return mFlinger->mTransactionFlags; }
@@ -677,13 +681,17 @@
auto& mutableDisplayModeController() { return mFlinger->mDisplayModeController; }
auto& mutableCurrentState() { return mFlinger->mCurrentState; }
auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; }
- auto& mutableDisplays() { return mFlinger->mDisplays; }
- auto& mutablePhysicalDisplays() { return mFlinger->mPhysicalDisplays; }
+ auto& mutableDisplays() NO_THREAD_SAFETY_ANALYSIS { return mFlinger->mDisplays; }
+ auto& mutablePhysicalDisplays() NO_THREAD_SAFETY_ANALYSIS {
+ return mFlinger->mPhysicalDisplays;
+ }
auto& mutableDrawingState() { return mFlinger->mDrawingState; }
auto& mutableGeometryDirty() { return mFlinger->mGeometryDirty; }
auto& mutableVisibleRegionsDirty() { return mFlinger->mVisibleRegionsDirty; }
auto& mutableMainThreadId() { return mFlinger->mMainThreadId; }
- auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; }
+ auto& mutablePendingHotplugEvents() NO_THREAD_SAFETY_ANALYSIS {
+ return mFlinger->mPendingHotplugEvents;
+ }
auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; }
auto& mutableDebugDisableHWC() { return mFlinger->mDebugDisableHWC; }
auto& mutableMaxRenderTargetSize() { return mFlinger->mMaxRenderTargetSize; }
@@ -691,7 +699,7 @@
auto& mutableHwcDisplayData() { return getHwComposer().mDisplayData; }
auto& mutableHwcPhysicalDisplayIdMap() { return getHwComposer().mPhysicalDisplayIdMap; }
auto& mutablePrimaryHwcDisplayId() { return getHwComposer().mPrimaryHwcDisplayId; }
- auto& mutableActiveDisplayId() { return mFlinger->mActiveDisplayId; }
+ auto& mutableActiveDisplayId() NO_THREAD_SAFETY_ANALYSIS { return mFlinger->mActiveDisplayId; }
auto& mutablePreviouslyComposedLayers() { return mFlinger->mPreviouslyComposedLayers; }
auto& mutableActiveDisplayRotationFlags() {
@@ -700,7 +708,9 @@
auto& mutableMinAcquiredBuffers() { return SurfaceFlinger::minAcquiredBuffers; }
auto& mutableLayersPendingRemoval() { return mFlinger->mLayersPendingRemoval; }
- auto& mutableLayerSnapshotBuilder() { return mFlinger->mLayerSnapshotBuilder; };
+ auto& mutableLayerSnapshotBuilder() NO_THREAD_SAFETY_ANALYSIS {
+ return mFlinger->mLayerSnapshotBuilder;
+ }
auto fromHandle(const sp<IBinder>& handle) { return LayerHandle::getLayer(handle); }