Merge "Revert "Disable Pre-reboot Dexopt."" into main
diff --git a/cmds/atrace/atrace_userdebug.rc b/cmds/atrace/atrace_userdebug.rc
index fa7be18..041ffe1 100644
--- a/cmds/atrace/atrace_userdebug.rc
+++ b/cmds/atrace/atrace_userdebug.rc
@@ -24,3 +24,7 @@
chmod 0666 /sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/filter
chmod 0666 /sys/kernel/tracing/events/raw_syscalls/sys_exit/filter
chmod 0666 /sys/kernel/debug/tracing/events/raw_syscalls/sys_exit/filter
+
+ # Allow traced_probes to use the kprobe interface
+ chmod 0666 /sys/kernel/debug/tracing/kprobe_events
+ chmod 0666 /sys/kernel/tracing/kprobe_events
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index ee91d80..e89543e 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -1449,7 +1449,7 @@
class BootProfileTest : public ProfileTest {
public:
- std::vector<const std::string> extra_apps_;
+ std::vector<std::string> extra_apps_;
std::vector<int64_t> extra_ce_data_inodes_;
virtual void SetUp() {
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 910cd63..19201b2 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -101,6 +101,9 @@
EXPECT_EQ(0, validate_apk_path(path2))
<< path2 << " should be allowed as a valid path";
+ const char* path3 = TEST_APP_DIR "..example..com../example.apk";
+ EXPECT_EQ(0, validate_apk_path(path3)) << path3 << " should be allowed as a valid path";
+
const char *badint1 = TEST_APP_DIR "../example.apk";
EXPECT_EQ(-1, validate_apk_path(badint1))
<< badint1 << " should be rejected as a invalid path";
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index ffc082d..b05c655 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -1040,25 +1040,30 @@
LOG(ERROR) << "Invalid directory " << dir;
return -1;
}
- if (path.find("..") != std::string::npos) {
- LOG(ERROR) << "Invalid path " << path;
- return -1;
- }
if (path.compare(0, dir.size(), dir) != 0) {
// Common case, path isn't under directory
return -1;
}
- // Count number of subdirectories
- auto pos = path.find('/', dir.size());
+ // Count number of subdirectories and invalidate ".." subdirectories
+ auto last = dir.size();
+ auto pos = path.find('/', last);
int count = 0;
while (pos != std::string::npos) {
- auto next = path.find('/', pos + 1);
- if (next > pos + 1) {
+ if (pos > last + 1) {
count++;
}
- pos = next;
+ if (path.substr(last, pos - last) == "..") {
+ LOG(ERROR) << "Invalid path " << path;
+ return -1;
+ }
+ last = pos + 1;
+ pos = path.find('/', last);
+ }
+ if (path.substr(last, path.size() - last) == "..") {
+ LOG(ERROR) << "Invalid path " << path;
+ return -1;
}
if (count > maxSubdirs) {
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index ef2fa4d..fa7cb64 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -505,8 +505,9 @@
return Status::fromExceptionCode(Status::EX_SECURITY, "App UIDs cannot add services.");
}
- if (!mAccess->canAdd(ctx, name)) {
- return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied.");
+ std::optional<std::string> accessorName;
+ if (auto status = canAddService(ctx, name, &accessorName); !status.isOk()) {
+ return status;
}
if (binder == nullptr) {
@@ -888,8 +889,9 @@
}
auto ctx = mAccess->getCallingContext();
- if (!mAccess->canAdd(ctx, name)) {
- return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied.");
+ std::optional<std::string> accessorName;
+ if (auto status = canAddService(ctx, name, &accessorName); !status.isOk()) {
+ return status;
}
auto serviceIt = mNameToService.find(name);
@@ -1051,8 +1053,9 @@
}
auto ctx = mAccess->getCallingContext();
- if (!mAccess->canAdd(ctx, name)) {
- return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied.");
+ std::optional<std::string> accessorName;
+ if (auto status = canAddService(ctx, name, &accessorName); !status.isOk()) {
+ return status;
}
auto serviceIt = mNameToService.find(name);
@@ -1110,6 +1113,23 @@
return Status::ok();
}
+Status ServiceManager::canAddService(const Access::CallingContext& ctx, const std::string& name,
+ std::optional<std::string>* accessor) {
+ if (!mAccess->canAdd(ctx, name)) {
+ return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied for service.");
+ }
+#ifndef VENDORSERVICEMANAGER
+ *accessor = getVintfAccessorName(name);
+#endif
+ if (accessor->has_value()) {
+ if (!mAccess->canAdd(ctx, accessor->value())) {
+ return Status::fromExceptionCode(Status::EX_SECURITY,
+ "SELinux denied for the accessor of the service.");
+ }
+ }
+ return Status::ok();
+}
+
Status ServiceManager::canFindService(const Access::CallingContext& ctx, const std::string& name,
std::optional<std::string>* accessor) {
if (!mAccess->canFind(ctx, name)) {
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index 0d666c6..c92141b 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -115,6 +115,8 @@
os::Service tryGetService(const std::string& name, bool startIfNotFound);
sp<IBinder> tryGetBinder(const std::string& name, bool startIfNotFound);
+ binder::Status canAddService(const Access::CallingContext& ctx, const std::string& name,
+ std::optional<std::string>* accessor);
binder::Status canFindService(const Access::CallingContext& ctx, const std::string& name,
std::optional<std::string>* accessor);
diff --git a/include/android/performance_hint.h b/include/android/performance_hint.h
index 3c82d88..62d0423 100644
--- a/include/android/performance_hint.h
+++ b/include/android/performance_hint.h
@@ -53,6 +53,7 @@
*/
#include <android/api-level.h>
+#include <stdbool.h>
#include <stdint.h>
#include <unistd.h>
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index 0765e01..665d9c6 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -369,6 +369,28 @@
float b, float alpha, enum ADataSpace dataspace)
__INTRODUCED_IN(29);
+// These APIs (setGeometry and setCrop) were originally written in a
+// C-incompatible form using references instead of pointers, and the OS shipped
+// that version for years before it was noticed. Fortunately the compiled code
+// for callers is the same regardless of whether it's a pointer or a reference,
+// so we can declare this as a nonnull pointer for C and keep the existing C++
+// decl and definition.
+//
+// We could alternatively change the decl and the definition to both be a
+// pointer (with an inline definition using references to preserve source compat
+// for existing C++ callers), but that requires changing the definition of an
+// API that has been in the OS for years. It's theoretically a safe change, but
+// without being able to prove it that's a very big risk to take. By keeping the
+// C-compatibility hack in the header, we can be sure that we haven't changed
+// anything for existing callers. By definition there were no C users of the
+// reference-based decl; if there were any C callers of the API at all, they were
+// using the same workaround that is now used below.
+//
+// Even if this workaround turns out to not work for C, there's no permanent
+// damage done to the platform (unlike if we were to change the definition). At
+// worst it continues to work for C++ (since the preprocessed header as seen by
+// C++ hasn't changed, nor has the definition) and continues to not work for C.
+
/**
* \param source The sub-rect within the buffer's content to be rendered inside the surface's area
* The surface's source rect is clipped by the bounds of its current buffer. The source rect's width
@@ -379,7 +401,7 @@
* clipped by the bounds of its parent. The destination rect's width and height must be > 0.
*
* \param transform The transform applied after the source rect is applied to the buffer. This
- * parameter should be set to 0 for no transform. To specify a transfrom use the
+ * parameter should be set to 0 for no transform. To specify a transform use the
* NATIVE_WINDOW_TRANSFORM_* enum.
*
* Available since API level 29.
@@ -390,9 +412,14 @@
* properties at once.
*/
void ASurfaceTransaction_setGeometry(ASurfaceTransaction* _Nonnull transaction,
- ASurfaceControl* _Nonnull surface_control, const ARect& source,
- const ARect& destination, int32_t transform)
- __INTRODUCED_IN(29);
+ ASurfaceControl* _Nonnull surface_control,
+#if defined(__cplusplus)
+ const ARect& source, const ARect& destination,
+#else
+ const ARect* _Nonnull source,
+ const ARect* _Nonnull destination,
+#endif
+ int32_t transform) __INTRODUCED_IN(29);
/**
* Bounds the surface and its children to the bounds specified. The crop and buffer size will be
@@ -404,7 +431,12 @@
* Available since API level 31.
*/
void ASurfaceTransaction_setCrop(ASurfaceTransaction* _Nonnull transaction,
- ASurfaceControl* _Nonnull surface_control, const ARect& crop)
+ ASurfaceControl* _Nonnull surface_control,
+#if defined(__cplusplus)
+ const ARect& crop)
+#else
+ const ARect* _Nonnull crop)
+#endif
__INTRODUCED_IN(31);
/**
diff --git a/include/android/thermal.h b/include/android/thermal.h
index fa168cd..7f9d2ed 100644
--- a/include/android/thermal.h
+++ b/include/android/thermal.h
@@ -85,6 +85,7 @@
/** Need shutdown immediately. */
ATHERMAL_STATUS_SHUTDOWN = 6,
};
+typedef enum AThermalStatus AThermalStatus;
/**
* An opaque type representing a handle to a thermal manager.
@@ -240,6 +241,7 @@
float headroom;
AThermalStatus thermalStatus;
};
+typedef struct AThermalHeadroomThreshold AThermalHeadroomThreshold;
/**
* Gets the thermal headroom thresholds for all available thermal status.
diff --git a/include/ftl/fake_guard.h b/include/ftl/fake_guard.h
index e601251..0bf2870 100644
--- a/include/ftl/fake_guard.h
+++ b/include/ftl/fake_guard.h
@@ -76,12 +76,8 @@
FTL_ATTRIBUTE(release_capability(mutex))
#endif
-// The parentheses around `expr` are needed to deduce an lvalue or rvalue reference.
-#define FTL_FAKE_GUARD2(mutex, expr) \
- [&]() -> decltype(auto) { \
- const android::ftl::FakeGuard guard(mutex); \
- return (expr); \
- }()
+#define FTL_FAKE_GUARD2(mutex, expr) \
+ (android::ftl::FakeGuard(mutex), expr)
#define FTL_MAKE_FAKE_GUARD(arg1, arg2, guard, ...) guard
diff --git a/include/ftl/small_vector.h b/include/ftl/small_vector.h
index 43e9fac..3d5d52e 100644
--- a/include/ftl/small_vector.h
+++ b/include/ftl/small_vector.h
@@ -234,7 +234,7 @@
}
// Extracts the elements as std::vector.
- std::vector<T> promote() && {
+ std::vector<std::remove_const_t<T>> promote() && {
if (dynamic()) {
return std::get<Dynamic>(std::move(vector_)).promote();
} else {
@@ -290,11 +290,11 @@
class SmallVector<T, 0> final : details::ArrayTraits<T>,
details::ArrayComparators<SmallVector>,
details::ArrayIterators<SmallVector<T, 0>, T>,
- std::vector<T> {
+ std::vector<std::remove_const_t<T>> {
using details::ArrayTraits<T>::replace_at;
using Iter = details::ArrayIterators<SmallVector, T>;
- using Impl = std::vector<T>;
+ using Impl = std::vector<std::remove_const_t<T>>;
friend Iter;
@@ -394,12 +394,12 @@
pop_back();
}
- std::vector<T> promote() && { return std::move(*this); }
+ std::vector<std::remove_const_t<T>> promote() && { return std::move(*this); }
private:
template <typename U, std::size_t M>
static Impl convert(SmallVector<U, M>&& other) {
- if constexpr (std::is_constructible_v<Impl, std::vector<U>&&>) {
+ if constexpr (std::is_constructible_v<Impl, std::vector<std::remove_const_t<U>>&&>) {
return std::move(other).promote();
} else {
SmallVector vector(other.size());
diff --git a/include/input/OWNERS b/include/input/OWNERS
index c88bfe9..21d208f 100644
--- a/include/input/OWNERS
+++ b/include/input/OWNERS
@@ -1 +1,2 @@
+# Bug component: 136048
include platform/frameworks/base:/INPUT_OWNERS
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index de331b7..379b609 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -87,6 +87,11 @@
cc_cmake_snapshot {
name: "binder_sdk",
+ dist: {
+ targets: ["binder_sdk"],
+ dest: "binder_sdk.zip",
+ },
+
modules_host: [
"libbinder_sdk",
"libbinder_sdk_single_threaded",
diff --git a/libs/binder/BackendUnifiedServiceManager.h b/libs/binder/BackendUnifiedServiceManager.h
index f5d7e66..8f3839f 100644
--- a/libs/binder/BackendUnifiedServiceManager.h
+++ b/libs/binder/BackendUnifiedServiceManager.h
@@ -57,8 +57,6 @@
return mTheRealServiceManager->getInterfaceDescriptor();
}
- IBinder* onAsBinder() override { return IInterface::asBinder(mTheRealServiceManager).get(); }
-
private:
sp<os::IServiceManager> mTheRealServiceManager;
void toBinderService(const os::Service& in, os::Service* _out);
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index c57c9cd..53bd08d 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -143,6 +143,22 @@
return reply.readNullableStrongBinder(out);
}
+status_t IBinder::addFrozenStateChangeCallback(const wp<FrozenStateChangeCallback>& callback) {
+ BpBinder* proxy = this->remoteBinder();
+ if (proxy != nullptr) {
+ return proxy->addFrozenStateChangeCallback(callback);
+ }
+ return INVALID_OPERATION;
+}
+
+status_t IBinder::removeFrozenStateChangeCallback(const wp<FrozenStateChangeCallback>& callback) {
+ BpBinder* proxy = this->remoteBinder();
+ if (proxy != nullptr) {
+ return proxy->removeFrozenStateChangeCallback(callback);
+ }
+ return INVALID_OPERATION;
+}
+
status_t IBinder::getDebugPid(pid_t* out) {
BBinder* local = this->localBinder();
if (local != nullptr) {
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 6594aa6..eae844c 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -160,11 +160,12 @@
// ---------------------------------------------------------------------------
-sp<BpBinder> BpBinder::create(int32_t handle) {
+sp<BpBinder> BpBinder::create(int32_t handle, std::function<void()>* postTask) {
if constexpr (!kEnableKernelIpc) {
LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
return nullptr;
}
+ LOG_ALWAYS_FATAL_IF(postTask == nullptr, "BAD STATE");
int32_t trackedUid = -1;
if (sCountByUidEnabled) {
@@ -183,7 +184,11 @@
ALOGE("Still too many binder proxy objects sent to uid %d from uid %d (%d proxies "
"held)",
getuid(), trackedUid, trackedValue);
- if (sLimitCallback) sLimitCallback(trackedUid);
+
+ if (sLimitCallback) {
+ *postTask = [=]() { sLimitCallback(trackedUid); };
+ }
+
sLastLimitCallbackMap[trackedUid] = trackedValue;
}
} else {
@@ -197,7 +202,11 @@
ALOGE("Too many binder proxy objects sent to uid %d from uid %d (%d proxies held)",
getuid(), trackedUid, trackedValue);
sTrackingMap[trackedUid] |= LIMIT_REACHED_MASK;
- if (sLimitCallback) sLimitCallback(trackedUid);
+
+ if (sLimitCallback) {
+ *postTask = [=]() { sLimitCallback(trackedUid); };
+ }
+
sLastLimitCallbackMap[trackedUid] = trackedValue & COUNTING_VALUE_MASK;
if (sBinderProxyThrottleCreate) {
ALOGI("Throttling binder proxy creates from uid %d in uid %d until binder proxy"
@@ -557,6 +566,123 @@
}
}
+status_t BpBinder::addFrozenStateChangeCallback(const wp<FrozenStateChangeCallback>& callback) {
+ LOG_ALWAYS_FATAL_IF(isRpcBinder(),
+ "addFrozenStateChangeCallback() is not supported for RPC Binder.");
+ LOG_ALWAYS_FATAL_IF(!kEnableKernelIpc, "Binder kernel driver disabled at build time");
+ LOG_ALWAYS_FATAL_IF(ProcessState::self()->getThreadPoolMaxTotalThreadCount() == 0,
+ "addFrozenStateChangeCallback on %s but there are no threads "
+ "(yet?) listening to incoming transactions. See "
+ "ProcessState::startThreadPool "
+ "and ProcessState::setThreadPoolMaxThreadCount. Generally you should "
+ "setup the binder threadpool before other initialization steps.",
+ String8(getInterfaceDescriptor()).c_str());
+ LOG_ALWAYS_FATAL_IF(callback == nullptr,
+ "addFrozenStateChangeCallback(): callback must be non-NULL");
+
+ const sp<FrozenStateChangeCallback> strongCallback = callback.promote();
+ if (strongCallback == nullptr) {
+ return BAD_VALUE;
+ }
+
+ {
+ RpcMutexUniqueLock _l(mLock);
+ if (!mFrozen) {
+ ALOGV("Requesting freeze notification: %p handle %d\n", this, binderHandle());
+ IPCThreadState* self = IPCThreadState::self();
+ status_t status = self->addFrozenStateChangeCallback(binderHandle(), this);
+ if (status != NO_ERROR) {
+ // Avoids logspam if kernel does not support freeze
+ // notification.
+ if (status != INVALID_OPERATION) {
+ ALOGE("IPCThreadState.addFrozenStateChangeCallback "
+ "failed with %s. %p handle %d\n",
+ statusToString(status).c_str(), this, binderHandle());
+ }
+ return status;
+ }
+ mFrozen = std::make_unique<FrozenStateChange>();
+ if (!mFrozen) {
+ std::ignore =
+ IPCThreadState::self()->removeFrozenStateChangeCallback(binderHandle(),
+ this);
+ return NO_MEMORY;
+ }
+ }
+ if (mFrozen->initialStateReceived) {
+ strongCallback->onStateChanged(wp<BpBinder>::fromExisting(this),
+ mFrozen->isFrozen
+ ? FrozenStateChangeCallback::State::FROZEN
+ : FrozenStateChangeCallback::State::UNFROZEN);
+ }
+ ssize_t res = mFrozen->callbacks.add(callback);
+ if (res < 0) {
+ return res;
+ }
+ return NO_ERROR;
+ }
+}
+
+status_t BpBinder::removeFrozenStateChangeCallback(const wp<FrozenStateChangeCallback>& callback) {
+ LOG_ALWAYS_FATAL_IF(isRpcBinder(),
+ "removeFrozenStateChangeCallback() is not supported for RPC Binder.");
+ LOG_ALWAYS_FATAL_IF(!kEnableKernelIpc, "Binder kernel driver disabled at build time");
+
+ RpcMutexUniqueLock _l(mLock);
+
+ const size_t N = mFrozen ? mFrozen->callbacks.size() : 0;
+ for (size_t i = 0; i < N; i++) {
+ if (mFrozen->callbacks.itemAt(i) == callback) {
+ mFrozen->callbacks.removeAt(i);
+ if (mFrozen->callbacks.size() == 0) {
+ ALOGV("Clearing freeze notification: %p handle %d\n", this, binderHandle());
+ status_t status =
+ IPCThreadState::self()->removeFrozenStateChangeCallback(binderHandle(),
+ this);
+ if (status != NO_ERROR) {
+ ALOGE("Unexpected error from "
+ "IPCThreadState.removeFrozenStateChangeCallback: %s. "
+ "%p handle %d\n",
+ statusToString(status).c_str(), this, binderHandle());
+ }
+ mFrozen.reset();
+ }
+ return NO_ERROR;
+ }
+ }
+
+ return NAME_NOT_FOUND;
+}
+
+void BpBinder::onFrozenStateChanged(bool isFrozen) {
+ LOG_ALWAYS_FATAL_IF(isRpcBinder(), "onFrozenStateChanged is not supported for RPC Binder.");
+ LOG_ALWAYS_FATAL_IF(!kEnableKernelIpc, "Binder kernel driver disabled at build time");
+
+ ALOGV("Sending frozen state change notification for proxy %p handle %d, isFrozen=%s\n", this,
+ binderHandle(), isFrozen ? "true" : "false");
+
+ RpcMutexUniqueLock _l(mLock);
+ if (!mFrozen) {
+ return;
+ }
+ bool stateChanged = !mFrozen->initialStateReceived || mFrozen->isFrozen != isFrozen;
+ if (stateChanged) {
+ mFrozen->isFrozen = isFrozen;
+ mFrozen->initialStateReceived = true;
+ for (size_t i = 0; i < mFrozen->callbacks.size();) {
+ sp<FrozenStateChangeCallback> callback = mFrozen->callbacks.itemAt(i).promote();
+ if (callback != nullptr) {
+ callback->onStateChanged(wp<BpBinder>::fromExisting(this),
+ isFrozen ? FrozenStateChangeCallback::State::FROZEN
+ : FrozenStateChangeCallback::State::UNFROZEN);
+ i++;
+ } else {
+ mFrozen->callbacks.removeItemsAt(i);
+ }
+ }
+ }
+}
+
void BpBinder::reportOneDeath(const Obituary& obit)
{
sp<DeathRecipient> recipient = obit.recipient.promote();
@@ -686,6 +812,10 @@
if (ipc) ipc->clearDeathNotification(binderHandle(), this);
mObituaries = nullptr;
}
+ if (mFrozen != nullptr) {
+ std::ignore = IPCThreadState::self()->removeFrozenStateChangeCallback(binderHandle(), this);
+ mFrozen.reset();
+ }
mLock.unlock();
if (obits != nullptr) {
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 984c93d..1d26d85 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -89,26 +89,33 @@
"BR_FROZEN_REPLY",
"BR_ONEWAY_SPAM_SUSPECT",
"BR_TRANSACTION_PENDING_FROZEN",
+ "BR_FROZEN_BINDER",
+ "BR_CLEAR_FREEZE_NOTIFICATION_DONE",
};
-static const char *kCommandStrings[] = {
- "BC_TRANSACTION",
- "BC_REPLY",
- "BC_ACQUIRE_RESULT",
- "BC_FREE_BUFFER",
- "BC_INCREFS",
- "BC_ACQUIRE",
- "BC_RELEASE",
- "BC_DECREFS",
- "BC_INCREFS_DONE",
- "BC_ACQUIRE_DONE",
- "BC_ATTEMPT_ACQUIRE",
- "BC_REGISTER_LOOPER",
- "BC_ENTER_LOOPER",
- "BC_EXIT_LOOPER",
- "BC_REQUEST_DEATH_NOTIFICATION",
- "BC_CLEAR_DEATH_NOTIFICATION",
- "BC_DEAD_BINDER_DONE"
+static const char* kCommandStrings[] = {
+ "BC_TRANSACTION",
+ "BC_REPLY",
+ "BC_ACQUIRE_RESULT",
+ "BC_FREE_BUFFER",
+ "BC_INCREFS",
+ "BC_ACQUIRE",
+ "BC_RELEASE",
+ "BC_DECREFS",
+ "BC_INCREFS_DONE",
+ "BC_ACQUIRE_DONE",
+ "BC_ATTEMPT_ACQUIRE",
+ "BC_REGISTER_LOOPER",
+ "BC_ENTER_LOOPER",
+ "BC_EXIT_LOOPER",
+ "BC_REQUEST_DEATH_NOTIFICATION",
+ "BC_CLEAR_DEATH_NOTIFICATION",
+ "BC_DEAD_BINDER_DONE",
+ "BC_TRANSACTION_SG",
+ "BC_REPLY_SG",
+ "BC_REQUEST_FREEZE_NOTIFICATION",
+ "BC_CLEAR_FREEZE_NOTIFICATION",
+ "BC_FREEZE_NOTIFICATION_DONE",
};
static const int64_t kWorkSourcePropagatedBitIndex = 32;
@@ -203,6 +210,18 @@
out << ": death cookie " << (void*)(uint64_t)c;
} break;
+ case BR_FROZEN_BINDER: {
+ const int32_t c = *cmd++;
+ const int32_t h = *cmd++;
+ const int32_t isFrozen = *cmd++;
+ out << ": freeze cookie " << (void*)(uint64_t)c << " isFrozen: " << isFrozen;
+ } break;
+
+ case BR_CLEAR_FREEZE_NOTIFICATION_DONE: {
+ const int32_t c = *cmd++;
+ out << ": freeze cookie " << (void*)(uint64_t)c;
+ } break;
+
default:
// no details to show for: BR_OK, BR_DEAD_REPLY,
// BR_TRANSACTION_COMPLETE, BR_FINISHED
@@ -270,11 +289,23 @@
out << ": handle=" << h << " (death cookie " << (void*)(uint64_t)c << ")";
} break;
+ case BC_REQUEST_FREEZE_NOTIFICATION:
+ case BC_CLEAR_FREEZE_NOTIFICATION: {
+ const int32_t h = *cmd++;
+ const int32_t c = *cmd++;
+ out << ": handle=" << h << " (freeze cookie " << (void*)(uint64_t)c << ")";
+ } break;
+
case BC_DEAD_BINDER_DONE: {
const int32_t c = *cmd++;
out << ": death cookie " << (void*)(uint64_t)c;
} break;
+ case BC_FREEZE_NOTIFICATION_DONE: {
+ const int32_t c = *cmd++;
+ out << ": freeze cookie " << (void*)(uint64_t)c;
+ } break;
+
default:
// no details to show for: BC_REGISTER_LOOPER, BC_ENTER_LOOPER,
// BC_EXIT_LOOPER
@@ -953,6 +984,33 @@
return NO_ERROR;
}
+status_t IPCThreadState::addFrozenStateChangeCallback(int32_t handle, BpBinder* proxy) {
+ static bool isSupported =
+ ProcessState::isDriverFeatureEnabled(ProcessState::DriverFeature::FREEZE_NOTIFICATION);
+ if (!isSupported) {
+ return INVALID_OPERATION;
+ }
+ proxy->getWeakRefs()->incWeak(proxy);
+ mOut.writeInt32(BC_REQUEST_FREEZE_NOTIFICATION);
+ mOut.writeInt32((int32_t)handle);
+ mOut.writePointer((uintptr_t)proxy);
+ flushCommands();
+ return NO_ERROR;
+}
+
+status_t IPCThreadState::removeFrozenStateChangeCallback(int32_t handle, BpBinder* proxy) {
+ static bool isSupported =
+ ProcessState::isDriverFeatureEnabled(ProcessState::DriverFeature::FREEZE_NOTIFICATION);
+ if (!isSupported) {
+ return INVALID_OPERATION;
+ }
+ mOut.writeInt32(BC_CLEAR_FREEZE_NOTIFICATION);
+ mOut.writeInt32((int32_t)handle);
+ mOut.writePointer((uintptr_t)proxy);
+ flushCommands();
+ return NO_ERROR;
+}
+
IPCThreadState::IPCThreadState()
: mProcess(ProcessState::self()),
mServingStackPointer(nullptr),
@@ -1487,6 +1545,26 @@
proxy->getWeakRefs()->decWeak(proxy);
} break;
+ case BR_FROZEN_BINDER: {
+ const struct binder_frozen_state_info* data =
+ reinterpret_cast<const struct binder_frozen_state_info*>(
+ mIn.readInplace(sizeof(struct binder_frozen_state_info)));
+ if (data == nullptr) {
+ result = UNKNOWN_ERROR;
+ break;
+ }
+ BpBinder* proxy = (BpBinder*)data->cookie;
+ bool isFrozen = mIn.readInt32() > 0;
+ proxy->getPrivateAccessor().onFrozenStateChanged(data->is_frozen);
+ mOut.writeInt32(BC_FREEZE_NOTIFICATION_DONE);
+ mOut.writePointer(data->cookie);
+ } break;
+
+ case BR_CLEAR_FREEZE_NOTIFICATION_DONE: {
+ BpBinder* proxy = (BpBinder*)mIn.readPointer();
+ proxy->getWeakRefs()->decWeak(proxy);
+ } break;
+
case BR_FINISHED:
result = TIMED_OUT;
break;
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 8b80aed..c55dd9d 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -79,10 +79,9 @@
IServiceManager::~IServiceManager() {}
// From the old libbinder IServiceManager interface to IServiceManager.
-class ServiceManagerShim : public IServiceManager
-{
+class CppBackendShim : public IServiceManager {
public:
- explicit ServiceManagerShim (const sp<AidlServiceManager>& impl);
+ explicit CppBackendShim(const sp<BackendUnifiedServiceManager>& impl);
sp<IBinder> getService(const String16& name) const override;
sp<IBinder> checkService(const String16& name) const override;
@@ -136,11 +135,11 @@
sp<RegistrationWaiter>* waiter);
// Directly get the service in a way that, for lazy services, requests the service to be started
- // if it is not currently started. This way, calls directly to ServiceManagerShim::getService
+ // if it is not currently started. This way, calls directly to CppBackendShim::getService
// will still have the 5s delay that is expected by a large amount of Android code.
//
- // When implementing ServiceManagerShim, use realGetService instead of
- // mUnifiedServiceManager->getService so that it can be overridden in ServiceManagerHostShim.
+ // When implementing CppBackendShim, use realGetService instead of
+ // mUnifiedServiceManager->getService so that it can be overridden in CppServiceManagerHostShim.
virtual Status realGetService(const std::string& name, sp<IBinder>* _aidl_return) {
Service service;
Status status = mUnifiedServiceManager->getService2(name, &service);
@@ -155,7 +154,7 @@
sp<IServiceManager> defaultServiceManager()
{
std::call_once(gSmOnce, []() {
- gDefaultServiceManager = sp<ServiceManagerShim>::make(getBackendUnifiedServiceManager());
+ gDefaultServiceManager = sp<CppBackendShim>::make(getBackendUnifiedServiceManager());
});
return gDefaultServiceManager;
@@ -253,8 +252,11 @@
}
}
+#endif //__ANDROID_VNDK__
+
void* openDeclaredPassthroughHal(const String16& interface, const String16& instance, int flag) {
-#if defined(__ANDROID__) && !defined(__ANDROID_RECOVERY__) && !defined(__ANDROID_NATIVE_BRIDGE__)
+#if defined(__ANDROID__) && !defined(__ANDROID_VENDOR__) && !defined(__ANDROID_RECOVERY__) && \
+ !defined(__ANDROID_NATIVE_BRIDGE__)
sp<IServiceManager> sm = defaultServiceManager();
String16 name = interface + String16("/") + instance;
if (!sm->isDeclared(name)) {
@@ -274,20 +276,16 @@
#endif
}
-#endif //__ANDROID_VNDK__
-
// ----------------------------------------------------------------------
-ServiceManagerShim::ServiceManagerShim(const sp<AidlServiceManager>& impl) {
- mUnifiedServiceManager = sp<BackendUnifiedServiceManager>::make(impl);
-}
+CppBackendShim::CppBackendShim(const sp<BackendUnifiedServiceManager>& impl)
+ : mUnifiedServiceManager(impl) {}
// This implementation could be simplified and made more efficient by delegating
// to waitForService. However, this changes the threading structure in some
// cases and could potentially break prebuilts. Once we have higher logistical
// complexity, this could be attempted.
-sp<IBinder> ServiceManagerShim::getService(const String16& name) const
-{
+sp<IBinder> CppBackendShim::getService(const String16& name) const {
static bool gSystemBootCompleted = false;
sp<IBinder> svc = checkService(name);
@@ -331,8 +329,7 @@
return nullptr;
}
-sp<IBinder> ServiceManagerShim::checkService(const String16& name) const
-{
+sp<IBinder> CppBackendShim::checkService(const String16& name) const {
Service ret;
if (!mUnifiedServiceManager->checkService(String8(name).c_str(), &ret).isOk()) {
return nullptr;
@@ -340,16 +337,14 @@
return ret.get<Service::Tag::binder>();
}
-status_t ServiceManagerShim::addService(const String16& name, const sp<IBinder>& service,
- bool allowIsolated, int dumpsysPriority)
-{
+status_t CppBackendShim::addService(const String16& name, const sp<IBinder>& service,
+ bool allowIsolated, int dumpsysPriority) {
Status status = mUnifiedServiceManager->addService(String8(name).c_str(), service,
allowIsolated, dumpsysPriority);
return status.exceptionCode();
}
-Vector<String16> ServiceManagerShim::listServices(int dumpsysPriority)
-{
+Vector<String16> CppBackendShim::listServices(int dumpsysPriority) {
std::vector<std::string> ret;
if (!mUnifiedServiceManager->listServices(dumpsysPriority, &ret).isOk()) {
return {};
@@ -363,8 +358,7 @@
return res;
}
-sp<IBinder> ServiceManagerShim::waitForService(const String16& name16)
-{
+sp<IBinder> CppBackendShim::waitForService(const String16& name16) {
class Waiter : public android::os::BnServiceCallback {
Status onRegistration(const std::string& /*name*/,
const sp<IBinder>& binder) override {
@@ -453,7 +447,7 @@
}
}
-bool ServiceManagerShim::isDeclared(const String16& name) {
+bool CppBackendShim::isDeclared(const String16& name) {
bool declared;
if (Status status = mUnifiedServiceManager->isDeclared(String8(name).c_str(), &declared);
!status.isOk()) {
@@ -464,7 +458,7 @@
return declared;
}
-Vector<String16> ServiceManagerShim::getDeclaredInstances(const String16& interface) {
+Vector<String16> CppBackendShim::getDeclaredInstances(const String16& interface) {
std::vector<std::string> out;
if (Status status =
mUnifiedServiceManager->getDeclaredInstances(String8(interface).c_str(), &out);
@@ -482,7 +476,7 @@
return res;
}
-std::optional<String16> ServiceManagerShim::updatableViaApex(const String16& name) {
+std::optional<String16> CppBackendShim::updatableViaApex(const String16& name) {
std::optional<std::string> declared;
if (Status status = mUnifiedServiceManager->updatableViaApex(String8(name).c_str(), &declared);
!status.isOk()) {
@@ -493,7 +487,7 @@
return declared ? std::optional<String16>(String16(declared.value().c_str())) : std::nullopt;
}
-Vector<String16> ServiceManagerShim::getUpdatableNames(const String16& apexName) {
+Vector<String16> CppBackendShim::getUpdatableNames(const String16& apexName) {
std::vector<std::string> out;
if (Status status = mUnifiedServiceManager->getUpdatableNames(String8(apexName).c_str(), &out);
!status.isOk()) {
@@ -510,7 +504,7 @@
return res;
}
-std::optional<IServiceManager::ConnectionInfo> ServiceManagerShim::getConnectionInfo(
+std::optional<IServiceManager::ConnectionInfo> CppBackendShim::getConnectionInfo(
const String16& name) {
std::optional<os::ConnectionInfo> connectionInfo;
if (Status status =
@@ -525,8 +519,8 @@
: std::nullopt;
}
-status_t ServiceManagerShim::registerForNotifications(const String16& name,
- const sp<AidlRegistrationCallback>& cb) {
+status_t CppBackendShim::registerForNotifications(const String16& name,
+ const sp<AidlRegistrationCallback>& cb) {
if (cb == nullptr) {
ALOGE("%s: null cb passed", __FUNCTION__);
return BAD_VALUE;
@@ -545,9 +539,9 @@
return OK;
}
-void ServiceManagerShim::removeRegistrationCallbackLocked(const sp<AidlRegistrationCallback>& cb,
- ServiceCallbackMap::iterator* it,
- sp<RegistrationWaiter>* waiter) {
+void CppBackendShim::removeRegistrationCallbackLocked(const sp<AidlRegistrationCallback>& cb,
+ ServiceCallbackMap::iterator* it,
+ sp<RegistrationWaiter>* waiter) {
std::vector<LocalRegistrationAndWaiter>& localRegistrationAndWaiters = (*it)->second;
for (auto lit = localRegistrationAndWaiters.begin();
lit != localRegistrationAndWaiters.end();) {
@@ -566,8 +560,8 @@
}
}
-status_t ServiceManagerShim::unregisterForNotifications(const String16& name,
- const sp<AidlRegistrationCallback>& cb) {
+status_t CppBackendShim::unregisterForNotifications(const String16& name,
+ const sp<AidlRegistrationCallback>& cb) {
if (cb == nullptr) {
ALOGE("%s: null cb passed", __FUNCTION__);
return BAD_VALUE;
@@ -596,7 +590,7 @@
return OK;
}
-std::vector<IServiceManager::ServiceDebugInfo> ServiceManagerShim::getServiceDebugInfo() {
+std::vector<IServiceManager::ServiceDebugInfo> CppBackendShim::getServiceDebugInfo() {
std::vector<os::ServiceDebugInfo> serviceDebugInfos;
std::vector<IServiceManager::ServiceDebugInfo> ret;
if (Status status = mUnifiedServiceManager->getServiceDebugInfo(&serviceDebugInfos);
@@ -614,21 +608,21 @@
}
#ifndef __ANDROID__
-// ServiceManagerShim for host. Implements the old libbinder android::IServiceManager API.
+// CppBackendShim for host. Implements the old libbinder android::IServiceManager API.
// The internal implementation of the AIDL interface android::os::IServiceManager calls into
// on-device service manager.
-class ServiceManagerHostShim : public ServiceManagerShim {
+class CppServiceManagerHostShim : public CppBackendShim {
public:
- ServiceManagerHostShim(const sp<AidlServiceManager>& impl,
- const RpcDelegateServiceManagerOptions& options)
- : ServiceManagerShim(impl), mOptions(options) {}
- // ServiceManagerShim::getService is based on checkService, so no need to override it.
+ CppServiceManagerHostShim(const sp<AidlServiceManager>& impl,
+ const RpcDelegateServiceManagerOptions& options)
+ : CppBackendShim(sp<BackendUnifiedServiceManager>::make(impl)), mOptions(options) {}
+ // CppBackendShim::getService is based on checkService, so no need to override it.
sp<IBinder> checkService(const String16& name) const override {
return getDeviceService({String8(name).c_str()}, mOptions);
}
protected:
- // Override realGetService for ServiceManagerShim::waitForService.
+ // Override realGetService for CppBackendShim::waitForService.
Status realGetService(const std::string& name, sp<IBinder>* _aidl_return) override {
*_aidl_return = getDeviceService({"-g", name}, mOptions);
return Status::ok();
@@ -649,7 +643,7 @@
ALOGE("getDeviceService(\"manager\") returns non service manager");
return nullptr;
}
- return sp<ServiceManagerHostShim>::make(interface, options);
+ return sp<CppServiceManagerHostShim>::make(interface, options);
}
#endif
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index f30b2aa..925cb23 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -1725,7 +1725,9 @@
}
}
}
- ::munmap(ptr, len);
+ if (::munmap(ptr, len) == -1) {
+ ALOGW("munmap() failed: %s", strerror(errno));
+ }
}
::close(fd);
return status;
@@ -3331,7 +3333,9 @@
void Parcel::Blob::release() {
if (mFd != -1 && mData) {
- ::munmap(mData, mSize);
+ if (::munmap(mData, mSize) == -1) {
+ ALOGW("munmap() failed: %s", strerror(errno));
+ }
}
clear();
}
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index a42ede2..5e7f151 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -24,7 +24,6 @@
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/Stability.h>
-#include <cutils/atomic.h>
#include <utils/AndroidThreads.h>
#include <utils/String8.h>
#include <utils/Thread.h>
@@ -57,6 +56,25 @@
// -------------------------------------------------------------------------
+namespace {
+bool readDriverFeatureFile(const char* filename) {
+ int fd = open(filename, O_RDONLY | O_CLOEXEC);
+ char on;
+ if (fd == -1) {
+ ALOGE_IF(errno != ENOENT, "%s: cannot open %s: %s", __func__, filename, strerror(errno));
+ return false;
+ }
+ if (read(fd, &on, sizeof(on)) == -1) {
+ ALOGE("%s: error reading to %s: %s", __func__, filename, strerror(errno));
+ close(fd);
+ return false;
+ }
+ close(fd);
+ return on == '1';
+}
+
+} // namespace
+
namespace android {
using namespace android::binder::impl;
@@ -311,6 +329,7 @@
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
+ std::function<void()> postTask;
std::unique_lock<std::mutex> _l(mLock);
@@ -358,7 +377,7 @@
return nullptr;
}
- sp<BpBinder> b = BpBinder::PrivateAccessor::create(handle);
+ sp<BpBinder> b = BpBinder::PrivateAccessor::create(handle, &postTask);
e->binder = b.get();
if (b) e->refs = b->getWeakRefs();
result = b;
@@ -371,6 +390,10 @@
}
}
+ _l.unlock();
+
+ if (postTask) postTask();
+
return result;
}
@@ -387,7 +410,7 @@
}
String8 ProcessState::makeBinderThreadName() {
- int32_t s = android_atomic_add(1, &mThreadPoolSeq);
+ int32_t s = mThreadPoolSeq.fetch_add(1, std::memory_order_release);
pid_t pid = getpid();
std::string_view driverName = mDriverName.c_str();
@@ -429,8 +452,17 @@
}
size_t ProcessState::getThreadPoolMaxTotalThreadCount() const {
+ // Need to read `mKernelStartedThreads` before `mThreadPoolStarted` (with
+ // non-relaxed memory ordering) to avoid a race like the following:
+ //
+ // thread A: if (mThreadPoolStarted) { // evaluates false
+ // thread B: mThreadPoolStarted = true;
+ // thread B: mKernelStartedThreads++;
+ // thread A: size_t kernelStarted = mKernelStartedThreads;
+ // thread A: LOG_ALWAYS_FATAL_IF(kernelStarted != 0, ...);
+ size_t kernelStarted = mKernelStartedThreads;
+
if (mThreadPoolStarted) {
- size_t kernelStarted = mKernelStartedThreads;
size_t max = mMaxThreads;
size_t current = mCurrentThreads;
@@ -460,7 +492,6 @@
// must not be initialized or maybe has poll thread setup, we
// currently don't track this in libbinder
- size_t kernelStarted = mKernelStartedThreads;
LOG_ALWAYS_FATAL_IF(kernelStarted != 0, "Expecting 0 kernel started threads but have %zu",
kernelStarted);
return mCurrentThreads;
@@ -472,27 +503,20 @@
#define DRIVER_FEATURES_PATH "/dev/binderfs/features/"
bool ProcessState::isDriverFeatureEnabled(const DriverFeature feature) {
- static const char* const names[] = {
- [static_cast<int>(DriverFeature::ONEWAY_SPAM_DETECTION)] =
- DRIVER_FEATURES_PATH "oneway_spam_detection",
- [static_cast<int>(DriverFeature::EXTENDED_ERROR)] =
- DRIVER_FEATURES_PATH "extended_error",
- };
- int fd = open(names[static_cast<int>(feature)], O_RDONLY | O_CLOEXEC);
- char on;
- if (fd == -1) {
- ALOGE_IF(errno != ENOENT, "%s: cannot open %s: %s", __func__,
- names[static_cast<int>(feature)], strerror(errno));
- return false;
+ // Use static variable to cache the results.
+ if (feature == DriverFeature::ONEWAY_SPAM_DETECTION) {
+ static bool enabled = readDriverFeatureFile(DRIVER_FEATURES_PATH "oneway_spam_detection");
+ return enabled;
}
- if (read(fd, &on, sizeof(on)) == -1) {
- ALOGE("%s: error reading to %s: %s", __func__,
- names[static_cast<int>(feature)], strerror(errno));
- close(fd);
- return false;
+ if (feature == DriverFeature::EXTENDED_ERROR) {
+ static bool enabled = readDriverFeatureFile(DRIVER_FEATURES_PATH "extended_error");
+ return enabled;
}
- close(fd);
- return on == '1';
+ if (feature == DriverFeature::FREEZE_NOTIFICATION) {
+ static bool enabled = readDriverFeatureFile(DRIVER_FEATURES_PATH "freeze_notification");
+ return enabled;
+ }
+ return false;
}
status_t ProcessState::enableOnewaySpamDetection(bool enable) {
@@ -577,7 +601,7 @@
#ifdef __ANDROID__
LOG_ALWAYS_FATAL_IF(!opened.ok(),
"Binder driver '%s' could not be opened. Error: %s. Terminating.",
- error.c_str(), driver);
+ driver, error.c_str());
#endif
if (opened.ok()) {
diff --git a/libs/binder/binder_module.h b/libs/binder/binder_module.h
index b3a2d9e..65cdcd7 100644
--- a/libs/binder/binder_module.h
+++ b/libs/binder/binder_module.h
@@ -32,4 +32,34 @@
#include <linux/android/binder.h>
#include <sys/ioctl.h>
+struct binder_frozen_state_info {
+ binder_uintptr_t cookie;
+ __u32 is_frozen;
+};
+
+#ifndef BR_FROZEN_BINDER
+// Temporary definition of BR_FROZEN_BINDER until UAPI binder.h includes it.
+#define BR_FROZEN_BINDER _IOR('r', 21, struct binder_frozen_state_info)
+#endif // BR_FROZEN_BINDER
+
+#ifndef BR_CLEAR_FREEZE_NOTIFICATION_DONE
+// Temporary definition of BR_CLEAR_FREEZE_NOTIFICATION_DONE until UAPI binder.h includes it.
+#define BR_CLEAR_FREEZE_NOTIFICATION_DONE _IOR('r', 22, binder_uintptr_t)
+#endif // BR_CLEAR_FREEZE_NOTIFICATION_DONE
+
+#ifndef BC_REQUEST_FREEZE_NOTIFICATION
+// Temporary definition of BC_REQUEST_FREEZE_NOTIFICATION until UAPI binder.h includes it.
+#define BC_REQUEST_FREEZE_NOTIFICATION _IOW('c', 19, struct binder_handle_cookie)
+#endif // BC_REQUEST_FREEZE_NOTIFICATION
+
+#ifndef BC_CLEAR_FREEZE_NOTIFICATION
+// Temporary definition of BC_CLEAR_FREEZE_NOTIFICATION until UAPI binder.h includes it.
+#define BC_CLEAR_FREEZE_NOTIFICATION _IOW('c', 20, struct binder_handle_cookie)
+#endif // BC_CLEAR_FREEZE_NOTIFICATION
+
+#ifndef BC_FREEZE_NOTIFICATION_DONE
+// Temporary definition of BC_FREEZE_NOTIFICATION_DONE until UAPI binder.h includes it.
+#define BC_FREEZE_NOTIFICATION_DONE _IOW('c', 21, binder_uintptr_t)
+#endif // BC_FREEZE_NOTIFICATION_DONE
+
#endif // _BINDER_MODULE_H_
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index d7f74c4..7518044 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -29,6 +29,7 @@
// ---------------------------------------------------------------------------
namespace android {
+class IPCThreadState;
class RpcSession;
class RpcState;
namespace internal {
@@ -66,6 +67,12 @@
void* cookie = nullptr, uint32_t flags = 0,
wp<DeathRecipient>* outRecipient = nullptr);
+ [[nodiscard]] status_t addFrozenStateChangeCallback(
+ const wp<FrozenStateChangeCallback>& recipient);
+
+ [[nodiscard]] status_t removeFrozenStateChangeCallback(
+ const wp<FrozenStateChangeCallback>& recipient);
+
LIBBINDER_EXPORTED virtual void* attachObject(const void* objectID, void* object,
void* cleanupCookie,
object_cleanup_func func) final;
@@ -75,7 +82,6 @@
LIBBINDER_EXPORTED sp<IBinder> lookupOrCreateWeak(const void* objectID,
IBinder::object_make_func make,
const void* makeArgs);
-
LIBBINDER_EXPORTED virtual BpBinder* remoteBinder();
LIBBINDER_EXPORTED void sendObituary();
@@ -132,9 +138,14 @@
friend class ::android::ProcessState;
friend class ::android::RpcSession;
friend class ::android::RpcState;
- explicit PrivateAccessor(const BpBinder* binder) : mBinder(binder) {}
+ friend class ::android::IPCThreadState;
+ explicit PrivateAccessor(const BpBinder* binder)
+ : mBinder(binder), mMutableBinder(nullptr) {}
+ explicit PrivateAccessor(BpBinder* binder) : mBinder(binder), mMutableBinder(binder) {}
- static sp<BpBinder> create(int32_t handle) { return BpBinder::create(handle); }
+ static sp<BpBinder> create(int32_t handle, std::function<void()>* postTask) {
+ return BpBinder::create(handle, postTask);
+ }
static sp<BpBinder> create(const sp<RpcSession>& session, uint64_t address) {
return BpBinder::create(session, address);
}
@@ -146,17 +157,22 @@
uint64_t rpcAddress() const { return mBinder->rpcAddress(); }
const sp<RpcSession>& rpcSession() const { return mBinder->rpcSession(); }
+ void onFrozenStateChanged(bool isFrozen) { mMutableBinder->onFrozenStateChanged(isFrozen); }
const BpBinder* mBinder;
+ BpBinder* mMutableBinder;
};
+
LIBBINDER_EXPORTED const PrivateAccessor getPrivateAccessor() const {
return PrivateAccessor(this);
}
+ PrivateAccessor getPrivateAccessor() { return PrivateAccessor(this); }
+
private:
friend PrivateAccessor;
friend class sp<BpBinder>;
- static sp<BpBinder> create(int32_t handle);
+ static sp<BpBinder> create(int32_t handle, std::function<void()>* postTask);
static sp<BpBinder> create(const sp<RpcSession>& session, uint64_t address);
struct BinderHandle {
@@ -192,6 +208,14 @@
uint32_t flags;
};
+ void onFrozenStateChanged(bool isFrozen);
+
+ struct FrozenStateChange {
+ bool isFrozen = false;
+ Vector<wp<FrozenStateChangeCallback>> callbacks;
+ bool initialStateReceived = false;
+ };
+
void reportOneDeath(const Obituary& obit);
bool isDescriptorCached() const;
@@ -199,6 +223,7 @@
volatile int32_t mAlive;
volatile int32_t mObitsSent;
Vector<Obituary>* mObituaries;
+ std::unique_ptr<FrozenStateChange> mFrozen;
ObjectManager mObjects;
mutable String16 mDescriptorCache;
int32_t mTrackedUid;
diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
index 4eb1c08..1ed7c91 100644
--- a/libs/binder/include/binder/IBinder.h
+++ b/libs/binder/include/binder/IBinder.h
@@ -202,9 +202,18 @@
virtual void binderDied(const wp<IBinder>& who) = 0;
};
- #if defined(__clang__)
- #pragma clang diagnostic pop
- #endif
+ class FrozenStateChangeCallback : public virtual RefBase {
+ public:
+ enum class State {
+ FROZEN,
+ UNFROZEN,
+ };
+ virtual void onStateChanged(const wp<IBinder>& who, State state) = 0;
+ };
+
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
/**
* Register the @a recipient for a notification if this binder
@@ -253,6 +262,48 @@
uint32_t flags = 0,
wp<DeathRecipient>* outRecipient = nullptr) = 0;
+ /**
+ * addFrozenStateChangeCallback provides a callback mechanism to notify
+ * about process frozen/unfrozen events. Upon registration and any
+ * subsequent state changes, the callback is invoked with the latest process
+ * frozen state.
+ *
+ * If the listener process (the one using this API) is itself frozen, state
+ * change events might be combined into a single one with the latest state.
+ * (meaning 'frozen, unfrozen' might just be 'unfrozen'). This single event
+ * would then be delivered when the listener process becomes unfrozen.
+ * Similarly, if an event happens before the previous event is consumed,
+ * they might be combined. This means the callback might not be called for
+ * every single state change, so don't rely on this API to count how many
+ * times the state has changed.
+ *
+ * @note When all references to the binder are dropped, the callback is
+ * automatically removed. So, you must hold onto a binder in order to
+ * receive notifications about it.
+ *
+ * @note You will only receive freeze notifications for remote binders, as
+ * local binders by definition can't be frozen without you being frozen as
+ * well. Trying to use this function on a local binder will result in an
+ * INVALID_OPERATION code being returned and nothing happening.
+ *
+ * @note This binder always holds a weak reference to the callback.
+ *
+ * @note You will only receive a weak reference to the binder object. You
+ * should not try to promote this to a strong reference. (Nor should you
+ * need to, as there is nothing useful you can directly do with it now that
+ * it has passed on.)
+ */
+ [[nodiscard]] status_t addFrozenStateChangeCallback(
+ const wp<FrozenStateChangeCallback>& callback);
+
+ /**
+ * Remove a previously registered freeze callback.
+ * The @a callback will no longer be called if this object
+ * changes its frozen state.
+ */
+ [[nodiscard]] status_t removeFrozenStateChangeCallback(
+ const wp<FrozenStateChangeCallback>& callback);
+
virtual bool checkSubclass(const void* subclassID) const;
typedef void (*object_cleanup_func)(const void* id, void* obj, void* cleanupCookie);
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index 09ab442..9ef4e69 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -174,6 +174,8 @@
LIBBINDER_EXPORTED static void expungeHandle(int32_t handle, IBinder* binder);
LIBBINDER_EXPORTED status_t requestDeathNotification(int32_t handle, BpBinder* proxy);
LIBBINDER_EXPORTED status_t clearDeathNotification(int32_t handle, BpBinder* proxy);
+ [[nodiscard]] status_t addFrozenStateChangeCallback(int32_t handle, BpBinder* proxy);
+ [[nodiscard]] status_t removeFrozenStateChangeCallback(int32_t handle, BpBinder* proxy);
LIBBINDER_EXPORTED static void shutdown();
@@ -210,13 +212,14 @@
IPCThreadState();
~IPCThreadState();
- status_t sendReply(const Parcel& reply, uint32_t flags);
- status_t waitForResponse(Parcel* reply, status_t* acquireResult = nullptr);
- status_t talkWithDriver(bool doReceive = true);
- status_t writeTransactionData(int32_t cmd, uint32_t binderFlags, int32_t handle, uint32_t code,
- const Parcel& data, status_t* statusBuffer);
- status_t getAndExecuteCommand();
- status_t executeCommand(int32_t command);
+ [[nodiscard]] status_t sendReply(const Parcel& reply, uint32_t flags);
+ [[nodiscard]] status_t waitForResponse(Parcel* reply, status_t* acquireResult = nullptr);
+ [[nodiscard]] status_t talkWithDriver(bool doReceive = true);
+ [[nodiscard]] status_t writeTransactionData(int32_t cmd, uint32_t binderFlags, int32_t handle,
+ uint32_t code, const Parcel& data,
+ status_t* statusBuffer);
+ [[nodiscard]] status_t getAndExecuteCommand();
+ [[nodiscard]] status_t executeCommand(int32_t command);
void processPendingDerefs();
void processPostWriteDerefs();
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index 021bd58..21bfd42 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -133,6 +133,7 @@
enum class DriverFeature {
ONEWAY_SPAM_DETECTION,
EXTENDED_ERROR,
+ FREEZE_NOTIFICATION,
};
// Determine whether a feature is supported by the binder driver.
LIBBINDER_EXPORTED static bool isDriverFeatureEnabled(const DriverFeature feature);
@@ -188,8 +189,8 @@
Vector<handle_entry> mHandleToObject;
bool mForked;
- bool mThreadPoolStarted;
- volatile int32_t mThreadPoolSeq;
+ std::atomic_bool mThreadPoolStarted;
+ std::atomic_int32_t mThreadPoolSeq;
CallRestriction mCallRestriction;
};
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 26c228d..4e02ace 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -255,6 +255,9 @@
"include_cpp/android/*.h",
],
license: "NOTICE",
+ // These are intentionally not C. It's a mistake that they're in the NDK.
+ // See the bug above.
+ skip_verification: true,
}
ndk_library {
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index 2929bce..72d255e 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -771,7 +771,7 @@
* This provides a per-process-unique total ordering of binders where a null
* AIBinder* object is considered to be before all other binder objects.
* For instance, two binders refer to the same object in a local or remote
- * process when both AIBinder_lt(a, b) and AIBinder(b, a) are false. This API
+ * process when both AIBinder_lt(a, b) and AIBinder_lt(b, a) are false. This API
* might be used to insert and lookup binders in binary search trees.
*
* AIBinder* pointers themselves actually also create a per-process-unique total
diff --git a/libs/binder/ndk/include_platform/android/binder_process.h b/libs/binder/ndk/include_platform/android/binder_process.h
index 68528e1..6aff994 100644
--- a/libs/binder/ndk/include_platform/android/binder_process.h
+++ b/libs/binder/ndk/include_platform/android/binder_process.h
@@ -47,8 +47,11 @@
* be called once before startThreadPool. The number of threads can never decrease.
*
* This count refers to the number of threads that will be created lazily by the kernel, in
- * addition to the threads created by ABinderProcess_startThreadPool or
- * ABinderProcess_joinThreadPool.
+ * addition to the single threads created by ABinderProcess_startThreadPool (+1) or
+ * ABinderProcess_joinThreadPool (+1). Note: ABinderProcess_startThreadPool starts a thread
+ * itself, but it also enables up to the number of threads passed to this function to start.
+ * This function does not start any threads itself; it only configures
+ * ABinderProcess_startThreadPool.
*
* Do not use this from a library. Apps setup their own threadpools, and otherwise, the main
* function should be responsible for configuring the threadpool for the entire application.
@@ -63,8 +66,8 @@
bool ABinderProcess_isThreadPoolStarted(void);
/**
* This adds the current thread to the threadpool. This thread will be in addition to the thread
- * started by ABinderProcess_startThreadPool and the lazy kernel-started threads specified by
- * ABinderProcess_setThreadPoolMaxThreadCount.
+ * configured with ABinderProcess_setThreadPoolMaxThreadCount and started with
+ * ABinderProcess_startThreadPool.
*
* Do not use this from a library. Apps setup their own threadpools, and otherwise, the main
* function should be responsible for configuring the threadpool for the entire application.
diff --git a/libs/binder/rust/rpcbinder/Android.bp b/libs/binder/rust/rpcbinder/Android.bp
index 2e46345..174fe8a 100644
--- a/libs/binder/rust/rpcbinder/Android.bp
+++ b/libs/binder/rust/rpcbinder/Android.bp
@@ -32,6 +32,7 @@
apex_available: [
"//apex_available:platform",
"com.android.compos",
+ "com.android.microfuchsia",
"com.android.uwb",
"com.android.virt",
],
@@ -60,6 +61,7 @@
apex_available: [
"//apex_available:platform",
"com.android.compos",
+ "com.android.microfuchsia",
"com.android.uwb",
"com.android.virt",
],
@@ -93,6 +95,7 @@
apex_available: [
"//apex_available:platform",
"com.android.compos",
+ "com.android.microfuchsia",
"com.android.uwb",
"com.android.virt",
],
diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs
index 33dfe19..7f70396 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -1333,7 +1333,7 @@
let vec = Vec::<u8>::deserialize(parcel.borrowed_ref()).unwrap();
assert_eq!(vec, [-128i8 as u8, 127, 42, -117i8 as u8]);
- let u16s = [u16::max_value(), 12_345, 42, 117];
+ let u16s = [u16::MAX, 12_345, 42, 117];
// SAFETY: start is less than the current size of the parcel data buffer, because we haven't
// made it any shorter since we got the position.
@@ -1348,7 +1348,7 @@
}
assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
- assert_eq!(parcel.read::<u32>().unwrap(), 0xffff); // u16::max_value()
+ assert_eq!(parcel.read::<u32>().unwrap(), 0xffff); // u16::MAX
assert_eq!(parcel.read::<u32>().unwrap(), 12345); // 12,345
assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
assert_eq!(parcel.read::<u32>().unwrap(), 117); // 117
@@ -1361,9 +1361,9 @@
let vec = Vec::<u16>::deserialize(parcel.borrowed_ref()).unwrap();
- assert_eq!(vec, [u16::max_value(), 12_345, 42, 117]);
+ assert_eq!(vec, [u16::MAX, 12_345, 42, 117]);
- let i16s = [i16::max_value(), i16::min_value(), 42, -117];
+ let i16s = [i16::MAX, i16::MIN, 42, -117];
// SAFETY: start is less than the current size of the parcel data buffer, because we haven't
// made it any shorter since we got the position.
@@ -1378,8 +1378,8 @@
}
assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
- assert_eq!(parcel.read::<u32>().unwrap(), 0x7fff); // i16::max_value()
- assert_eq!(parcel.read::<u32>().unwrap(), 0x8000); // i16::min_value()
+ assert_eq!(parcel.read::<u32>().unwrap(), 0x7fff); // i16::MAX
+ assert_eq!(parcel.read::<u32>().unwrap(), 0x8000); // i16::MIN
assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
assert_eq!(parcel.read::<u32>().unwrap(), 0xff8b); // -117
@@ -1391,9 +1391,9 @@
let vec = Vec::<i16>::deserialize(parcel.borrowed_ref()).unwrap();
- assert_eq!(vec, [i16::max_value(), i16::min_value(), 42, -117]);
+ assert_eq!(vec, [i16::MAX, i16::MIN, 42, -117]);
- let u32s = [u32::max_value(), 12_345, 42, 117];
+ let u32s = [u32::MAX, 12_345, 42, 117];
// SAFETY: start is less than the current size of the parcel data buffer, because we haven't
// made it any shorter since we got the position.
@@ -1408,7 +1408,7 @@
}
assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
- assert_eq!(parcel.read::<u32>().unwrap(), 0xffffffff); // u32::max_value()
+ assert_eq!(parcel.read::<u32>().unwrap(), 0xffffffff); // u32::MAX
assert_eq!(parcel.read::<u32>().unwrap(), 12345); // 12,345
assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
assert_eq!(parcel.read::<u32>().unwrap(), 117); // 117
@@ -1421,9 +1421,9 @@
let vec = Vec::<u32>::deserialize(parcel.borrowed_ref()).unwrap();
- assert_eq!(vec, [u32::max_value(), 12_345, 42, 117]);
+ assert_eq!(vec, [u32::MAX, 12_345, 42, 117]);
- let i32s = [i32::max_value(), i32::min_value(), 42, -117];
+ let i32s = [i32::MAX, i32::MIN, 42, -117];
// SAFETY: start is less than the current size of the parcel data buffer, because we haven't
// made it any shorter since we got the position.
@@ -1438,8 +1438,8 @@
}
assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
- assert_eq!(parcel.read::<u32>().unwrap(), 0x7fffffff); // i32::max_value()
- assert_eq!(parcel.read::<u32>().unwrap(), 0x80000000); // i32::min_value()
+ assert_eq!(parcel.read::<u32>().unwrap(), 0x7fffffff); // i32::MAX
+ assert_eq!(parcel.read::<u32>().unwrap(), 0x80000000); // i32::MIN
assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
assert_eq!(parcel.read::<u32>().unwrap(), 0xffffff8b); // -117
@@ -1451,9 +1451,9 @@
let vec = Vec::<i32>::deserialize(parcel.borrowed_ref()).unwrap();
- assert_eq!(vec, [i32::max_value(), i32::min_value(), 42, -117]);
+ assert_eq!(vec, [i32::MAX, i32::MIN, 42, -117]);
- let u64s = [u64::max_value(), 12_345, 42, 117];
+ let u64s = [u64::MAX, 12_345, 42, 117];
// SAFETY: start is less than the current size of the parcel data buffer, because we haven't
// made it any shorter since we got the position.
@@ -1469,9 +1469,9 @@
let vec = Vec::<u64>::deserialize(parcel.borrowed_ref()).unwrap();
- assert_eq!(vec, [u64::max_value(), 12_345, 42, 117]);
+ assert_eq!(vec, [u64::MAX, 12_345, 42, 117]);
- let i64s = [i64::max_value(), i64::min_value(), 42, -117];
+ let i64s = [i64::MAX, i64::MIN, 42, -117];
// SAFETY: start is less than the current size of the parcel data buffer, because we haven't
// made it any shorter since we got the position.
@@ -1487,9 +1487,9 @@
let vec = Vec::<i64>::deserialize(parcel.borrowed_ref()).unwrap();
- assert_eq!(vec, [i64::max_value(), i64::min_value(), 42, -117]);
+ assert_eq!(vec, [i64::MAX, i64::MIN, 42, -117]);
- let f32s = [std::f32::NAN, std::f32::INFINITY, 1.23456789, std::f32::EPSILON];
+ let f32s = [f32::NAN, f32::INFINITY, 1.23456789, f32::EPSILON];
// SAFETY: start is less than the current size of the parcel data buffer, because we haven't
// made it any shorter since we got the position.
@@ -1509,7 +1509,7 @@
assert!(vec[0].is_nan());
assert_eq!(vec[1..], f32s[1..]);
- let f64s = [std::f64::NAN, std::f64::INFINITY, 1.234567890123456789, std::f64::EPSILON];
+ let f64s = [f64::NAN, f64::INFINITY, 1.234567890123456789, f64::EPSILON];
// SAFETY: start is less than the current size of the parcel data buffer, because we haven't
// made it any shorter since we got the position.
diff --git a/libs/binder/rust/tests/serialization.rs b/libs/binder/rust/tests/serialization.rs
index 2b6c282..a902e96 100644
--- a/libs/binder/rust/tests/serialization.rs
+++ b/libs/binder/rust/tests/serialization.rs
@@ -124,7 +124,7 @@
bindings::Transaction_TEST_BYTE => {
assert_eq!(parcel.read::<i8>()?, 0);
assert_eq!(parcel.read::<i8>()?, 1);
- assert_eq!(parcel.read::<i8>()?, i8::max_value());
+ assert_eq!(parcel.read::<i8>()?, i8::MAX);
// SAFETY: Just reading an extern constant.
assert_eq!(parcel.read::<Vec<i8>>()?, unsafe { bindings::TESTDATA_I8 });
// SAFETY: Just reading an extern constant.
@@ -133,7 +133,7 @@
reply.write(&0i8)?;
reply.write(&1i8)?;
- reply.write(&i8::max_value())?;
+ reply.write(&i8::MAX)?;
// SAFETY: Just reading an extern constant.
reply.write(&unsafe { bindings::TESTDATA_I8 }[..])?;
// SAFETY: Just reading an extern constant.
@@ -143,14 +143,14 @@
bindings::Transaction_TEST_U16 => {
assert_eq!(parcel.read::<u16>()?, 0);
assert_eq!(parcel.read::<u16>()?, 1);
- assert_eq!(parcel.read::<u16>()?, u16::max_value());
+ assert_eq!(parcel.read::<u16>()?, u16::MAX);
// SAFETY: Just reading an extern constant.
assert_eq!(parcel.read::<Vec<u16>>()?, unsafe { bindings::TESTDATA_CHARS });
assert_eq!(parcel.read::<Option<Vec<u16>>>()?, None);
reply.write(&0u16)?;
reply.write(&1u16)?;
- reply.write(&u16::max_value())?;
+ reply.write(&u16::MAX)?;
// SAFETY: Just reading an extern constant.
reply.write(&unsafe { bindings::TESTDATA_CHARS }[..])?;
reply.write(&(None as Option<Vec<u16>>))?;
@@ -158,14 +158,14 @@
bindings::Transaction_TEST_I32 => {
assert_eq!(parcel.read::<i32>()?, 0);
assert_eq!(parcel.read::<i32>()?, 1);
- assert_eq!(parcel.read::<i32>()?, i32::max_value());
+ assert_eq!(parcel.read::<i32>()?, i32::MAX);
// SAFETY: Just reading an extern constant.
assert_eq!(parcel.read::<Vec<i32>>()?, unsafe { bindings::TESTDATA_I32 });
assert_eq!(parcel.read::<Option<Vec<i32>>>()?, None);
reply.write(&0i32)?;
reply.write(&1i32)?;
- reply.write(&i32::max_value())?;
+ reply.write(&i32::MAX)?;
// SAFETY: Just reading an extern constant.
reply.write(&unsafe { bindings::TESTDATA_I32 }[..])?;
reply.write(&(None as Option<Vec<i32>>))?;
@@ -173,14 +173,14 @@
bindings::Transaction_TEST_I64 => {
assert_eq!(parcel.read::<i64>()?, 0);
assert_eq!(parcel.read::<i64>()?, 1);
- assert_eq!(parcel.read::<i64>()?, i64::max_value());
+ assert_eq!(parcel.read::<i64>()?, i64::MAX);
// SAFETY: Just reading an extern constant.
assert_eq!(parcel.read::<Vec<i64>>()?, unsafe { bindings::TESTDATA_I64 });
assert_eq!(parcel.read::<Option<Vec<i64>>>()?, None);
reply.write(&0i64)?;
reply.write(&1i64)?;
- reply.write(&i64::max_value())?;
+ reply.write(&i64::MAX)?;
// SAFETY: Just reading an extern constant.
reply.write(&unsafe { bindings::TESTDATA_I64 }[..])?;
reply.write(&(None as Option<Vec<i64>>))?;
@@ -188,14 +188,14 @@
bindings::Transaction_TEST_U64 => {
assert_eq!(parcel.read::<u64>()?, 0);
assert_eq!(parcel.read::<u64>()?, 1);
- assert_eq!(parcel.read::<u64>()?, u64::max_value());
+ assert_eq!(parcel.read::<u64>()?, u64::MAX);
// SAFETY: Just reading an extern constant.
assert_eq!(parcel.read::<Vec<u64>>()?, unsafe { bindings::TESTDATA_U64 });
assert_eq!(parcel.read::<Option<Vec<u64>>>()?, None);
reply.write(&0u64)?;
reply.write(&1u64)?;
- reply.write(&u64::max_value())?;
+ reply.write(&u64::MAX)?;
// SAFETY: Just reading an extern constant.
reply.write(&unsafe { bindings::TESTDATA_U64 }[..])?;
reply.write(&(None as Option<Vec<u64>>))?;
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index dd50fbd..9578713 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -42,8 +42,11 @@
defaults: ["binder_test_defaults"],
header_libs: ["libbinder_headers"],
srcs: ["binderDriverInterfaceTest.cpp"],
+ shared_libs: [
+ "libbinder",
+ ],
test_suites: [
- "device-tests",
+ "general-tests",
"vts",
],
}
@@ -127,13 +130,14 @@
"libbase",
"libbinder",
"liblog",
+ "libprocessgroup",
"libutils",
],
static_libs: [
"libgmock",
],
test_suites: [
- "device-tests",
+ "general-tests",
"vts",
],
require_root: true,
@@ -701,7 +705,7 @@
"libutils",
],
test_suites: [
- "device-tests",
+ "general-tests",
"vts",
],
require_root: true,
@@ -758,7 +762,7 @@
],
test_suites: [
- "device-tests",
+ "general-tests",
"vts",
],
require_root: true,
diff --git a/libs/binder/tests/binderDriverInterfaceTest.cpp b/libs/binder/tests/binderDriverInterfaceTest.cpp
index 7be4f21..af82860 100644
--- a/libs/binder/tests/binderDriverInterfaceTest.cpp
+++ b/libs/binder/tests/binderDriverInterfaceTest.cpp
@@ -20,12 +20,15 @@
#include <stdlib.h>
#include <binder/IBinder.h>
+#include <binder/ProcessState.h>
#include <gtest/gtest.h>
#include <linux/android/binder.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
+#include "../binder_module.h"
+
#define BINDER_DEV_NAME "/dev/binder"
testing::Environment* binder_env;
@@ -365,6 +368,251 @@
binderTestReadEmpty();
}
+TEST_F(BinderDriverInterfaceTest, RequestFrozenNotification) {
+ if (!android::ProcessState::isDriverFeatureEnabled(
+ android::ProcessState::DriverFeature::FREEZE_NOTIFICATION)) {
+ GTEST_SKIP() << "Skipping test for kernels that support freeze notification";
+ return;
+ }
+ binder_uintptr_t cookie = 1234;
+ struct {
+ uint32_t cmd0;
+ uint32_t arg0;
+ uint32_t cmd1;
+ struct binder_handle_cookie arg1;
+ } __attribute__((packed)) bc1 = {
+ .cmd0 = BC_INCREFS,
+ .arg0 = 0,
+ .cmd1 = BC_REQUEST_FREEZE_NOTIFICATION,
+ .arg1 =
+ {
+ .handle = 0,
+ .cookie = cookie,
+ },
+ };
+ struct {
+ uint32_t cmd0;
+ // Expecting a BR_FROZEN_BINDER since BC_REQUEST_FREEZE_NOTIFICATION
+ // above should lead to an immediate notification of the current state.
+ uint32_t cmd1;
+ struct binder_frozen_state_info arg1;
+ uint32_t pad[16];
+ } __attribute__((packed)) br1;
+ struct {
+ uint32_t cmd2;
+ binder_uintptr_t arg2;
+ uint32_t cmd3;
+ struct binder_handle_cookie arg3;
+ uint32_t cmd4;
+ uint32_t arg4;
+ } __attribute__((packed)) bc2 = {
+ // Tell kernel that userspace has done handling BR_FROZEN_BINDER.
+ .cmd2 = BC_FREEZE_NOTIFICATION_DONE,
+ .arg2 = cookie,
+ .cmd3 = BC_CLEAR_FREEZE_NOTIFICATION,
+ .arg3 =
+ {
+ .handle = 0,
+ .cookie = cookie,
+ },
+ .cmd4 = BC_DECREFS,
+ .arg4 = 0,
+ };
+ struct {
+ uint32_t cmd2;
+ uint32_t cmd3;
+ binder_uintptr_t arg3;
+ uint32_t pad[16];
+ } __attribute__((packed)) br2;
+
+ struct binder_write_read bwr1 = binder_write_read();
+ bwr1.write_buffer = (uintptr_t)&bc1;
+ bwr1.write_size = sizeof(bc1);
+ bwr1.read_buffer = (uintptr_t)&br1;
+ bwr1.read_size = sizeof(br1);
+ binderTestIoctl(BINDER_WRITE_READ, &bwr1);
+ EXPECT_EQ(sizeof(bc1), bwr1.write_consumed);
+ EXPECT_EQ(sizeof(br1) - sizeof(br1.pad), bwr1.read_consumed);
+ EXPECT_EQ(BR_NOOP, br1.cmd0);
+ ASSERT_EQ(BR_FROZEN_BINDER, br1.cmd1);
+ EXPECT_FALSE(br1.arg1.is_frozen);
+
+ struct binder_write_read bwr2 = binder_write_read();
+ bwr2.write_buffer = (uintptr_t)&bc2;
+ bwr2.write_size = sizeof(bc2);
+ bwr2.read_buffer = (uintptr_t)&br2;
+ bwr2.read_size = sizeof(br2);
+ binderTestIoctl(BINDER_WRITE_READ, &bwr2);
+ EXPECT_EQ(sizeof(bc2), bwr2.write_consumed);
+ EXPECT_EQ(sizeof(br2) - sizeof(br2.pad), bwr2.read_consumed);
+ EXPECT_EQ(BR_NOOP, br2.cmd2);
+ EXPECT_EQ(BR_CLEAR_FREEZE_NOTIFICATION_DONE, br2.cmd3);
+ EXPECT_EQ(cookie, br2.arg3);
+
+ binderTestReadEmpty();
+}
+
+TEST_F(BinderDriverInterfaceTest, OverwritePendingFrozenNotification) {
+ if (!android::ProcessState::isDriverFeatureEnabled(
+ android::ProcessState::DriverFeature::FREEZE_NOTIFICATION)) {
+ GTEST_SKIP() << "Skipping test for kernels that support freeze notification";
+ return;
+ }
+ binder_uintptr_t cookie = 1234;
+ struct {
+ uint32_t cmd0;
+ uint32_t arg0;
+ uint32_t cmd1;
+ struct binder_handle_cookie arg1;
+ uint32_t cmd2;
+ struct binder_handle_cookie arg2;
+ uint32_t cmd3;
+ uint32_t arg3;
+ } __attribute__((packed)) bc = {
+ .cmd0 = BC_INCREFS,
+ .arg0 = 0,
+ .cmd1 = BC_REQUEST_FREEZE_NOTIFICATION,
+ // This BC_REQUEST_FREEZE_NOTIFICATION should lead to a pending
+ // frozen notification inserted into the queue.
+ .arg1 =
+ {
+ .handle = 0,
+ .cookie = cookie,
+ },
+ // Send BC_CLEAR_FREEZE_NOTIFICATION before the above frozen
+ // notification has a chance of being sent. The notification should
+ // be overwritten. Userspace is expected to only receive
+ // BR_CLEAR_FREEZE_NOTIFICATION_DONE.
+ .cmd2 = BC_CLEAR_FREEZE_NOTIFICATION,
+ .arg2 =
+ {
+ .handle = 0,
+ .cookie = cookie,
+ },
+ .cmd3 = BC_DECREFS,
+ .arg3 = 0,
+ };
+ struct {
+ uint32_t cmd0;
+ uint32_t cmd1;
+ binder_uintptr_t arg1;
+ uint32_t pad[16];
+ } __attribute__((packed)) br;
+ struct binder_write_read bwr = binder_write_read();
+
+ bwr.write_buffer = (uintptr_t)&bc;
+ bwr.write_size = sizeof(bc);
+ bwr.read_buffer = (uintptr_t)&br;
+ bwr.read_size = sizeof(br);
+
+ binderTestIoctl(BINDER_WRITE_READ, &bwr);
+ EXPECT_EQ(sizeof(bc), bwr.write_consumed);
+ EXPECT_EQ(sizeof(br) - sizeof(br.pad), bwr.read_consumed);
+ EXPECT_EQ(BR_NOOP, br.cmd0);
+ EXPECT_EQ(BR_CLEAR_FREEZE_NOTIFICATION_DONE, br.cmd1);
+ EXPECT_EQ(cookie, br.arg1);
+ binderTestReadEmpty();
+}
+
+TEST_F(BinderDriverInterfaceTest, ResendFrozenNotification) {
+ if (!android::ProcessState::isDriverFeatureEnabled(
+ android::ProcessState::DriverFeature::FREEZE_NOTIFICATION)) {
+ GTEST_SKIP() << "Skipping test for kernels that support freeze notification";
+ return;
+ }
+ binder_uintptr_t cookie = 1234;
+ struct {
+ uint32_t cmd0;
+ uint32_t arg0;
+ uint32_t cmd1;
+ struct binder_handle_cookie arg1;
+ } __attribute__((packed)) bc1 = {
+ .cmd0 = BC_INCREFS,
+ .arg0 = 0,
+ .cmd1 = BC_REQUEST_FREEZE_NOTIFICATION,
+ .arg1 =
+ {
+ .handle = 0,
+ .cookie = cookie,
+ },
+ };
+ struct {
+ uint32_t cmd0;
+ uint32_t cmd1;
+ struct binder_frozen_state_info arg1;
+ uint32_t pad[16];
+ } __attribute__((packed)) br1;
+ struct {
+ uint32_t cmd2;
+ struct binder_handle_cookie arg2;
+ } __attribute__((packed)) bc2 = {
+ // Clear the notification before acknowledging the in-flight
+ // BR_FROZEN_BINDER. Kernel should hold off sending
+ // BR_CLEAR_FREEZE_NOTIFICATION_DONE until the acknowledgement
+ // reaches kernel.
+ .cmd2 = BC_CLEAR_FREEZE_NOTIFICATION,
+ .arg2 =
+ {
+ .handle = 0,
+ .cookie = cookie,
+ },
+ };
+ struct {
+ uint32_t pad[16];
+ } __attribute__((packed)) br2;
+ struct {
+ uint32_t cmd3;
+ binder_uintptr_t arg3;
+ uint32_t cmd4;
+ uint32_t arg4;
+ } __attribute__((packed)) bc3 = {
+ // Send the acknowledgement. Now the kernel should send out
+ // BR_CLEAR_FREEZE_NOTIFICATION_DONE.
+ .cmd3 = BC_FREEZE_NOTIFICATION_DONE,
+ .arg3 = cookie,
+ .cmd4 = BC_DECREFS,
+ .arg4 = 0,
+ };
+ struct {
+ uint32_t cmd2;
+ uint32_t cmd3;
+ binder_uintptr_t arg3;
+ uint32_t pad[16];
+ } __attribute__((packed)) br3;
+
+ struct binder_write_read bwr1 = binder_write_read();
+ bwr1.write_buffer = (uintptr_t)&bc1;
+ bwr1.write_size = sizeof(bc1);
+ bwr1.read_buffer = (uintptr_t)&br1;
+ bwr1.read_size = sizeof(br1);
+ binderTestIoctl(BINDER_WRITE_READ, &bwr1);
+ EXPECT_EQ(sizeof(bc1), bwr1.write_consumed);
+ EXPECT_EQ(sizeof(br1) - sizeof(br1.pad), bwr1.read_consumed);
+ EXPECT_EQ(BR_NOOP, br1.cmd0);
+ ASSERT_EQ(BR_FROZEN_BINDER, br1.cmd1);
+ EXPECT_FALSE(br1.arg1.is_frozen);
+
+ struct binder_write_read bwr2 = binder_write_read();
+ bwr2.write_buffer = (uintptr_t)&bc2;
+ bwr2.write_size = sizeof(bc2);
+ bwr2.read_buffer = (uintptr_t)&br2;
+ bwr2.read_size = sizeof(br2);
+ binderTestIoctlSuccessOrError(BINDER_WRITE_READ, &bwr2, EAGAIN);
+ binderTestReadEmpty();
+
+ struct binder_write_read bwr3 = binder_write_read();
+ bwr3.write_buffer = (uintptr_t)&bc3;
+ bwr3.write_size = sizeof(bc3);
+ bwr3.read_buffer = (uintptr_t)&br3;
+ bwr3.read_size = sizeof(br3);
+ binderTestIoctl(BINDER_WRITE_READ, &bwr3);
+ EXPECT_EQ(sizeof(bc3), bwr3.write_consumed);
+ EXPECT_EQ(sizeof(br3) - sizeof(br3.pad), bwr3.read_consumed);
+ EXPECT_EQ(BR_CLEAR_FREEZE_NOTIFICATION_DONE, br3.cmd3);
+ EXPECT_EQ(cookie, br3.arg3);
+ binderTestReadEmpty();
+}
+
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 9b1ba01..bcab6de 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -27,6 +27,7 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/result-gmock.h>
#include <binder/Binder.h>
@@ -39,6 +40,8 @@
#include <binder/RpcSession.h>
#include <binder/Status.h>
#include <binder/unique_fd.h>
+#include <input/BlockingQueue.h>
+#include <processgroup/processgroup.h>
#include <utils/Flattenable.h>
#include <linux/sched.h>
@@ -57,6 +60,7 @@
using android::base::testing::HasValue;
using android::binder::Status;
using android::binder::unique_fd;
+using std::chrono_literals::operator""ms;
using testing::ExplainMatchResult;
using testing::Matcher;
using testing::Not;
@@ -115,6 +119,8 @@
BINDER_LIB_TEST_NOP_TRANSACTION_WAIT,
BINDER_LIB_TEST_GETPID,
BINDER_LIB_TEST_GETUID,
+ BINDER_LIB_TEST_LISTEN_FOR_FROZEN_STATE_CHANGE,
+ BINDER_LIB_TEST_CONSUME_STATE_CHANGE_EVENTS,
BINDER_LIB_TEST_ECHO_VECTOR,
BINDER_LIB_TEST_GET_NON_BLOCKING_FD,
BINDER_LIB_TEST_REJECT_OBJECTS,
@@ -247,6 +253,43 @@
sp<IBinder> m_server;
};
+class TestFrozenStateChangeCallback : public IBinder::FrozenStateChangeCallback {
+public:
+ BlockingQueue<std::pair<const wp<IBinder>, State>> events;
+
+ virtual void onStateChanged(const wp<IBinder>& who, State state) {
+ events.push(std::make_pair(who, state));
+ }
+
+ void ensureFrozenEventReceived() {
+ auto event = events.popWithTimeout(500ms);
+ ASSERT_TRUE(event.has_value());
+ EXPECT_EQ(State::FROZEN, event->second); // isFrozen should be true
+ EXPECT_EQ(0u, events.size());
+ }
+
+ void ensureUnfrozenEventReceived() {
+ auto event = events.popWithTimeout(500ms);
+ ASSERT_TRUE(event.has_value());
+ EXPECT_EQ(State::UNFROZEN, event->second); // isFrozen should be false
+ EXPECT_EQ(0u, events.size());
+ }
+
+ std::vector<bool> getAllAndClear() {
+ std::vector<bool> results;
+ while (true) {
+ auto event = events.popWithTimeout(0ms);
+ if (!event.has_value()) {
+ break;
+ }
+ results.push_back(event->second == State::FROZEN);
+ }
+ return results;
+ }
+
+ sp<IBinder> binder;
+};
+
class BinderLibTest : public ::testing::Test {
public:
virtual void SetUp() {
@@ -291,6 +334,51 @@
EXPECT_EQ(1, ret);
}
+ bool checkFreezeSupport() {
+ std::ifstream freezer_file("/sys/fs/cgroup/uid_0/cgroup.freeze");
+ // Pass test on devices where the cgroup v2 freezer is not supported
+ if (freezer_file.fail()) {
+ return false;
+ }
+ return IPCThreadState::self()->freeze(getpid(), false, 0) == NO_ERROR;
+ }
+
+ bool checkFreezeAndNotificationSupport() {
+ if (!checkFreezeSupport()) {
+ return false;
+ }
+ return ProcessState::isDriverFeatureEnabled(
+ ProcessState::DriverFeature::FREEZE_NOTIFICATION);
+ }
+
+ bool getBinderPid(int32_t* pid, sp<IBinder> server) {
+ Parcel data, replypid;
+ if (server->transact(BINDER_LIB_TEST_GETPID, data, &replypid) != NO_ERROR) {
+ ALOGE("BINDER_LIB_TEST_GETPID failed");
+ return false;
+ }
+ *pid = replypid.readInt32();
+ if (*pid <= 0) {
+ ALOGE("pid should be greater than zero");
+ return false;
+ }
+ return true;
+ }
+
+ void freezeProcess(int32_t pid) {
+ EXPECT_EQ(NO_ERROR, IPCThreadState::self()->freeze(pid, true, 1000));
+ }
+
+ void unfreezeProcess(int32_t pid) {
+ EXPECT_EQ(NO_ERROR, IPCThreadState::self()->freeze(pid, false, 0));
+ }
+
+ void removeCallbackAndValidateNoEvent(sp<IBinder> binder,
+ sp<TestFrozenStateChangeCallback> callback) {
+ EXPECT_THAT(binder->removeFrozenStateChangeCallback(callback), StatusEq(NO_ERROR));
+ EXPECT_EQ(0u, callback->events.size());
+ }
+
sp<IBinder> m_server;
};
@@ -516,29 +604,18 @@
}
TEST_F(BinderLibTest, Freeze) {
- Parcel data, reply, replypid;
- std::ifstream freezer_file("/sys/fs/cgroup/uid_0/cgroup.freeze");
-
- // Pass test on devices where the cgroup v2 freezer is not supported
- if (freezer_file.fail()) {
- GTEST_SKIP();
+ if (!checkFreezeSupport()) {
+ GTEST_SKIP() << "Skipping test for kernels that do not support proceess freezing";
return;
}
-
+ Parcel data, reply, replypid;
EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_GETPID, data, &replypid), StatusEq(NO_ERROR));
int32_t pid = replypid.readInt32();
for (int i = 0; i < 10; i++) {
EXPECT_EQ(NO_ERROR, m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION_WAIT, data, &reply, TF_ONE_WAY));
}
- // Pass test on devices where BINDER_FREEZE ioctl is not supported
- int ret = IPCThreadState::self()->freeze(pid, false, 0);
- if (ret == -EINVAL) {
- GTEST_SKIP();
- return;
- }
- EXPECT_EQ(NO_ERROR, ret);
-
+ EXPECT_EQ(NO_ERROR, IPCThreadState::self()->freeze(pid, false, 0));
EXPECT_EQ(-EAGAIN, IPCThreadState::self()->freeze(pid, true, 0));
// b/268232063 - succeeds ~0.08% of the time
@@ -835,6 +912,199 @@
EXPECT_THAT(callback->getResult(), StatusEq(NO_ERROR));
}
+TEST_F(BinderLibTest, ReturnErrorIfKernelDoesNotSupportFreezeNotification) {
+ if (ProcessState::isDriverFeatureEnabled(ProcessState::DriverFeature::FREEZE_NOTIFICATION)) {
+ GTEST_SKIP() << "Skipping test for kernels that support FREEZE_NOTIFICATION";
+ return;
+ }
+ sp<TestFrozenStateChangeCallback> callback = sp<TestFrozenStateChangeCallback>::make();
+ sp<IBinder> binder = addServer();
+ ASSERT_NE(nullptr, binder);
+ ASSERT_EQ(nullptr, binder->localBinder());
+ EXPECT_THAT(binder->addFrozenStateChangeCallback(callback), StatusEq(INVALID_OPERATION));
+}
+
+TEST_F(BinderLibTest, FrozenStateChangeNotificatiion) {
+ if (!checkFreezeAndNotificationSupport()) {
+ GTEST_SKIP() << "Skipping test for kernels that do not support FREEZE_NOTIFICATION";
+ return;
+ }
+ sp<TestFrozenStateChangeCallback> callback = sp<TestFrozenStateChangeCallback>::make();
+ sp<IBinder> binder = addServer();
+ ASSERT_NE(nullptr, binder);
+ int32_t pid;
+ ASSERT_TRUE(getBinderPid(&pid, binder));
+
+ EXPECT_THAT(binder->addFrozenStateChangeCallback(callback), StatusEq(NO_ERROR));
+ // Expect current state (unfrozen) to be delivered immediately.
+ callback->ensureUnfrozenEventReceived();
+ // Check that the process hasn't died otherwise there's a risk of freezing
+ // the wrong process.
+ EXPECT_EQ(OK, binder->pingBinder());
+ freezeProcess(pid);
+ callback->ensureFrozenEventReceived();
+ unfreezeProcess(pid);
+ callback->ensureUnfrozenEventReceived();
+ removeCallbackAndValidateNoEvent(binder, callback);
+}
+
+TEST_F(BinderLibTest, AddFrozenCallbackWhenFrozen) {
+ if (!checkFreezeAndNotificationSupport()) {
+ GTEST_SKIP() << "Skipping test for kernels that do not support FREEZE_NOTIFICATION";
+ return;
+ }
+ sp<TestFrozenStateChangeCallback> callback = sp<TestFrozenStateChangeCallback>::make();
+ sp<IBinder> binder = addServer();
+ ASSERT_NE(nullptr, binder);
+ int32_t pid;
+ ASSERT_TRUE(getBinderPid(&pid, binder));
+
+ // Check that the process hasn't died otherwise there's a risk of freezing
+ // the wrong process.
+ EXPECT_EQ(OK, binder->pingBinder());
+ freezeProcess(pid);
+ // Add the callback while the target process is frozen.
+ EXPECT_THAT(binder->addFrozenStateChangeCallback(callback), StatusEq(NO_ERROR));
+ callback->ensureFrozenEventReceived();
+ unfreezeProcess(pid);
+ callback->ensureUnfrozenEventReceived();
+ removeCallbackAndValidateNoEvent(binder, callback);
+
+ // Check that the process hasn't died otherwise there's a risk of freezing
+ // the wrong process.
+ EXPECT_EQ(OK, binder->pingBinder());
+ freezeProcess(pid);
+ unfreezeProcess(pid);
+ // Make sure no callback happens since the listener has been removed.
+ EXPECT_EQ(0u, callback->events.size());
+}
+
+TEST_F(BinderLibTest, NoFrozenNotificationAfterCallbackRemoval) {
+ if (!checkFreezeAndNotificationSupport()) {
+ GTEST_SKIP() << "Skipping test for kernels that do not support FREEZE_NOTIFICATION";
+ return;
+ }
+ sp<TestFrozenStateChangeCallback> callback = sp<TestFrozenStateChangeCallback>::make();
+ sp<IBinder> binder = addServer();
+ ASSERT_NE(nullptr, binder);
+ int32_t pid;
+ ASSERT_TRUE(getBinderPid(&pid, binder));
+
+ EXPECT_THAT(binder->addFrozenStateChangeCallback(callback), StatusEq(NO_ERROR));
+ callback->ensureUnfrozenEventReceived();
+ removeCallbackAndValidateNoEvent(binder, callback);
+
+ // Make sure no callback happens after the listener is removed.
+ freezeProcess(pid);
+ unfreezeProcess(pid);
+ EXPECT_EQ(0u, callback->events.size());
+}
+
+TEST_F(BinderLibTest, MultipleFrozenStateChangeCallbacks) {
+ if (!checkFreezeAndNotificationSupport()) {
+ GTEST_SKIP() << "Skipping test for kernels that do not support FREEZE_NOTIFICATION";
+ return;
+ }
+ sp<TestFrozenStateChangeCallback> callback1 = sp<TestFrozenStateChangeCallback>::make();
+ sp<TestFrozenStateChangeCallback> callback2 = sp<TestFrozenStateChangeCallback>::make();
+ sp<IBinder> binder = addServer();
+ ASSERT_NE(nullptr, binder);
+ int32_t pid;
+ ASSERT_TRUE(getBinderPid(&pid, binder));
+
+ EXPECT_THAT(binder->addFrozenStateChangeCallback(callback1), StatusEq(NO_ERROR));
+ // Expect current state (unfrozen) to be delivered immediately.
+ callback1->ensureUnfrozenEventReceived();
+
+ EXPECT_THAT(binder->addFrozenStateChangeCallback(callback2), StatusEq(NO_ERROR));
+ // Expect current state (unfrozen) to be delivered immediately.
+ callback2->ensureUnfrozenEventReceived();
+
+ freezeProcess(pid);
+ callback1->ensureFrozenEventReceived();
+ callback2->ensureFrozenEventReceived();
+
+ removeCallbackAndValidateNoEvent(binder, callback1);
+ unfreezeProcess(pid);
+ EXPECT_EQ(0u, callback1->events.size());
+ callback2->ensureUnfrozenEventReceived();
+ removeCallbackAndValidateNoEvent(binder, callback2);
+
+ freezeProcess(pid);
+ EXPECT_EQ(0u, callback2->events.size());
+}
+
+TEST_F(BinderLibTest, RemoveThenAddFrozenStateChangeCallbacks) {
+ if (!checkFreezeAndNotificationSupport()) {
+ GTEST_SKIP() << "Skipping test for kernels that do not support FREEZE_NOTIFICATION";
+ return;
+ }
+ sp<TestFrozenStateChangeCallback> callback = sp<TestFrozenStateChangeCallback>::make();
+ sp<IBinder> binder = addServer();
+ ASSERT_NE(nullptr, binder);
+ int32_t pid;
+ ASSERT_TRUE(getBinderPid(&pid, binder));
+
+ EXPECT_THAT(binder->addFrozenStateChangeCallback(callback), StatusEq(NO_ERROR));
+ // Expect current state (unfrozen) to be delivered immediately.
+ callback->ensureUnfrozenEventReceived();
+ removeCallbackAndValidateNoEvent(binder, callback);
+
+ EXPECT_THAT(binder->addFrozenStateChangeCallback(callback), StatusEq(NO_ERROR));
+ callback->ensureUnfrozenEventReceived();
+}
+
+TEST_F(BinderLibTest, CoalesceFreezeCallbacksWhenListenerIsFrozen) {
+ if (!checkFreezeAndNotificationSupport()) {
+ GTEST_SKIP() << "Skipping test for kernels that do not support FREEZE_NOTIFICATION";
+ return;
+ }
+ sp<IBinder> binder = addServer();
+ sp<IBinder> listener = addServer();
+ ASSERT_NE(nullptr, binder);
+ ASSERT_NE(nullptr, listener);
+ int32_t pid, listenerPid;
+ ASSERT_TRUE(getBinderPid(&pid, binder));
+ ASSERT_TRUE(getBinderPid(&listenerPid, listener));
+
+ // Ask the listener process to register for state change callbacks.
+ {
+ Parcel data, reply;
+ data.writeStrongBinder(binder);
+ ASSERT_THAT(listener->transact(BINDER_LIB_TEST_LISTEN_FOR_FROZEN_STATE_CHANGE, data,
+ &reply),
+ StatusEq(NO_ERROR));
+ }
+ // Freeze the listener process.
+ freezeProcess(listenerPid);
+ createProcessGroup(getuid(), listenerPid);
+ ASSERT_TRUE(SetProcessProfiles(getuid(), listenerPid, {"Frozen"}));
+ // Repeatedly flip the target process between frozen and unfrozen states.
+ for (int i = 0; i < 1000; i++) {
+ usleep(50);
+ unfreezeProcess(pid);
+ usleep(50);
+ freezeProcess(pid);
+ }
+ // Unfreeze the listener process. Now it should receive the frozen state
+ // change notifications.
+ ASSERT_TRUE(SetProcessProfiles(getuid(), listenerPid, {"Unfrozen"}));
+ unfreezeProcess(listenerPid);
+ // Wait for 500ms to give the process enough time to wake up and handle
+ // notifications.
+ usleep(500 * 1000);
+ {
+ std::vector<bool> events;
+ Parcel data, reply;
+ ASSERT_THAT(listener->transact(BINDER_LIB_TEST_CONSUME_STATE_CHANGE_EVENTS, data, &reply),
+ StatusEq(NO_ERROR));
+ reply.readBoolVector(&events);
+ // There should only be one single state change notifications delievered.
+ ASSERT_EQ(1u, events.size());
+ EXPECT_TRUE(events[0]);
+ }
+}
+
TEST_F(BinderLibTest, PassFile) {
int ret;
int pipefd[2];
@@ -1981,6 +2251,26 @@
reply->writeInt32(param.sched_priority);
return NO_ERROR;
}
+ case BINDER_LIB_TEST_LISTEN_FOR_FROZEN_STATE_CHANGE: {
+ sp<IBinder> binder = data.readStrongBinder();
+ frozenStateChangeCallback = sp<TestFrozenStateChangeCallback>::make();
+ // Hold an strong pointer to the binder object so it doesn't go
+ // away.
+ frozenStateChangeCallback->binder = binder;
+ int ret = binder->addFrozenStateChangeCallback(frozenStateChangeCallback);
+ if (ret != NO_ERROR) {
+ return ret;
+ }
+ auto event = frozenStateChangeCallback->events.popWithTimeout(10ms);
+ if (!event.has_value()) {
+ return NOT_ENOUGH_DATA;
+ }
+ return NO_ERROR;
+ }
+ case BINDER_LIB_TEST_CONSUME_STATE_CHANGE_EVENTS: {
+ reply->writeBoolVector(frozenStateChangeCallback->getAllAndClear());
+ return NO_ERROR;
+ }
case BINDER_LIB_TEST_ECHO_VECTOR: {
std::vector<uint64_t> vector;
auto err = data.readUint64Vector(&vector);
@@ -2067,6 +2357,7 @@
sp<IBinder> m_callback;
bool m_exitOnDestroy;
std::mutex m_blockMutex;
+ sp<TestFrozenStateChangeCallback> frozenStateChangeCallback;
};
int run_server(int index, int readypipefd, bool usePoll)
diff --git a/libs/binder/tests/binderRecordReplayTest.cpp b/libs/binder/tests/binderRecordReplayTest.cpp
index b975fad..f867b42 100644
--- a/libs/binder/tests/binderRecordReplayTest.cpp
+++ b/libs/binder/tests/binderRecordReplayTest.cpp
@@ -99,12 +99,12 @@
GENERATE_GETTER_SETTER(SingleDataParcelableArray, std::vector<SingleDataParcelable>);
Status setFileDescriptor(unique_fd input) {
- mFd = std::move(unique_fd(dup(input)));
+ mFd = unique_fd(dup(input));
return Status::ok();
}
Status getFileDescriptor(unique_fd* output) {
- *output = std::move(unique_fd(dup(mFd)));
+ *output = unique_fd(dup(mFd));
return Status::ok();
}
unique_fd mFd;
@@ -117,7 +117,7 @@
std::vector<uint8_t> buffer(fdStat.st_size);
auto readResult = android::base::ReadFully(fd, buffer.data(), fdStat.st_size);
EXPECT_TRUE(readResult != 0);
- return std::move(buffer);
+ return buffer;
}
void replayFuzzService(const sp<BpBinder>& binder, const RecordedTransaction& transaction) {
@@ -387,8 +387,8 @@
// When fds are replayed, it will be replaced by /dev/null..reading from it should yield
// null data
- recordReplay(&IBinderRecordReplayTest::setFileDescriptor, std::move(unique_fd(dup(saved))),
- &IBinderRecordReplayTest::getFileDescriptor, std::move(unique_fd(dup(changed))));
+ recordReplay(&IBinderRecordReplayTest::setFileDescriptor, unique_fd(dup(saved)),
+ &IBinderRecordReplayTest::getFileDescriptor, unique_fd(dup(changed)));
}
int main(int argc, char** argv) {
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index cd78e82..3038de9 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -1384,8 +1384,8 @@
sp<IServiceManager> sm = defaultServiceManager();
ASSERT_NE(nullptr, sm);
// Any Java service with non-empty getInterfaceDescriptor() would do.
- // Let's pick batteryproperties.
- auto binder = sm->checkService(String16("batteryproperties"));
+ // Let's pick activity.
+ auto binder = sm->checkService(String16("activity"));
ASSERT_NE(nullptr, binder);
auto descriptor = binder->getInterfaceDescriptor();
ASSERT_GE(descriptor.size(), 0u);
diff --git a/libs/binder/tests/binderRpcUniversalTests.cpp b/libs/binder/tests/binderRpcUniversalTests.cpp
index f480780..c6fd487 100644
--- a/libs/binder/tests/binderRpcUniversalTests.cpp
+++ b/libs/binder/tests/binderRpcUniversalTests.cpp
@@ -301,7 +301,8 @@
auto proc = createRpcTestSocketServerProcess({});
- sp<IBinder> someRealBinder = IInterface::asBinder(defaultServiceManager());
+ sp<IBinder> someRealBinder = defaultServiceManager()->getService(String16("activity"));
+ ASSERT_NE(someRealBinder, nullptr);
sp<IBinder> outBinder;
EXPECT_EQ(INVALID_OPERATION,
proc.rootIface->repeatBinder(someRealBinder, &outBinder).transactionError());
@@ -323,6 +324,22 @@
// END TESTS FOR LIMITATIONS OF SOCKET BINDER
+class TestFrozenStateChangeCallback : public IBinder::FrozenStateChangeCallback {
+public:
+ virtual void onStateChanged(const wp<IBinder>&, State) {}
+};
+
+TEST_P(BinderRpc, RpcBinderShouldFailOnFrozenStateCallbacks) {
+ auto proc = createRpcTestSocketServerProcess({});
+
+ sp<IBinder> a;
+ sp<TestFrozenStateChangeCallback> callback = sp<TestFrozenStateChangeCallback>::make();
+ EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&a));
+ EXPECT_DEATH_IF_SUPPORTED(
+ { std::ignore = a->addFrozenStateChangeCallback(callback); },
+ "addFrozenStateChangeCallback\\(\\) is not supported for RPC Binder.");
+}
+
TEST_P(BinderRpc, RepeatRootObject) {
auto proc = createRpcTestSocketServerProcess({});
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp
index fd9777a..0ed8a55 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp
@@ -55,7 +55,7 @@
offset += CHAR_BIT;
}
- return std::move(reverseData);
+ return reverseData;
}
template <typename T>
diff --git a/libs/binder/trusty/include/binder/RpcServerTrusty.h b/libs/binder/trusty/include/binder/RpcServerTrusty.h
index fe44ea5..583ad01 100644
--- a/libs/binder/trusty/include/binder/RpcServerTrusty.h
+++ b/libs/binder/trusty/include/binder/RpcServerTrusty.h
@@ -42,7 +42,7 @@
// equivalent.
struct PortAcl {
uint32_t flags;
- std::vector<const uuid> uuids;
+ std::vector<uuid> uuids;
const void* extraData;
};
diff --git a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferDemosAppBar.kt b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferDemosAppBar.kt
index ff3ae5a..4f293b9 100644
--- a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferDemosAppBar.kt
+++ b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferDemosAppBar.kt
@@ -1,7 +1,5 @@
package com.android.graphics.bufferstreamsdemoapp
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
@@ -29,10 +27,11 @@
navigationIcon = {
if (canNavigateBack) {
IconButton(onClick = navigateUp) {
- Icon(
- imageVector = Icons.AutoMirrored.Filled.ArrowBack,
- contentDescription = stringResource(R.string.back_button)
- )
+ // b/355293776
+ // Icon(
+ // imageVector = Icons.AutoMirrored.Filled.ArrowBack,
+ // contentDescription = stringResource(R.string.back_button)
+ // )
}
}
}
diff --git a/libs/bufferstreams/rust/src/lib.rs b/libs/bufferstreams/rust/src/lib.rs
index 17d4d87..9c48b49 100644
--- a/libs/bufferstreams/rust/src/lib.rs
+++ b/libs/bufferstreams/rust/src/lib.rs
@@ -37,23 +37,23 @@
/// BufferPublishers are required to adhere to the following, based on the
/// reactive streams specification:
/// * The total number of on_next´s signalled by a Publisher to a Subscriber
-/// MUST be less than or equal to the total number of elements requested by that
-/// Subscriber´s Subscription at all times.
+/// MUST be less than or equal to the total number of elements requested by that
+/// Subscriber´s Subscription at all times.
/// * A Publisher MAY signal fewer on_next than requested and terminate the
-/// Subscription by calling on_complete or on_error.
+/// Subscription by calling on_complete or on_error.
/// * on_subscribe, on_next, on_error and on_complete signaled to a Subscriber
-/// MUST be signaled serially.
+/// MUST be signaled serially.
/// * If a Publisher fails it MUST signal an on_error.
/// * If a Publisher terminates successfully (finite stream) it MUST signal an
-/// on_complete.
+/// on_complete.
/// * If a Publisher signals either on_error or on_complete on a Subscriber,
-/// that Subscriber’s Subscription MUST be considered cancelled.
+/// that Subscriber’s Subscription MUST be considered cancelled.
/// * Once a terminal state has been signaled (on_error, on_complete) it is
-/// REQUIRED that no further signals occur.
+/// REQUIRED that no further signals occur.
/// * If a Subscription is cancelled its Subscriber MUST eventually stop being
-/// signaled.
+/// signaled.
/// * A Publisher MAY support multiple Subscribers and decides whether each
-/// Subscription is unicast or multicast.
+/// Subscription is unicast or multicast.
pub trait BufferPublisher {
/// Returns the StreamConfig of buffers that publisher creates.
fn get_publisher_stream_config(&self) -> StreamConfig;
@@ -69,25 +69,25 @@
/// BufferSubcribers are required to adhere to the following, based on the
/// reactive streams specification:
/// * The total number of on_next´s signalled by a Publisher to a Subscriber
-/// MUST be less than or equal to the total number of elements requested by that
-/// Subscriber´s Subscription at all times.
+/// MUST be less than or equal to the total number of elements requested by that
+/// Subscriber´s Subscription at all times.
/// * A Publisher MAY signal fewer on_next than requested and terminate the
-/// Subscription by calling on_complete or on_error.
+/// Subscription by calling on_complete or on_error.
/// * on_subscribe, on_next, on_error and on_complete signaled to a Subscriber
-/// MUST be signaled serially.
+/// MUST be signaled serially.
/// * If a Publisher fails it MUST signal an on_error.
/// * If a Publisher terminates successfully (finite stream) it MUST signal an
-/// on_complete.
+/// on_complete.
/// * If a Publisher signals either on_error or on_complete on a Subscriber,
-/// that Subscriber’s Subscription MUST be considered cancelled.
+/// that Subscriber’s Subscription MUST be considered cancelled.
/// * Once a terminal state has been signaled (on_error, on_complete) it is
-/// REQUIRED that no further signals occur.
+/// REQUIRED that no further signals occur.
/// * If a Subscription is cancelled its Subscriber MUST eventually stop being
-/// signaled.
+/// signaled.
/// * Publisher.subscribe MAY be called as many times as wanted but MUST be
-/// with a different Subscriber each time.
+/// with a different Subscriber each time.
/// * A Publisher MAY support multiple Subscribers and decides whether each
-/// Subscription is unicast or multicast.
+/// Subscription is unicast or multicast.
pub trait BufferSubscriber {
/// The StreamConfig of buffers that this subscriber expects.
fn get_subscriber_stream_config(&self) -> StreamConfig;
@@ -111,39 +111,39 @@
/// BufferSubcriptions are required to adhere to the following, based on the
/// reactive streams specification:
/// * Subscription.request and Subscription.cancel MUST only be called inside
-/// of its Subscriber context.
+/// of its Subscriber context.
/// * The Subscription MUST allow the Subscriber to call Subscription.request
-/// synchronously from within on_next or on_subscribe.
+/// synchronously from within on_next or on_subscribe.
/// * Subscription.request MUST place an upper bound on possible synchronous
-/// recursion between Publisher and Subscriber.
+/// recursion between Publisher and Subscriber.
/// * Subscription.request SHOULD respect the responsivity of its caller by
-/// returning in a timely manner.
+/// returning in a timely manner.
/// * Subscription.cancel MUST respect the responsivity of its caller by
-/// returning in a timely manner, MUST be idempotent and MUST be thread-safe.
+/// returning in a timely manner, MUST be idempotent and MUST be thread-safe.
/// * After the Subscription is cancelled, additional
-/// Subscription.request(n: u64) MUST be NOPs.
+/// Subscription.request(n: u64) MUST be NOPs.
/// * After the Subscription is cancelled, additional Subscription.cancel()
-/// MUST be NOPs.
+/// MUST be NOPs.
/// * While the Subscription is not cancelled, Subscription.request(n: u64)
-/// MUST register the given number of additional elements to be produced to the
-/// respective subscriber.
+/// MUST register the given number of additional elements to be produced to the
+/// respective subscriber.
/// * While the Subscription is not cancelled, Subscription.request(n: u64)
-/// MUST signal on_error if the argument is <= 0. The cause message SHOULD
-/// explain that non-positive request signals are illegal.
+/// MUST signal on_error if the argument is <= 0. The cause message SHOULD
+/// explain that non-positive request signals are illegal.
/// * While the Subscription is not cancelled, Subscription.request(n: u64)
-/// MAY synchronously call on_next on this (or other) subscriber(s).
+/// MAY synchronously call on_next on this (or other) subscriber(s).
/// * While the Subscription is not cancelled, Subscription.request(n: u64)
-/// MAY synchronously call on_complete or on_error on this (or other)
-/// subscriber(s).
+/// MAY synchronously call on_complete or on_error on this (or other)
+/// subscriber(s).
/// * While the Subscription is not cancelled, Subscription.cancel() MUST
-/// request the Publisher to eventually stop signaling its Subscriber. The
-/// operation is NOT REQUIRED to affect the Subscription immediately.
+/// request the Publisher to eventually stop signaling its Subscriber. The
+/// operation is NOT REQUIRED to affect the Subscription immediately.
/// * While the Subscription is not cancelled, Subscription.cancel() MUST
-/// request the Publisher to eventually drop any references to the corresponding
-/// subscriber.
+/// request the Publisher to eventually drop any references to the corresponding
+/// subscriber.
/// * While the Subscription is not cancelled, calling Subscription.cancel MAY
-/// cause the Publisher, if stateful, to transition into the shut-down state if
-/// no other Subscription exists at this point.
+/// cause the Publisher, if stateful, to transition into the shut-down state if
+/// no other Subscription exists at this point.
/// * Calling Subscription.cancel MUST return normally.
/// * Calling Subscription.request MUST return normally.
pub trait BufferSubscription: Send + Sync + 'static {
diff --git a/libs/gralloc/types/fuzzer/Android.bp b/libs/gralloc/types/fuzzer/Android.bp
index 8337182..d9cdb59 100644
--- a/libs/gralloc/types/fuzzer/Android.bp
+++ b/libs/gralloc/types/fuzzer/Android.bp
@@ -28,14 +28,10 @@
],
static_libs: [
"libbase",
- "libcgrouprc",
- "libcgrouprc_format",
"libcutils",
"libgralloctypes",
"libhidlbase",
"liblog",
- "libprocessgroup",
- "libjsoncpp",
"libutils",
],
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 50c05f4..c6d1931 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -83,6 +83,55 @@
static const char* kLlndkLibrariesTxtPath = "/system/etc/llndk.libraries.txt";
+// List of libraries that were previously available via VNDK-SP,
+// and are now available via SPHAL.
+// On modern devices that lack the VNDK APEX, the device no longer
+// contains a helpful list of these libraries on the filesystem as above.
+// See system/sepolicy/vendor/file_contexts
+static const char* kFormerlyVndkspLibrariesList =
+ "android.hardware.common-V2-ndk.so:"
+ "android.hardware.common.fmq-V1-ndk.so:"
+ "android.hardware.graphics.allocator-V2-ndk.so:"
+ "android.hardware.graphics.common-V5-ndk.so:"
+ "android.hardware.graphics.common@1.0.so:"
+ "android.hardware.graphics.common@1.1.so:"
+ "android.hardware.graphics.common@1.2.so:"
+ "android.hardware.graphics.composer3-V1-ndk.so:"
+ "android.hardware.graphics.mapper@2.0.so:"
+ "android.hardware.graphics.mapper@2.1.so:"
+ "android.hardware.graphics.mapper@3.0.so:"
+ "android.hardware.graphics.mapper@4.0.so:"
+ "android.hardware.renderscript@1.0.so:"
+ "android.hidl.memory.token@1.0.so:"
+ "android.hidl.memory@1.0-impl.so:"
+ "android.hidl.memory@1.0.so:"
+ "android.hidl.safe_union@1.0.so:"
+ "libRSCpuRef.so:"
+ "libRSDriver.so:"
+ "libRS_internal.so:"
+ "libbacktrace.so:"
+ "libbase.so:"
+ "libbcinfo.so:"
+ "libblas.so:"
+ "libc++.so:"
+ "libcompiler_rt.so:"
+ "libcutils.so:"
+ "libdmabufheap.so:"
+ "libft2.so:"
+ "libgralloctypes.so:"
+ "libhardware.so:"
+ "libhidlbase.so:"
+ "libhidlmemory.so:"
+ "libion.so:"
+ "libjsoncpp.so:"
+ "liblzma.so:"
+ "libpng.so:"
+ "libprocessgroup.so:"
+ "libunwindstack.so:"
+ "libutils.so:"
+ "libutilscallstack.so:"
+ "libz.so";
+
static std::string vndkVersionStr() {
#ifdef __BIONIC__
return base::GetProperty("ro.vndk.version", "");
@@ -122,8 +171,12 @@
static const std::string getSystemNativeLibraries(NativeLibrary type) {
std::string nativeLibrariesSystemConfig = "";
- if (!isVndkEnabled() && type == NativeLibrary::LLNDK) {
- nativeLibrariesSystemConfig = kLlndkLibrariesTxtPath;
+ if (!isVndkEnabled()) {
+ if (type == NativeLibrary::VNDKSP) {
+ return kFormerlyVndkspLibrariesList;
+ } else {
+ nativeLibrariesSystemConfig = kLlndkLibrariesTxtPath;
+ }
} else {
nativeLibrariesSystemConfig = kNativeLibrariesSystemConfigPath[type];
insertVndkVersionStr(&nativeLibrariesSystemConfig);
@@ -263,7 +316,7 @@
ALOGI("Driver path is setup via UPDATABLE_GFX_DRIVER: %s", mDriverPath.c_str());
}
- auto vndkNamespace = android_get_exported_namespace("vndk");
+ auto vndkNamespace = android_get_exported_namespace(isVndkEnabled() ? "vndk" : "sphal");
if (!vndkNamespace) {
mDriverNamespace = nullptr;
return mDriverNamespace;
@@ -616,7 +669,7 @@
return mAngleNamespace;
}
- auto vndkNamespace = android_get_exported_namespace("vndk");
+ auto vndkNamespace = android_get_exported_namespace(isVndkEnabled() ? "vndk" : "sphal");
if (!vndkNamespace) {
mAngleNamespace = nullptr;
return mAngleNamespace;
diff --git a/libs/graphicsenv/OWNERS b/libs/graphicsenv/OWNERS
index 1db8cbe..4aa8fff 100644
--- a/libs/graphicsenv/OWNERS
+++ b/libs/graphicsenv/OWNERS
@@ -1,4 +1,11 @@
chrisforbes@google.com
-cnorthrop@google.com
ianelliott@google.com
-lpy@google.com
+
+abdolrashidi@google.com
+cclao@google.com
+cnorthrop@google.com
+hibrian@google.com
+mathias@google.com
+romanl@google.com
+solti@google.com
+yuxinhu@google.com
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 11f5174..69d25be 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -42,6 +42,8 @@
#include <system/window.h>
+#include <com_android_graphics_libgui_flags.h>
+
namespace android {
// Macros for include BufferQueueCore information in log messages
@@ -370,79 +372,94 @@
return BAD_VALUE;
}
- std::lock_guard<std::mutex> lock(mCore->mMutex);
+ sp<IProducerListener> listener;
+ {
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
- if (mCore->mSharedBufferMode) {
- BQ_LOGE("attachBuffer: cannot attach a buffer in shared buffer mode");
- return BAD_VALUE;
- }
-
- // Make sure we don't have too many acquired buffers
- int numAcquiredBuffers = 0;
- for (int s : mCore->mActiveBuffers) {
- if (mSlots[s].mBufferState.isAcquired()) {
- ++numAcquiredBuffers;
+ if (mCore->mSharedBufferMode) {
+ BQ_LOGE("attachBuffer: cannot attach a buffer in shared buffer mode");
+ return BAD_VALUE;
}
+
+ // Make sure we don't have too many acquired buffers
+ int numAcquiredBuffers = 0;
+ for (int s : mCore->mActiveBuffers) {
+ if (mSlots[s].mBufferState.isAcquired()) {
+ ++numAcquiredBuffers;
+ }
+ }
+
+ if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) {
+ BQ_LOGE("attachBuffer: max acquired buffer count reached: %d "
+ "(max %d)", numAcquiredBuffers,
+ mCore->mMaxAcquiredBufferCount);
+ return INVALID_OPERATION;
+ }
+
+ if (buffer->getGenerationNumber() != mCore->mGenerationNumber) {
+ BQ_LOGE("attachBuffer: generation number mismatch [buffer %u] "
+ "[queue %u]", buffer->getGenerationNumber(),
+ mCore->mGenerationNumber);
+ return BAD_VALUE;
+ }
+
+ // Find a free slot to put the buffer into
+ int found = BufferQueueCore::INVALID_BUFFER_SLOT;
+ if (!mCore->mFreeSlots.empty()) {
+ auto slot = mCore->mFreeSlots.begin();
+ found = *slot;
+ mCore->mFreeSlots.erase(slot);
+ } else if (!mCore->mFreeBuffers.empty()) {
+ found = mCore->mFreeBuffers.front();
+ mCore->mFreeBuffers.remove(found);
+ }
+ if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
+ BQ_LOGE("attachBuffer: could not find free buffer slot");
+ return NO_MEMORY;
+ }
+
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
+ if (mCore->mBufferAttachedCbEnabled) {
+ listener = mCore->mConnectedProducerListener;
+ }
+#endif
+
+ mCore->mActiveBuffers.insert(found);
+ *outSlot = found;
+ ATRACE_BUFFER_INDEX(*outSlot);
+ BQ_LOGV("attachBuffer: returning slot %d", *outSlot);
+
+ mSlots[*outSlot].mGraphicBuffer = buffer;
+ mSlots[*outSlot].mBufferState.attachConsumer();
+ mSlots[*outSlot].mNeedsReallocation = true;
+ mSlots[*outSlot].mFence = Fence::NO_FENCE;
+ mSlots[*outSlot].mFrameNumber = 0;
+
+ // mAcquireCalled tells BufferQueue that it doesn't need to send a valid
+ // GraphicBuffer pointer on the next acquireBuffer call, which decreases
+ // Binder traffic by not un/flattening the GraphicBuffer. However, it
+ // requires that the consumer maintain a cached copy of the slot <--> buffer
+ // mappings, which is why the consumer doesn't need the valid pointer on
+ // acquire.
+ //
+ // The StreamSplitter is one of the primary users of the attach/detach
+ // logic, and while it is running, all buffers it acquires are immediately
+ // detached, and all buffers it eventually releases are ones that were
+ // attached (as opposed to having been obtained from acquireBuffer), so it
+ // doesn't make sense to maintain the slot/buffer mappings, which would
+ // become invalid for every buffer during detach/attach. By setting this to
+ // false, the valid GraphicBuffer pointer will always be sent with acquire
+ // for attached buffers.
+ mSlots[*outSlot].mAcquireCalled = false;
+
+ VALIDATE_CONSISTENCY();
}
- if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) {
- BQ_LOGE("attachBuffer: max acquired buffer count reached: %d "
- "(max %d)", numAcquiredBuffers,
- mCore->mMaxAcquiredBufferCount);
- return INVALID_OPERATION;
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
+ if (listener != nullptr) {
+ listener->onBufferAttached();
}
-
- if (buffer->getGenerationNumber() != mCore->mGenerationNumber) {
- BQ_LOGE("attachBuffer: generation number mismatch [buffer %u] "
- "[queue %u]", buffer->getGenerationNumber(),
- mCore->mGenerationNumber);
- return BAD_VALUE;
- }
-
- // Find a free slot to put the buffer into
- int found = BufferQueueCore::INVALID_BUFFER_SLOT;
- if (!mCore->mFreeSlots.empty()) {
- auto slot = mCore->mFreeSlots.begin();
- found = *slot;
- mCore->mFreeSlots.erase(slot);
- } else if (!mCore->mFreeBuffers.empty()) {
- found = mCore->mFreeBuffers.front();
- mCore->mFreeBuffers.remove(found);
- }
- if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
- BQ_LOGE("attachBuffer: could not find free buffer slot");
- return NO_MEMORY;
- }
-
- mCore->mActiveBuffers.insert(found);
- *outSlot = found;
- ATRACE_BUFFER_INDEX(*outSlot);
- BQ_LOGV("attachBuffer: returning slot %d", *outSlot);
-
- mSlots[*outSlot].mGraphicBuffer = buffer;
- mSlots[*outSlot].mBufferState.attachConsumer();
- mSlots[*outSlot].mNeedsReallocation = true;
- mSlots[*outSlot].mFence = Fence::NO_FENCE;
- mSlots[*outSlot].mFrameNumber = 0;
-
- // mAcquireCalled tells BufferQueue that it doesn't need to send a valid
- // GraphicBuffer pointer on the next acquireBuffer call, which decreases
- // Binder traffic by not un/flattening the GraphicBuffer. However, it
- // requires that the consumer maintain a cached copy of the slot <--> buffer
- // mappings, which is why the consumer doesn't need the valid pointer on
- // acquire.
- //
- // The StreamSplitter is one of the primary users of the attach/detach
- // logic, and while it is running, all buffers it acquires are immediately
- // detached, and all buffers it eventually releases are ones that were
- // attached (as opposed to having been obtained from acquireBuffer), so it
- // doesn't make sense to maintain the slot/buffer mappings, which would
- // become invalid for every buffer during detach/attach. By setting this to
- // false, the valid GraphicBuffer pointer will always be sent with acquire
- // for attached buffers.
- mSlots[*outSlot].mAcquireCalled = false;
-
- VALIDATE_CONSISTENCY();
+#endif
return NO_ERROR;
}
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 648db67..e0c5b1f 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -96,6 +96,7 @@
mLinkedToDeath(),
mConnectedProducerListener(),
mBufferReleasedCbEnabled(false),
+ mBufferAttachedCbEnabled(false),
mSlots(),
mQueue(),
mFreeSlots(),
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index fb69fda..88d456b 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -1324,6 +1324,9 @@
#endif
mCore->mConnectedProducerListener = listener;
mCore->mBufferReleasedCbEnabled = listener->needsReleaseNotify();
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
+ mCore->mBufferAttachedCbEnabled = listener->needsAttachNotify();
+#endif
}
break;
default:
diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp
index 0683087..7700795 100644
--- a/libs/gui/IProducerListener.cpp
+++ b/libs/gui/IProducerListener.cpp
@@ -25,6 +25,9 @@
ON_BUFFER_RELEASED = IBinder::FIRST_CALL_TRANSACTION,
NEEDS_RELEASE_NOTIFY,
ON_BUFFERS_DISCARDED,
+ ON_BUFFER_DETACHED,
+ ON_BUFFER_ATTACHED,
+ NEEDS_ATTACH_NOTIFY,
};
class BpProducerListener : public BpInterface<IProducerListener>
@@ -64,6 +67,38 @@
data.writeInt32Vector(discardedSlots);
remote()->transact(ON_BUFFERS_DISCARDED, data, &reply, IBinder::FLAG_ONEWAY);
}
+
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
+ virtual void onBufferDetached(int slot) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor());
+ data.writeInt32(slot);
+ remote()->transact(ON_BUFFER_DETACHED, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+
+ virtual void onBufferAttached() {
+ Parcel data, reply;
+ data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor());
+ remote()->transact(ON_BUFFER_ATTACHED, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+
+ virtual bool needsAttachNotify() {
+ bool result;
+ Parcel data, reply;
+ data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor());
+ status_t err = remote()->transact(NEEDS_ATTACH_NOTIFY, data, &reply);
+ if (err != NO_ERROR) {
+ ALOGE("IProducerListener: binder call \'needsAttachNotify\' failed");
+ return true;
+ }
+ err = reply.readBool(&result);
+ if (err != NO_ERROR) {
+ ALOGE("IProducerListener: malformed binder reply");
+ return true;
+ }
+ return result;
+ }
+#endif
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -115,6 +150,27 @@
onBuffersDiscarded(discardedSlots);
return NO_ERROR;
}
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
+ case ON_BUFFER_DETACHED: {
+ CHECK_INTERFACE(IProducerListener, data, reply);
+ int slot;
+ status_t result = data.readInt32(&slot);
+ if (result != NO_ERROR) {
+ ALOGE("ON_BUFFER_DETACHED failed to read slot: %d", result);
+ return result;
+ }
+ onBufferDetached(slot);
+ return NO_ERROR;
+ }
+ case ON_BUFFER_ATTACHED:
+ CHECK_INTERFACE(IProducerListener, data, reply);
+ onBufferAttached();
+ return NO_ERROR;
+ case NEEDS_ATTACH_NOTIFY:
+ CHECK_INTERFACE(IProducerListener, data, reply);
+ reply->writeBool(needsAttachNotify());
+ return NO_ERROR;
+#endif
}
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h
index 22c2be7..c16e370 100644
--- a/libs/gui/include/gui/BufferQueueCore.h
+++ b/libs/gui/include/gui/BufferQueueCore.h
@@ -189,6 +189,10 @@
// callback is registered by the listener. When set to false,
// mConnectedProducerListener will not trigger onBufferReleased() callback.
bool mBufferReleasedCbEnabled;
+ // mBufferAttachedCbEnabled is used to indicate whether onBufferAttached()
+ // callback is registered by the listener. When set to false,
+ // mConnectedProducerListener will not trigger onBufferAttached() callback.
+ bool mBufferAttachedCbEnabled;
// mSlots is an array of buffer slots that must be mirrored on the producer
// side. This allows buffer ownership to be transferred between the producer
diff --git a/libs/gui/include/gui/IProducerListener.h b/libs/gui/include/gui/IProducerListener.h
index b15f501..3dcc6b6 100644
--- a/libs/gui/include/gui/IProducerListener.h
+++ b/libs/gui/include/gui/IProducerListener.h
@@ -25,6 +25,8 @@
#include <hidl/HybridInterface.h>
#include <utils/RefBase.h>
+#include <com_android_graphics_libgui_flags.h>
+
namespace android {
// ProducerListener is the interface through which the BufferQueue notifies the
@@ -55,6 +57,16 @@
// This is called without any lock held and can be called concurrently by
// multiple threads.
virtual void onBufferDetached(int /*slot*/) {} // Asynchronous
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
+ // onBufferAttached is called from IGraphicBufferConsumer::attachBuffer to
+ // notify the producer that a buffer is attached.
+ //
+ // This is called without any lock held and can be called concurrently by
+ // multiple threads. This callback is enabled only when needsAttachNotify()
+ // returns {@code true}.
+ virtual void onBufferAttached() {} // Asynchronous
+ virtual bool needsAttachNotify() { return false; }
+#endif
};
#ifndef NO_BINDER
diff --git a/libs/gui/libgui_flags.aconfig b/libs/gui/libgui_flags.aconfig
index 3864699..78fc590 100644
--- a/libs/gui/libgui_flags.aconfig
+++ b/libs/gui/libgui_flags.aconfig
@@ -10,6 +10,14 @@
}
flag {
+ name: "bq_consumer_attach_callback"
+ namespace: "core_graphics"
+ description: "Controls IProducerListener to have consumer side attach callback"
+ bug: "353202582"
+ is_fixed_read_only: true
+} # bq_consumer_attach_callback
+
+flag {
name: "frametimestamps_previousrelease"
namespace: "core_graphics"
description: "Controls a fence fixup for timestamp apis"
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index df7739c..be6c7d6 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -1257,6 +1257,91 @@
ASSERT_TRUE(result == WOULD_BLOCK || result == TIMED_OUT || result == INVALID_OPERATION);
}
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
+struct BufferAttachedListener : public BnProducerListener {
+public:
+ BufferAttachedListener(bool enable) : mEnabled(enable), mAttached(0) {}
+ virtual ~BufferAttachedListener() = default;
+
+ virtual void onBufferReleased() {}
+ virtual bool needsReleaseNotify() { return true; }
+ virtual void onBufferAttached() {
+ ++mAttached;
+ }
+ virtual bool needsAttachNotify() { return mEnabled; }
+
+ int getNumAttached() const { return mAttached; }
+private:
+ const bool mEnabled;
+ int mAttached;
+};
+
+TEST_F(BufferQueueTest, TestConsumerAttachProducerListener) {
+ createBufferQueue();
+ sp<MockConsumer> mc1(new MockConsumer);
+ ASSERT_EQ(OK, mConsumer->consumerConnect(mc1, true));
+ IGraphicBufferProducer::QueueBufferOutput output;
+ // Do not enable attach callback.
+ sp<BufferAttachedListener> pl1(new BufferAttachedListener(false));
+ ASSERT_EQ(OK, mProducer->connect(pl1, NATIVE_WINDOW_API_CPU, true, &output));
+ ASSERT_EQ(OK, mProducer->setDequeueTimeout(0));
+ ASSERT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(1));
+
+ sp<Fence> fence = Fence::NO_FENCE;
+ sp<GraphicBuffer> buffer = nullptr;
+
+ int slot;
+ status_t result = OK;
+
+ ASSERT_EQ(OK, mProducer->setMaxDequeuedBufferCount(1));
+
+ result = mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
+ GRALLOC_USAGE_SW_READ_RARELY, nullptr, nullptr);
+ ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result);
+ ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
+ ASSERT_EQ(OK, mProducer->detachBuffer(slot));
+
+ // Check # of attach is zero.
+ ASSERT_EQ(0, pl1->getNumAttached());
+
+ // Attach a buffer and check the callback was not called.
+ ASSERT_EQ(OK, mConsumer->attachBuffer(&slot, buffer));
+ ASSERT_EQ(0, pl1->getNumAttached());
+
+ mProducer = nullptr;
+ mConsumer = nullptr;
+ createBufferQueue();
+
+ sp<MockConsumer> mc2(new MockConsumer);
+ ASSERT_EQ(OK, mConsumer->consumerConnect(mc2, true));
+ // Enable attach callback.
+ sp<BufferAttachedListener> pl2(new BufferAttachedListener(true));
+ ASSERT_EQ(OK, mProducer->connect(pl2, NATIVE_WINDOW_API_CPU, true, &output));
+ ASSERT_EQ(OK, mProducer->setDequeueTimeout(0));
+ ASSERT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(1));
+
+ fence = Fence::NO_FENCE;
+ buffer = nullptr;
+
+ result = OK;
+
+ ASSERT_EQ(OK, mProducer->setMaxDequeuedBufferCount(1));
+
+ result = mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
+ GRALLOC_USAGE_SW_READ_RARELY, nullptr, nullptr);
+ ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result);
+ ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
+ ASSERT_EQ(OK, mProducer->detachBuffer(slot));
+
+ // Check # of attach is zero.
+ ASSERT_EQ(0, pl2->getNumAttached());
+
+ // Attach a buffer and check the callback was called.
+ ASSERT_EQ(OK, mConsumer->attachBuffer(&slot, buffer));
+ ASSERT_EQ(1, pl2->getNumAttached());
+}
+#endif
+
TEST_F(BufferQueueTest, TestStaleBufferHandleSentAfterDisconnect) {
createBufferQueue();
sp<MockConsumer> mc(new MockConsumer);
diff --git a/libs/math/include/math/TVecHelpers.h b/libs/math/include/math/TVecHelpers.h
index 0dac662..7278d2d 100644
--- a/libs/math/include/math/TVecHelpers.h
+++ b/libs/math/include/math/TVecHelpers.h
@@ -620,15 +620,10 @@
} // namespace details
} // namespace android
-namespace std {
- template<template<typename T> class VECTOR, typename T>
- struct hash<VECTOR<T>> {
- static constexpr bool IS_VECTOR =
- std::is_base_of<android::details::TVecUnaryOperators<VECTOR, T>, VECTOR<T>>::value;
-
- typename std::enable_if<IS_VECTOR, size_t>::type
- operator()(const VECTOR<T>& v) const {
- return v.hash();
- }
- };
-}
+#define TVECHELPERS_STD_HASH(VECTOR) \
+ template <typename T> \
+ struct std::hash<VECTOR<T>> { \
+ size_t operator()(const VECTOR<T>& v) const { \
+ return v.hash(); \
+ } \
+ }
diff --git a/libs/math/include/math/mat2.h b/libs/math/include/math/mat2.h
index 3e6cd4c..24c2bad 100644
--- a/libs/math/include/math/mat2.h
+++ b/libs/math/include/math/mat2.h
@@ -373,5 +373,7 @@
// ----------------------------------------------------------------------------------------
} // namespace android
+TVECHELPERS_STD_HASH(android::details::TMat22);
+
#undef PURE
#undef CONSTEXPR
diff --git a/libs/math/include/math/mat3.h b/libs/math/include/math/mat3.h
index 5c8a9b2..4647a60 100644
--- a/libs/math/include/math/mat3.h
+++ b/libs/math/include/math/mat3.h
@@ -436,5 +436,7 @@
// ----------------------------------------------------------------------------------------
} // namespace android
+TVECHELPERS_STD_HASH(android::details::TMat33);
+
#undef PURE
#undef CONSTEXPR
diff --git a/libs/math/include/math/mat4.h b/libs/math/include/math/mat4.h
index c630d97..c9e118a 100644
--- a/libs/math/include/math/mat4.h
+++ b/libs/math/include/math/mat4.h
@@ -590,5 +590,7 @@
// ----------------------------------------------------------------------------------------
} // namespace android
+TVECHELPERS_STD_HASH(android::details::TMat44);
+
#undef PURE
#undef CONSTEXPR
diff --git a/libs/math/include/math/quat.h b/libs/math/include/math/quat.h
index 07573c5..43c8038 100644
--- a/libs/math/include/math/quat.h
+++ b/libs/math/include/math/quat.h
@@ -187,6 +187,8 @@
// ----------------------------------------------------------------------------------------
} // namespace android
+TVECHELPERS_STD_HASH(android::details::TQuaternion);
+
#pragma clang diagnostic pop
#undef PURE
diff --git a/libs/math/include/math/vec2.h b/libs/math/include/math/vec2.h
index e0adb7f..909c77e 100644
--- a/libs/math/include/math/vec2.h
+++ b/libs/math/include/math/vec2.h
@@ -122,4 +122,6 @@
// ----------------------------------------------------------------------------------------
} // namespace android
+TVECHELPERS_STD_HASH(android::details::TVec2);
+
#pragma clang diagnostic pop
diff --git a/libs/math/include/math/vec3.h b/libs/math/include/math/vec3.h
index 21fb684..ff2b3e4 100644
--- a/libs/math/include/math/vec3.h
+++ b/libs/math/include/math/vec3.h
@@ -128,4 +128,6 @@
// ----------------------------------------------------------------------------------------
} // namespace android
+TVECHELPERS_STD_HASH(android::details::TVec3);
+
#pragma clang diagnostic pop
diff --git a/libs/math/include/math/vec4.h b/libs/math/include/math/vec4.h
index 1e279fe..16509c9 100644
--- a/libs/math/include/math/vec4.h
+++ b/libs/math/include/math/vec4.h
@@ -125,4 +125,6 @@
// ----------------------------------------------------------------------------------------
} // namespace android
+TVECHELPERS_STD_HASH(android::details::TVec4);
+
#pragma clang diagnostic pop
diff --git a/opengl/Android.bp b/opengl/Android.bp
index 4454f36..37dc931 100644
--- a/opengl/Android.bp
+++ b/opengl/Android.bp
@@ -30,6 +30,10 @@
to: "",
srcs: ["include/EGL/**/*.h"],
license: "include/EGL/NOTICE",
+ // eglext.h is not self-contained. Safe to skip C-compat verification
+ // though since upstream also cares about C compatibility, and the header is
+ // auto-generated anyway.
+ skip_verification: true,
}
ndk_headers {
@@ -38,6 +42,10 @@
to: "",
srcs: ["include/GLES/**/*.h"],
license: "include/GLES/NOTICE",
+ // glext.h is not self-contained. Safe to skip C-compat verification
+ // though since upstream also cares about C compatibility, and the header is
+ // auto-generated anyway.
+ skip_verification: true,
}
ndk_headers {
@@ -46,6 +54,10 @@
to: "",
srcs: ["include/GLES2/**/*.h"],
license: "include/GLES2/NOTICE",
+ // gl2ext.h is not self-contained. Safe to skip C-compat verification
+ // though since upstream also cares about C compatibility, and the header is
+ // auto-generated anyway.
+ skip_verification: true,
}
ndk_headers {
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index af0bcff..3297fe0 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -262,7 +262,7 @@
hnd = attempt_to_load_updated_driver(cnx);
// If updated driver apk is set but fail to load, abort here.
- LOG_ALWAYS_FATAL_IF(android::GraphicsEnv::getInstance().getDriverNamespace(),
+ LOG_ALWAYS_FATAL_IF(android::GraphicsEnv::getInstance().getDriverNamespace() && !hnd,
"couldn't find an OpenGL ES implementation from %s",
android::GraphicsEnv::getInstance().getDriverPath().c_str());
}
diff --git a/services/gpuservice/bpfprogs/Android.bp b/services/gpuservice/bpfprogs/Android.bp
index 680b291..a391c81 100644
--- a/services/gpuservice/bpfprogs/Android.bp
+++ b/services/gpuservice/bpfprogs/Android.bp
@@ -24,9 +24,4 @@
bpf {
name: "gpuMem.o",
srcs: ["gpuMem.c"],
- btf: true,
- cflags: [
- "-Wall",
- "-Werror",
- ],
}
diff --git a/services/gpuservice/gpuwork/bpfprogs/Android.bp b/services/gpuservice/gpuwork/bpfprogs/Android.bp
index fe45c98..2e444fe 100644
--- a/services/gpuservice/gpuwork/bpfprogs/Android.bp
+++ b/services/gpuservice/gpuwork/bpfprogs/Android.bp
@@ -20,11 +20,7 @@
name: "gpuWork.o",
srcs: ["gpuWork.c"],
cflags: [
- "-Wall",
- "-Werror",
- "-Wformat",
"-Wthread-safety",
- "-Wunused",
"-Wunreachable-code",
],
}
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 3c26d1d..539731b 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -984,8 +984,9 @@
viewportChanged = mViewport != newViewport;
}
+ const bool deviceModeChanged = mDeviceMode != oldDeviceMode;
bool skipViewportUpdate = false;
- if (viewportChanged) {
+ if (viewportChanged || deviceModeChanged) {
const bool viewportOrientationChanged = mViewport.orientation != newViewport.orientation;
const bool viewportDisplayIdChanged = mViewport.displayId != newViewport.displayId;
mViewport = newViewport;
@@ -1027,7 +1028,6 @@
}
// If moving between pointer modes, need to reset some state.
- bool deviceModeChanged = mDeviceMode != oldDeviceMode;
if (deviceModeChanged) {
mOrientedRanges.clear();
}
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 835f8b8..33ba79e 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -57,6 +57,7 @@
using namespace ftl::flag_operators;
using testing::AllOf;
+using testing::VariantWith;
using std::chrono_literals::operator""ms;
using std::chrono_literals::operator""s;
@@ -4430,15 +4431,15 @@
void prepareButtons();
void prepareAxes(int axes);
- void processDown(SingleTouchInputMapper& mapper, int32_t x, int32_t y);
- void processMove(SingleTouchInputMapper& mapper, int32_t x, int32_t y);
- void processUp(SingleTouchInputMapper& mappery);
- void processPressure(SingleTouchInputMapper& mapper, int32_t pressure);
- void processToolMajor(SingleTouchInputMapper& mapper, int32_t toolMajor);
- void processDistance(SingleTouchInputMapper& mapper, int32_t distance);
- void processTilt(SingleTouchInputMapper& mapper, int32_t tiltX, int32_t tiltY);
- void processKey(SingleTouchInputMapper& mapper, int32_t code, int32_t value);
- void processSync(SingleTouchInputMapper& mapper);
+ std::list<NotifyArgs> processDown(SingleTouchInputMapper& mapper, int32_t x, int32_t y);
+ std::list<NotifyArgs> processMove(SingleTouchInputMapper& mapper, int32_t x, int32_t y);
+ std::list<NotifyArgs> processUp(SingleTouchInputMapper& mappery);
+ std::list<NotifyArgs> processPressure(SingleTouchInputMapper& mapper, int32_t pressure);
+ std::list<NotifyArgs> processToolMajor(SingleTouchInputMapper& mapper, int32_t toolMajor);
+ std::list<NotifyArgs> processDistance(SingleTouchInputMapper& mapper, int32_t distance);
+ std::list<NotifyArgs> processTilt(SingleTouchInputMapper& mapper, int32_t tiltX, int32_t tiltY);
+ std::list<NotifyArgs> processKey(SingleTouchInputMapper& mapper, int32_t code, int32_t value);
+ std::list<NotifyArgs> processSync(SingleTouchInputMapper& mapper);
};
void SingleTouchInputMapperTest::prepareButtons() {
@@ -4468,47 +4469,57 @@
}
}
-void SingleTouchInputMapperTest::processDown(SingleTouchInputMapper& mapper, int32_t x, int32_t y) {
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, BTN_TOUCH, 1);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_X, x);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_Y, y);
+std::list<NotifyArgs> SingleTouchInputMapperTest::processDown(SingleTouchInputMapper& mapper,
+ int32_t x, int32_t y) {
+ std::list<NotifyArgs> args;
+ args += process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, BTN_TOUCH, 1);
+ args += process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_X, x);
+ args += process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_Y, y);
+ return args;
}
-void SingleTouchInputMapperTest::processMove(SingleTouchInputMapper& mapper, int32_t x, int32_t y) {
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_X, x);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_Y, y);
+std::list<NotifyArgs> SingleTouchInputMapperTest::processMove(SingleTouchInputMapper& mapper,
+ int32_t x, int32_t y) {
+ std::list<NotifyArgs> args;
+ args += process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_X, x);
+ args += process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_Y, y);
+ return args;
}
-void SingleTouchInputMapperTest::processUp(SingleTouchInputMapper& mapper) {
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, BTN_TOUCH, 0);
+std::list<NotifyArgs> SingleTouchInputMapperTest::processUp(SingleTouchInputMapper& mapper) {
+ return process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, BTN_TOUCH, 0);
}
-void SingleTouchInputMapperTest::processPressure(SingleTouchInputMapper& mapper, int32_t pressure) {
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_PRESSURE, pressure);
+std::list<NotifyArgs> SingleTouchInputMapperTest::processPressure(SingleTouchInputMapper& mapper,
+ int32_t pressure) {
+ return process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_PRESSURE, pressure);
}
-void SingleTouchInputMapperTest::processToolMajor(SingleTouchInputMapper& mapper,
- int32_t toolMajor) {
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_TOOL_WIDTH, toolMajor);
+std::list<NotifyArgs> SingleTouchInputMapperTest::processToolMajor(SingleTouchInputMapper& mapper,
+ int32_t toolMajor) {
+ return process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_TOOL_WIDTH, toolMajor);
}
-void SingleTouchInputMapperTest::processDistance(SingleTouchInputMapper& mapper, int32_t distance) {
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_DISTANCE, distance);
+std::list<NotifyArgs> SingleTouchInputMapperTest::processDistance(SingleTouchInputMapper& mapper,
+ int32_t distance) {
+ return process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_DISTANCE, distance);
}
-void SingleTouchInputMapperTest::processTilt(SingleTouchInputMapper& mapper, int32_t tiltX,
- int32_t tiltY) {
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_TILT_X, tiltX);
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_TILT_Y, tiltY);
+std::list<NotifyArgs> SingleTouchInputMapperTest::processTilt(SingleTouchInputMapper& mapper,
+ int32_t tiltX, int32_t tiltY) {
+ std::list<NotifyArgs> args;
+ args += process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_TILT_X, tiltX);
+ args += process(mapper, ARBITRARY_TIME, READ_TIME, EV_ABS, ABS_TILT_Y, tiltY);
+ return args;
}
-void SingleTouchInputMapperTest::processKey(SingleTouchInputMapper& mapper, int32_t code,
- int32_t value) {
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, code, value);
+std::list<NotifyArgs> SingleTouchInputMapperTest::processKey(SingleTouchInputMapper& mapper,
+ int32_t code, int32_t value) {
+ return process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, code, value);
}
-void SingleTouchInputMapperTest::processSync(SingleTouchInputMapper& mapper) {
- process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
+std::list<NotifyArgs> SingleTouchInputMapperTest::processSync(SingleTouchInputMapper& mapper) {
+ return process(mapper, ARBITRARY_TIME, READ_TIME, EV_SYN, SYN_REPORT, 0);
}
TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndNotACursor_ReturnsPointer) {
@@ -4599,6 +4610,42 @@
ASSERT_FALSE(flags[1]);
}
+TEST_F(SingleTouchInputMapperTest, DeviceTypeChange_RecalculatesRawToDisplayTransform) {
+ prepareDisplay(ui::ROTATION_0);
+ prepareAxes(POSITION);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ SingleTouchInputMapper& mapper = constructAndAddMapper<SingleTouchInputMapper>();
+
+ const int32_t x = 900;
+ const int32_t y = 75;
+ std::list<NotifyArgs> args;
+ args += processDown(mapper, x, y);
+ args += processSync(mapper);
+
+ // Assert that motion event is received in display coordinate space for deviceType touchScreen.
+ ASSERT_THAT(args,
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
+ WithCoords(toDisplayX(x), toDisplayY(y))))));
+
+ // Add device type association after the device was created.
+ mFakePolicy->addDeviceTypeAssociation(DEVICE_LOCATION, "touchNavigation");
+ // Send update to the mapper.
+ std::list<NotifyArgs> unused =
+ mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ InputReaderConfiguration::Change::DEVICE_TYPE /*changes*/);
+
+ args.clear();
+ args += processDown(mapper, x, y);
+ args += processSync(mapper);
+
+ // Assert that motion event is received in raw coordinate space for deviceType touchNavigation.
+ ASSERT_THAT(args,
+ ElementsAre(VariantWith<NotifyMotionArgs>(
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN),
+ WithCoords(x - RAW_X_MIN, y - RAW_Y_MIN)))));
+}
+
TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndReleasedNormally_SendsKeyDownAndKeyUp) {
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(ui::ROTATION_0);
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index dad945c..05af4ed 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -49,6 +49,7 @@
"libtonemap",
"libaidlcommonsupport",
"libprocessgroup",
+ "libprocessgroup_util",
"libcgrouprc",
"libjsoncpp",
"libcgrouprc_format",
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index 12ab2c2..be95913 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -209,7 +209,7 @@
if (!buffer || buffer->initCheck() != ::android::OK) {
return nullptr;
}
- return std::move(buffer);
+ return buffer;
}
} // anonymous namespace
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 0f8e3bf..19995f2 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -6675,7 +6675,7 @@
}
void SurfaceFlinger::dumpHwcLayersMinidumpLockedLegacy(std::string& result) const {
- for (const auto& [token, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) {
+ for (const auto& [token, display] : mDisplays) {
const auto displayId = HalDisplayId::tryCast(display->getId());
if (!displayId) {
continue;
@@ -6695,7 +6695,7 @@
if (!mLayerLifecycleManagerEnabled) {
return dumpHwcLayersMinidumpLockedLegacy(result);
}
- for (const auto& [token, display] : FTL_FAKE_GUARD(mStateLock, mDisplays)) {
+ for (const auto& [token, display] : mDisplays) {
const auto displayId = HalDisplayId::tryCast(display->getId());
if (!displayId) {
continue;
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
index 2dc89b5..3752d5e 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -62,12 +62,12 @@
proto.mutable_layer_changes()->Reserve(static_cast<int32_t>(t.states.size()));
for (auto& layerState : t.states) {
- proto.mutable_layer_changes()->Add(std::move(toProto(layerState)));
+ proto.mutable_layer_changes()->Add(toProto(layerState));
}
proto.mutable_display_changes()->Reserve(static_cast<int32_t>(t.displays.size()));
for (auto& displayState : t.displays) {
- proto.mutable_display_changes()->Add(std::move(toProto(displayState)));
+ proto.mutable_display_changes()->Add(toProto(displayState));
}
proto.mutable_merged_transaction_ids()->Reserve(
diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp
index 696f348..bc9f809 100644
--- a/services/surfaceflinger/Tracing/TransactionTracing.cpp
+++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp
@@ -244,7 +244,7 @@
static_cast<int32_t>(update.createdLayers.size()));
for (const auto& args : update.createdLayers) {
- entryProto.mutable_added_layers()->Add(std::move(mProtoParser.toProto(args)));
+ entryProto.mutable_added_layers()->Add(mProtoParser.toProto(args));
}
entryProto.mutable_destroyed_layers()->Reserve(
@@ -276,7 +276,7 @@
static_cast<int32_t>(update.displayInfos.size()));
for (auto& [layerStack, displayInfo] : update.displayInfos) {
entryProto.mutable_displays()->Add(
- std::move(mProtoParser.toProto(displayInfo, layerStack.id)));
+ mProtoParser.toProto(displayInfo, layerStack.id));
}
}
diff --git a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
index fb4ef70..7bf1674 100644
--- a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
@@ -131,14 +131,14 @@
// add layers and add some layer transaction
{
frontend::Update update;
- update.layerCreationArgs.emplace_back(std::move(
+ update.layerCreationArgs.emplace_back(
getLayerCreationArgs(mParentLayerId, /*parentId=*/UNASSIGNED_LAYER_ID,
/*layerIdToMirror=*/UNASSIGNED_LAYER_ID, /*flags=*/123,
- /*addToRoot=*/true)));
- update.layerCreationArgs.emplace_back(std::move(
+ /*addToRoot=*/true));
+ update.layerCreationArgs.emplace_back(
getLayerCreationArgs(mChildLayerId, mParentLayerId,
/*layerIdToMirror=*/UNASSIGNED_LAYER_ID, /*flags=*/456,
- /*addToRoot=*/true)));
+ /*addToRoot=*/true));
TransactionState transaction;
transaction.id = 50;
ResolvedComposerState layerState;
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 81fd118..e9204ab 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -339,10 +339,13 @@
ALOGD("Unload builtin Vulkan driver.");
- // Close the opened device
- int err = hal_.dev_->common.close(
- const_cast<struct hw_device_t*>(&hal_.dev_->common));
- ALOG_ASSERT(!err, "hw_device_t::close() failed.");
+ if (hal_.dev_->common.close != nullptr)
+ {
+ // Close the opened device
+ int err = hal_.dev_->common.close(
+ const_cast<struct hw_device_t*>(&hal_.dev_->common));
+ ALOG_ASSERT(!err, "hw_device_t::close() failed.");
+ }
// Close the opened shared library in the hw_module_t
android_unload_sphal_library(hal_.dev_->common.module->dso);