Merge "Update ANGLE Platform.h file"
diff --git a/libs/gui/CleanSpec.mk b/CleanSpec.mk
similarity index 70%
rename from libs/gui/CleanSpec.mk
rename to CleanSpec.mk
index 5a5144c..1855d26 100644
--- a/libs/gui/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2012 The Android Open Source Project
+# Copyright (C) 2018 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -34,19 +34,23 @@
# made today requires touching the same file, just copy the old
# touch step and add it to the end of the list.
#
-# ************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
+# *****************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER
+# *****************************************************************
# For example:
#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
-
-# ************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
+$(call add-clean-step, find $(PRODUCT_OUT) -type f -name "libdvr.so" -print0 | xargs -0 rm -f)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libdvr_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libdvr_intermediates)
$(call add-clean-step, find $(PRODUCT_OUT) -type f -name "libgui*" -print0 | xargs -0 rm -f)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libgui_intermediates)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libgui_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/thermalserviced)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/init/thermalservice.rc)
+# ******************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
+# ******************************************************************
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index d6ca0bf..4459cef 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -97,6 +97,14 @@
chmod 0666 /sys/kernel/tracing/events/kmem/ion_heap_grow/enable
chmod 0666 /sys/kernel/debug/tracing/events/kmem/ion_heap_shrink/enable
chmod 0666 /sys/kernel/tracing/events/kmem/ion_heap_shrink/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/signal/signal_generate/enable
+ chmod 0666 /sys/kernel/tracing/events/signal/signal_generate/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/signal/signal_deliver/enable
+ chmod 0666 /sys/kernel/tracing/events/signal/signal_deliver/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/mm_event/mm_event_record/enable
+ chmod 0666 /sys/kernel/tracing/events/mm_event/mm_event_record/enable
+ chmod 0666 /sys/kernel/debug/tracing/events/lowmemorykiller/lowmemory_kill/enable
+ chmod 0666 /sys/kernel/tracing/events/lowmemorykiller/lowmemory_kill/enable
# disk
chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_get_data_block/enable
diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp
index 600a500..97c8ae2 100644
--- a/cmds/dumpstate/DumpstateUtil.cpp
+++ b/cmds/dumpstate/DumpstateUtil.cpp
@@ -101,13 +101,16 @@
}
CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::AsRoot() {
- values.account_mode_ = SU_ROOT;
+ if (!PropertiesHelper::IsUnroot()) {
+ values.account_mode_ = SU_ROOT;
+ }
return *this;
}
CommandOptions::CommandOptionsBuilder& CommandOptions::CommandOptionsBuilder::AsRootIfAvailable() {
- if (!PropertiesHelper::IsUserBuild())
- values.account_mode_ = SU_ROOT;
+ if (!PropertiesHelper::IsUserBuild()) {
+ return AsRoot();
+ }
return *this;
}
@@ -176,6 +179,7 @@
std::string PropertiesHelper::build_type_ = "";
int PropertiesHelper::dry_run_ = -1;
+int PropertiesHelper::unroot_ = -1;
bool PropertiesHelper::IsUserBuild() {
if (build_type_.empty()) {
@@ -191,6 +195,13 @@
return dry_run_ == 1;
}
+bool PropertiesHelper::IsUnroot() {
+ if (unroot_ == -1) {
+ unroot_ = android::base::GetBoolProperty("dumpstate.unroot", false) ? 1 : 0;
+ }
+ return unroot_ == 1;
+}
+
int DumpFileToFd(int out_fd, const std::string& title, const std::string& path) {
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
if (fd.get() < 0) {
diff --git a/cmds/dumpstate/DumpstateUtil.h b/cmds/dumpstate/DumpstateUtil.h
index 8342099..d69ffbf 100644
--- a/cmds/dumpstate/DumpstateUtil.h
+++ b/cmds/dumpstate/DumpstateUtil.h
@@ -97,9 +97,16 @@
public:
/* Sets the command to always run, even on `dry-run` mode. */
CommandOptionsBuilder& Always();
- /* Sets the command's PrivilegeMode as `SU_ROOT` */
+ /*
+ * Sets the command's PrivilegeMode as `SU_ROOT` unless overridden by system property
+ * 'dumpstate.unroot'.
+ */
CommandOptionsBuilder& AsRoot();
- /* If !IsUserBuild(), sets the command's PrivilegeMode as `SU_ROOT` */
+ /*
+ * Runs AsRoot() on userdebug builds. No-op on user builds since 'su' is
+ * not available. This is used for commands that return some useful information even
+ * when run as shell.
+ */
CommandOptionsBuilder& AsRootIfAvailable();
/* Sets the command's PrivilegeMode as `DROP_ROOT` */
CommandOptionsBuilder& DropRoot();
@@ -162,9 +169,17 @@
*/
static bool IsDryRun();
+ /**
+ * Checks whether root availability should be overridden.
+ *
+ * Useful to verify how dumpstate would work in a device with an user build.
+ */
+ static bool IsUnroot();
+
private:
static std::string build_type_;
static int dry_run_;
+ static int unroot_;
};
/*
diff --git a/cmds/dumpstate/README.md b/cmds/dumpstate/README.md
index 0302ea5..d5b2953 100644
--- a/cmds/dumpstate/README.md
+++ b/cmds/dumpstate/README.md
@@ -28,22 +28,22 @@
## To build, deploy, and run unit tests
-First create `/data/nativetest`:
+First create `/data/nativetest64`:
```
-adb shell mkdir /data/nativetest
+adb shell mkdir /data/nativetest64
```
Then run:
```
-mmm -j frameworks/native/cmds/dumpstate/ && adb push ${OUT}/data/nativetest/dumpstate_test* /data/nativetest && adb shell /data/nativetest/dumpstate_test/dumpstate_test
+mmm -j frameworks/native/cmds/dumpstate/ && adb push ${OUT}/data/nativetest64/dumpstate_test* /data/nativetest64 && adb shell /data/nativetest/dumpstate_test/dumpstate_test
```
And to run just one test (for example, `DumpstateTest.RunCommandNoArgs`):
```
-mmm -j frameworks/native/cmds/dumpstate/ && adb push ${OUT}/data/nativetest/dumpstate_test* /data/nativetest && adb shell /data/nativetest/dumpstate_test/dumpstate_test --gtest_filter=DumpstateTest.RunCommandNoArgs
+mmm -j frameworks/native/cmds/dumpstate/ && adb push ${OUT}/data/nativetest64/dumpstate_test* /data/nativetest64 && adb shell /data/nativetest/dumpstate_test/dumpstate_test --gtest_filter=DumpstateTest.RunCommandNoArgs
```
## To take quick bugreports
@@ -52,6 +52,12 @@
adb shell setprop dumpstate.dry_run true
```
+## To emulate a device with user build
+
+```
+adb shell setprop dumpstate.unroot true
+```
+
## To change the `dumpstate` version
```
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 904c0e9..1a45436 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1977,7 +1977,8 @@
// Reset the property
android::base::SetProperty(PROPERTY_EXTRA_TITLE, "");
- options->extra_options = android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
+ options->notification_description =
+ android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
if (!options->notification_description.empty()) {
// Reset the property
android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index b675c51..2cb9800 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -85,6 +85,10 @@
PropertiesHelper::build_type_ = build_type;
}
+ void SetUnroot(bool unroot) const {
+ PropertiesHelper::unroot_ = unroot;
+ }
+
bool IsStandalone() const {
return calls_ == 1;
}
@@ -650,6 +654,32 @@
EXPECT_THAT(err, StrEq("stderr\n"));
}
+TEST_F(DumpstateTest, RunCommandAsRootNonUserBuild_withUnroot) {
+ if (!IsStandalone()) {
+ // TODO: temporarily disabled because it might cause other tests to fail after dropping
+ // to Shell - need to refactor tests to avoid this problem)
+ MYLOGE(
+ "Skipping DumpstateTest.RunCommandAsRootNonUserBuild_withUnroot() "
+ "on test suite\n")
+ return;
+ }
+ if (PropertiesHelper::IsUserBuild()) {
+ ALOGI("Skipping RunCommandAsRootNonUserBuild_withUnroot on user builds\n");
+ return;
+ }
+
+ // Same test as above, but with unroot property set, which will override su availability.
+ SetUnroot(true);
+ DropRoot();
+
+ EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
+ CommandOptions::WithTimeout(1).AsRoot().Build()));
+
+ // AsRoot is ineffective.
+ EXPECT_THAT(out, StrEq("2000\nstdout\n"));
+ EXPECT_THAT(err, StrEq("drop_root_user(): already running as Shell\nstderr\n"));
+}
+
TEST_F(DumpstateTest, RunCommandAsRootIfAvailableOnUserBuild) {
if (!IsStandalone()) {
// TODO: temporarily disabled because it might cause other tests to fail after dropping
@@ -692,6 +722,32 @@
EXPECT_THAT(err, StrEq("stderr\n"));
}
+TEST_F(DumpstateTest, RunCommandAsRootIfAvailableOnDebugBuild_withUnroot) {
+ if (!IsStandalone()) {
+ // TODO: temporarily disabled because it might cause other tests to fail after dropping
+ // to Shell - need to refactor tests to avoid this problem)
+ MYLOGE(
+ "Skipping DumpstateTest.RunCommandAsRootIfAvailableOnDebugBuild_withUnroot() "
+ "on test suite\n")
+ return;
+ }
+ if (PropertiesHelper::IsUserBuild()) {
+ ALOGI("Skipping RunCommandAsRootIfAvailableOnDebugBuild_withUnroot on user builds\n");
+ return;
+ }
+ // Same test as above, but with unroot property set, which will override su availability.
+ SetUnroot(true);
+
+ DropRoot();
+
+ EXPECT_EQ(0, RunCommand("", {kSimpleCommand, "--uid"},
+ CommandOptions::WithTimeout(1).AsRootIfAvailable().Build()));
+
+ // It's a userdebug build, so "su root" should be available, but unroot=true overrides it.
+ EXPECT_THAT(out, StrEq("2000\nstdout\n"));
+ EXPECT_THAT(err, StrEq("stderr\n"));
+}
+
TEST_F(DumpstateTest, DumpFileNotFoundNoTitle) {
EXPECT_EQ(-1, DumpFile("", "/I/cant/believe/I/exist"));
EXPECT_THAT(out,
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 50a2412..aad9939 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -701,12 +701,13 @@
unique_fd&& reference_profile_fd,
unique_fd&& apk_fd,
const std::string& dex_location) {
- std::vector<unique_fd> profiles_fd;
- profiles_fd.push_back(std::move(profile_fd));
- std::vector<unique_fd> apk_fds;
- profiles_fd.push_back(std::move(apk_fd));
+ // The fds need to stay open longer than the scope of the function, so put them into a local
+ // variable vector.
+ profiles_fd_.push_back(std::move(profile_fd));
+ apk_fds_.push_back(std::move(apk_fd));
+ reference_profile_fd_ = std::move(reference_profile_fd);
std::vector<std::string> dex_locations = {dex_location};
- SetupArgs(profiles_fd, reference_profile_fd, apk_fds, dex_locations,
+ SetupArgs(profiles_fd_, reference_profile_fd_, apk_fds_, dex_locations,
/*copy_and_update=*/true);
}
@@ -724,6 +725,11 @@
void Exec() {
ExecVHelper::Exec(DexoptReturnCodes::kProfmanExec);
}
+
+ private:
+ unique_fd reference_profile_fd_;
+ std::vector<unique_fd> profiles_fd_;
+ std::vector<unique_fd> apk_fds_;
};
diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto
index 68ddeb0..c169b76 100644
--- a/cmds/surfacereplayer/proto/src/trace.proto
+++ b/cmds/surfacereplayer/proto/src/trace.proto
@@ -160,7 +160,7 @@
message DisplayCreation {
required int32 id = 1;
required string name = 2;
- required int32 type = 3;
+ optional uint64 display_id = 3;
required bool is_secure = 4;
}
diff --git a/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py b/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py
index a892e46..d63d97f 100644
--- a/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py
+++ b/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py
@@ -172,7 +172,7 @@
def display_create(increment):
increment.display_creation.id = int(input("Enter id: "))
increment.display_creation.name = str(raw_input("Enter name: "))
- increment.display_creation.type = int(input("Enter type: "))
+ increment.display_creation.display_id = int(input("Enter display ID: "))
increment.display_creation.is_secure = bool(input("Enter if secure: "))
def display_delete(increment):
diff --git a/headers/media_plugin/media/drm/DrmAPI.h b/headers/media_plugin/media/drm/DrmAPI.h
index c44a1f6..aa8bd3d 100644
--- a/headers/media_plugin/media/drm/DrmAPI.h
+++ b/headers/media_plugin/media/drm/DrmAPI.h
@@ -167,6 +167,25 @@
kSecurityLevelHwSecureAll
};
+ // An offline license may be usable or inactive. The keys in a
+ // usable offline license are available for decryption. When
+ // the offline license state is inactive, the keys have been
+ // marked for release using getKeyRequest with
+ // kKeyType_Release but the key response has not been
+ // received. The keys in an inactive offline license are not
+ // usable for decryption.
+
+ enum OfflineLicenseState {
+ // The offline license state is unknown due to an error
+ kOfflineLicenseStateUnknown,
+ // Offline license state is usable, the keys may be used for decryption.
+ kOfflineLicenseStateUsable,
+ // Offline license state is inactive, the keys have been marked for
+ // release using getKeyRequest() with kKeyType_Release but the
+ // key response has not been received.
+ kOfflineLicenseStateInactive
+ };
+
DrmPlugin() {}
virtual ~DrmPlugin() {}
diff --git a/include/input/IInputFlinger.h b/include/input/IInputFlinger.h
index 11bb721..1ef8986 100644
--- a/include/input/IInputFlinger.h
+++ b/include/input/IInputFlinger.h
@@ -22,6 +22,9 @@
#include <binder/IInterface.h>
+#include <utils/Vector.h>
+#include <input/InputWindow.h>
+
namespace android {
/*
@@ -31,6 +34,8 @@
class IInputFlinger : public IInterface {
public:
DECLARE_META_INTERFACE(InputFlinger)
+
+ virtual void setInputWindows(const Vector<InputWindowInfo>& inputHandles) = 0;
};
@@ -40,7 +45,7 @@
class BnInputFlinger : public BnInterface<IInputFlinger> {
public:
enum {
- DO_SOMETHING_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+ SET_INPUT_WINDOWS_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
};
virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/include/input/Input.h b/include/input/Input.h
index 819a89f..d35354b 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -17,6 +17,8 @@
#ifndef _LIBINPUT_INPUT_H
#define _LIBINPUT_INPUT_H
+#pragma GCC system_header
+
/**
* Native input event structures.
*/
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 4782c9b..d906db3 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -17,6 +17,8 @@
#ifndef _LIBINPUT_INPUT_TRANSPORT_H
#define _LIBINPUT_INPUT_TRANSPORT_H
+#pragma GCC system_header
+
/**
* Native input transport.
*
@@ -29,6 +31,7 @@
#include <string>
+#include <binder/IBinder.h>
#include <input/Input.h>
#include <utils/Errors.h>
#include <utils/Timers.h>
@@ -188,11 +191,16 @@
status_t write(Parcel& out) const;
status_t read(const Parcel& from);
+ sp<IBinder> getToken() const;
+ void setToken(const sp<IBinder>& token);
+
private:
void setFd(int fd);
std::string mName;
int mFd = -1;
+
+ sp<IBinder> mToken = nullptr;
};
/*
diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h
index 7c284dd..9e3d334 100644
--- a/include/input/InputWindow.h
+++ b/include/input/InputWindow.h
@@ -33,6 +33,9 @@
* Describes the properties of a window that can receive input.
*/
struct InputWindowInfo {
+ InputWindowInfo() = default;
+ InputWindowInfo(const Parcel& from);
+
// Window flags from WindowManager.LayoutParams
enum {
FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001,
@@ -168,17 +171,17 @@
const sp<InputApplicationHandle> inputApplicationHandle;
inline const InputWindowInfo* getInfo() const {
- return mInfo;
+ return &mInfo;
}
sp<InputChannel> getInputChannel() const;
inline std::string getName() const {
- return mInfo ? mInfo->name : "<invalid>";
+ return mInfo.inputChannel ? mInfo.name : "<invalid>";
}
inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {
- return mInfo ? mInfo->dispatchingTimeout : defaultValue;
+ return mInfo.inputChannel? mInfo.dispatchingTimeout : defaultValue;
}
/**
@@ -193,16 +196,16 @@
virtual bool updateInfo() = 0;
/**
- * Releases the storage used by the associated information when it is
+ * Releases the channel used by the associated information when it is
* no longer needed.
*/
- void releaseInfo();
+ void releaseChannel();
protected:
explicit InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle);
virtual ~InputWindowHandle();
- InputWindowInfo* mInfo;
+ InputWindowInfo mInfo;
};
} // namespace android
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index bc1a71c..532f7f1 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -2245,8 +2245,30 @@
int32_t hasComm = readInt32();
int fd = readFileDescriptor();
if (hasComm != 0) {
- // skip
- readFileDescriptor();
+ // detach (owned by the binder driver)
+ int comm = readFileDescriptor();
+
+ // warning: this must be kept in sync with:
+ // frameworks/base/core/java/android/os/ParcelFileDescriptor.java
+ enum ParcelFileDescriptorStatus {
+ DETACHED = 2,
+ };
+
+#if BYTE_ORDER == BIG_ENDIAN
+ const int32_t message = ParcelFileDescriptorStatus::DETACHED;
+#endif
+#if BYTE_ORDER == LITTLE_ENDIAN
+ const int32_t message = __builtin_bswap32(ParcelFileDescriptorStatus::DETACHED);
+#endif
+
+ ssize_t written = TEMP_FAILURE_RETRY(
+ ::write(comm, &message, sizeof(message)));
+
+ if (written == -1 || written != sizeof(message)) {
+ ALOGW("Failed to detach ParcelFileDescriptor written: %zd err: %s",
+ written, strerror(errno));
+ return BAD_TYPE;
+ }
}
return fd;
}
diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
index 14edcbe..1674516 100644
--- a/libs/binder/include/binder/IBinder.h
+++ b/libs/binder/include/binder/IBinder.h
@@ -47,7 +47,7 @@
* (method calls, property get and set) is down through a low-level
* protocol implemented on top of the transact() API.
*/
-class IBinder : public virtual RefBase
+class [[clang::lto_visibility_public]] IBinder : public virtual RefBase
{
public:
enum {
diff --git a/libs/binder/ndk/.clang-format b/libs/binder/ndk/.clang-format
new file mode 100644
index 0000000..9a9d936
--- /dev/null
+++ b/libs/binder/ndk/.clang-format
@@ -0,0 +1,10 @@
+BasedOnStyle: Google
+ColumnLimit: 100
+IndentWidth: 4
+ContinuationIndentWidth: 8
+PointerAlignment: Left
+TabWidth: 4
+AllowShortFunctionsOnASingleLine: Inline
+PointerAlignment: Left
+TabWidth: 4
+UseTab: Never
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index d16502f..14ce4cb 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -39,6 +39,8 @@
"libutils",
],
+ cpp_std: "c++17",
+
version_script: "libbinder_ndk.map.txt",
}
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index e1c2009..f9c8c8a 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -22,6 +22,7 @@
#include "status_internal.h"
#include <android-base/logging.h>
+#include <binder/IPCThreadState.h>
using DeathRecipient = ::android::IBinder::DeathRecipient;
@@ -45,7 +46,7 @@
return binder != nullptr && binder->findObject(kId) == kValue;
}
-} // namespace ABBinderTag
+} // namespace ABBinderTag
namespace ABpBinderTag {
@@ -60,7 +61,7 @@
delete static_cast<Value*>(obj);
};
-} // namespace ABpBinderTag
+} // namespace ABpBinderTag
AIBinder::AIBinder(const AIBinder_Class* clazz) : mClazz(clazz) {}
AIBinder::~AIBinder() {}
@@ -91,7 +92,7 @@
return false;
}
- CHECK(asABpBinder() != nullptr); // ABBinder always has a descriptor
+ CHECK(asABpBinder() != nullptr); // ABBinder always has a descriptor
String8 descriptor(getBinder()->getInterfaceDescriptor());
if (descriptor != newDescriptor) {
@@ -107,7 +108,7 @@
}
ABBinder::ABBinder(const AIBinder_Class* clazz, void* userData)
- : AIBinder(clazz), BBinder(), mUserData(userData) {
+ : AIBinder(clazz), BBinder(), mUserData(userData) {
CHECK(clazz != nullptr);
}
ABBinder::~ABBinder() {
@@ -136,7 +137,7 @@
}
ABpBinder::ABpBinder(const ::android::sp<::android::IBinder>& binder)
- : AIBinder(nullptr /*clazz*/), BpRefBase(binder) {
+ : AIBinder(nullptr /*clazz*/), BpRefBase(binder) {
CHECK(binder != nullptr);
}
ABpBinder::~ABpBinder() {}
@@ -214,10 +215,10 @@
AIBinder_Class::AIBinder_Class(const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate,
AIBinder_Class_onDestroy onDestroy,
AIBinder_Class_onTransact onTransact)
- : onCreate(onCreate),
- onDestroy(onDestroy),
- onTransact(onTransact),
- mInterfaceDescriptor(interfaceDescriptor) {}
+ : onCreate(onCreate),
+ onDestroy(onDestroy),
+ onTransact(onTransact),
+ mInterfaceDescriptor(interfaceDescriptor) {}
AIBinder_Class* AIBinder_Class_define(const char* interfaceDescriptor,
AIBinder_Class_onCreate onCreate,
@@ -239,7 +240,7 @@
}
AIBinder_DeathRecipient::AIBinder_DeathRecipient(AIBinder_DeathRecipient_onBinderDied onDied)
- : mOnDied(onDied) {
+ : mOnDied(onDied) {
CHECK(onDied != nullptr);
}
@@ -346,6 +347,14 @@
return recipient->unlinkToDeath(binder, cookie);
}
+uid_t AIBinder_getCallingUid() {
+ return ::android::IPCThreadState::self()->getCallingUid();
+}
+
+pid_t AIBinder_getCallingPid() {
+ return ::android::IPCThreadState::self()->getCallingPid();
+}
+
void AIBinder_incStrong(AIBinder* binder) {
if (binder == nullptr) {
LOG(ERROR) << __func__ << ": on null binder";
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index 5b6bc94..ac592ea 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -49,7 +49,7 @@
return binder->remoteBinder() != nullptr;
}
-private:
+ private:
// AIBinder instance is instance of this class for a local object. In order to transact on a
// remote object, this also must be set for simplicity (although right now, only the
// interfaceDescriptor from it is used).
@@ -69,7 +69,7 @@
::android::status_t onTransact(uint32_t code, const ::android::Parcel& data,
::android::Parcel* reply, binder_flags_t flags) override;
-private:
+ private:
ABBinder(const AIBinder_Class* clazz, void* userData);
// only thing that should create an ABBinder
@@ -96,7 +96,7 @@
::android::sp<::android::IBinder> getBinder() override { return remote(); }
ABpBinder* asABpBinder() override { return this; }
-private:
+ private:
ABpBinder(const ::android::sp<::android::IBinder>& binder);
};
@@ -110,7 +110,7 @@
const AIBinder_Class_onDestroy onDestroy;
const AIBinder_Class_onTransact onTransact;
-private:
+ private:
// This must be a String16 since BBinder virtual getInterfaceDescriptor returns a reference to
// one.
const ::android::String16 mInterfaceDescriptor;
@@ -128,14 +128,14 @@
struct TransferDeathRecipient : ::android::IBinder::DeathRecipient {
TransferDeathRecipient(const ::android::wp<::android::IBinder>& who, void* cookie,
const AIBinder_DeathRecipient_onBinderDied& onDied)
- : mWho(who), mCookie(cookie), mOnDied(onDied) {}
+ : mWho(who), mCookie(cookie), mOnDied(onDied) {}
void binderDied(const ::android::wp<::android::IBinder>& who) override;
const ::android::wp<::android::IBinder>& getWho() { return mWho; }
void* getCookie() { return mCookie; }
- private:
+ private:
::android::wp<::android::IBinder> mWho;
void* mCookie;
const AIBinder_DeathRecipient_onBinderDied& mOnDied;
@@ -145,7 +145,7 @@
binder_status_t linkToDeath(AIBinder* binder, void* cookie);
binder_status_t unlinkToDeath(AIBinder* binder, void* cookie);
-private:
+ private:
std::mutex mDeathRecipientsMutex;
std::vector<::android::sp<TransferDeathRecipient>> mDeathRecipients;
AIBinder_DeathRecipient_onBinderDied mOnDied;
diff --git a/libs/binder/ndk/include_apex/android/binder_manager.h b/libs/binder/ndk/include_apex/android/binder_manager.h
index b8f38ba..80b6c07 100644
--- a/libs/binder/ndk/include_apex/android/binder_manager.h
+++ b/libs/binder/ndk/include_apex/android/binder_manager.h
@@ -17,11 +17,18 @@
#pragma once
#include <android/binder_ibinder.h>
+#include <android/binder_status.h>
__BEGIN_DECLS
/**
- * This registers the service with the default service manager under this instance name.
+ * This registers the service with the default service manager under this instance name. This does
+ * not take ownership of binder.
+ *
+ * \param binder object to register globally with the service manager.
+ * \param instance identifier of the service. This will be used to lookup the service.
+ *
+ * \return STATUS_OK on success.
*/
binder_status_t AServiceManager_addService(AIBinder* binder, const char* instance);
@@ -29,6 +36,8 @@
* Gets a binder object with this specific instance name. Blocks for a couple of seconds waiting on
* it. This also implicitly calls AIBinder_incStrong (so the caller of this function is responsible
* for calling AIBinder_decStrong).
+ *
+ * \param instance identifier of the service used to lookup the service.
*/
__attribute__((warn_unused_result)) AIBinder* AServiceManager_getService(const char* instance);
diff --git a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
index e52a1d6..e2c0cfa 100644
--- a/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_auto_utils.h
@@ -31,10 +31,8 @@
#include <android/binder_status.h>
#include <assert.h>
+
#include <unistd.h>
-
-#ifdef __cplusplus
-
#include <cstddef>
namespace ndk {
@@ -43,7 +41,7 @@
* Represents one strong pointer to an AIBinder object.
*/
class SpAIBinder {
-public:
+ public:
/**
* Takes ownership of one strong refcount of binder.
*/
@@ -107,7 +105,7 @@
*/
AIBinder** getR() { return &mBinder; }
-private:
+ private:
AIBinder* mBinder = nullptr;
};
@@ -116,7 +114,7 @@
*/
template <typename T, typename R, R (*Destroy)(T), T DEFAULT>
class ScopedAResource {
-public:
+ public:
/**
* Takes ownership of t.
*/
@@ -167,7 +165,7 @@
// move-constructing is okay
ScopedAResource(ScopedAResource&&) = default;
-private:
+ private:
T mT;
};
@@ -175,7 +173,7 @@
* Convenience wrapper. See AParcel.
*/
class ScopedAParcel : public ScopedAResource<AParcel*, void, AParcel_delete, nullptr> {
-public:
+ public:
/**
* Takes ownership of a.
*/
@@ -188,7 +186,7 @@
* Convenience wrapper. See AStatus.
*/
class ScopedAStatus : public ScopedAResource<AStatus*, void, AStatus_delete, nullptr> {
-public:
+ public:
/**
* Takes ownership of a.
*/
@@ -200,20 +198,25 @@
* See AStatus_isOk.
*/
bool isOk() { return get() != nullptr && AStatus_isOk(get()); }
+
+ /**
+ * Convenience method for okay status.
+ */
+ static ScopedAStatus ok() { return ScopedAStatus(AStatus_newOk()); }
};
/**
* Convenience wrapper. See AIBinder_DeathRecipient.
*/
class ScopedAIBinder_DeathRecipient
- : public ScopedAResource<AIBinder_DeathRecipient*, void, AIBinder_DeathRecipient_delete,
- nullptr> {
-public:
+ : public ScopedAResource<AIBinder_DeathRecipient*, void, AIBinder_DeathRecipient_delete,
+ nullptr> {
+ public:
/**
* Takes ownership of a.
*/
explicit ScopedAIBinder_DeathRecipient(AIBinder_DeathRecipient* a = nullptr)
- : ScopedAResource(a) {}
+ : ScopedAResource(a) {}
~ScopedAIBinder_DeathRecipient() {}
ScopedAIBinder_DeathRecipient(ScopedAIBinder_DeathRecipient&&) = default;
};
@@ -222,8 +225,8 @@
* Convenience wrapper. See AIBinder_Weak.
*/
class ScopedAIBinder_Weak
- : public ScopedAResource<AIBinder_Weak*, void, AIBinder_Weak_delete, nullptr> {
-public:
+ : public ScopedAResource<AIBinder_Weak*, void, AIBinder_Weak_delete, nullptr> {
+ public:
/**
* Takes ownership of a.
*/
@@ -241,7 +244,7 @@
* Convenience wrapper for a file descriptor.
*/
class ScopedFileDescriptor : public ScopedAResource<int, int, close, -1> {
-public:
+ public:
/**
* Takes ownership of a.
*/
@@ -250,8 +253,6 @@
ScopedFileDescriptor(ScopedFileDescriptor&&) = default;
};
-} // namespace ndk
-
-#endif // __cplusplus
+} // namespace ndk
/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index c222c16..9c6c55e 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -28,6 +28,7 @@
#include <stdint.h>
#include <sys/cdefs.h>
+#include <sys/types.h>
#include <android/binder_parcel.h>
#include <android/binder_status.h>
@@ -126,8 +127,9 @@
/**
* This is called whenever a new AIBinder object is needed of a specific class.
*
- * These arguments are passed from AIBinder_new. The return value is stored and can be retrieved
- * using AIBinder_getUserData.
+ * \param args these can be used to construct a new class. These are passed from AIBinder_new.
+ * \return this is the userdata representing the class. It can be retrieved using
+ * AIBinder_getUserData.
*/
typedef void* (*AIBinder_Class_onCreate)(void* args);
@@ -135,23 +137,41 @@
* This is called whenever an AIBinder object is no longer referenced and needs destroyed.
*
* Typically, this just deletes whatever the implementation is.
+ *
+ * \param userData this is the same object returned by AIBinder_Class_onCreate
*/
typedef void (*AIBinder_Class_onDestroy)(void* userData);
/**
* This is called whenever a transaction needs to be processed by a local implementation.
+ *
+ * \param binder the object being transacted on.
+ * \param code implementation-specific code representing which transaction should be taken.
+ * \param in the implementation-specific input data to this transaction.
+ * \param out the implementation-specific output data to this transaction.
+ *
+ * \return the implementation-specific output code. This may be forwarded from another service, the
+ * result of a parcel read or write, or another error as is applicable to the specific
+ * implementation. Usually, implementation-specific error codes are written to the output parcel,
+ * and the transaction code is reserved for kernel errors or error codes that have been repeated
+ * from subsequent transactions.
*/
typedef binder_status_t (*AIBinder_Class_onTransact)(AIBinder* binder, transaction_code_t code,
const AParcel* in, AParcel* out);
/**
- * An interfaceDescriptor uniquely identifies the type of object that is being created. This is used
- * internally for sanity checks on transactions.
+ * This creates a new instance of a class of binders which can be instantiated. This is called one
+ * time during library initialization and cleaned up when the process exits or execs.
*
- * None of these parameters can be nullptr.
+ * None of these parameters can be null.
*
- * This is created one time during library initialization and cleaned up when the process exits or
- * execs.
+ * \param interfaceDescriptor this is a unique identifier for the class. This is used internally for
+ * sanity checks on transactions.
+ * \param onCreate see AIBinder_Class_onCreate.
+ * \param onDestroy see AIBinder_Class_onDestroy.
+ * \param onTransact see AIBinder_Class_onTransact.
+ *
+ * \return the class object representing these parameters or null on error.
*/
__attribute__((warn_unused_result)) AIBinder_Class* AIBinder_Class_define(
const char* interfaceDescriptor, AIBinder_Class_onCreate onCreate,
@@ -174,12 +194,21 @@
* hypothetical removeCallback function, the remote process would have no way to determine that
* these two objects are actually equal using the AIBinder pointer alone (which they should be able
* to do). Also see the suggested memory ownership model suggested above.
+ *
+ * \param clazz the type of the object to be created.
+ * \param args the args to pass to AIBinder_onCreate for that class.
+ *
+ * \return a binder object representing the newly instantiated object.
*/
__attribute__((warn_unused_result)) AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args)
__INTRODUCED_IN(29);
/**
* If this is hosted in a process other than the current one.
+ *
+ * \param binder the binder being queried.
+ *
+ * \return true if the AIBinder represents an object in another process.
*/
bool AIBinder_isRemote(const AIBinder* binder) __INTRODUCED_IN(29);
@@ -189,13 +218,21 @@
* this is automatically updated to reflect the current alive status of this binder. This will be
* updated as the result of a transaction made using AIBinder_transact, but it will also be updated
* based on the results of bookkeeping or other transactions made internally.
+ *
+ * \param binder the binder being queried.
+ *
+ * \return true if the binder is alive.
*/
bool AIBinder_isAlive(const AIBinder* binder) __INTRODUCED_IN(29);
/**
- * Built-in transaction for all binder objects. This sends a transaction which will immediately
+ * Built-in transaction for all binder objects. This sends a transaction that will immediately
* return. Usually this is used to make sure that a binder is alive, as a placeholder call, or as a
* sanity check.
+ *
+ * \param binder the binder being queried.
+ *
+ * \return STATUS_OK if the ping succeeds.
*/
binder_status_t AIBinder_ping(AIBinder* binder) __INTRODUCED_IN(29);
@@ -209,6 +246,12 @@
* identification and holding user data.
*
* If binder is local, this will return STATUS_INVALID_OPERATION.
+ *
+ * \param binder the binder object you want to receive death notifications from.
+ * \param recipient the callback that will receive notifications when/if the binder dies.
+ * \param cookie the value that will be passed to the death recipient on death.
+ *
+ * \return STATUS_OK on success.
*/
binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
void* cookie) __INTRODUCED_IN(29);
@@ -217,22 +260,62 @@
* Stops registration for the associated binder dying. Does not delete the recipient. This function
* may return a binder transaction failure and in case the death recipient cannot be found, it
* returns STATUS_NAME_NOT_FOUND.
+ *
+ * \param binder the binder object to remove a previously linked death recipient from.
+ * \param recipient the callback to remove.
+ * \param cookie the cookie used to link to death.
+ *
+ * \return STATUS_OK on success. STATUS_NAME_NOT_FOUND if the binder cannot be found to be unlinked.
*/
binder_status_t AIBinder_unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
void* cookie) __INTRODUCED_IN(29);
/**
+ * This returns the calling UID assuming that this thread is called from a thread that is processing
+ * a binder transaction (for instance, in the implementation of AIBinder_Class_onTransact).
+ *
+ * This can be used with higher-level system services to determine the caller's identity and check
+ * permissions.
+ *
+ * \return calling uid or the current process's UID if this thread isn't processing a transaction.
+ */
+uid_t AIBinder_getCallingUid();
+
+/**
+ * This returns the calling PID assuming that this thread is called from a thread that is processing
+ * a binder transaction (for instance, in the implementation of AIBinder_Class_onTransact).
+ *
+ * This can be used with higher-level system services to determine the caller's identity and check
+ * permissions. However, when doing this, one should be aware of possible TOCTOU problems when the
+ * calling process dies and is replaced with another process with elevated permissions and the same
+ * PID.
+ *
+ * \return calling pid or the current process's PID if this thread isn't processing a transaction.
+ * If the transaction being processed is a oneway transaction, then this method will return 0.
+ */
+pid_t AIBinder_getCallingPid();
+
+/**
* This can only be called if a strong reference to this object already exists in process.
+ *
+ * \param binder the binder object to add a refcount to.
*/
void AIBinder_incStrong(AIBinder* binder) __INTRODUCED_IN(29);
/**
* This will delete the object and call onDestroy once the refcount reaches zero.
+ *
+ * \param binder the binder object to remove a refcount from.
*/
void AIBinder_decStrong(AIBinder* binder) __INTRODUCED_IN(29);
/**
* For debugging only!
+ *
+ * \param binder the binder object to retrieve the refcount of.
+ *
+ * \return the number of strong-refs on this binder in this process. If binder is null, this will be
+ * -1.
*/
int32_t AIBinder_debugGetRefCount(AIBinder* binder) __INTRODUCED_IN(29);
@@ -244,17 +327,32 @@
*
* This returns true if the class association succeeds. If it fails, no change is made to the
* binder object.
+ *
+ * \param binder the object to attach the class to.
+ * \param clazz the clazz to attach to binder.
+ *
+ * \return true if the binder has the class clazz and if the association was successful.
*/
bool AIBinder_associateClass(AIBinder* binder, const AIBinder_Class* clazz) __INTRODUCED_IN(29);
/**
* Returns the class that this binder was constructed with or associated with.
+ *
+ * \param binder the object that is being queried.
+ *
+ * \return the class that this binder is associated with. If this binder wasn't created with
+ * AIBinder_new, and AIBinder_associateClass hasn't been called, then this will return null.
*/
const AIBinder_Class* AIBinder_getClass(AIBinder* binder) __INTRODUCED_IN(29);
/**
* Value returned by onCreate for a local binder. For stateless classes (if onCreate returns
- * nullptr), this also returns nullptr. For a remote binder, this will always return nullptr.
+ * null), this also returns null. For a remote binder, this will always return null.
+ *
+ * \param binder the object that is being queried.
+ *
+ * \return the userdata returned from AIBinder_onCreate when this object was created. This may be
+ * null for stateless objects. For remote objects, this is always null.
*/
void* AIBinder_getUserData(AIBinder* binder) __INTRODUCED_IN(29);
@@ -278,6 +376,12 @@
* ownership is passed to the caller. At this point, the parcel can be filled out and passed to
* AIBinder_transact. Alternatively, if there is an error while filling out the parcel, it can be
* deleted with AParcel_delete.
+ *
+ * \param binder the binder object to start a transaction on.
+ * \param in out parameter for input data to the transaction.
+ *
+ * \return STATUS_OK on success. This will return STATUS_INVALID_OPERATION if the binder has not yet
+ * been associated with a class (see AIBinder_new and AIBinder_associateClass).
*/
binder_status_t AIBinder_prepareTransaction(AIBinder* binder, AParcel** in) __INTRODUCED_IN(29);
@@ -292,6 +396,16 @@
*
* This does not affect the ownership of binder. The out parcel's ownership is passed to the caller
* and must be released with AParcel_delete when finished reading.
+ *
+ * \param binder the binder object to transact on.
+ * \param code the implementation-specific code representing which transaction should be taken.
+ * \param in the implementation-specific input data to this transaction.
+ * \param out the implementation-specific output data to this transaction.
+ * \param flags possible flags to alter the way in which the transaction is conducted or 0.
+ *
+ * \return the result from the kernel or from the remote process. Usually, implementation-specific
+ * error codes are written to the output parcel, and the transaction code is reserved for kernel
+ * errors or error codes that have been repeated from subsequent transactions.
*/
binder_status_t AIBinder_transact(AIBinder* binder, transaction_code_t code, AParcel** in,
AParcel** out, binder_flags_t flags) __INTRODUCED_IN(29);
@@ -299,29 +413,45 @@
/**
* This does not take any ownership of the input binder, but it can be used to retrieve it if
* something else in some process still holds a reference to it.
+ *
+ * \param binder object to create a weak pointer to.
+ *
+ * \return object representing a weak pointer to binder (or null if binder is null).
*/
__attribute__((warn_unused_result)) AIBinder_Weak* AIBinder_Weak_new(AIBinder* binder)
__INTRODUCED_IN(29);
/**
* Deletes the weak reference. This will have no impact on the lifetime of the binder.
+ *
+ * \param weakBinder object created with AIBinder_Weak_new.
*/
void AIBinder_Weak_delete(AIBinder_Weak* weakBinder) __INTRODUCED_IN(29);
/**
* If promotion succeeds, result will have one strong refcount added to it. Otherwise, this returns
- * nullptr.
+ * null.
+ *
+ * \param weakBinder weak pointer to attempt retrieving the original object from.
+ *
+ * \return an AIBinder object with one refcount given to the caller or null.
*/
__attribute__((warn_unused_result)) AIBinder* AIBinder_Weak_promote(AIBinder_Weak* weakBinder)
__INTRODUCED_IN(29);
/**
* This function is executed on death receipt. See AIBinder_linkToDeath/AIBinder_unlinkToDeath.
+ *
+ * \param cookie the cookie passed to AIBinder_linkToDeath.
*/
typedef void (*AIBinder_DeathRecipient_onBinderDied)(void* cookie) __INTRODUCED_IN(29);
/**
* Creates a new binder death recipient. This can be attached to multiple different binder objects.
+ *
+ * \param onBinderDied the callback to call when this death recipient is invoked.
+ *
+ * \return the newly constructed object (or null if onBinderDied is null).
*/
__attribute__((warn_unused_result)) AIBinder_DeathRecipient* AIBinder_DeathRecipient_new(
AIBinder_DeathRecipient_onBinderDied onBinderDied) __INTRODUCED_IN(29);
@@ -329,10 +459,12 @@
/**
* Deletes a binder death recipient. It is not necessary to call AIBinder_unlinkToDeath before
* calling this as these will all be automatically unlinked.
+ *
+ * \param recipient the binder to delete (previously created with AIBinder_DeathRecipient_new).
*/
void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient* recipient) __INTRODUCED_IN(29);
-#endif //__ANDROID_API__ >= __ANDROID_API_Q__
+#endif //__ANDROID_API__ >= __ANDROID_API_Q__
__END_DECLS
/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
index 81fb3c5..124f36c 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
@@ -39,6 +39,12 @@
* If either env or the binder is null, null is returned. If this binder object was originally an
* AIBinder object, the original object is returned. The returned object has one refcount
* associated with it, and so this should be accompanied with an AIBinder_decStrong call.
+ *
+ * \param env Java environment.
+ * \param binder android.os.IBinder java object.
+ *
+ * \return an AIBinder object representing the Java binder object. If either parameter is null, or
+ * the Java object is of the wrong type, this will return null.
*/
__attribute__((warn_unused_result)) AIBinder* AIBinder_fromJavaBinder(JNIEnv* env, jobject binder)
__INTRODUCED_IN(29);
@@ -48,11 +54,16 @@
*
* If either env or the binder is null, null is returned. If this binder object was originally an
* IBinder object, the original java object will be returned.
+ *
+ * \param env Java environment.
+ * \param binder the object to convert.
+ *
+ * \return an android.os.IBinder object or null if the parameters were null.
*/
__attribute__((warn_unused_result)) jobject AIBinder_toJavaBinder(JNIEnv* env, AIBinder* binder)
__INTRODUCED_IN(29);
-#endif //__ANDROID_API__ >= __ANDROID_API_Q__
+#endif //__ANDROID_API__ >= __ANDROID_API_Q__
__END_DECLS
/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
index e37c388..1532725 100644
--- a/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_interface_utils.h
@@ -32,8 +32,6 @@
#include <assert.h>
-#ifdef __cplusplus
-
#include <memory>
#include <mutex>
@@ -46,7 +44,7 @@
* construct this object is with SharedRefBase::make.
*/
class SharedRefBase {
-public:
+ public:
SharedRefBase() {}
virtual ~SharedRefBase() {
std::call_once(mFlagThis, [&]() {
@@ -83,7 +81,7 @@
return t->template ref<T>();
}
-private:
+ private:
std::once_flag mFlagThis;
std::weak_ptr<SharedRefBase> mThis;
};
@@ -92,7 +90,7 @@
* wrapper analog to IInterface
*/
class ICInterface : public SharedRefBase {
-public:
+ public:
ICInterface() {}
virtual ~ICInterface() {}
@@ -113,7 +111,7 @@
*/
template <typename INTERFACE>
class BnCInterface : public INTERFACE {
-public:
+ public:
BnCInterface() {}
virtual ~BnCInterface() {}
@@ -121,15 +119,15 @@
bool isRemote() override { return true; }
-protected:
+ protected:
/**
* This function should only be called by asBinder. Otherwise, there is a possibility of
* multiple AIBinder* objects being created for the same instance of an object.
*/
virtual SpAIBinder createBinder() = 0;
-private:
- std::mutex mMutex; // for asBinder
+ private:
+ std::mutex mMutex; // for asBinder
ScopedAIBinder_Weak mWeakBinder;
};
@@ -138,7 +136,7 @@
*/
template <typename INTERFACE>
class BpCInterface : public INTERFACE {
-public:
+ public:
BpCInterface(const SpAIBinder& binder) : mBinder(binder) {}
virtual ~BpCInterface() {}
@@ -146,7 +144,7 @@
bool isRemote() override { return AIBinder_isRemote(mBinder.get()); }
-private:
+ private:
SpAIBinder mBinder;
};
@@ -171,8 +169,6 @@
return mBinder;
}
-} // namespace ndk
-
-#endif // __cplusplus
+} // namespace ndk
/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index a303f4a..b021c23 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -47,45 +47,81 @@
/**
* Cleans up a parcel.
+ *
+ * \param parcel A parcel returned by AIBinder_prepareTransaction or AIBinder_transact when a
+ * transaction is being aborted.
*/
void AParcel_delete(AParcel* parcel) __INTRODUCED_IN(29);
/**
* This is called to allocate a buffer for a C-style string (null-terminated). The returned buffer
- * should be at least length bytes. This includes space for a null terminator. length will always be
- * strictly less than or equal to the maximum size that can be held in a size_t and will always be
- * greater than 0.
+ * should be at least length bytes. This includes space for a null terminator. For a string, length
+ * will always be strictly less than or equal to the maximum size that can be held in a size_t and
+ * will always be greater than 0. However, if a 'null' string is being read, length will be -1.
*
* See also AParcel_readString.
*
* If allocation fails, null should be returned.
+ *
+ * \param stringData some external representation of a string
+ * \param length the length of the buffer needed to fill (including the null-terminator)
+ * \param buffer a buffer of size 'length' or null if allocation failed.
+ *
+ * \return true if the allocation succeeded, false otherwise. If length is -1, a true return here
+ * means that a 'null' value (or equivalent) was successfully stored.
*/
-typedef char* (*AParcel_stringAllocator)(void* stringData, size_t length);
+typedef bool (*AParcel_stringAllocator)(void* stringData, int32_t length, char** buffer);
/**
- * This is called to allocate an array of size 'length'.
+ * This is called to allocate an array of size 'length'. If length is -1, then a 'null' array (or
+ * equivalent) should be created.
*
* See also AParcel_readStringArray
+ *
+ * \param arrayData some external representation of an array
+ * \param length the length to allocate this array to
+ *
+ * \return true if allocation succeeded. If length is -1, a true return here means that a 'null'
+ * value (or equivalent) was successfully stored.
*/
-typedef bool (*AParcel_stringArrayAllocator)(void* arrayData, size_t length);
+typedef bool (*AParcel_stringArrayAllocator)(void* arrayData, int32_t length);
/**
* This is called to allocate a string inside of an array that was allocated by an
* AParcel_stringArrayAllocator.
*
* The index returned will always be within the range [0, length of arrayData). The returned buffer
- * should be at least length bytes. This includes space for a null-terminator. length will always be
- * strictly less than or equal to the maximum size that can be held in a size_t and will always be
- * greater than 0.
+ * should be at least length bytes. This includes space for a null-terminator. For a string, length
+ * will always be strictly less than or equal to the maximum size that can be held in a size_t and
+ * will always be greater than 0. However, if a 'null' string is being read, length will be -1.
*
* See also AParcel_readStringArray
+ *
+ * \param arrayData some external representation of an array.
+ * \param index the index at which a string should be allocated.
+ * \param length the length of the string to be allocated at this index. See also
+ * AParcel_stringAllocator. This includes the length required for a null-terminator.
+ * \param buffer a buffer of size 'length' or null if allocation failed.
+ *
+ * \return true if the allocation succeeded, false otherwise. If length is -1, a true return here
+ * means that a 'null' value (or equivalent) was successfully stored.
*/
-typedef char* (*AParcel_stringArrayElementAllocator)(void* arrayData, size_t index, size_t length);
+typedef bool (*AParcel_stringArrayElementAllocator)(void* arrayData, size_t index, int32_t length,
+ char** buffer);
/**
* This returns the length and buffer of an array at a specific index in an arrayData object.
*
* See also AParcel_writeStringArray
+ *
+ * \param arrayData some external representation of an array.
+ * \param index the index at which a string should be allocated.
+ * \param outLength an out parameter for the length of the string at the specified index. This
+ * should not include the length for a null-terminator if there is one. If the object at this index
+ * is 'null', then this should be set to -1.
+ *
+ * \param a buffer of size outLength or more representing the string at the provided index. This is
+ * not required to be null-terminated. If the object at index is null, then this should be null.
*/
typedef const char* (*AParcel_stringArrayElementGetter)(const void* arrayData, size_t index,
size_t* outLength);
@@ -96,79 +132,137 @@
*
* The implementation of this function should allocate a contiguous array of size 'length' and
* return that underlying buffer to be filled out. If there is an error or length is 0, null may be
- * returned.
+ * returned. If length is -1, this should allocate some representation of a null array.
*
* See also AParcel_readInt32Array
+ *
+ * \param arrayData some external representation of an array of int32_t.
+ * \param length the length to allocate arrayData to.
+ * \param outBuffer a buffer of int32_t of size 'length' (if length is >= 0, if length is 0, this
+ * may be nullptr).
+ *
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
*/
-typedef int32_t* (*AParcel_int32ArrayAllocator)(void* arrayData, size_t length);
+typedef bool (*AParcel_int32ArrayAllocator)(void* arrayData, int32_t length, int32_t** outBuffer);
/**
* This is called to get the underlying data from an arrayData object.
*
* The implementation of this function should allocate a contiguous array of size 'length' and
* return that underlying buffer to be filled out. If there is an error or length is 0, null may be
- * returned.
+ * returned. If length is -1, this should allocate some representation of a null array.
*
* See also AParcel_readUint32Array
+ *
+ * \param arrayData some external representation of an array of uint32_t.
+ * \param length the length to allocate arrayData to.
+ * \param outBuffer a buffer of uint32_t of size 'length' (if length is >= 0, if length is 0, this
+ * may be nullptr).
+ *
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
*/
-typedef uint32_t* (*AParcel_uint32ArrayAllocator)(void* arrayData, size_t length);
+typedef bool (*AParcel_uint32ArrayAllocator)(void* arrayData, int32_t length, uint32_t** outBuffer);
/**
* This is called to get the underlying data from an arrayData object.
*
* The implementation of this function should allocate a contiguous array of size 'length' and
* return that underlying buffer to be filled out. If there is an error or length is 0, null may be
- * returned.
+ * returned. If length is -1, this should allocate some representation of a null array.
*
* See also AParcel_readInt64Array
+ *
+ * \param arrayData some external representation of an array of int64_t.
+ * \param length the length to allocate arrayData to.
+ * \param outBuffer a buffer of int64_t of size 'length' (if length is >= 0, if length is 0, this
+ * may be nullptr).
+ *
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
*/
-typedef int64_t* (*AParcel_int64ArrayAllocator)(void* arrayData, size_t length);
+typedef bool (*AParcel_int64ArrayAllocator)(void* arrayData, int32_t length, int64_t** outBuffer);
/**
* This is called to get the underlying data from an arrayData object.
*
* The implementation of this function should allocate a contiguous array of size 'length' and
* return that underlying buffer to be filled out. If there is an error or length is 0, null may be
- * returned.
+ * returned. If length is -1, this should allocate some representation of a null array.
*
* See also AParcel_readUint64Array
+ *
+ * \param arrayData some external representation of an array of uint64_t.
+ * \param length the length to allocate arrayData to.
+ * \param outBuffer a buffer of uint64_t of size 'length' (if length is >= 0, if length is 0, this
+ * may be nullptr).
+ *
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
*/
-typedef uint64_t* (*AParcel_uint64ArrayAllocator)(void* arrayData, size_t length);
+typedef bool (*AParcel_uint64ArrayAllocator)(void* arrayData, int32_t length, uint64_t** outBuffer);
/**
* This is called to get the underlying data from an arrayData object.
*
* The implementation of this function should allocate a contiguous array of size 'length' and
* return that underlying buffer to be filled out. If there is an error or length is 0, null may be
- * returned.
+ * returned. If length is -1, this should allocate some representation of a null array.
*
* See also AParcel_readFloatArray
+ *
+ * \param arrayData some external representation of an array of float.
+ * \param length the length to allocate arrayData to.
+ * \param outBuffer a buffer of float of size 'length' (if length is >= 0, if length is 0, this may
+ * be nullptr).
+ *
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
*/
-typedef float* (*AParcel_floatArrayAllocator)(void* arrayData, size_t length);
+typedef bool (*AParcel_floatArrayAllocator)(void* arrayData, int32_t length, float** outBuffer);
/**
* This is called to get the underlying data from an arrayData object.
*
* The implementation of this function should allocate a contiguous array of size 'length' and
* return that underlying buffer to be filled out. If there is an error or length is 0, null may be
- * returned.
+ * returned. If length is -1, this should allocate some representation of a null array.
*
* See also AParcel_readDoubleArray
+ *
+ * \param arrayData some external representation of an array of double.
+ * \param length the length to allocate arrayData to.
+ * \param outBuffer a buffer of double of size 'length' (if length is >= 0, if length is 0, this may
+ * be nullptr).
+ *
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
*/
-typedef double* (*AParcel_doubleArrayAllocator)(void* arrayData, size_t length);
+typedef bool (*AParcel_doubleArrayAllocator)(void* arrayData, int32_t length, double** outBuffer);
/**
* This allocates an array of size 'length' inside of arrayData and returns whether or not there was
- * a success.
+ * a success. If length is -1, then this should allocate some representation of a null array.
*
* See also AParcel_readBoolArray
+ *
+ * \param arrayData some external representation of an array of bool.
+ * \param length the length to allocate arrayData to (or -1 if this represents a null array).
+ *
+ * \return whether the allocation succeeded.
*/
-typedef bool (*AParcel_boolArrayAllocator)(void* arrayData, size_t length);
+typedef bool (*AParcel_boolArrayAllocator)(void* arrayData, int32_t length);
/**
* This is called to get the underlying data from an arrayData object at index.
*
* See also AParcel_writeBoolArray
+ *
+ * \param arrayData some external representation of an array of bool.
+ * \param index the index of the value to be retrieved.
+ *
+ * \return the value of the array at index index.
*/
typedef bool (*AParcel_boolArrayGetter)(const void* arrayData, size_t index);
@@ -176,6 +270,10 @@
* This is called to set an underlying value in an arrayData object at index.
*
* See also AParcel_readBoolArray
+ *
+ * \param arrayData some external representation of an array of bool.
+ * \param index the index of the value to be set.
+ * \param value the value to set at index index.
*/
typedef void (*AParcel_boolArraySetter)(void* arrayData, size_t index, bool value);
@@ -184,49 +282,74 @@
*
* The implementation of this function should allocate a contiguous array of size 'length' and
* return that underlying buffer to be filled out. If there is an error or length is 0, null may be
- * returned.
+ * returned. If length is -1, this should allocate some representation of a null array.
*
* See also AParcel_readCharArray
+ *
+ * \param arrayData some external representation of an array of char16_t.
+ * \param length the length to allocate arrayData to.
+ * \param outBuffer a buffer of char16_t of size 'length' (if length is >= 0, if length is 0, this
+ * may be nullptr).
+ *
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
*/
-typedef char16_t* (*AParcel_charArrayAllocator)(void* arrayData, size_t length);
+typedef bool (*AParcel_charArrayAllocator)(void* arrayData, int32_t length, char16_t** outBuffer);
/**
* This is called to get the underlying data from an arrayData object.
*
* The implementation of this function should allocate a contiguous array of size 'length' and
* return that underlying buffer to be filled out. If there is an error or length is 0, null may be
- * returned.
+ * returned. If length is -1, this should allocate some representation of a null array.
*
* See also AParcel_readByteArray
+ *
+ * \param arrayData some external representation of an array of int8_t.
+ * \param length the length to allocate arrayData to.
+ * \param outBuffer a buffer of int8_t of size 'length' (if length is >= 0, if length is 0, this may
+ * be nullptr).
+ *
+ * \return whether or not the allocation was successful (or whether a null array is represented when
+ * length is -1).
*/
-typedef int8_t* (*AParcel_byteArrayAllocator)(void* arrayData, size_t length);
+typedef bool (*AParcel_byteArrayAllocator)(void* arrayData, int32_t length, int8_t** outBuffer);
// @END-PRIMITIVE-VECTOR-GETTERS
/**
- * Writes an AIBinder to the next location in a non-null parcel. Can be null.
+ * Writes an AIBinder to the next location in a non-null parcel. Can be null. This does not take any
+ * refcounts of ownership of the binder from the client.
+ *
+ * \param parcel the parcel to write to.
+ * \param binder the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder) __INTRODUCED_IN(29);
/**
- * Reads an AIBinder from the next location in a non-null parcel. This will fail if the binder is
- * non-null. One strong ref-count of ownership is passed to the caller of this function.
+ * Reads an AIBinder from the next location in a non-null parcel. One strong ref-count of ownership
+ * is passed to the caller of this function.
+ *
+ * \param parcel the parcel to read from.
+ * \param binder the out parameter for what is read from the parcel. This may be null.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_readStrongBinder(const AParcel* parcel, AIBinder** binder)
__INTRODUCED_IN(29);
/**
- * Reads an AIBinder from the next location in a non-null parcel. This may read a null. One strong
- * ref-count of ownership is passed to the caller of this function.
- */
-binder_status_t AParcel_readNullableStrongBinder(const AParcel* parcel, AIBinder** binder)
- __INTRODUCED_IN(29);
-
-/**
* Writes a file descriptor to the next location in a non-null parcel. This does not take ownership
* of fd.
*
* This corresponds to the SDK's android.os.ParcelFileDescriptor.
+ *
+ * \param parcel the parcel to write to.
+ * \param fd the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_writeParcelFileDescriptor(AParcel* parcel, int fd);
@@ -236,6 +359,11 @@
* The returned fd must be closed.
*
* This corresponds to the SDK's android.os.ParcelFileDescriptor.
+ *
+ * \param parcel the parcel to read from.
+ * \param binder the out parameter for what is read from the parcel.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_readParcelFileDescriptor(const AParcel* parcel, int* fd);
@@ -247,6 +375,11 @@
* status will be returned from this method and nothing will be written to the parcel. If either
* this happens or if writing the status object itself fails, the return value from this function
* should be propagated to the client, and AParcel_readStatusHeader shouldn't be called.
+ *
+ * \param parcel the parcel to write to.
+ * \param status the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_writeStatusHeader(AParcel* parcel, const AStatus* status)
__INTRODUCED_IN(29);
@@ -254,14 +387,27 @@
/**
* Reads an AStatus from the next location in a non-null parcel. Ownership is passed to the caller
* of this function.
+ *
+ * \param parcel the parcel to read from.
+ * \param status the out parameter for what is read from the parcel.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_readStatusHeader(const AParcel* parcel, AStatus** status)
__INTRODUCED_IN(29);
/**
* Writes utf-8 string value to the next location in a non-null parcel.
+ *
+ * If length is -1, and string is nullptr, this will write a 'null' string to the parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param string the null-terminated string to write to the parcel, at least of size 'length'.
+ * \param length the length of the string to be written.
+ *
+ * \return STATUS_OK on successful write.
*/
-binder_status_t AParcel_writeString(AParcel* parcel, const char* string, size_t length)
+binder_status_t AParcel_writeString(AParcel* parcel, const char* string, int32_t length)
__INTRODUCED_IN(29);
/**
@@ -269,7 +415,14 @@
*
* Data is passed to the string allocator once the string size is known. This size includes the
* space for the null-terminator of this string. This allocator returns a buffer which is used as
- * the output buffer from this read.
+ * the output buffer from this read. If there is a 'null' string on the binder buffer, the allocator
+ * will be called with length -1.
+ *
+ * \param parcel the parcel to read from.
+ * \param stringData some external representation of a string.
+ * \param allocator allocator that will be called once the size of the string is known.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_readString(const AParcel* parcel, void* stringData,
AParcel_stringAllocator allocator) __INTRODUCED_IN(29);
@@ -279,9 +432,18 @@
*
* length is the length of the array. AParcel_stringArrayElementGetter will be called for all
* indices in range [0, length) with the arrayData provided here. The string length and buffer
- * returned from this function will be used to fill out the data from the parcel.
+ * returned from this function will be used to fill out the data from the parcel. If length is -1,
+ * this will write a 'null' string array to the binder buffer.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData some external representation of an array.
+ * \param length the length of the array to be written.
+ * \param getter the callback that will be called for every index of the array to retrieve the
+ * corresponding string buffer.
+ *
+ * \return STATUS_OK on successful write.
*/
-binder_status_t AParcel_writeStringArray(AParcel* parcel, const void* arrayData, size_t length,
+binder_status_t AParcel_writeStringArray(AParcel* parcel, const void* arrayData, int32_t length,
AParcel_stringArrayElementGetter getter)
__INTRODUCED_IN(29);
@@ -292,7 +454,17 @@
* length is the length of the array to be read from the parcel. Then, for each index i in [0,
* length), AParcel_stringArrayElementAllocator will be called with the length of the string to be
* read from the parcel. The resultant buffer from each of these calls will be filled according to
- * the contents of the string that is read.
+ * the contents of the string that is read. If the string array being read is 'null', this will
+ * instead just pass -1 to AParcel_stringArrayAllocator.
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called with arrayData once the size of the output
+ * array is known.
+ * \param elementAllocator the callback that will be called on every index of arrayData to allocate
+ * the string at that location.
+ *
+ * \return STATUS_OK on successful read.
*/
binder_status_t AParcel_readStringArray(const AParcel* parcel, void* arrayData,
AParcel_stringArrayAllocator allocator,
@@ -302,128 +474,254 @@
// @START-PRIMITIVE-READ-WRITE
/**
* Writes int32_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_writeInt32(AParcel* parcel, int32_t value) __INTRODUCED_IN(29);
/**
* Writes uint32_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_writeUint32(AParcel* parcel, uint32_t value) __INTRODUCED_IN(29);
/**
* Writes int64_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_writeInt64(AParcel* parcel, int64_t value) __INTRODUCED_IN(29);
/**
* Writes uint64_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_writeUint64(AParcel* parcel, uint64_t value) __INTRODUCED_IN(29);
/**
* Writes float value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_writeFloat(AParcel* parcel, float value) __INTRODUCED_IN(29);
/**
* Writes double value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_writeDouble(AParcel* parcel, double value) __INTRODUCED_IN(29);
/**
* Writes bool value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_writeBool(AParcel* parcel, bool value) __INTRODUCED_IN(29);
/**
* Writes char16_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_writeChar(AParcel* parcel, char16_t value) __INTRODUCED_IN(29);
/**
* Writes int8_t value to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param value the value to write to the parcel.
+ *
+ * \return STATUS_OK on successful write.
*/
binder_status_t AParcel_writeByte(AParcel* parcel, int8_t value) __INTRODUCED_IN(29);
/**
* Reads into int32_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
*/
binder_status_t AParcel_readInt32(const AParcel* parcel, int32_t* value) __INTRODUCED_IN(29);
/**
* Reads into uint32_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
*/
binder_status_t AParcel_readUint32(const AParcel* parcel, uint32_t* value) __INTRODUCED_IN(29);
/**
* Reads into int64_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
*/
binder_status_t AParcel_readInt64(const AParcel* parcel, int64_t* value) __INTRODUCED_IN(29);
/**
* Reads into uint64_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
*/
binder_status_t AParcel_readUint64(const AParcel* parcel, uint64_t* value) __INTRODUCED_IN(29);
/**
* Reads into float value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
*/
binder_status_t AParcel_readFloat(const AParcel* parcel, float* value) __INTRODUCED_IN(29);
/**
* Reads into double value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
*/
binder_status_t AParcel_readDouble(const AParcel* parcel, double* value) __INTRODUCED_IN(29);
/**
* Reads into bool value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
*/
binder_status_t AParcel_readBool(const AParcel* parcel, bool* value) __INTRODUCED_IN(29);
/**
* Reads into char16_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
*/
binder_status_t AParcel_readChar(const AParcel* parcel, char16_t* value) __INTRODUCED_IN(29);
/**
* Reads into int8_t value from the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to read from.
+ * \param value the value to read from the parcel.
+ *
+ * \return STATUS_OK on successful read.
*/
binder_status_t AParcel_readByte(const AParcel* parcel, int8_t* value) __INTRODUCED_IN(29);
/**
* Writes an array of int32_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
+ * \param length the length of arrayData or -1 if this represents a null array.
+ *
+ * \return STATUS_OK on successful write.
*/
-binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* value, size_t length)
+binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* arrayData, int32_t length)
__INTRODUCED_IN(29);
/**
* Writes an array of uint32_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
+ * \param length the length of arrayData or -1 if this represents a null array.
+ *
+ * \return STATUS_OK on successful write.
*/
-binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* value, size_t length)
+binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* arrayData, int32_t length)
__INTRODUCED_IN(29);
/**
* Writes an array of int64_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
+ * \param length the length of arrayData or -1 if this represents a null array.
+ *
+ * \return STATUS_OK on successful write.
*/
-binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* value, size_t length)
+binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* arrayData, int32_t length)
__INTRODUCED_IN(29);
/**
* Writes an array of uint64_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
+ * \param length the length of arrayData or -1 if this represents a null array.
+ *
+ * \return STATUS_OK on successful write.
*/
-binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* value, size_t length)
+binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* arrayData, int32_t length)
__INTRODUCED_IN(29);
/**
* Writes an array of float to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
+ * \param length the length of arrayData or -1 if this represents a null array.
+ *
+ * \return STATUS_OK on successful write.
*/
-binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* value, size_t length)
+binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* arrayData, int32_t length)
__INTRODUCED_IN(29);
/**
* Writes an array of double to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
+ * \param length the length of arrayData or -1 if this represents a null array.
+ *
+ * \return STATUS_OK on successful write.
*/
-binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* value, size_t length)
+binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* arrayData, int32_t length)
__INTRODUCED_IN(29);
/**
@@ -431,20 +729,39 @@
*
* getter(arrayData, i) will be called for each i in [0, length) in order to get the underlying
* values to write to the parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData some external representation of an array.
+ * \param length the length of arrayData (or -1 if this represents a null array).
+ * \param getter the callback to retrieve data at specific locations in the array.
+ *
+ * \return STATUS_OK on successful write.
*/
-binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData, size_t length,
+binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData, int32_t length,
AParcel_boolArrayGetter getter) __INTRODUCED_IN(29);
/**
* Writes an array of char16_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
+ * \param length the length of arrayData or -1 if this represents a null array.
+ *
+ * \return STATUS_OK on successful write.
*/
-binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* value, size_t length)
+binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* arrayData, int32_t length)
__INTRODUCED_IN(29);
/**
* Writes an array of int8_t to the next location in a non-null parcel.
+ *
+ * \param parcel the parcel to write to.
+ * \param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).
+ * \param length the length of arrayData or -1 if this represents a null array.
+ *
+ * \return STATUS_OK on successful write.
*/
-binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* value, size_t length)
+binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* arrayData, int32_t length)
__INTRODUCED_IN(29);
/**
@@ -453,6 +770,12 @@
* First, allocator will be called with the length of the array. If the allocation succeeds and the
* length is greater than zero, the buffer returned by the allocator will be filled with the
* corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
*/
binder_status_t AParcel_readInt32Array(const AParcel* parcel, void* arrayData,
AParcel_int32ArrayAllocator allocator) __INTRODUCED_IN(29);
@@ -463,6 +786,12 @@
* First, allocator will be called with the length of the array. If the allocation succeeds and the
* length is greater than zero, the buffer returned by the allocator will be filled with the
* corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
*/
binder_status_t AParcel_readUint32Array(const AParcel* parcel, void* arrayData,
AParcel_uint32ArrayAllocator allocator) __INTRODUCED_IN(29);
@@ -473,6 +802,12 @@
* First, allocator will be called with the length of the array. If the allocation succeeds and the
* length is greater than zero, the buffer returned by the allocator will be filled with the
* corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
*/
binder_status_t AParcel_readInt64Array(const AParcel* parcel, void* arrayData,
AParcel_int64ArrayAllocator allocator) __INTRODUCED_IN(29);
@@ -483,6 +818,12 @@
* First, allocator will be called with the length of the array. If the allocation succeeds and the
* length is greater than zero, the buffer returned by the allocator will be filled with the
* corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
*/
binder_status_t AParcel_readUint64Array(const AParcel* parcel, void* arrayData,
AParcel_uint64ArrayAllocator allocator) __INTRODUCED_IN(29);
@@ -493,6 +834,12 @@
* First, allocator will be called with the length of the array. If the allocation succeeds and the
* length is greater than zero, the buffer returned by the allocator will be filled with the
* corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
*/
binder_status_t AParcel_readFloatArray(const AParcel* parcel, void* arrayData,
AParcel_floatArrayAllocator allocator) __INTRODUCED_IN(29);
@@ -503,6 +850,12 @@
* First, allocator will be called with the length of the array. If the allocation succeeds and the
* length is greater than zero, the buffer returned by the allocator will be filled with the
* corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
*/
binder_status_t AParcel_readDoubleArray(const AParcel* parcel, void* arrayData,
AParcel_doubleArrayAllocator allocator) __INTRODUCED_IN(29);
@@ -512,6 +865,14 @@
*
* First, allocator will be called with the length of the array. Then, for every i in [0, length),
* setter(arrayData, i, x) will be called where x is the value at the associated index.
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ * \param setter the callback that will be called to set a value at a specific location in the
+ * array.
+ *
+ * \return STATUS_OK on successful read.
*/
binder_status_t AParcel_readBoolArray(const AParcel* parcel, void* arrayData,
AParcel_boolArrayAllocator allocator,
@@ -523,6 +884,12 @@
* First, allocator will be called with the length of the array. If the allocation succeeds and the
* length is greater than zero, the buffer returned by the allocator will be filled with the
* corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
*/
binder_status_t AParcel_readCharArray(const AParcel* parcel, void* arrayData,
AParcel_charArrayAllocator allocator) __INTRODUCED_IN(29);
@@ -533,13 +900,19 @@
* First, allocator will be called with the length of the array. If the allocation succeeds and the
* length is greater than zero, the buffer returned by the allocator will be filled with the
* corresponding data
+ *
+ * \param parcel the parcel to read from.
+ * \param arrayData some external representation of an array.
+ * \param allocator the callback that will be called to allocate the array.
+ *
+ * \return STATUS_OK on successful read.
*/
binder_status_t AParcel_readByteArray(const AParcel* parcel, void* arrayData,
AParcel_byteArrayAllocator allocator) __INTRODUCED_IN(29);
// @END-PRIMITIVE-READ-WRITE
-#endif //__ANDROID_API__ >= __ANDROID_API_Q__
+#endif //__ANDROID_API__ >= __ANDROID_API_Q__
__END_DECLS
/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
index 3fcb121..a478ee0 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel_utils.h
@@ -28,8 +28,7 @@
#include <android/binder_parcel.h>
-#ifdef __cplusplus
-
+#include <optional>
#include <string>
#include <vector>
@@ -39,12 +38,37 @@
* This retrieves and allocates a vector to size 'length' and returns the underlying buffer.
*/
template <typename T>
-static inline T* AParcel_stdVectorAllocator(void* vectorData, size_t length) {
+static inline bool AParcel_stdVectorAllocator(void* vectorData, int32_t length, T** outBuffer) {
+ if (length < 0) return false;
+
std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
- if (length > vec->max_size()) return nullptr;
+ if (length > vec->max_size()) return false;
vec->resize(length);
- return vec->data();
+ *outBuffer = vec->data();
+ return true;
+}
+
+/**
+ * This retrieves and allocates a vector to size 'length' and returns the underlying buffer.
+ */
+template <typename T>
+static inline bool AParcel_nullableStdVectorAllocator(void* vectorData, int32_t length,
+ T** outBuffer) {
+ std::optional<std::vector<T>>* vec = static_cast<std::optional<std::vector<T>>*>(vectorData);
+
+ if (length < 0) {
+ *vec = std::nullopt;
+ return true;
+ }
+
+ *vec = std::optional<std::vector<T>>(std::vector<T>{});
+
+ if (length > (*vec)->max_size()) return false;
+ (*vec)->resize(length);
+
+ *outBuffer = (*vec)->data();
+ return true;
}
/**
@@ -52,13 +76,16 @@
*
* See also AParcel_stdVectorAllocator. Types used with this allocator have their sizes defined
* externally with respect to the NDK, and that size information is not passed into the NDK.
- * Instead, it is used in cases where callbacks are used.
+ * Instead, it is used in cases where callbacks are used. Note that when this allocator is used,
+ * null arrays are not supported.
*
* See AParcel_readVector(const AParcel* parcel, std::vector<bool>)
* See AParcel_readVector(const AParcel* parcel, std::vector<std::string>)
*/
template <typename T>
-static inline bool AParcel_stdVectorExternalAllocator(void* vectorData, size_t length) {
+static inline bool AParcel_stdVectorExternalAllocator(void* vectorData, int32_t length) {
+ if (length < 0) return false;
+
std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
if (length > vec->max_size()) return false;
@@ -67,6 +94,34 @@
}
/**
+ * This allocates a vector to size 'length' and returns whether the allocation is successful.
+ *
+ * See also AParcel_stdVectorAllocator. Types used with this allocator have their sizes defined
+ * externally with respect to the NDK, and that size information is not passed into the NDK.
+ * Instead, it is used in cases where callbacks are used. Note, when this allocator is used,
+ * the vector itself can be nullable.
+ *
+ * See AParcel_readVector(const AParcel* parcel,
+ * std::optional<std::vector<std::optional<std::string>>>)
+ */
+template <typename T>
+static inline bool AParcel_nullableStdVectorExternalAllocator(void* vectorData, int32_t length) {
+ std::optional<std::vector<T>>* vec = static_cast<std::optional<std::vector<T>>*>(vectorData);
+
+ if (length < 0) {
+ *vec = std::nullopt;
+ return true;
+ }
+
+ *vec = std::optional<std::vector<T>>(std::vector<T>{});
+
+ if (length > (*vec)->max_size()) return false;
+ (*vec)->resize(length);
+
+ return true;
+}
+
+/**
* This retrieves the underlying value in a vector which may not be contiguous at index from a
* corresponding vectorData.
*/
@@ -86,166 +141,81 @@
(*vec)[index] = value;
}
-// @START
/**
- * Writes a vector of int32_t to the next location in a non-null parcel.
+ * This sets the underlying value in a corresponding vectorData which may not be contiguous at
+ * index.
*/
-inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int32_t>& vec) {
- return AParcel_writeInt32Array(parcel, vec.data(), vec.size());
+template <typename T>
+static inline void AParcel_nullableStdVectorSetter(void* vectorData, size_t index, T value) {
+ std::optional<std::vector<T>>* vec = static_cast<std::optional<std::vector<T>>*>(vectorData);
+ vec->value()[index] = value;
}
/**
- * Reads a vector of int32_t from the next location in a non-null parcel.
+ * Convenience method to write a strong binder but return an error if it is null.
*/
-inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int32_t>* vec) {
- void* vectorData = static_cast<void*>(vec);
- return AParcel_readInt32Array(parcel, vectorData, AParcel_stdVectorAllocator<int32_t>);
+static inline binder_status_t AParcel_writeRequiredStrongBinder(AParcel* parcel, AIBinder* binder) {
+ if (binder == nullptr) {
+ return STATUS_UNEXPECTED_NULL;
+ }
+ return AParcel_writeStrongBinder(parcel, binder);
}
/**
- * Writes a vector of uint32_t to the next location in a non-null parcel.
+ * Convenience method to read a strong binder but return an error if it is null.
*/
-inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint32_t>& vec) {
- return AParcel_writeUint32Array(parcel, vec.data(), vec.size());
+static inline binder_status_t AParcel_readRequiredStrongBinder(const AParcel* parcel,
+ AIBinder** binder) {
+ binder_status_t ret = AParcel_readStrongBinder(parcel, binder);
+ if (ret == STATUS_OK && *binder == nullptr) {
+ return STATUS_UNEXPECTED_NULL;
+ }
+ return ret;
}
/**
- * Reads a vector of uint32_t from the next location in a non-null parcel.
- */
-inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<uint32_t>* vec) {
- void* vectorData = static_cast<void*>(vec);
- return AParcel_readUint32Array(parcel, vectorData, AParcel_stdVectorAllocator<uint32_t>);
-}
-
-/**
- * Writes a vector of int64_t to the next location in a non-null parcel.
- */
-inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int64_t>& vec) {
- return AParcel_writeInt64Array(parcel, vec.data(), vec.size());
-}
-
-/**
- * Reads a vector of int64_t from the next location in a non-null parcel.
- */
-inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int64_t>* vec) {
- void* vectorData = static_cast<void*>(vec);
- return AParcel_readInt64Array(parcel, vectorData, AParcel_stdVectorAllocator<int64_t>);
-}
-
-/**
- * Writes a vector of uint64_t to the next location in a non-null parcel.
- */
-inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint64_t>& vec) {
- return AParcel_writeUint64Array(parcel, vec.data(), vec.size());
-}
-
-/**
- * Reads a vector of uint64_t from the next location in a non-null parcel.
- */
-inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<uint64_t>* vec) {
- void* vectorData = static_cast<void*>(vec);
- return AParcel_readUint64Array(parcel, vectorData, AParcel_stdVectorAllocator<uint64_t>);
-}
-
-/**
- * Writes a vector of float to the next location in a non-null parcel.
- */
-inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<float>& vec) {
- return AParcel_writeFloatArray(parcel, vec.data(), vec.size());
-}
-
-/**
- * Reads a vector of float from the next location in a non-null parcel.
- */
-inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<float>* vec) {
- void* vectorData = static_cast<void*>(vec);
- return AParcel_readFloatArray(parcel, vectorData, AParcel_stdVectorAllocator<float>);
-}
-
-/**
- * Writes a vector of double to the next location in a non-null parcel.
- */
-inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<double>& vec) {
- return AParcel_writeDoubleArray(parcel, vec.data(), vec.size());
-}
-
-/**
- * Reads a vector of double from the next location in a non-null parcel.
- */
-inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<double>* vec) {
- void* vectorData = static_cast<void*>(vec);
- return AParcel_readDoubleArray(parcel, vectorData, AParcel_stdVectorAllocator<double>);
-}
-
-/**
- * Writes a vector of bool to the next location in a non-null parcel.
- */
-inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<bool>& vec) {
- return AParcel_writeBoolArray(parcel, static_cast<const void*>(&vec), vec.size(),
- AParcel_stdVectorGetter<bool>);
-}
-
-/**
- * Reads a vector of bool from the next location in a non-null parcel.
- */
-inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<bool>* vec) {
- void* vectorData = static_cast<void*>(vec);
- return AParcel_readBoolArray(parcel, vectorData, AParcel_stdVectorExternalAllocator<bool>,
- AParcel_stdVectorSetter<bool>);
-}
-
-/**
- * Writes a vector of char16_t to the next location in a non-null parcel.
- */
-inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<char16_t>& vec) {
- return AParcel_writeCharArray(parcel, vec.data(), vec.size());
-}
-
-/**
- * Reads a vector of char16_t from the next location in a non-null parcel.
- */
-inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<char16_t>* vec) {
- void* vectorData = static_cast<void*>(vec);
- return AParcel_readCharArray(parcel, vectorData, AParcel_stdVectorAllocator<char16_t>);
-}
-
-/**
- * Writes a vector of int8_t to the next location in a non-null parcel.
- */
-inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int8_t>& vec) {
- return AParcel_writeByteArray(parcel, vec.data(), vec.size());
-}
-
-/**
- * Reads a vector of int8_t from the next location in a non-null parcel.
- */
-inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int8_t>* vec) {
- void* vectorData = static_cast<void*>(vec);
- return AParcel_readByteArray(parcel, vectorData, AParcel_stdVectorAllocator<int8_t>);
-}
-
-// @END
-
-/**
* Allocates a std::string to length and returns the underlying buffer. For use with
* AParcel_readString. See use below in AParcel_readString(const AParcel*, std::string*).
*/
-static inline char* AParcel_stdStringAllocator(void* stringData, size_t length) {
+static inline bool AParcel_stdStringAllocator(void* stringData, int32_t length, char** buffer) {
+ if (length <= 0) return false;
+
std::string* str = static_cast<std::string*>(stringData);
str->resize(length - 1);
- return &(*str)[0];
+ *buffer = &(*str)[0];
+ return true;
}
/**
- * Allocates a std::string inside of a std::vector<std::string> at index index to size 'length'.
+ * Allocates a string in a std::optional<std::string> to size 'length' (or to std::nullopt when
+ * length is -1) and returns the underlying buffer. For use with AParcel_readString. See use below
+ * in AParcel_readString(const AParcel*, std::optional<std::string>*).
*/
-static inline char* AParcel_stdVectorStringElementAllocator(void* vectorData, size_t index,
- size_t length) {
- std::vector<std::string>* vec = static_cast<std::vector<std::string>*>(vectorData);
+static inline bool AParcel_nullableStdStringAllocator(void* stringData, int32_t length,
+ char** buffer) {
+ if (length == 0) return false;
+ std::optional<std::string>* str = static_cast<std::optional<std::string>*>(stringData);
+
+ if (length < 0) {
+ *str = std::nullopt;
+ return true;
+ }
+
+ *str = std::optional<std::string>(std::string{});
+ (*str)->resize(length - 1);
+ *buffer = &(**str)[0];
+ return true;
+}
+
+/**
+ * Allocates a std::string inside of a std::vector<std::string> at index 'index' to size 'length'.
+ */
+static inline bool AParcel_stdVectorStringElementAllocator(void* vectorData, size_t index,
+ int32_t length, char** buffer) {
+ std::vector<std::string>* vec = static_cast<std::vector<std::string>*>(vectorData);
std::string& element = vec->at(index);
- element.resize(length - 1);
- return &element[0];
+ return AParcel_stdStringAllocator(static_cast<void*>(&element), length, buffer);
}
/**
@@ -255,7 +225,6 @@
static inline const char* AParcel_stdVectorStringElementGetter(const void* vectorData, size_t index,
size_t* outLength) {
const std::vector<std::string>* vec = static_cast<const std::vector<std::string>*>(vectorData);
-
const std::string& element = vec->at(index);
*outLength = element.size();
@@ -263,6 +232,40 @@
}
/**
+ * Allocates a string in a std::optional<std::string> inside of a
+ * std::optional<std::vector<std::optional<std::string>>> at index 'index' to size 'length' (or to
+ * std::nullopt when length is -1).
+ */
+static inline bool AParcel_nullableStdVectorStringElementAllocator(void* vectorData, size_t index,
+ int32_t length, char** buffer) {
+ std::optional<std::vector<std::optional<std::string>>>* vec =
+ static_cast<std::optional<std::vector<std::optional<std::string>>>*>(vectorData);
+ std::optional<std::string>& element = vec->value().at(index);
+ return AParcel_nullableStdStringAllocator(static_cast<void*>(&element), length, buffer);
+}
+
+/**
+ * This gets the length and buffer of a std::optional<std::string> inside of a
+ * std::vector<std::string> at index index. If the string is null, then it returns null and a length
+ * of -1.
+ */
+static inline const char* AParcel_nullableStdVectorStringElementGetter(const void* vectorData,
+ size_t index,
+ size_t* outLength) {
+ const std::optional<std::vector<std::optional<std::string>>>* vec =
+ static_cast<const std::optional<std::vector<std::optional<std::string>>>*>(vectorData);
+ const std::optional<std::string>& element = vec->value().at(index);
+
+ if (!element) {
+ *outLength = -1;
+ return nullptr;
+ }
+
+ *outLength = element->size();
+ return element->c_str();
+}
+
+/**
* Convenience API for writing a std::string.
*/
static inline binder_status_t AParcel_writeString(AParcel* parcel, const std::string& str) {
@@ -278,6 +281,27 @@
}
/**
+ * Convenience API for writing a std::optional<std::string>.
+ */
+static inline binder_status_t AParcel_writeString(AParcel* parcel,
+ const std::optional<std::string>& str) {
+ if (!str) {
+ return AParcel_writeString(parcel, nullptr, -1);
+ }
+
+ return AParcel_writeString(parcel, str->c_str(), str->size());
+}
+
+/**
+ * Convenience API for reading a std::optional<std::string>.
+ */
+static inline binder_status_t AParcel_readString(const AParcel* parcel,
+ std::optional<std::string>* str) {
+ void* stringData = static_cast<void*>(str);
+ return AParcel_readString(parcel, stringData, AParcel_nullableStdStringAllocator);
+}
+
+/**
* Convenience API for writing a std::vector<std::string>
*/
static inline binder_status_t AParcel_writeVector(AParcel* parcel,
@@ -298,6 +322,337 @@
AParcel_stdVectorStringElementAllocator);
}
+/**
+ * Convenience API for writing a std::optional<std::vector<std::optional<std::string>>>
+ */
+static inline binder_status_t AParcel_writeVector(
+ AParcel* parcel, const std::optional<std::vector<std::optional<std::string>>>& vec) {
+ const void* vectorData = static_cast<const void*>(&vec);
+ return AParcel_writeStringArray(parcel, vectorData, (vec ? vec->size() : -1),
+ AParcel_nullableStdVectorStringElementGetter);
+}
+
+/**
+ * Convenience API for reading a std::optional<std::vector<std::optional<std::string>>>
+ */
+static inline binder_status_t AParcel_readVector(
+ const AParcel* parcel, std::optional<std::vector<std::optional<std::string>>>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readStringArray(
+ parcel, vectorData,
+ AParcel_nullableStdVectorExternalAllocator<std::optional<std::string>>,
+ AParcel_nullableStdVectorStringElementAllocator);
+}
+
+// @START
+/**
+ * Writes a vector of int32_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int32_t>& vec) {
+ return AParcel_writeInt32Array(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Writes an optional vector of int32_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel,
+ const std::optional<std::vector<int32_t>>& vec) {
+ if (!vec) return AParcel_writeInt32Array(parcel, nullptr, -1);
+ return AParcel_writeVector(parcel, *vec);
+}
+
+/**
+ * Reads a vector of int32_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int32_t>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readInt32Array(parcel, vectorData, AParcel_stdVectorAllocator<int32_t>);
+}
+
+/**
+ * Reads an optional vector of int32_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel,
+ std::optional<std::vector<int32_t>>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readInt32Array(parcel, vectorData, AParcel_nullableStdVectorAllocator<int32_t>);
+}
+
+/**
+ * Writes a vector of uint32_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint32_t>& vec) {
+ return AParcel_writeUint32Array(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Writes an optional vector of uint32_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel,
+ const std::optional<std::vector<uint32_t>>& vec) {
+ if (!vec) return AParcel_writeUint32Array(parcel, nullptr, -1);
+ return AParcel_writeVector(parcel, *vec);
+}
+
+/**
+ * Reads a vector of uint32_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<uint32_t>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readUint32Array(parcel, vectorData, AParcel_stdVectorAllocator<uint32_t>);
+}
+
+/**
+ * Reads an optional vector of uint32_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel,
+ std::optional<std::vector<uint32_t>>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readUint32Array(parcel, vectorData,
+ AParcel_nullableStdVectorAllocator<uint32_t>);
+}
+
+/**
+ * Writes a vector of int64_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int64_t>& vec) {
+ return AParcel_writeInt64Array(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Writes an optional vector of int64_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel,
+ const std::optional<std::vector<int64_t>>& vec) {
+ if (!vec) return AParcel_writeInt64Array(parcel, nullptr, -1);
+ return AParcel_writeVector(parcel, *vec);
+}
+
+/**
+ * Reads a vector of int64_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int64_t>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readInt64Array(parcel, vectorData, AParcel_stdVectorAllocator<int64_t>);
+}
+
+/**
+ * Reads an optional vector of int64_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel,
+ std::optional<std::vector<int64_t>>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readInt64Array(parcel, vectorData, AParcel_nullableStdVectorAllocator<int64_t>);
+}
+
+/**
+ * Writes a vector of uint64_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint64_t>& vec) {
+ return AParcel_writeUint64Array(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Writes an optional vector of uint64_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel,
+ const std::optional<std::vector<uint64_t>>& vec) {
+ if (!vec) return AParcel_writeUint64Array(parcel, nullptr, -1);
+ return AParcel_writeVector(parcel, *vec);
+}
+
+/**
+ * Reads a vector of uint64_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<uint64_t>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readUint64Array(parcel, vectorData, AParcel_stdVectorAllocator<uint64_t>);
+}
+
+/**
+ * Reads an optional vector of uint64_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel,
+ std::optional<std::vector<uint64_t>>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readUint64Array(parcel, vectorData,
+ AParcel_nullableStdVectorAllocator<uint64_t>);
+}
+
+/**
+ * Writes a vector of float to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<float>& vec) {
+ return AParcel_writeFloatArray(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Writes an optional vector of float to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel,
+ const std::optional<std::vector<float>>& vec) {
+ if (!vec) return AParcel_writeFloatArray(parcel, nullptr, -1);
+ return AParcel_writeVector(parcel, *vec);
+}
+
+/**
+ * Reads a vector of float from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<float>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readFloatArray(parcel, vectorData, AParcel_stdVectorAllocator<float>);
+}
+
+/**
+ * Reads an optional vector of float from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel,
+ std::optional<std::vector<float>>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readFloatArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<float>);
+}
+
+/**
+ * Writes a vector of double to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<double>& vec) {
+ return AParcel_writeDoubleArray(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Writes an optional vector of double to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel,
+ const std::optional<std::vector<double>>& vec) {
+ if (!vec) return AParcel_writeDoubleArray(parcel, nullptr, -1);
+ return AParcel_writeVector(parcel, *vec);
+}
+
+/**
+ * Reads a vector of double from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<double>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readDoubleArray(parcel, vectorData, AParcel_stdVectorAllocator<double>);
+}
+
+/**
+ * Reads an optional vector of double from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel,
+ std::optional<std::vector<double>>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readDoubleArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<double>);
+}
+
+/**
+ * Writes a vector of bool to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<bool>& vec) {
+ return AParcel_writeBoolArray(parcel, static_cast<const void*>(&vec), vec.size(),
+ AParcel_stdVectorGetter<bool>);
+}
+
+/**
+ * Writes an optional vector of bool to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel,
+ const std::optional<std::vector<bool>>& vec) {
+ if (!vec) return AParcel_writeBoolArray(parcel, nullptr, -1, AParcel_stdVectorGetter<bool>);
+ return AParcel_writeVector(parcel, *vec);
+}
+
+/**
+ * Reads a vector of bool from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<bool>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readBoolArray(parcel, vectorData, AParcel_stdVectorExternalAllocator<bool>,
+ AParcel_stdVectorSetter<bool>);
+}
+
+/**
+ * Reads an optional vector of bool from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel,
+ std::optional<std::vector<bool>>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readBoolArray(parcel, vectorData,
+ AParcel_nullableStdVectorExternalAllocator<bool>,
+ AParcel_nullableStdVectorSetter<bool>);
+}
+
+/**
+ * Writes a vector of char16_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<char16_t>& vec) {
+ return AParcel_writeCharArray(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Writes an optional vector of char16_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel,
+ const std::optional<std::vector<char16_t>>& vec) {
+ if (!vec) return AParcel_writeCharArray(parcel, nullptr, -1);
+ return AParcel_writeVector(parcel, *vec);
+}
+
+/**
+ * Reads a vector of char16_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<char16_t>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readCharArray(parcel, vectorData, AParcel_stdVectorAllocator<char16_t>);
+}
+
+/**
+ * Reads an optional vector of char16_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel,
+ std::optional<std::vector<char16_t>>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readCharArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<char16_t>);
+}
+
+/**
+ * Writes a vector of int8_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int8_t>& vec) {
+ return AParcel_writeByteArray(parcel, vec.data(), vec.size());
+}
+
+/**
+ * Writes an optional vector of int8_t to the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_writeVector(AParcel* parcel,
+ const std::optional<std::vector<int8_t>>& vec) {
+ if (!vec) return AParcel_writeByteArray(parcel, nullptr, -1);
+ return AParcel_writeVector(parcel, *vec);
+}
+
+/**
+ * Reads a vector of int8_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<int8_t>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readByteArray(parcel, vectorData, AParcel_stdVectorAllocator<int8_t>);
+}
+
+/**
+ * Reads an optional vector of int8_t from the next location in a non-null parcel.
+ */
+inline binder_status_t AParcel_readVector(const AParcel* parcel,
+ std::optional<std::vector<int8_t>>* vec) {
+ void* vectorData = static_cast<void*>(vec);
+ return AParcel_readByteArray(parcel, vectorData, AParcel_nullableStdVectorAllocator<int8_t>);
+}
+
+// @END
+
+/**
+ * Convenience API for writing the size of a vector.
+ */
template <typename T>
static inline binder_status_t AParcel_writeVectorSize(AParcel* parcel, const std::vector<T>& vec) {
if (vec.size() > INT32_MAX) {
@@ -307,6 +662,26 @@
return AParcel_writeInt32(parcel, static_cast<int32_t>(vec.size()));
}
+/**
+ * Convenience API for writing the size of a vector.
+ */
+template <typename T>
+static inline binder_status_t AParcel_writeVectorSize(AParcel* parcel,
+ const std::optional<std::vector<T>>& vec) {
+ if (!vec) {
+ return AParcel_writeInt32(parcel, -1);
+ }
+
+ if (vec->size() > INT32_MAX) {
+ return STATUS_BAD_VALUE;
+ }
+
+ return AParcel_writeInt32(parcel, static_cast<int32_t>(vec->size()));
+}
+
+/**
+ * Convenience API for resizing a vector.
+ */
template <typename T>
static inline binder_status_t AParcel_resizeVector(const AParcel* parcel, std::vector<T>* vec) {
int32_t size;
@@ -319,8 +694,28 @@
return STATUS_OK;
}
-} // namespace ndk
+/**
+ * Convenience API for resizing a vector.
+ */
+template <typename T>
+static inline binder_status_t AParcel_resizeVector(const AParcel* parcel,
+ std::optional<std::vector<T>>* vec) {
+ int32_t size;
+ binder_status_t err = AParcel_readInt32(parcel, &size);
-#endif // __cplusplus
+ if (err != STATUS_OK) return err;
+ if (size < -1) return STATUS_UNEXPECTED_NULL;
+
+ if (size == -1) {
+ *vec = std::nullopt;
+ return STATUS_OK;
+ }
+
+ *vec = std::optional<std::vector<T>>(std::vector<T>{});
+ (*vec)->resize(static_cast<size_t>(size));
+ return STATUS_OK;
+}
+
+} // namespace ndk
/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_status.h b/libs/binder/ndk/include_ndk/android/binder_status.h
index 2d8b7fa..2671b9b 100644
--- a/libs/binder/ndk/include_ndk/android/binder_status.h
+++ b/libs/binder/ndk/include_ndk/android/binder_status.h
@@ -35,7 +35,7 @@
enum {
STATUS_OK = 0,
- STATUS_UNKNOWN_ERROR = (-2147483647 - 1), // INT32_MIN value
+ STATUS_UNKNOWN_ERROR = (-2147483647 - 1), // INT32_MIN value
STATUS_NO_MEMORY = -ENOMEM,
STATUS_INVALID_OPERATION = -ENOSYS,
STATUS_BAD_VALUE = -EINVAL,
@@ -95,24 +95,39 @@
* along with service specific errors.
*
* It is not required to be used in order to parcel/receive transactions, but it is required in
- * order to be compatible with standard AIDL transactions.
+ * order to be compatible with standard AIDL transactions since it is written as the header to the
+ * out parcel for transactions which get executed (don't fail during unparceling of input arguments
+ * or sooner).
*/
struct AStatus;
typedef struct AStatus AStatus;
/**
* New status which is considered a success.
+ *
+ * \return a newly constructed status object that the caller owns.
*/
__attribute__((warn_unused_result)) AStatus* AStatus_newOk() __INTRODUCED_IN(29);
/**
* New status with exception code.
+ *
+ * \param exception the code that this status should represent. If this is EX_NONE, then this
+ * constructs an non-error status object.
+ *
+ * \return a newly constructed status object that the caller owns.
*/
__attribute__((warn_unused_result)) AStatus* AStatus_fromExceptionCode(binder_exception_t exception)
__INTRODUCED_IN(29);
/**
* New status with exception code and message.
+ *
+ * \param exception the code that this status should represent. If this is EX_NONE, then this
+ * constructs an non-error status object.
+ * \param message the error message to associate with this status object.
+ *
+ * \return a newly constructed status object that the caller owns.
*/
__attribute__((warn_unused_result)) AStatus* AStatus_fromExceptionCodeWithMessage(
binder_exception_t exception, const char* message) __INTRODUCED_IN(29);
@@ -121,6 +136,10 @@
* New status with a service speciic error.
*
* This is considered to be EX_TRANSACTION_FAILED with extra information.
+ *
+ * \param serviceSpecific an implementation defined error code.
+ *
+ * \return a newly constructed status object that the caller owns.
*/
__attribute__((warn_unused_result)) AStatus* AStatus_fromServiceSpecificError(
int32_t serviceSpecific) __INTRODUCED_IN(29);
@@ -129,6 +148,11 @@
* New status with a service specific error and message.
*
* This is considered to be EX_TRANSACTION_FAILED with extra information.
+ *
+ * \param serviceSpecific an implementation defined error code.
+ * \param message the error message to associate with this status object.
+ *
+ * \return a newly constructed status object that the caller owns.
*/
__attribute__((warn_unused_result)) AStatus* AStatus_fromServiceSpecificErrorWithMessage(
int32_t serviceSpecific, const char* message) __INTRODUCED_IN(29);
@@ -137,6 +161,10 @@
* New status with binder_status_t. This is typically for low level failures when a binder_status_t
* is returned by an API on AIBinder or AParcel, and that is to be returned from a method returning
* an AStatus instance.
+ *
+ * \param a low-level error to associate with this status object.
+ *
+ * \return a newly constructed status object that the caller owns.
*/
__attribute__((warn_unused_result)) AStatus* AStatus_fromStatus(binder_status_t status)
__INTRODUCED_IN(29);
@@ -144,11 +172,19 @@
/**
* Whether this object represents a successful transaction. If this function returns true, then
* AStatus_getExceptionCode will return EX_NONE.
+ *
+ * \param status the status being queried.
+ *
+ * \return whether the status represents a successful transaction. For more details, see below.
*/
bool AStatus_isOk(const AStatus* status) __INTRODUCED_IN(29);
/**
* The exception that this status object represents.
+ *
+ * \param status the status being queried.
+ *
+ * \return the exception code that this object represents.
*/
binder_exception_t AStatus_getExceptionCode(const AStatus* status) __INTRODUCED_IN(29);
@@ -157,6 +193,10 @@
* non-zero result if AStatus_getExceptionCode returns EX_SERVICE_SPECIFIC. If this function returns
* 0, the status object may still represent a different exception or status. To find out if this
* transaction as a whole is okay, use AStatus_isOk instead.
+ *
+ * \param status the status being queried.
+ *
+ * \return the service-specific error code if the exception code is EX_SERVICE_SPECIFIC or 0.
*/
int32_t AStatus_getServiceSpecificError(const AStatus* status) __INTRODUCED_IN(29);
@@ -165,6 +205,10 @@
* if AStatus_getExceptionCode returns EX_TRANSACTION_FAILED. If this function return 0, the status
* object may represent a different exception or a service specific error. To find out if this
* transaction as a whole is okay, use AStatus_isOk instead.
+ *
+ * \param status the status being queried.
+ *
+ * \return the status code if the exception code is EX_TRANSACTION_FAILED or 0.
*/
binder_status_t AStatus_getStatus(const AStatus* status) __INTRODUCED_IN(29);
@@ -173,15 +217,21 @@
* message, this will return an empty string.
*
* The returned string has the lifetime of the status object passed into this function.
+ *
+ * \param status the status being queried.
+ *
+ * \return the message associated with this error.
*/
const char* AStatus_getMessage(const AStatus* status) __INTRODUCED_IN(29);
/**
* Deletes memory associated with the status instance.
+ *
+ * \param status the status to delete, returned from AStatus_newOk or one of the AStatus_from* APIs.
*/
void AStatus_delete(AStatus* status) __INTRODUCED_IN(29);
-#endif //__ANDROID_API__ >= __ANDROID_API_Q__
+#endif //__ANDROID_API__ >= __ANDROID_API_Q__
__END_DECLS
/** @} */
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index d2c1a3d..41df90b 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -7,6 +7,8 @@
AIBinder_debugGetRefCount;
AIBinder_decStrong;
AIBinder_fromJavaBinder;
+ AIBinder_getCallingPid;
+ AIBinder_getCallingUid;
AIBinder_getClass;
AIBinder_getUserData;
AIBinder_incStrong;
@@ -37,7 +39,6 @@
AParcel_readInt32Array;
AParcel_readInt64;
AParcel_readInt64Array;
- AParcel_readNullableStrongBinder;
AParcel_readParcelFileDescriptor;
AParcel_readStatusHeader;
AParcel_readString;
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index 3b44a62..b1a2955 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -36,28 +36,46 @@
using ::android::os::ParcelFileDescriptor;
template <typename T>
-using ContiguousArrayAllocator = T* (*)(void* arrayData, size_t length);
+using ContiguousArrayAllocator = bool (*)(void* arrayData, int32_t length, T** outBuffer);
template <typename T>
-using ArrayAllocator = bool (*)(void* arrayData, size_t length);
+using ArrayAllocator = bool (*)(void* arrayData, int32_t length);
template <typename T>
using ArrayGetter = T (*)(const void* arrayData, size_t index);
template <typename T>
using ArraySetter = void (*)(void* arrayData, size_t index, T value);
-template <typename T>
-binder_status_t WriteArray(AParcel* parcel, const T* array, size_t length) {
- if (length > std::numeric_limits<int32_t>::max()) return STATUS_BAD_VALUE;
+binder_status_t WriteAndValidateArraySize(AParcel* parcel, bool isNullArray, int32_t length) {
+ // only -1 can be used to represent a null array
+ if (length < -1) return STATUS_BAD_VALUE;
+
+ if (!isNullArray && length < 0) {
+ LOG(ERROR) << __func__ << ": null array must be used with length == -1.";
+ return STATUS_BAD_VALUE;
+ }
+ if (isNullArray && length > 0) {
+ LOG(ERROR) << __func__ << ": null buffer cannot be for size " << length << " array.";
+ return STATUS_BAD_VALUE;
+ }
Parcel* rawParcel = parcel->get();
status_t status = rawParcel->writeInt32(static_cast<int32_t>(length));
if (status != STATUS_OK) return PruneStatusT(status);
+ return STATUS_OK;
+}
+
+template <typename T>
+binder_status_t WriteArray(AParcel* parcel, const T* array, int32_t length) {
+ binder_status_t status = WriteAndValidateArraySize(parcel, array == nullptr, length);
+ if (status != STATUS_OK) return status;
+ if (length <= 0) return STATUS_OK;
+
int32_t size = 0;
if (__builtin_smul_overflow(sizeof(T), length, &size)) return STATUS_NO_MEMORY;
- void* const data = rawParcel->writeInplace(size);
+ void* const data = parcel->get()->writeInplace(size);
if (data == nullptr) return STATUS_NO_MEMORY;
memcpy(data, array, size);
@@ -67,17 +85,16 @@
// Each element in a char16_t array is converted to an int32_t (not packed).
template <>
-binder_status_t WriteArray<char16_t>(AParcel* parcel, const char16_t* array, size_t length) {
- if (length > std::numeric_limits<int32_t>::max()) return STATUS_BAD_VALUE;
-
- Parcel* rawParcel = parcel->get();
-
- status_t status = rawParcel->writeInt32(static_cast<int32_t>(length));
- if (status != STATUS_OK) return PruneStatusT(status);
+binder_status_t WriteArray<char16_t>(AParcel* parcel, const char16_t* array, int32_t length) {
+ binder_status_t status = WriteAndValidateArraySize(parcel, array == nullptr, length);
+ if (status != STATUS_OK) return status;
+ if (length <= 0) return STATUS_OK;
int32_t size = 0;
if (__builtin_smul_overflow(sizeof(char16_t), length, &size)) return STATUS_NO_MEMORY;
+ Parcel* rawParcel = parcel->get();
+
for (int32_t i = 0; i < length; i++) {
status = rawParcel->writeChar(array[i]);
@@ -96,10 +113,12 @@
status_t status = rawParcel->readInt32(&length);
if (status != STATUS_OK) return PruneStatusT(status);
- if (length < 0) return STATUS_UNEXPECTED_NULL;
+ if (length < -1) return STATUS_BAD_VALUE;
- T* array = allocator(arrayData, length);
- if (length == 0) return STATUS_OK;
+ T* array;
+ if (!allocator(arrayData, length, &array)) return STATUS_NO_MEMORY;
+
+ if (length <= 0) return STATUS_OK;
if (array == nullptr) return STATUS_NO_MEMORY;
int32_t size = 0;
@@ -123,10 +142,12 @@
status_t status = rawParcel->readInt32(&length);
if (status != STATUS_OK) return PruneStatusT(status);
- if (length < 0) return STATUS_UNEXPECTED_NULL;
+ if (length < -1) return STATUS_BAD_VALUE;
- char16_t* array = allocator(arrayData, length);
- if (length == 0) return STATUS_OK;
+ char16_t* array;
+ if (!allocator(arrayData, length, &array)) return STATUS_NO_MEMORY;
+
+ if (length <= 0) return STATUS_OK;
if (array == nullptr) return STATUS_NO_MEMORY;
int32_t size = 0;
@@ -142,15 +163,16 @@
}
template <typename T>
-binder_status_t WriteArray(AParcel* parcel, const void* arrayData, size_t length,
+binder_status_t WriteArray(AParcel* parcel, const void* arrayData, int32_t length,
ArrayGetter<T> getter, status_t (Parcel::*write)(T)) {
- if (length > std::numeric_limits<int32_t>::max()) return STATUS_BAD_VALUE;
+ // we have no clue if arrayData represents a null object or not, we can only infer from length
+ bool arrayIsNull = length < 0;
+ binder_status_t status = WriteAndValidateArraySize(parcel, arrayIsNull, length);
+ if (status != STATUS_OK) return status;
+ if (length <= 0) return STATUS_OK;
Parcel* rawParcel = parcel->get();
- status_t status = rawParcel->writeInt32(static_cast<int32_t>(length));
- if (status != STATUS_OK) return PruneStatusT(status);
-
for (size_t i = 0; i < length; i++) {
status = (rawParcel->*write)(getter(arrayData, i));
@@ -169,10 +191,12 @@
status_t status = rawParcel->readInt32(&length);
if (status != STATUS_OK) return PruneStatusT(status);
- if (length < 0) return STATUS_UNEXPECTED_NULL;
+ if (length < -1) return STATUS_BAD_VALUE;
if (!allocator(arrayData, length)) return STATUS_NO_MEMORY;
+ if (length <= 0) return STATUS_OK;
+
for (size_t i = 0; i < length; i++) {
T readTarget;
status = (rawParcel->*read)(&readTarget);
@@ -194,17 +218,6 @@
}
binder_status_t AParcel_readStrongBinder(const AParcel* parcel, AIBinder** binder) {
sp<IBinder> readBinder = nullptr;
- status_t status = parcel->get()->readStrongBinder(&readBinder);
- if (status != STATUS_OK) {
- return PruneStatusT(status);
- }
- sp<AIBinder> ret = ABpBinder::lookupOrCreateFromBinder(readBinder);
- AIBinder_incStrong(ret.get());
- *binder = ret.get();
- return PruneStatusT(status);
-}
-binder_status_t AParcel_readNullableStrongBinder(const AParcel* parcel, AIBinder** binder) {
- sp<IBinder> readBinder = nullptr;
status_t status = parcel->get()->readNullableStrongBinder(&readBinder);
if (status != STATUS_OK) {
return PruneStatusT(status);
@@ -248,9 +261,23 @@
return PruneStatusT(ret);
}
-binder_status_t AParcel_writeString(AParcel* parcel, const char* string, size_t length) {
- const uint8_t* str8 = (uint8_t*)string;
+binder_status_t AParcel_writeString(AParcel* parcel, const char* string, int32_t length) {
+ if (string == nullptr) {
+ if (length != -1) {
+ LOG(WARNING) << __func__ << ": null string must be used with length == -1.";
+ return STATUS_BAD_VALUE;
+ }
+ status_t err = parcel->get()->writeInt32(-1);
+ return PruneStatusT(err);
+ }
+
+ if (length < 0) {
+ LOG(WARNING) << __func__ << ": Negative string length: " << length;
+ return STATUS_BAD_VALUE;
+ }
+
+ const uint8_t* str8 = (uint8_t*)string;
const ssize_t len16 = utf8_to_utf16_length(str8, length);
if (len16 < 0 || len16 >= std::numeric_limits<int32_t>::max()) {
@@ -279,7 +306,10 @@
const char16_t* str16 = parcel->get()->readString16Inplace(&len16);
if (str16 == nullptr) {
- LOG(WARNING) << __func__ << ": Failed to read string in place.";
+ if (allocator(stringData, -1, nullptr)) {
+ return STATUS_OK;
+ }
+
return STATUS_UNEXPECTED_NULL;
}
@@ -296,9 +326,10 @@
return STATUS_BAD_VALUE;
}
- char* str8 = allocator(stringData, len8);
+ char* str8;
+ bool success = allocator(stringData, len8, &str8);
- if (str8 == nullptr) {
+ if (!success || str8 == nullptr) {
LOG(WARNING) << __func__ << ": AParcel_stringAllocator failed to allocate.";
return STATUS_NO_MEMORY;
}
@@ -308,19 +339,18 @@
return STATUS_OK;
}
-binder_status_t AParcel_writeStringArray(AParcel* parcel, const void* arrayData, size_t length,
+binder_status_t AParcel_writeStringArray(AParcel* parcel, const void* arrayData, int32_t length,
AParcel_stringArrayElementGetter getter) {
- if (length > std::numeric_limits<int32_t>::max()) return STATUS_BAD_VALUE;
-
- Parcel* rawParcel = parcel->get();
-
- status_t status = rawParcel->writeInt32(static_cast<int32_t>(length));
- if (status != STATUS_OK) return PruneStatusT(status);
+ // we have no clue if arrayData represents a null object or not, we can only infer from length
+ bool arrayIsNull = length < 0;
+ binder_status_t status = WriteAndValidateArraySize(parcel, arrayIsNull, length);
+ if (status != STATUS_OK) return status;
+ if (length <= 0) return STATUS_OK;
for (size_t i = 0; i < length; i++) {
size_t length = 0;
const char* str = getter(arrayData, i, &length);
- if (str == nullptr) return STATUS_BAD_VALUE;
+ if (str == nullptr && length != -1) return STATUS_BAD_VALUE;
binder_status_t status = AParcel_writeString(parcel, str, length);
if (status != STATUS_OK) return status;
@@ -332,14 +362,14 @@
// This implements AParcel_stringAllocator for a string using an array, index, and element
// allocator.
struct StringArrayElementAllocationAdapter {
- void* arrayData; // stringData from the NDK
- size_t index; // index into the string array
+ void* arrayData; // stringData from the NDK
+ size_t index; // index into the string array
AParcel_stringArrayElementAllocator elementAllocator;
- static char* Allocator(void* stringData, size_t length) {
+ static bool Allocator(void* stringData, int32_t length, char** buffer) {
StringArrayElementAllocationAdapter* adapter =
static_cast<StringArrayElementAllocationAdapter*>(stringData);
- return adapter->elementAllocator(adapter->arrayData, adapter->index, length);
+ return adapter->elementAllocator(adapter->arrayData, adapter->index, length, buffer);
}
};
@@ -352,10 +382,12 @@
status_t status = rawParcel->readInt32(&length);
if (status != STATUS_OK) return PruneStatusT(status);
- if (length < 0) return STATUS_UNEXPECTED_NULL;
+ if (length < -1) return STATUS_BAD_VALUE;
if (!allocator(arrayData, length)) return STATUS_NO_MEMORY;
+ if (length == -1) return STATUS_OK; // null string array
+
StringArrayElementAllocationAdapter adapter{
.arrayData = arrayData,
.index = 0,
@@ -363,8 +395,10 @@
};
for (; adapter.index < length; adapter.index++) {
- AParcel_readString(parcel, static_cast<void*>(&adapter),
- StringArrayElementAllocationAdapter::Allocator);
+ binder_status_t status = AParcel_readString(parcel, static_cast<void*>(&adapter),
+ StringArrayElementAllocationAdapter::Allocator);
+
+ if (status != STATUS_OK) return status;
}
return STATUS_OK;
@@ -463,41 +497,43 @@
return PruneStatusT(status);
}
-binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* value, size_t length) {
- return WriteArray<int32_t>(parcel, value, length);
+binder_status_t AParcel_writeInt32Array(AParcel* parcel, const int32_t* arrayData, int32_t length) {
+ return WriteArray<int32_t>(parcel, arrayData, length);
}
-binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* value, size_t length) {
- return WriteArray<uint32_t>(parcel, value, length);
+binder_status_t AParcel_writeUint32Array(AParcel* parcel, const uint32_t* arrayData,
+ int32_t length) {
+ return WriteArray<uint32_t>(parcel, arrayData, length);
}
-binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* value, size_t length) {
- return WriteArray<int64_t>(parcel, value, length);
+binder_status_t AParcel_writeInt64Array(AParcel* parcel, const int64_t* arrayData, int32_t length) {
+ return WriteArray<int64_t>(parcel, arrayData, length);
}
-binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* value, size_t length) {
- return WriteArray<uint64_t>(parcel, value, length);
+binder_status_t AParcel_writeUint64Array(AParcel* parcel, const uint64_t* arrayData,
+ int32_t length) {
+ return WriteArray<uint64_t>(parcel, arrayData, length);
}
-binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* value, size_t length) {
- return WriteArray<float>(parcel, value, length);
+binder_status_t AParcel_writeFloatArray(AParcel* parcel, const float* arrayData, int32_t length) {
+ return WriteArray<float>(parcel, arrayData, length);
}
-binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* value, size_t length) {
- return WriteArray<double>(parcel, value, length);
+binder_status_t AParcel_writeDoubleArray(AParcel* parcel, const double* arrayData, int32_t length) {
+ return WriteArray<double>(parcel, arrayData, length);
}
-binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData, size_t length,
+binder_status_t AParcel_writeBoolArray(AParcel* parcel, const void* arrayData, int32_t length,
AParcel_boolArrayGetter getter) {
return WriteArray<bool>(parcel, arrayData, length, getter, &Parcel::writeBool);
}
-binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* value, size_t length) {
- return WriteArray<char16_t>(parcel, value, length);
+binder_status_t AParcel_writeCharArray(AParcel* parcel, const char16_t* arrayData, int32_t length) {
+ return WriteArray<char16_t>(parcel, arrayData, length);
}
-binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* value, size_t length) {
- return WriteArray<int8_t>(parcel, value, length);
+binder_status_t AParcel_writeByteArray(AParcel* parcel, const int8_t* arrayData, int32_t length) {
+ return WriteArray<int8_t>(parcel, arrayData, length);
}
binder_status_t AParcel_readInt32Array(const AParcel* parcel, void* arrayData,
diff --git a/libs/binder/ndk/parcel_internal.h b/libs/binder/ndk/parcel_internal.h
index d69971f..f292309 100644
--- a/libs/binder/ndk/parcel_internal.h
+++ b/libs/binder/ndk/parcel_internal.h
@@ -29,7 +29,7 @@
AParcel(const AIBinder* binder) : AParcel(binder, new ::android::Parcel, true /*owns*/) {}
AParcel(const AIBinder* binder, ::android::Parcel* parcel, bool owns)
- : mBinder(binder), mParcel(parcel), mOwns(owns) {}
+ : mBinder(binder), mParcel(parcel), mOwns(owns) {}
~AParcel() {
if (mOwns) {
@@ -43,7 +43,7 @@
const AIBinder* getBinder() { return mBinder; }
-private:
+ private:
// This object is associated with a calls to a specific AIBinder object. This is used for sanity
// checking to make sure that a parcel is one that is expected.
const AIBinder* mBinder;
diff --git a/libs/binder/ndk/runtests.sh b/libs/binder/ndk/runtests.sh
index 2257eb2..a0c49fb 100755
--- a/libs/binder/ndk/runtests.sh
+++ b/libs/binder/ndk/runtests.sh
@@ -22,12 +22,13 @@
set -ex
function run_libbinder_ndk_test() {
- adb shell /data/nativetest64/libbinder_ndk_test_server/libbinder_ndk_test_server &
- local pid=$!
- trap "kill $pid" ERR
- adb shell /data/nativetest64/libbinder_ndk_test_client/libbinder_ndk_test_client
- trap '' ERR
- kill $pid
+ adb shell /data/nativetest64/libbinder_ndk_test_server/libbinder_ndk_test_server &
+
+ # avoid getService 1s delay for most runs, non-critical
+ sleep 0.1
+
+ adb shell /data/nativetest64/libbinder_ndk_test_client/libbinder_ndk_test_client; \
+ adb shell killall libbinder_ndk_test_server
}
[ "$1" != "--skip-build" ] && $ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode \
@@ -40,4 +41,5 @@
# very simple unit tests, tests things outside of the NDK as well
run_libbinder_ndk_test
-atest android.binder.cts.NdkBinderTest
+# CTS tests (much more comprehensive, new tests should ideally go here)
+atest android.binder.cts
diff --git a/libs/binder/ndk/scripts/gen_parcel_helper.py b/libs/binder/ndk/scripts/gen_parcel_helper.py
index 0e10220..8f587d2 100755
--- a/libs/binder/ndk/scripts/gen_parcel_helper.py
+++ b/libs/binder/ndk/scripts/gen_parcel_helper.py
@@ -69,6 +69,11 @@
for pretty, cpp in data_types:
header += "/**\n"
header += " * Writes " + cpp + " value to the next location in a non-null parcel.\n"
+ header += " *\n"
+ header += " * \\param parcel the parcel to write to.\n"
+ header += " * \\param value the value to write to the parcel.\n"
+ header += " *\n"
+ header += " * \\return STATUS_OK on successful write.\n"
header += " */\n"
header += "binder_status_t AParcel_write" + pretty + "(AParcel* parcel, " + cpp + " value) __INTRODUCED_IN(29);\n\n"
source += "binder_status_t AParcel_write" + pretty + "(AParcel* parcel, " + cpp + " value) {\n"
@@ -79,6 +84,11 @@
for pretty, cpp in data_types:
header += "/**\n"
header += " * Reads into " + cpp + " value from the next location in a non-null parcel.\n"
+ header += " *\n"
+ header += " * \\param parcel the parcel to read from.\n"
+ header += " * \\param value the value to read from the parcel.\n"
+ header += " *\n"
+ header += " * \\return STATUS_OK on successful read.\n"
header += " */\n"
header += "binder_status_t AParcel_read" + pretty + "(const AParcel* parcel, " + cpp + "* value) __INTRODUCED_IN(29);\n\n"
source += "binder_status_t AParcel_read" + pretty + "(const AParcel* parcel, " + cpp + "* value) {\n"
@@ -89,9 +99,9 @@
for pretty, cpp in data_types:
nca = pretty in non_contiguously_addressable
- arg_types = "const " + cpp + "* value, size_t length"
- if nca: arg_types = "const void* arrayData, size_t length, AParcel_" + pretty.lower() + "ArrayGetter getter"
- args = "value, length"
+ arg_types = "const " + cpp + "* arrayData, int32_t length"
+ if nca: arg_types = "const void* arrayData, int32_t length, AParcel_" + pretty.lower() + "ArrayGetter getter"
+ args = "arrayData, length"
if nca: args = "arrayData, length, getter, &Parcel::write" + pretty
header += "/**\n"
@@ -100,6 +110,17 @@
header += " *\n"
header += " * getter(arrayData, i) will be called for each i in [0, length) in order to get the underlying values to write "
header += "to the parcel.\n"
+ header += " *\n"
+ header += " * \\param parcel the parcel to write to.\n"
+ if nca:
+ header += " * \\param arrayData some external representation of an array.\n"
+ header += " * \\param length the length of arrayData (or -1 if this represents a null array).\n"
+ header += " * \\param getter the callback to retrieve data at specific locations in the array.\n"
+ else:
+ header += " * \\param arrayData an array of size 'length' (or null if length is -1, may be null if length is 0).\n"
+ header += " * \\param length the length of arrayData or -1 if this represents a null array.\n"
+ header += " *\n"
+ header += " * \\return STATUS_OK on successful write.\n"
header += " */\n"
header += "binder_status_t AParcel_write" + pretty + "Array(AParcel* parcel, " + arg_types + ") __INTRODUCED_IN(29);\n\n"
source += "binder_status_t AParcel_write" + pretty + "Array(AParcel* parcel, " + arg_types + ") {\n"
@@ -118,16 +139,26 @@
if nca:
pre_header += "/**\n"
pre_header += " * This allocates an array of size 'length' inside of arrayData and returns whether or not there was "
- pre_header += "a success.\n"
+ pre_header += "a success. If length is -1, then this should allocate some representation of a null array.\n"
pre_header += " *\n"
pre_header += " * See also " + read_func + "\n"
+ pre_header += " *\n"
+ pre_header += " * \\param arrayData some external representation of an array of " + cpp + ".\n"
+ pre_header += " * \\param length the length to allocate arrayData to (or -1 if this represents a null array).\n"
+ pre_header += " *\n"
+ pre_header += " * \\return whether the allocation succeeded.\n"
pre_header += " */\n"
- pre_header += "typedef bool (*" + allocator_type + ")(void* arrayData, size_t length);\n\n"
+ pre_header += "typedef bool (*" + allocator_type + ")(void* arrayData, int32_t length);\n\n"
pre_header += "/**\n"
pre_header += " * This is called to get the underlying data from an arrayData object at index.\n"
pre_header += " *\n"
pre_header += " * See also " + write_func + "\n"
+ pre_header += " *\n"
+ pre_header += " * \\param arrayData some external representation of an array of " + cpp + ".\n"
+ pre_header += " * \\param index the index of the value to be retrieved.\n"
+ pre_header += " *\n"
+ pre_header += " * \\return the value of the array at index index.\n"
pre_header += " */\n"
pre_header += "typedef " + cpp + " (*" + getter_type + ")(const void* arrayData, size_t index);\n\n"
@@ -135,6 +166,10 @@
pre_header += " * This is called to set an underlying value in an arrayData object at index.\n"
pre_header += " *\n"
pre_header += " * See also " + read_func + "\n"
+ pre_header += " *\n"
+ pre_header += " * \\param arrayData some external representation of an array of " + cpp + ".\n"
+ pre_header += " * \\param index the index of the value to be set.\n"
+ pre_header += " * \\param value the value to set at index index.\n"
pre_header += " */\n"
pre_header += "typedef void (*" + setter_type + ")(void* arrayData, size_t index, " + cpp + " value);\n\n"
else:
@@ -143,11 +178,18 @@
pre_header += " *\n"
pre_header += " * The implementation of this function should allocate a contiguous array of size 'length' and "
pre_header += "return that underlying buffer to be filled out. If there is an error or length is 0, null may be "
- pre_header += "returned.\n"
+ pre_header += "returned. If length is -1, this should allocate some representation of a null array.\n"
pre_header += " *\n"
pre_header += " * See also " + read_func + "\n"
+ pre_header += " *\n"
+ pre_header += " * \\param arrayData some external representation of an array of " + cpp + ".\n"
+ pre_header += " * \\param length the length to allocate arrayData to.\n"
+ pre_header += " * \\param outBuffer a buffer of " + cpp + " of size 'length' (if length is >= 0, if length is 0, "
+ pre_header += "this may be nullptr).\n"
+ pre_header += " *\n"
+ pre_header += " * \\return whether or not the allocation was successful (or whether a null array is represented when length is -1).\n"
pre_header += " */\n"
- pre_header += "typedef " + cpp + "* (*" + allocator_type + ")(void* arrayData, size_t length);\n\n"
+ pre_header += "typedef bool (*" + allocator_type + ")(void* arrayData, int32_t length, " + cpp + "** outBuffer);\n\n"
read_array_args = [("const AParcel*", "parcel")]
read_array_args += [("void*", "arrayData")]
@@ -166,6 +208,14 @@
else:
header += " * First, allocator will be called with the length of the array. If the allocation succeeds and the "
header += "length is greater than zero, the buffer returned by the allocator will be filled with the corresponding data\n"
+ header += " *\n"
+ header += " * \\param parcel the parcel to read from.\n"
+ header += " * \\param arrayData some external representation of an array.\n"
+ header += " * \\param allocator the callback that will be called to allocate the array.\n"
+ if nca:
+ header += " * \\param setter the callback that will be called to set a value at a specific location in the array.\n"
+ header += " *\n"
+ header += " * \\return STATUS_OK on successful read.\n"
header += " */\n"
header += "binder_status_t " + read_func + "(" + read_type_args + ") __INTRODUCED_IN(29);\n\n"
source += "binder_status_t " + read_func + "(" + read_type_args + ") {\n"
@@ -184,6 +234,16 @@
cpp_helper += "}\n\n"
cpp_helper += "/**\n"
+ cpp_helper += " * Writes an optional vector of " + cpp + " to the next location in a non-null parcel.\n"
+ cpp_helper += " */\n"
+ cpp_helper += "inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::optional<std::vector<" + cpp + ">>& vec) {\n"
+ extra_args = ""
+ if nca: extra_args = ", AParcel_stdVectorGetter<" + cpp + ">"
+ cpp_helper += " if (!vec) return AParcel_write" + pretty + "Array(parcel, nullptr, -1" + extra_args + ");\n"
+ cpp_helper += " return AParcel_writeVector(parcel, *vec);\n"
+ cpp_helper += "}\n\n"
+
+ cpp_helper += "/**\n"
cpp_helper += " * Reads a vector of " + cpp + " from the next location in a non-null parcel.\n"
cpp_helper += " */\n"
cpp_helper += "inline binder_status_t AParcel_readVector(const AParcel* parcel, std::vector<" + cpp + ">* vec) {\n"
@@ -199,6 +259,22 @@
cpp_helper += " return AParcel_read" + pretty + "Array(" + ", ".join(read_args) + ");\n"
cpp_helper += "}\n\n"
+ cpp_helper += "/**\n"
+ cpp_helper += " * Reads an optional vector of " + cpp + " from the next location in a non-null parcel.\n"
+ cpp_helper += " */\n"
+ cpp_helper += "inline binder_status_t AParcel_readVector(const AParcel* parcel, std::optional<std::vector<" + cpp + ">>* vec) {\n"
+ cpp_helper += " void* vectorData = static_cast<void*>(vec);\n"
+ read_args = []
+ read_args += ["parcel"]
+ read_args += ["vectorData"]
+ if nca:
+ read_args += ["AParcel_nullableStdVectorExternalAllocator<bool>"]
+ read_args += ["AParcel_nullableStdVectorSetter<" + cpp + ">"]
+ else:
+ read_args += ["AParcel_nullableStdVectorAllocator<" + cpp + ">"]
+ cpp_helper += " return AParcel_read" + pretty + "Array(" + ", ".join(read_args) + ");\n"
+ cpp_helper += "}\n\n"
+
replaceFileTags(ROOT + "include_ndk/android/binder_parcel.h", pre_header, "START-PRIMITIVE-VECTOR-GETTERS", "END-PRIMITIVE-VECTOR-GETTERS")
replaceFileTags(ROOT + "include_ndk/android/binder_parcel.h", header, "START-PRIMITIVE-READ-WRITE", "END-PRIMITIVE-READ-WRITE")
replaceFileTags(ROOT + "parcel.cpp", source, "START", "END")
diff --git a/libs/binder/ndk/status_internal.h b/libs/binder/ndk/status_internal.h
index 8c32baf..d39f0d8 100644
--- a/libs/binder/ndk/status_internal.h
+++ b/libs/binder/ndk/status_internal.h
@@ -22,13 +22,13 @@
#include <utils/Errors.h>
struct AStatus {
- AStatus() {} // ok
+ AStatus() {} // ok
AStatus(::android::binder::Status&& status) : mStatus(std::move(status)) {}
::android::binder::Status* get() { return &mStatus; }
const ::android::binder::Status* get() const { return &mStatus; }
-private:
+ private:
::android::binder::Status mStatus;
};
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp
index 8e40a01..67481cf 100644
--- a/libs/binder/ndk/test/Android.bp
+++ b/libs/binder/ndk/test/Android.bp
@@ -14,9 +14,6 @@
* limitations under the License.
*/
-// This test is a unit test of the low-level API that is presented here.
-// Actual users should use AIDL to generate these complicated stubs.
-
cc_defaults {
name: "test_libbinder_ndk_defaults",
shared_libs: [
@@ -25,6 +22,7 @@
strip: {
none: true,
},
+ cpp_std: "c++17",
cflags: [
"-O0",
"-g",
@@ -55,6 +53,9 @@
],
}
+// This test is a unit test of the low-level API that is presented here,
+// specifically the parts which are outside of the NDK. Actual users should
+// also instead use AIDL to generate these stubs. See android.binder.cts.
cc_test {
name: "libbinder_ndk_test_client",
defaults: ["test_libbinder_ndk_test_defaults"],
diff --git a/libs/binder/ndk/test/iface.cpp b/libs/binder/ndk/test/iface.cpp
index 0dc3cc4..6ef964e 100644
--- a/libs/binder/ndk/test/iface.cpp
+++ b/libs/binder/ndk/test/iface.cpp
@@ -18,10 +18,13 @@
#include <android/binder_manager.h>
#include <iface/iface.h>
+#include <android/binder_auto_utils.h>
+
using ::android::sp;
using ::android::wp;
const char* IFoo::kSomeInstanceName = "libbinder_ndk-test-IFoo";
+const char* IFoo::kInstanceNameToDieFor = "libbinder_ndk-test-IFoo-to-die";
const char* kIFooDescriptor = "my-special-IFoo-class";
struct IFoo_Class_Data {
@@ -49,12 +52,18 @@
switch (code) {
case IFoo::DOFOO: {
int32_t valueIn;
+ int32_t valueOut;
stat = AParcel_readInt32(in, &valueIn);
if (stat != STATUS_OK) break;
- int32_t valueOut = foo->doubleNumber(valueIn);
+ stat = foo->doubleNumber(valueIn, &valueOut);
+ if (stat != STATUS_OK) break;
stat = AParcel_writeInt32(out, valueOut);
break;
}
+ case IFoo::DIE: {
+ stat = foo->die();
+ break;
+ }
}
return stat;
@@ -64,29 +73,43 @@
IFoo_Class_onDestroy, IFoo_Class_onTransact);
class BpFoo : public IFoo {
-public:
+ public:
BpFoo(AIBinder* binder) : mBinder(binder) {}
virtual ~BpFoo() { AIBinder_decStrong(mBinder); }
- virtual int32_t doubleNumber(int32_t in) {
+ virtual binder_status_t doubleNumber(int32_t in, int32_t* out) {
+ binder_status_t stat = STATUS_OK;
+
AParcel* parcelIn;
- CHECK(STATUS_OK == AIBinder_prepareTransaction(mBinder, &parcelIn));
+ stat = AIBinder_prepareTransaction(mBinder, &parcelIn);
+ if (stat != STATUS_OK) return stat;
- CHECK(STATUS_OK == AParcel_writeInt32(parcelIn, in));
+ stat = AParcel_writeInt32(parcelIn, in);
+ if (stat != STATUS_OK) return stat;
- AParcel* parcelOut;
- CHECK(STATUS_OK ==
- AIBinder_transact(mBinder, IFoo::DOFOO, &parcelIn, &parcelOut, 0 /*flags*/));
+ ::ndk::ScopedAParcel parcelOut;
+ stat = AIBinder_transact(mBinder, IFoo::DOFOO, &parcelIn, parcelOut.getR(), 0 /*flags*/);
+ if (stat != STATUS_OK) return stat;
- int32_t out;
- CHECK(STATUS_OK == AParcel_readInt32(parcelOut, &out));
+ stat = AParcel_readInt32(parcelOut.get(), out);
+ if (stat != STATUS_OK) return stat;
- AParcel_delete(parcelOut);
-
- return out;
+ return stat;
}
-private:
+ virtual binder_status_t die() {
+ binder_status_t stat = STATUS_OK;
+
+ AParcel* parcelIn;
+ stat = AIBinder_prepareTransaction(mBinder, &parcelIn);
+
+ ::ndk::ScopedAParcel parcelOut;
+ stat = AIBinder_transact(mBinder, IFoo::DIE, &parcelIn, parcelOut.getR(), 0 /*flags*/);
+
+ return stat;
+ }
+
+ private:
// Always assumes one refcount
AIBinder* mBinder;
};
@@ -117,8 +140,8 @@
return status;
}
-sp<IFoo> IFoo::getService(const char* instance) {
- AIBinder* binder = AServiceManager_getService(instance); // maybe nullptr
+sp<IFoo> IFoo::getService(const char* instance, AIBinder** outBinder) {
+ AIBinder* binder = AServiceManager_getService(instance); // maybe nullptr
if (binder == nullptr) {
return nullptr;
}
@@ -128,14 +151,19 @@
return nullptr;
}
+ if (outBinder != nullptr) {
+ AIBinder_incStrong(binder);
+ *outBinder = binder;
+ }
+
if (AIBinder_isRemote(binder)) {
- sp<IFoo> ret = new BpFoo(binder); // takes ownership of binder
+ sp<IFoo> ret = new BpFoo(binder); // takes ownership of binder
return ret;
}
IFoo_Class_Data* data = static_cast<IFoo_Class_Data*>(AIBinder_getUserData(binder));
- CHECK(data != nullptr); // always created with non-null data
+ CHECK(data != nullptr); // always created with non-null data
sp<IFoo> ret = data->foo;
@@ -143,7 +171,6 @@
CHECK(held == binder);
AIBinder_decStrong(held);
- // IFoo only keeps a weak reference to AIBinder, so we can drop this
AIBinder_decStrong(binder);
return ret;
}
diff --git a/libs/binder/ndk/test/include/iface/iface.h b/libs/binder/ndk/test/include/iface/iface.h
index 4c61e9d..cdf5493 100644
--- a/libs/binder/ndk/test/include/iface/iface.h
+++ b/libs/binder/ndk/test/include/iface/iface.h
@@ -19,22 +19,33 @@
#include <android/binder_ibinder.h>
#include <utils/RefBase.h>
+// warning: it is recommended to use AIDL output instead of this. binder_ibinder_utils.h and some of
+// the other niceties make sure that, for instance, binder proxies are always the same. They also
+// don't use internal Android APIs like refbase which are used here only for convenience.
+
class IFoo : public virtual ::android::RefBase {
-public:
+ public:
static const char* kSomeInstanceName;
+ static const char* kInstanceNameToDieFor;
+
static AIBinder_Class* kClass;
// Takes ownership of IFoo
binder_status_t addService(const char* instance);
- static ::android::sp<IFoo> getService(const char* instance);
+ static ::android::sp<IFoo> getService(const char* instance, AIBinder** outBinder = nullptr);
enum Call {
DOFOO = FIRST_CALL_TRANSACTION + 0,
+ DIE = FIRST_CALL_TRANSACTION + 1,
};
virtual ~IFoo();
- virtual int32_t doubleNumber(int32_t in) = 0;
-private:
- AIBinder_Weak* mWeakBinder = nullptr; // maybe owns AIBinder
+ virtual binder_status_t doubleNumber(int32_t in, int32_t* out) = 0;
+ virtual binder_status_t die() = 0;
+
+ private:
+ // this variable is only when IFoo is local (since this test combines 'IFoo' and 'BnFoo'), not
+ // for BpFoo.
+ AIBinder_Weak* mWeakBinder = nullptr;
};
diff --git a/libs/binder/ndk/test/main_client.cpp b/libs/binder/ndk/test/main_client.cpp
index 6945cac..c159d71 100644
--- a/libs/binder/ndk/test/main_client.cpp
+++ b/libs/binder/ndk/test/main_client.cpp
@@ -21,6 +21,10 @@
#include <gtest/gtest.h>
#include <iface/iface.h>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+
using ::android::sp;
constexpr char kExistingNonNdkService[] = "SurfaceFlinger";
@@ -34,7 +38,47 @@
TEST(NdkBinder, DoubleNumber) {
sp<IFoo> foo = IFoo::getService(IFoo::kSomeInstanceName);
ASSERT_NE(foo, nullptr);
- EXPECT_EQ(2, foo->doubleNumber(1));
+
+ int32_t out;
+ EXPECT_EQ(STATUS_OK, foo->doubleNumber(1, &out));
+ EXPECT_EQ(2, out);
+}
+
+void LambdaOnDeath(void* cookie) {
+ auto onDeath = static_cast<std::function<void(void)>*>(cookie);
+ (*onDeath)();
+};
+TEST(NdkBinder, DeathRecipient) {
+ using namespace std::chrono_literals;
+
+ AIBinder* binder;
+ sp<IFoo> foo = IFoo::getService(IFoo::kInstanceNameToDieFor, &binder);
+ ASSERT_NE(nullptr, foo.get());
+ ASSERT_NE(nullptr, binder);
+
+ std::mutex deathMutex;
+ std::condition_variable deathCv;
+ bool deathRecieved = false;
+
+ std::function<void(void)> onDeath = [&] {
+ std::cerr << "Binder died (as requested)." << std::endl;
+ deathRecieved = true;
+ deathCv.notify_one();
+ };
+
+ AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(LambdaOnDeath);
+
+ EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient, static_cast<void*>(&onDeath)));
+
+ // the binder driver should return this if the service dies during the transaction
+ EXPECT_EQ(STATUS_DEAD_OBJECT, foo->die());
+
+ std::unique_lock<std::mutex> lock(deathMutex);
+ EXPECT_TRUE(deathCv.wait_for(lock, 1s, [&] { return deathRecieved; }));
+ EXPECT_TRUE(deathRecieved);
+
+ AIBinder_DeathRecipient_delete(recipient);
+ AIBinder_decStrong(binder);
}
TEST(NdkBinder, RetrieveNonNdkService) {
@@ -52,9 +96,6 @@
}
TEST(NdkBinder, LinkToDeath) {
- ABinderProcess_setThreadPoolMaxThreadCount(1); // to recieve death notifications
- ABinderProcess_startThreadPool();
-
AIBinder* binder = AServiceManager_getService(kExistingNonNdkService);
ASSERT_NE(nullptr, binder);
@@ -72,9 +113,14 @@
}
class MyTestFoo : public IFoo {
- int32_t doubleNumber(int32_t in) override {
- LOG(INFO) << "doubleNumber " << in;
- return 2 * in;
+ binder_status_t doubleNumber(int32_t in, int32_t* out) override {
+ *out = 2 * in;
+ LOG(INFO) << "doubleNumber (" << in << ") => " << *out;
+ return STATUS_OK;
+ }
+ binder_status_t die() override {
+ ADD_FAILURE() << "die called on local instance";
+ return STATUS_OK;
}
};
@@ -87,7 +133,9 @@
sp<IFoo> getFoo = IFoo::getService(kInstanceName);
EXPECT_EQ(foo.get(), getFoo.get());
- EXPECT_EQ(2, getFoo->doubleNumber(1));
+ int32_t out;
+ EXPECT_EQ(STATUS_OK, getFoo->doubleNumber(1, &out));
+ EXPECT_EQ(2, out);
}
TEST(NdkBinder, EqualityOfRemoteBinderPointer) {
@@ -132,6 +180,15 @@
EXPECT_EQ(IFoo::getService(kInstanceName1), IFoo::getService(kInstanceName2));
}
+int main(int argc, char* argv[]) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ ABinderProcess_setThreadPoolMaxThreadCount(1); // to recieve death notifications/callbacks
+ ABinderProcess_startThreadPool();
+
+ return RUN_ALL_TESTS();
+}
+
#include <android/binder_auto_utils.h>
#include <android/binder_interface_utils.h>
#include <android/binder_parcel_utils.h>
diff --git a/libs/binder/ndk/test/main_server.cpp b/libs/binder/ndk/test/main_server.cpp
index 0718a69..a6e17e8 100644
--- a/libs/binder/ndk/test/main_server.cpp
+++ b/libs/binder/ndk/test/main_server.cpp
@@ -21,23 +21,37 @@
using ::android::sp;
class MyFoo : public IFoo {
- int32_t doubleNumber(int32_t in) override {
- LOG(INFO) << "doubling " << in;
- return 2 * in;
+ binder_status_t doubleNumber(int32_t in, int32_t* out) override {
+ *out = 2 * in;
+ LOG(INFO) << "doubleNumber (" << in << ") => " << *out;
+ return STATUS_OK;
+ }
+
+ binder_status_t die() override {
+ LOG(FATAL) << "IFoo::die called!";
+ return STATUS_UNKNOWN_ERROR;
}
};
-int main() {
+int service(const char* instance) {
ABinderProcess_setThreadPoolMaxThreadCount(0);
// Strong reference to MyFoo kept by service manager.
- binder_status_t status = (new MyFoo)->addService(IFoo::kSomeInstanceName);
+ binder_status_t status = (new MyFoo)->addService(instance);
if (status != STATUS_OK) {
- LOG(FATAL) << "Could not register: " << status;
+ LOG(FATAL) << "Could not register: " << status << " " << instance;
}
ABinderProcess_joinThreadPool();
- return 1;
+ return 1; // should not return
+}
+
+int main() {
+ if (fork() == 0) {
+ return service(IFoo::kInstanceNameToDieFor);
+ }
+
+ return service(IFoo::kSomeInstanceName);
}
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 97b4828..afa32b6 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -68,8 +68,7 @@
}
void GraphicsEnv::setAngleInfo(const std::string path, const std::string appName,
- const std::string appPref, bool developerOptIn,
- const int rulesFd, const long rulesOffset,
+ bool developerOptIn, const int rulesFd, const long rulesOffset,
const long rulesLength) {
if (!mAnglePath.empty()) {
ALOGV("ignoring attempt to change ANGLE path from '%s' to '%s'", mAnglePath.c_str(),
@@ -87,14 +86,6 @@
mAngleAppName = appName;
}
- if (!mAngleAppPref.empty()) {
- ALOGV("ignoring attempt to change ANGLE application opt-in from '%s' to '%s'",
- mAngleAppPref.c_str(), appPref.c_str());
- } else {
- ALOGV("setting ANGLE application opt-in to '%s'", appPref.c_str());
- mAngleAppPref = appPref;
- }
-
mAngleDeveloperOptIn = developerOptIn;
ALOGV("setting ANGLE rules file descriptor to '%i'", rulesFd);
@@ -128,11 +119,6 @@
return mAngleDeveloperOptIn;
}
-const char* GraphicsEnv::getAngleAppPref() {
- if (mAngleAppPref.empty()) return nullptr;
- return mAngleAppPref.c_str();
-}
-
int GraphicsEnv::getAngleRulesFd() {
return mAngleRulesFd;
}
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 528c260..20e4d66 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -44,9 +44,8 @@
// (libraries must be stored uncompressed and page aligned); such elements
// in the search path must have a '!' after the zip filename, e.g.
// /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a
- void setAngleInfo(const std::string path, const std::string appName, const std::string appPref,
- bool devOptIn, const int rulesFd, const long rulesOffset,
- const long rulesLength);
+ void setAngleInfo(const std::string path, const std::string appName, bool devOptIn,
+ const int rulesFd, const long rulesOffset, const long rulesLength);
android_namespace_t* getAngleNamespace();
const char* getAngleAppName();
const char* getAngleAppPref();
@@ -70,7 +69,6 @@
std::string mDriverPath;
std::string mAnglePath;
std::string mAngleAppName;
- std::string mAngleAppPref;
bool mAngleDeveloperOptIn;
int mAngleRulesFd;
long mAngleRulesOffset;
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 98264ac..127fcd6 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -107,6 +107,7 @@
"IProducerListener.cpp",
"ISurfaceComposer.cpp",
"ISurfaceComposerClient.cpp",
+ "ITransactionCompletedListener.cpp",
"LayerDebugInfo.cpp",
"LayerState.cpp",
"OccupancyTracker.cpp",
@@ -134,6 +135,7 @@
"libutils",
"libnativewindow",
"liblog",
+ "libinput",
"libhidlbase",
"libhidltransport",
"android.hidl.token@1.0-utils",
@@ -145,7 +147,7 @@
// bufferhub is not used when building libgui for vendors
target: {
vendor: {
- cflags: ["-DNO_BUFFERHUB"],
+ cflags: ["-DNO_BUFFERHUB", "-DNO_INPUT"],
exclude_srcs: [
"BufferHubConsumer.cpp",
"BufferHubProducer.cpp",
@@ -154,6 +156,7 @@
"libbufferhub",
"libbufferhubqueue",
"libpdx_default_transport",
+ "libinput"
],
},
},
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index accf72c..69e5379 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -634,10 +634,10 @@
if (count > data.dataSize()) {
return BAD_VALUE;
}
- ComposerState s;
Vector<ComposerState> state;
state.setCapacity(count);
for (size_t i = 0; i < count; i++) {
+ ComposerState s;
if (s.read(data) == BAD_VALUE) {
return BAD_VALUE;
}
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
new file mode 100644
index 0000000..95b1038
--- /dev/null
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ITransactionCompletedListener"
+//#define LOG_NDEBUG 0
+
+#include <gui/ITransactionCompletedListener.h>
+
+namespace android {
+
+namespace { // Anonymous
+
+enum class Tag : uint32_t {
+ ON_TRANSACTION_COMPLETED = IBinder::FIRST_CALL_TRANSACTION,
+ LAST = ON_TRANSACTION_COMPLETED,
+};
+
+} // Anonymous namespace
+
+status_t SurfaceStats::writeToParcel(Parcel* output) const {
+ status_t err = output->writeStrongBinder(surfaceControl);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ err = output->writeInt64(acquireTime);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ return output->writeBool(releasePreviousBuffer);
+}
+
+status_t SurfaceStats::readFromParcel(const Parcel* input) {
+ status_t err = input->readStrongBinder(&surfaceControl);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ err = input->readInt64(&acquireTime);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ return input->readBool(&releasePreviousBuffer);
+}
+
+status_t TransactionStats::writeToParcel(Parcel* output) const {
+ status_t err = output->writeInt64(latchTime);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ err = output->writeInt64(presentTime);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ return output->writeParcelableVector(surfaceStats);
+}
+
+status_t TransactionStats::readFromParcel(const Parcel* input) {
+ status_t err = input->readInt64(&latchTime);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ err = input->readInt64(&presentTime);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ return input->readParcelableVector(&surfaceStats);
+}
+
+status_t ListenerStats::writeToParcel(Parcel* output) const {
+ status_t err = output->writeInt32(static_cast<int32_t>(transactionStats.size()));
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ for (const auto& [callbackIds, stats] : transactionStats) {
+ err = output->writeParcelable(stats);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ err = output->writeInt64Vector(callbackIds);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t ListenerStats::readFromParcel(const Parcel* input) {
+ int32_t transactionStats_size = input->readInt32();
+
+ for (int i = 0; i < transactionStats_size; i++) {
+ TransactionStats stats;
+ std::vector<CallbackId> callbackIds;
+
+ status_t err = input->readParcelable(&stats);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ err = input->readInt64Vector(&callbackIds);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ transactionStats.emplace(callbackIds, stats);
+ }
+ return NO_ERROR;
+}
+
+ListenerStats ListenerStats::createEmpty(const sp<ITransactionCompletedListener>& listener,
+ const std::unordered_set<CallbackId>& callbackIds) {
+ ListenerStats listenerStats;
+ listenerStats.listener = listener;
+ TransactionStats transactionStats;
+ listenerStats.transactionStats.emplace(std::piecewise_construct,
+ std::forward_as_tuple(callbackIds.begin(),
+ callbackIds.end()),
+ std::forward_as_tuple(transactionStats));
+ return listenerStats;
+}
+
+class BpTransactionCompletedListener : public SafeBpInterface<ITransactionCompletedListener> {
+public:
+ explicit BpTransactionCompletedListener(const sp<IBinder>& impl)
+ : SafeBpInterface<ITransactionCompletedListener>(impl, "BpTransactionCompletedListener") {
+ }
+
+ ~BpTransactionCompletedListener() override;
+
+ void onTransactionCompleted(ListenerStats stats) override {
+ callRemoteAsync<decltype(&ITransactionCompletedListener::
+ onTransactionCompleted)>(Tag::ON_TRANSACTION_COMPLETED,
+ stats);
+ }
+};
+
+// Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see
+// clang warning -Wweak-vtables)
+BpTransactionCompletedListener::~BpTransactionCompletedListener() = default;
+
+IMPLEMENT_META_INTERFACE(TransactionCompletedListener, "android.gui.ITransactionComposerListener");
+
+status_t BnTransactionCompletedListener::onTransact(uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags) {
+ if (code < IBinder::FIRST_CALL_TRANSACTION || code > static_cast<uint32_t>(Tag::LAST)) {
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+ auto tag = static_cast<Tag>(code);
+ switch (tag) {
+ case Tag::ON_TRANSACTION_COMPLETED:
+ return callLocalAsync(data, reply,
+ &ITransactionCompletedListener::onTransactionCompleted);
+ }
+}
+
+}; // namespace android
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 2b0a461..9f30060 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -50,6 +50,9 @@
output.writeFloat(color.r);
output.writeFloat(color.g);
output.writeFloat(color.b);
+#ifndef NO_INPUT
+ inputInfo.write(output);
+#endif
output.write(transparentRegion);
output.writeUint32(transform);
output.writeBool(transformToDisplayInverse);
@@ -80,6 +83,13 @@
memcpy(output.writeInplace(16 * sizeof(float)),
colorTransform.asArray(), 16 * sizeof(float));
+ if (output.writeVectorSize(listenerCallbacks) == NO_ERROR) {
+ for (const auto& [listener, callbackIds] : listenerCallbacks) {
+ output.writeStrongBinder(IInterface::asBinder(listener));
+ output.writeInt64Vector(callbackIds);
+ }
+ }
+
return NO_ERROR;
}
@@ -113,6 +123,11 @@
color.r = input.readFloat();
color.g = input.readFloat();
color.b = input.readFloat();
+
+#ifndef NO_INPUT
+ inputInfo = InputWindowInfo::read(input);
+#endif
+
input.read(transparentRegion);
transform = input.readUint32();
transformToDisplayInverse = input.readBool();
@@ -135,6 +150,14 @@
colorTransform = mat4(static_cast<const float*>(input.readInplace(16 * sizeof(float))));
+ int32_t listenersSize = input.readInt32();
+ for (int32_t i = 0; i < listenersSize; i++) {
+ auto listener = interface_cast<ITransactionCompletedListener>(input.readStrongBinder());
+ std::vector<CallbackId> callbackIds;
+ input.readInt64Vector(&callbackIds);
+ listenerCallbacks.emplace_back(listener, callbackIds);
+ }
+
return NO_ERROR;
}
@@ -323,6 +346,17 @@
what |= eColorTransformChanged;
colorTransform = other.colorTransform;
}
+ if (other.what & eListenerCallbacksChanged) {
+ what |= eListenerCallbacksChanged;
+ listenerCallbacks = other.listenerCallbacks;
+ }
+
+#ifndef NO_INPUT
+ if (other.what & eInputInfoChanged) {
+ what |= eInputInfoChanged;
+ inputInfo = other.inputInfo;
+ }
+#endif
if ((other.what & what) != other.what) {
ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index e5a2454..87c6f27 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -25,7 +25,9 @@
#include <utils/String8.h>
#include <utils/threads.h>
+#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
#include <system/graphics.h>
@@ -40,6 +42,10 @@
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
+#ifndef NO_INPUT
+#include <input/InputWindow.h>
+#endif
+
#include <private/gui/ComposerService.h>
namespace android {
@@ -98,6 +104,61 @@
// ---------------------------------------------------------------------------
+// TransactionCompletedListener does not use ANDROID_SINGLETON_STATIC_INSTANCE because it needs
+// to be able to return a sp<> to its instance to pass to SurfaceFlinger.
+// ANDROID_SINGLETON_STATIC_INSTANCE only allows a reference to an instance.
+
+// 0 is an invalid callback id
+TransactionCompletedListener::TransactionCompletedListener() : mCallbackIdCounter(1) {}
+
+CallbackId TransactionCompletedListener::getNextIdLocked() {
+ return mCallbackIdCounter++;
+}
+
+sp<TransactionCompletedListener> TransactionCompletedListener::getInstance() {
+ static sp<TransactionCompletedListener> sInstance = new TransactionCompletedListener;
+ return sInstance;
+}
+
+sp<ITransactionCompletedListener> TransactionCompletedListener::getIInstance() {
+ return static_cast<sp<ITransactionCompletedListener>>(getInstance());
+}
+
+void TransactionCompletedListener::startListeningLocked() {
+ if (mListening) {
+ return;
+ }
+ ProcessState::self()->startThreadPool();
+ mListening = true;
+}
+
+CallbackId TransactionCompletedListener::addCallback(const TransactionCompletedCallback& callback) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ startListeningLocked();
+
+ CallbackId callbackId = getNextIdLocked();
+ mCallbacks.emplace(callbackId, callback);
+ return callbackId;
+}
+
+void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) {
+ std::lock_guard lock(mMutex);
+
+ for (const auto& [callbackIds, transactionStats] : listenerStats.transactionStats) {
+ for (auto callbackId : callbackIds) {
+ const auto& callback = mCallbacks[callbackId];
+ if (!callback) {
+ ALOGE("cannot call null callback function, skipping");
+ continue;
+ }
+ callback(transactionStats);
+ mCallbacks.erase(callbackId);
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+
SurfaceComposerClient::Transaction::Transaction(const Transaction& other) :
mForceSynchronous(other.mForceSynchronous),
mTransactionNestCount(other.mTransactionNestCount),
@@ -127,6 +188,17 @@
}
other.mDisplayStates.clear();
+ for (const auto& [listener, callbackInfo] : other.mListenerCallbacks) {
+ auto& [callbackIds, surfaceControls] = callbackInfo;
+ mListenerCallbacks[listener].callbackIds.insert(std::make_move_iterator(
+ callbackIds.begin()),
+ std::make_move_iterator(callbackIds.end()));
+ mListenerCallbacks[listener]
+ .surfaceControls.insert(std::make_move_iterator(surfaceControls.begin()),
+ std::make_move_iterator(surfaceControls.end()));
+ }
+ other.mListenerCallbacks.clear();
+
return *this;
}
@@ -137,6 +209,32 @@
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ // For every listener with registered callbacks
+ for (const auto& [listener, callbackInfo] : mListenerCallbacks) {
+ auto& [callbackIds, surfaceControls] = callbackInfo;
+ if (callbackIds.empty()) {
+ continue;
+ }
+
+ // If the listener does not have any SurfaceControls set on this Transaction, send the
+ // callback now
+ if (surfaceControls.empty()) {
+ listener->onTransactionCompleted(ListenerStats::createEmpty(listener, callbackIds));
+ }
+
+ // If the listener has any SurfaceControls set on this Transaction update the surface state
+ for (const auto& surfaceControl : surfaceControls) {
+ layer_state_t* s = getLayerState(surfaceControl);
+ if (!s) {
+ ALOGE("failed to get layer state");
+ continue;
+ }
+ s->what |= layer_state_t::eListenerCallbacksChanged;
+ s->listenerCallbacks.emplace_back(listener, std::move(callbackIds));
+ }
+ }
+ mListenerCallbacks.clear();
+
Vector<ComposerState> composerStates;
Vector<DisplayState> displayStates;
uint32_t flags = 0;
@@ -206,6 +304,11 @@
return &(mComposerStates[sc].state);
}
+void SurfaceComposerClient::Transaction::registerSurfaceControlForCallback(
+ const sp<SurfaceControl>& sc) {
+ mListenerCallbacks[TransactionCompletedListener::getIInstance()].surfaceControls.insert(sc);
+}
+
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setPosition(
const sp<SurfaceControl>& sc, float x, float y) {
layer_state_t* s = getLayerState(sc);
@@ -216,6 +319,8 @@
s->what |= layer_state_t::ePositionChanged;
s->x = x;
s->y = y;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -240,6 +345,7 @@
s->w = w;
s->h = h;
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -252,6 +358,8 @@
}
s->what |= layer_state_t::eLayerChanged;
s->z = z;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -264,6 +372,8 @@
s->what |= layer_state_t::eRelativeLayerChanged;
s->relativeLayerHandle = relativeTo;
s->z = z;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -283,6 +393,8 @@
s->flags &= ~mask;
s->flags |= (flags & mask);
s->mask |= mask;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -296,6 +408,8 @@
}
s->what |= layer_state_t::eTransparentRegionChanged;
s->transparentRegion = transparentRegion;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -308,6 +422,8 @@
}
s->what |= layer_state_t::eAlphaChanged;
s->alpha = alpha;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -320,6 +436,8 @@
}
s->what |= layer_state_t::eLayerStackChanged;
s->layerStack = layerStack;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -338,6 +456,8 @@
matrix.dsdy = dsdy;
matrix.dtdy = dtdy;
s->matrix = matrix;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -350,6 +470,8 @@
}
s->what |= layer_state_t::eCropChanged_legacy;
s->crop_legacy = crop;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -365,6 +487,8 @@
s->what |= layer_state_t::eDeferTransaction_legacy;
s->barrierHandle_legacy = handle;
s->frameNumber_legacy = frameNumber;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -380,6 +504,8 @@
s->what |= layer_state_t::eDeferTransaction_legacy;
s->barrierGbp_legacy = barrierSurface->getIGraphicBufferProducer();
s->frameNumber_legacy = frameNumber;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -393,6 +519,8 @@
}
s->what |= layer_state_t::eReparentChildren;
s->reparentHandle = newParentHandle;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -406,6 +534,8 @@
}
s->what |= layer_state_t::eReparent;
s->parentHandleForChild = newParentHandle;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -419,6 +549,8 @@
}
s->what |= layer_state_t::eColorChanged;
s->color = color;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -431,6 +563,8 @@
}
s->what |= layer_state_t::eTransformChanged;
s->transform = transform;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -444,6 +578,8 @@
}
s->what |= layer_state_t::eTransformToDisplayInverseChanged;
s->transformToDisplayInverse = transformToDisplayInverse;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -456,6 +592,8 @@
}
s->what |= layer_state_t::eCropChanged;
s->crop = crop;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -468,6 +606,8 @@
}
s->what |= layer_state_t::eBufferChanged;
s->buffer = buffer;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -480,6 +620,8 @@
}
s->what |= layer_state_t::eAcquireFenceChanged;
s->acquireFence = fence;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -492,6 +634,8 @@
}
s->what |= layer_state_t::eDataspaceChanged;
s->dataspace = dataspace;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -504,6 +648,8 @@
}
s->what |= layer_state_t::eHdrMetadataChanged;
s->hdrMetadata = hdrMetadata;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -516,6 +662,8 @@
}
s->what |= layer_state_t::eSurfaceDamageRegionChanged;
s->surfaceDamageRegion = surfaceDamageRegion;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -528,6 +676,8 @@
}
s->what |= layer_state_t::eApiChanged;
s->api = api;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -540,6 +690,22 @@
}
s->what |= layer_state_t::eSidebandStreamChanged;
s->sidebandStream = sidebandStream;
+
+ registerSurfaceControlForCallback(sc);
+ return *this;
+}
+
+SurfaceComposerClient::Transaction&
+SurfaceComposerClient::Transaction::addTransactionCompletedCallback(
+ TransactionCompletedCallbackTakesContext callback, void* callbackContext) {
+ auto listener = TransactionCompletedListener::getInstance();
+
+ auto callbackWithContext = std::bind(callback, callbackContext, std::placeholders::_1);
+
+ CallbackId callbackId = listener->addCallback(callbackWithContext);
+
+ mListenerCallbacks[TransactionCompletedListener::getIInstance()].callbackIds.emplace(
+ callbackId);
return *this;
}
@@ -550,6 +716,8 @@
mStatus = BAD_INDEX;
}
s->what |= layer_state_t::eDetachChildren;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -577,6 +745,8 @@
s->what |= layer_state_t::eOverrideScalingModeChanged;
s->overrideScalingMode = overrideScalingMode;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
@@ -588,9 +758,26 @@
return *this;
}
s->what |= layer_state_t::eGeometryAppliesWithResize;
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
+#ifndef NO_INPUT
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setInputWindowInfo(
+ const sp<SurfaceControl>& sc,
+ const InputWindowInfo& info) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+ s->inputInfo = info;
+ s->what |= layer_state_t::eInputInfoChanged;
+ return *this;
+}
+#endif
+
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::destroySurface(
const sp<SurfaceControl>& sc) {
layer_state_t* s = getLayerState(sc);
@@ -611,6 +798,8 @@
}
s->what |= layer_state_t::eColorTransformChanged;
s->colorTransform = mat4(matrix, translation);
+
+ registerSurfaceControlForCallback(sc);
return *this;
}
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
new file mode 100644
index 0000000..5c41c21
--- /dev/null
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <binder/SafeInterface.h>
+
+#include <utils/Timers.h>
+
+#include <cstdint>
+#include <unordered_map>
+#include <unordered_set>
+
+namespace android {
+
+class ITransactionCompletedListener;
+
+using CallbackId = int64_t;
+
+struct CallbackIdsHash {
+ // CallbackId vectors have several properties that let us get away with this simple hash.
+ // 1) CallbackIds are never 0 so if something has gone wrong and our CallbackId vector is
+ // empty we can still hash 0.
+ // 2) CallbackId vectors for the same listener either are identical or contain none of the
+ // same members. It is sufficient to just check the first CallbackId in the vectors. If
+ // they match, they are the same. If they do not match, they are not the same.
+ std::size_t operator()(const std::vector<CallbackId> callbackIds) const {
+ return std::hash<CallbackId>{}((callbackIds.size() == 0) ? 0 : callbackIds.front());
+ }
+};
+
+class SurfaceStats : public Parcelable {
+public:
+ status_t writeToParcel(Parcel* output) const override;
+ status_t readFromParcel(const Parcel* input) override;
+
+ SurfaceStats() = default;
+ SurfaceStats(const sp<IBinder>& sc, nsecs_t time, bool releasePrevBuffer)
+ : surfaceControl(sc), acquireTime(time), releasePreviousBuffer(releasePrevBuffer) {}
+
+ sp<IBinder> surfaceControl;
+ nsecs_t acquireTime = -1;
+ bool releasePreviousBuffer = false;
+};
+
+class TransactionStats : public Parcelable {
+public:
+ status_t writeToParcel(Parcel* output) const override;
+ status_t readFromParcel(const Parcel* input) override;
+
+ nsecs_t latchTime = -1;
+ nsecs_t presentTime = -1;
+ std::vector<SurfaceStats> surfaceStats;
+};
+
+class ListenerStats : public Parcelable {
+public:
+ status_t writeToParcel(Parcel* output) const override;
+ status_t readFromParcel(const Parcel* input) override;
+
+ static ListenerStats createEmpty(const sp<ITransactionCompletedListener>& listener,
+ const std::unordered_set<CallbackId>& callbackIds);
+
+ sp<ITransactionCompletedListener> listener;
+ std::unordered_map<std::vector<CallbackId>, TransactionStats, CallbackIdsHash> transactionStats;
+};
+
+class ITransactionCompletedListener : public IInterface {
+public:
+ DECLARE_META_INTERFACE(TransactionCompletedListener)
+
+ virtual void onTransactionCompleted(ListenerStats stats) = 0;
+};
+
+class BnTransactionCompletedListener : public SafeBnInterface<ITransactionCompletedListener> {
+public:
+ BnTransactionCompletedListener()
+ : SafeBnInterface<ITransactionCompletedListener>("BnTransactionCompletedListener") {}
+
+ status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags = 0) override;
+};
+
+class ListenerCallbacks {
+public:
+ ListenerCallbacks(const sp<ITransactionCompletedListener>& listener,
+ const std::unordered_set<CallbackId>& callbacks)
+ : transactionCompletedListener(listener),
+ callbackIds(callbacks.begin(), callbacks.end()) {}
+
+ ListenerCallbacks(const sp<ITransactionCompletedListener>& listener,
+ const std::vector<CallbackId>& ids)
+ : transactionCompletedListener(listener), callbackIds(ids) {}
+
+ sp<ITransactionCompletedListener> transactionCompletedListener;
+ std::vector<CallbackId> callbackIds;
+};
+
+} // namespace android
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index e06e2b1..cdb2309 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -23,7 +23,13 @@
#include <utils/Errors.h>
#include <gui/IGraphicBufferProducer.h>
+#include <gui/ITransactionCompletedListener.h>
#include <math/mat4.h>
+
+#ifndef NO_INPUT
+#include <input/InputWindow.h>
+#endif
+
#include <math/vec3.h>
#include <ui/GraphicTypes.h>
#include <ui/Rect.h>
@@ -74,6 +80,8 @@
eApiChanged = 0x04000000,
eSidebandStreamChanged = 0x08000000,
eColorTransformChanged = 0x10000000,
+ eListenerCallbacksChanged = 0x20000000,
+ eInputInfoChanged = 0x40000000,
};
layer_state_t()
@@ -154,6 +162,11 @@
int32_t api;
sp<NativeHandle> sidebandStream;
mat4 colorTransform;
+
+ std::vector<ListenerCallbacks> listenerCallbacks;
+#ifndef NO_INPUT
+ InputWindowInfo inputInfo;
+#endif
};
struct ComposerState {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 8ccee05..10c27b1 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -19,7 +19,9 @@
#include <stdint.h>
#include <sys/types.h>
+#include <set>
#include <unordered_map>
+#include <unordered_set>
#include <binder/IBinder.h>
@@ -33,9 +35,10 @@
#include <ui/PixelFormat.h>
#include <gui/CpuConsumer.h>
+#include <gui/ITransactionCompletedListener.h>
+#include <gui/LayerState.h>
#include <gui/SurfaceControl.h>
#include <math/vec3.h>
-#include <gui/LayerState.h>
namespace android {
@@ -49,6 +52,37 @@
// ---------------------------------------------------------------------------
+using TransactionCompletedCallbackTakesContext =
+ std::function<void(void* /*context*/, const TransactionStats&)>;
+using TransactionCompletedCallback = std::function<void(const TransactionStats&)>;
+
+class TransactionCompletedListener : public BnTransactionCompletedListener {
+ TransactionCompletedListener();
+
+ CallbackId getNextIdLocked() REQUIRES(mMutex);
+
+ std::mutex mMutex;
+
+ bool mListening GUARDED_BY(mMutex) = false;
+
+ CallbackId mCallbackIdCounter GUARDED_BY(mMutex) = 1;
+
+ std::map<CallbackId, TransactionCompletedCallback> mCallbacks GUARDED_BY(mMutex);
+
+public:
+ static sp<TransactionCompletedListener> getInstance();
+ static sp<ITransactionCompletedListener> getIInstance();
+
+ void startListeningLocked() REQUIRES(mMutex);
+
+ CallbackId addCallback(const TransactionCompletedCallback& callback);
+
+ // Overrides BnTransactionCompletedListener's onTransactionCompleted
+ void onTransactionCompleted(ListenerStats stats) override;
+};
+
+// ---------------------------------------------------------------------------
+
class SurfaceComposerClient : public RefBase
{
friend class Composer;
@@ -158,9 +192,27 @@
}
};
+ struct TCLHash {
+ std::size_t operator()(const sp<ITransactionCompletedListener>& tcl) const {
+ return std::hash<IBinder*>{}((tcl) ? IInterface::asBinder(tcl).get() : nullptr);
+ }
+ };
+
+ struct CallbackInfo {
+ // All the callbacks that have been requested for a TransactionCompletedListener in the
+ // Transaction
+ std::unordered_set<CallbackId> callbackIds;
+ // All the SurfaceControls that have been modified in this TransactionCompletedListener's
+ // process that require a callback if there is one or more callbackIds set.
+ std::unordered_set<sp<SurfaceControl>, SCHash> surfaceControls;
+ };
+
class Transaction {
std::unordered_map<sp<SurfaceControl>, ComposerState, SCHash> mComposerStates;
SortedVector<DisplayState > mDisplayStates;
+ std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash>
+ mListenerCallbacks;
+
uint32_t mForceSynchronous = 0;
uint32_t mTransactionNestCount = 0;
bool mAnimation = false;
@@ -171,6 +223,8 @@
layer_state_t* getLayerState(const sp<SurfaceControl>& sc);
DisplayState& getDisplayState(const sp<IBinder>& token);
+ void registerSurfaceControlForCallback(const sp<SurfaceControl>& sc);
+
public:
Transaction() = default;
virtual ~Transaction() = default;
@@ -250,6 +304,9 @@
Transaction& setSidebandStream(const sp<SurfaceControl>& sc,
const sp<NativeHandle>& sidebandStream);
+ Transaction& addTransactionCompletedCallback(
+ TransactionCompletedCallbackTakesContext callback, void* callbackContext);
+
// Detaches all child surfaces (and their children recursively)
// from their SurfaceControl.
// The child SurfaceControls will not throw exceptions or return errors,
@@ -273,6 +330,10 @@
// freezing the total geometry of a surface until a resize is completed.
Transaction& setGeometryAppliesWithResize(const sp<SurfaceControl>& sc);
+#ifndef NO_INPUT
+ Transaction& setInputWindowInfo(const sp<SurfaceControl>& sc, const InputWindowInfo& info);
+#endif
+
Transaction& destroySurface(const sp<SurfaceControl>& sc);
// Set a color transform matrix on the given layer on the built-in display.
@@ -349,6 +410,7 @@
};
// ---------------------------------------------------------------------------
+
}; // namespace android
#endif // ANDROID_GUI_SURFACE_COMPOSER_CLIENT_H
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 72558a6..8cb8649 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -43,12 +43,12 @@
target: {
android: {
srcs: [
- "IInputFlinger.cpp",
"InputTransport.cpp",
"VelocityControl.cpp",
"VelocityTracker.cpp",
"InputApplication.cpp",
- "InputWindow.cpp"
+ "InputWindow.cpp",
+ "IInputFlinger.cpp"
],
shared_libs: [
diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp
index 003e73d..47a2c0c 100644
--- a/libs/input/IInputFlinger.cpp
+++ b/libs/input/IInputFlinger.cpp
@@ -23,7 +23,6 @@
#include <input/IInputFlinger.h>
-
namespace android {
class BpInputFlinger : public BpInterface<IInputFlinger> {
@@ -31,23 +30,35 @@
explicit BpInputFlinger(const sp<IBinder>& impl) :
BpInterface<IInputFlinger>(impl) { }
- virtual status_t doSomething() {
+ virtual void setInputWindows(const Vector<InputWindowInfo>& inputInfo) {
Parcel data, reply;
data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
- remote()->transact(BnInputFlinger::DO_SOMETHING_TRANSACTION, data, &reply);
- return reply.readInt32();
+
+ data.writeUint32(static_cast<uint32_t>(inputInfo.size()));
+ for (const auto& info : inputInfo) {
+ info.write(data);
+ }
+ remote()->transact(BnInputFlinger::SET_INPUT_WINDOWS_TRANSACTION, data, &reply);
}
};
IMPLEMENT_META_INTERFACE(InputFlinger, "android.input.IInputFlinger");
-
status_t BnInputFlinger::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
switch(code) {
- case DO_SOMETHING_TRANSACTION: {
+ case SET_INPUT_WINDOWS_TRANSACTION: {
CHECK_INTERFACE(IInputFlinger, data, reply);
- reply->writeInt32(0);
+ size_t count = data.readUint32();
+ if (count > data.dataSize()) {
+ return BAD_VALUE;
+ }
+ Vector<InputWindowInfo> handles;
+ handles.setCapacity(count);
+ for (size_t i = 0; i < count; i++) {
+ handles.add(InputWindowInfo(data));
+ }
+ setInputWindows(handles);
break;
}
default:
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 32444f9..e93f3a4 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -247,6 +247,10 @@
if (s != OK) {
return s;
}
+ s = out.writeStrongBinder(mToken);
+ if (s != OK) {
+ return s;
+ }
s = out.writeDupFileDescriptor(getFd());
@@ -255,6 +259,7 @@
status_t InputChannel::read(const Parcel& from) {
mName = from.readString8();
+ mToken = from.readStrongBinder();
int rawFd = from.readFileDescriptor();
setFd(::dup(rawFd));
@@ -266,6 +271,17 @@
return OK;
}
+sp<IBinder> InputChannel::getToken() const {
+ return mToken;
+}
+
+void InputChannel::setToken(const sp<IBinder>& token) {
+ if (mToken != nullptr) {
+ ALOGE("Assigning InputChannel (%s) a second handle?", mName.c_str());
+ }
+ mToken = token;
+}
+
// --- InputPublisher ---
InputPublisher::InputPublisher(const sp<InputChannel>& channel) :
diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp
index f94faba..f82437e 100644
--- a/libs/input/InputWindow.cpp
+++ b/libs/input/InputWindow.cpp
@@ -135,25 +135,25 @@
return ret;
}
+InputWindowInfo::InputWindowInfo(const Parcel& from) {
+ *this = read(from);
+}
+
// --- InputWindowHandle ---
InputWindowHandle::InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) :
- inputApplicationHandle(inputApplicationHandle), mInfo(nullptr) {
+ inputApplicationHandle(inputApplicationHandle) {
}
InputWindowHandle::~InputWindowHandle() {
- delete mInfo;
}
-void InputWindowHandle::releaseInfo() {
- if (mInfo) {
- delete mInfo;
- mInfo = nullptr;
- }
+void InputWindowHandle::releaseChannel() {
+ mInfo.inputChannel.clear();
}
sp<InputChannel> InputWindowHandle::getInputChannel() const {
- return mInfo ? mInfo->inputChannel : nullptr;
+ return mInfo.inputChannel;
}
} // namespace android
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index 1bbd82b..42d774e 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -327,8 +327,8 @@
eventTime = event->getHistoricalEventTime(h);
for (size_t i = 0; i < pointerCount; i++) {
uint32_t index = pointerIndex[i];
- positions[index].x = event->getHistoricalRawX(i, h);
- positions[index].y = event->getHistoricalRawY(i, h);
+ positions[index].x = event->getHistoricalX(i, h);
+ positions[index].y = event->getHistoricalY(i, h);
}
addMovement(eventTime, idBits, positions);
}
@@ -336,8 +336,8 @@
eventTime = event->getEventTime();
for (size_t i = 0; i < pointerCount; i++) {
uint32_t index = pointerIndex[i];
- positions[index].x = event->getRawX(i);
- positions[index].y = event->getRawY(i);
+ positions[index].x = event->getX(i);
+ positions[index].y = event->getY(i);
}
addMovement(eventTime, idBits, positions);
}
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 647fe86..fba319d 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -47,6 +47,7 @@
cflags: [
"-Wall",
"-Werror",
+ "-Wno-enum-compare",
"-Wno-unused-function",
],
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index 9ca4941..23ac60b 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -15,12 +15,31 @@
*/
/**
- * @addtogroup NativeActivity Native Activity
- * @{
- */
-
-/**
* @file hardware_buffer.h
+ * @brief API for native hardware buffers.
+ */
+/**
+ * @defgroup AHardwareBuffer Native Hardware Buffer
+ *
+ * AHardwareBuffer objects represent chunks of memory that can be
+ * accessed by various hardware components in the system. It can be
+ * easily converted to the Java counterpart
+ * android.hardware.HardwareBuffer and passed between processes using
+ * Binder. All operations involving AHardwareBuffer and HardwareBuffer
+ * are zero-copy, i.e., passing AHardwareBuffer to another process
+ * creates a shared view of the same region of memory.
+ *
+ * AHardwareBuffers can be bound to EGL/OpenGL and Vulkan primitives.
+ * For EGL, use the extension function eglGetNativeClientBufferANDROID
+ * to obtain an EGLClientBuffer and pass it directly to
+ * eglCreateImageKHR. Refer to the EGL extensions
+ * EGL_ANDROID_get_native_client_buffer and
+ * EGL_ANDROID_image_native_buffer for more information. In Vulkan,
+ * the contents of the AHardwareBuffer can be accessed as external
+ * memory. See the VK_ANDROID_external_memory_android_hardware_buffer
+ * extension for details.
+ *
+ * @{
*/
#ifndef ANDROID_HARDWARE_BUFFER_H
@@ -37,7 +56,7 @@
/**
* Buffer pixel formats.
*/
-enum {
+enum AHardwareBuffer_Format {
/**
* Corresponding formats:
* Vulkan: VK_FORMAT_R8G8B8A8_UNORM
@@ -134,27 +153,47 @@
/**
* Buffer usage flags, specifying how the buffer will be accessed.
*/
-enum {
- /// The buffer will never be read by the CPU.
+enum AHardwareBuffer_UsageFlags {
+ /// The buffer will never be locked for direct CPU reads using the
+ /// AHardwareBuffer_lock() function. Note that reading the buffer
+ /// using OpenGL or Vulkan functions or memory mappings is still
+ /// allowed.
AHARDWAREBUFFER_USAGE_CPU_READ_NEVER = 0UL,
- /// The buffer will sometimes be read by the CPU.
+ /// The buffer will sometimes be locked for direct CPU reads using
+ /// the AHardwareBuffer_lock() function. Note that reading the
+ /// buffer using OpenGL or Vulkan functions or memory mappings
+ /// does not require the presence of this flag.
AHARDWAREBUFFER_USAGE_CPU_READ_RARELY = 2UL,
- /// The buffer will often be read by the CPU.
+ /// The buffer will often be locked for direct CPU reads using
+ /// the AHardwareBuffer_lock() function. Note that reading the
+ /// buffer using OpenGL or Vulkan functions or memory mappings
+ /// does not require the presence of this flag.
AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN = 3UL,
/// CPU read value mask.
AHARDWAREBUFFER_USAGE_CPU_READ_MASK = 0xFUL,
- /// The buffer will never be written by the CPU.
+ /// The buffer will never be locked for direct CPU writes using the
+ /// AHardwareBuffer_lock() function. Note that writing the buffer
+ /// using OpenGL or Vulkan functions or memory mappings is still
+ /// allowed.
AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER = 0UL << 4,
- /// The buffer will sometimes be written to by the CPU.
+ /// The buffer will sometimes be locked for direct CPU writes using
+ /// the AHardwareBuffer_lock() function. Note that writing the
+ /// buffer using OpenGL or Vulkan functions or memory mappings
+ /// does not require the presence of this flag.
AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY = 2UL << 4,
- /// The buffer will often be written to by the CPU.
+ /// The buffer will often be locked for direct CPU writes using
+ /// the AHardwareBuffer_lock() function. Note that writing the
+ /// buffer using OpenGL or Vulkan functions or memory mappings
+ /// does not require the presence of this flag.
AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN = 3UL << 4,
/// CPU write value mask.
AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK = 0xFUL << 4,
/// The buffer will be read from by the GPU as a texture.
AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE = 1UL << 8,
+ /// The buffer will be written to by the GPU as a framebuffer attachment.
+ AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER = 1UL << 9,
/**
* The buffer will be written to by the GPU as a framebuffer attachment.
* Note that the name of this flag is somewhat misleading: it does not imply
@@ -162,16 +201,33 @@
* format that will be used as a framebuffer attachment should also have
* this flag.
*/
- AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT = 1UL << 9,
- /// The buffer must not be used outside of a protected hardware path.
+ AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT = AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER,
+ /**
+ * The buffer is protected from direct CPU access or being read by non-secure
+ * hardware, such as video encoders. This flag is incompatible with CPU
+ * read and write flags. It is mainly used when handling DRM video.
+ * Refer to the EGL extension EGL_EXT_protected_content and GL extension
+ * EXT_protected_textures for more information on how these buffers are expected
+ * to behave.
+ */
AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT = 1UL << 14,
/// The buffer will be read by a hardware video encoder.
AHARDWAREBUFFER_USAGE_VIDEO_ENCODE = 1UL << 16,
- /// The buffer will be used for direct writes from sensors.
+ /**
+ * The buffer will be used for direct writes from sensors.
+ * When this flag is present, the format must be AHARDWAREBUFFER_FORMAT_BLOB.
+ */
AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA = 1UL << 23,
- /// The buffer will be used as a shader storage or uniform buffer object.
+ /**
+ * The buffer will be used as a shader storage or uniform buffer object.
+ * When this flag is present, the format must be AHARDWAREBUFFER_FORMAT_BLOB.
+ */
AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER = 1UL << 24,
- /// The buffer will be used as a cube map texture.
+ /**
+ * The buffer will be used as a cube map texture.
+ * When this flag is present, the buffer must have a layer count that is
+ * a multiple of 6.
+ */
AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP = 1UL << 25,
/// The buffer contains a complete mipmap hierarchy.
AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE = 1UL << 26,
@@ -206,20 +262,27 @@
uint32_t width; ///< Width in pixels.
uint32_t height; ///< Height in pixels.
uint32_t layers; ///< Number of images in an image array.
- uint32_t format; ///< One of AHARDWAREBUFFER_FORMAT_*
- uint64_t usage; ///< Combination of AHARDWAREBUFFER_USAGE_*
+ uint32_t format; ///< One of AHardwareBuffer_Format.
+ uint64_t usage; ///< Combination of AHardwareBuffer_UsageFlags.
uint32_t stride; ///< Row stride in pixels, ignored for AHardwareBuffer_allocate()
uint32_t rfu0; ///< Initialize to zero, reserved for future use.
uint64_t rfu1; ///< Initialize to zero, reserved for future use.
} AHardwareBuffer_Desc;
+/**
+ * Opaque handle for a native hardware buffer.
+ */
typedef struct AHardwareBuffer AHardwareBuffer;
#if __ANDROID_API__ >= 26
/**
- * Allocates a buffer that backs an AHardwareBuffer using the passed
- * AHardwareBuffer_Desc.
+ * Allocates a buffer that matches the passed AHardwareBuffer_Desc.
+ *
+ * If allocation succeeds, the buffer can be used according to the
+ * usage flags specified in its description. If a buffer is used in ways
+ * not compatible with its usage flags, the results are undefined and
+ * may include program termination.
*
* \return 0 on success, or an error number of the allocation fails for
* any reason. The returned buffer has a reference count of 1.
@@ -234,7 +297,7 @@
/**
* Remove a reference that was previously acquired with
- * AHardwareBuffer_acquire().
+ * AHardwareBuffer_acquire() or AHardwareBuffer_allocate().
*/
void AHardwareBuffer_release(AHardwareBuffer* buffer) __INTRODUCED_IN(26);
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index 6831f91..6730596 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -15,7 +15,13 @@
*/
/**
- * @addtogroup NativeActivity Native Activity
+ * @defgroup ANativeWindow Native Window
+ *
+ * ANativeWindow represents the producer end of an image queue.
+ * It is the C counterpart of the android.view.Surface object in Java,
+ * and can be converted both ways. Depending on the consumer, images
+ * submitted to ANativeWindow can be shown on the display or sent to
+ * other consumers, such as video encoders.
* @{
*/
@@ -41,7 +47,7 @@
* Legacy window pixel format names, kept for backwards compatibility.
* New code and APIs should use AHARDWAREBUFFER_FORMAT_*.
*/
-enum {
+enum ANativeWindow_LegacyFormat {
// NOTE: these values must match the values from graphics/common/x.x/types.hal
/** Red: 8 bits, Green: 8 bits, Blue: 8 bits, Alpha: 8 bits. **/
@@ -95,7 +101,7 @@
/// memory. This may be >= width.
int32_t stride;
- /// The format of the buffer. One of AHARDWAREBUFFER_FORMAT_*
+ /// The format of the buffer. One of AHardwareBuffer_Format.
int32_t format;
/// The actual bits.
@@ -151,7 +157,7 @@
*
* \param width width of the buffers in pixels.
* \param height height of the buffers in pixels.
- * \param format one of AHARDWAREBUFFER_FORMAT_* constants.
+ * \param format one of the AHardwareBuffer_Format constants.
* \return 0 for success, or a negative value on error.
*/
int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window,
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 5a1ddee..29deb01 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -64,12 +64,11 @@
{
}
-GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
- PixelFormat inFormat, uint32_t inLayerCount, uint64_t usage, std::string requestorName)
- : GraphicBuffer()
-{
- mInitCheck = initWithSize(inWidth, inHeight, inFormat, inLayerCount,
- usage, std::move(requestorName));
+GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
+ uint32_t inLayerCount, uint64_t inUsage, std::string requestorName)
+ : GraphicBuffer() {
+ mInitCheck = initWithSize(inWidth, inHeight, inFormat, inLayerCount, inUsage,
+ std::move(requestorName));
}
// deprecated
@@ -82,15 +81,12 @@
{
}
-GraphicBuffer::GraphicBuffer(const native_handle_t* handle,
- HandleWrapMethod method, uint32_t width, uint32_t height,
- PixelFormat format, uint32_t layerCount,
- uint64_t usage,
- uint32_t stride)
- : GraphicBuffer()
-{
- mInitCheck = initWithHandle(handle, method, width, height, format,
- layerCount, usage, stride);
+GraphicBuffer::GraphicBuffer(const native_handle_t* inHandle, HandleWrapMethod method,
+ uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
+ uint32_t inLayerCount, uint64_t inUsage, uint32_t inStride)
+ : GraphicBuffer() {
+ mInitCheck = initWithHandle(inHandle, method, inWidth, inHeight, inFormat, inLayerCount,
+ inUsage, inStride);
}
GraphicBuffer::~GraphicBuffer()
@@ -182,26 +178,24 @@
return err;
}
-status_t GraphicBuffer::initWithHandle(const native_handle_t* handle,
- HandleWrapMethod method, uint32_t width, uint32_t height,
- PixelFormat format, uint32_t layerCount, uint64_t usage,
- uint32_t stride)
-{
- ANativeWindowBuffer::width = static_cast<int>(width);
- ANativeWindowBuffer::height = static_cast<int>(height);
- ANativeWindowBuffer::stride = static_cast<int>(stride);
- ANativeWindowBuffer::format = format;
- ANativeWindowBuffer::usage = usage;
- ANativeWindowBuffer::usage_deprecated = int(usage);
+status_t GraphicBuffer::initWithHandle(const native_handle_t* inHandle, HandleWrapMethod method,
+ uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
+ uint32_t inLayerCount, uint64_t inUsage, uint32_t inStride) {
+ ANativeWindowBuffer::width = static_cast<int>(inWidth);
+ ANativeWindowBuffer::height = static_cast<int>(inHeight);
+ ANativeWindowBuffer::stride = static_cast<int>(inStride);
+ ANativeWindowBuffer::format = inFormat;
+ ANativeWindowBuffer::usage = inUsage;
+ ANativeWindowBuffer::usage_deprecated = int(inUsage);
- ANativeWindowBuffer::layerCount = layerCount;
+ ANativeWindowBuffer::layerCount = inLayerCount;
mOwner = (method == WRAP_HANDLE) ? ownNone : ownHandle;
if (method == TAKE_UNREGISTERED_HANDLE || method == CLONE_HANDLE) {
buffer_handle_t importedHandle;
- status_t err = mBufferMapper.importBuffer(handle, width, height,
- layerCount, format, usage, stride, &importedHandle);
+ status_t err = mBufferMapper.importBuffer(inHandle, inWidth, inHeight, inLayerCount,
+ inFormat, inUsage, inStride, &importedHandle);
if (err != NO_ERROR) {
initWithHandle(nullptr, WRAP_HANDLE, 0, 0, 0, 0, 0, 0);
@@ -209,15 +203,15 @@
}
if (method == TAKE_UNREGISTERED_HANDLE) {
- native_handle_close(handle);
- native_handle_delete(const_cast<native_handle_t*>(handle));
+ native_handle_close(inHandle);
+ native_handle_delete(const_cast<native_handle_t*>(inHandle));
}
- handle = importedHandle;
- mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts);
+ inHandle = importedHandle;
+ mBufferMapper.getTransportSize(inHandle, &mTransportNumFds, &mTransportNumInts);
}
- ANativeWindowBuffer::handle = handle;
+ ANativeWindowBuffer::handle = inHandle;
return NO_ERROR;
}
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index e794462..fe6229a 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -117,18 +117,16 @@
// cannot be used directly, such as one from hidl_handle.
CLONE_HANDLE,
};
- GraphicBuffer(const native_handle_t* handle, HandleWrapMethod method,
- uint32_t width, uint32_t height,
- PixelFormat format, uint32_t layerCount,
- uint64_t usage, uint32_t stride);
+ GraphicBuffer(const native_handle_t* inHandle, HandleWrapMethod method, uint32_t inWidth,
+ uint32_t inHeight, PixelFormat inFormat, uint32_t inLayerCount, uint64_t inUsage,
+ uint32_t inStride);
// These functions are deprecated because they only take 32 bits of usage
- GraphicBuffer(const native_handle_t* handle, HandleWrapMethod method,
- uint32_t width, uint32_t height,
- PixelFormat format, uint32_t layerCount,
- uint32_t usage, uint32_t stride)
- : GraphicBuffer(handle, method, width, height, format, layerCount,
- static_cast<uint64_t>(usage), stride) {}
+ GraphicBuffer(const native_handle_t* inHandle, HandleWrapMethod method, uint32_t inWidth,
+ uint32_t inHeight, PixelFormat inFormat, uint32_t inLayerCount, uint32_t inUsage,
+ uint32_t inStride)
+ : GraphicBuffer(inHandle, method, inWidth, inHeight, inFormat, inLayerCount,
+ static_cast<uint64_t>(inUsage), inStride) {}
GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
uint32_t inLayerCount, uint32_t inUsage, uint32_t inStride,
native_handle_t* inHandle, bool keepOwnership);
@@ -220,10 +218,9 @@
PixelFormat inFormat, uint32_t inLayerCount,
uint64_t inUsage, std::string requestorName);
- status_t initWithHandle(const native_handle_t* handle,
- HandleWrapMethod method, uint32_t width, uint32_t height,
- PixelFormat format, uint32_t layerCount,
- uint64_t usage, uint32_t stride);
+ status_t initWithHandle(const native_handle_t* inHandle, HandleWrapMethod method,
+ uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
+ uint32_t inLayerCount, uint64_t inUsage, uint32_t inStride);
void free_handle();
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 1521e1d..4c9c176 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -32,7 +32,8 @@
name: "BufferHubBuffer_test",
header_libs: [
"libbufferhub_headers",
- "libdvr_headers"
+ "libdvr_headers",
+ "libnativewindow_headers",
],
shared_libs: [
"android.frameworks.bufferhub@1.0",
diff --git a/libs/ui/tests/BufferHubBuffer_test.cpp b/libs/ui/tests/BufferHubBuffer_test.cpp
index a247e60..6af8033 100644
--- a/libs/ui/tests/BufferHubBuffer_test.cpp
+++ b/libs/ui/tests/BufferHubBuffer_test.cpp
@@ -16,7 +16,9 @@
#define LOG_TAG "BufferHubBufferTest"
+#include <android/frameworks/bufferhub/1.0/IBufferClient.h>
#include <android/frameworks/bufferhub/1.0/IBufferHub.h>
+#include <android/hardware_buffer.h>
#include <gtest/gtest.h>
#include <hidl/ServiceManagement.h>
#include <hwbinder/IPCThreadState.h>
@@ -33,13 +35,14 @@
const int kUsage = 0;
const size_t kUserMetadataSize = 0;
-} // namespace
-
using dvr::BufferHubDefs::IsBufferGained;
using dvr::BufferHubDefs::kFirstClientBitMask;
using dvr::BufferHubDefs::kMetadataHeaderSize;
+using frameworks::bufferhub::V1_0::BufferHubStatus;
+using frameworks::bufferhub::V1_0::IBufferClient;
using frameworks::bufferhub::V1_0::IBufferHub;
using hardware::hidl_handle;
+using hardware::graphics::common::V1_2::HardwareBufferDescription;
using hidl::base::V1_0::IBase;
using pdx::LocalChannelHandle;
@@ -123,14 +126,51 @@
return;
}
-TEST_F(BufferHubBufferTest, ConnectHidlServer) {
+TEST_F(BufferHubBufferTest, AllocateBuffer) {
+ // TODO(b/116681016): directly test on BufferHubBuffer instead of the service.
+ sp<IBufferHub> bufferHub = IBufferHub::getService();
+ ASSERT_NE(nullptr, bufferHub.get());
+
+ // Stride is an output, rfu0 and rfu1 are reserved data slot for future use.
+ AHardwareBuffer_Desc aDesc = {kWidth, kHeight, kLayerCount, kFormat,
+ kUsage, /*stride=*/0UL, /*rfu0=*/0UL, /*rfu1=*/0ULL};
+ HardwareBufferDescription desc;
+ memcpy(&desc, &aDesc, sizeof(HardwareBufferDescription));
+
+ IBufferHub::allocateBuffer_cb callback = [](const auto& client, const auto& status) {
+ EXPECT_EQ(status, BufferHubStatus::NO_ERROR);
+ EXPECT_NE(nullptr, client.get());
+ };
+ EXPECT_TRUE(bufferHub->allocateBuffer(desc, kUserMetadataSize, callback).isOk());
+}
+
+TEST_F(BufferHubBufferTest, DuplicateBuffer) {
+ // TODO(b/116681016): directly test on BufferHubBuffer instead of the service.
sp<IBufferHub> bufferhub = IBufferHub::getService();
ASSERT_NE(nullptr, bufferhub.get());
- // TODO(b/116681016): Fill in real test once the interface gets implemented..
- hidl_handle handle;
- sp<IBase> interface = bufferhub->importBuffer(handle);
- EXPECT_EQ(nullptr, interface.get());
+ // Stride is an output, rfu0 and rfu1 are reserved data slot for future use.
+ AHardwareBuffer_Desc aDesc = {kWidth, kHeight, kLayerCount, kFormat,
+ kUsage, /*stride=*/0UL, /*rfu0=*/0UL, /*rfu1=*/0ULL};
+ HardwareBufferDescription desc;
+ memcpy(&desc, &aDesc, sizeof(HardwareBufferDescription));
+
+ sp<IBufferClient> client;
+ IBufferHub::allocateBuffer_cb alloc_cb = [&](const auto& outClient, const auto& status) {
+ ASSERT_EQ(status, BufferHubStatus::NO_ERROR);
+ ASSERT_NE(nullptr, outClient.get());
+ client = outClient;
+ };
+ ASSERT_TRUE(bufferhub->allocateBuffer(desc, kUserMetadataSize, alloc_cb).isOk());
+
+ IBufferClient::duplicate_cb dup_cb = [](const auto& token, const auto& status) {
+ ASSERT_EQ(status, BufferHubStatus::NO_ERROR);
+ ASSERT_NE(token.getNativeHandle(), nullptr);
+ EXPECT_EQ(token->numInts, 1);
+ EXPECT_EQ(token->numFds, 0);
+ };
+ EXPECT_TRUE(client->duplicate(dup_cb).isOk());
}
+} // namespace
} // namespace android
diff --git a/libs/vr/CleanSpec.mk b/libs/vr/CleanSpec.mk
deleted file mode 100644
index a17c9b2..0000000
--- a/libs/vr/CleanSpec.mk
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright (C) 2012 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-# If you don't need to do a full clean build but would like to touch
-# a file or delete some intermediate files, add a clean step to the end
-# of the list. These steps will only be run once, if they haven't been
-# run before.
-#
-# E.g.:
-# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
-# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
-#
-# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
-# files that are missing or have been moved.
-#
-# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
-# Use $(OUT_DIR) to refer to the "out" directory.
-#
-# If you need to re-do something that's already mentioned, just copy
-# the command and add it to the bottom of the list. E.g., if a change
-# that you made last week required touching a file and a change you
-# made today requires touching the same file, just copy the old
-# touch step and add it to the end of the list.
-#
-# ************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
-
-# For example:
-#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
-#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
-#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
-#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
-
-# ************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
-# ************************************************
-$(call add-clean-step, find $(PRODUCT_OUT) -type f -name "libdvr.so" -print0 | xargs -0 rm -f)
-$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libdvr_intermediates)
-$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libdvr_intermediates)
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index e1c1aa9..f7942d0 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -69,7 +69,7 @@
.data = {.u64 = Stuff(-1, BufferHubQueue::kEpollQueueEventIndex)}};
ret = epoll_fd_.Control(EPOLL_CTL_ADD, event_fd(), &event);
if (ret < 0) {
- ALOGE("BufferHubQueue::Initialize: Failed to add event fd to epoll set: %s",
+ ALOGE("%s: Failed to add event fd to epoll set: %s", __FUNCTION__,
strerror(-ret));
}
}
@@ -77,7 +77,7 @@
Status<void> BufferHubQueue::ImportQueue() {
auto status = InvokeRemoteMethod<BufferHubRPC::GetQueueInfo>();
if (!status) {
- ALOGE("BufferHubQueue::ImportQueue: Failed to import queue: %s",
+ ALOGE("%s: Failed to import queue: %s", __FUNCTION__,
status.GetErrorMessage().c_str());
return ErrorStatus(status.error());
} else {
@@ -136,9 +136,7 @@
consumer_queue->GetChannel()->TakeChannelParcelable());
if (!queue_parcelable.IsValid()) {
- ALOGE(
- "BufferHubQueue::CreateConsumerQueueParcelable: Failed to create "
- "consumer queue parcelable.");
+ ALOGE("%s: Failed to create consumer queue parcelable.", __FUNCTION__);
return ErrorStatus(EINVAL);
}
@@ -169,8 +167,7 @@
}
if (ret < 0 && ret != -EINTR) {
- ALOGE("BufferHubQueue::WaitForBuffers: Failed to wait for buffers: %s",
- strerror(-ret));
+ ALOGE("%s: Failed to wait for buffers: %s", __FUNCTION__, strerror(-ret));
return false;
}
@@ -264,14 +261,14 @@
// wait will be tried again to acquire the newly imported buffer.
auto buffer_status = OnBufferAllocated();
if (!buffer_status) {
- ALOGE("BufferHubQueue::HandleQueueEvent: Failed to import buffer: %s",
+ ALOGE("%s: Failed to import buffer: %s", __FUNCTION__,
buffer_status.GetErrorMessage().c_str());
}
} else if (events & EPOLLHUP) {
- ALOGD_IF(TRACE, "BufferHubQueue::HandleQueueEvent: hang up event!");
+ ALOGD_IF(TRACE, "%s: hang up event!", __FUNCTION__);
hung_up_ = true;
} else {
- ALOGW("BufferHubQueue::HandleQueueEvent: Unknown epoll events=%x", events);
+ ALOGW("%s: Unknown epoll events=%x", __FUNCTION__, events);
}
return {};
@@ -279,12 +276,11 @@
Status<void> BufferHubQueue::AddBuffer(
const std::shared_ptr<BufferHubBase>& buffer, size_t slot) {
- ALOGD_IF(TRACE, "BufferHubQueue::AddBuffer: buffer_id=%d slot=%zu",
- buffer->id(), slot);
+ ALOGD_IF(TRACE, "%s: buffer_id=%d slot=%zu", __FUNCTION__, buffer->id(),
+ slot);
if (is_full()) {
- ALOGE("BufferHubQueue::AddBuffer queue is at maximum capacity: %zu",
- capacity_);
+ ALOGE("%s: queue is at maximum capacity: %zu", __FUNCTION__, capacity_);
return ErrorStatus(E2BIG);
}
@@ -303,7 +299,7 @@
const int ret =
epoll_fd_.Control(EPOLL_CTL_ADD, event_source.event_fd, &event);
if (ret < 0) {
- ALOGE("BufferHubQueue::AddBuffer: Failed to add buffer to epoll set: %s",
+ ALOGE("%s: Failed to add buffer to epoll set: %s", __FUNCTION__,
strerror(-ret));
return ErrorStatus(-ret);
}
@@ -315,17 +311,15 @@
}
Status<void> BufferHubQueue::RemoveBuffer(size_t slot) {
- ALOGD_IF(TRACE, "BufferHubQueue::RemoveBuffer: slot=%zu", slot);
+ ALOGD_IF(TRACE, "%s: slot=%zu", __FUNCTION__, slot);
if (buffers_[slot]) {
for (const auto& event_source : buffers_[slot]->GetEventSources()) {
const int ret =
epoll_fd_.Control(EPOLL_CTL_DEL, event_source.event_fd, nullptr);
if (ret < 0) {
- ALOGE(
- "BufferHubQueue::RemoveBuffer: Failed to remove buffer from epoll "
- "set: %s",
- strerror(-ret));
+ ALOGE("%s: Failed to remove buffer from epoll set: %s", __FUNCTION__,
+ strerror(-ret));
return ErrorStatus(-ret);
}
}
@@ -343,6 +337,15 @@
Status<void> BufferHubQueue::Enqueue(Entry entry) {
if (!is_full()) {
+ // Find and remove the enqueued buffer from unavailable_buffers_slot if
+ // exist.
+ auto enqueued_buffer_iter = std::find_if(
+ unavailable_buffers_slot_.begin(), unavailable_buffers_slot_.end(),
+ [&entry](size_t slot) -> bool { return slot == entry.slot; });
+ if (enqueued_buffer_iter != unavailable_buffers_slot_.end()) {
+ unavailable_buffers_slot_.erase(enqueued_buffer_iter);
+ }
+
available_buffers_.push(std::move(entry));
// Trigger OnBufferAvailable callback if registered.
@@ -351,17 +354,16 @@
return {};
} else {
- ALOGE("BufferHubQueue::Enqueue: Buffer queue is full!");
+ ALOGE("%s: Buffer queue is full!", __FUNCTION__);
return ErrorStatus(E2BIG);
}
}
Status<std::shared_ptr<BufferHubBase>> BufferHubQueue::Dequeue(int timeout,
size_t* slot) {
- ALOGD_IF(TRACE, "BufferHubQueue::Dequeue: count=%zu, timeout=%d", count(),
- timeout);
+ ALOGD_IF(TRACE, "%s: count=%zu, timeout=%d", __FUNCTION__, count(), timeout);
- PDX_TRACE_FORMAT("BufferHubQueue::Dequeue|count=%zu|", count());
+ PDX_TRACE_FORMAT("%s|count=%zu|", __FUNCTION__, count());
if (count() == 0) {
if (!WaitForBuffers(timeout))
@@ -376,6 +378,7 @@
*slot = entry.slot;
available_buffers_.pop();
+ unavailable_buffers_slot_.push_back(*slot);
return {std::move(buffer)};
}
@@ -564,7 +567,7 @@
auto status =
InvokeRemoteMethod<BufferHubRPC::ProducerQueueRemoveBuffer>(slot);
if (!status) {
- ALOGE("ProducerQueue::RemoveBuffer: Failed to remove producer buffer: %s",
+ ALOGE("%s: Failed to remove producer buffer: %s", __FUNCTION__,
status.GetErrorMessage().c_str());
return status.error_status();
}
@@ -580,31 +583,81 @@
pdx::Status<std::shared_ptr<BufferProducer>> ProducerQueue::Dequeue(
int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta,
- pdx::LocalHandle* release_fence) {
+ pdx::LocalHandle* release_fence, bool gain_posted_buffer) {
ATRACE_NAME("ProducerQueue::Dequeue");
if (slot == nullptr || out_meta == nullptr || release_fence == nullptr) {
- ALOGE("ProducerQueue::Dequeue: Invalid parameter.");
+ ALOGE("%s: Invalid parameter.", __FUNCTION__);
return ErrorStatus(EINVAL);
}
- auto status = BufferHubQueue::Dequeue(timeout, slot);
- if (!status)
- return status.error_status();
-
- auto buffer = std::static_pointer_cast<BufferProducer>(status.take());
- const int ret = buffer->GainAsync(out_meta, release_fence);
+ std::shared_ptr<BufferProducer> buffer;
+ Status<std::shared_ptr<BufferHubBase>> dequeue_status =
+ BufferHubQueue::Dequeue(timeout, slot);
+ if (dequeue_status.ok()) {
+ buffer = std::static_pointer_cast<BufferProducer>(dequeue_status.take());
+ } else {
+ if (gain_posted_buffer) {
+ Status<std::shared_ptr<BufferProducer>> dequeue_unacquired_status =
+ ProducerQueue::DequeueUnacquiredBuffer(slot);
+ if (!dequeue_unacquired_status.ok()) {
+ ALOGE("%s: DequeueUnacquiredBuffer returned error: %d", __FUNCTION__,
+ dequeue_unacquired_status.error());
+ return dequeue_unacquired_status.error_status();
+ }
+ buffer = dequeue_unacquired_status.take();
+ } else {
+ return dequeue_status.error_status();
+ }
+ }
+ const int ret =
+ buffer->GainAsync(out_meta, release_fence, gain_posted_buffer);
if (ret < 0 && ret != -EALREADY)
return ErrorStatus(-ret);
return {std::move(buffer)};
}
+Status<std::shared_ptr<BufferProducer>> ProducerQueue::DequeueUnacquiredBuffer(
+ size_t* slot) {
+ if (unavailable_buffers_slot_.size() < 1) {
+ ALOGE(
+ "%s: Failed to dequeue un-acquired buffer. All buffer(s) are in "
+ "acquired state if exist.",
+ __FUNCTION__);
+ return ErrorStatus(ENOMEM);
+ }
+
+ // Find the first buffer that is not in acquired state from
+ // unavailable_buffers_slot_.
+ for (auto iter = unavailable_buffers_slot_.begin();
+ iter != unavailable_buffers_slot_.end(); iter++) {
+ std::shared_ptr<BufferProducer> buffer = ProducerQueue::GetBuffer(*iter);
+ if (buffer == nullptr) {
+ ALOGE("%s failed. Buffer slot %d is null.", __FUNCTION__,
+ static_cast<int>(*slot));
+ return ErrorStatus(EIO);
+ }
+ if (!BufferHubDefs::IsBufferAcquired(buffer->buffer_state())) {
+ *slot = *iter;
+ unavailable_buffers_slot_.erase(iter);
+ unavailable_buffers_slot_.push_back(*slot);
+ ALOGD("%s: Producer queue dequeue unacquired buffer in slot %d",
+ __FUNCTION__, static_cast<int>(*slot));
+ return {std::move(buffer)};
+ }
+ }
+ ALOGE(
+ "%s: Failed to dequeue un-acquired buffer. No un-acquired buffer exist.",
+ __FUNCTION__);
+ return ErrorStatus(EBUSY);
+}
+
pdx::Status<ProducerQueueParcelable> ProducerQueue::TakeAsParcelable() {
if (capacity() != 0) {
ALOGE(
- "ProducerQueue::TakeAsParcelable: producer queue can only be taken out"
- " as a parcelable when empty. Current queue capacity: %zu",
- capacity());
+ "%s: producer queue can only be taken out as a parcelable when empty. "
+ "Current queue capacity: %zu",
+ __FUNCTION__, capacity());
return ErrorStatus(EINVAL);
}
@@ -628,17 +681,16 @@
: BufferHubQueue(std::move(handle)) {
auto status = ImportQueue();
if (!status) {
- ALOGE("ConsumerQueue::ConsumerQueue: Failed to import queue: %s",
+ ALOGE("%s: Failed to import queue: %s", __FUNCTION__,
status.GetErrorMessage().c_str());
Close(-status.error());
}
auto import_status = ImportBuffers();
if (import_status) {
- ALOGI("ConsumerQueue::ConsumerQueue: Imported %zu buffers.",
- import_status.get());
+ ALOGI("%s: Imported %zu buffers.", __FUNCTION__, import_status.get());
} else {
- ALOGE("ConsumerQueue::ConsumerQueue: Failed to import buffers: %s",
+ ALOGE("%s: Failed to import buffers: %s", __FUNCTION__,
import_status.GetErrorMessage().c_str());
}
}
@@ -647,14 +699,11 @@
auto status = InvokeRemoteMethod<BufferHubRPC::ConsumerQueueImportBuffers>();
if (!status) {
if (status.error() == EBADR) {
- ALOGI(
- "ConsumerQueue::ImportBuffers: Queue is silent, no buffers "
- "imported.");
+ ALOGI("%s: Queue is silent, no buffers imported.", __FUNCTION__);
return {0};
} else {
- ALOGE(
- "ConsumerQueue::ImportBuffers: Failed to import consumer buffer: %s",
- status.GetErrorMessage().c_str());
+ ALOGE("%s: Failed to import consumer buffer: %s", __FUNCTION__,
+ status.GetErrorMessage().c_str());
return status.error_status();
}
}
@@ -665,13 +714,13 @@
auto buffer_handle_slots = status.take();
for (auto& buffer_handle_slot : buffer_handle_slots) {
- ALOGD_IF(TRACE, "ConsumerQueue::ImportBuffers: buffer_handle=%d",
+ ALOGD_IF(TRACE, ": buffer_handle=%d", __FUNCTION__,
buffer_handle_slot.first.value());
std::unique_ptr<BufferConsumer> buffer_consumer =
BufferConsumer::Import(std::move(buffer_handle_slot.first));
if (!buffer_consumer) {
- ALOGE("ConsumerQueue::ImportBuffers: Failed to import buffer: slot=%zu",
+ ALOGE("%s: Failed to import buffer: slot=%zu", __FUNCTION__,
buffer_handle_slot.second);
last_error = ErrorStatus(EPIPE);
continue;
@@ -680,7 +729,7 @@
auto add_status =
AddBuffer(std::move(buffer_consumer), buffer_handle_slot.second);
if (!add_status) {
- ALOGE("ConsumerQueue::ImportBuffers: Failed to add buffer: %s",
+ ALOGE("%s: Failed to add buffer: %s", __FUNCTION__,
add_status.GetErrorMessage().c_str());
last_error = add_status;
} else {
@@ -696,8 +745,8 @@
Status<void> ConsumerQueue::AddBuffer(
const std::shared_ptr<BufferConsumer>& buffer, size_t slot) {
- ALOGD_IF(TRACE, "ConsumerQueue::AddBuffer: queue_id=%d buffer_id=%d slot=%zu",
- id(), buffer->id(), slot);
+ ALOGD_IF(TRACE, "%s: queue_id=%d buffer_id=%d slot=%zu", __FUNCTION__, id(),
+ buffer->id(), slot);
return BufferHubQueue::AddBuffer(buffer, slot);
}
@@ -706,9 +755,9 @@
LocalHandle* acquire_fence) {
if (user_metadata_size != user_metadata_size_) {
ALOGE(
- "ConsumerQueue::Dequeue: Metadata size (%zu) for the dequeuing buffer "
- "does not match metadata size (%zu) for the queue.",
- user_metadata_size, user_metadata_size_);
+ "%s: Metadata size (%zu) for the dequeuing buffer does not match "
+ "metadata size (%zu) for the queue.",
+ __FUNCTION__, user_metadata_size, user_metadata_size_);
return ErrorStatus(EINVAL);
}
@@ -723,7 +772,7 @@
if (metadata_src) {
memcpy(meta, metadata_src, user_metadata_size);
} else {
- ALOGW("ConsumerQueue::Dequeue: no user-defined metadata.");
+ ALOGW("%s: no user-defined metadata.", __FUNCTION__);
}
}
@@ -735,7 +784,7 @@
pdx::LocalHandle* acquire_fence) {
ATRACE_NAME("ConsumerQueue::Dequeue");
if (slot == nullptr || out_meta == nullptr || acquire_fence == nullptr) {
- ALOGE("ConsumerQueue::Dequeue: Invalid parameter.");
+ ALOGE("%s: Invalid parameter.", __FUNCTION__);
return ErrorStatus(EINVAL);
}
@@ -752,19 +801,18 @@
}
Status<void> ConsumerQueue::OnBufferAllocated() {
- ALOGD_IF(TRACE, "ConsumerQueue::OnBufferAllocated: queue_id=%d", id());
+ ALOGD_IF(TRACE, "%s: queue_id=%d", __FUNCTION__, id());
auto status = ImportBuffers();
if (!status) {
- ALOGE("ConsumerQueue::OnBufferAllocated: Failed to import buffers: %s",
+ ALOGE("%s: Failed to import buffers: %s", __FUNCTION__,
status.GetErrorMessage().c_str());
return ErrorStatus(status.error());
} else if (status.get() == 0) {
- ALOGW("ConsumerQueue::OnBufferAllocated: No new buffers allocated!");
+ ALOGW("%s: No new buffers allocated!", __FUNCTION__);
return ErrorStatus(ENOBUFS);
} else {
- ALOGD_IF(TRACE,
- "ConsumerQueue::OnBufferAllocated: Imported %zu consumer buffers.",
+ ALOGD_IF(TRACE, "%s: Imported %zu consumer buffers.", __FUNCTION__,
status.get());
return {};
}
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
index c69002d..def7c6b 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
@@ -57,10 +57,10 @@
uint32_t default_width() const { return default_width_; }
// Returns the default buffer height of this buffer queue.
- uint32_t default_height() const { return static_cast<uint32_t>(default_height_); }
+ uint32_t default_height() const { return default_height_; }
// Returns the default buffer format of this buffer queue.
- uint32_t default_format() const { return static_cast<uint32_t>(default_format_); }
+ uint32_t default_format() const { return default_format_; }
// Creates a new consumer in handle form for immediate transport over RPC.
pdx::Status<pdx::LocalChannelHandle> CreateConsumerQueueHandle(
@@ -208,6 +208,14 @@
// Size of the metadata that buffers in this queue cary.
size_t user_metadata_size_{0};
+ // Buffers and related data that are available for dequeue.
+ std::priority_queue<Entry, std::vector<Entry>, EntryComparator>
+ available_buffers_;
+
+ // Slot of the buffers that are not available for normal dequeue. For example,
+ // the slot of posted or acquired buffers in the perspective of a producer.
+ std::vector<size_t> unavailable_buffers_slot_;
+
private:
void Initialize();
@@ -252,10 +260,6 @@
// queue regardless of its queue position or presence in the ring buffer.
std::array<std::shared_ptr<BufferHubBase>, kMaxQueueCapacity> buffers_;
- // Buffers and related data that are available for dequeue.
- std::priority_queue<Entry, std::vector<Entry>, EntryComparator>
- available_buffers_;
-
// Keeps track with how many buffers have been added into the queue.
size_t capacity_{0};
@@ -349,11 +353,30 @@
// Dequeue a producer buffer to write. The returned buffer in |Gain|'ed mode,
// and caller should call Post() once it's done writing to release the buffer
// to the consumer side.
+ // @return a buffer in gained state, which was originally in released state.
pdx::Status<std::shared_ptr<BufferProducer>> Dequeue(
int timeout, size_t* slot, pdx::LocalHandle* release_fence);
+
+ // Dequeue a producer buffer to write. The returned buffer in |Gain|'ed mode,
+ // and caller should call Post() once it's done writing to release the buffer
+ // to the consumer side.
+ //
+ // @param timeout to dequeue a buffer.
+ // @param slot is the slot of the output BufferProducer.
+ // @param release_fence for gaining a buffer.
+ // @param out_meta metadata of the output buffer.
+ // @param gain_posted_buffer whether to gain posted buffer if no released
+ // buffer is available to gain.
+ // @return a buffer in gained state, which was originally in released state if
+ // gain_posted_buffer is false, or in posted/released state if
+ // gain_posted_buffer is true.
+ // TODO(b/112007999): gain_posted_buffer true is only used to prevent
+ // libdvrtracking from starving when there are non-responding clients. This
+ // gain_posted_buffer param can be removed once libdvrtracking start to use
+ // the new AHardwareBuffer API.
pdx::Status<std::shared_ptr<BufferProducer>> Dequeue(
int timeout, size_t* slot, DvrNativeBufferMetadata* out_meta,
- pdx::LocalHandle* release_fence);
+ pdx::LocalHandle* release_fence, bool gain_posted_buffer = false);
// Enqueues a producer buffer in the queue.
pdx::Status<void> Enqueue(const std::shared_ptr<BufferProducer>& buffer,
@@ -374,6 +397,16 @@
// arguments as the constructors.
explicit ProducerQueue(pdx::LocalChannelHandle handle);
ProducerQueue(const ProducerQueueConfig& config, const UsagePolicy& usage);
+
+ // Dequeue a producer buffer to write. The returned buffer in |Gain|'ed mode,
+ // and caller should call Post() once it's done writing to release the buffer
+ // to the consumer side.
+ //
+ // @param slot the slot of the returned buffer.
+ // @return a buffer in gained state, which was originally in posted state or
+ // released state.
+ pdx::Status<std::shared_ptr<BufferProducer>> DequeueUnacquiredBuffer(
+ size_t* slot);
};
class ConsumerQueue : public BufferHubQueue {
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
index 046df54..c58f55f 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
@@ -1,5 +1,6 @@
#include <base/logging.h>
#include <binder/Parcel.h>
+#include <dvr/dvr_api.h>
#include <private/dvr/buffer_hub_client.h>
#include <private/dvr/buffer_hub_queue_client.h>
@@ -122,6 +123,147 @@
}
}
+TEST_F(BufferHubQueueTest,
+ TestDequeuePostedBufferIfNoAvailableReleasedBuffer_withBufferConsumer) {
+ ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
+
+ // Allocate 3 buffers to use.
+ const size_t test_queue_capacity = 3;
+ for (int64_t i = 0; i < test_queue_capacity; i++) {
+ AllocateBuffer();
+ }
+ EXPECT_EQ(producer_queue_->capacity(), test_queue_capacity);
+
+ size_t producer_slot, consumer_slot;
+ LocalHandle fence;
+ DvrNativeBufferMetadata mi, mo;
+
+ // Producer posts 2 buffers and remember their posted sequence.
+ std::deque<size_t> posted_slots;
+ for (int64_t i = 0; i < 2; i++) {
+ auto p1_status =
+ producer_queue_->Dequeue(kTimeoutMs, &producer_slot, &mo, &fence, true);
+ EXPECT_TRUE(p1_status.ok());
+ auto p1 = p1_status.take();
+ ASSERT_NE(p1, nullptr);
+
+ // Producer should not be gaining posted buffer when there are still
+ // available buffers to gain.
+ auto found_iter =
+ std::find(posted_slots.begin(), posted_slots.end(), producer_slot);
+ EXPECT_EQ(found_iter, posted_slots.end());
+ posted_slots.push_back(producer_slot);
+
+ // Producer posts the buffer.
+ mi.index = i;
+ EXPECT_EQ(0, p1->PostAsync(&mi, LocalHandle()));
+ }
+
+ // Consumer acquires one buffer.
+ auto c1_status =
+ consumer_queue_->Dequeue(kTimeoutMs, &consumer_slot, &mo, &fence);
+ EXPECT_TRUE(c1_status.ok());
+ auto c1 = c1_status.take();
+ ASSERT_NE(c1, nullptr);
+ // Consumer should get the oldest posted buffer. No checks here.
+ // posted_slots[0] should be in acquired state now.
+ EXPECT_EQ(mo.index, 0);
+ // Consumer releases the buffer.
+ EXPECT_EQ(c1->ReleaseAsync(&mi, LocalHandle()), 0);
+ // posted_slots[0] should be in released state now.
+
+ // Producer gain and post 2 buffers.
+ for (int64_t i = 0; i < 2; i++) {
+ auto p1_status =
+ producer_queue_->Dequeue(kTimeoutMs, &producer_slot, &mo, &fence, true);
+ EXPECT_TRUE(p1_status.ok());
+ auto p1 = p1_status.take();
+ ASSERT_NE(p1, nullptr);
+
+ // The gained buffer should be the one in released state or the one haven't
+ // been use.
+ EXPECT_NE(posted_slots[1], producer_slot);
+
+ mi.index = i + 2;
+ EXPECT_EQ(0, p1->PostAsync(&mi, LocalHandle()));
+ }
+
+ // Producer gains a buffer.
+ auto p1_status =
+ producer_queue_->Dequeue(kTimeoutMs, &producer_slot, &mo, &fence, true);
+ EXPECT_TRUE(p1_status.ok());
+ auto p1 = p1_status.take();
+ ASSERT_NE(p1, nullptr);
+
+ // The gained buffer should be the oldest posted buffer.
+ EXPECT_EQ(posted_slots[1], producer_slot);
+
+ // Producer posts the buffer.
+ mi.index = 4;
+ EXPECT_EQ(0, p1->PostAsync(&mi, LocalHandle()));
+}
+
+TEST_F(BufferHubQueueTest,
+ TestDequeuePostedBufferIfNoAvailableReleasedBuffer_noBufferConsumer) {
+ ASSERT_TRUE(CreateQueues(config_builder_.Build(), UsagePolicy{}));
+
+ // Allocate 4 buffers to use.
+ const size_t test_queue_capacity = 4;
+ for (int64_t i = 0; i < test_queue_capacity; i++) {
+ AllocateBuffer();
+ }
+ EXPECT_EQ(producer_queue_->capacity(), test_queue_capacity);
+
+ // Post all allowed buffers and remember their posted sequence.
+ std::deque<size_t> posted_slots;
+ for (int64_t i = 0; i < test_queue_capacity; i++) {
+ size_t slot;
+ LocalHandle fence;
+ DvrNativeBufferMetadata mi, mo;
+
+ // Producer gains a buffer.
+ auto p1_status =
+ producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence, true);
+ EXPECT_TRUE(p1_status.ok());
+ auto p1 = p1_status.take();
+ ASSERT_NE(p1, nullptr);
+
+ // Producer should not be gaining posted buffer when there are still
+ // available buffers to gain.
+ auto found_iter = std::find(posted_slots.begin(), posted_slots.end(), slot);
+ EXPECT_EQ(found_iter, posted_slots.end());
+ posted_slots.push_back(slot);
+
+ // Producer posts the buffer.
+ mi.index = i;
+ EXPECT_EQ(p1->PostAsync(&mi, LocalHandle()), 0);
+ }
+
+ // Gain posted buffers in sequence.
+ const int64_t nb_dequeue_all_times = 2;
+ for (int j = 0; j < nb_dequeue_all_times; ++j) {
+ for (int i = 0; i < test_queue_capacity; ++i) {
+ size_t slot;
+ LocalHandle fence;
+ DvrNativeBufferMetadata mi, mo;
+
+ // Producer gains a buffer.
+ auto p1_status =
+ producer_queue_->Dequeue(kTimeoutMs, &slot, &mo, &fence, true);
+ EXPECT_TRUE(p1_status.ok());
+ auto p1 = p1_status.take();
+ ASSERT_NE(p1, nullptr);
+
+ // The gained buffer should be the oldest posted buffer.
+ EXPECT_EQ(posted_slots[i], slot);
+
+ // Producer posts the buffer.
+ mi.index = i + test_queue_capacity * (j + 1);
+ EXPECT_EQ(p1->PostAsync(&mi, LocalHandle()), 0);
+ }
+ }
+}
+
TEST_F(BufferHubQueueTest, TestProducerConsumer) {
const size_t kBufferCount = 16;
size_t slot;
@@ -245,8 +387,8 @@
for (size_t i = 0; i < kBufferCount; i++) {
Entry* entry = &buffers[i];
- auto producer_status = producer_queue_->Dequeue(
- kTimeoutMs, &entry->slot, &mo, &entry->fence);
+ auto producer_status =
+ producer_queue_->Dequeue(kTimeoutMs, &entry->slot, &mo, &entry->fence);
ASSERT_TRUE(producer_status.ok());
entry->buffer = producer_status.take();
ASSERT_NE(nullptr, entry->buffer);
diff --git a/libs/vr/libpdx/service.cpp b/libs/vr/libpdx/service.cpp
index 68b8dd7..3769162 100644
--- a/libs/vr/libpdx/service.cpp
+++ b/libs/vr/libpdx/service.cpp
@@ -318,13 +318,7 @@
PDX_TRACE_NAME("Message::ReplyFileHandle");
auto svc = service_.lock();
if (!replied_ && svc) {
- Status<void> ret;
-
- if (handle)
- ret = svc->endpoint()->MessageReply(this, handle.Get());
- else
- ret = svc->endpoint()->MessageReply(this, handle.Get());
-
+ Status<void> ret = svc->endpoint()->MessageReply(this, handle.Get());
replied_ = ret.ok();
return ret;
} else {
diff --git a/libs/vr/libpdx/status_tests.cpp b/libs/vr/libpdx/status_tests.cpp
index d4e697c..772c529 100644
--- a/libs/vr/libpdx/status_tests.cpp
+++ b/libs/vr/libpdx/status_tests.cpp
@@ -2,6 +2,8 @@
#include <gtest/gtest.h>
+#include <memory>
+
using android::pdx::ErrorStatus;
using android::pdx::Status;
@@ -84,8 +86,8 @@
Status<std::unique_ptr<int>> status1;
Status<std::unique_ptr<int>> status2;
- status1 = Status<std::unique_ptr<int>>{std::unique_ptr<int>{new int{11}}};
- status2 = Status<std::unique_ptr<int>>{std::unique_ptr<int>{new int{12}}};
+ status1 = Status<std::unique_ptr<int>>{std::make_unique<int>(int{11})};
+ status2 = Status<std::unique_ptr<int>>{std::make_unique<int>(int{12})};
EXPECT_FALSE(status1.empty());
EXPECT_FALSE(status2.empty());
EXPECT_TRUE(status1.ok());
@@ -114,7 +116,7 @@
}
TEST(Status, Take) {
- Status<std::unique_ptr<int>> status{std::unique_ptr<int>{new int{123}}};
+ Status<std::unique_ptr<int>> status{std::make_unique<int>(int{123})};
EXPECT_FALSE(status.empty());
EXPECT_NE(nullptr, status.get());
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index a150db1..e27f233 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -42,18 +42,6 @@
android_namespace_t* android_get_exported_namespace(const char*);
// TODO(ianelliott@): Get this from an ANGLE header:
- typedef enum ANGLEPreference {
- ANGLE_NO_PREFERENCE = 0,
- ANGLE_PREFER_NATIVE = 1,
- ANGLE_PREFER_ANGLE = 2,
- } ANGLEPreference;
-
- // TODO(ianelliott@): Get this from an ANGLE header:
- typedef bool (*fpANGLEUseForApplication)(const char* appName, const char* deviceMfr,
- const char* deviceModel, ANGLEPreference developerOption,
- ANGLEPreference appPreference);
-
- // TODO(ianelliott@): Get this from an ANGLE header:
typedef bool (*fpANGLEGetUtilityAPI)(unsigned int* versionToUse);
// TODO(ianelliott@): Get this from an ANGLE header:
@@ -522,16 +510,56 @@
return nullptr;
}
-static ANGLEPreference getAnglePref(const char* app_pref) {
- if (app_pref == nullptr)
- return ANGLE_NO_PREFERENCE;
- if (strcmp(app_pref, "angle") == 0) {
- return ANGLE_PREFER_ANGLE;
- } else if (strcmp(app_pref, "native") == 0) {
- return ANGLE_PREFER_NATIVE;
+static bool check_angle_rules(void* so, const char* app_name) {
+ bool use_angle = false;
+ const int rules_fd = android::GraphicsEnv::getInstance().getAngleRulesFd();
+ const long rules_offset = android::GraphicsEnv::getInstance().getAngleRulesOffset();
+ const long rules_length = android::GraphicsEnv::getInstance().getAngleRulesLength();
+
+ std::string app_name_str = app_name ? app_name : "";
+ char manufacturer[PROPERTY_VALUE_MAX];
+ char model[PROPERTY_VALUE_MAX];
+ property_get("ro.product.manufacturer", manufacturer, "UNSET");
+ property_get("ro.product.model", model, "UNSET");
+
+ fpANGLEGetUtilityAPI ANGLEGetUtilityAPI =
+ (fpANGLEGetUtilityAPI)dlsym(so, "ANGLEGetUtilityAPI");
+
+ if (ANGLEGetUtilityAPI) {
+
+ // Negotiate the interface version by requesting most recent known to the platform
+ unsigned int versionToUse = 1;
+ if ((ANGLEGetUtilityAPI)(&versionToUse)) {
+
+ // Add and remove versions below as needed
+ switch(versionToUse) {
+ case 1: {
+ ALOGV("Using version 1 of ANGLE opt-in/out logic interface");
+ fpAndroidUseANGLEForApplication AndroidUseANGLEForApplication =
+ (fpAndroidUseANGLEForApplication)dlsym(so, "AndroidUseANGLEForApplication");
+
+ if (AndroidUseANGLEForApplication) {
+ use_angle = (AndroidUseANGLEForApplication)(rules_fd, rules_offset,
+ rules_length, app_name_str.c_str(),
+ manufacturer, model);
+ } else {
+ ALOGW("Cannot find AndroidUseANGLEForApplication in ANGLE feature-support library");
+ }
+ }
+ break;
+ default:
+ ALOGW("Cannot find supported version of ANGLE feature-support library, found version %u", versionToUse);
+ }
+ } else {
+ ALOGW("Cannot use ANGLE feature-support library, it is older than supported by EGL, requested version %u", versionToUse);
+ }
+ } else {
+ ALOGW("Cannot find ANGLEGetUtilityAPI function");
}
- return ANGLE_NO_PREFERENCE;
+
+ ALOGV("Close temporarily-loaded ANGLE opt-in/out logic");
+ return use_angle;
}
static void* load_angle(const char* kind, android_namespace_t* ns, egl_connection_t* cnx) {
@@ -543,15 +571,10 @@
char prop[PROPERTY_VALUE_MAX];
const char* app_name = android::GraphicsEnv::getInstance().getAngleAppName();
- const char* app_pref = android::GraphicsEnv::getInstance().getAngleAppPref();
bool developer_opt_in = android::GraphicsEnv::getInstance().getAngleDeveloperOptIn();
- const int rules_fd = android::GraphicsEnv::getInstance().getAngleRulesFd();
- const long rules_offset = android::GraphicsEnv::getInstance().getAngleRulesOffset();
- const long rules_length = android::GraphicsEnv::getInstance().getAngleRulesLength();
// Determine whether or not to use ANGLE:
- ANGLEPreference developer_option = developer_opt_in ? ANGLE_PREFER_ANGLE : ANGLE_NO_PREFERENCE;
- bool use_angle = (developer_option == ANGLE_PREFER_ANGLE);
+ bool use_angle = developer_opt_in;
if (use_angle) {
ALOGV("User set \"Developer Options\" to force the use of ANGLE");
@@ -560,59 +583,17 @@
} else {
// The "Developer Options" value wasn't set to force the use of ANGLE. Need to temporarily
// load ANGLE and call the updatable opt-in/out logic:
- std::string app_name_str = app_name ? app_name : "";
- char manufacturer[PROPERTY_VALUE_MAX];
- char model[PROPERTY_VALUE_MAX];
- property_get("ro.product.manufacturer", manufacturer, "UNSET");
- property_get("ro.product.model", model, "UNSET");
- cnx->featureSo = load_angle_from_namespace("feature_support", ns);
+ // Check if ANGLE is enabled. Workaround for several bugs:
+ // b/119305693 b/119322355 b/119305887
+ // Something is not working correctly in the feature library
+ property_get("debug.angle.enable", prop, "0");
+ if (atoi(prop)) {
+ cnx->featureSo = load_angle_from_namespace("feature_support", ns);
+ }
if (cnx->featureSo) {
ALOGV("loaded ANGLE's opt-in/out logic from namespace");
- bool use_version0_API = false;
- bool use_version1_API = false;
- fpANGLEGetUtilityAPI ANGLEGetUtilityAPI =
- (fpANGLEGetUtilityAPI)dlsym(cnx->featureSo, "ANGLEGetUtilityAPI");
- if (ANGLEGetUtilityAPI) {
- unsigned int versionToUse = 1;
- if ((ANGLEGetUtilityAPI)(&versionToUse)) {
- if (versionToUse == 1) {
- use_version1_API = true;
- } else {
- use_version0_API = true;
- }
- }
- } else {
- use_version0_API = true;
- ALOGV("Cannot find ANGLEGetUtilityAPI in library");
- }
- if (use_version1_API) {
- // Use the new version 1 API to determine if the
- // application should use the ANGLE or the native driver.
- fpAndroidUseANGLEForApplication AndroidUseANGLEForApplication =
- (fpAndroidUseANGLEForApplication)dlsym(cnx->featureSo, "AndroidUseANGLEForApplication");
- if (AndroidUseANGLEForApplication) {
- use_angle = (AndroidUseANGLEForApplication)(rules_fd, rules_offset,
- rules_length, app_name_str.c_str(),
- manufacturer, model);
- } else {
- ALOGW("Cannot find AndroidUseANGLEForApplication in library");
- }
- } else if (use_version0_API) {
- // Use the old version 0 API to determine if the
- // application should use the ANGLE or the native driver.
- fpANGLEUseForApplication ANGLEUseForApplication =
- (fpANGLEUseForApplication)dlsym(cnx->featureSo, "ANGLEUseForApplication");
- if (ANGLEUseForApplication) {
- ANGLEPreference app_preference =
- getAnglePref(android::GraphicsEnv::getInstance().getAngleAppPref());
- use_angle = (ANGLEUseForApplication)(app_name_str.c_str(), manufacturer, model,
- developer_option, app_preference);
- ALOGV("Result of opt-in/out logic is %s", use_angle ? "true" : "false");
- } else {
- ALOGW("Cannot find ANGLEUseForApplication in library");
- }
- }
+ use_angle = check_angle_rules(cnx->featureSo, app_name);
} else {
// We weren't able to load and call the updateable opt-in/out logic.
// If we can't load the library, there is no ANGLE available.
diff --git a/services/bufferhub/Android.bp b/services/bufferhub/Android.bp
index d03d833..8b43333 100644
--- a/services/bufferhub/Android.bp
+++ b/services/bufferhub/Android.bp
@@ -22,6 +22,7 @@
"-Wextra",
],
srcs: [
+ "BufferClient.cpp",
"BufferHubService.cpp",
"BufferNode.cpp",
],
@@ -33,6 +34,7 @@
],
shared_libs: [
"android.frameworks.bufferhub@1.0",
+ "libcutils",
"libhidlbase",
"libhidltransport",
"libhwbinder",
@@ -51,9 +53,16 @@
srcs: [
"main_bufferhub.cpp"
],
+ header_libs: [
+ "libbufferhub_headers",
+ "libdvr_headers",
+ "libnativewindow_headers",
+ "libpdx_headers",
+ ],
shared_libs: [
"android.frameworks.bufferhub@1.0",
"libbufferhubservice",
+ "libcutils",
"libhidltransport",
"libhwbinder",
"liblog",
diff --git a/services/bufferhub/BufferClient.cpp b/services/bufferhub/BufferClient.cpp
new file mode 100644
index 0000000..37fd75f
--- /dev/null
+++ b/services/bufferhub/BufferClient.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <bufferhub/BufferClient.h>
+#include <bufferhub/BufferHubService.h>
+#include <hidl/HidlSupport.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+using hardware::hidl_handle;
+using hardware::Void;
+
+BufferClient* BufferClient::create(BufferHubService* service,
+ const std::shared_ptr<BufferNode>& node) {
+ if (!service) {
+ ALOGE("%s: service cannot be nullptr.", __FUNCTION__);
+ return nullptr;
+ } else if (!node) {
+ ALOGE("%s: node cannot be nullptr.", __FUNCTION__);
+ return nullptr;
+ }
+ return new BufferClient(service, node);
+}
+
+Return<void> BufferClient::duplicate(duplicate_cb _hidl_cb) {
+ if (!mBufferNode) {
+ // Should never happen
+ ALOGE("%s: node is missing.", __FUNCTION__);
+ _hidl_cb(/*token=*/hidl_handle(), /*status=*/BufferHubStatus::BUFFER_FREED);
+ return Void();
+ }
+
+ sp<BufferHubService> service = mService.promote();
+ if (service == nullptr) {
+ // Should never happen. Kill the process.
+ LOG_FATAL("%s: service died.", __FUNCTION__);
+ }
+
+ const hidl_handle token = service->registerToken(this);
+ _hidl_cb(/*token=*/token, /*status=*/BufferHubStatus::NO_ERROR);
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bufferhub
+} // namespace frameworks
+} // namespace android
\ No newline at end of file
diff --git a/services/bufferhub/BufferHubService.cpp b/services/bufferhub/BufferHubService.cpp
index 8be85a5..3bfd9cb 100644
--- a/services/bufferhub/BufferHubService.cpp
+++ b/services/bufferhub/BufferHubService.cpp
@@ -14,7 +14,10 @@
* limitations under the License.
*/
+#include <android/hardware_buffer.h>
#include <bufferhub/BufferHubService.h>
+#include <cutils/native_handle.h>
+#include <log/log.h>
namespace android {
namespace frameworks {
@@ -22,16 +25,56 @@
namespace V1_0 {
namespace implementation {
-using ::android::status_t;
-using ::android::hardware::Void;
+using hardware::Void;
-Return<void> BufferHubService::allocateBuffer(const HardwareBufferDescription& /*description*/,
- allocateBuffer_cb /*hidl_cb*/) {
+Return<void> BufferHubService::allocateBuffer(const HardwareBufferDescription& description,
+ const uint32_t userMetadataSize,
+ allocateBuffer_cb _hidl_cb) {
+ AHardwareBuffer_Desc desc;
+ memcpy(&desc, &description, sizeof(AHardwareBuffer_Desc));
+
+ std::shared_ptr<BufferNode> node =
+ std::make_shared<BufferNode>(desc.width, desc.height, desc.layers, desc.format,
+ desc.usage, userMetadataSize);
+ if (node == nullptr || !node->IsValid()) {
+ ALOGE("%s: creating BufferNode failed.", __FUNCTION__);
+ _hidl_cb(/*bufferClient=*/nullptr, /*status=*/BufferHubStatus::ALLOCATION_FAILED);
+ return Void();
+ }
+
+ sp<BufferClient> client = BufferClient::create(this, node);
+ // Add it to list for bookkeeping and dumpsys.
+ std::lock_guard<std::mutex> lock(mClientListMutex);
+ mClientList.push_back(client);
+
+ _hidl_cb(/*bufferClient=*/client, /*status=*/BufferHubStatus::NO_ERROR);
return Void();
}
-Return<sp<IBase>> BufferHubService::importBuffer(const hidl_handle& /*nativeHandle*/) {
- return nullptr;
+Return<void> BufferHubService::importBuffer(const hidl_handle& /*nativeHandle*/,
+ importBuffer_cb _hidl_cb) {
+ // TODO(b/118614157): implement buffer import
+ _hidl_cb(/*bufferClient=*/nullptr, /*status=*/BufferHubStatus::NO_ERROR);
+ return Void();
+}
+
+hidl_handle BufferHubService::registerToken(const BufferClient* client) {
+ uint32_t token;
+ std::lock_guard<std::mutex> lock(mTokenMapMutex);
+ do {
+ token = mTokenEngine();
+ } while (mTokenMap.find(token) != mTokenMap.end());
+
+ // native_handle_t use int[], so here need one slots to fit in uint32_t
+ native_handle_t* handle = native_handle_create(/*numFds=*/0, /*numInts=*/1);
+ handle->data[0] = token;
+
+ // returnToken owns the native_handle_t* thus doing lifecycle management
+ hidl_handle returnToken;
+ returnToken.setTo(handle, /*shoudOwn=*/true);
+
+ mTokenMap.emplace(token, client);
+ return returnToken;
}
} // namespace implementation
diff --git a/services/bufferhub/BufferNode.cpp b/services/bufferhub/BufferNode.cpp
index 62583a6..53dd702 100644
--- a/services/bufferhub/BufferNode.cpp
+++ b/services/bufferhub/BufferNode.cpp
@@ -35,7 +35,7 @@
/*requestor=*/"bufferhub");
if (ret != OK || buffer_handle_ == nullptr) {
- ALOGE("BufferNode::BufferNode: Failed to allocate buffer: %s", strerror(-ret));
+ ALOGE("%s: Failed to allocate buffer: %s", __FUNCTION__, strerror(-ret));
return;
}
@@ -48,7 +48,7 @@
metadata_ = BufferHubMetadata::Create(user_metadata_size);
if (!metadata_.IsValid()) {
- ALOGE("BufferNode::BufferNode: Failed to allocate metadata.");
+ ALOGE("%s: Failed to allocate metadata.", __FUNCTION__);
return;
}
InitializeMetadata();
@@ -59,7 +59,7 @@
if (buffer_handle_ != nullptr) {
status_t ret = GraphicBufferAllocator::get().free(buffer_handle_);
if (ret != OK) {
- ALOGE("BufferNode::~BufferNode: Failed to free handle; Got error: %d", ret);
+ ALOGE("%s: Failed to free handle; Got error: %d", __FUNCTION__, ret);
}
}
}
@@ -76,8 +76,7 @@
client_state_mask = dvr::BufferHubDefs::FindNextAvailableClientStateMask(
current_active_clients_bit_mask);
if (client_state_mask == 0ULL) {
- ALOGE("BufferNode::AddNewActiveClientsBitToMask: reached the maximum "
- "mumber of channels per buffer node: 32.");
+ ALOGE("%s: reached the maximum number of channels per buffer node: 32.", __FUNCTION__);
errno = E2BIG;
return 0ULL;
}
diff --git a/services/bufferhub/include/bufferhub/BufferClient.h b/services/bufferhub/include/bufferhub/BufferClient.h
new file mode 100644
index 0000000..5456ec3
--- /dev/null
+++ b/services/bufferhub/include/bufferhub/BufferClient.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_CLIENT_H
+#define ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_CLIENT_H
+
+#include <mutex>
+
+#include <android/frameworks/bufferhub/1.0/IBufferClient.h>
+#include <bufferhub/BufferNode.h>
+
+namespace android {
+namespace frameworks {
+namespace bufferhub {
+namespace V1_0 {
+namespace implementation {
+
+using hardware::hidl_handle;
+using hardware::Return;
+
+// Forward declaration to avoid circular dependency
+class BufferHubService;
+
+class BufferClient : public IBufferClient {
+public:
+ // Creates a server-side buffer client from an existing BufferNode. Note that
+ // this funciton takes ownership of the shared_ptr.
+ // Returns a raw pointer to the BufferClient on success, nullptr on failure.
+ static BufferClient* create(BufferHubService* service, const std::shared_ptr<BufferNode>& node);
+
+ Return<void> duplicate(duplicate_cb _hidl_cb) override;
+
+private:
+ BufferClient(wp<BufferHubService> service, const std::shared_ptr<BufferNode>& node)
+ : mService(service), mBufferNode(node){};
+
+ wp<BufferHubService> mService;
+ std::shared_ptr<BufferNode> mBufferNode;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace bufferhub
+} // namespace frameworks
+} // namespace android
+
+#endif
\ No newline at end of file
diff --git a/services/bufferhub/include/bufferhub/BufferHubService.h b/services/bufferhub/include/bufferhub/BufferHubService.h
index b273e5b..dbbee8f 100644
--- a/services/bufferhub/include/bufferhub/BufferHubService.h
+++ b/services/bufferhub/include/bufferhub/BufferHubService.h
@@ -17,8 +17,12 @@
#ifndef ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_HUB_SERVICE_H
#define ANDROID_FRAMEWORKS_BUFFERHUB_V1_0_BUFFER_HUB_SERVICE_H
+#include <mutex>
+#include <random>
+
#include <android/frameworks/bufferhub/1.0/IBufferHub.h>
-#include <android/hardware/graphics/common/1.2/types.h>
+#include <bufferhub/BufferClient.h>
+#include <utils/Mutex.h>
namespace android {
namespace frameworks {
@@ -26,17 +30,31 @@
namespace V1_0 {
namespace implementation {
-using ::android::sp;
-using ::android::hardware::hidl_handle;
-using ::android::hardware::Return;
-using ::android::hardware::graphics::common::V1_2::HardwareBufferDescription;
-using ::android::hidl::base::V1_0::IBase;
+using hardware::hidl_handle;
+using hardware::Return;
+using hardware::graphics::common::V1_2::HardwareBufferDescription;
class BufferHubService : public IBufferHub {
public:
- Return<void> allocateBuffer(const HardwareBufferDescription& /*description*/,
- allocateBuffer_cb /*hidl_cb*/) override;
- Return<sp<IBase>> importBuffer(const hidl_handle& /*nativeHandle*/) override;
+ Return<void> allocateBuffer(const HardwareBufferDescription& description,
+ const uint32_t userMetadataSize,
+ allocateBuffer_cb _hidl_cb) override;
+ Return<void> importBuffer(const hidl_handle& nativeHandle, importBuffer_cb _hidl_cb) override;
+
+ // Non-binder functions
+ // Internal help function for IBufferClient::duplicate.
+ hidl_handle registerToken(const BufferClient* client);
+
+private:
+ // List of active BufferClient for bookkeeping.
+ std::mutex mClientListMutex;
+ std::vector<sp<BufferClient>> mClientList GUARDED_BY(mClientListMutex);
+
+ // TODO(b/118180214): use a more secure implementation
+ std::mt19937 mTokenEngine;
+ // The mapping from token to the client creates it.
+ std::mutex mTokenMapMutex;
+ std::map<uint32_t, const BufferClient*> mTokenMap GUARDED_BY(mTokenMapMutex);
};
} // namespace implementation
diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp
new file mode 100644
index 0000000..250bbee
--- /dev/null
+++ b/services/gpuservice/Android.bp
@@ -0,0 +1,74 @@
+filegroup {
+ name: "gpuservice_sources",
+ srcs: [
+ "GpuService.cpp",
+ ],
+}
+
+filegroup {
+ name: "gpuservice_binary_sources",
+ srcs: ["main_gpuservice.cpp"],
+}
+
+cc_defaults {
+ name: "gpuservice_defaults",
+ cflags: [
+ "-DLOG_TAG=\"GpuService\"",
+ "-Wall",
+ "-Werror",
+ "-Wformat",
+ "-Wthread-safety",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+ cppflags: ["-std=c++1z"],
+ srcs: [
+ ":gpuservice_sources",
+ ],
+ include_dirs: [
+ "frameworks/native/vulkan/vkjson",
+ "frameworks/native/vulkan/include",
+ ],
+ shared_libs: [
+ "libbinder",
+ "liblog",
+ "libutils",
+ "libvulkan",
+ ],
+ static_libs: [
+ "libvkjson",
+ ],
+}
+
+cc_defaults {
+ name: "gpuservice_production_defaults",
+ defaults: ["gpuservice_defaults"],
+ cflags: [
+ "-fvisibility=hidden",
+ "-fwhole-program-vtables", // requires ThinLTO
+ ],
+ lto: {
+ thin: true,
+ },
+}
+
+cc_defaults {
+ name: "gpuservice_binary",
+ defaults: ["gpuservice_defaults"],
+ whole_static_libs: [
+ "libsigchain",
+ ],
+ shared_libs: [
+ "libbinder",
+ "liblog",
+ "libutils",
+ ],
+ ldflags: ["-Wl,--export-dynamic"],
+}
+
+cc_binary {
+ name: "gpuservice",
+ defaults: ["gpuservice_binary"],
+ init_rc: ["gpuservice.rc"],
+ srcs: [":gpuservice_binary_sources"],
+}
diff --git a/services/surfaceflinger/GpuService.cpp b/services/gpuservice/GpuService.cpp
similarity index 83%
rename from services/surfaceflinger/GpuService.cpp
rename to services/gpuservice/GpuService.cpp
index 71052fb..e4ca6bc 100644
--- a/services/surfaceflinger/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -23,10 +23,7 @@
namespace android {
-// ----------------------------------------------------------------------------
-
-class BpGpuService : public BpInterface<IGpuService>
-{
+class BpGpuService : public BpInterface<IGpuService> {
public:
explicit BpGpuService(const sp<IBinder>& impl) : BpInterface<IGpuService>(impl) {}
};
@@ -34,19 +31,15 @@
IMPLEMENT_META_INTERFACE(GpuService, "android.ui.IGpuService");
status_t BnGpuService::onTransact(uint32_t code, const Parcel& data,
- Parcel* reply, uint32_t flags)
-{
+ Parcel* reply, uint32_t flags) {
status_t status;
switch (code) {
case SHELL_COMMAND_TRANSACTION: {
int in = data.readFileDescriptor();
int out = data.readFileDescriptor();
int err = data.readFileDescriptor();
- int argc = data.readInt32();
- Vector<String16> args;
- for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
- args.add(data.readString16());
- }
+ std::vector<String16> args;
+ data.readString16Vector(&args);
sp<IBinder> unusedCallback;
sp<IResultReceiver> resultReceiver;
if ((status = data.readNullableStrongBinder(&unusedCallback)) != OK)
@@ -64,20 +57,17 @@
}
}
-// ----------------------------------------------------------------------------
-
namespace {
status_t cmd_help(int out);
status_t cmd_vkjson(int out, int err);
}
-const char* const GpuService::SERVICE_NAME = "gpu";
+const char* const GpuService::SERVICE_NAME = "gpuservice";
-GpuService::GpuService() {}
+GpuService::GpuService() = default;
status_t GpuService::shellCommand(int /*in*/, int out, int err,
- Vector<String16>& args)
-{
+ std::vector<String16>& args) {
ALOGV("GpuService::shellCommand");
for (size_t i = 0, n = args.size(); i < n; i++)
ALOGV(" arg[%zu]: '%s'", i, String8(args[i]).string());
@@ -93,8 +83,6 @@
return BAD_VALUE;
}
-// ----------------------------------------------------------------------------
-
namespace {
status_t cmd_help(int out) {
diff --git a/services/surfaceflinger/GpuService.h b/services/gpuservice/GpuService.h
similarity index 80%
rename from services/surfaceflinger/GpuService.h
rename to services/gpuservice/GpuService.h
index b8c28d2..e2b396e 100644
--- a/services/surfaceflinger/GpuService.h
+++ b/services/gpuservice/GpuService.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_GPUSERVICE_H
#define ANDROID_GPUSERVICE_H
+#include <vector>
+
#include <binder/IInterface.h>
#include <cutils/compiler.h>
@@ -34,22 +36,21 @@
class BnGpuService: public BnInterface<IGpuService> {
protected:
virtual status_t shellCommand(int in, int out, int err,
- Vector<String16>& args) = 0;
+ std::vector<String16>& args) = 0;
- virtual status_t onTransact(uint32_t code, const Parcel& data,
+ status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags = 0) override;
};
-class GpuService : public BnGpuService
-{
+class GpuService : public BnGpuService {
public:
static const char* const SERVICE_NAME ANDROID_API;
GpuService() ANDROID_API;
protected:
- virtual status_t shellCommand(int in, int out, int err,
- Vector<String16>& args) override;
+ status_t shellCommand(int in, int out, int err,
+ std::vector<String16>& args) override;
};
} // namespace android
diff --git a/services/gpuservice/gpuservice.rc b/services/gpuservice/gpuservice.rc
new file mode 100644
index 0000000..d23cf46
--- /dev/null
+++ b/services/gpuservice/gpuservice.rc
@@ -0,0 +1,4 @@
+service gpuservice /system/bin/gpuservice
+ class core
+ user gpu_service
+ group graphics
diff --git a/services/gpuservice/main_gpuservice.cpp b/services/gpuservice/main_gpuservice.cpp
new file mode 100644
index 0000000..64aafca
--- /dev/null
+++ b/services/gpuservice/main_gpuservice.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <sys/resource.h>
+#include "GpuService.h"
+
+using namespace android;
+
+int main(int /* argc */, char** /* argv */) {
+ signal(SIGPIPE, SIG_IGN);
+
+ // publish GpuService
+ sp<GpuService> gpuservice = new GpuService();
+ sp<IServiceManager> sm(defaultServiceManager());
+ sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);
+
+ // limit the number of binder threads to 4.
+ ProcessState::self()->setThreadPoolMaxThreadCount(4);
+
+ // start the thread pool
+ sp<ProcessState> ps(ProcessState::self());
+ ps->startThreadPool();
+ ps->giveThreadPoolName();
+ IPCThreadState::self()->joinThreadPool();
+
+ return 0;
+}
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 9a65452..7812cb2 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -35,6 +35,7 @@
"libutils",
"libui",
"libhardware_legacy",
+ "libutils"
],
cflags: [
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index a964d29..31057f6 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -147,8 +147,7 @@
fd(fd), id(id), path(path), identifier(identifier),
classes(0), configuration(nullptr), virtualKeyMap(nullptr),
ffEffectPlaying(false), ffEffectId(-1), controllerNumber(0),
- timestampOverrideSec(0), timestampOverrideUsec(0), enabled(true),
- isVirtual(fd < 0) {
+ enabled(true), isVirtual(fd < 0) {
memset(keyBitmask, 0, sizeof(keyBitmask));
memset(absBitmask, 0, sizeof(absBitmask));
memset(relBitmask, 0, sizeof(relBitmask));
@@ -193,8 +192,6 @@
// --- EventHub ---
-const uint32_t EventHub::EPOLL_ID_INOTIFY;
-const uint32_t EventHub::EPOLL_ID_WAKE;
const int EventHub::EPOLL_SIZE_HINT;
const int EventHub::EPOLL_MAX_EVENTS;
@@ -217,7 +214,7 @@
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN;
- eventItem.data.u32 = EPOLL_ID_INOTIFY;
+ eventItem.data.fd = mINotifyFd;
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance. errno=%d", errno);
@@ -236,7 +233,7 @@
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",
errno);
- eventItem.data.u32 = EPOLL_ID_WAKE;
+ eventItem.data.fd = mWakeReadPipeFd;
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d",
errno);
@@ -735,6 +732,16 @@
return nullptr;
}
+EventHub::Device* EventHub::getDeviceByFdLocked(int fd) const {
+ for (size_t i = 0; i < mDevices.size(); i++) {
+ Device* device = mDevices.valueAt(i);
+ if (device->fd == fd) {
+ return device;
+ }
+ }
+ return nullptr;
+}
+
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
ALOG_ASSERT(bufferSize >= 1);
@@ -811,7 +818,7 @@
bool deviceChanged = false;
while (mPendingEventIndex < mPendingEventCount) {
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
- if (eventItem.data.u32 == EPOLL_ID_INOTIFY) {
+ if (eventItem.data.fd == mINotifyFd) {
if (eventItem.events & EPOLLIN) {
mPendingINotify = true;
} else {
@@ -820,7 +827,7 @@
continue;
}
- if (eventItem.data.u32 == EPOLL_ID_WAKE) {
+ if (eventItem.data.fd == mWakeReadPipeFd) {
if (eventItem.events & EPOLLIN) {
ALOGV("awoken after wake()");
awoken = true;
@@ -836,14 +843,13 @@
continue;
}
- ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32);
- if (deviceIndex < 0) {
- ALOGW("Received unexpected epoll event 0x%08x for unknown device id %d.",
- eventItem.events, eventItem.data.u32);
+ Device* device = getDeviceByFdLocked(eventItem.data.fd);
+ if (device == nullptr) {
+ ALOGW("Received unexpected epoll event 0x%08x for unknown device fd %d.",
+ eventItem.events, eventItem.data.fd);
continue;
}
- Device* device = mDevices.valueAt(deviceIndex);
if (eventItem.events & EPOLLIN) {
int32_t readSize = read(device->fd, readBuffer,
sizeof(struct input_event) * capacity);
@@ -871,31 +877,6 @@
(int) iev.time.tv_sec, (int) iev.time.tv_usec,
iev.type, iev.code, iev.value);
- // Some input devices may have a better concept of the time
- // when an input event was actually generated than the kernel
- // which simply timestamps all events on entry to evdev.
- // This is a custom Android extension of the input protocol
- // mainly intended for use with uinput based device drivers.
- if (iev.type == EV_MSC) {
- if (iev.code == MSC_ANDROID_TIME_SEC) {
- device->timestampOverrideSec = iev.value;
- continue;
- } else if (iev.code == MSC_ANDROID_TIME_USEC) {
- device->timestampOverrideUsec = iev.value;
- continue;
- }
- }
- if (device->timestampOverrideSec || device->timestampOverrideUsec) {
- iev.time.tv_sec = device->timestampOverrideSec;
- iev.time.tv_usec = device->timestampOverrideUsec;
- if (iev.type == EV_SYN && iev.code == SYN_REPORT) {
- device->timestampOverrideSec = 0;
- device->timestampOverrideUsec = 0;
- }
- ALOGV("applied override time %d.%06d",
- int(iev.time.tv_sec), int(iev.time.tv_usec));
- }
-
// Use the time specified in the event instead of the current time
// so that downstream code can get more accurate estimates of
// event dispatch latency from the time the event is enqueued onto
@@ -1089,7 +1070,7 @@
if (mUsingEpollWakeup) {
eventItem.events |= EPOLLWAKEUP;
}
- eventItem.data.u32 = device->id;
+ eventItem.data.fd = device->fd;
if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, device->fd, &eventItem)) {
ALOGE("Could not add device fd to epoll instance. errno=%d", errno);
return -errno;
diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h
index ea663b7..e2c7e82 100644
--- a/services/inputflinger/EventHub.h
+++ b/services/inputflinger/EventHub.h
@@ -42,20 +42,6 @@
#define BTN_FIRST 0x100 // first button code
#define BTN_LAST 0x15f // last button code
-/*
- * These constants are used privately in Android to pass raw timestamps
- * through evdev from uinput device drivers because there is currently no
- * other way to transfer this information. The evdev driver automatically
- * timestamps all input events with the time they were posted and clobbers
- * whatever information was passed in.
- *
- * For the purposes of this hack, the timestamp is specified in the
- * CLOCK_MONOTONIC timebase and is split into two EV_MSC events specifying
- * seconds and microseconds.
- */
-#define MSC_ANDROID_TIME_SEC 0x6
-#define MSC_ANDROID_TIME_USEC 0x7
-
namespace android {
enum {
@@ -371,9 +357,6 @@
int32_t controllerNumber;
- int32_t timestampOverrideSec;
- int32_t timestampOverrideUsec;
-
Device(int fd, int32_t id, const std::string& path,
const InputDeviceIdentifier& identifier);
~Device();
@@ -418,6 +401,7 @@
Device* getDeviceByDescriptorLocked(const std::string& descriptor) const;
Device* getDeviceLocked(int32_t deviceId) const;
Device* getDeviceByPathLocked(const char* devicePath) const;
+ Device* getDeviceByFdLocked(int fd) const;
bool hasKeycodeLocked(Device* device, int keycode) const;
@@ -466,10 +450,6 @@
int mWakeReadPipeFd;
int mWakeWritePipeFd;
- // Ids used for epoll notifications not associated with devices.
- static const uint32_t EPOLL_ID_INOTIFY = 0x80000001;
- static const uint32_t EPOLL_ID_WAKE = 0x80000002;
-
// Epoll FD list size hint.
static const int EPOLL_SIZE_HINT = 8;
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 2e984d9..0c9e04b 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -58,6 +58,7 @@
#include <utils/Trace.h>
#include <powermanager/PowerManager.h>
#include <ui/Region.h>
+#include <binder/Binder.h>
#define INDENT " "
#define INDENT2 " "
@@ -818,7 +819,7 @@
sp<InputWindowHandle> focusedWindowHandle =
getValueByKey(mFocusedWindowHandlesByDisplay, getTargetDisplayId(entry));
if (focusedWindowHandle != nullptr) {
- commandEntry->inputWindowHandle = focusedWindowHandle;
+ commandEntry->inputChannel = focusedWindowHandle->getInputChannel();
}
commandEntry->keyEntry = entry;
entry->refCount += 1;
@@ -1064,6 +1065,13 @@
}
}
+void InputDispatcher::removeWindowByTokenLocked(const sp<IBinder>& token) {
+ for (size_t d = 0; d < mTouchStatesByDisplay.size(); d++) {
+ TouchState& state = mTouchStatesByDisplay.editValueAt(d);
+ state.removeWindowByToken(token);
+ }
+}
+
void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout,
const sp<InputChannel>& inputChannel) {
if (newTimeout > 0) {
@@ -1078,17 +1086,10 @@
ssize_t connectionIndex = getConnectionIndexLocked(inputChannel);
if (connectionIndex >= 0) {
sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
- sp<InputWindowHandle> windowHandle = connection->inputWindowHandle;
+ sp<IBinder> token = connection->inputChannel->getToken();
- if (windowHandle != nullptr) {
- const InputWindowInfo* info = windowHandle->getInfo();
- if (info) {
- ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(info->displayId);
- if (stateIndex >= 0) {
- mTouchStatesByDisplay.editValueAt(stateIndex).removeWindow(
- windowHandle);
- }
- }
+ if (token != nullptr) {
+ removeWindowByTokenLocked(token);
}
if (connection->status == Connection::STATUS_NORMAL) {
@@ -1168,7 +1169,8 @@
goto Unresponsive;
}
- ALOGI("Dropping event because there is no focused window or focused application.");
+ ALOGI("Dropping event because there is no focused window or focused application in display "
+ "%" PRId32 ".", displayId);
injectionResult = INPUT_EVENT_INJECTION_FAILED;
goto Failed;
}
@@ -1254,7 +1256,8 @@
bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN;
if (switchedDevice && mTempTouchState.down && !down && !isHoverAction) {
#if DEBUG_FOCUS
- ALOGD("Dropping event because a pointer for a different device is already down.");
+ ALOGD("Dropping event because a pointer for a different device is already down "
+ "in display %" PRId32, displayId);
#endif
// TODO: test multiple simultaneous input streams.
injectionResult = INPUT_EVENT_INJECTION_FAILED;
@@ -1270,7 +1273,8 @@
isSplit = false;
} else if (switchedDevice && maskedAction == AMOTION_EVENT_ACTION_MOVE) {
#if DEBUG_FOCUS
- ALOGI("Dropping move event because a pointer for a different device is already active.");
+ ALOGI("Dropping move event because a pointer for a different device is already active "
+ "in display %" PRId32, displayId);
#endif
// TODO: test multiple simultaneous input streams.
injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
@@ -1335,7 +1339,8 @@
// Try to assign the pointer to the first foreground window we find, if there is one.
newTouchedWindowHandle = mTempTouchState.getFirstForegroundWindowHandle();
if (newTouchedWindowHandle == nullptr) {
- ALOGI("Dropping event because there is no touchable window at (%d, %d).", x, y);
+ ALOGI("Dropping event because there is no touchable window at (%d, %d) in display "
+ "%" PRId32 ".", x, y, displayId);
injectionResult = INPUT_EVENT_INJECTION_FAILED;
goto Failed;
}
@@ -1373,7 +1378,7 @@
if (! mTempTouchState.down) {
#if DEBUG_FOCUS
ALOGD("Dropping event because the pointer is not down or we previously "
- "dropped the pointer down event.");
+ "dropped the pointer down event in display %" PRId32, displayId);
#endif
injectionResult = INPUT_EVENT_INJECTION_FAILED;
goto Failed;
@@ -1393,9 +1398,10 @@
if (oldTouchedWindowHandle != newTouchedWindowHandle
&& newTouchedWindowHandle != nullptr) {
#if DEBUG_FOCUS
- ALOGD("Touch is slipping out of window %s into window %s.",
+ ALOGD("Touch is slipping out of window %s into window %s in display %" PRId32,
oldTouchedWindowHandle->getName().c_str(),
- newTouchedWindowHandle->getName().c_str());
+ newTouchedWindowHandle->getName().c_str(),
+ displayId);
#endif
// Make a slippery exit from the old window.
mTempTouchState.addOrUpdateWindow(oldTouchedWindowHandle,
@@ -1464,7 +1470,8 @@
}
if (! haveForegroundWindow) {
#if DEBUG_FOCUS
- ALOGD("Dropping event because there is no touched foreground window to receive it.");
+ ALOGD("Dropping event because there is no touched foreground window in display %" PRId32
+ " to receive it.", displayId);
#endif
injectionResult = INPUT_EVENT_INJECTION_FAILED;
goto Failed;
@@ -1689,7 +1696,7 @@
} else {
// If there is no monitor channel registered or all monitor channel unregistered,
// the display can't detect the extra system gesture by a copy of input events.
- ALOGW("There is no monitor channel found in display=%" PRId32, displayId);
+ ALOGW("There is no monitor channel found in display %" PRId32, displayId);
}
}
@@ -3011,11 +3018,13 @@
const Vector<sp<InputWindowHandle>> windowHandles = it.second;
size_t numWindows = windowHandles.size();
for (size_t i = 0; i < numWindows; i++) {
- if (windowHandles.itemAt(i) == windowHandle) {
+ if (windowHandles.itemAt(i)->getInputChannel()->getToken()
+ == windowHandle->getInputChannel()->getToken()) {
if (windowHandle->getInfo()->displayId != it.first) {
- ALOGE("Found window %s in display %d, but it should belong to display %d",
- windowHandle->getName().c_str(), it.first,
- windowHandle->getInfo()->displayId);
+ ALOGE("Found window %s in display %" PRId32
+ ", but it should belong to display %" PRId32,
+ windowHandle->getName().c_str(), it.first,
+ windowHandle->getInfo()->displayId);
}
return true;
}
@@ -3034,7 +3043,7 @@
void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle>>& inputWindowHandles,
int32_t displayId) {
#if DEBUG_FOCUS
- ALOGD("setInputWindows");
+ ALOGD("setInputWindows displayId=%" PRId32, displayId);
#endif
{ // acquire lock
AutoMutex _l(mLock);
@@ -3085,8 +3094,8 @@
if (oldFocusedWindowHandle != newFocusedWindowHandle) {
if (oldFocusedWindowHandle != nullptr) {
#if DEBUG_FOCUS
- ALOGD("Focus left window: %s",
- oldFocusedWindowHandle->getName().c_str());
+ ALOGD("Focus left window: %s in display %" PRId32,
+ oldFocusedWindowHandle->getName().c_str(), displayId);
#endif
sp<InputChannel> focusedInputChannel = oldFocusedWindowHandle->getInputChannel();
if (focusedInputChannel != nullptr) {
@@ -3099,8 +3108,8 @@
}
if (newFocusedWindowHandle != nullptr) {
#if DEBUG_FOCUS
- ALOGD("Focus entered window: %s",
- newFocusedWindowHandle->getName().c_str());
+ ALOGD("Focus entered window: %s in display %" PRId32,
+ newFocusedWindowHandle->getName().c_str(), displayId);
#endif
mFocusedWindowHandlesByDisplay[displayId] = newFocusedWindowHandle;
}
@@ -3113,8 +3122,8 @@
TouchedWindow& touchedWindow = state.windows.editItemAt(i);
if (!hasWindowHandleLocked(touchedWindow.windowHandle)) {
#if DEBUG_FOCUS
- ALOGD("Touched window was removed: %s",
- touchedWindow.windowHandle->getName().c_str());
+ ALOGD("Touched window was removed: %s in display %" PRId32,
+ touchedWindow.windowHandle->getName().c_str(), displayId);
#endif
sp<InputChannel> touchedInputChannel =
touchedWindow.windowHandle->getInputChannel();
@@ -3142,7 +3151,7 @@
#if DEBUG_FOCUS
ALOGD("Window went away: %s", oldWindowHandle->getName().c_str());
#endif
- oldWindowHandle->releaseInfo();
+ oldWindowHandle->releaseChannel();
}
}
} // release lock
@@ -3154,7 +3163,7 @@
void InputDispatcher::setFocusedApplication(
int32_t displayId, const sp<InputApplicationHandle>& inputApplicationHandle) {
#if DEBUG_FOCUS
- ALOGD("setFocusedApplication");
+ ALOGD("setFocusedApplication displayId=%" PRId32, displayId);
#endif
{ // acquire lock
AutoMutex _l(mLock);
@@ -3469,7 +3478,7 @@
if (!mWindowHandlesByDisplay.empty()) {
for (auto& it : mWindowHandlesByDisplay) {
const Vector<sp<InputWindowHandle>> windowHandles = it.second;
- dump += StringPrintf(INDENT "Display: %d\n", it.first);
+ dump += StringPrintf(INDENT "Display: %" PRId32 "\n", it.first);
if (!windowHandles.isEmpty()) {
dump += INDENT2 "Windows:\n";
for (size_t i = 0; i < windowHandles.size(); i++) {
@@ -3509,7 +3518,7 @@
if (!mMonitoringChannelsByDisplay.empty()) {
for (auto& it : mMonitoringChannelsByDisplay) {
const Vector<sp<InputChannel>>& monitoringChannels = it.second;
- dump += INDENT "MonitoringChannels in Display %d:\n";
+ dump += StringPrintf(INDENT "MonitoringChannels in display %" PRId32 ":\n", it.first);
const size_t numChannels = monitoringChannels.size();
for (size_t i = 0; i < numChannels; i++) {
const sp<InputChannel>& channel = monitoringChannels[i];
@@ -3632,8 +3641,7 @@
mConfig.keyRepeatTimeout * 0.000001f);
}
-status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
- const sp<InputWindowHandle>& inputWindowHandle, int32_t displayId) {
+status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel, int32_t displayId) {
#if DEBUG_REGISTRATION
ALOGD("channel '%s' ~ registerInputChannel - displayId=%" PRId32,
inputChannel->getName().c_str(), displayId);
@@ -3642,17 +3650,20 @@
{ // acquire lock
AutoMutex _l(mLock);
+ // If InputWindowHandle is null and displayId is not ADISPLAY_ID_NONE,
+ // treat inputChannel as monitor channel for displayId.
+ bool monitor = inputChannel->getToken() == nullptr && displayId != ADISPLAY_ID_NONE;
+ if (monitor) {
+ inputChannel->setToken(new BBinder());
+ }
+
if (getConnectionIndexLocked(inputChannel) >= 0) {
ALOGW("Attempted to register already registered input channel '%s'",
inputChannel->getName().c_str());
return BAD_VALUE;
}
- // If InputWindowHandle is null and displayId is not ADISPLAY_ID_NONE,
- // treat inputChannel as monitor channel for displayId.
- bool monitor = inputWindowHandle == nullptr && displayId != ADISPLAY_ID_NONE;
-
- sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);
+ sp<Connection> connection = new Connection(inputChannel, monitor);
int fd = inputChannel->getFd();
mConnectionsByFd.add(fd, connection);
@@ -3737,11 +3748,14 @@
}
ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputChannel) {
- ssize_t connectionIndex = mConnectionsByFd.indexOfKey(inputChannel->getFd());
- if (connectionIndex >= 0) {
- sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
- if (connection->inputChannel.get() == inputChannel.get()) {
- return connectionIndex;
+ if (inputChannel == nullptr) {
+ return -1;
+ }
+
+ for (size_t i = 0; i < mConnectionsByFd.size(); i++) {
+ sp<Connection> connection = mConnectionsByFd.valueAt(i);
+ if (connection->inputChannel->getToken() == inputChannel->getToken()) {
+ return i;
}
}
@@ -3798,7 +3812,7 @@
CommandEntry* commandEntry = postCommandLocked(
& InputDispatcher::doNotifyANRLockedInterruptible);
commandEntry->inputApplicationHandle = applicationHandle;
- commandEntry->inputWindowHandle = windowHandle;
+ commandEntry->inputChannel = windowHandle != nullptr ? windowHandle->getInputChannel() : nullptr;
commandEntry->reason = reason;
}
@@ -3818,7 +3832,7 @@
if (connection->status != Connection::STATUS_ZOMBIE) {
mLock.unlock();
- mPolicy->notifyInputChannelBroken(connection->inputWindowHandle);
+ mPolicy->notifyInputChannelBroken(connection->inputChannel->getToken());
mLock.lock();
}
@@ -3829,14 +3843,14 @@
mLock.unlock();
nsecs_t newTimeout = mPolicy->notifyANR(
- commandEntry->inputApplicationHandle, commandEntry->inputWindowHandle,
+ commandEntry->inputApplicationHandle,
+ commandEntry->inputChannel ? commandEntry->inputChannel->getToken() : nullptr,
commandEntry->reason);
mLock.lock();
resumeAfterTargetsNotReadyTimeoutLocked(newTimeout,
- commandEntry->inputWindowHandle != nullptr
- ? commandEntry->inputWindowHandle->getInputChannel() : nullptr);
+ commandEntry->inputChannel);
}
void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
@@ -3849,7 +3863,9 @@
mLock.unlock();
android::base::Timer t;
- nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle,
+ sp<IBinder> token = commandEntry->inputChannel != nullptr ?
+ commandEntry->inputChannel->getToken() : nullptr;
+ nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(token,
&event, entry->policyFlags);
if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
ALOGW("Excessive delay in interceptKeyBeforeDispatching; took %s ms",
@@ -3950,7 +3966,7 @@
mLock.unlock();
- mPolicy->dispatchUnhandledKey(connection->inputWindowHandle,
+ mPolicy->dispatchUnhandledKey(connection->inputChannel->getToken(),
&event, keyEntry->policyFlags, &event);
mLock.lock();
@@ -3995,7 +4011,7 @@
mLock.unlock();
- bool fallback = mPolicy->dispatchUnhandledKey(connection->inputWindowHandle,
+ bool fallback = mPolicy->dispatchUnhandledKey(connection->inputChannel->getToken(),
&event, keyEntry->policyFlags, &event);
mLock.lock();
@@ -4711,9 +4727,8 @@
// --- InputDispatcher::Connection ---
-InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel,
- const sp<InputWindowHandle>& inputWindowHandle, bool monitor) :
- status(STATUS_NORMAL), inputChannel(inputChannel), inputWindowHandle(inputWindowHandle),
+InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel, bool monitor) :
+ status(STATUS_NORMAL), inputChannel(inputChannel),
monitor(monitor),
inputPublisher(inputChannel), inputPublisherBlocked(false) {
}
@@ -4722,8 +4737,8 @@
}
const std::string InputDispatcher::Connection::getWindowName() const {
- if (inputWindowHandle != nullptr) {
- return inputWindowHandle->getName();
+ if (inputChannel != nullptr) {
+ return inputChannel->getName();
}
if (monitor) {
return "monitor";
@@ -4830,6 +4845,15 @@
}
}
+void InputDispatcher::TouchState::removeWindowByToken(const sp<IBinder>& token) {
+ for (size_t i = 0; i < windows.size(); i++) {
+ if (windows.itemAt(i).windowHandle->getInputChannel()->getToken() == token) {
+ windows.removeAt(i);
+ return;
+ }
+ }
+}
+
void InputDispatcher::TouchState::filterNonAsIsTouchWindows() {
for (size_t i = 0 ; i < windows.size(); ) {
TouchedWindow& window = windows.editItemAt(i);
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 5efb2fa..5016082 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -208,11 +208,11 @@
/* Notifies the system that an application is not responding.
* Returns a new timeout to continue waiting, or 0 to abort dispatch. */
virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
- const sp<InputWindowHandle>& inputWindowHandle,
+ const sp<IBinder>& token,
const std::string& reason) = 0;
/* Notifies the system that an input channel is unrecoverably broken. */
- virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) = 0;
+ virtual void notifyInputChannelBroken(const sp<IBinder>& token) = 0;
/* Gets the input dispatcher configuration. */
virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0;
@@ -243,12 +243,12 @@
virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) = 0;
/* Allows the policy a chance to intercept a key before dispatching. */
- virtual nsecs_t interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle,
+ virtual nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>& token,
const KeyEvent* keyEvent, uint32_t policyFlags) = 0;
/* Allows the policy a chance to perform default processing for an unhandled key.
* Returns an alternate keycode to redispatch as a fallback, or 0 to give up. */
- virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle,
+ virtual bool dispatchUnhandledKey(const sp<IBinder>& token,
const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) = 0;
/* Notifies the policy about switch events.
@@ -352,8 +352,8 @@
*
* This method may be called on any thread (usually by the input manager).
*/
- virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel,
- const sp<InputWindowHandle>& inputWindowHandle, int32_t displayId) = 0;
+ virtual status_t registerInputChannel(
+ const sp<InputChannel>& inputChannel, int32_t displayId) = 0;
/* Unregister input channels that will no longer receive input events.
*
@@ -413,7 +413,7 @@
const sp<InputChannel>& toChannel);
virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel,
- const sp<InputWindowHandle>& inputWindowHandle, int32_t displayId);
+ int32_t displayId);
virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel);
private:
@@ -617,11 +617,11 @@
nsecs_t eventTime;
KeyEntry* keyEntry;
sp<InputApplicationHandle> inputApplicationHandle;
- sp<InputWindowHandle> inputWindowHandle;
std::string reason;
int32_t userActivityEventType;
uint32_t seq;
bool handled;
+ sp<InputChannel> inputChannel;
};
// Generic queue implementation.
@@ -834,7 +834,6 @@
Status status;
sp<InputChannel> inputChannel; // never null
- sp<InputWindowHandle> inputWindowHandle; // may be null
bool monitor;
InputPublisher inputPublisher;
InputState inputState;
@@ -850,8 +849,7 @@
// yet received a "finished" response from the application.
Queue<DispatchEntry> waitQueue;
- explicit Connection(const sp<InputChannel>& inputChannel,
- const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
+ explicit Connection(const sp<InputChannel>& inputChannel, bool monitor);
inline const std::string getInputChannelName() const { return inputChannel->getName(); }
@@ -1007,6 +1005,7 @@
void addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle,
int32_t targetFlags, BitSet32 pointerIds);
void removeWindow(const sp<InputWindowHandle>& windowHandle);
+ void removeWindowByToken(const sp<IBinder>& token);
void filterNonAsIsTouchWindows();
sp<InputWindowHandle> getFirstForegroundWindowHandle() const;
bool isSlippery() const;
@@ -1062,6 +1061,9 @@
const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle,
nsecs_t* nextWakeupTime, const char* reason);
+
+ void removeWindowByTokenLocked(const sp<IBinder>& token);
+
void resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout,
const sp<InputChannel>& inputChannel);
nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime);
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 519faa6..40ca6a7 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -21,6 +21,7 @@
#include "InputManager.h"
#include <log/log.h>
+#include <unordered_map>
namespace android {
@@ -90,4 +91,39 @@
return mDispatcher;
}
+class BinderApplicationHandle : public InputApplicationHandle {
+public:
+ BinderApplicationHandle() = default;
+
+ bool updateInfo() override {
+ return true;
+ }
+};
+
+class BinderWindowHandle : public InputWindowHandle {
+public:
+ BinderWindowHandle(const InputWindowInfo& info) :
+ InputWindowHandle(new BinderApplicationHandle()) {
+
+ mInfo = info;
+ }
+
+ bool updateInfo() override {
+ return true;
+ }
+};
+
+void InputManager::setInputWindows(const Vector<InputWindowInfo>& infos) {
+ std::unordered_map<int32_t, Vector<sp<InputWindowHandle>>> handlesPerDisplay;
+
+ Vector<sp<InputWindowHandle>> handles;
+ for (const auto& info : infos) {
+ handlesPerDisplay.emplace(info.displayId, Vector<sp<InputWindowHandle>>());
+ handlesPerDisplay[info.displayId].add(new BinderWindowHandle(info));
+ }
+ for (auto const& i : handlesPerDisplay) {
+ mDispatcher->setInputWindows(i.second, i.first);
+ }
+}
+
} // namespace android
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index 92e0af2..d0e4cb0 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -27,6 +27,8 @@
#include <input/Input.h>
#include <input/InputTransport.h>
+
+#include <input/IInputFlinger.h>
#include <utils/Errors.h>
#include <utils/Vector.h>
#include <utils/Timers.h>
@@ -72,7 +74,7 @@
virtual sp<InputDispatcherInterface> getDispatcher() = 0;
};
-class InputManager : public InputManagerInterface {
+class InputManager : public InputManagerInterface, public BnInputFlinger {
protected:
virtual ~InputManager();
@@ -93,6 +95,8 @@
virtual sp<InputReaderInterface> getReader();
virtual sp<InputDispatcherInterface> getDispatcher();
+ virtual void setInputWindows(const Vector<InputWindowInfo>& handles);
+
private:
sp<InputReaderInterface> mReader;
sp<InputReaderThread> mReaderThread;
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 869bd71..e85e6ef 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -3480,8 +3480,8 @@
}
// Raw width and height in the natural orientation.
- int32_t rawWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1;
- int32_t rawHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1;
+ int32_t rawWidth = mRawPointerAxes.getRawWidth();
+ int32_t rawHeight = mRawPointerAxes.getRawHeight();
// Get associated display dimensions.
DisplayViewport newViewport;
@@ -3913,8 +3913,8 @@
int32_t touchScreenLeft = mRawPointerAxes.x.minValue;
int32_t touchScreenTop = mRawPointerAxes.y.minValue;
- int32_t touchScreenWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1;
- int32_t touchScreenHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1;
+ int32_t touchScreenWidth = mRawPointerAxes.getRawWidth();
+ int32_t touchScreenHeight = mRawPointerAxes.getRawHeight();
for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) {
const VirtualKeyDefinition& virtualKeyDefinition =
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index 3410bc9..9b0007a 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -772,6 +772,8 @@
RawAbsoluteAxisInfo slot;
RawPointerAxes();
+ inline int32_t getRawWidth() const { return x.maxValue - x.minValue + 1; }
+ inline int32_t getRawHeight() const { return y.maxValue - y.minValue + 1; }
void clear();
};
diff --git a/services/inputflinger/host/Android.bp b/services/inputflinger/host/Android.bp
index 775dbdc..0e48f24 100644
--- a/services/inputflinger/host/Android.bp
+++ b/services/inputflinger/host/Android.bp
@@ -30,6 +30,9 @@
"libutils",
"libhardware",
],
+ static_libs: [
+ "libarect",
+ ],
cflags: [
"-Wall",
@@ -54,7 +57,10 @@
shared_libs: [
"libbinder",
"libinputflingerhost",
- "libutils",
+ "libutils"
+ ],
+ static_libs: [
+ "libarect",
],
init_rc: ["inputflinger.rc"],
diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h
index 39e69e5..15ca7b3 100644
--- a/services/inputflinger/host/InputFlinger.h
+++ b/services/inputflinger/host/InputFlinger.h
@@ -39,6 +39,7 @@
InputFlinger() ANDROID_API;
virtual status_t dump(int fd, const Vector<String16>& args);
+ void setInputWindows(const Vector<InputWindowInfo>&) {}
private:
virtual ~InputFlinger();
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index a1cd71c..ea42855 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -15,6 +15,7 @@
],
shared_libs: [
"libbase",
+ "libbinder",
"libcutils",
"liblog",
"libutils",
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index c6eaf9f..e860db5 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -16,6 +16,8 @@
#include "../InputDispatcher.h"
+#include <binder/Binder.h>
+
#include <gtest/gtest.h>
#include <linux/input.h>
@@ -53,12 +55,12 @@
}
virtual nsecs_t notifyANR(const sp<InputApplicationHandle>&,
- const sp<InputWindowHandle>&,
+ const sp<IBinder>&,
const std::string&) {
return 0;
}
- virtual void notifyInputChannelBroken(const sp<InputWindowHandle>&) {
+ virtual void notifyInputChannelBroken(const sp<IBinder>&) {
}
virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
@@ -75,12 +77,12 @@
virtual void interceptMotionBeforeQueueing(nsecs_t, uint32_t&) {
}
- virtual nsecs_t interceptKeyBeforeDispatching(const sp<InputWindowHandle>&,
+ virtual nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>&,
const KeyEvent*, uint32_t) {
return 0;
}
- virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>&,
+ virtual bool dispatchUnhandledKey(const sp<IBinder>&,
const KeyEvent*, uint32_t, KeyEvent*) {
return false;
}
@@ -336,6 +338,7 @@
const std::string name, int32_t displayId) :
mDispatcher(dispatcher), mName(name), mDisplayId(displayId) {
InputChannel::openInputChannelPair(name, mServerChannel, mClientChannel);
+
mConsumer = new InputConsumer(mClientChannel);
}
@@ -366,34 +369,32 @@
InputWindowHandle(inputApplicationHandle),
FakeInputReceiver(dispatcher, name, displayId),
mFocused(false) {
- mDispatcher->registerInputChannel(mServerChannel, this, displayId);
+ mServerChannel->setToken(new BBinder());
+ mDispatcher->registerInputChannel(mServerChannel, displayId);
}
virtual bool updateInfo() {
- if (!mInfo) {
- mInfo = new InputWindowInfo();
- }
- mInfo->inputChannel = mServerChannel;
- mInfo->name = mName;
- mInfo->layoutParamsFlags = 0;
- mInfo->layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
- mInfo->dispatchingTimeout = DISPATCHING_TIMEOUT;
- mInfo->frameLeft = 0;
- mInfo->frameTop = 0;
- mInfo->frameRight = WIDTH;
- mInfo->frameBottom = HEIGHT;
- mInfo->scaleFactor = 1.0;
- mInfo->addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
- mInfo->visible = true;
- mInfo->canReceiveKeys = true;
- mInfo->hasFocus = mFocused;
- mInfo->hasWallpaper = false;
- mInfo->paused = false;
- mInfo->layer = 0;
- mInfo->ownerPid = INJECTOR_PID;
- mInfo->ownerUid = INJECTOR_UID;
- mInfo->inputFeatures = 0;
- mInfo->displayId = mDisplayId;
+ mInfo.inputChannel = mServerChannel;
+ mInfo.name = mName;
+ mInfo.layoutParamsFlags = 0;
+ mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
+ mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
+ mInfo.frameLeft = 0;
+ mInfo.frameTop = 0;
+ mInfo.frameRight = WIDTH;
+ mInfo.frameBottom = HEIGHT;
+ mInfo.scaleFactor = 1.0;
+ mInfo.addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
+ mInfo.visible = true;
+ mInfo.canReceiveKeys = true;
+ mInfo.hasFocus = mFocused;
+ mInfo.hasWallpaper = false;
+ mInfo.paused = false;
+ mInfo.layer = 0;
+ mInfo.ownerPid = INJECTOR_PID;
+ mInfo.ownerUid = INJECTOR_UID;
+ mInfo.inputFeatures = 0;
+ mInfo.displayId = mDisplayId;
return true;
}
@@ -529,6 +530,34 @@
windowSecond->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
}
+TEST_F(InputDispatcherTest, SetInputWindow_InputWindowInfo) {
+ sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+
+ sp<FakeWindowHandle> windowTop = new FakeWindowHandle(application, mDispatcher, "Top",
+ ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second",
+ ADISPLAY_ID_DEFAULT);
+
+ windowTop->setFocus();
+
+ Vector<sp<InputWindowHandle>> inputWindowHandles;
+ inputWindowHandles.add(windowTop);
+ inputWindowHandles.add(windowSecond);
+
+ mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
+
+ // Release channel for window is no longer valid.
+ windowTop->releaseChannel();
+
+ // Test inject a motion down, should timeout because of no target channel.
+ ASSERT_EQ(INPUT_EVENT_INJECTION_TIMED_OUT, injectKeyDown(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_TIMED_OUT";
+
+ // Top window is invalid, so it should not receive any input event.
+ windowTop->assertNoEvents();
+ windowSecond->assertNoEvents();
+}
+
/* Test InputDispatcher for MultiDisplay */
class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest {
public:
@@ -624,7 +653,7 @@
public:
FakeMonitorReceiver(const sp<InputDispatcher>& dispatcher, const std::string name,
int32_t displayId) : FakeInputReceiver(dispatcher, name, displayId) {
- mDispatcher->registerInputChannel(mServerChannel, nullptr, displayId);
+ mDispatcher->registerInputChannel(mServerChannel, displayId);
}
};
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 16003a2..f168db9 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -19,10 +19,6 @@
"-DGL_GLEXT_PROTOTYPES",
"-DEGL_EGLEXT_PROTOTYPES",
],
- include_dirs: [
- "frameworks/native/vulkan/vkjson",
- "frameworks/native/vulkan/include",
- ],
shared_libs: [
"android.frameworks.vr.composer@1.0",
"android.hardware.configstore-utils",
@@ -59,13 +55,11 @@
"libtimestats_proto",
"libui",
"libutils",
- "libvulkan",
],
static_libs: [
"librenderengine",
"libserviceutils",
"libtrace_proto",
- "libvkjson",
"libvr_manager",
"libvrflinger",
],
@@ -132,7 +126,6 @@
"Effects/Daltonizer.cpp",
"EventLog/EventLog.cpp",
"FrameTracker.cpp",
- "GpuService.cpp",
"Layer.cpp",
"LayerBE.cpp",
"LayerProtoHelper.cpp",
@@ -153,6 +146,7 @@
"SurfaceInterceptor.cpp",
"SurfaceTracing.cpp",
"TimeStats/TimeStats.cpp",
+ "TransactionCompletedThread.cpp",
],
}
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 440f1e2..ade62bf 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -229,18 +229,14 @@
getBE().compositionInfo.mBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102);
}
-void BufferLayer::setPerFrameData(const sp<const DisplayDevice>& display) {
+void BufferLayer::setPerFrameData(DisplayId displayId, const ui::Transform& transform,
+ const Rect& viewport, int32_t supportedPerFrameMetadata) {
+ RETURN_IF_NO_HWC_LAYER(displayId);
+
// Apply this display's projection's viewport to the visible region
// before giving it to the HWC HAL.
- const ui::Transform& tr = display->getTransform();
- const auto& viewport = display->getViewport();
- Region visible = tr.transform(visibleRegion.intersect(viewport));
- const auto displayId = display->getId();
- if (!hasHwcLayer(displayId)) {
- ALOGE("[%s] failed to setPerFrameData: no HWC layer found (%d)",
- mName.string(), displayId);
- return;
- }
+ Region visible = transform.transform(visibleRegion.intersect(viewport));
+
auto& hwcInfo = getBE().mHwcLayers[displayId];
auto& hwcLayer = hwcInfo.layer;
auto error = hwcLayer->setVisibleRegion(visible);
@@ -290,7 +286,7 @@
}
const HdrMetadata& metadata = getDrawingHdrMetadata();
- error = hwcLayer->setPerFrameMetadata(display->getSupportedPerFrameMetadata(), metadata);
+ error = hwcLayer->setPerFrameMetadata(supportedPerFrameMetadata, metadata);
if (error != HWC2::Error::None && error != HWC2::Error::Unsupported) {
ALOGE("[%s] Failed to set hdrMetadata: %s (%d)", mName.string(),
to_string(error).c_str(), static_cast<int32_t>(error));
@@ -303,10 +299,10 @@
}
getBE().compositionInfo.hwc.dataspace = mCurrentDataSpace;
getBE().compositionInfo.hwc.hdrMetadata = getDrawingHdrMetadata();
- getBE().compositionInfo.hwc.supportedPerFrameMetadata = display->getSupportedPerFrameMetadata();
+ getBE().compositionInfo.hwc.supportedPerFrameMetadata = supportedPerFrameMetadata;
getBE().compositionInfo.hwc.colorTransform = getColorTransform();
- setHwcLayerBuffer(display);
+ setHwcLayerBuffer(displayId);
}
bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) {
@@ -318,10 +314,10 @@
return hasReadyFrame();
}
-bool BufferLayer::onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
+bool BufferLayer::onPostComposition(const std::optional<DisplayId>& displayId,
+ const std::shared_ptr<FenceTime>& glDoneFence,
const std::shared_ptr<FenceTime>& presentFence,
const CompositorTiming& compositorTiming) {
-
// mFrameLatencyNeeded is true when a new frame was latched for the
// composition.
if (!mFrameLatencyNeeded) return false;
@@ -352,11 +348,10 @@
if (presentFence->isValid()) {
mTimeStats.setPresentFence(layerID, mCurrentFrameNumber, presentFence);
mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
- } else if (mFlinger->getHwComposer().isConnected(HWC_DISPLAY_PRIMARY)) {
+ } else if (displayId && mFlinger->getHwComposer().isConnected(*displayId)) {
// The HWC doesn't support present fences, so use the refresh
// timestamp instead.
- const nsecs_t actualPresentTime =
- mFlinger->getHwComposer().getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
+ const nsecs_t actualPresentTime = mFlinger->getHwComposer().getRefreshTimestamp(*displayId);
mTimeStats.setPresentTime(layerID, mCurrentFrameNumber, actualPresentTime);
mFrameTracker.setActualPresentTime(actualPresentTime);
}
@@ -522,7 +517,7 @@
}
bool BufferLayer::hasReadyFrame() const {
- return hasDrawingBuffer() || getSidebandStreamChanged() || getAutoRefresh();
+ return hasFrameUpdate() || getSidebandStreamChanged() || getAutoRefresh();
}
uint32_t BufferLayer::getEffectiveScalingMode() const {
@@ -660,13 +655,43 @@
}
uint64_t BufferLayer::getHeadFrameNumber() const {
- if (hasDrawingBuffer()) {
+ if (hasFrameUpdate()) {
return getFrameNumber();
} else {
return mCurrentFrameNumber;
}
}
+Rect BufferLayer::getBufferSize(const State& s) const {
+ // If we have a sideband stream, or we are scaling the buffer then return the layer size since
+ // we cannot determine the buffer size.
+ if ((s.sidebandStream != nullptr) ||
+ (getEffectiveScalingMode() != NATIVE_WINDOW_SCALING_MODE_FREEZE)) {
+ return Rect(getActiveWidth(s), getActiveHeight(s));
+ }
+
+ if (mActiveBuffer == nullptr) {
+ return Rect::INVALID_RECT;
+ }
+
+ uint32_t bufWidth = mActiveBuffer->getWidth();
+ uint32_t bufHeight = mActiveBuffer->getHeight();
+
+ // Undo any transformations on the buffer and return the result.
+ if (mCurrentTransform & ui::Transform::ROT_90) {
+ std::swap(bufWidth, bufHeight);
+ }
+
+ if (getTransformToDisplayInverse()) {
+ uint32_t invTransform = DisplayDevice::getPrimaryDisplayOrientationTransform();
+ if (invTransform & ui::Transform::ROT_90) {
+ std::swap(bufWidth, bufHeight);
+ }
+ }
+
+ return Rect(bufWidth, bufHeight);
+}
+
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index d000d85..690a4e5 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -80,10 +80,12 @@
bool isHdrY410() const override;
- void setPerFrameData(const sp<const DisplayDevice>& displayDevice) override;
+ void setPerFrameData(DisplayId displayId, const ui::Transform& transform, const Rect& viewport,
+ int32_t supportedPerFrameMetadata) override;
bool onPreComposition(nsecs_t refreshStartTime) override;
- bool onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
+ bool onPostComposition(const std::optional<DisplayId>& displayId,
+ const std::shared_ptr<FenceTime>& glDoneFence,
const std::shared_ptr<FenceTime>& presentFence,
const CompositorTiming& compositorTiming) override;
@@ -134,7 +136,7 @@
virtual std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) = 0;
- virtual bool hasDrawingBuffer() const = 0;
+ virtual bool hasFrameUpdate() const = 0;
virtual void setFilteringEnabled(bool enabled) = 0;
@@ -145,7 +147,7 @@
virtual status_t updateActiveBuffer() = 0;
virtual status_t updateFrameNumber(nsecs_t latchTime) = 0;
- virtual void setHwcLayerBuffer(const sp<const DisplayDevice>& display) = 0;
+ virtual void setHwcLayerBuffer(DisplayId displayId) = 0;
// -----------------------------------------------------------------------
@@ -186,6 +188,8 @@
mutable renderengine::Texture mTexture;
bool mRefreshPending{false};
+
+ Rect getBufferSize(const State& s) const override;
};
} // namespace android
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index c130bc5..78ab23a 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -82,7 +82,7 @@
return true;
}
- if (!hasDrawingBuffer()) {
+ if (!hasFrameUpdate()) {
return false;
}
@@ -110,7 +110,7 @@
return true;
}
- if (!hasDrawingBuffer()) {
+ if (!hasFrameUpdate()) {
return true;
}
@@ -206,7 +206,7 @@
return {};
}
-bool BufferQueueLayer::hasDrawingBuffer() const {
+bool BufferQueueLayer::hasFrameUpdate() const {
return mQueuedFrames > 0;
}
@@ -325,8 +325,7 @@
return NO_ERROR;
}
-void BufferQueueLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
- const auto displayId = display->getId();
+void BufferQueueLayer::setHwcLayerBuffer(DisplayId displayId) {
auto& hwcInfo = getBE().mHwcLayers[displayId];
auto& hwcLayer = hwcInfo.layer;
@@ -353,6 +352,11 @@
void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
// Add this buffer from our internal queue tracker
{ // Autolock scope
+ // Report the timestamp to the Scheduler.
+ if (mFlinger->mUseScheduler) {
+ mFlinger->mScheduler->addNewFrameTimestamp(item.mTimestamp, item.mIsAutoTimestamp);
+ }
+
Mutex::Autolock lock(mQueueItemLock);
// Reset the frame number tracker when we receive the first buffer after
// a frame number reset
@@ -403,7 +407,7 @@
}
}
- if (!hasDrawingBuffer()) {
+ if (!hasFrameUpdate()) {
ALOGE("Can't replace a frame on an empty queue");
return;
}
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index c9ebe04..ae0b705 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -83,7 +83,7 @@
std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) override;
- bool hasDrawingBuffer() const override;
+ bool hasFrameUpdate() const override;
void setFilteringEnabled(bool enabled) override;
@@ -94,8 +94,7 @@
status_t updateActiveBuffer() override;
status_t updateFrameNumber(nsecs_t latchTime) override;
- void setHwcLayerBuffer(const sp<const DisplayDevice>& display) override;
- // -----------------------------------------------------------------------
+ void setHwcLayerBuffer(DisplayId displayId) override;
// -----------------------------------------------------------------------
// Interface implementation for BufferLayerConsumer::ContentsChangedListener
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 73098bf..425f5c7 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -35,15 +35,19 @@
};
// clang-format on
-BufferStateLayer::BufferStateLayer(const LayerCreationArgs& args) : BufferLayer(args) {}
+BufferStateLayer::BufferStateLayer(const LayerCreationArgs& args) : BufferLayer(args) {
+ mOverrideScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
+}
BufferStateLayer::~BufferStateLayer() = default;
// -----------------------------------------------------------------------
// Interface implementation for Layer
// -----------------------------------------------------------------------
-void BufferStateLayer::onLayerDisplayed(const sp<Fence>& /*releaseFence*/) {
- // TODO(marissaw): send the release fence back to buffer owner
- return;
+void BufferStateLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
+ // The transaction completed callback can only be sent if the release fence from the PREVIOUS
+ // frame has fired. In practice, we should never actually wait on the previous release fence
+ // but we should store it just in case.
+ mPreviousReleaseFence = releaseFence;
}
void BufferStateLayer::setTransformHint(uint32_t /*orientation*/) const {
@@ -52,7 +56,6 @@
}
void BufferStateLayer::releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) {
- // TODO(marissaw): use this to signal the buffer owner
return;
}
@@ -61,7 +64,13 @@
return true;
}
- return hasDrawingBuffer();
+ return hasFrameUpdate();
+}
+
+bool BufferStateLayer::willPresentCurrentTransaction() const {
+ // Returns true if the most recent Transaction applied to CurrentState will be presented.
+ return getSidebandStreamChanged() || getAutoRefresh() ||
+ (mCurrentState.modified && mCurrentState.buffer != nullptr);
}
bool BufferStateLayer::getTransformToDisplayInverse() const {
@@ -81,6 +90,7 @@
while (!mPendingStates.empty()) {
popPendingState(stateToCommit);
}
+ mCurrentStateModified = stateUpdateAvailable && mCurrentState.modified;
mCurrentState.modified = false;
return stateUpdateAvailable;
}
@@ -118,7 +128,11 @@
return true;
}
-bool BufferStateLayer::setBuffer(sp<GraphicBuffer> buffer) {
+bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer) {
+ if (mCurrentState.buffer) {
+ mReleasePreviousBuffer = true;
+ }
+
mCurrentState.sequence++;
mCurrentState.buffer = buffer;
mCurrentState.modified = true;
@@ -127,6 +141,9 @@
}
bool BufferStateLayer::setAcquireFence(const sp<Fence>& fence) {
+ // The acquire fences of BufferStateLayers have already signaled before they are set
+ mCallbackHandleAcquireTime = fence->getSignalTime();
+
mCurrentState.acquireFence = fence;
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
@@ -182,6 +199,44 @@
return true;
}
+bool BufferStateLayer::setTransactionCompletedListeners(
+ const std::vector<sp<CallbackHandle>>& handles) {
+ // If there is no handle, we will not send a callback so reset mReleasePreviousBuffer and return
+ if (handles.empty()) {
+ mReleasePreviousBuffer = false;
+ return false;
+ }
+
+ const bool willPresent = willPresentCurrentTransaction();
+
+ for (const auto& handle : handles) {
+ // If this transaction set a buffer on this layer, release its previous buffer
+ handle->releasePreviousBuffer = mReleasePreviousBuffer;
+
+ // If this layer will be presented in this frame
+ if (willPresent) {
+ // If this transaction set an acquire fence on this layer, set its acquire time
+ handle->acquireTime = mCallbackHandleAcquireTime;
+
+ // Notify the transaction completed thread that there is a pending latched callback
+ // handle
+ mFlinger->getTransactionCompletedThread().registerPendingLatchedCallbackHandle(handle);
+
+ // Store so latched time and release fence can be set
+ mCurrentState.callbackHandles.push_back(handle);
+
+ } else { // If this layer will NOT need to be relatched and presented this frame
+ // Notify the transaction completed thread this handle is done
+ mFlinger->getTransactionCompletedThread().addUnlatchedCallbackHandle(handle);
+ }
+ }
+
+ mReleasePreviousBuffer = false;
+ mCallbackHandleAcquireTime = -1;
+
+ return willPresent;
+}
+
bool BufferStateLayer::setSize(uint32_t w, uint32_t h) {
if (mCurrentState.active.w == w && mCurrentState.active.h == h) return false;
mCurrentState.active.w = w;
@@ -265,7 +320,7 @@
}
uint32_t BufferStateLayer::getDrawingScalingMode() const {
- return NATIVE_WINDOW_SCALING_MODE_FREEZE;
+ return NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
}
Region BufferStateLayer::getDrawingSurfaceDamage() const {
@@ -314,8 +369,8 @@
return {};
}
-bool BufferStateLayer::hasDrawingBuffer() const {
- return getDrawingState().buffer != nullptr;
+bool BufferStateLayer::hasFrameUpdate() const {
+ return mCurrentStateModified && getCurrentState().buffer != nullptr;
}
void BufferStateLayer::setFilteringEnabled(bool enabled) {
@@ -394,7 +449,7 @@
}
}
- if (mOverrideScalingMode == NATIVE_WINDOW_SCALING_MODE_FREEZE &&
+ if (getEffectiveScalingMode() == NATIVE_WINDOW_SCALING_MODE_FREEZE &&
(s.active.w != bufferWidth || s.active.h != bufferHeight)) {
ALOGE("[%s] rejecting buffer: "
"bufferWidth=%d, bufferHeight=%d, front.active.{w=%d, h=%d}",
@@ -403,6 +458,10 @@
return BAD_VALUE;
}
+ mFlinger->getTransactionCompletedThread()
+ .addLatchedCallbackHandles(getDrawingState().callbackHandles, latchTime,
+ mPreviousReleaseFence);
+
// Handle sync fences
if (SyncFeatures::getInstance().useNativeFenceSync() && releaseFence != Fence::NO_FENCE) {
// TODO(alecmouri): Fail somewhere upstream if the fence is invalid.
@@ -497,8 +556,7 @@
return NO_ERROR;
}
-void BufferStateLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
- const auto displayId = display->getId();
+void BufferStateLayer::setHwcLayerBuffer(DisplayId displayId) {
auto& hwcInfo = getBE().mHwcLayers[displayId];
auto& hwcLayer = hwcInfo.layer;
@@ -513,6 +571,7 @@
s.buffer->handle, to_string(error).c_str(), static_cast<int32_t>(error));
}
+ mCurrentStateModified = false;
mFrameNumber++;
}
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 0c6eaf5..315d5af 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -62,13 +62,14 @@
bool setTransform(uint32_t transform) override;
bool setTransformToDisplayInverse(bool transformToDisplayInverse) override;
bool setCrop(const Rect& crop) override;
- bool setBuffer(sp<GraphicBuffer> buffer) override;
+ bool setBuffer(const sp<GraphicBuffer>& buffer) override;
bool setAcquireFence(const sp<Fence>& fence) override;
bool setDataspace(ui::Dataspace dataspace) override;
bool setHdrMetadata(const HdrMetadata& hdrMetadata) override;
bool setSurfaceDamageRegion(const Region& surfaceDamage) override;
bool setApi(int32_t api) override;
bool setSidebandStream(const sp<NativeHandle>& sidebandStream) override;
+ bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& handles) override;
bool setSize(uint32_t w, uint32_t h) override;
bool setPosition(float x, float y, bool immediate) override;
@@ -110,7 +111,7 @@
std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) override;
- bool hasDrawingBuffer() const override;
+ bool hasFrameUpdate() const override;
void setFilteringEnabled(bool enabled) override;
@@ -121,10 +122,11 @@
status_t updateActiveBuffer() override;
status_t updateFrameNumber(nsecs_t latchTime) override;
- void setHwcLayerBuffer(const sp<const DisplayDevice>& display) override;
- // -----------------------------------------------------------------------
+ void setHwcLayerBuffer(DisplayId displayId) override;
+
private:
void onFirstRef() override;
+ bool willPresentCurrentTransaction() const;
static const std::array<float, 16> IDENTITY_MATRIX;
@@ -136,6 +138,12 @@
uint32_t mFrameNumber{0};
+ sp<Fence> mPreviousReleaseFence;
+
+ bool mCurrentStateModified = false;
+ bool mReleasePreviousBuffer = false;
+ nsecs_t mCallbackHandleAcquireTime = -1;
+
// TODO(marissaw): support sticky transform for LEGACY camera mode
};
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 263f872..9c34308 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -57,16 +57,12 @@
return !isHiddenByPolicy() && getAlpha() > 0.0f;
}
-void ColorLayer::setPerFrameData(const sp<const DisplayDevice>& display) {
- const ui::Transform& tr = display->getTransform();
- const auto& viewport = display->getViewport();
- Region visible = tr.transform(visibleRegion.intersect(viewport));
- const auto displayId = display->getId();
- if (!hasHwcLayer(displayId)) {
- ALOGE("[%s] failed to setPerFrameData: no HWC layer found (%d)",
- mName.string(), displayId);
- return;
- }
+void ColorLayer::setPerFrameData(DisplayId displayId, const ui::Transform& transform,
+ const Rect& viewport, int32_t /* supportedPerFrameMetadata */) {
+ RETURN_IF_NO_HWC_LAYER(displayId);
+
+ Region visible = transform.transform(visibleRegion.intersect(viewport));
+
auto& hwcInfo = getBE().mHwcLayers[displayId];
auto& hwcLayer = hwcInfo.layer;
auto error = hwcLayer->setVisibleRegion(visible);
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index 2c10357..d1b1697 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -33,7 +33,10 @@
bool useIdentityTransform);
bool isVisible() const override;
- void setPerFrameData(const sp<const DisplayDevice>& display) override;
+ void setPerFrameData(DisplayId displayId, const ui::Transform& transform, const Rect& viewport,
+ int32_t supportedPerFrameMetadata) override;
+
+ bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
protected:
FloatRect computeCrop(const sp<const DisplayDevice>& /*display*/) const override { return {}; }
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index 44e843e..ca49f6c 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -32,6 +32,6 @@
return !isHiddenByPolicy();
}
-void ContainerLayer::setPerFrameData(const sp<const DisplayDevice>&) {}
+void ContainerLayer::setPerFrameData(DisplayId, const ui::Transform&, const Rect&, int32_t) {}
} // namespace android
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index 8eddc7f..413844b 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -33,9 +33,12 @@
bool useIdentityTransform) override;
bool isVisible() const override;
- void setPerFrameData(const sp<const DisplayDevice>& display) override;
+ void setPerFrameData(DisplayId displayId, const ui::Transform& transform, const Rect& viewport,
+ int32_t supportedPerFrameMetadata) override;
bool isCreatedFromMainThread() const override { return true; }
+
+ bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
};
} // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 91b18c9..5342bcf 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -212,22 +212,20 @@
DisplayDeviceCreationArgs::DisplayDeviceCreationArgs(const sp<SurfaceFlinger>& flinger,
const wp<IBinder>& displayToken,
- DisplayDevice::DisplayType type, int32_t id)
- : flinger(flinger), displayToken(displayToken), type(type), id(id) {}
+ const std::optional<DisplayId>& displayId)
+ : flinger(flinger), displayToken(displayToken), displayId(displayId) {}
DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs&& args)
: lastCompositionHadVisibleLayers(false),
mFlinger(args.flinger),
- mType(args.type),
- mId(args.id),
mDisplayToken(args.displayToken),
+ mId(args.displayId),
mNativeWindow(args.nativeWindow),
mDisplaySurface(args.displaySurface),
mSurface{std::move(args.renderSurface)},
- mDisplayWidth(args.displayWidth),
- mDisplayHeight(args.displayHeight),
mDisplayInstallOrientation(args.displayInstallOrientation),
mPageFlipCount(0),
+ mIsVirtual(args.isVirtual),
mIsSecure(args.isSecure),
mLayerStack(NO_LAYER_STACK),
mOrientation(),
@@ -240,14 +238,13 @@
mHasHdr10(false),
mHasHLG(false),
mHasDolbyVision(false),
- mSupportedPerFrameMetadata(args.supportedPerFrameMetadata) {
+ mSupportedPerFrameMetadata(args.supportedPerFrameMetadata),
+ mIsPrimary(args.isPrimary) {
populateColorModes(args.hwcColorModes);
ALOGE_IF(!mNativeWindow, "No native window was set for display");
ALOGE_IF(!mDisplaySurface, "No display surface was set for display");
ALOGE_IF(!mSurface, "No render surface was set for display");
- ALOGE_IF(mDisplayWidth <= 0 || mDisplayHeight <= 0,
- "Invalid dimensions of %d x %d were set for display", mDisplayWidth, mDisplayHeight);
std::vector<Hdr> types = args.hdrCapabilities.getSupportedHdrTypes();
for (Hdr hdrType : types) {
@@ -286,6 +283,10 @@
}
mHdrCapabilities = HdrCapabilities(types, maxLuminance, maxAverageLuminance, minLuminance);
+ ANativeWindow* const window = mNativeWindow.get();
+ mDisplayWidth = ANativeWindow_getWidth(window);
+ mDisplayHeight = ANativeWindow_getHeight(window);
+
// initialize the display orientation transform.
setProjection(DisplayState::eOrientationDefault, mViewport, mFrame);
}
@@ -293,16 +294,12 @@
DisplayDevice::~DisplayDevice() = default;
void DisplayDevice::disconnect(HWComposer& hwc) {
- if (mId >= 0) {
- hwc.disconnectDisplay(mId);
- mId = -1;
+ if (mId) {
+ hwc.disconnectDisplay(*mId);
+ mId.reset();
}
}
-bool DisplayDevice::isValid() const {
- return mFlinger != nullptr;
-}
-
int DisplayDevice::getWidth() const {
return mDisplayWidth;
}
@@ -334,9 +331,11 @@
status_t DisplayDevice::prepareFrame(HWComposer& hwc,
std::vector<CompositionInfo>& compositionData) {
- status_t error = hwc.prepare(*this, compositionData);
- if (error != NO_ERROR) {
- return error;
+ if (mId) {
+ status_t error = hwc.prepare(*mId, compositionData);
+ if (error != NO_ERROR) {
+ return error;
+ }
}
DisplaySurface::CompositionType compositionType;
@@ -539,13 +538,8 @@
ANativeWindow* const window = mNativeWindow.get();
mSurface->setNativeWindow(window);
- mDisplayWidth = mSurface->getWidth();
- mDisplayHeight = mSurface->getHeight();
-
- LOG_FATAL_IF(mDisplayWidth != newWidth,
- "Unable to set new width to %d", newWidth);
- LOG_FATAL_IF(mDisplayHeight != newHeight,
- "Unable to set new height to %d", newHeight);
+ mDisplayWidth = newWidth;
+ mDisplayHeight = newHeight;
}
void DisplayDevice::setProjection(int orientation,
@@ -600,7 +594,7 @@
// need to take care of primary display rotation for mGlobalTransform
// for case if the panel is not installed aligned with device orientation
- if (mType == DisplayType::DISPLAY_PRIMARY) {
+ if (isPrimary()) {
DisplayDevice::orientationToTransfrom(
(orientation + mDisplayInstallOrientation) % (DisplayState::eOrientation270 + 1),
w, h, &R);
@@ -648,7 +642,7 @@
}
std::string DisplayDevice::getDebugName() const {
- const auto id = mId >= 0 ? base::StringPrintf("%d, ", mId) : std::string();
+ const auto id = mId ? to_string(*mId) + ", " : std::string();
return base::StringPrintf("DisplayDevice{%s%s%s\"%s\"}", id.c_str(),
isPrimary() ? "primary, " : "", isVirtual() ? "virtual, " : "",
mDisplayName.c_str());
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 152d0ec..bcd3330 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -20,6 +20,7 @@
#include <stdlib.h>
#include <memory>
+#include <optional>
#include <string>
#include <unordered_map>
@@ -37,6 +38,7 @@
#include <utils/String8.h>
#include <utils/Timers.h>
+#include "DisplayHardware/DisplayIdentification.h"
#include "RenderArea.h"
struct ANativeWindow;
@@ -66,25 +68,15 @@
Region undefinedRegion;
bool lastCompositionHadVisibleLayers;
- enum DisplayType {
- DISPLAY_ID_INVALID = -1,
- DISPLAY_PRIMARY = HWC_DISPLAY_PRIMARY,
- DISPLAY_EXTERNAL = HWC_DISPLAY_EXTERNAL,
- DISPLAY_VIRTUAL = HWC_DISPLAY_VIRTUAL,
- NUM_BUILTIN_DISPLAY_TYPES = HWC_NUM_PHYSICAL_DISPLAY_TYPES,
- };
-
enum {
NO_LAYER_STACK = 0xFFFFFFFF,
};
explicit DisplayDevice(DisplayDeviceCreationArgs&& args);
-
~DisplayDevice();
- // whether this is a valid object. An invalid DisplayDevice is returned
- // when an non existing id is requested
- bool isValid() const;
+ bool isVirtual() const { return mIsVirtual; }
+ bool isPrimary() const { return mIsPrimary; }
// isSecure indicates whether this display can be trusted to display
// secure surfaces.
@@ -118,11 +110,9 @@
bool needsFiltering() const { return mNeedsFiltering; }
uint32_t getLayerStack() const { return mLayerStack; }
- int32_t getDisplayType() const { return mType; }
- bool isPrimary() const { return mType == DISPLAY_PRIMARY; }
- bool isVirtual() const { return mType == DISPLAY_VIRTUAL; }
- int32_t getId() const { return mId; }
- const wp<IBinder>& getDisplayToken() const { return mDisplayToken; }
+
+ const std::optional<DisplayId>& getId() const { return mId; }
+ const wp<IBinder>& getDisplayToken() const { return mDisplayToken; }
int32_t getSupportedPerFrameMetadata() const { return mSupportedPerFrameMetadata; }
@@ -207,13 +197,10 @@
void dump(String8& result) const;
private:
- /*
- * Constants, set during initialization
- */
- sp<SurfaceFlinger> mFlinger;
- DisplayType mType;
- int32_t mId;
- wp<IBinder> mDisplayToken;
+ const sp<SurfaceFlinger> mFlinger;
+ const wp<IBinder> mDisplayToken;
+
+ std::optional<DisplayId> mId;
// ANativeWindow this display is rendering into
sp<ANativeWindow> mNativeWindow;
@@ -225,7 +212,9 @@
const int mDisplayInstallOrientation;
mutable uint32_t mPageFlipCount;
std::string mDisplayName;
- bool mIsSecure;
+
+ const bool mIsVirtual;
+ const bool mIsSecure;
/*
* Can only accessed from the main thread, these members
@@ -299,13 +288,16 @@
const ui::ColorMode mode, const ui::RenderIntent intent);
std::unordered_map<ColorModeKey, ColorModeValue> mColorModes;
+
+ // TODO(b/74619554): Remove special cases for primary display.
+ const bool mIsPrimary;
};
struct DisplayDeviceState {
- bool isVirtual() const { return type >= DisplayDevice::DISPLAY_VIRTUAL; }
+ bool isVirtual() const { return !displayId.has_value(); }
int32_t sequenceId = sNextSequenceId++;
- DisplayDevice::DisplayType type = DisplayDevice::DISPLAY_ID_INVALID;
+ std::optional<DisplayId> displayId;
sp<IGraphicBufferProducer> surface;
uint32_t layerStack = DisplayDevice::NO_LAYER_STACK;
Rect viewport;
@@ -324,25 +316,24 @@
// We use a constructor to ensure some of the values are set, without
// assuming a default value.
DisplayDeviceCreationArgs(const sp<SurfaceFlinger>& flinger, const wp<IBinder>& displayToken,
- DisplayDevice::DisplayType type, int32_t id);
+ const std::optional<DisplayId>& displayId);
const sp<SurfaceFlinger> flinger;
const wp<IBinder> displayToken;
- const DisplayDevice::DisplayType type;
- const int32_t id;
+ const std::optional<DisplayId> displayId;
+ bool isVirtual{false};
bool isSecure{false};
sp<ANativeWindow> nativeWindow;
sp<DisplaySurface> displaySurface;
std::unique_ptr<renderengine::Surface> renderSurface;
- int displayWidth{0};
- int displayHeight{0};
int displayInstallOrientation{DisplayState::eOrientationDefault};
bool hasWideColorGamut{false};
HdrCapabilities hdrCapabilities;
int32_t supportedPerFrameMetadata{0};
std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> hwcColorModes;
int initialPowerMode{HWC_POWER_MODE_NORMAL};
+ bool isPrimary{false};
};
class DisplayRenderArea : public RenderArea {
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
index dcc4138..ba7818d 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
@@ -33,6 +33,9 @@
constexpr size_t kEdidHeaderLength = 5;
+constexpr uint16_t kFallbackEdidManufacturerId = 0;
+constexpr uint16_t kVirtualEdidManufacturerId = 0xffffu;
+
std::optional<uint8_t> getEdidDescriptorType(const byte_view& view) {
if (view.size() < kEdidHeaderLength || view[0] || view[1] || view[2] || view[4]) {
return {};
@@ -61,12 +64,16 @@
return letter < 'A' || letter > 'Z' ? '\0' : letter;
}
-DisplayId getEdidDisplayId(uint8_t port, uint16_t manufacturerId, uint32_t displayNameHash) {
- return (static_cast<DisplayId>(manufacturerId) << 40) |
- (static_cast<DisplayId>(displayNameHash) << 8) | port;
+} // namespace
+
+uint16_t DisplayId::manufacturerId() const {
+ return static_cast<uint16_t>(value >> 40);
}
-} // namespace
+DisplayId DisplayId::fromEdid(uint8_t port, uint16_t manufacturerId, uint32_t displayNameHash) {
+ return {(static_cast<Type>(manufacturerId) << 40) | (static_cast<Type>(displayNameHash) << 8) |
+ port};
+}
bool isEdid(const DisplayIdentificationData& data) {
const uint8_t kMagic[] = {0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0};
@@ -165,7 +172,12 @@
return a && b && c ? std::make_optional(PnpId{a, b, c}) : std::nullopt;
}
-std::optional<DisplayId> generateDisplayId(uint8_t port, const DisplayIdentificationData& data) {
+std::optional<PnpId> getPnpId(DisplayId displayId) {
+ return getPnpId(displayId.manufacturerId());
+}
+
+std::optional<DisplayIdentificationInfo> parseDisplayIdentificationData(
+ uint8_t port, const DisplayIdentificationData& data) {
if (!isEdid(data)) {
ALOGE("Display identification data has unknown format.");
return {};
@@ -179,7 +191,16 @@
// Hash display name instead of using product code or serial number, since the latter have been
// observed to change on some displays with multiple inputs.
const auto hash = static_cast<uint32_t>(std::hash<std::string_view>()(edid->displayName));
- return getEdidDisplayId(port, edid->manufacturerId, hash);
+ return DisplayIdentificationInfo{DisplayId::fromEdid(port, edid->manufacturerId, hash),
+ std::string(edid->displayName)};
+}
+
+DisplayId getFallbackDisplayId(uint8_t port) {
+ return DisplayId::fromEdid(port, kFallbackEdidManufacturerId, 0);
+}
+
+DisplayId getVirtualDisplayId(uint32_t id) {
+ return DisplayId::fromEdid(0, kVirtualEdidManufacturerId, id);
}
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
index 379f2d3..1599995 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
@@ -19,14 +19,40 @@
#include <array>
#include <cstdint>
#include <optional>
+#include <string>
#include <string_view>
#include <vector>
namespace android {
-using DisplayId = uint64_t;
+struct DisplayId {
+ using Type = uint64_t;
+ Type value;
+
+ uint16_t manufacturerId() const;
+
+ static DisplayId fromEdid(uint8_t port, uint16_t manufacturerId, uint32_t displayNameHash);
+};
+
+inline bool operator==(DisplayId lhs, DisplayId rhs) {
+ return lhs.value == rhs.value;
+}
+
+inline bool operator!=(DisplayId lhs, DisplayId rhs) {
+ return !(lhs == rhs);
+}
+
+inline std::string to_string(DisplayId displayId) {
+ return std::to_string(displayId.value);
+}
+
using DisplayIdentificationData = std::vector<uint8_t>;
+struct DisplayIdentificationInfo {
+ DisplayId id;
+ std::string name;
+};
+
// NUL-terminated plug and play ID.
using PnpId = std::array<char, 4>;
@@ -39,7 +65,23 @@
bool isEdid(const DisplayIdentificationData&);
std::optional<Edid> parseEdid(const DisplayIdentificationData&);
std::optional<PnpId> getPnpId(uint16_t manufacturerId);
+std::optional<PnpId> getPnpId(DisplayId);
-std::optional<DisplayId> generateDisplayId(uint8_t port, const DisplayIdentificationData&);
+std::optional<DisplayIdentificationInfo> parseDisplayIdentificationData(
+ uint8_t port, const DisplayIdentificationData&);
+
+DisplayId getFallbackDisplayId(uint8_t port);
+DisplayId getVirtualDisplayId(uint32_t id);
} // namespace android
+
+namespace std {
+
+template <>
+struct hash<android::DisplayId> {
+ size_t operator()(android::DisplayId displayId) const {
+ return hash<android::DisplayId::Type>()(displayId.value);
+ }
+};
+
+} // namespace std
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index e6d7834..27812f7 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -52,26 +52,25 @@
*
*/
-FramebufferSurface::FramebufferSurface(HWComposer& hwc, int disp,
- const sp<IGraphicBufferConsumer>& consumer) :
- ConsumerBase(consumer),
- mDisplayType(disp),
- mCurrentBufferSlot(-1),
- mCurrentBuffer(),
- mCurrentFence(Fence::NO_FENCE),
- mHwc(hwc),
- mHasPendingRelease(false),
- mPreviousBufferSlot(BufferQueue::INVALID_BUFFER_SLOT),
- mPreviousBuffer()
-{
- ALOGV("Creating for display %d", disp);
+FramebufferSurface::FramebufferSurface(HWComposer& hwc, DisplayId displayId,
+ const sp<IGraphicBufferConsumer>& consumer)
+ : ConsumerBase(consumer),
+ mDisplayId(displayId),
+ mCurrentBufferSlot(-1),
+ mCurrentBuffer(),
+ mCurrentFence(Fence::NO_FENCE),
+ mHwc(hwc),
+ mHasPendingRelease(false),
+ mPreviousBufferSlot(BufferQueue::INVALID_BUFFER_SLOT),
+ mPreviousBuffer() {
+ ALOGV("Creating for display %s", to_string(displayId).c_str());
mName = "FramebufferSurface";
mConsumer->setConsumerName(mName);
mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_FB |
GRALLOC_USAGE_HW_RENDER |
GRALLOC_USAGE_HW_COMPOSER);
- const auto& activeConfig = mHwc.getActiveConfig(disp);
+ const auto& activeConfig = mHwc.getActiveConfig(displayId);
mConsumer->setDefaultBufferSize(activeConfig->getWidth(),
activeConfig->getHeight());
mConsumer->setMaxAcquiredBufferCount(
@@ -142,8 +141,7 @@
mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer,
&outSlot, &outBuffer);
outDataspace = static_cast<Dataspace>(item.mDataSpace);
- status_t result =
- mHwc.setClientTarget(mDisplayType, outSlot, outFence, outBuffer, outDataspace);
+ status_t result = mHwc.setClientTarget(mDisplayId, outSlot, outFence, outBuffer, outDataspace);
if (result != NO_ERROR) {
ALOGE("error posting framebuffer: %d", result);
return result;
@@ -161,7 +159,7 @@
void FramebufferSurface::onFrameCommitted() {
if (mHasPendingRelease) {
- sp<Fence> fence = mHwc.getPresentFence(mDisplayType);
+ sp<Fence> fence = mHwc.getPresentFence(mDisplayId);
if (fence->isValid()) {
status_t result = addReleaseFence(mPreviousBufferSlot,
mPreviousBuffer, fence);
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index 0fd8e9e..2431dfd 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_SF_FRAMEBUFFER_SURFACE_H
#define ANDROID_SF_FRAMEBUFFER_SURFACE_H
+#include "DisplayIdentification.h"
#include "DisplaySurface.h"
#include "HWComposerBufferCache.h"
@@ -38,7 +39,8 @@
class FramebufferSurface : public ConsumerBase,
public DisplaySurface {
public:
- FramebufferSurface(HWComposer& hwc, int disp, const sp<IGraphicBufferConsumer>& consumer);
+ FramebufferSurface(HWComposer& hwc, DisplayId displayId,
+ const sp<IGraphicBufferConsumer>& consumer);
virtual status_t beginFrame(bool mustRecompose);
virtual status_t prepareFrame(CompositionType compositionType);
@@ -63,8 +65,7 @@
status_t nextBuffer(uint32_t& outSlot, sp<GraphicBuffer>& outBuffer,
sp<Fence>& outFence, ui::Dataspace& outDataspace);
- // mDisplayType must match one of the HWC display types
- int mDisplayType;
+ const DisplayId mDisplayId;
// mCurrentBufferIndex is the slot index of the current buffer or
// INVALID_BUFFER_SLOT to indicate that either there is no current buffer
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index d827fd2..0f25b52 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -58,15 +58,15 @@
ALOGE("%s failed for HWC display %" PRIu64 ": %s", __FUNCTION__, hwcDisplayId, msg)
#define LOG_DISPLAY_ERROR(displayId, msg) \
- ALOGE("%s failed for display %d: %s", __FUNCTION__, displayId, msg)
+ ALOGE("%s failed for display %s: %s", __FUNCTION__, to_string(displayId).c_str(), msg)
-#define LOG_HWC_ERROR(what, error, displayId) \
- ALOGE("%s: %s failed for display %d: %s (%d)", __FUNCTION__, what, displayId, \
- to_string(error).c_str(), static_cast<int32_t>(error))
+#define LOG_HWC_ERROR(what, error, displayId) \
+ ALOGE("%s: %s failed for display %s: %s (%d)", __FUNCTION__, what, \
+ to_string(displayId).c_str(), to_string(error).c_str(), static_cast<int32_t>(error))
#define RETURN_IF_INVALID_DISPLAY(displayId, ...) \
do { \
- if (!isValidDisplay(displayId)) { \
+ if (mDisplayData.count(displayId) == 0) { \
LOG_DISPLAY_ERROR(displayId, "Invalid display"); \
return __VA_ARGS__; \
} \
@@ -92,7 +92,9 @@
HWComposer::HWComposer(std::unique_ptr<android::Hwc2::Composer> composer)
: mHwcDevice(std::make_unique<HWC2::Device>(std::move(composer))) {}
-HWComposer::~HWComposer() = default;
+HWComposer::~HWComposer() {
+ mDisplayData.clear();
+}
void HWComposer::registerCallback(HWC2::ComposerCallback* callback,
int32_t sequenceId) {
@@ -116,11 +118,6 @@
return mHwcDevice->getCapabilities().count(capability) > 0;
}
-bool HWComposer::isValidDisplay(int32_t displayId) const {
- return static_cast<size_t>(displayId) < mDisplayData.size() &&
- mDisplayData[displayId].hwcDisplay;
-}
-
void HWComposer::validateChange(HWC2::Composition from, HWC2::Composition to) {
bool valid = true;
switch (from) {
@@ -146,52 +143,50 @@
}
}
-std::optional<DisplayId> HWComposer::onHotplug(hwc2_display_t hwcDisplayId, int32_t displayType,
- HWC2::Connection connection) {
- if (displayType >= HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
- ALOGE("Invalid display type of %d", displayType);
- return {};
- }
+std::optional<DisplayIdentificationInfo> HWComposer::onHotplug(hwc2_display_t hwcDisplayId,
+ HWC2::Connection connection) {
+ std::optional<DisplayIdentificationInfo> info;
- ALOGV("hotplug: %" PRIu64 ", %s %s", hwcDisplayId,
- displayType == DisplayDevice::DISPLAY_PRIMARY ? "primary" : "external",
- to_string(connection).c_str());
- mHwcDevice->onHotplug(hwcDisplayId, connection);
-
- std::optional<DisplayId> displayId;
-
- if (connection == HWC2::Connection::Connected) {
- uint8_t port;
- DisplayIdentificationData data;
- if (getDisplayIdentificationData(hwcDisplayId, &port, &data)) {
- displayId = generateDisplayId(port, data);
- ALOGE_IF(!displayId, "Failed to generate stable ID for display %" PRIu64, hwcDisplayId);
+ if (const auto displayId = toPhysicalDisplayId(hwcDisplayId)) {
+ info = DisplayIdentificationInfo{*displayId, std::string()};
+ } else {
+ if (connection == HWC2::Connection::Disconnected) {
+ ALOGE("Ignoring disconnection of invalid HWC display %" PRIu64, hwcDisplayId);
+ return {};
}
+
+ info = onHotplugConnect(hwcDisplayId);
+ if (!info) return {};
}
+ ALOGV("%s: %s %s display %s with HWC ID %" PRIu64, __FUNCTION__, to_string(connection).c_str(),
+ hwcDisplayId == mInternalHwcDisplayId ? "internal" : "external",
+ to_string(info->id).c_str(), hwcDisplayId);
+
+ mHwcDevice->onHotplug(hwcDisplayId, connection);
+
// Disconnect is handled through HWComposer::disconnectDisplay via
// SurfaceFlinger's onHotplugReceived callback handling
if (connection == HWC2::Connection::Connected) {
- mDisplayData[displayType].hwcDisplay = mHwcDevice->getDisplayById(hwcDisplayId);
- mHwcDisplaySlots[hwcDisplayId] = displayType;
+ mDisplayData[info->id].hwcDisplay = mHwcDevice->getDisplayById(hwcDisplayId);
+ mPhysicalDisplayIdMap[hwcDisplayId] = info->id;
}
- return displayId;
+ return info;
}
-bool HWComposer::onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp, int32_t* outDisplayId) {
- const auto it = mHwcDisplaySlots.find(hwcDisplayId);
- if (it == mHwcDisplaySlots.end()) {
- LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Invalid display");
+bool HWComposer::onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp) {
+ const auto displayId = toPhysicalDisplayId(hwcDisplayId);
+ if (!displayId) {
+ LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Invalid HWC display");
return false;
}
- const int32_t displayId = it->second;
- RETURN_IF_INVALID_DISPLAY(displayId, false);
+ RETURN_IF_INVALID_DISPLAY(*displayId, false);
- const auto& displayData = mDisplayData[displayId];
+ const auto& displayData = mDisplayData[*displayId];
if (displayData.isVirtual) {
- LOG_DISPLAY_ERROR(displayId, "Invalid operation on virtual display");
+ LOG_DISPLAY_ERROR(*displayId, "Invalid operation on virtual display");
return false;
}
@@ -202,31 +197,26 @@
// with the same timestamp when turning the display off and on. This
// is a bug in the HWC implementation, but filter the extra events
// out here so they don't cause havoc downstream.
- if (timestamp == mLastHwVSync[displayId]) {
- ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")",
- timestamp);
+ if (timestamp == mLastHwVSync[*displayId]) {
+ ALOGW("Ignoring duplicate VSYNC event from HWC for display %s (t=%" PRId64 ")",
+ to_string(*displayId).c_str(), timestamp);
return false;
}
- mLastHwVSync[displayId] = timestamp;
+ mLastHwVSync[*displayId] = timestamp;
}
- if (outDisplayId) {
- *outDisplayId = displayId;
- }
-
- char tag[16];
- snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", displayId);
- ATRACE_INT(tag, ++mVSyncCounts[displayId] & 1);
+ const auto tag = "HW_VSYNC_" + to_string(*displayId);
+ ATRACE_INT(tag.c_str(), ++mVSyncCounts[*displayId] & 1);
return true;
}
-status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height,
- ui::PixelFormat* format, int32_t *outId) {
+std::optional<DisplayId> HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height,
+ ui::PixelFormat* format) {
if (mRemainingHwcVirtualDisplays == 0) {
ALOGE("%s: No remaining virtual displays", __FUNCTION__);
- return NO_MEMORY;
+ return {};
}
if (SurfaceFlinger::maxVirtualDisplaySize != 0 &&
@@ -234,41 +224,33 @@
height > SurfaceFlinger::maxVirtualDisplaySize)) {
ALOGE("%s: Display size %ux%u exceeds maximum dimension of %" PRIu64, __FUNCTION__, width,
height, SurfaceFlinger::maxVirtualDisplaySize);
- return INVALID_OPERATION;
+ return {};
}
-
HWC2::Display* display;
auto error = mHwcDevice->createVirtualDisplay(width, height, format,
&display);
if (error != HWC2::Error::None) {
ALOGE("%s: Failed to create HWC virtual display", __FUNCTION__);
- return NO_MEMORY;
+ return {};
}
- size_t displaySlot = 0;
- if (!mFreeDisplaySlots.empty()) {
- displaySlot = *mFreeDisplaySlots.begin();
- mFreeDisplaySlots.erase(displaySlot);
- } else if (mDisplayData.size() < INT32_MAX) {
- // Don't bother allocating a slot larger than we can return
- displaySlot = mDisplayData.size();
- mDisplayData.resize(displaySlot + 1);
+ DisplayId displayId;
+ if (mFreeVirtualDisplayIds.empty()) {
+ displayId = getVirtualDisplayId(mNextVirtualDisplayId++);
} else {
- ALOGE("%s: Unable to allocate a display slot", __FUNCTION__);
- return NO_MEMORY;
+ displayId = *mFreeVirtualDisplayIds.begin();
+ mFreeVirtualDisplayIds.erase(displayId);
}
- auto& displayData = mDisplayData[displaySlot];
+ auto& displayData = mDisplayData[displayId];
displayData.hwcDisplay = display;
displayData.isVirtual = true;
--mRemainingHwcVirtualDisplays;
- *outId = static_cast<int32_t>(displaySlot);
-
- return NO_ERROR;
+ return displayId;
}
-HWC2::Layer* HWComposer::createLayer(int32_t displayId) {
+HWC2::Layer* HWComposer::createLayer(DisplayId displayId) {
RETURN_IF_INVALID_DISPLAY(displayId, nullptr);
auto display = mDisplayData[displayId].hwcDisplay;
@@ -278,7 +260,7 @@
return layer;
}
-void HWComposer::destroyLayer(int32_t displayId, HWC2::Layer* layer) {
+void HWComposer::destroyLayer(DisplayId displayId, HWC2::Layer* layer) {
RETURN_IF_INVALID_DISPLAY(displayId);
auto display = mDisplayData[displayId].hwcDisplay;
@@ -286,7 +268,8 @@
RETURN_IF_HWC_ERROR(error, displayId);
}
-nsecs_t HWComposer::getRefreshTimestamp(int32_t displayId) const {
+nsecs_t HWComposer::getRefreshTimestamp(DisplayId displayId) const {
+ RETURN_IF_INVALID_DISPLAY(displayId, 0);
// this returns the last refresh timestamp.
// if the last one is not available, we estimate it based on
// the refresh period and whatever closest timestamp we have.
@@ -296,17 +279,17 @@
return now - ((now - mLastHwVSync[displayId]) % vsyncPeriod);
}
-bool HWComposer::isConnected(int32_t displayId) const {
+bool HWComposer::isConnected(DisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, false);
- return mDisplayData[displayId].hwcDisplay->isConnected();
+ return mDisplayData.at(displayId).hwcDisplay->isConnected();
}
-std::vector<std::shared_ptr<const HWC2::Display::Config>>
- HWComposer::getConfigs(int32_t displayId) const {
+std::vector<std::shared_ptr<const HWC2::Display::Config>> HWComposer::getConfigs(
+ DisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, {});
- auto& displayData = mDisplayData[displayId];
- auto configs = mDisplayData[displayId].hwcDisplay->getConfigs();
+ const auto& displayData = mDisplayData.at(displayId);
+ auto configs = displayData.hwcDisplay->getConfigs();
if (displayData.configMap.empty()) {
for (size_t i = 0; i < configs.size(); ++i) {
displayData.configMap[i] = configs[i];
@@ -315,12 +298,12 @@
return configs;
}
-std::shared_ptr<const HWC2::Display::Config>
- HWComposer::getActiveConfig(int32_t displayId) const {
+std::shared_ptr<const HWC2::Display::Config> HWComposer::getActiveConfig(
+ DisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, nullptr);
std::shared_ptr<const HWC2::Display::Config> config;
- auto error = mDisplayData[displayId].hwcDisplay->getActiveConfig(&config);
+ auto error = mDisplayData.at(displayId).hwcDisplay->getActiveConfig(&config);
if (error == HWC2::Error::BadConfig) {
LOG_DISPLAY_ERROR(displayId, "No active config");
return nullptr;
@@ -336,11 +319,11 @@
return config;
}
-int HWComposer::getActiveConfigIndex(int32_t displayId) const {
+int HWComposer::getActiveConfigIndex(DisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, -1);
int index;
- auto error = mDisplayData[displayId].hwcDisplay->getActiveConfigIndex(&index);
+ auto error = mDisplayData.at(displayId).hwcDisplay->getActiveConfigIndex(&index);
if (error == HWC2::Error::BadConfig) {
LOG_DISPLAY_ERROR(displayId, "No active config");
return -1;
@@ -356,17 +339,17 @@
return index;
}
-std::vector<ui::ColorMode> HWComposer::getColorModes(int32_t displayId) const {
+std::vector<ui::ColorMode> HWComposer::getColorModes(DisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, {});
std::vector<ui::ColorMode> modes;
- auto error = mDisplayData[displayId].hwcDisplay->getColorModes(&modes);
+ auto error = mDisplayData.at(displayId).hwcDisplay->getColorModes(&modes);
RETURN_IF_HWC_ERROR(error, displayId, {});
return modes;
}
-status_t HWComposer::setActiveColorMode(int32_t displayId, ui::ColorMode mode,
- ui::RenderIntent renderIntent) {
+status_t HWComposer::setActiveColorMode(DisplayId displayId, ui::ColorMode mode,
+ ui::RenderIntent renderIntent) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
auto& displayData = mDisplayData[displayId];
@@ -379,8 +362,7 @@
return NO_ERROR;
}
-
-void HWComposer::setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled) {
+void HWComposer::setVsyncEnabled(DisplayId displayId, HWC2::Vsync enabled) {
RETURN_IF_INVALID_DISPLAY(displayId);
auto& displayData = mDisplayData[displayId];
@@ -401,37 +383,30 @@
displayData.vsyncEnabled = enabled;
- char tag[16];
- snprintf(tag, sizeof(tag), "HW_VSYNC_ON_%1u", displayId);
- ATRACE_INT(tag, enabled == HWC2::Vsync::Enable ? 1 : 0);
+ const auto tag = "HW_VSYNC_ON_" + to_string(displayId);
+ ATRACE_INT(tag.c_str(), enabled == HWC2::Vsync::Enable ? 1 : 0);
}
}
-status_t HWComposer::setClientTarget(int32_t displayId, uint32_t slot,
- const sp<Fence>& acquireFence, const sp<GraphicBuffer>& target,
- ui::Dataspace dataspace) {
+status_t HWComposer::setClientTarget(DisplayId displayId, uint32_t slot,
+ const sp<Fence>& acquireFence, const sp<GraphicBuffer>& target,
+ ui::Dataspace dataspace) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
- ALOGV("setClientTarget for display %d", displayId);
+ ALOGV("%s for display %s", __FUNCTION__, to_string(displayId).c_str());
auto& hwcDisplay = mDisplayData[displayId].hwcDisplay;
auto error = hwcDisplay->setClientTarget(slot, target, acquireFence, dataspace);
RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE);
return NO_ERROR;
}
-status_t HWComposer::prepare(DisplayDevice& display,
- std::vector<CompositionInfo>& compositionData) {
+status_t HWComposer::prepare(DisplayId displayId, std::vector<CompositionInfo>& compositionData) {
ATRACE_CALL();
- Mutex::Autolock _l(mDisplayLock);
- const auto displayId = display.getId();
- if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
- ALOGV("Skipping HWComposer prepare for non-HWC display");
- return NO_ERROR;
- }
-
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
+ Mutex::Autolock _l(mDisplayLock);
+
auto& displayData = mDisplayData[displayId];
auto& hwcDisplay = displayData.hwcDisplay;
if (!hwcDisplay->isConnected()) {
@@ -501,7 +476,8 @@
changedTypes[&*hwcLayer]);
compositionInfo.compositionType = changedTypes[&*hwcLayer];
compositionInfo.layer->mLayer->setCompositionType(displayId,
- compositionInfo.compositionType, false);
+ compositionInfo.compositionType,
+ false);
}
switch (compositionInfo.compositionType) {
@@ -540,49 +516,48 @@
return NO_ERROR;
}
-bool HWComposer::hasDeviceComposition(int32_t displayId) const {
- if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
+bool HWComposer::hasDeviceComposition(const std::optional<DisplayId>& displayId) const {
+ if (!displayId) {
// Displays without a corresponding HWC display are never composed by
// the device
return false;
}
- RETURN_IF_INVALID_DISPLAY(displayId, false);
- return mDisplayData[displayId].hasDeviceComposition;
+ RETURN_IF_INVALID_DISPLAY(*displayId, false);
+ return mDisplayData.at(*displayId).hasDeviceComposition;
}
-bool HWComposer::hasFlipClientTargetRequest(int32_t displayId) const {
- if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
+bool HWComposer::hasFlipClientTargetRequest(const std::optional<DisplayId>& displayId) const {
+ if (!displayId) {
// Displays without a corresponding HWC display are never composed by
// the device
return false;
}
- RETURN_IF_INVALID_DISPLAY(displayId, false);
- return ((static_cast<uint32_t>(mDisplayData[displayId].displayRequests) &
+ RETURN_IF_INVALID_DISPLAY(*displayId, false);
+ return ((static_cast<uint32_t>(mDisplayData.at(*displayId).displayRequests) &
static_cast<uint32_t>(HWC2::DisplayRequest::FlipClientTarget)) != 0);
}
-bool HWComposer::hasClientComposition(int32_t displayId) const {
- if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
+bool HWComposer::hasClientComposition(const std::optional<DisplayId>& displayId) const {
+ if (!displayId) {
// Displays without a corresponding HWC display are always composed by
// the client
return true;
}
- RETURN_IF_INVALID_DISPLAY(displayId, true);
- return mDisplayData[displayId].hasClientComposition;
+ RETURN_IF_INVALID_DISPLAY(*displayId, true);
+ return mDisplayData.at(*displayId).hasClientComposition;
}
-sp<Fence> HWComposer::getPresentFence(int32_t displayId) const {
+sp<Fence> HWComposer::getPresentFence(DisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, Fence::NO_FENCE);
- return mDisplayData[displayId].lastPresentFence;
+ return mDisplayData.at(displayId).lastPresentFence;
}
-sp<Fence> HWComposer::getLayerReleaseFence(int32_t displayId,
- HWC2::Layer* layer) const {
+sp<Fence> HWComposer::getLayerReleaseFence(DisplayId displayId, HWC2::Layer* layer) const {
RETURN_IF_INVALID_DISPLAY(displayId, Fence::NO_FENCE);
- auto displayFences = mDisplayData[displayId].releaseFences;
+ auto displayFences = mDisplayData.at(displayId).releaseFences;
if (displayFences.count(layer) == 0) {
ALOGV("getLayerReleaseFence: Release fence not found");
return Fence::NO_FENCE;
@@ -590,7 +565,7 @@
return displayFences[layer];
}
-status_t HWComposer::presentAndGetReleaseFences(int32_t displayId) {
+status_t HWComposer::presentAndGetReleaseFences(DisplayId displayId) {
ATRACE_CALL();
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
@@ -618,8 +593,7 @@
return NO_ERROR;
}
-status_t HWComposer::setPowerMode(int32_t displayId, int32_t intMode) {
- ALOGV("setPowerMode(%d, %d)", displayId, intMode);
+status_t HWComposer::setPowerMode(DisplayId displayId, int32_t intMode) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
const auto& displayData = mDisplayData[displayId];
@@ -675,7 +649,7 @@
return NO_ERROR;
}
-status_t HWComposer::setActiveConfig(int32_t displayId, size_t configId) {
+status_t HWComposer::setActiveConfig(DisplayId displayId, size_t configId) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
auto& displayData = mDisplayData[displayId];
@@ -689,8 +663,7 @@
return NO_ERROR;
}
-status_t HWComposer::setColorTransform(int32_t displayId,
- const mat4& transform) {
+status_t HWComposer::setColorTransform(DisplayId displayId, const mat4& transform) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
auto& displayData = mDisplayData[displayId];
@@ -702,26 +675,34 @@
return NO_ERROR;
}
-void HWComposer::disconnectDisplay(int32_t displayId) {
+void HWComposer::disconnectDisplay(DisplayId displayId) {
RETURN_IF_INVALID_DISPLAY(displayId);
auto& displayData = mDisplayData[displayId];
// If this was a virtual display, add its slot back for reuse by future
// virtual displays
if (displayData.isVirtual) {
- mFreeDisplaySlots.insert(displayId);
+ mFreeVirtualDisplayIds.insert(displayId);
++mRemainingHwcVirtualDisplays;
}
const auto hwcDisplayId = displayData.hwcDisplay->getId();
- mHwcDisplaySlots.erase(hwcDisplayId);
- displayData = DisplayData();
+ mPhysicalDisplayIdMap.erase(hwcDisplayId);
+ mDisplayData.erase(displayId);
+ mVSyncCounts.erase(displayId);
+
+ // TODO(b/74619554): Select internal/external display from remaining displays.
+ if (hwcDisplayId == mInternalHwcDisplayId) {
+ mInternalHwcDisplayId.reset();
+ } else if (hwcDisplayId == mExternalHwcDisplayId) {
+ mExternalHwcDisplayId.reset();
+ }
mHwcDevice->destroyDisplay(hwcDisplayId);
}
-status_t HWComposer::setOutputBuffer(int32_t displayId,
- const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buffer) {
+status_t HWComposer::setOutputBuffer(DisplayId displayId, const sp<Fence>& acquireFence,
+ const sp<GraphicBuffer>& buffer) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
const auto& displayData = mDisplayData[displayId];
@@ -735,13 +716,12 @@
return NO_ERROR;
}
-void HWComposer::clearReleaseFences(int32_t displayId) {
+void HWComposer::clearReleaseFences(DisplayId displayId) {
RETURN_IF_INVALID_DISPLAY(displayId);
mDisplayData[displayId].releaseFences.clear();
}
-status_t HWComposer::getHdrCapabilities(
- int32_t displayId, HdrCapabilities* outCapabilities) {
+status_t HWComposer::getHdrCapabilities(DisplayId displayId, HdrCapabilities* outCapabilities) {
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
auto& hwcDisplay = mDisplayData[displayId].hwcDisplay;
@@ -750,22 +730,22 @@
return NO_ERROR;
}
-int32_t HWComposer::getSupportedPerFrameMetadata(int32_t displayId) const {
+int32_t HWComposer::getSupportedPerFrameMetadata(DisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, 0);
- return mDisplayData[displayId].hwcDisplay->getSupportedPerFrameMetadata();
+ return mDisplayData.at(displayId).hwcDisplay->getSupportedPerFrameMetadata();
}
-std::vector<ui::RenderIntent> HWComposer::getRenderIntents(int32_t displayId,
- ui::ColorMode colorMode) const {
+std::vector<ui::RenderIntent> HWComposer::getRenderIntents(DisplayId displayId,
+ ui::ColorMode colorMode) const {
RETURN_IF_INVALID_DISPLAY(displayId, {});
std::vector<ui::RenderIntent> renderIntents;
- auto error = mDisplayData[displayId].hwcDisplay->getRenderIntents(colorMode, &renderIntents);
+ auto error = mDisplayData.at(displayId).hwcDisplay->getRenderIntents(colorMode, &renderIntents);
RETURN_IF_HWC_ERROR(error, displayId, {});
return renderIntents;
}
-mat4 HWComposer::getDataspaceSaturationMatrix(int32_t displayId, ui::Dataspace dataspace) {
+mat4 HWComposer::getDataspaceSaturationMatrix(DisplayId displayId, ui::Dataspace dataspace) {
RETURN_IF_INVALID_DISPLAY(displayId, {});
mat4 matrix;
@@ -806,12 +786,67 @@
result.append(mHwcDevice->dump().c_str());
}
-std::optional<hwc2_display_t>
-HWComposer::getHwcDisplayId(int32_t displayId) const {
- if (!isValidDisplay(displayId)) {
+std::optional<DisplayId> HWComposer::toPhysicalDisplayId(hwc2_display_t hwcDisplayId) const {
+ if (const auto it = mPhysicalDisplayIdMap.find(hwcDisplayId);
+ it != mPhysicalDisplayIdMap.end()) {
+ return it->second;
+ }
+ return {};
+}
+
+std::optional<hwc2_display_t> HWComposer::fromPhysicalDisplayId(DisplayId displayId) const {
+ if (const auto it = mDisplayData.find(displayId);
+ it != mDisplayData.end() && !it->second.isVirtual) {
+ return it->second.hwcDisplay->getId();
+ }
+ return {};
+}
+
+std::optional<DisplayIdentificationInfo> HWComposer::onHotplugConnect(hwc2_display_t hwcDisplayId) {
+ if (isUsingVrComposer() && mInternalHwcDisplayId) {
+ ALOGE("Ignoring connection of external display %" PRIu64 " in VR mode", hwcDisplayId);
return {};
}
- return mDisplayData[displayId].hwcDisplay->getId();
+
+ uint8_t port;
+ DisplayIdentificationData data;
+ const bool hasMultiDisplaySupport = getDisplayIdentificationData(hwcDisplayId, &port, &data);
+
+ if (mPhysicalDisplayIdMap.empty()) {
+ mHasMultiDisplaySupport = hasMultiDisplaySupport;
+ ALOGI("Switching to %s multi-display mode",
+ hasMultiDisplaySupport ? "generalized" : "legacy");
+ } else if (mHasMultiDisplaySupport && !hasMultiDisplaySupport) {
+ ALOGE("Ignoring connection of display %" PRIu64 " without identification data",
+ hwcDisplayId);
+ return {};
+ }
+
+ std::optional<DisplayIdentificationInfo> info;
+
+ if (mHasMultiDisplaySupport) {
+ info = parseDisplayIdentificationData(port, data);
+ ALOGE_IF(!info, "Failed to parse identification data for display %" PRIu64, hwcDisplayId);
+ } else if (mInternalHwcDisplayId && mExternalHwcDisplayId) {
+ ALOGE("Ignoring connection of tertiary display %" PRIu64, hwcDisplayId);
+ return {};
+ } else {
+ ALOGW_IF(hasMultiDisplaySupport, "Ignoring identification data for display %" PRIu64,
+ hwcDisplayId);
+ port = mInternalHwcDisplayId ? HWC_DISPLAY_EXTERNAL : HWC_DISPLAY_PRIMARY;
+ }
+
+ if (!mInternalHwcDisplayId) {
+ mInternalHwcDisplayId = hwcDisplayId;
+ } else if (!mExternalHwcDisplayId) {
+ mExternalHwcDisplayId = hwcDisplayId;
+ }
+
+ if (info) return info;
+
+ return DisplayIdentificationInfo{getFallbackDisplayId(port),
+ hwcDisplayId == mInternalHwcDisplayId ? "Internal display"
+ : "External display"};
}
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 4777ca9..b78433d 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -34,7 +34,8 @@
#include <memory>
#include <optional>
-#include <set>
+#include <unordered_map>
+#include <unordered_set>
#include <vector>
#include "DisplayIdentification.h"
@@ -82,101 +83,94 @@
bool hasCapability(HWC2::Capability capability) const;
- // Attempts to allocate a virtual display. If the virtual display is created
- // on the HWC device, outId will contain its HWC ID.
- status_t allocateVirtualDisplay(uint32_t width, uint32_t height,
- ui::PixelFormat* format, int32_t* outId);
+ // Attempts to allocate a virtual display and returns its ID if created on the HWC device.
+ std::optional<DisplayId> allocateVirtualDisplay(uint32_t width, uint32_t height,
+ ui::PixelFormat* format);
// Attempts to create a new layer on this display
- HWC2::Layer* createLayer(int32_t displayId);
+ HWC2::Layer* createLayer(DisplayId displayId);
// Destroy a previously created layer
- void destroyLayer(int32_t displayId, HWC2::Layer* layer);
+ void destroyLayer(DisplayId displayId, HWC2::Layer* layer);
// Asks the HAL what it can do
- status_t prepare(DisplayDevice& display,
- std::vector<CompositionInfo>& compositionData);
+ status_t prepare(DisplayId displayId, std::vector<CompositionInfo>& compositionData);
- status_t setClientTarget(int32_t displayId, uint32_t slot,
- const sp<Fence>& acquireFence,
- const sp<GraphicBuffer>& target, ui::Dataspace dataspace);
+ status_t setClientTarget(DisplayId displayId, uint32_t slot, const sp<Fence>& acquireFence,
+ const sp<GraphicBuffer>& target, ui::Dataspace dataspace);
// Present layers to the display and read releaseFences.
- status_t presentAndGetReleaseFences(int32_t displayId);
+ status_t presentAndGetReleaseFences(DisplayId displayId);
// set power mode
- status_t setPowerMode(int32_t displayId, int mode);
+ status_t setPowerMode(DisplayId displayId, int mode);
// set active config
- status_t setActiveConfig(int32_t displayId, size_t configId);
+ status_t setActiveConfig(DisplayId displayId, size_t configId);
// Sets a color transform to be applied to the result of composition
- status_t setColorTransform(int32_t displayId, const mat4& transform);
+ status_t setColorTransform(DisplayId displayId, const mat4& transform);
// reset state when an external, non-virtual display is disconnected
- void disconnectDisplay(int32_t displayId);
+ void disconnectDisplay(DisplayId displayId);
// does this display have layers handled by HWC
- bool hasDeviceComposition(int32_t displayId) const;
+ bool hasDeviceComposition(const std::optional<DisplayId>& displayId) const;
// does this display have pending request to flip client target
- bool hasFlipClientTargetRequest(int32_t displayId) const;
+ bool hasFlipClientTargetRequest(const std::optional<DisplayId>& displayId) const;
// does this display have layers handled by GLES
- bool hasClientComposition(int32_t displayId) const;
+ bool hasClientComposition(const std::optional<DisplayId>& displayId) const;
// get the present fence received from the last call to present.
- sp<Fence> getPresentFence(int32_t displayId) const;
+ sp<Fence> getPresentFence(DisplayId displayId) const;
// Get last release fence for the given layer
- sp<Fence> getLayerReleaseFence(int32_t displayId,
- HWC2::Layer* layer) const;
+ sp<Fence> getLayerReleaseFence(DisplayId displayId, HWC2::Layer* layer) const;
// Set the output buffer and acquire fence for a virtual display.
// Returns INVALID_OPERATION if displayId is not a virtual display.
- status_t setOutputBuffer(int32_t displayId, const sp<Fence>& acquireFence,
- const sp<GraphicBuffer>& buf);
+ status_t setOutputBuffer(DisplayId displayId, const sp<Fence>& acquireFence,
+ const sp<GraphicBuffer>& buffer);
// After SurfaceFlinger has retrieved the release fences for all the frames,
// it can call this to clear the shared pointers in the release fence map
- void clearReleaseFences(int32_t displayId);
+ void clearReleaseFences(DisplayId displayId);
// Fetches the HDR capabilities of the given display
- status_t getHdrCapabilities(int32_t displayId, HdrCapabilities* outCapabilities);
+ status_t getHdrCapabilities(DisplayId displayId, HdrCapabilities* outCapabilities);
- int32_t getSupportedPerFrameMetadata(int32_t displayId) const;
+ int32_t getSupportedPerFrameMetadata(DisplayId displayId) const;
// Returns the available RenderIntent of the given display.
- std::vector<ui::RenderIntent> getRenderIntents(int32_t displayId, ui::ColorMode colorMode) const;
+ std::vector<ui::RenderIntent> getRenderIntents(DisplayId displayId,
+ ui::ColorMode colorMode) const;
- mat4 getDataspaceSaturationMatrix(int32_t displayId, ui::Dataspace dataspace);
+ mat4 getDataspaceSaturationMatrix(DisplayId displayId, ui::Dataspace dataspace);
// Events handling ---------------------------------------------------------
- // Returns true if successful, false otherwise. The
- // DisplayDevice::DisplayType of the display is returned as an output param.
- bool onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp, int32_t* outDisplay);
- std::optional<DisplayId> onHotplug(hwc2_display_t hwcDisplayId, int32_t displayType,
- HWC2::Connection connection);
+ // Returns stable display ID (and display name on connection of new or previously disconnected
+ // display), or std::nullopt if hotplug event was ignored.
+ std::optional<DisplayIdentificationInfo> onHotplug(hwc2_display_t hwcDisplayId,
+ HWC2::Connection connection);
- void setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled);
+ bool onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp);
+ void setVsyncEnabled(DisplayId displayId, HWC2::Vsync enabled);
- // Query display parameters. Pass in a display index (e.g.
- // HWC_DISPLAY_PRIMARY).
- nsecs_t getRefreshTimestamp(int32_t displayId) const;
- bool isConnected(int32_t displayId) const;
+ nsecs_t getRefreshTimestamp(DisplayId displayId) const;
+ bool isConnected(DisplayId displayId) const;
// Non-const because it can update configMap inside of mDisplayData
- std::vector<std::shared_ptr<const HWC2::Display::Config>>
- getConfigs(int32_t displayId) const;
+ std::vector<std::shared_ptr<const HWC2::Display::Config>> getConfigs(DisplayId displayId) const;
- std::shared_ptr<const HWC2::Display::Config>
- getActiveConfig(int32_t displayId) const;
- int getActiveConfigIndex(int32_t displayId) const;
+ std::shared_ptr<const HWC2::Display::Config> getActiveConfig(DisplayId displayId) const;
+ int getActiveConfigIndex(DisplayId displayId) const;
- std::vector<ui::ColorMode> getColorModes(int32_t displayId) const;
+ std::vector<ui::ColorMode> getColorModes(DisplayId displayId) const;
- status_t setActiveColorMode(int32_t displayId, ui::ColorMode mode,
- ui::RenderIntent renderIntent);
+ status_t setActiveColorMode(DisplayId displayId, ui::ColorMode mode,
+ ui::RenderIntent renderIntent);
bool isUsingVrComposer() const;
@@ -185,12 +179,19 @@
android::Hwc2::Composer* getComposer() const { return mHwcDevice->getComposer(); }
- std::optional<hwc2_display_t> getHwcDisplayId(int32_t displayId) const;
+ // TODO(b/74619554): Remove special cases for internal/external display.
+ std::optional<hwc2_display_t> getInternalHwcDisplayId() const { return mInternalHwcDisplayId; }
+ std::optional<hwc2_display_t> getExternalHwcDisplayId() const { return mExternalHwcDisplayId; }
+
+ std::optional<DisplayId> toPhysicalDisplayId(hwc2_display_t hwcDisplayId) const;
+ std::optional<hwc2_display_t> fromPhysicalDisplayId(DisplayId displayId) const;
+
private:
// For unit tests
friend TestableSurfaceFlinger;
- bool isValidDisplay(int32_t displayId) const;
+ std::optional<DisplayIdentificationInfo> onHotplugConnect(hwc2_display_t hwcDisplayId);
+
static void validateChange(HWC2::Composition from, HWC2::Composition to);
struct cb_context;
@@ -215,21 +216,30 @@
HWC2::Error presentError;
};
- std::unique_ptr<HWC2::Device> mHwcDevice;
- std::vector<DisplayData> mDisplayData{HWC_NUM_PHYSICAL_DISPLAY_TYPES};
- std::set<size_t> mFreeDisplaySlots;
- std::unordered_map<hwc2_display_t, int32_t> mHwcDisplaySlots;
+ std::unordered_map<DisplayId, DisplayData> mDisplayData;
+
+ // This must be destroyed before mDisplayData, because destructor may call back into HWComposer
+ // and look up DisplayData.
+ std::unique_ptr<HWC2::Device> mHwcDevice;
+
+ std::unordered_map<hwc2_display_t, DisplayId> mPhysicalDisplayIdMap;
+ std::optional<hwc2_display_t> mInternalHwcDisplayId;
+ std::optional<hwc2_display_t> mExternalHwcDisplayId;
+ bool mHasMultiDisplaySupport = false;
+
// protect mDisplayData from races between prepare and dump
mutable Mutex mDisplayLock;
cb_context* mCBContext = nullptr;
- size_t mVSyncCounts[HWC_NUM_PHYSICAL_DISPLAY_TYPES]{0, 0};
+ std::unordered_map<DisplayId, size_t> mVSyncCounts;
+
+ std::unordered_set<DisplayId> mFreeVirtualDisplayIds;
+ uint32_t mNextVirtualDisplayId = 0;
uint32_t mRemainingHwcVirtualDisplays{mHwcDevice->getMaxVirtualDisplayCount()};
// protected by mLock
mutable Mutex mLock;
- mutable std::unordered_map<int32_t, nsecs_t> mLastHwVSync{
- {{HWC_DISPLAY_PRIMARY, 0}, {HWC_DISPLAY_EXTERNAL, 0}}};
+ mutable std::unordered_map<DisplayId, nsecs_t> mLastHwVSync;
// thread-safe
mutable Mutex mVsyncLock;
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index c111a27..27d3dc5 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -48,34 +48,34 @@
}
}
-VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId,
- const sp<IGraphicBufferProducer>& sink,
- const sp<IGraphicBufferProducer>& bqProducer,
- const sp<IGraphicBufferConsumer>& bqConsumer,
- const std::string& name)
-: ConsumerBase(bqConsumer),
- mHwc(hwc),
- mDisplayId(dispId),
- mDisplayName(name),
- mSource{},
- mDefaultOutputFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
- mOutputFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
- mOutputUsage(GRALLOC_USAGE_HW_COMPOSER),
- mProducerSlotSource(0),
- mProducerBuffers(),
- mQueueBufferOutput(),
- mSinkBufferWidth(0),
- mSinkBufferHeight(0),
- mCompositionType(COMPOSITION_UNKNOWN),
- mFbFence(Fence::NO_FENCE),
- mOutputFence(Fence::NO_FENCE),
- mFbProducerSlot(BufferQueue::INVALID_BUFFER_SLOT),
- mOutputProducerSlot(BufferQueue::INVALID_BUFFER_SLOT),
- mDbgState(DBG_STATE_IDLE),
- mDbgLastCompositionType(COMPOSITION_UNKNOWN),
- mMustRecompose(false),
- mForceHwcCopy(SurfaceFlinger::useHwcForRgbToYuv)
-{
+VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc,
+ const std::optional<DisplayId>& displayId,
+ const sp<IGraphicBufferProducer>& sink,
+ const sp<IGraphicBufferProducer>& bqProducer,
+ const sp<IGraphicBufferConsumer>& bqConsumer,
+ const std::string& name)
+ : ConsumerBase(bqConsumer),
+ mHwc(hwc),
+ mDisplayId(displayId),
+ mDisplayName(name),
+ mSource{},
+ mDefaultOutputFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
+ mOutputFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
+ mOutputUsage(GRALLOC_USAGE_HW_COMPOSER),
+ mProducerSlotSource(0),
+ mProducerBuffers(),
+ mQueueBufferOutput(),
+ mSinkBufferWidth(0),
+ mSinkBufferHeight(0),
+ mCompositionType(COMPOSITION_UNKNOWN),
+ mFbFence(Fence::NO_FENCE),
+ mOutputFence(Fence::NO_FENCE),
+ mFbProducerSlot(BufferQueue::INVALID_BUFFER_SLOT),
+ mOutputProducerSlot(BufferQueue::INVALID_BUFFER_SLOT),
+ mDbgState(DBG_STATE_IDLE),
+ mDbgLastCompositionType(COMPOSITION_UNKNOWN),
+ mMustRecompose(false),
+ mForceHwcCopy(SurfaceFlinger::useHwcForRgbToYuv) {
mSource[SOURCE_SINK] = sink;
mSource[SOURCE_SCRATCH] = bqProducer;
@@ -116,8 +116,9 @@
}
status_t VirtualDisplaySurface::beginFrame(bool mustRecompose) {
- if (mDisplayId < 0)
+ if (!mDisplayId) {
return NO_ERROR;
+ }
mMustRecompose = mustRecompose;
@@ -129,8 +130,9 @@
}
status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) {
- if (mDisplayId < 0)
+ if (!mDisplayId) {
return NO_ERROR;
+ }
VDS_LOGW_IF(mDbgState != DBG_STATE_BEGUN,
"Unexpected prepareFrame() in %s state", dbgStateStr());
@@ -177,8 +179,9 @@
}
status_t VirtualDisplaySurface::advanceFrame() {
- if (mDisplayId < 0)
+ if (!mDisplayId) {
return NO_ERROR;
+ }
if (mCompositionType == COMPOSITION_HWC) {
VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED,
@@ -211,7 +214,7 @@
// At this point we know the output buffer acquire fence,
// so update HWC state with it.
- mHwc.setOutputBuffer(mDisplayId, mOutputFence, outBuffer);
+ mHwc.setOutputBuffer(*mDisplayId, mOutputFence, outBuffer);
status_t result = NO_ERROR;
if (fbBuffer != nullptr) {
@@ -221,22 +224,23 @@
&hwcSlot, &hwcBuffer);
// TODO: Correctly propagate the dataspace from GL composition
- result = mHwc.setClientTarget(mDisplayId, hwcSlot, mFbFence,
- hwcBuffer, ui::Dataspace::UNKNOWN);
+ result = mHwc.setClientTarget(*mDisplayId, hwcSlot, mFbFence, hwcBuffer,
+ ui::Dataspace::UNKNOWN);
}
return result;
}
void VirtualDisplaySurface::onFrameCommitted() {
- if (mDisplayId < 0)
+ if (!mDisplayId) {
return;
+ }
VDS_LOGW_IF(mDbgState != DBG_STATE_HWC,
"Unexpected onFrameCommitted() in %s state", dbgStateStr());
mDbgState = DBG_STATE_IDLE;
- sp<Fence> retireFence = mHwc.getPresentFence(mDisplayId);
+ sp<Fence> retireFence = mHwc.getPresentFence(*mDisplayId);
if (mCompositionType == COMPOSITION_MIXED && mFbProducerSlot >= 0) {
// release the scratch buffer back to the pool
Mutex::Autolock lock(mMutex);
@@ -291,8 +295,9 @@
status_t VirtualDisplaySurface::requestBuffer(int pslot,
sp<GraphicBuffer>* outBuf) {
- if (mDisplayId < 0)
+ if (!mDisplayId) {
return mSource[SOURCE_SINK]->requestBuffer(pslot, outBuf);
+ }
VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
"Unexpected requestBuffer pslot=%d in %s state",
@@ -313,7 +318,7 @@
status_t VirtualDisplaySurface::dequeueBuffer(Source source,
PixelFormat format, uint64_t usage, int* sslot, sp<Fence>* fence) {
- LOG_FATAL_IF(mDisplayId < 0, "mDisplayId=%d but should not be < 0.", mDisplayId);
+ LOG_FATAL_IF(!mDisplayId);
status_t result =
mSource[source]->dequeueBuffer(sslot, fence, mSinkBufferWidth, mSinkBufferHeight,
@@ -359,7 +364,7 @@
PixelFormat format, uint64_t usage,
uint64_t* outBufferAge,
FrameEventHistoryDelta* outTimestamps) {
- if (mDisplayId < 0) {
+ if (!mDisplayId) {
return mSource[SOURCE_SINK]->dequeueBuffer(pslot, fence, w, h, format, usage, outBufferAge,
outTimestamps);
}
@@ -446,8 +451,9 @@
status_t VirtualDisplaySurface::queueBuffer(int pslot,
const QueueBufferInput& input, QueueBufferOutput* output) {
- if (mDisplayId < 0)
+ if (!mDisplayId) {
return mSource[SOURCE_SINK]->queueBuffer(pslot, input, output);
+ }
VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
"Unexpected queueBuffer(pslot=%d) in %s state", pslot,
@@ -504,8 +510,9 @@
status_t VirtualDisplaySurface::cancelBuffer(int pslot,
const sp<Fence>& fence) {
- if (mDisplayId < 0)
+ if (!mDisplayId) {
return mSource[SOURCE_SINK]->cancelBuffer(mapProducer2SourceSlot(SOURCE_SINK, pslot), fence);
+ }
VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
"Unexpected cancelBuffer(pslot=%d) in %s state", pslot,
@@ -616,6 +623,8 @@
}
status_t VirtualDisplaySurface::refreshOutputBuffer() {
+ LOG_FATAL_IF(!mDisplayId);
+
if (mOutputProducerSlot >= 0) {
mSource[SOURCE_SINK]->cancelBuffer(
mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot),
@@ -633,8 +642,8 @@
// until after GLES calls queueBuffer(). So here we just set the buffer
// (for use in HWC prepare) but not the fence; we'll call this again with
// the proper fence once we have it.
- result = mHwc.setOutputBuffer(mDisplayId, Fence::NO_FENCE,
- mProducerBuffers[mOutputProducerSlot]);
+ result = mHwc.setOutputBuffer(*mDisplayId, Fence::NO_FENCE,
+ mProducerBuffers[mOutputProducerSlot]);
return result;
}
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 4bd4d0f..33678df 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -17,8 +17,10 @@
#ifndef ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H
#define ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H
+#include <optional>
#include <string>
+#include "DisplayIdentification.h"
#include "DisplaySurface.h"
#include "HWComposerBufferCache.h"
@@ -75,11 +77,10 @@
public BnGraphicBufferProducer,
private ConsumerBase {
public:
- VirtualDisplaySurface(HWComposer& hwc, int32_t dispId,
- const sp<IGraphicBufferProducer>& sink,
- const sp<IGraphicBufferProducer>& bqProducer,
- const sp<IGraphicBufferConsumer>& bqConsumer,
- const std::string& name);
+ VirtualDisplaySurface(HWComposer& hwc, const std::optional<DisplayId>& displayId,
+ const sp<IGraphicBufferProducer>& sink,
+ const sp<IGraphicBufferProducer>& bqProducer,
+ const sp<IGraphicBufferConsumer>& bqConsumer, const std::string& name);
//
// DisplaySurface interface
@@ -154,7 +155,7 @@
// Immutable after construction
//
HWComposer& mHwc;
- const int32_t mDisplayId;
+ const std::optional<DisplayId> mDisplayId;
const std::string mDisplayName;
sp<IGraphicBufferProducer> mSource[2]; // indexed by SOURCE_*
uint32_t mDefaultOutputFormat;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f29dfc0..038bc58 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -196,9 +196,9 @@
// h/w composer set-up
// ---------------------------------------------------------------------------
-bool Layer::createHwcLayer(HWComposer* hwc, int32_t displayId) {
- LOG_ALWAYS_FATAL_IF(getBE().mHwcLayers.count(displayId) != 0,
- "Already have a layer for display %d", displayId);
+bool Layer::createHwcLayer(HWComposer* hwc, DisplayId displayId) {
+ LOG_ALWAYS_FATAL_IF(hasHwcLayer(displayId), "Already have a layer for display %s",
+ to_string(displayId).c_str());
auto layer = std::shared_ptr<HWC2::Layer>(
hwc->createLayer(displayId),
[hwc, displayId](HWC2::Layer* layer) {
@@ -214,8 +214,8 @@
return true;
}
-bool Layer::destroyHwcLayer(int32_t displayId) {
- if (getBE().mHwcLayers.count(displayId) == 0) {
+bool Layer::destroyHwcLayer(DisplayId displayId) {
+ if (!hasHwcLayer(displayId)) {
return false;
}
auto& hwcInfo = getBE().mHwcLayers[displayId];
@@ -275,39 +275,12 @@
return Region(Rect{win}).subtract(exclude).getBounds().toFloatRect();
}
-Rect Layer::computeScreenBounds(bool reduceTransparentRegion) const {
- const State& s(getDrawingState());
- Rect win(getActiveWidth(s), getActiveHeight(s));
-
- Rect crop = getCrop(s);
- if (!crop.isEmpty()) {
- win.intersect(crop, &win);
- }
-
+Rect Layer::computeScreenBounds() const {
+ FloatRect bounds = computeBounds();
ui::Transform t = getTransform();
- win = t.transform(win);
-
- const sp<Layer>& p = mDrawingParent.promote();
- // Now we need to calculate the parent bounds, so we can clip ourselves to those.
- // When calculating the parent bounds for purposes of clipping,
- // we don't need to constrain the parent to its transparent region.
- // The transparent region is an optimization based on the
- // buffer contents of the layer, but does not affect the space allocated to
- // it by policy, and thus children should be allowed to extend into the
- // parent's transparent region. In fact one of the main uses, is to reduce
- // buffer allocation size in cases where a child window sits behind a main window
- // (by marking the hole in the parent window as a transparent region)
- if (p != nullptr) {
- Rect bounds = p->computeScreenBounds(false);
- bounds.intersect(win, &win);
- }
-
- if (reduceTransparentRegion) {
- auto const screenTransparentRegion = t.transform(getActiveTransparentRegion(s));
- win = reduce(win, screenTransparentRegion);
- }
-
- return win;
+ // Transform to screen space.
+ bounds = t.transform(bounds);
+ return Rect{bounds};
}
FloatRect Layer::computeBounds() const {
@@ -317,32 +290,72 @@
FloatRect Layer::computeBounds(const Region& activeTransparentRegion) const {
const State& s(getDrawingState());
- Rect win(getActiveWidth(s), getActiveHeight(s));
+ Rect bounds = getCroppedBufferSize(s);
+ FloatRect floatBounds = bounds.toFloatRect();
+ if (bounds.isValid()) {
+ // Layer has bounds. Pass in our bounds as a special case. Then pass on to our parents so
+ // that they can clip it.
+ floatBounds = cropChildBounds(floatBounds);
+ } else {
+ // Layer does not have bounds, so we fill to our parent bounds. This is done by getting our
+ // parent bounds and inverting the transform to get the maximum bounds we can have that
+ // will fit within our parent bounds.
+ const auto& p = mDrawingParent.promote();
+ if (p != nullptr) {
+ ui::Transform t = s.active_legacy.transform;
+ // When calculating the parent bounds for purposes of clipping, we don't need to
+ // constrain the parent to its transparent region. The transparent region is an
+ // optimization based on the buffer contents of the layer, but does not affect the
+ // space allocated to it by policy, and thus children should be allowed to extend into
+ // the parent's transparent region.
+ // One of the main uses is a parent window with a child sitting behind the parent
+ // window, marked by a transparent region. When computing the parent bounds from the
+ // parent's perspective we pass in the transparent region to reduce buffer allocation
+ // size. When computing the parent bounds from the child's perspective, we pass in an
+ // empty transparent region in order to extend into the the parent bounds.
+ floatBounds = p->computeBounds(Region());
+ // Transform back to layer space.
+ floatBounds = t.inverse().transform(floatBounds);
+ }
+ }
- Rect crop = getCrop(s);
- if (!crop.isEmpty()) {
- win.intersect(crop, &win);
+ // Subtract the transparent region and snap to the bounds.
+ return reduce(floatBounds, activeTransparentRegion);
+}
+
+FloatRect Layer::cropChildBounds(const FloatRect& childBounds) const {
+ const State& s(getDrawingState());
+ Rect bounds = getCroppedBufferSize(s);
+ FloatRect croppedBounds = childBounds;
+
+ // If the layer has bounds, then crop the passed in child bounds and pass
+ // it to our parents so they can crop it as well. If the layer has no bounds,
+ // then pass on the child bounds.
+ if (bounds.isValid()) {
+ croppedBounds = croppedBounds.intersect(bounds.toFloatRect());
}
const auto& p = mDrawingParent.promote();
- FloatRect floatWin = win.toFloatRect();
- FloatRect parentBounds = floatWin;
if (p != nullptr) {
- // We pass an empty Region here for reasons mirroring that of the case described in
- // the computeScreenBounds reduceTransparentRegion=false case.
- parentBounds = p->computeBounds(Region());
+ // Transform to parent space and allow parent layer to crop the
+ // child bounds as well.
+ ui::Transform t = s.active_legacy.transform;
+ croppedBounds = t.transform(croppedBounds);
+ croppedBounds = p->cropChildBounds(croppedBounds);
+ croppedBounds = t.inverse().transform(croppedBounds);
}
+ return croppedBounds;
+}
- ui::Transform t = s.active_legacy.transform;
-
- if (p != nullptr) {
- floatWin = t.transform(floatWin);
- floatWin = floatWin.intersect(parentBounds);
- floatWin = t.inverse().transform(floatWin);
+Rect Layer::getCroppedBufferSize(const State& s) const {
+ Rect size = getBufferSize(s);
+ Rect crop = getCrop(s);
+ if (!crop.isEmpty() && size.isValid()) {
+ size.intersect(crop, &size);
+ } else if (!crop.isEmpty()) {
+ size = crop;
}
-
- // subtract the transparent region and snap to the bounds
- return reduce(floatWin, activeTransparentRegion);
+ return size;
}
Rect Layer::computeInitialCrop(const sp<const DisplayDevice>& display) const {
@@ -461,12 +474,9 @@
void Layer::setGeometry(const sp<const DisplayDevice>& display, uint32_t z) {
const auto displayId = display->getId();
- if (!hasHwcLayer(displayId)) {
- ALOGE("[%s] failed to setGeometry: no HWC layer found (%d)",
- mName.string(), displayId);
- return;
- }
- auto& hwcInfo = getBE().mHwcLayers[displayId];
+ LOG_ALWAYS_FATAL_IF(!displayId);
+ RETURN_IF_NO_HWC_LAYER(*displayId);
+ auto& hwcInfo = getBE().mHwcLayers[*displayId];
// enable this layer
hwcInfo.forceClientComposition = false;
@@ -618,7 +628,7 @@
if (orientation & ui::Transform::ROT_INVALID) {
// we can only handle simple transformation
hwcInfo.forceClientComposition = true;
- getBE().mHwcLayers[displayId].compositionType = HWC2::Composition::Client;
+ getBE().mHwcLayers[*displayId].compositionType = HWC2::Composition::Client;
} else {
auto transform = static_cast<HWC2::Transform>(orientation);
hwcInfo.transform = transform;
@@ -632,28 +642,20 @@
}
}
-void Layer::forceClientComposition(int32_t displayId) {
- if (getBE().mHwcLayers.count(displayId) == 0) {
- ALOGE("forceClientComposition: no HWC layer found (%d)", displayId);
- return;
- }
-
+void Layer::forceClientComposition(DisplayId displayId) {
+ RETURN_IF_NO_HWC_LAYER(displayId);
getBE().mHwcLayers[displayId].forceClientComposition = true;
}
-bool Layer::getForceClientComposition(int32_t displayId) {
- if (getBE().mHwcLayers.count(displayId) == 0) {
- ALOGE("getForceClientComposition: no HWC layer found (%d)", displayId);
- return false;
- }
-
+bool Layer::getForceClientComposition(DisplayId displayId) {
+ RETURN_IF_NO_HWC_LAYER(displayId, false);
return getBE().mHwcLayers[displayId].forceClientComposition;
}
void Layer::updateCursorPosition(const sp<const DisplayDevice>& display) {
const auto displayId = display->getId();
- if (getBE().mHwcLayers.count(displayId) == 0 ||
- getCompositionType(displayId) != HWC2::Composition::Cursor) {
+ LOG_ALWAYS_FATAL_IF(!displayId);
+ if (!hasHwcLayer(*displayId) || getCompositionType(displayId) != HWC2::Composition::Cursor) {
return;
}
@@ -675,8 +677,8 @@
auto position = displayTransform.transform(frame);
auto error =
- (getBE().mHwcLayers[displayId].layer)->setCursorPosition(
- position.left, position.top);
+ getBE().mHwcLayers[*displayId].layer->setCursorPosition(position.left, position.top);
+
ALOGE_IF(error != HWC2::Error::None,
"[%s] Failed to set cursor position "
"to (%d, %d): %s (%d)",
@@ -708,7 +710,7 @@
clearWithOpenGL(renderArea, 0, 0, 0, 0);
}
-void Layer::setCompositionType(int32_t displayId, HWC2::Composition type, bool callIntoHwc) {
+void Layer::setCompositionType(DisplayId displayId, HWC2::Composition type, bool callIntoHwc) {
if (getBE().mHwcLayers.count(displayId) == 0) {
ALOGE("setCompositionType called without a valid HWC layer");
return;
@@ -731,16 +733,20 @@
}
}
-HWC2::Composition Layer::getCompositionType(int32_t displayId) const {
- if (getBE().mHwcLayers.count(displayId) == 0) {
+HWC2::Composition Layer::getCompositionType(const std::optional<DisplayId>& displayId) const {
+ if (!displayId) {
// If we're querying the composition type for a display that does not
// have a HWC counterpart, then it will always be Client
return HWC2::Composition::Client;
}
- return getBE().mHwcLayers[displayId].compositionType;
+ if (getBE().mHwcLayers.count(*displayId) == 0) {
+ ALOGE("getCompositionType called with an invalid HWC layer");
+ return HWC2::Composition::Invalid;
+ }
+ return getBE().mHwcLayers.at(*displayId).compositionType;
}
-void Layer::setClearClientTarget(int32_t displayId, bool clear) {
+void Layer::setClearClientTarget(DisplayId displayId, bool clear) {
if (getBE().mHwcLayers.count(displayId) == 0) {
ALOGE("setClearClientTarget called without a valid HWC layer");
return;
@@ -748,7 +754,7 @@
getBE().mHwcLayers[displayId].clearClientTarget = clear;
}
-bool Layer::getClearClientTarget(int32_t displayId) const {
+bool Layer::getClearClientTarget(DisplayId displayId) const {
if (getBE().mHwcLayers.count(displayId) == 0) {
ALOGE("getClearClientTarget called without a valid HWC layer");
return false;
@@ -1049,6 +1055,7 @@
// Commit the transaction
commitTransaction(c);
+ mCurrentState.callbackHandles = {};
return flags;
}
@@ -1416,8 +1423,8 @@
result.append("-----------------------------\n");
}
-void Layer::miniDump(String8& result, int32_t displayId) const {
- if (getBE().mHwcLayers.count(displayId) == 0) {
+void Layer::miniDump(String8& result, DisplayId displayId) const {
+ if (!hasHwcLayer(displayId)) {
return;
}
@@ -1980,7 +1987,7 @@
}
}
-void Layer::writeToProto(LayerProto* layerInfo, int32_t displayId) {
+void Layer::writeToProto(LayerProto* layerInfo, DisplayId displayId) {
if (!hasHwcLayer(displayId)) {
return;
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 12671ff..40ebe1e 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -38,6 +38,7 @@
#include <cstdint>
#include <list>
+#include <optional>
#include <vector>
#include "Client.h"
@@ -47,6 +48,7 @@
#include "MonitoredProducer.h"
#include "SurfaceFlinger.h"
#include "TimeStats/TimeStats.h"
+#include "TransactionCompletedThread.h"
#include "DisplayHardware/HWComposer.h"
#include "DisplayHardware/HWComposerBufferCache.h"
@@ -183,6 +185,10 @@
sp<NativeHandle> sidebandStream;
mat4 colorTransform;
bool hasColorTransform;
+
+ // The deque of callback handles for this frame. The back of the deque contains the most
+ // recent callback handle.
+ std::deque<sp<CallbackHandle>> callbackHandles;
};
explicit Layer(const LayerCreationArgs& args);
@@ -265,13 +271,17 @@
virtual bool setTransform(uint32_t /*transform*/) { return false; };
virtual bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/) { return false; };
virtual bool setCrop(const Rect& /*crop*/) { return false; };
- virtual bool setBuffer(sp<GraphicBuffer> /*buffer*/) { return false; };
+ virtual bool setBuffer(const sp<GraphicBuffer>& /*buffer*/) { return false; };
virtual bool setAcquireFence(const sp<Fence>& /*fence*/) { return false; };
virtual bool setDataspace(ui::Dataspace /*dataspace*/) { return false; };
virtual bool setHdrMetadata(const HdrMetadata& /*hdrMetadata*/) { return false; };
virtual bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/) { return false; };
virtual bool setApi(int32_t /*api*/) { return false; };
virtual bool setSidebandStream(const sp<NativeHandle>& /*sidebandStream*/) { return false; };
+ virtual bool setTransactionCompletedListeners(
+ const std::vector<sp<CallbackHandle>>& /*handles*/) {
+ return false;
+ };
ui::Dataspace getDataSpace() const { return mCurrentDataSpace; }
@@ -351,7 +361,7 @@
void writeToProto(LayerProto* layerInfo,
LayerVector::StateSet stateSet = LayerVector::StateSet::Drawing);
- void writeToProto(LayerProto* layerInfo, int32_t displayId);
+ void writeToProto(LayerProto* layerInfo, DisplayId displayId);
virtual Geometry getActiveGeometry(const Layer::State& s) const { return s.active_legacy; }
virtual uint32_t getActiveWidth(const Layer::State& s) const { return s.active_legacy.w; }
@@ -377,16 +387,17 @@
virtual bool isHdrY410() const { return false; }
void setGeometry(const sp<const DisplayDevice>& display, uint32_t z);
- void forceClientComposition(int32_t displayId);
- bool getForceClientComposition(int32_t displayId);
- virtual void setPerFrameData(const sp<const DisplayDevice>& display) = 0;
+ void forceClientComposition(DisplayId displayId);
+ bool getForceClientComposition(DisplayId displayId);
+ virtual void setPerFrameData(DisplayId displayId, const ui::Transform& transform,
+ const Rect& viewport, int32_t supportedPerFrameMetadata) = 0;
// callIntoHwc exists so we can update our local state and call
// acceptDisplayChanges without unnecessarily updating the device's state
- void setCompositionType(int32_t displayId, HWC2::Composition type, bool callIntoHwc = true);
- HWC2::Composition getCompositionType(int32_t displayId) const;
- void setClearClientTarget(int32_t displayId, bool clear);
- bool getClearClientTarget(int32_t displayId) const;
+ void setCompositionType(DisplayId displayId, HWC2::Composition type, bool callIntoHwc = true);
+ HWC2::Composition getCompositionType(const std::optional<DisplayId>& displayId) const;
+ void setClearClientTarget(DisplayId displayId, bool clear);
+ bool getClearClientTarget(DisplayId displayId) const;
void updateCursorPosition(const sp<const DisplayDevice>& display);
/*
@@ -401,13 +412,14 @@
* called before composition.
* returns true if the layer has pending updates.
*/
- virtual bool onPreComposition(nsecs_t /*refreshStartTime*/) { return true; }
+ virtual bool onPreComposition(nsecs_t refreshStartTime) = 0;
/*
* called after composition.
* returns true if the layer latched a new buffer this frame.
*/
- virtual bool onPostComposition(const std::shared_ptr<FenceTime>& /*glDoneFence*/,
+ virtual bool onPostComposition(const std::optional<DisplayId>& /*displayId*/,
+ const std::shared_ptr<FenceTime>& /*glDoneFence*/,
const std::shared_ptr<FenceTime>& /*presentFence*/,
const CompositorTiming& /*compositorTiming*/) {
return false;
@@ -492,24 +504,24 @@
// -----------------------------------------------------------------------
- bool createHwcLayer(HWComposer* hwc, int32_t displayId);
- bool destroyHwcLayer(int32_t displayId);
+ bool createHwcLayer(HWComposer* hwc, DisplayId displayId);
+ bool destroyHwcLayer(DisplayId displayId);
void destroyAllHwcLayers();
- bool hasHwcLayer(int32_t displayId) { return getBE().mHwcLayers.count(displayId) > 0; }
+ bool hasHwcLayer(DisplayId displayId) const { return getBE().mHwcLayers.count(displayId) > 0; }
- HWC2::Layer* getHwcLayer(int32_t displayId) {
- if (getBE().mHwcLayers.count(displayId) == 0) {
+ HWC2::Layer* getHwcLayer(DisplayId displayId) {
+ if (!hasHwcLayer(displayId)) {
return nullptr;
}
return getBE().mHwcLayers[displayId].layer.get();
}
- bool setHwcLayer(int32_t hwcId) {
- if (getBE().mHwcLayers.count(hwcId) == 0) {
+ bool setHwcLayer(DisplayId displayId) {
+ if (!hasHwcLayer(displayId)) {
return false;
}
- getBE().compositionInfo.hwc.hwcLayer = getBE().mHwcLayers[hwcId].layer;
+ getBE().compositionInfo.hwc.hwcLayer = getBE().mHwcLayers[displayId].layer;
return true;
}
@@ -524,7 +536,7 @@
/* always call base class first */
static void miniDumpHeader(String8& result);
- void miniDump(String8& result, int32_t displayId) const;
+ void miniDump(String8& result, DisplayId displayId) const;
void dumpFrameStats(String8& result) const;
void dumpFrameEvents(String8& result);
void clearFrameStats();
@@ -567,7 +579,7 @@
ssize_t removeChild(const sp<Layer>& layer);
sp<Layer> getParent() const { return mCurrentParent.promote(); }
bool hasParent() const { return getParent() != nullptr; }
- Rect computeScreenBounds(bool reduceTransparentRegion = true) const;
+ Rect computeScreenBounds() const;
bool setChildLayer(const sp<Layer>& childLayer, int32_t z);
bool setChildRelativeLayer(const sp<Layer>& childLayer,
const sp<IBinder>& relativeToHandle, int32_t relativeZ);
@@ -779,10 +791,38 @@
const LayerVector::Visitor& visitor);
LayerVector makeChildrenTraversalList(LayerVector::StateSet stateSet,
const std::vector<Layer*>& layersInTree);
+
+ /**
+ * Retuns the child bounds in layer space cropped to its bounds as well all its parent bounds.
+ * The cropped bounds must be transformed back from parent layer space to child layer space by
+ * applying the inverse of the child's transformation.
+ */
+ FloatRect cropChildBounds(const FloatRect& childBounds) const;
+
+ /**
+ * Returns the cropped buffer size or the layer crop if the layer has no buffer. Return
+ * INVALID_RECT if the layer has no buffer and no crop.
+ * A layer with an invalid buffer size and no crop is considered to be boundless. The layer
+ * bounds are constrained by its parent bounds.
+ */
+ Rect getCroppedBufferSize(const Layer::State& s) const;
+
+ /**
+ * Returns active buffer size in the correct orientation. Buffer size is determined by undoing
+ * any buffer transformations. If the layer has no buffer then return INVALID_RECT.
+ */
+ virtual Rect getBufferSize(const Layer::State&) const { return Rect::INVALID_RECT; }
};
-// ---------------------------------------------------------------------------
+} // namespace android
-}; // namespace android
+#define RETURN_IF_NO_HWC_LAYER(displayId, ...) \
+ do { \
+ if (!hasHwcLayer(displayId)) { \
+ ALOGE("[%s] %s failed: no HWC layer found for display %s", mName.string(), \
+ __FUNCTION__, to_string(displayId).c_str()); \
+ return __VA_ARGS__; \
+ } \
+ } while (false)
#endif // ANDROID_LAYER_H
diff --git a/services/surfaceflinger/LayerBE.h b/services/surfaceflinger/LayerBE.h
index 463c46c..3f5134e 100644
--- a/services/surfaceflinger/LayerBE.h
+++ b/services/surfaceflinger/LayerBE.h
@@ -24,6 +24,7 @@
#include <renderengine/Texture.h>
#include <ui/Region.h>
+#include "DisplayHardware/DisplayIdentification.h"
#include "DisplayHardware/HWComposer.h"
#include "DisplayHardware/HWComposerBufferCache.h"
#include "SurfaceFlinger.h"
@@ -41,7 +42,7 @@
std::shared_ptr<LayerBE> layer;
struct {
std::shared_ptr<HWC2::Layer> hwcLayer;
- int32_t displayId = -1;
+ DisplayId displayId;
sp<Fence> fence;
HWC2::BlendMode blendMode = HWC2::BlendMode::Invalid;
Rect displayFrame;
@@ -123,12 +124,11 @@
HWC2::Transform transform;
};
-
// A layer can be attached to multiple displays when operating in mirror mode
// (a.k.a: when several displays are attached with equal layerStack). In this
// case we need to keep track. In non-mirror mode, a layer will have only one
- // HWCInfo. This map key is a display layerStack.
- std::unordered_map<int32_t, HWCInfo> mHwcLayers;
+ // HWCInfo.
+ std::unordered_map<DisplayId, HWCInfo> mHwcLayers;
CompositionInfo compositionInfo;
};
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 18a8bb1..4286cc9 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -14,11 +14,14 @@
* limitations under the License.
*/
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include "Scheduler.h"
#include <cinttypes>
#include <cstdint>
#include <memory>
+#include <numeric>
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
@@ -27,6 +30,7 @@
#include <gui/ISurfaceComposer.h>
#include <ui/DisplayStatInfo.h>
+#include <utils/Trace.h>
#include "DispSync.h"
#include "DispSyncSource.h"
@@ -196,4 +200,58 @@
mPrimaryDispSync->setIgnorePresentFences(ignore);
}
+void Scheduler::makeHWSyncAvailable(bool makeAvailable) {
+ std::lock_guard<std::mutex> lock(mHWVsyncLock);
+ mHWVsyncAvailable = makeAvailable;
+}
+
+void Scheduler::addNewFrameTimestamp(const nsecs_t newFrameTimestamp, bool isAutoTimestamp) {
+ ATRACE_INT("AutoTimestamp", isAutoTimestamp);
+ // Video does not have timestamp automatically set, so we discard timestamps that are
+ // coming in from other sources for now.
+ if (isAutoTimestamp) {
+ return;
+ }
+ int64_t differenceMs = (newFrameTimestamp - mPreviousFrameTimestamp) / 1000000;
+ mPreviousFrameTimestamp = newFrameTimestamp;
+
+ if (differenceMs < 10 || differenceMs > 100) {
+ // Dismiss noise.
+ return;
+ }
+ ATRACE_INT("TimestampDiff", differenceMs);
+
+ mTimeDifferences[mCounter % ARRAY_SIZE] = differenceMs;
+ mCounter++;
+ nsecs_t average = calculateAverage();
+ ATRACE_INT("TimestampAverage", average);
+
+ // TODO(b/113612090): This are current numbers from trial and error while running videos
+ // from YouTube at 24, 30, and 60 fps.
+ if (average > 14 && average < 18) {
+ ATRACE_INT("FPS", 60);
+ } else if (average > 31 && average < 34) {
+ ATRACE_INT("FPS", 30);
+ updateFrameSkipping(1);
+ return;
+ } else if (average > 39 && average < 42) {
+ ATRACE_INT("FPS", 24);
+ }
+ updateFrameSkipping(0);
+}
+
+nsecs_t Scheduler::calculateAverage() const {
+ nsecs_t sum = std::accumulate(mTimeDifferences.begin(), mTimeDifferences.end(), 0);
+ return (sum / ARRAY_SIZE);
+}
+
+void Scheduler::updateFrameSkipping(const int64_t skipCount) {
+ ATRACE_INT("FrameSkipCount", skipCount);
+ if (mSkipCount != skipCount) {
+ // Only update DispSync if it hasn't been updated yet.
+ mPrimaryDispSync->setRefreshSkipCount(skipCount);
+ mSkipCount = skipCount;
+ }
+}
+
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index fdafe58..dd1f24b 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -102,6 +102,8 @@
void addResyncSample(const nsecs_t timestamp);
void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
void setIgnorePresentFences(bool ignore);
+ void makeHWSyncAvailable(bool makeAvailable);
+ void addNewFrameTimestamp(const nsecs_t newFrameTimestamp, bool isAutoTimestamp);
protected:
virtual std::unique_ptr<EventThread> makeEventThread(
@@ -110,6 +112,9 @@
impl::EventThread::InterceptVSyncsCallback interceptCallback);
private:
+ nsecs_t calculateAverage() const;
+ void updateFrameSkipping(const int64_t skipCount);
+
// TODO(b/113612090): Instead of letting BufferQueueLayer to access mDispSync directly, it
// should make request to Scheduler to compute next refresh.
friend class BufferQueueLayer;
@@ -133,6 +138,18 @@
std::unique_ptr<DispSync> mPrimaryDispSync;
std::unique_ptr<EventControlThread> mEventControlThread;
+
+ // TODO(b/113612090): The following set of variables needs to be revised. For now, this is
+ // a proof of concept. We turn on frame skipping if the difference between the timestamps
+ // is between 32 and 34ms. We expect this currently for 30fps videos, so we render them at 30Hz.
+ nsecs_t mPreviousFrameTimestamp = 0;
+ // Keeping track of whether we are skipping the refresh count. If we want to
+ // simulate 30Hz rendering, we skip every other frame, and this variable is set
+ // to 1.
+ int64_t mSkipCount = 0;
+ static constexpr size_t ARRAY_SIZE = 30;
+ std::array<int64_t, ARRAY_SIZE> mTimeDifferences;
+ size_t mCounter = 0;
};
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index dec08fd..35ba391 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -105,8 +105,6 @@
#include <layerproto/LayerProtoParser.h>
-#define DISPLAY_COUNT 1
-
namespace android {
using namespace android::hardware::configstore;
@@ -173,6 +171,11 @@
bool mLocked;
};
+// Currently we only support V0_SRGB and DISPLAY_P3 as composition preference.
+bool validateCompositionDataspace(Dataspace dataspace) {
+ return dataspace == Dataspace::V0_SRGB || dataspace == Dataspace::DISPLAY_P3;
+}
+
} // namespace anonymous
// ---------------------------------------------------------------------------
@@ -191,7 +194,6 @@
bool SurfaceFlinger::hasSyncFramework;
bool SurfaceFlinger::useVrFlinger;
int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
-// TODO(courtneygo): Rename hasWideColorDisplay to clarify its actual meaning.
bool SurfaceFlinger::hasWideColorDisplay;
int SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientationDefault;
bool SurfaceFlinger::useColorManagement;
@@ -247,7 +249,6 @@
mLayersRemoved(false),
mLayersAdded(false),
mBootTime(systemTime()),
- mDisplayTokens(),
mVisibleRegionsDirty(false),
mGeometryInvalid(false),
mAnimCompositionPending(false),
@@ -313,6 +314,8 @@
wideColorGamutCompositionPixelFormat = tmpWideColorGamutPixelFormat;
});
}
+ mDefaultCompositionDataspace = defaultCompositionDataspace;
+ mWideColorGamutCompositionDataspace = wideColorGamutCompositionDataspace;
useContextPriority = getBool<ISurfaceFlingerConfigs,
&ISurfaceFlingerConfigs::useContextPriority>(true);
@@ -482,40 +485,49 @@
sp<BBinder> token = new DisplayToken(this);
Mutex::Autolock _l(mStateLock);
- DisplayDeviceState info;
- info.type = DisplayDevice::DISPLAY_VIRTUAL;
- info.displayName = displayName;
- info.isSecure = secure;
- mCurrentState.displays.add(token, info);
- mInterceptor->saveDisplayCreation(info);
+ // Display ID is assigned when virtual display is allocated by HWC.
+ DisplayDeviceState state;
+ state.isSecure = secure;
+ state.displayName = displayName;
+ mCurrentState.displays.add(token, state);
+ mInterceptor->saveDisplayCreation(state);
return token;
}
void SurfaceFlinger::destroyDisplay(const sp<IBinder>& displayToken) {
Mutex::Autolock _l(mStateLock);
- ssize_t idx = mCurrentState.displays.indexOfKey(displayToken);
- if (idx < 0) {
+ ssize_t index = mCurrentState.displays.indexOfKey(displayToken);
+ if (index < 0) {
ALOGE("destroyDisplay: Invalid display token %p", displayToken.get());
return;
}
- const DisplayDeviceState& info(mCurrentState.displays.valueAt(idx));
- if (!info.isVirtual()) {
+ const DisplayDeviceState& state = mCurrentState.displays.valueAt(index);
+ if (!state.isVirtual()) {
ALOGE("destroyDisplay called for non-virtual display");
return;
}
- mInterceptor->saveDisplayDeletion(info.sequenceId);
- mCurrentState.displays.removeItemsAt(idx);
+ mInterceptor->saveDisplayDeletion(state.sequenceId);
+ mCurrentState.displays.removeItemsAt(index);
setTransactionFlags(eDisplayTransactionNeeded);
}
sp<IBinder> SurfaceFlinger::getBuiltInDisplay(int32_t id) {
- if (uint32_t(id) >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
- ALOGE("getDefaultDisplay: id=%d is not a valid default display id", id);
+ std::optional<DisplayId> displayId;
+
+ if (id == HWC_DISPLAY_PRIMARY) {
+ displayId = getInternalDisplayId();
+ } else if (id == HWC_DISPLAY_EXTERNAL) {
+ displayId = getExternalDisplayId();
+ }
+
+ if (!displayId) {
+ ALOGE("%s: Invalid display %d", __FUNCTION__, id);
return nullptr;
}
- return mDisplayTokens[id];
+
+ return getPhysicalDisplayToken(*displayId);
}
status_t SurfaceFlinger::getColorManagement(bool* outGetColorManagement) const {
@@ -598,8 +610,10 @@
// start the EventThread
if (mUseScheduler) {
- mScheduler = getFactory().createScheduler(
- [this](bool enabled) { setVsyncEnabled(HWC_DISPLAY_PRIMARY, enabled); });
+ mScheduler = getFactory().createScheduler([this](bool enabled) {
+ setVsyncEnabled(EventThread::DisplayType::Primary, enabled);
+ });
+
mAppConnectionHandle =
mScheduler->createConnection("appConnection", SurfaceFlinger::vsyncPhaseOffsetNs,
[this] { resyncWithRateLimit(); },
@@ -659,7 +673,7 @@
processDisplayHotplugEventsLocked();
const auto display = getDefaultDisplayDeviceLocked();
LOG_ALWAYS_FATAL_IF(!display, "Missing internal display after registering composer callback.");
- LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(display->getId()),
+ LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(*display->getId()),
"Internal display is disconnected.");
// make the default display GLContext current so that we can create textures
@@ -682,7 +696,7 @@
};
mVrFlinger = dvr::VrFlinger::Create(getHwComposer().getComposer(),
getHwComposer()
- .getHwcDisplayId(display->getId())
+ .fromPhysicalDisplayId(*display->getId())
.value_or(0),
vrFlingerRequestDisplayCallback);
if (!mVrFlinger) {
@@ -691,7 +705,7 @@
}
mEventControlThread = getFactory().createEventControlThread(
- [this](bool enabled) { setVsyncEnabled(HWC_DISPLAY_PRIMARY, enabled); });
+ [this](bool enabled) { setVsyncEnabled(EventThread::DisplayType::Primary, enabled); });
// initialize our drawing state
mDrawingState = mCurrentState;
@@ -717,8 +731,8 @@
// and apply this saturation matrix on Display P3 content. Unless the risk of applying
// such saturation matrix on Display P3 is understood fully, the API should always return
// identify matrix.
- mEnhancedSaturationMatrix = getBE().mHwc->getDataspaceSaturationMatrix(display->getId(),
- Dataspace::SRGB_LINEAR);
+ mEnhancedSaturationMatrix =
+ getHwComposer().getDataspaceSaturationMatrix(*display->getId(), Dataspace::SRGB_LINEAR);
// we will apply this on Display P3.
if (mEnhancedSaturationMatrix != mat4()) {
@@ -805,16 +819,9 @@
return BAD_VALUE;
}
- int32_t type = NAME_NOT_FOUND;
- for (int i = 0; i < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES; ++i) {
- if (displayToken == mDisplayTokens[i]) {
- type = i;
- break;
- }
- }
-
- if (type < 0) {
- return type;
+ const auto displayId = getPhysicalDisplayId(displayToken);
+ if (!displayId) {
+ return NAME_NOT_FOUND;
}
// TODO: Not sure if display density should handled by SF any longer
@@ -838,7 +845,7 @@
ConditionalLock _l(mStateLock,
std::this_thread::get_id() != mMainThreadId);
- for (const auto& hwConfig : getHwComposer().getConfigs(type)) {
+ for (const auto& hwConfig : getHwComposer().getConfigs(*displayId)) {
DisplayInfo info = DisplayInfo();
float xdpi = hwConfig->getDpiX();
@@ -850,7 +857,7 @@
info.viewportW = info.w;
info.viewportH = info.h;
- if (type == DisplayDevice::DISPLAY_PRIMARY) {
+ if (displayId == getInternalDisplayId()) {
// The density of the device is provided by a build property
float density = Density::getBuildDensity() / 160.0f;
if (density == 0) {
@@ -906,7 +913,7 @@
// All non-virtual displays are currently considered secure.
info.secure = true;
- if (type == DisplayDevice::DISPLAY_PRIMARY &&
+ if (displayId == getInternalDisplayId() &&
primaryDisplayOrientation & DisplayState::eOrientationSwapMask) {
std::swap(info.w, info.h);
}
@@ -922,7 +929,6 @@
return BAD_VALUE;
}
- // FIXME for now we always return stats for the primary display.
if (mUseScheduler) {
mScheduler->getDisplayStatInfo(stats);
} else {
@@ -943,18 +949,21 @@
}
void SurfaceFlinger::setActiveConfigInternal(const sp<DisplayDevice>& display, int mode) {
+ if (display->isVirtual()) {
+ ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
+ return;
+ }
+
int currentMode = display->getActiveConfig();
if (mode == currentMode) {
return;
}
- if (display->isVirtual()) {
- ALOGW("Trying to set config for virtual display");
- return;
- }
+ const auto displayId = display->getId();
+ LOG_ALWAYS_FATAL_IF(!displayId);
display->setActiveConfig(mode);
- getHwComposer().setActiveConfig(display->getDisplayType(), mode);
+ getHwComposer().setActiveConfig(*displayId, mode);
}
status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
@@ -979,29 +988,23 @@
return NO_ERROR;
}
+
status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& displayToken,
Vector<ColorMode>* outColorModes) {
if (!displayToken || !outColorModes) {
return BAD_VALUE;
}
- int32_t type = NAME_NOT_FOUND;
- for (int i = 0; i < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES; ++i) {
- if (displayToken == mDisplayTokens[i]) {
- type = i;
- break;
- }
- }
-
- if (type < 0) {
- return type;
+ const auto displayId = getPhysicalDisplayId(displayToken);
+ if (!displayId) {
+ return NAME_NOT_FOUND;
}
std::vector<ColorMode> modes;
{
ConditionalLock _l(mStateLock,
std::this_thread::get_id() != mMainThreadId);
- modes = getHwComposer().getColorModes(type);
+ modes = getHwComposer().getColorModes(*displayId);
}
outColorModes->clear();
std::copy(modes.cbegin(), modes.cend(), std::back_inserter(*outColorModes));
@@ -1018,6 +1021,11 @@
void SurfaceFlinger::setActiveColorModeInternal(const sp<DisplayDevice>& display, ColorMode mode,
Dataspace dataSpace, RenderIntent renderIntent) {
+ if (display->isVirtual()) {
+ ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
+ return;
+ }
+
ColorMode currentMode = display->getActiveColorMode();
Dataspace currentDataSpace = display->getCompositionDataSpace();
RenderIntent currentRenderIntent = display->getActiveRenderIntent();
@@ -1027,19 +1035,17 @@
return;
}
- if (display->isVirtual()) {
- ALOGW("Trying to set config for virtual display");
- return;
- }
-
display->setActiveColorMode(mode);
display->setCompositionDataSpace(dataSpace);
display->setActiveRenderIntent(renderIntent);
- getHwComposer().setActiveColorMode(display->getDisplayType(), mode, renderIntent);
- ALOGV("Set active color mode: %s (%d), active render intent: %s (%d), type=%d",
+ const auto displayId = display->getId();
+ LOG_ALWAYS_FATAL_IF(!displayId);
+ getHwComposer().setActiveColorMode(*displayId, mode, renderIntent);
+
+ ALOGV("Set active color mode: %s (%d), active render intent: %s (%d), display=%s",
decodeColorMode(mode).c_str(), mode, decodeRenderIntent(renderIntent).c_str(),
- renderIntent, display->getDisplayType());
+ renderIntent, to_string(*displayId).c_str());
}
status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, ColorMode mode) {
@@ -1170,9 +1176,9 @@
Dataspace* outDataspace, ui::PixelFormat* outPixelFormat,
Dataspace* outWideColorGamutDataspace,
ui::PixelFormat* outWideColorGamutPixelFormat) const {
- *outDataspace = defaultCompositionDataspace;
+ *outDataspace = mDefaultCompositionDataspace;
*outPixelFormat = defaultCompositionPixelFormat;
- *outWideColorGamutDataspace = wideColorGamutCompositionDataspace;
+ *outWideColorGamutDataspace = mWideColorGamutCompositionDataspace;
*outWideColorGamutPixelFormat = wideColorGamutCompositionPixelFormat;
return NO_ERROR;
}
@@ -1249,18 +1255,22 @@
if (makeAvailable) {
mHWVsyncAvailable = true;
+ // TODO(b/113612090): This is silly, but necessary evil until we turn on the flag for good.
+ if (mUseScheduler) {
+ mScheduler->makeHWSyncAvailable(true);
+ }
} else if (!mHWVsyncAvailable) {
// Hardware vsync is not currently available, so abort the resync
// attempt for now
return;
}
- const auto displayId = DisplayDevice::DISPLAY_PRIMARY;
- if (!getHwComposer().isConnected(displayId)) {
+ const auto displayId = getInternalDisplayId();
+ if (!displayId || !getHwComposer().isConnected(*displayId)) {
return;
}
- const auto activeConfig = getHwComposer().getActiveConfig(displayId);
+ const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
const nsecs_t period = activeConfig->getVsyncPeriod();
if (mUseScheduler) {
@@ -1311,12 +1321,11 @@
return;
}
- int32_t type;
- if (!getBE().mHwc->onVsync(hwcDisplayId, timestamp, &type)) {
+ if (!getHwComposer().onVsync(hwcDisplayId, timestamp)) {
return;
}
- if (type != DisplayDevice::DISPLAY_PRIMARY) {
+ if (hwcDisplayId != getHwComposer().getInternalHwcDisplayId()) {
// For now, we don't do anything with external display vsyncs.
return;
}
@@ -1379,11 +1388,13 @@
repaintEverything();
}
-void SurfaceFlinger::setVsyncEnabled(int disp, int enabled) {
+void SurfaceFlinger::setVsyncEnabled(EventThread::DisplayType /*displayType*/, bool enabled) {
ATRACE_CALL();
Mutex::Autolock lock(mStateLock);
- getHwComposer().setVsyncEnabled(disp,
- enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable);
+ if (const auto displayId = getInternalDisplayId()) {
+ getHwComposer().setVsyncEnabled(*displayId,
+ enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable);
+ }
}
// Note: it is assumed the caller holds |mStateLock| when this is called
@@ -1454,7 +1465,7 @@
setPowerModeInternal(display, currentDisplayPowerMode, /*stateLockHeld*/ true);
// Reset the timing values to account for the period of the swapped in HWC
- const auto activeConfig = getHwComposer().getActiveConfig(display->getId());
+ const auto activeConfig = getHwComposer().getActiveConfig(*display->getId());
const nsecs_t period = activeConfig->getVsyncPeriod();
mAnimFrameTracker.setDisplayRefreshPeriod(period);
@@ -1595,24 +1606,25 @@
mGeometryInvalid = false;
for (const auto& [token, display] : mDisplays) {
const auto displayId = display->getId();
- if (displayId >= 0) {
- const Vector<sp<Layer>>& currentLayers(
- display->getVisibleLayersSortedByZ());
- for (size_t i = 0; i < currentLayers.size(); i++) {
- const auto& layer = currentLayers[i];
+ if (!displayId) {
+ continue;
+ }
- if (!layer->hasHwcLayer(displayId)) {
- if (!layer->createHwcLayer(getBE().mHwc.get(), displayId)) {
- layer->forceClientComposition(displayId);
- continue;
- }
- }
+ const Vector<sp<Layer>>& currentLayers = display->getVisibleLayersSortedByZ();
+ for (size_t i = 0; i < currentLayers.size(); i++) {
+ const auto& layer = currentLayers[i];
- layer->setGeometry(display, i);
- if (mDebugDisableHWC || mDebugRegion) {
- layer->forceClientComposition(displayId);
+ if (!layer->hasHwcLayer(*displayId)) {
+ if (!layer->createHwcLayer(&getHwComposer(), *displayId)) {
+ layer->forceClientComposition(*displayId);
+ continue;
}
}
+
+ layer->setGeometry(display, i);
+ if (mDebugDisableHWC || mDebugRegion) {
+ layer->forceClientComposition(*displayId);
+ }
}
}
}
@@ -1620,41 +1632,43 @@
// Set the per-frame data
for (const auto& [token, display] : mDisplays) {
const auto displayId = display->getId();
- if (displayId < 0) {
+ if (!displayId) {
continue;
}
if (mDrawingState.colorMatrixChanged) {
display->setColorTransform(mDrawingState.colorMatrix);
- status_t result = getBE().mHwc->setColorTransform(displayId, mDrawingState.colorMatrix);
- ALOGE_IF(result != NO_ERROR, "Failed to set color transform on "
- "display %d: %d", displayId, result);
+ status_t result =
+ getHwComposer().setColorTransform(*displayId, mDrawingState.colorMatrix);
+ ALOGE_IF(result != NO_ERROR, "Failed to set color transform on display %s: %d",
+ to_string(*displayId).c_str(), result);
}
for (auto& layer : display->getVisibleLayersSortedByZ()) {
if (layer->isHdrY410()) {
- layer->forceClientComposition(displayId);
+ layer->forceClientComposition(*displayId);
} else if ((layer->getDataSpace() == Dataspace::BT2020_PQ ||
layer->getDataSpace() == Dataspace::BT2020_ITU_PQ) &&
!display->hasHDR10Support()) {
- layer->forceClientComposition(displayId);
+ layer->forceClientComposition(*displayId);
} else if ((layer->getDataSpace() == Dataspace::BT2020_HLG ||
layer->getDataSpace() == Dataspace::BT2020_ITU_HLG) &&
!display->hasHLGSupport()) {
- layer->forceClientComposition(displayId);
+ layer->forceClientComposition(*displayId);
}
// TODO(b/111562338) remove when composer 2.3 is shipped.
if (layer->hasColorTransform()) {
- layer->forceClientComposition(displayId);
+ layer->forceClientComposition(*displayId);
}
- if (layer->getForceClientComposition(displayId)) {
+ if (layer->getForceClientComposition(*displayId)) {
ALOGV("[%s] Requesting Client composition", layer->getName().string());
- layer->setCompositionType(displayId, HWC2::Composition::Client);
+ layer->setCompositionType(*displayId, HWC2::Composition::Client);
continue;
}
- layer->setPerFrameData(display);
+ layer->setPerFrameData(*displayId, display->getTransform(), display->getViewport(),
+ display->getSupportedPerFrameMetadata());
}
if (useColorManagement) {
@@ -1674,10 +1688,14 @@
for (auto& layer : display->getVisibleLayersSortedByZ()) {
const auto displayId = display->getId();
layer->getBE().compositionInfo.compositionType = layer->getCompositionType(displayId);
- if (!layer->setHwcLayer(displayId)) {
- ALOGV("Need to create HWCLayer for %s", layer->getName().string());
+
+ if (displayId) {
+ if (!layer->setHwcLayer(*displayId)) {
+ ALOGV("Need to create HWCLayer for %s", layer->getName().string());
+ }
+ layer->getBE().compositionInfo.hwc.displayId = *displayId;
}
- layer->getBE().compositionInfo.hwc.displayId = displayId;
+
getBE().mCompositionInfo[token].push_back(layer->getBE().compositionInfo);
layer->getBE().compositionInfo.hwc.hwcLayer = nullptr;
}
@@ -1837,7 +1855,7 @@
getBE().mDisplayTimeline.updateSignalTimes();
mPreviousPresentFence =
- display ? getHwComposer().getPresentFence(display->getId()) : Fence::NO_FENCE;
+ display ? getHwComposer().getPresentFence(*display->getId()) : Fence::NO_FENCE;
auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFence);
getBE().mDisplayTimeline.push(presentFenceTime);
@@ -1860,8 +1878,8 @@
}
mDrawingState.traverseInZOrder([&](Layer* layer) {
- bool frameLatched = layer->onPostComposition(glCompositionDoneFenceTime,
- presentFenceTime, compositorTiming);
+ bool frameLatched = layer->onPostComposition(display->getId(), glCompositionDoneFenceTime,
+ presentFenceTime, compositorTiming);
if (frameLatched) {
recordBufferingStats(layer->getName().string(),
layer->getOccupancyHistory(false));
@@ -1881,7 +1899,7 @@
}
if (!hasSyncFramework) {
- if (display && getHwComposer().isConnected(display->getId()) && display->isPoweredOn()) {
+ if (display && getHwComposer().isConnected(*display->getId()) && display->isPoweredOn()) {
if (mUseScheduler) {
mScheduler->enableHardwareVsync();
} else {
@@ -1896,10 +1914,10 @@
if (presentFenceTime->isValid()) {
mAnimFrameTracker.setActualPresentFence(
std::move(presentFenceTime));
- } else if (display && getHwComposer().isConnected(display->getId())) {
+ } else if (display && getHwComposer().isConnected(*display->getId())) {
// The HWC doesn't support present fences, so use the refresh
// timestamp instead.
- const nsecs_t presentTime = getHwComposer().getRefreshTimestamp(display->getId());
+ const nsecs_t presentTime = getHwComposer().getRefreshTimestamp(*display->getId());
mAnimFrameTracker.setActualPresentTime(presentTime);
}
mAnimFrameTracker.advanceFrame();
@@ -1912,8 +1930,7 @@
mTimeStats.setPresentFenceGlobal(presentFenceTime);
- if (display && getHwComposer().isConnected(display->getId()) &&
- display->getPowerMode() == HWC_POWER_MODE_OFF) {
+ if (display && getHwComposer().isConnected(*display->getId()) && !display->isPoweredOn()) {
return;
}
@@ -1942,6 +1959,9 @@
ATRACE_INT("TexturePoolSize", mTexturePool.size());
}
}
+
+ mTransactionCompletedThread.addPresentFence(mPreviousPresentFence);
+ mTransactionCompletedThread.sendCallbacks();
}
void SurfaceFlinger::rebuildLayerStacks() {
@@ -1967,6 +1987,7 @@
mDrawingState.traverseInZOrder([&](Layer* layer) {
bool hwcLayerDestroyed = false;
+ const auto displayId = display->getId();
if (layer->belongsToDisplay(display->getLayerStack(), display->isPrimary())) {
Region drawRegion(tr.transform(
layer->visibleNonTransparentRegion));
@@ -1976,13 +1997,13 @@
} else {
// Clear out the HWC layer if this layer was
// previously visible, but no longer is
- hwcLayerDestroyed = layer->destroyHwcLayer(display->getId());
+ hwcLayerDestroyed = displayId && layer->destroyHwcLayer(*displayId);
}
} else {
// WM changes display->layerStack upon sleep/awake.
// Here we make sure we delete the HWC layers even if
// WM changed their layer stack.
- hwcLayerDestroyed = layer->destroyHwcLayer(display->getId());
+ hwcLayerDestroyed = displayId && layer->destroyHwcLayer(*displayId);
}
// If a layer is not going to get a release fence because
@@ -2107,12 +2128,11 @@
// emit any black frames until a layer is added to the layer stack.
bool mustRecompose = dirty && !(empty && wasEmpty);
- ALOGV_IF(display->getDisplayType() == DisplayDevice::DISPLAY_VIRTUAL,
- "id[%d]: %s composition (%sdirty %sempty %swasEmpty)", display->getId(),
- mustRecompose ? "doing" : "skipping",
- dirty ? "+" : "-",
- empty ? "+" : "-",
- wasEmpty ? "+" : "-");
+ const char flagPrefix[] = {'-', '+'};
+ static_cast<void>(flagPrefix);
+ ALOGV_IF(display->isVirtual(), "%s: %s composition for %s (%cdirty %cempty %cwasEmpty)",
+ __FUNCTION__, mustRecompose ? "doing" : "skipping", display->getDebugName().c_str(),
+ flagPrefix[dirty], flagPrefix[empty], flagPrefix[wasEmpty]);
display->beginFrame(mustRecompose);
@@ -2129,10 +2149,8 @@
status_t result = display->prepareFrame(getHwComposer(),
getBE().mCompositionInfo[display->getDisplayToken()]);
- ALOGE_IF(result != NO_ERROR,
- "prepareFrame for display %d failed:"
- " %d (%s)",
- display->getId(), result, strerror(-result));
+ ALOGE_IF(result != NO_ERROR, "prepareFrame failed for %s: %d (%s)",
+ display->getDebugName().c_str(), result, strerror(-result));
}
void SurfaceFlinger::doComposition(const sp<DisplayDevice>& display, bool repaintEverything) {
@@ -2155,8 +2173,9 @@
void SurfaceFlinger::postFrame()
{
// |mStateLock| not needed as we are on the main thread
- if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY)) {
- uint32_t flipCount = getDefaultDisplayDeviceLocked()->getPageFlipCount();
+ const auto display = getDefaultDisplayDeviceLocked();
+ if (display && getHwComposer().isConnected(*display->getId())) {
+ uint32_t flipCount = display->getPageFlipCount();
if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
logFrameStats();
}
@@ -2172,8 +2191,8 @@
if (display->isPoweredOn()) {
const auto displayId = display->getId();
- if (displayId >= 0) {
- getBE().mHwc->presentAndGetReleaseFences(displayId);
+ if (displayId) {
+ getHwComposer().presentAndGetReleaseFences(*displayId);
}
display->onSwapBuffersCompleted();
display->makeCurrent();
@@ -2183,9 +2202,9 @@
// The layer buffer from the previous frame (if any) is released
// by HWC only when the release fence from this frame (if any) is
// signaled. Always get the release fence from HWC first.
- auto hwcLayer = layer->getHwcLayer(displayId);
- if (displayId >= 0) {
- releaseFence = getBE().mHwc->getLayerReleaseFence(displayId, hwcLayer);
+ if (displayId && layer->hasHwcLayer(*displayId)) {
+ releaseFence = getHwComposer().getLayerReleaseFence(*displayId,
+ layer->getHwcLayer(*displayId));
}
// If the layer was client composited in the previous frame, we
@@ -2205,14 +2224,15 @@
// display->getVisibleLayersSortedByZ. The best we can do is to
// supply them with the present fence.
if (!display->getLayersNeedingFences().isEmpty()) {
- sp<Fence> presentFence = getBE().mHwc->getPresentFence(displayId);
+ sp<Fence> presentFence =
+ displayId ? getBE().mHwc->getPresentFence(*displayId) : Fence::NO_FENCE;
for (auto& layer : display->getLayersNeedingFences()) {
layer->getBE().onLayerDisplayed(presentFence);
}
}
- if (displayId >= 0) {
- getBE().mHwc->clearReleaseFences(displayId);
+ if (displayId) {
+ getHwComposer().clearReleaseFences(*displayId);
}
}
}
@@ -2247,72 +2267,36 @@
// here the transaction has been committed
}
-DisplayDevice::DisplayType SurfaceFlinger::determineDisplayType(hwc2_display_t hwcDisplayId,
- HWC2::Connection connection) const {
- // Figure out whether the event is for the primary display or an
- // external display by matching the Hwc display id against one for a
- // connected display. If we did not find a match, we then check what
- // displays are not already connected to determine the type. If we don't
- // have a connected primary display, we assume the new display is meant to
- // be the primary display, and then if we don't have an external display,
- // we assume it is that.
- const auto primaryHwcDisplayId = getBE().mHwc->getHwcDisplayId(DisplayDevice::DISPLAY_PRIMARY);
- const auto externalHwcDisplayId =
- getBE().mHwc->getHwcDisplayId(DisplayDevice::DISPLAY_EXTERNAL);
- if (primaryHwcDisplayId && primaryHwcDisplayId == hwcDisplayId) {
- return DisplayDevice::DISPLAY_PRIMARY;
- } else if (externalHwcDisplayId && externalHwcDisplayId == hwcDisplayId) {
- return DisplayDevice::DISPLAY_EXTERNAL;
- } else if (connection == HWC2::Connection::Connected && !primaryHwcDisplayId) {
- return DisplayDevice::DISPLAY_PRIMARY;
- } else if (connection == HWC2::Connection::Connected && !externalHwcDisplayId) {
- return DisplayDevice::DISPLAY_EXTERNAL;
- }
-
- return DisplayDevice::DISPLAY_ID_INVALID;
-}
-
void SurfaceFlinger::processDisplayHotplugEventsLocked() {
for (const auto& event : mPendingHotplugEvents) {
- auto displayType = determineDisplayType(event.hwcDisplayId, event.connection);
- if (displayType == DisplayDevice::DISPLAY_ID_INVALID) {
- ALOGW("Unable to determine the display type for display %" PRIu64, event.hwcDisplayId);
- continue;
- }
+ const std::optional<DisplayIdentificationInfo> info =
+ getHwComposer().onHotplug(event.hwcDisplayId, event.connection);
- if (getBE().mHwc->isUsingVrComposer() && displayType == DisplayDevice::DISPLAY_EXTERNAL) {
- ALOGE("External displays are not supported by the vr hardware composer.");
+ if (!info) {
continue;
}
- const auto displayId =
- getBE().mHwc->onHotplug(event.hwcDisplayId, displayType, event.connection);
- if (displayId) {
- ALOGV("Display %" PRIu64 " has stable ID %" PRIu64, event.hwcDisplayId, *displayId);
- }
-
if (event.connection == HWC2::Connection::Connected) {
- if (!mDisplayTokens[displayType].get()) {
- ALOGV("Creating built in display %d", displayType);
- mDisplayTokens[displayType] = new BBinder();
- DisplayDeviceState info;
- info.type = displayType;
- info.displayName = displayType == DisplayDevice::DISPLAY_PRIMARY ?
- "Built-in Screen" : "External Screen";
- info.isSecure = true; // All physical displays are currently considered secure.
- mCurrentState.displays.add(mDisplayTokens[displayType], info);
- mInterceptor->saveDisplayCreation(info);
+ if (!mPhysicalDisplayTokens.count(info->id)) {
+ ALOGV("Creating display %s", to_string(info->id).c_str());
+ mPhysicalDisplayTokens[info->id] = new BBinder();
+ DisplayDeviceState state;
+ state.displayId = info->id;
+ state.isSecure = true; // All physical displays are currently considered secure.
+ state.displayName = info->name;
+ mCurrentState.displays.add(mPhysicalDisplayTokens[info->id], state);
+ mInterceptor->saveDisplayCreation(state);
}
} else {
- ALOGV("Removing built in display %d", displayType);
+ ALOGV("Removing display %s", to_string(info->id).c_str());
- ssize_t idx = mCurrentState.displays.indexOfKey(mDisplayTokens[displayType]);
- if (idx >= 0) {
- const DisplayDeviceState& info(mCurrentState.displays.valueAt(idx));
- mInterceptor->saveDisplayDeletion(info.sequenceId);
- mCurrentState.displays.removeItemsAt(idx);
+ ssize_t index = mCurrentState.displays.indexOfKey(mPhysicalDisplayTokens[info->id]);
+ if (index >= 0) {
+ const DisplayDeviceState& state = mCurrentState.displays.valueAt(index);
+ mInterceptor->saveDisplayDeletion(state.sequenceId);
+ mCurrentState.displays.removeItemsAt(index);
}
- mDisplayTokens[displayType].clear();
+ mPhysicalDisplayTokens.erase(info->id);
}
processDisplayChangesLocked();
@@ -2322,31 +2306,36 @@
}
sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
- const wp<IBinder>& displayToken, int32_t displayId, const DisplayDeviceState& state,
- const sp<DisplaySurface>& dispSurface, const sp<IGraphicBufferProducer>& producer) {
- DisplayDeviceCreationArgs creationArgs(this, displayToken, state.type, displayId);
+ const wp<IBinder>& displayToken, const std::optional<DisplayId>& displayId,
+ const DisplayDeviceState& state, const sp<DisplaySurface>& dispSurface,
+ const sp<IGraphicBufferProducer>& producer) {
+ DisplayDeviceCreationArgs creationArgs(this, displayToken, displayId);
+ creationArgs.isVirtual = state.isVirtual();
creationArgs.isSecure = state.isSecure;
creationArgs.displaySurface = dispSurface;
creationArgs.hasWideColorGamut = false;
creationArgs.supportedPerFrameMetadata = 0;
- if (useColorManagement && displayId >= 0) {
- std::vector<ColorMode> modes = getHwComposer().getColorModes(displayId);
+ const bool isInternalDisplay = displayId && displayId == getInternalDisplayId();
+ creationArgs.isPrimary = isInternalDisplay;
+
+ if (useColorManagement && displayId) {
+ std::vector<ColorMode> modes = getHwComposer().getColorModes(*displayId);
for (ColorMode colorMode : modes) {
if (isWideColorMode(colorMode)) {
creationArgs.hasWideColorGamut = true;
}
std::vector<RenderIntent> renderIntents =
- getHwComposer().getRenderIntents(displayId, colorMode);
+ getHwComposer().getRenderIntents(*displayId, colorMode);
creationArgs.hwcColorModes.emplace(colorMode, renderIntents);
}
}
- if (displayId >= 0) {
- getHwComposer().getHdrCapabilities(displayId, &creationArgs.hdrCapabilities);
+ if (displayId) {
+ getHwComposer().getHdrCapabilities(*displayId, &creationArgs.hdrCapabilities);
creationArgs.supportedPerFrameMetadata =
- getHwComposer().getSupportedPerFrameMetadata(displayId);
+ getHwComposer().getSupportedPerFrameMetadata(*displayId);
}
auto nativeWindowSurface = getFactory().createNativeWindowSurface(producer);
@@ -2357,11 +2346,9 @@
* Create our display's surface
*/
std::unique_ptr<renderengine::Surface> renderSurface = getRenderEngine().createSurface();
- renderSurface->setCritical(state.type == DisplayDevice::DISPLAY_PRIMARY);
+ renderSurface->setCritical(isInternalDisplay);
renderSurface->setAsync(state.isVirtual());
renderSurface->setNativeWindow(nativeWindow.get());
- creationArgs.displayWidth = renderSurface->getWidth();
- creationArgs.displayHeight = renderSurface->getHeight();
creationArgs.renderSurface = std::move(renderSurface);
// Make sure that composition can never be stalled by a virtual display
@@ -2375,9 +2362,8 @@
nativeWindow->setSwapInterval(nativeWindow.get(), 0);
}
- creationArgs.displayInstallOrientation = state.type == DisplayDevice::DISPLAY_PRIMARY
- ? primaryDisplayOrientation
- : DisplayState::eOrientationDefault;
+ creationArgs.displayInstallOrientation =
+ isInternalDisplay ? primaryDisplayOrientation : DisplayState::eOrientationDefault;
// virtual displays are always considered enabled
creationArgs.initialPowerMode = state.isVirtual() ? HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF;
@@ -2396,9 +2382,11 @@
}
setActiveColorModeInternal(display, defaultColorMode, defaultDataSpace,
RenderIntent::COLORIMETRIC);
- if (state.type < DisplayDevice::DISPLAY_VIRTUAL) {
- display->setActiveConfig(getHwComposer().getActiveConfigIndex(state.type));
+ if (!state.isVirtual()) {
+ LOG_ALWAYS_FATAL_IF(!displayId);
+ display->setActiveConfig(getHwComposer().getActiveConfigIndex(*displayId));
}
+
display->setLayerStack(state.layerStack);
display->setProjection(state.orientation, state.viewport, state.frame);
display->setDisplayName(state.displayName);
@@ -2424,6 +2412,10 @@
for (size_t i = 0; i < dc;) {
const ssize_t j = curr.indexOfKey(draw.keyAt(i));
if (j < 0) {
+ // Save display IDs before disconnecting.
+ const auto internalDisplayId = getInternalDisplayId();
+ const auto externalDisplayId = getExternalDisplayId();
+
// in drawing state but not in current state
// Call makeCurrent() on the primary display so we can
// be sure that nothing associated with this display
@@ -2434,14 +2426,14 @@
if (const auto display = getDisplayDeviceLocked(draw.keyAt(i))) {
display->disconnect(getHwComposer());
}
- if (draw[i].type == DisplayDevice::DISPLAY_PRIMARY) {
+ if (internalDisplayId && internalDisplayId == draw[i].displayId) {
if (mUseScheduler) {
mScheduler->hotplugReceived(mAppConnectionHandle,
EventThread::DisplayType::Primary, false);
} else {
mEventThread->onHotplugReceived(EventThread::DisplayType::Primary, false);
}
- } else if (draw[i].type == DisplayDevice::DISPLAY_EXTERNAL) {
+ } else if (externalDisplayId && externalDisplayId == draw[i].displayId) {
if (mUseScheduler) {
mScheduler->hotplugReceived(mAppConnectionHandle,
EventThread::DisplayType::External, false);
@@ -2499,14 +2491,14 @@
sp<IGraphicBufferConsumer> bqConsumer;
getFactory().createBufferQueue(&bqProducer, &bqConsumer, false);
- int32_t displayId = -1;
+ std::optional<DisplayId> displayId;
if (state.isVirtual()) {
// Virtual displays without a surface are dormant:
// they have external state (layer stack, projection,
// etc.) but no internal state (i.e. a DisplayDevice).
if (state.surface != nullptr) {
// Allow VR composer to use virtual displays.
- if (mUseHwcVirtualDisplays || getBE().mHwc->isUsingVrComposer()) {
+ if (mUseHwcVirtualDisplays || getHwComposer().isUsingVrComposer()) {
int width = 0;
int status = state.surface->query(NATIVE_WINDOW_WIDTH, &width);
ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status);
@@ -2518,14 +2510,14 @@
ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status);
auto format = static_cast<ui::PixelFormat>(intFormat);
- getBE().mHwc->allocateVirtualDisplay(width, height, &format,
- &displayId);
+ displayId =
+ getHwComposer().allocateVirtualDisplay(width, height, &format);
}
// TODO: Plumb requested format back up to consumer
sp<VirtualDisplaySurface> vds =
- new VirtualDisplaySurface(*getBE().mHwc, displayId, state.surface,
+ new VirtualDisplaySurface(getHwComposer(), displayId, state.surface,
bqProducer, bqConsumer,
state.displayName);
@@ -2538,8 +2530,9 @@
"surface is provided (%p), ignoring it",
state.surface.get());
- displayId = state.type;
- dispSurface = new FramebufferSurface(*getBE().mHwc, displayId, bqConsumer);
+ displayId = state.displayId;
+ LOG_ALWAYS_FATAL_IF(!displayId);
+ dispSurface = new FramebufferSurface(getHwComposer(), *displayId, bqConsumer);
producer = bqProducer;
}
@@ -2549,7 +2542,9 @@
setupNewDisplayDeviceInternal(displayToken, displayId, state,
dispSurface, producer));
if (!state.isVirtual()) {
- if (state.type == DisplayDevice::DISPLAY_PRIMARY) {
+ LOG_ALWAYS_FATAL_IF(!displayId);
+
+ if (displayId == getInternalDisplayId()) {
if (mUseScheduler) {
mScheduler->hotplugReceived(mAppConnectionHandle,
EventThread::DisplayType::Primary,
@@ -2558,7 +2553,7 @@
mEventThread->onHotplugReceived(EventThread::DisplayType::Primary,
true);
}
- } else if (state.type == DisplayDevice::DISPLAY_EXTERNAL) {
+ } else if (displayId == getExternalDisplayId()) {
if (mUseScheduler) {
mScheduler->hotplugReceived(mAppConnectionHandle,
EventThread::DisplayType::External,
@@ -2712,7 +2707,7 @@
void SurfaceFlinger::updateCursorAsync()
{
for (const auto& [token, display] : mDisplays) {
- if (display->getId() < 0) {
+ if (!display->getId()) {
continue;
}
@@ -2736,7 +2731,11 @@
// abandon the buffer queue.
if (l->isRemovedFromCurrentState()) {
l->destroyAllHwcLayers();
- l->releasePendingBuffer(systemTime());
+ // destroyAllHwcLayers traverses to children, but releasePendingBuffer
+ // doesn't in other scenarios. So we have to traverse explicitly here.
+ l->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* child) {
+ child->releasePendingBuffer(systemTime());
+ });
}
}
mLayersPendingRemoval.clear();
@@ -2980,8 +2979,7 @@
// 1) It is being handled by hardware composer, which may need this to
// keep its virtual display state machine in sync, or
// 2) There is work to be done (the dirty region isn't empty)
- bool isHwcDisplay = display->getId() >= 0;
- if (!isHwcDisplay && inDirtyRegion.isEmpty()) {
+ if (!display->getId() && inDirtyRegion.isEmpty()) {
ALOGV("Skipping display composition");
return;
}
@@ -3104,8 +3102,9 @@
case HWC2::Composition::Device:
case HWC2::Composition::Sideband:
case HWC2::Composition::SolidColor: {
+ LOG_ALWAYS_FATAL_IF(!displayId);
const Layer::State& state(layer->getDrawingState());
- if (layer->getClearClientTarget(displayId) && !firstLayer &&
+ if (layer->getClearClientTarget(*displayId) && !firstLayer &&
layer->isOpaque(state) && (layer->getAlpha() == 1.0f) &&
hasClientComposition) {
// never clear the very first layer since we're
@@ -3194,19 +3193,15 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer, bool topLevelOnly) {
+status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer) {
Mutex::Autolock _l(mStateLock);
- return removeLayerLocked(mStateLock, layer, topLevelOnly);
+ return removeLayerLocked(mStateLock, layer);
}
-status_t SurfaceFlinger::removeLayerLocked(const Mutex& lock, const sp<Layer>& layer,
- bool topLevelOnly) {
+status_t SurfaceFlinger::removeLayerLocked(const Mutex& lock, const sp<Layer>& layer) {
const auto& p = layer->getParent();
ssize_t index;
if (p != nullptr) {
- if (topLevelOnly) {
- return NO_ERROR;
- }
index = p->removeChild(layer);
} else {
index = mCurrentState.layersSortedByZ.remove(layer);
@@ -3295,9 +3290,15 @@
transactionFlags |= setDisplayStateLocked(display);
}
+ uint32_t clientStateFlags = 0;
for (const ComposerState& state : states) {
- transactionFlags |= setClientStateLocked(state);
+ clientStateFlags |= setClientStateLocked(state);
}
+ // If the state doesn't require a traversal and there are callbacks, send them now
+ if (!(clientStateFlags & eTraversalNeeded)) {
+ mTransactionCompletedThread.sendCallbacks();
+ }
+ transactionFlags |= clientStateFlags;
// Iterate through all layers again to determine if any need to be destroyed. Marking layers
// as destroyed should only occur after setting all other states. This is to allow for a
@@ -3606,6 +3607,17 @@
if (what & layer_state_t::eSidebandStreamChanged) {
if (layer->setSidebandStream(s.sidebandStream)) flags |= eTraversalNeeded;
}
+
+ std::vector<sp<CallbackHandle>> callbackHandles;
+ if ((what & layer_state_t::eListenerCallbacksChanged) && (!s.listenerCallbacks.empty())) {
+ mTransactionCompletedThread.run();
+ for (const auto& [listener, callbackIds] : s.listenerCallbacks) {
+ callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface));
+ }
+ }
+ if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded;
+ // Do not put anything that updates layer state or modifies flags after
+ // setTransactionCompletedListener
return flags;
}
@@ -3806,7 +3818,7 @@
// ---------------------------------------------------------------------------
void SurfaceFlinger::onInitializeDisplays() {
- const auto displayToken = mDisplayTokens[DisplayDevice::DISPLAY_PRIMARY];
+ const auto displayToken = getInternalDisplayToken();
if (!displayToken) return;
// reset screen orientation and use primary layer stack
@@ -3830,7 +3842,7 @@
setPowerModeInternal(display, HWC_POWER_MODE_NORMAL, /*stateLockHeld*/ false);
- const auto activeConfig = getHwComposer().getActiveConfig(display->getId());
+ const auto activeConfig = getHwComposer().getActiveConfig(*display->getId());
const nsecs_t period = activeConfig->getVsyncPeriod();
mAnimFrameTracker.setDisplayRefreshPeriod(period);
@@ -3847,16 +3859,18 @@
void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int mode,
bool stateLockHeld) {
- const int32_t displayId = display->getId();
- ALOGD("Setting power mode %d on display %d", mode, displayId);
-
- int currentMode = display->getPowerMode();
- if (mode == currentMode) {
+ if (display->isVirtual()) {
+ ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
return;
}
- if (display->isVirtual()) {
- ALOGW("Trying to set power mode for virtual display");
+ const auto displayId = display->getId();
+ LOG_ALWAYS_FATAL_IF(!displayId);
+
+ ALOGD("Setting power mode %d on display %s", mode, to_string(*displayId).c_str());
+
+ int currentMode = display->getPowerMode();
+ if (mode == currentMode) {
return;
}
@@ -3872,12 +3886,10 @@
mInterceptor->savePowerModeUpdate(mCurrentState.displays.valueAt(idx).sequenceId, mode);
}
- int32_t type = display->getDisplayType();
if (currentMode == HWC_POWER_MODE_OFF) {
// Turn on the display
- getHwComposer().setPowerMode(type, mode);
+ getHwComposer().setPowerMode(*displayId, mode);
if (display->isPrimary() && mode != HWC_POWER_MODE_DOZE_SUSPEND) {
- // FIXME: eventthread only knows about the main display right now
if (mUseScheduler) {
mScheduler->onScreenAcquired(mAppConnectionHandle);
} else {
@@ -3908,7 +3920,6 @@
} else {
disableHardwareVsync(true); // also cancels any in-progress resync
}
- // FIXME: eventthread only knows about the main display right now
if (mUseScheduler) {
mScheduler->onScreenReleased(mAppConnectionHandle);
} else {
@@ -3916,15 +3927,14 @@
}
}
- getHwComposer().setPowerMode(type, mode);
+ getHwComposer().setPowerMode(*displayId, mode);
mVisibleRegionsDirty = true;
// from this point on, SF will stop drawing on this display
} else if (mode == HWC_POWER_MODE_DOZE ||
mode == HWC_POWER_MODE_NORMAL) {
// Update display while dozing
- getHwComposer().setPowerMode(type, mode);
+ getHwComposer().setPowerMode(*displayId, mode);
if (display->isPrimary() && currentMode == HWC_POWER_MODE_DOZE_SUSPEND) {
- // FIXME: eventthread only knows about the main display right now
if (mUseScheduler) {
mScheduler->onScreenAcquired(mAppConnectionHandle);
} else {
@@ -3940,24 +3950,23 @@
} else {
disableHardwareVsync(true); // also cancels any in-progress resync
}
- // FIXME: eventthread only knows about the main display right now
if (mUseScheduler) {
mScheduler->onScreenReleased(mAppConnectionHandle);
} else {
mEventThread->onScreenReleased();
}
}
- getHwComposer().setPowerMode(type, mode);
+ getHwComposer().setPowerMode(*displayId, mode);
} else {
ALOGE("Attempting to set unknown power mode: %d\n", mode);
- getHwComposer().setPowerMode(type, mode);
+ getHwComposer().setPowerMode(*displayId, mode);
}
if (display->isPrimary()) {
mTimeStats.setPowerMode(mode);
}
- ALOGD("Finished setting power mode %d on display %d", mode, displayId);
+ ALOGD("Finished setting power mode %d on display %s", mode, to_string(*displayId).c_str());
}
void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) {
@@ -4136,9 +4145,9 @@
index++;
}
- if (const auto displayId = DisplayDevice::DISPLAY_PRIMARY;
- getHwComposer().isConnected(displayId)) {
- const auto activeConfig = getBE().mHwc->getActiveConfig(displayId);
+ if (const auto displayId = getInternalDisplayId();
+ displayId && getHwComposer().isConnected(*displayId)) {
+ const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
const nsecs_t period = activeConfig->getVsyncPeriod();
result.appendFormat("%" PRId64 "\n", period);
}
@@ -4279,13 +4288,17 @@
void SurfaceFlinger::dumpDisplayIdentificationData(String8& result) const {
for (const auto& [token, display] : mDisplays) {
- const int32_t displayId = display->getId();
- const auto hwcDisplayId = getHwComposer().getHwcDisplayId(displayId);
+ const auto displayId = display->getId();
+ if (!displayId) {
+ continue;
+ }
+ const auto hwcDisplayId = getHwComposer().fromPhysicalDisplayId(*displayId);
if (!hwcDisplayId) {
continue;
}
- result.appendFormat("Display %d (HWC display %" PRIu64 "): ", displayId, *hwcDisplayId);
+ result.appendFormat("Display %s (HWC display %" PRIu64 "): ", to_string(*displayId).c_str(),
+ *hwcDisplayId);
uint8_t port;
DisplayIdentificationData data;
if (!getHwComposer().getDisplayIdentificationData(*hwcDisplayId, &port, &data)) {
@@ -4316,7 +4329,6 @@
result.append(edid->displayName.data(), edid->displayName.length());
result.append("\"\n");
}
- result.append("\n");
}
void SurfaceFlinger::dumpWideColorInfo(String8& result) const {
@@ -4328,13 +4340,13 @@
// TODO: print out if wide-color mode is active or not
for (const auto& [token, display] : mDisplays) {
- const int32_t displayId = display->getId();
- if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
+ const auto displayId = display->getId();
+ if (!displayId) {
continue;
}
- result.appendFormat("Display %d color modes:\n", displayId);
- std::vector<ColorMode> modes = getHwComposer().getColorModes(displayId);
+ result.appendFormat("Display %s color modes:\n", to_string(*displayId).c_str());
+ std::vector<ColorMode> modes = getHwComposer().getColorModes(*displayId);
for (auto&& mode : modes) {
result.appendFormat(" %s (%d)\n", decodeColorMode(mode).c_str(), mode);
}
@@ -4390,11 +4402,12 @@
layersProto.set_color_transform(decodeColorTransform(display.getColorTransform()));
layersProto.set_global_transform(static_cast<int32_t>(display.getOrientationTransform()));
- const int32_t displayId = display.getId();
+ const auto displayId = display.getId();
+ LOG_ALWAYS_FATAL_IF(!displayId);
mDrawingState.traverseInZOrder([&](Layer* layer) {
- if (!layer->visibleRegion.isEmpty() && layer->getBE().mHwcLayers.count(displayId)) {
+ if (!layer->visibleRegion.isEmpty() && layer->getBE().mHwcLayers.count(*displayId)) {
LayerProto* layerProto = layersProto.add_layers();
- layer->writeToProto(layerProto, displayId);
+ layer->writeToProto(layerProto, *displayId);
}
});
@@ -4448,25 +4461,19 @@
const auto [sfEarlyOffset, appEarlyOffset] = mVsyncModulator.getEarlyOffsets();
const auto [sfEarlyGlOffset, appEarlyGlOffset] = mVsyncModulator.getEarlyGlOffsets();
- if (const auto displayId = DisplayDevice::DISPLAY_PRIMARY;
- getHwComposer().isConnected(displayId)) {
- const auto activeConfig = getHwComposer().getActiveConfig(displayId);
- result.appendFormat("Display %d: "
- "app phase %" PRId64 " ns, "
- "sf phase %" PRId64 " ns, "
- "early app phase %" PRId64 " ns, "
- "early sf phase %" PRId64 " ns, "
- "early app gl phase %" PRId64 " ns, "
- "early sf gl phase %" PRId64 " ns, "
- "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
- displayId,
- vsyncPhaseOffsetNs,
- sfVsyncPhaseOffsetNs,
- appEarlyOffset,
- sfEarlyOffset,
- appEarlyGlOffset,
- sfEarlyGlOffset,
- dispSyncPresentTimeOffset, activeConfig->getVsyncPeriod());
+ if (const auto displayId = getInternalDisplayId();
+ displayId && getHwComposer().isConnected(*displayId)) {
+ const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
+ result.appendFormat("Display %s: app phase %" PRId64 " ns, "
+ "sf phase %" PRId64 " ns, "
+ "early app phase %" PRId64 " ns, "
+ "early sf phase %" PRId64 " ns, "
+ "early app gl phase %" PRId64 " ns, "
+ "early sf gl phase %" PRId64 " ns, "
+ "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
+ to_string(*displayId).c_str(), vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs,
+ appEarlyOffset, sfEarlyOffset, appEarlyGlOffset, sfEarlyGlOffset,
+ dispSyncPresentTimeOffset, activeConfig->getVsyncPeriod());
}
result.append("\n");
@@ -4519,12 +4526,9 @@
result.append("SurfaceFlinger global state:\n");
colorizer.reset(result);
- HWComposer& hwc(getHwComposer());
- const auto display = getDefaultDisplayDeviceLocked();
-
getBE().mRenderEngine->dump(result);
- if (display) {
+ if (const auto display = getDefaultDisplayDeviceLocked()) {
display->undefinedRegion.dump(result, "undefinedRegion");
result.appendFormat(" orientation=%d, isPoweredOn=%d\n", display->getOrientation(),
display->isPoweredOn());
@@ -4533,8 +4537,9 @@
" gpu_to_cpu_unsupported : %d\n",
mTransactionFlags.load(), !mGpuToCpuSupported);
- if (display) {
- const auto activeConfig = getHwComposer().getActiveConfig(display->getId());
+ if (const auto displayId = getInternalDisplayId();
+ displayId && getHwComposer().isConnected(*displayId)) {
+ const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
result.appendFormat(" refresh-rate : %f fps\n"
" x-dpi : %f\n"
" y-dpi : %f\n",
@@ -4566,14 +4571,14 @@
* HWC layer minidump
*/
for (const auto& [token, display] : mDisplays) {
- const int32_t displayId = display->getId();
- if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
+ const auto displayId = display->getId();
+ if (!displayId) {
continue;
}
- result.appendFormat("Display %d HWC layers:\n", displayId);
+ result.appendFormat("Display %s HWC layers:\n", to_string(*displayId).c_str());
Layer::miniDumpHeader(result);
- mCurrentState.traverseInZOrder([&](Layer* layer) { layer->miniDump(result, displayId); });
+ mCurrentState.traverseInZOrder([&](Layer* layer) { layer->miniDump(result, *displayId); });
result.append("\n");
}
@@ -4586,7 +4591,7 @@
bool hwcDisabled = mDebugDisableHWC || mDebugRegion;
result.appendFormat(" h/w composer %s\n",
hwcDisabled ? "disabled" : "enabled");
- hwc.dump(result);
+ getHwComposer().dump(result);
/*
* Dump gralloc state
@@ -4604,7 +4609,7 @@
}
}
-const Vector<sp<Layer>>& SurfaceFlinger::getLayerSortedByZForHwcDisplay(int32_t displayId) {
+const Vector<sp<Layer>>& SurfaceFlinger::getLayerSortedByZForHwcDisplay(DisplayId displayId) {
// Note: mStateLock is held here
for (const auto& [token, display] : mDisplays) {
if (display->getId() == displayId) {
@@ -4612,7 +4617,7 @@
}
}
- ALOGE("%s: Invalid display %d", __FUNCTION__, displayId);
+ ALOGE("%s: Invalid display %s", __FUNCTION__, to_string(displayId).c_str());
static const Vector<sp<Layer>> empty;
return empty;
}
@@ -4746,9 +4751,9 @@
code == IBinder::SYSPROPS_TRANSACTION) {
return OK;
}
- // Numbers from 1000 to 1030 are currently use for backdoors. The code
+ // Numbers from 1000 to 1031 are currently use for backdoors. The code
// in onTransact verifies that the user is root, and has access to use SF.
- if (code >= 1000 && code <= 1030) {
+ if (code >= 1000 && code <= 1031) {
ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
return OK;
}
@@ -5002,6 +5007,38 @@
reply->writeBool(useColorManagement);
return NO_ERROR;
}
+ // Override default composition data space
+ // adb shell service call SurfaceFlinger 1031 i32 1 DATASPACE_NUMBER DATASPACE_NUMBER \
+ // && adb shell stop zygote && adb shell start zygote
+ // to restore: adb shell service call SurfaceFlinger 1031 i32 0 && \
+ // adb shell stop zygote && adb shell start zygote
+ case 1031: {
+ Mutex::Autolock _l(mStateLock);
+ n = data.readInt32();
+ if (n) {
+ n = data.readInt32();
+ if (n) {
+ Dataspace dataspace = static_cast<Dataspace>(n);
+ if (!validateCompositionDataspace(dataspace)) {
+ return BAD_VALUE;
+ }
+ mDefaultCompositionDataspace = dataspace;
+ }
+ n = data.readInt32();
+ if (n) {
+ Dataspace dataspace = static_cast<Dataspace>(n);
+ if (!validateCompositionDataspace(dataspace)) {
+ return BAD_VALUE;
+ }
+ mWideColorGamutCompositionDataspace = dataspace;
+ }
+ } else {
+ // restore composition data space.
+ mDefaultCompositionDataspace = defaultCompositionDataspace;
+ mWideColorGamutCompositionDataspace = wideColorGamutCompositionDataspace;
+ }
+ return NO_ERROR;
+ }
}
}
return err;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 51168a6..8b389bc 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -62,6 +62,7 @@
#include "SurfaceFlingerFactory.h"
#include "SurfaceInterceptor.h"
#include "SurfaceTracing.h"
+#include "TransactionCompletedThread.h"
#include "DisplayHardware/HWC2.h"
#include "DisplayHardware/HWComposer.h"
@@ -76,10 +77,11 @@
#include <map>
#include <mutex>
#include <queue>
+#include <set>
#include <string>
#include <thread>
+#include <unordered_map>
#include <utility>
-#include "RenderArea.h"
#include <layerproto/LayerProtoHeader.h>
@@ -348,7 +350,7 @@
// enable/disable h/w composer event
// TODO: this should be made accessible only to EventThread
- void setVsyncEnabled(int disp, int enabled);
+ void setVsyncEnabled(EventThread::DisplayType displayType, bool enabled);
// called on the main thread by MessageQueue when an internal message
// is received
@@ -357,7 +359,7 @@
// for debugging only
// TODO: this should be made accessible only to HWComposer
- const Vector< sp<Layer> >& getLayerSortedByZForHwcDisplay(int id);
+ const Vector<sp<Layer>>& getLayerSortedByZForHwcDisplay(DisplayId displayId);
renderengine::RenderEngine& getRenderEngine() const { return *getBE().mRenderEngine; }
@@ -367,6 +369,10 @@
inline void onLayerCreated() { mNumLayers++; }
inline void onLayerDestroyed() { mNumLayers--; }
+ TransactionCompletedThread& getTransactionCompletedThread() {
+ return mTransactionCompletedThread;
+ }
+
private:
friend class Client;
friend class DisplayEventConnection;
@@ -586,8 +592,8 @@
void onHandleDestroyed(const sp<Layer>& layer);
// remove a layer from SurfaceFlinger immediately
- status_t removeLayer(const sp<Layer>& layer, bool topLevelOnly = false);
- status_t removeLayerLocked(const Mutex&, const sp<Layer>& layer, bool topLevelOnly = false);
+ status_t removeLayer(const sp<Layer>& layer);
+ status_t removeLayerLocked(const Mutex&, const sp<Layer>& layer);
// add a layer to SurfaceFlinger
status_t addClientLayer(const sp<Client>& client,
@@ -659,7 +665,10 @@
}
sp<DisplayDevice> getDefaultDisplayDeviceLocked() {
- return getDisplayDeviceLocked(mDisplayTokens[DisplayDevice::DISPLAY_PRIMARY]);
+ if (const auto token = getInternalDisplayToken()) {
+ return getDisplayDeviceLocked(token);
+ }
+ return nullptr;
}
// mark a region of a layer stack dirty. this updates the dirty
@@ -724,10 +733,8 @@
/* ------------------------------------------------------------------------
* Display management
*/
- DisplayDevice::DisplayType determineDisplayType(hwc2_display_t hwcDisplayId,
- HWC2::Connection connection) const;
sp<DisplayDevice> setupNewDisplayDeviceInternal(const wp<IBinder>& displayToken,
- int32_t displayId,
+ const std::optional<DisplayId>& displayId,
const DisplayDeviceState& state,
const sp<DisplaySurface>& dispSurface,
const sp<IGraphicBufferProducer>& producer);
@@ -759,6 +766,37 @@
}
private:
+ sp<IBinder> getPhysicalDisplayToken(DisplayId displayId) const {
+ const auto it = mPhysicalDisplayTokens.find(displayId);
+ return it != mPhysicalDisplayTokens.end() ? it->second : nullptr;
+ }
+
+ std::optional<DisplayId> getPhysicalDisplayId(const sp<IBinder>& displayToken) const {
+ for (const auto& [id, token] : mPhysicalDisplayTokens) {
+ if (token == displayToken) {
+ return id;
+ }
+ }
+ return {};
+ }
+
+ // TODO(b/74619554): Remove special cases for primary display.
+ sp<IBinder> getInternalDisplayToken() const {
+ const auto displayId = getInternalDisplayId();
+ return displayId ? getPhysicalDisplayToken(*displayId) : nullptr;
+ }
+
+ std::optional<DisplayId> getInternalDisplayId() const {
+ const auto hwcDisplayId = getHwComposer().getInternalHwcDisplayId();
+ return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt;
+ }
+
+ // TODO(b/74619554): Remove special cases for external display.
+ std::optional<DisplayId> getExternalDisplayId() const {
+ const auto hwcDisplayId = getHwComposer().getExternalHwcDisplayId();
+ return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt;
+ }
+
void listLayersLocked(const Vector<String16>& args, size_t& index, String8& result) const;
void dumpStatsLocked(const Vector<String16>& args, size_t& index, String8& result) const;
void clearStatsLocked(const Vector<String16>& args, size_t& index, String8& result);
@@ -836,7 +874,7 @@
std::unique_ptr<VSyncSource> mSfEventThreadSource;
std::unique_ptr<InjectVSyncSource> mVSyncInjector;
std::unique_ptr<EventControlThread> mEventControlThread;
- sp<IBinder> mDisplayTokens[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES];
+ std::unordered_map<DisplayId, sp<IBinder>> mPhysicalDisplayTokens;
VSyncModulator mVsyncModulator;
@@ -886,6 +924,8 @@
bool mUseHwcVirtualDisplays = false;
std::atomic<uint32_t> mFrameMissedCount{0};
+ TransactionCompletedThread mTransactionCompletedThread;
+
// Restrict layers to use two buffers in their bufferqueues.
bool mLayerTripleBufferingDisabled = false;
@@ -937,6 +977,9 @@
// Applied on Display P3 layers when the render intent is non-colorimetric.
mat4 mEnhancedSaturationMatrix;
+ ui::Dataspace mDefaultCompositionDataspace;
+ ui::Dataspace mWideColorGamutCompositionDataspace;
+
SurfaceFlingerBE mBE;
bool mUseScheduler = false;
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 57bda5a..55cfa4b 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -495,8 +495,10 @@
DisplayCreation* creation(increment->mutable_display_creation());
creation->set_id(info.sequenceId);
creation->set_name(info.displayName);
- creation->set_type(info.type);
creation->set_is_secure(info.isSecure);
+ if (info.displayId) {
+ creation->set_display_id(info.displayId->value);
+ }
}
void SurfaceInterceptor::addDisplayDeletionLocked(Increment* increment, int32_t sequenceId) {
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index ace7c1b..9730e8c 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -173,8 +173,8 @@
ALOGV("[%d]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerID,
timeRecords[0].frameTime.frameNumber, timeRecords[0].frameTime.presentTime);
+ const std::string& layerName = layerRecord.layerName;
if (prevTimeRecord.ready) {
- const std::string& layerName = layerRecord.layerName;
if (!mTimeStats.stats.count(layerName)) {
mTimeStats.stats[layerName].layerName = layerName;
mTimeStats.stats[layerName].packageName = getPackageName(layerName);
@@ -220,6 +220,18 @@
timeRecords[0].frameTime.frameNumber, presentToPresentMs);
timeStatsLayer.deltas["present2present"].insert(presentToPresentMs);
}
+
+ // Output additional trace points to track frame time.
+ ATRACE_INT64(("TimeStats-Post - " + layerName).c_str(), timeRecords[0].frameTime.postTime);
+ ATRACE_INT64(("TimeStats-Acquire - " + layerName).c_str(),
+ timeRecords[0].frameTime.acquireTime);
+ ATRACE_INT64(("TimeStats-Latch - " + layerName).c_str(),
+ timeRecords[0].frameTime.latchTime);
+ ATRACE_INT64(("TimeStats-Desired - " + layerName).c_str(),
+ timeRecords[0].frameTime.desiredTime);
+ ATRACE_INT64(("TimeStats-Present - " + layerName).c_str(),
+ timeRecords[0].frameTime.presentTime);
+
prevTimeRecord = timeRecords[0];
timeRecords.pop_front();
layerRecord.waitData--;
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
new file mode 100644
index 0000000..9b9dc57
--- /dev/null
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "TransactionCompletedThread"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "TransactionCompletedThread.h"
+
+#include <cinttypes>
+
+#include <binder/IInterface.h>
+#include <gui/ITransactionCompletedListener.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+TransactionCompletedThread::~TransactionCompletedThread() {
+ {
+ std::lock_guard lock(mMutex);
+ mKeepRunning = false;
+ mConditionVariable.notify_all();
+ }
+
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+
+ {
+ std::lock_guard lock(mMutex);
+ for (const auto& [listener, listenerStats] : mListenerStats) {
+ listener->unlinkToDeath(mDeathRecipient);
+ }
+ }
+}
+
+void TransactionCompletedThread::run() {
+ std::lock_guard lock(mMutex);
+ if (mRunning) {
+ return;
+ }
+ mDeathRecipient = new ThreadDeathRecipient();
+ mRunning = true;
+ mThread = std::thread(&TransactionCompletedThread::threadMain, this);
+}
+
+void TransactionCompletedThread::registerPendingLatchedCallbackHandle(
+ const sp<CallbackHandle>& handle) {
+ std::lock_guard lock(mMutex);
+
+ sp<IBinder> listener = IInterface::asBinder(handle->listener);
+ const auto& callbackIds = handle->callbackIds;
+
+ mPendingTransactions[listener][callbackIds]++;
+}
+
+void TransactionCompletedThread::addLatchedCallbackHandles(
+ const std::deque<sp<CallbackHandle>>& handles, nsecs_t latchTime,
+ const sp<Fence>& previousReleaseFence) {
+ std::lock_guard lock(mMutex);
+
+ // If the previous release fences have not signaled, something as probably gone wrong.
+ // Store the fences and check them again before sending a callback.
+ if (previousReleaseFence &&
+ previousReleaseFence->getSignalTime() == Fence::SIGNAL_TIME_PENDING) {
+ ALOGD("release fence from the previous frame has not signaled");
+ mPreviousReleaseFences.push_back(previousReleaseFence);
+ }
+
+ for (const auto& handle : handles) {
+ auto listener = mPendingTransactions.find(IInterface::asBinder(handle->listener));
+ auto& pendingCallbacks = listener->second;
+ auto pendingCallback = pendingCallbacks.find(handle->callbackIds);
+
+ if (pendingCallback != pendingCallbacks.end()) {
+ auto& pendingCount = pendingCallback->second;
+
+ // Decrease the pending count for this listener
+ if (--pendingCount == 0) {
+ pendingCallbacks.erase(pendingCallback);
+ }
+ } else {
+ ALOGE("there are more latched callbacks than there were registered callbacks");
+ }
+
+ addCallbackHandle(handle, latchTime);
+ }
+}
+
+void TransactionCompletedThread::addUnlatchedCallbackHandle(const sp<CallbackHandle>& handle) {
+ std::lock_guard lock(mMutex);
+ addCallbackHandle(handle);
+}
+
+void TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle,
+ nsecs_t latchTime) {
+ const sp<IBinder> listener = IInterface::asBinder(handle->listener);
+
+ // If we don't already have a reference to this listener, linkToDeath so we get a notification
+ // if it dies.
+ if (mListenerStats.count(listener) == 0) {
+ status_t error = listener->linkToDeath(mDeathRecipient);
+ if (error != NO_ERROR) {
+ ALOGE("cannot add callback handle because linkToDeath failed, err: %d", error);
+ return;
+ }
+ }
+
+ auto& listenerStats = mListenerStats[listener];
+ listenerStats.listener = handle->listener;
+
+ auto& transactionStats = listenerStats.transactionStats[handle->callbackIds];
+ transactionStats.latchTime = latchTime;
+ transactionStats.surfaceStats.emplace_back(handle->surfaceControl, handle->acquireTime,
+ handle->releasePreviousBuffer);
+}
+
+void TransactionCompletedThread::addPresentFence(const sp<Fence>& presentFence) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mPresentFence = presentFence;
+}
+
+void TransactionCompletedThread::sendCallbacks() {
+ std::lock_guard lock(mMutex);
+ if (mRunning) {
+ mConditionVariable.notify_all();
+ }
+}
+
+void TransactionCompletedThread::threadMain() {
+ std::lock_guard lock(mMutex);
+
+ while (mKeepRunning) {
+ mConditionVariable.wait(mMutex);
+
+ // Present fence should fire almost immediately. If the fence has not signaled in 100ms,
+ // there is a major problem and it will probably never fire.
+ nsecs_t presentTime = -1;
+ if (mPresentFence) {
+ status_t status = mPresentFence->wait(100);
+ if (status == NO_ERROR) {
+ presentTime = mPresentFence->getSignalTime();
+ } else {
+ ALOGE("present fence has not signaled, err %d", status);
+ }
+ }
+
+ // We should never hit this case. The release fences from the previous frame should have
+ // signaled long before the current frame is presented.
+ for (const auto& fence : mPreviousReleaseFences) {
+ status_t status = fence->wait(100);
+ if (status != NO_ERROR) {
+ ALOGE("previous release fence has not signaled, err %d", status);
+ }
+ }
+
+ // For each listener
+ auto it = mListenerStats.begin();
+ while (it != mListenerStats.end()) {
+ auto& [listener, listenerStats] = *it;
+
+ // For each transaction
+ bool sendCallback = true;
+ for (auto& [callbackIds, transactionStats] : listenerStats.transactionStats) {
+ // If we are still waiting on the callback handles for this transaction, skip it
+ if (mPendingTransactions[listener].count(callbackIds) != 0) {
+ sendCallback = false;
+ break;
+ }
+
+ // If the transaction has been latched
+ if (transactionStats.latchTime >= 0) {
+ // If the present time is < 0, this transaction has been latched but not
+ // presented. Skip it for now. This can happen when a new transaction comes
+ // in between the latch and present steps. sendCallbacks is called by
+ // SurfaceFlinger when the transaction is received to ensure that if the
+ // transaction that didn't update state it still got a callback.
+ if (presentTime < 0) {
+ sendCallback = false;
+ break;
+ }
+
+ transactionStats.presentTime = presentTime;
+ }
+ }
+ // If the listener has no pending transactions and all latched transactions have been
+ // presented
+ if (sendCallback) {
+ // If the listener is still alive
+ if (listener->isBinderAlive()) {
+ // Send callback
+ listenerStats.listener->onTransactionCompleted(listenerStats);
+ listener->unlinkToDeath(mDeathRecipient);
+ }
+ it = mListenerStats.erase(it);
+ } else {
+ it++;
+ }
+ }
+
+ if (mPresentFence) {
+ mPresentFence.clear();
+ mPreviousReleaseFences.clear();
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+CallbackHandle::CallbackHandle(const sp<ITransactionCompletedListener>& transactionListener,
+ const std::vector<CallbackId>& ids, const sp<IBinder>& sc)
+ : listener(transactionListener), callbackIds(ids), surfaceControl(sc) {}
+
+} // namespace android
diff --git a/services/surfaceflinger/TransactionCompletedThread.h b/services/surfaceflinger/TransactionCompletedThread.h
new file mode 100644
index 0000000..5af4097
--- /dev/null
+++ b/services/surfaceflinger/TransactionCompletedThread.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <condition_variable>
+#include <deque>
+#include <mutex>
+#include <thread>
+#include <unordered_map>
+
+#include <android-base/thread_annotations.h>
+
+#include <binder/IBinder.h>
+#include <gui/ITransactionCompletedListener.h>
+#include <ui/Fence.h>
+
+namespace android {
+
+class CallbackHandle : public RefBase {
+public:
+ CallbackHandle(const sp<ITransactionCompletedListener>& transactionListener,
+ const std::vector<CallbackId>& ids, const sp<IBinder>& sc);
+
+ sp<ITransactionCompletedListener> listener;
+ std::vector<CallbackId> callbackIds;
+ sp<IBinder> surfaceControl;
+
+ bool releasePreviousBuffer = false;
+ nsecs_t acquireTime = -1;
+};
+
+class TransactionCompletedThread {
+public:
+ ~TransactionCompletedThread();
+
+ void run();
+
+ // Informs the TransactionCompletedThread that there is a Transaction with a CallbackHandle
+ // that needs to be latched and presented this frame. This function should be called once the
+ // layer has received the CallbackHandle so the TransactionCompletedThread knows not to send
+ // a callback for that Listener/Transaction pair until that CallbackHandle has been latched and
+ // presented.
+ void registerPendingLatchedCallbackHandle(const sp<CallbackHandle>& handle);
+ // Notifies the TransactionCompletedThread that a pending CallbackHandle has been latched.
+ void addLatchedCallbackHandles(const std::deque<sp<CallbackHandle>>& handles, nsecs_t latchTime,
+ const sp<Fence>& previousReleaseFence);
+
+ // Adds the Transaction CallbackHandle from a layer that does not need to be relatched and
+ // presented this frame.
+ void addUnlatchedCallbackHandle(const sp<CallbackHandle>& handle);
+
+ void addPresentFence(const sp<Fence>& presentFence);
+
+ void sendCallbacks();
+
+private:
+ void threadMain();
+
+ void addCallbackHandle(const sp<CallbackHandle>& handle, nsecs_t latchTime = -1)
+ REQUIRES(mMutex);
+
+ class ThreadDeathRecipient : public IBinder::DeathRecipient {
+ public:
+ // This function is a no-op. isBinderAlive needs a linked DeathRecipient to work.
+ // Death recipients needs a binderDied function.
+ //
+ // (isBinderAlive checks if BpBinder's mAlive is 0. mAlive is only set to 0 in sendObituary.
+ // sendObituary is only called if linkToDeath was called with a DeathRecipient.)
+ void binderDied(const wp<IBinder>& /*who*/) override {}
+ };
+ sp<ThreadDeathRecipient> mDeathRecipient;
+
+ struct IBinderHash {
+ std::size_t operator()(const sp<IBinder>& strongPointer) const {
+ return std::hash<IBinder*>{}(strongPointer.get());
+ }
+ };
+
+ std::thread mThread;
+
+ std::mutex mMutex;
+ std::condition_variable_any mConditionVariable;
+
+ std::unordered_map<
+ sp<IBinder /*listener*/>,
+ std::unordered_map<std::vector<CallbackId>, uint32_t /*count*/, CallbackIdsHash>,
+ IBinderHash>
+ mPendingTransactions GUARDED_BY(mMutex);
+ std::unordered_map<sp<IBinder /*listener*/>, ListenerStats, IBinderHash> mListenerStats
+ GUARDED_BY(mMutex);
+
+ bool mRunning GUARDED_BY(mMutex) = false;
+ bool mKeepRunning GUARDED_BY(mMutex) = true;
+
+ sp<Fence> mPresentFence GUARDED_BY(mMutex);
+ std::vector<sp<Fence>> mPreviousReleaseFences GUARDED_BY(mMutex);
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index 9c2edca..92ae87b 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -28,7 +28,6 @@
#include <cutils/sched_policy.h>
#include <displayservice/DisplayService.h>
#include <hidl/LegacySupport.h>
-#include "GpuService.h"
#include "SurfaceFlinger.h"
#include "SurfaceFlingerFactory.h"
@@ -104,10 +103,6 @@
sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
- // publish GpuService
- sp<GpuService> gpuservice = new GpuService();
- sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);
-
startDisplayService(); // dependency on SF getting registered above
struct sched_param param = {0};
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index 8bd5fcb..91999ae 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
{
"presubmit": {
- "filter": "CredentialsTest.*:SurfaceFlingerStress.*:SurfaceInterceptorTest.*:LayerTransactionTest.*:LayerTypeTransactionTest.*:LayerUpdateTest.*:GeometryLatchingTest.*:CropLatchingTest.*:ChildLayerTest.*:ScreenCaptureTest.*:ScreenCaptureChildOnlyTest.*:DereferenceSurfaceControlTest.*"
+ "filter": "CredentialsTest.*:SurfaceFlingerStress.*:SurfaceInterceptorTest.*:LayerTransactionTest.*:LayerTypeTransactionTest.*:LayerUpdateTest.*:GeometryLatchingTest.*:CropLatchingTest.*:ChildLayerTest.*:ScreenCaptureTest.*:ScreenCaptureChildOnlyTest.*:DereferenceSurfaceControlTest.*:BoundlessLayerTest.*"
}
}
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 94b33ac..988454a 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -15,9 +15,12 @@
*/
#include <algorithm>
+#include <chrono>
+#include <cinttypes>
#include <functional>
#include <limits>
#include <ostream>
+#include <thread>
#include <gtest/gtest.h>
@@ -64,6 +67,7 @@
const Color Color::TRANSPARENT{0, 0, 0, 0};
using android::hardware::graphics::common::V1_1::BufferUsage;
+using namespace std::chrono_literals;
std::ostream& operator<<(std::ostream& os, const Color& color) {
os << int(color.r) << ", " << int(color.g) << ", " << int(color.b) << ", " << int(color.a);
@@ -327,16 +331,21 @@
mClient = 0;
}
- virtual sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
+ virtual sp<SurfaceControl> createLayer(const sp<SurfaceComposerClient>& client,
+ const char* name, uint32_t width, uint32_t height,
uint32_t flags = 0) {
auto layer =
- mClient->createSurface(String8(name), width, height, PIXEL_FORMAT_RGBA_8888, flags);
+ client->createSurface(String8(name), width, height, PIXEL_FORMAT_RGBA_8888, flags);
EXPECT_NE(nullptr, layer.get()) << "failed to create SurfaceControl";
- status_t error = Transaction()
- .setLayerStack(layer, mDisplayLayerStack)
- .setLayer(layer, mLayerZBase)
- .apply();
+ Transaction t;
+ t.setLayerStack(layer, mDisplayLayerStack).setLayer(layer, mLayerZBase);
+ // If we are creating a color layer, set its crop since its size will be ignored.
+ if (flags == ISurfaceComposerClient::eFXSurfaceColor) {
+ t.setCrop_legacy(layer, Rect(0, 0, width, height));
+ }
+
+ status_t error = t.apply();
if (error != NO_ERROR) {
ADD_FAILURE() << "failed to initialize SurfaceControl";
layer.clear();
@@ -345,6 +354,11 @@
return layer;
}
+ virtual sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
+ uint32_t flags = 0) {
+ return createLayer(mClient, name, width, height, flags);
+ }
+
ANativeWindow_Buffer getBufferQueueLayerBuffer(const sp<SurfaceControl>& layer) {
// wait for previous transactions (such as setSize) to complete
Transaction().apply(true);
@@ -502,6 +516,7 @@
// set layer stack (b/68888219)
Transaction t;
t.setDisplayLayerStack(mDisplay, mDisplayLayerStack);
+ t.setCrop_legacy(mBlackBgSurface, Rect(0, 0, mDisplayWidth, mDisplayHeight));
t.setLayerStack(mBlackBgSurface, mDisplayLayerStack);
t.setColor(mBlackBgSurface, half3{0, 0, 0});
t.setLayer(mBlackBgSurface, mLayerZBase);
@@ -1953,7 +1968,7 @@
"test");
fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
- sp<Fence> fence = new Fence(-1);
+ sp<Fence> fence = Fence::NO_FENCE;
Transaction()
.setBuffer(layer, buffer)
@@ -2156,6 +2171,627 @@
}
}
+class ExpectedResult {
+public:
+ enum Transaction {
+ NOT_PRESENTED = 0,
+ PRESENTED,
+ };
+
+ enum Buffer {
+ NOT_ACQUIRED = 0,
+ ACQUIRED,
+ };
+
+ enum PreviousBuffer {
+ NOT_RELEASED = 0,
+ RELEASED,
+ };
+
+ void reset() {
+ mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED;
+ mExpectedSurfaceResults.clear();
+ }
+
+ void addSurface(ExpectedResult::Transaction transactionResult, const sp<SurfaceControl>& layer,
+ ExpectedResult::Buffer bufferResult = NOT_ACQUIRED,
+ ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) {
+ mTransactionResult = transactionResult;
+ mExpectedSurfaceResults.emplace(std::piecewise_construct,
+ std::forward_as_tuple(layer->getHandle()),
+ std::forward_as_tuple(bufferResult, previousBufferResult));
+ }
+
+ void addSurfaces(ExpectedResult::Transaction transactionResult,
+ const std::vector<sp<SurfaceControl>>& layers,
+ ExpectedResult::Buffer bufferResult = NOT_ACQUIRED,
+ ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) {
+ for (const auto& layer : layers) {
+ addSurface(transactionResult, layer, bufferResult, previousBufferResult);
+ }
+ }
+
+ void verifyTransactionStats(const TransactionStats& transactionStats) const {
+ const auto& [latchTime, presentTime, surfaceStats] = transactionStats;
+ if (mTransactionResult == ExpectedResult::Transaction::PRESENTED) {
+ ASSERT_GE(latchTime, 0) << "bad latch time";
+ ASSERT_GE(presentTime, 0) << "bad present time";
+ } else {
+ ASSERT_EQ(presentTime, -1) << "transaction shouldn't have been presented";
+ ASSERT_EQ(latchTime, -1) << "unpresented transactions shouldn't be latched";
+ }
+
+ ASSERT_EQ(surfaceStats.size(), mExpectedSurfaceResults.size())
+ << "wrong number of surfaces";
+
+ for (const auto& stats : surfaceStats) {
+ const auto& expectedSurfaceResult = mExpectedSurfaceResults.find(stats.surfaceControl);
+ ASSERT_NE(expectedSurfaceResult, mExpectedSurfaceResults.end())
+ << "unexpected surface control";
+ expectedSurfaceResult->second.verifySurfaceStats(stats, latchTime);
+ }
+ }
+
+private:
+ class ExpectedSurfaceResult {
+ public:
+ ExpectedSurfaceResult(ExpectedResult::Buffer bufferResult,
+ ExpectedResult::PreviousBuffer previousBufferResult)
+ : mBufferResult(bufferResult), mPreviousBufferResult(previousBufferResult) {}
+
+ void verifySurfaceStats(const SurfaceStats& surfaceStats, nsecs_t latchTime) const {
+ const auto& [surfaceControl, acquireTime, releasePreviousBuffer] = surfaceStats;
+
+ ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED)
+ << "bad acquire time";
+ ASSERT_LE(acquireTime, latchTime) << "acquire time should be <= latch time";
+ ASSERT_EQ(releasePreviousBuffer,
+ mPreviousBufferResult == ExpectedResult::PreviousBuffer::RELEASED)
+ << "bad previous buffer released";
+ }
+
+ private:
+ ExpectedResult::Buffer mBufferResult;
+ ExpectedResult::PreviousBuffer mPreviousBufferResult;
+ };
+
+ struct IBinderHash {
+ std::size_t operator()(const sp<IBinder>& strongPointer) const {
+ return std::hash<IBinder*>{}(strongPointer.get());
+ }
+ };
+ ExpectedResult::Transaction mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED;
+ std::unordered_map<sp<IBinder>, ExpectedSurfaceResult, IBinderHash> mExpectedSurfaceResults;
+};
+
+class CallbackHelper {
+public:
+ static void function(void* callbackContext, const TransactionStats& transactionStats) {
+ if (!callbackContext) {
+ ALOGE("failed to get callback context");
+ }
+ CallbackHelper* helper = static_cast<CallbackHelper*>(callbackContext);
+ std::lock_guard lock(helper->mMutex);
+ helper->mTransactionStatsQueue.push(transactionStats);
+ helper->mConditionVariable.notify_all();
+ }
+
+ void getTransactionStats(TransactionStats* outStats) {
+ std::unique_lock lock(mMutex);
+
+ if (mTransactionStatsQueue.empty()) {
+ ASSERT_NE(mConditionVariable.wait_for(lock, std::chrono::seconds(3)),
+ std::cv_status::timeout)
+ << "did not receive callback";
+ }
+
+ *outStats = std::move(mTransactionStatsQueue.front());
+ mTransactionStatsQueue.pop();
+ }
+
+ void verifyFinalState() {
+ // Wait to see if there are extra callbacks
+ std::this_thread::sleep_for(500ms);
+
+ std::lock_guard lock(mMutex);
+ EXPECT_EQ(mTransactionStatsQueue.size(), 0) << "extra callbacks received";
+ mTransactionStatsQueue = {};
+ }
+
+ void* getContext() { return static_cast<void*>(this); }
+
+ std::mutex mMutex;
+ std::condition_variable mConditionVariable;
+ std::queue<TransactionStats> mTransactionStatsQueue;
+};
+
+class LayerCallbackTest : public LayerTransactionTest {
+protected:
+ virtual sp<SurfaceControl> createBufferStateLayer() {
+ return createLayer(mClient, "test", mWidth, mHeight,
+ ISurfaceComposerClient::eFXSurfaceBufferState);
+ }
+
+ virtual void fillTransaction(Transaction& transaction, CallbackHelper* callbackHelper,
+ const sp<SurfaceControl>& layer = nullptr) {
+ if (layer) {
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(mWidth, mHeight, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY |
+ BufferUsage::GPU_TEXTURE,
+ "test");
+ fillGraphicBufferColor(buffer, Rect(0, 0, mWidth, mHeight), Color::RED);
+
+ sp<Fence> fence = new Fence(-1);
+
+ transaction.setBuffer(layer, buffer)
+ .setAcquireFence(layer, fence)
+ .setSize(layer, mWidth, mHeight);
+ }
+
+ transaction.addTransactionCompletedCallback(callbackHelper->function,
+ callbackHelper->getContext());
+ }
+
+ void waitForCallback(CallbackHelper& helper, const ExpectedResult& expectedResult,
+ bool finalState = false) {
+ TransactionStats transactionStats;
+ ASSERT_NO_FATAL_FAILURE(helper.getTransactionStats(&transactionStats));
+ EXPECT_NO_FATAL_FAILURE(expectedResult.verifyTransactionStats(transactionStats));
+
+ if (finalState) {
+ ASSERT_NO_FATAL_FAILURE(helper.verifyFinalState());
+ }
+ }
+
+ void waitForCallbacks(CallbackHelper& helper,
+ const std::vector<ExpectedResult>& expectedResults,
+ bool finalState = false) {
+ for (const auto& expectedResult : expectedResults) {
+ waitForCallback(helper, expectedResult);
+ }
+ if (finalState) {
+ ASSERT_NO_FATAL_FAILURE(helper.verifyFinalState());
+ }
+ }
+
+ uint32_t mWidth = 32;
+ uint32_t mHeight = 32;
+};
+
+TEST_F(LayerCallbackTest, Basic) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ fillTransaction(transaction, &callback, layer);
+
+ transaction.apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, NoBuffer) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ fillTransaction(transaction, &callback);
+
+ transaction.setPosition(layer, mWidth, mHeight).apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, NoStateChange) {
+ Transaction transaction;
+ CallbackHelper callback;
+ fillTransaction(transaction, &callback);
+
+ transaction.apply();
+
+ ExpectedResult expected;
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, OffScreen) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ fillTransaction(transaction, &callback, layer);
+
+ transaction.setPosition(layer, -100, -100).apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, Merge) {
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+ ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ fillTransaction(transaction1, &callback1, layer1);
+ fillTransaction(transaction2, &callback2, layer2);
+
+ transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, Merge_SameCallback) {
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+ ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback;
+ fillTransaction(transaction1, &callback, layer1);
+ fillTransaction(transaction2, &callback, layer2);
+
+ transaction2.merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, Merge_SameLayer) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ fillTransaction(transaction1, &callback1, layer);
+ fillTransaction(transaction2, &callback2, layer);
+
+ transaction2.merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, Merge_SingleBuffer) {
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+ ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ fillTransaction(transaction1, &callback1, layer1);
+ fillTransaction(transaction2, &callback2);
+
+ transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, Merge_DifferentClients) {
+ sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
+ client2(new SurfaceComposerClient);
+
+ ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
+ ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
+
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", mWidth, mHeight,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", mWidth, mHeight,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ fillTransaction(transaction1, &callback1, layer1);
+ fillTransaction(transaction2, &callback2, layer2);
+
+ transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ for (size_t i = 0; i < 10; i++) {
+ fillTransaction(transaction, &callback, layer);
+
+ transaction.apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED,
+ (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
+ : ExpectedResult::PreviousBuffer::RELEASED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
+ }
+ ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_NoStateChange) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ for (size_t i = 0; i < 10; i++) {
+ ExpectedResult expected;
+
+ if (i == 0) {
+ fillTransaction(transaction, &callback, layer);
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ } else {
+ fillTransaction(transaction, &callback);
+ }
+
+ transaction.apply();
+
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
+ }
+ ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_SameStateChange) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ for (size_t i = 0; i < 10; i++) {
+ if (i == 0) {
+ fillTransaction(transaction, &callback, layer);
+ } else {
+ fillTransaction(transaction, &callback);
+ }
+
+ transaction.setPosition(layer, mWidth, mHeight).apply();
+
+ ExpectedResult expected;
+ expected.addSurface((i == 0) ? ExpectedResult::Transaction::PRESENTED
+ : ExpectedResult::Transaction::NOT_PRESENTED,
+ layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, i == 0));
+ }
+ ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_Merge) {
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+ ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ for (size_t i = 0; i < 10; i++) {
+ fillTransaction(transaction1, &callback1, layer1);
+ fillTransaction(transaction2, &callback2, layer2);
+
+ transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
+ ExpectedResult::Buffer::NOT_ACQUIRED,
+ (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
+ : ExpectedResult::PreviousBuffer::RELEASED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected));
+ }
+ ASSERT_NO_FATAL_FAILURE(callback1.verifyFinalState());
+ ASSERT_NO_FATAL_FAILURE(callback2.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients) {
+ sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
+ client2(new SurfaceComposerClient);
+ ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
+ ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
+
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", mWidth, mHeight,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", mWidth, mHeight,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ for (size_t i = 0; i < 10; i++) {
+ fillTransaction(transaction1, &callback1, layer1);
+ fillTransaction(transaction2, &callback2, layer2);
+
+ transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
+ ExpectedResult::Buffer::NOT_ACQUIRED,
+ (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
+ : ExpectedResult::PreviousBuffer::RELEASED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected));
+ }
+ ASSERT_NO_FATAL_FAILURE(callback1.verifyFinalState());
+ ASSERT_NO_FATAL_FAILURE(callback2.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_NoStateChange) {
+ sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
+ client2(new SurfaceComposerClient);
+ ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
+ ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
+
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", mWidth, mHeight,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", mWidth, mHeight,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+
+ // Normal call to set up test
+ fillTransaction(transaction1, &callback1, layer1);
+ fillTransaction(transaction2, &callback2, layer2);
+
+ transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+ expected.reset();
+
+ // Test
+ fillTransaction(transaction1, &callback1);
+ fillTransaction(transaction2, &callback2);
+
+ transaction2.merge(std::move(transaction1)).apply();
+
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_SameStateChange) {
+ sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
+ client2(new SurfaceComposerClient);
+
+ ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
+ ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
+
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", mWidth, mHeight,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", mWidth, mHeight,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+
+ // Normal call to set up test
+ fillTransaction(transaction1, &callback1, layer1);
+ fillTransaction(transaction2, &callback2, layer2);
+
+ transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+ expected.reset();
+
+ // Test
+ fillTransaction(transaction1, &callback1);
+ fillTransaction(transaction2, &callback2);
+
+ transaction2.setPosition(layer2, mWidth, mHeight).merge(std::move(transaction1)).apply();
+
+ expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer2);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ std::vector<ExpectedResult> expectedResults(50);
+ ExpectedResult::PreviousBuffer previousBufferResult =
+ ExpectedResult::PreviousBuffer::NOT_RELEASED;
+ for (auto& expected : expectedResults) {
+ expected.reset();
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED, previousBufferResult);
+ previousBufferResult = ExpectedResult::PreviousBuffer::RELEASED;
+
+ fillTransaction(transaction, &callback, layer);
+
+ transaction.apply();
+ std::this_thread::sleep_for(200ms);
+ }
+ EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_NoStateChange) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ std::vector<ExpectedResult> expectedResults(50);
+ bool first = true;
+ for (auto& expected : expectedResults) {
+ expected.reset();
+
+ if (first) {
+ fillTransaction(transaction, &callback, layer);
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ first = false;
+ } else {
+ fillTransaction(transaction, &callback);
+ }
+
+ transaction.apply();
+ std::this_thread::sleep_for(200ms);
+ }
+ EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_SameStateChange) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ // Normal call to set up test
+ Transaction transaction;
+ CallbackHelper callback;
+ fillTransaction(transaction, &callback, layer);
+
+ transaction.setPosition(layer, mWidth, mHeight).apply();
+
+ ExpectedResult expectedResult;
+ expectedResult.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expectedResult, true));
+
+ // Test
+ std::vector<ExpectedResult> expectedResults(50);
+ for (auto& expected : expectedResults) {
+ expected.reset();
+ expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer);
+
+ fillTransaction(transaction, &callback);
+
+ transaction.setPosition(layer, mWidth, mHeight).apply();
+
+ std::this_thread::sleep_for(200ms);
+ }
+ EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
+}
+
class LayerUpdateTest : public LayerTransactionTest {
protected:
virtual void SetUp() {
@@ -2394,17 +3030,19 @@
mClient->createSurface(String8("Buffered child"), 20, 20,
PIXEL_FORMAT_RGBA_8888, 0, childNoBuffer.get());
fillSurfaceRGBA8(childBuffer, 200, 200, 200);
-
- SurfaceComposerClient::Transaction{}.show(childNoBuffer).show(childBuffer).apply(true);
-
+ SurfaceComposerClient::Transaction{}
+ .setCrop_legacy(childNoBuffer, Rect(0, 0, 10, 10))
+ .show(childNoBuffer)
+ .show(childBuffer)
+ .apply(true);
{
ScreenCapture::captureScreen(&sc);
sc->expectChildColor(73, 73);
sc->expectFGColor(74, 74);
}
-
- SurfaceComposerClient::Transaction{}.setSize(childNoBuffer, 20, 20).apply(true);
-
+ SurfaceComposerClient::Transaction{}
+ .setCrop_legacy(childNoBuffer, Rect(0, 0, 20, 20))
+ .apply(true);
{
ScreenCapture::captureScreen(&sc);
sc->expectChildColor(73, 73);
@@ -2939,6 +3577,221 @@
mCapture->checkPixel(10, 10, 255, 255, 255);
}
}
+class BoundlessLayerTest : public LayerUpdateTest {
+protected:
+ std::unique_ptr<ScreenCapture> mCapture;
+};
+
+// Verify setting a size on a buffer layer has no effect.
+TEST_F(BoundlessLayerTest, BufferLayerIgnoresSize) {
+ sp<SurfaceControl> bufferLayer =
+ mClient->createSurface(String8("BufferLayer"), 45, 45, PIXEL_FORMAT_RGBA_8888, 0,
+ mFGSurfaceControl.get());
+ ASSERT_TRUE(bufferLayer != nullptr);
+ ASSERT_TRUE(bufferLayer->isValid());
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::BLACK, 30, 30));
+ asTransaction([&](Transaction& t) { t.show(bufferLayer); });
+ {
+ mCapture = screenshot();
+ // Top left of background must now be visible
+ mCapture->expectBGColor(0, 0);
+ // Foreground Surface bounds must be color layer
+ mCapture->expectColor(Rect(64, 64, 94, 94), Color::BLACK);
+ // Buffer layer should not extend past buffer bounds
+ mCapture->expectFGColor(95, 95);
+ }
+}
+
+// Verify a boundless color layer will fill its parent bounds. The parent has a buffer size
+// which will crop the color layer.
+TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentBufferBounds) {
+ sp<SurfaceControl> colorLayer =
+ mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor,
+ mFGSurfaceControl.get());
+ ASSERT_TRUE(colorLayer != nullptr);
+ ASSERT_TRUE(colorLayer->isValid());
+ asTransaction([&](Transaction& t) {
+ t.setColor(colorLayer, half3{0, 0, 0});
+ t.show(colorLayer);
+ });
+ {
+ mCapture = screenshot();
+ // Top left of background must now be visible
+ mCapture->expectBGColor(0, 0);
+ // Foreground Surface bounds must be color layer
+ mCapture->expectColor(Rect(64, 64, 128, 128), Color::BLACK);
+ // Color layer should not extend past foreground bounds
+ mCapture->expectBGColor(129, 129);
+ }
+}
+
+// Verify a boundless color layer will fill its parent bounds. The parent has no buffer but has
+// a crop which will be used to crop the color layer.
+TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentCropBounds) {
+ sp<SurfaceControl> cropLayer =
+ mClient->createSurface(String8("CropLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ 0 /* flags */, mFGSurfaceControl.get());
+ ASSERT_TRUE(cropLayer != nullptr);
+ ASSERT_TRUE(cropLayer->isValid());
+ sp<SurfaceControl> colorLayer =
+ mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor, cropLayer.get());
+ ASSERT_TRUE(colorLayer != nullptr);
+ ASSERT_TRUE(colorLayer->isValid());
+ asTransaction([&](Transaction& t) {
+ t.setCrop_legacy(cropLayer, Rect(5, 5, 10, 10));
+ t.setColor(colorLayer, half3{0, 0, 0});
+ t.show(cropLayer);
+ t.show(colorLayer);
+ });
+ {
+ mCapture = screenshot();
+ // Top left of background must now be visible
+ mCapture->expectBGColor(0, 0);
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // 5 pixels from the foreground we should see the child surface
+ mCapture->expectColor(Rect(69, 69, 74, 74), Color::BLACK);
+ // 10 pixels from the foreground we should be back to the foreground surface
+ mCapture->expectFGColor(74, 74);
+ }
+}
+
+// Verify for boundless layer with no children, their transforms have no effect.
+TEST_F(BoundlessLayerTest, BoundlessColorLayerTransformHasNoEffect) {
+ sp<SurfaceControl> colorLayer =
+ mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor,
+ mFGSurfaceControl.get());
+ ASSERT_TRUE(colorLayer != nullptr);
+ ASSERT_TRUE(colorLayer->isValid());
+ asTransaction([&](Transaction& t) {
+ t.setPosition(colorLayer, 320, 320);
+ t.setMatrix(colorLayer, 2, 0, 0, 2);
+ t.setColor(colorLayer, half3{0, 0, 0});
+ t.show(colorLayer);
+ });
+ {
+ mCapture = screenshot();
+ // Top left of background must now be visible
+ mCapture->expectBGColor(0, 0);
+ // Foreground Surface bounds must be color layer
+ mCapture->expectColor(Rect(64, 64, 128, 128), Color::BLACK);
+ // Color layer should not extend past foreground bounds
+ mCapture->expectBGColor(129, 129);
+ }
+}
+
+// Verify for boundless layer with children, their transforms have an effect.
+TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerCanSetTransform) {
+ sp<SurfaceControl> boundlessLayerRightShift =
+ mClient->createSurface(String8("BoundlessLayerRightShift"), 0, 0,
+ PIXEL_FORMAT_RGBA_8888, 0 /* flags */, mFGSurfaceControl.get());
+ ASSERT_TRUE(boundlessLayerRightShift != nullptr);
+ ASSERT_TRUE(boundlessLayerRightShift->isValid());
+ sp<SurfaceControl> boundlessLayerDownShift =
+ mClient->createSurface(String8("BoundlessLayerLeftShift"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ 0 /* flags */, boundlessLayerRightShift.get());
+ ASSERT_TRUE(boundlessLayerDownShift != nullptr);
+ ASSERT_TRUE(boundlessLayerDownShift->isValid());
+ sp<SurfaceControl> colorLayer =
+ mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor,
+ boundlessLayerDownShift.get());
+ ASSERT_TRUE(colorLayer != nullptr);
+ ASSERT_TRUE(colorLayer->isValid());
+ asTransaction([&](Transaction& t) {
+ t.setPosition(boundlessLayerRightShift, 32, 0);
+ t.show(boundlessLayerRightShift);
+ t.setPosition(boundlessLayerDownShift, 0, 32);
+ t.show(boundlessLayerDownShift);
+ t.setCrop_legacy(colorLayer, Rect(0, 0, 64, 64));
+ t.setColor(colorLayer, half3{0, 0, 0});
+ t.show(colorLayer);
+ });
+ {
+ mCapture = screenshot();
+ // Top left of background must now be visible
+ mCapture->expectBGColor(0, 0);
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // Foreground Surface bounds must be color layer
+ mCapture->expectColor(Rect(96, 96, 128, 128), Color::BLACK);
+ // Color layer should not extend past foreground bounds
+ mCapture->expectBGColor(129, 129);
+ }
+}
+
+// Verify child layers do not get clipped if they temporarily move into the negative
+// coordinate space as the result of an intermediate transformation.
+TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerDoNotCrop) {
+ sp<SurfaceControl> boundlessLayer =
+ mClient->createSurface(String8("BoundlessLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ 0 /* flags */, mFGSurfaceControl.get());
+ ASSERT_TRUE(boundlessLayer != nullptr);
+ ASSERT_TRUE(boundlessLayer->isValid());
+ sp<SurfaceControl> colorLayer =
+ mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor, boundlessLayer.get());
+ ASSERT_TRUE(colorLayer != nullptr);
+ ASSERT_TRUE(colorLayer->isValid());
+ asTransaction([&](Transaction& t) {
+ // shift child layer off bounds. If this layer was not boundless, we will
+ // expect the child layer to be cropped.
+ t.setPosition(boundlessLayer, 32, 32);
+ t.show(boundlessLayer);
+ t.setCrop_legacy(colorLayer, Rect(0, 0, 64, 64));
+ // undo shift by parent
+ t.setPosition(colorLayer, -32, -32);
+ t.setColor(colorLayer, half3{0, 0, 0});
+ t.show(colorLayer);
+ });
+ {
+ mCapture = screenshot();
+ // Top left of background must now be visible
+ mCapture->expectBGColor(0, 0);
+ // Foreground Surface bounds must be color layer
+ mCapture->expectColor(Rect(64, 64, 128, 128), Color::BLACK);
+ // Color layer should not extend past foreground bounds
+ mCapture->expectBGColor(129, 129);
+ }
+}
+
+// Verify for boundless root layers with children, their transforms have an effect.
+TEST_F(BoundlessLayerTest, RootBoundlessLayerCanSetTransform) {
+ sp<SurfaceControl> rootBoundlessLayer =
+ mClient->createSurface(String8("RootBoundlessLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ 0 /* flags */);
+ ASSERT_TRUE(rootBoundlessLayer != nullptr);
+ ASSERT_TRUE(rootBoundlessLayer->isValid());
+ sp<SurfaceControl> colorLayer =
+ mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor,
+ rootBoundlessLayer.get());
+ ASSERT_TRUE(colorLayer != nullptr);
+ ASSERT_TRUE(colorLayer->isValid());
+ asTransaction([&](Transaction& t) {
+ t.setLayer(rootBoundlessLayer, INT32_MAX - 1);
+ t.setPosition(rootBoundlessLayer, 32, 32);
+ t.show(rootBoundlessLayer);
+ t.setCrop_legacy(colorLayer, Rect(0, 0, 64, 64));
+ t.setColor(colorLayer, half3{0, 0, 0});
+ t.show(colorLayer);
+ t.hide(mFGSurfaceControl);
+ });
+ {
+ mCapture = screenshot();
+ // Top left of background must now be visible
+ mCapture->expectBGColor(0, 0);
+ // Top left of foreground must now be visible
+ mCapture->expectBGColor(31, 31);
+ // Foreground Surface bounds must be color layer
+ mCapture->expectColor(Rect(32, 32, 96, 96), Color::BLACK);
+ // Color layer should not extend past foreground bounds
+ mCapture->expectBGColor(97, 97);
+ }
+}
class ScreenCaptureTest : public LayerUpdateTest {
protected:
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 1352df5..ab1b252 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -37,6 +37,7 @@
#include "mock/MockEventThread.h"
#include "mock/MockMessageQueue.h"
#include "mock/RenderEngine/MockRenderEngine.h"
+#include "mock/system/window/MockNativeWindow.h"
namespace android {
namespace {
@@ -65,6 +66,7 @@
constexpr hwc2_layer_t HWC_LAYER = 5000;
constexpr Transform DEFAULT_TRANSFORM = static_cast<Transform>(0);
+constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{42};
constexpr int DEFAULT_DISPLAY_WIDTH = 1920;
constexpr int DEFAULT_DISPLAY_HEIGHT = 1024;
@@ -138,6 +140,7 @@
sp<DisplayDevice> mExternalDisplay;
sp<mock::DisplaySurface> mDisplaySurface = new mock::DisplaySurface();
renderengine::mock::Surface* mRenderSurface = new renderengine::mock::Surface();
+ mock::NativeWindow* mNativeWindow = new mock::NativeWindow();
mock::EventThread* mEventThread = new mock::EventThread();
mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
@@ -226,16 +229,22 @@
static constexpr int INIT_POWER_MODE = HWC_POWER_MODE_NORMAL;
static void setupPreconditions(CompositionTest* test) {
- FakeHwcDisplayInjector(DisplayDevice::DISPLAY_PRIMARY, HWC2::DisplayType::Physical)
+ EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_WIDTH), Return(0)));
+ EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_HEIGHT), Return(0)));
+
+ FakeHwcDisplayInjector(DEFAULT_DISPLAY_ID, HWC2::DisplayType::Physical,
+ true /* isPrimary */)
.setCapabilities(&test->mDefaultCapabilities)
.inject(&test->mFlinger, test->mComposer);
- test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, DisplayDevice::DISPLAY_PRIMARY,
- DisplayDevice::DISPLAY_PRIMARY)
- .setDisplaySize(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT)
+ test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, DEFAULT_DISPLAY_ID,
+ false /* isVirtual */, true /* isPrimary */)
.setDisplaySurface(test->mDisplaySurface)
.setRenderSurface(std::unique_ptr<renderengine::Surface>(
test->mRenderSurface))
+ .setNativeWindow(test->mNativeWindow)
.setSecure(Derived::IS_SECURE)
.setPowerMode(Derived::INIT_POWER_MODE)
.inject();
@@ -553,10 +562,6 @@
IComposerClient::Color({0xff, 0xff, 0xff, 0xff})))
.Times(1);
- // TODO: ColorLayer::onPreComposition() always returns true, triggering an
- // extra layer update in SurfaceFlinger::preComposition(). This seems
- // wrong on the surface.
- EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1);
}
static void setupHwcSetPerFrameBufferCallExpectations(CompositionTest* test) {
@@ -749,7 +754,9 @@
EXPECT_CALL(*test->mComposer, createLayer(HWC_DISPLAY, _))
.WillOnce(DoAll(SetArgPointee<1>(HWC_LAYER), Return(Error::NONE)));
- layer->createHwcLayer(test->mFlinger.mFlinger->getBE().mHwc.get(), test->mDisplay->getId());
+ const auto displayId = test->mDisplay->getId();
+ ASSERT_TRUE(displayId);
+ layer->createHwcLayer(test->mFlinger.mFlinger->getBE().mHwc.get(), *displayId);
Mock::VerifyAndClear(test->mComposer);
@@ -762,8 +769,10 @@
static void cleanupInjectedLayers(CompositionTest* test) {
EXPECT_CALL(*test->mComposer, destroyLayer(HWC_DISPLAY, HWC_LAYER))
.WillOnce(Return(Error::NONE));
+ const auto displayId = test->mDisplay->getId();
+ ASSERT_TRUE(displayId);
for (auto layer : test->mFlinger.mutableDrawingState().layersSortedByZ) {
- layer->destroyHwcLayer(test->mDisplay->getId());
+ layer->destroyHwcLayer(*displayId);
}
test->mFlinger.mutableDrawingState().layersSortedByZ.clear();
}
@@ -781,6 +790,9 @@
LayerProperties::HEIGHT,
LayerProperties::LAYER_FLAGS));
});
+
+ auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer);
+ layerDrawingState.crop_legacy = Rect(0, 0, LayerProperties::HEIGHT, LayerProperties::WIDTH);
return layer;
}
@@ -951,7 +963,7 @@
struct ForcedClientCompositionResultVariant : public RECompositionResultVariant {
static void setupLayerState(CompositionTest*, sp<Layer> layer) {
- layer->forceClientComposition(DisplayDevice::DISPLAY_PRIMARY);
+ layer->forceClientComposition(DEFAULT_DISPLAY_ID);
}
template <typename Case>
diff --git a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
index 4f1c99e..55995d0 100644
--- a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
@@ -68,32 +68,44 @@
} // namespace
+const DisplayIdentificationData& getInternalEdid() {
+ static const DisplayIdentificationData data = asDisplayIdentificationData(kInternalEdid);
+ return data;
+}
+
+const DisplayIdentificationData& getExternalEdid() {
+ static const DisplayIdentificationData data = asDisplayIdentificationData(kExternalEdid);
+ return data;
+}
+
+const DisplayIdentificationData& getExternalEedid() {
+ static const DisplayIdentificationData data = asDisplayIdentificationData(kExternalEedid);
+ return data;
+}
+
TEST(DisplayIdentificationTest, isEdid) {
EXPECT_FALSE(isEdid({}));
- EXPECT_TRUE(isEdid(asDisplayIdentificationData(kInternalEdid)));
- EXPECT_TRUE(isEdid(asDisplayIdentificationData(kExternalEdid)));
- EXPECT_TRUE(isEdid(asDisplayIdentificationData(kExternalEedid)));
+ EXPECT_TRUE(isEdid(getInternalEdid()));
+ EXPECT_TRUE(isEdid(getExternalEdid()));
+ EXPECT_TRUE(isEdid(getExternalEedid()));
}
TEST(DisplayIdentificationTest, parseEdid) {
- auto data = asDisplayIdentificationData(kInternalEdid);
- auto edid = parseEdid(data);
+ auto edid = parseEdid(getInternalEdid());
ASSERT_TRUE(edid);
EXPECT_EQ(0x4ca3u, edid->manufacturerId);
EXPECT_STREQ("SEC", edid->pnpId.data());
// ASCII text should be used as fallback if display name and serial number are missing.
EXPECT_EQ("121AT11-801", edid->displayName);
- data = asDisplayIdentificationData(kExternalEdid);
- edid = parseEdid(data);
+ edid = parseEdid(getExternalEdid());
ASSERT_TRUE(edid);
EXPECT_EQ(0x22f0u, edid->manufacturerId);
EXPECT_STREQ("HWP", edid->pnpId.data());
EXPECT_EQ("HP ZR30w", edid->displayName);
- data = asDisplayIdentificationData(kExternalEedid);
- edid = parseEdid(data);
+ edid = parseEdid(getExternalEedid());
ASSERT_TRUE(edid);
EXPECT_EQ(0x4c2du, edid->manufacturerId);
EXPECT_STREQ("SAM", edid->pnpId.data());
@@ -105,7 +117,7 @@
EXPECT_FALSE(parseEdid({}));
// Display name must be printable.
- auto data = asDisplayIdentificationData(kExternalEdid);
+ auto data = getExternalEdid();
data[97] = '\x1b';
auto edid = parseEdid(data);
ASSERT_TRUE(edid);
@@ -128,20 +140,32 @@
EXPECT_STREQ("SAM", getPnpId(0x4c2du).value_or(PnpId{}).data());
}
-TEST(DisplayIdentificationTest, generateDisplayId) {
- const auto primaryId = generateDisplayId(0, asDisplayIdentificationData(kInternalEdid));
- ASSERT_TRUE(primaryId);
+TEST(DisplayIdentificationTest, parseDisplayIdentificationData) {
+ const auto primaryInfo = parseDisplayIdentificationData(0, getInternalEdid());
+ ASSERT_TRUE(primaryInfo);
- const auto secondaryId = generateDisplayId(1, asDisplayIdentificationData(kExternalEdid));
- ASSERT_TRUE(secondaryId);
+ const auto secondaryInfo = parseDisplayIdentificationData(1, getExternalEdid());
+ ASSERT_TRUE(secondaryInfo);
- const auto tertiaryId = generateDisplayId(2, asDisplayIdentificationData(kExternalEedid));
- ASSERT_TRUE(tertiaryId);
+ const auto tertiaryInfo = parseDisplayIdentificationData(2, getExternalEedid());
+ ASSERT_TRUE(tertiaryInfo);
// Display IDs should be unique.
- EXPECT_NE(primaryId, secondaryId);
- EXPECT_NE(primaryId, tertiaryId);
- EXPECT_NE(secondaryId, tertiaryId);
+ EXPECT_NE(primaryInfo->id, secondaryInfo->id);
+ EXPECT_NE(primaryInfo->id, tertiaryInfo->id);
+ EXPECT_NE(secondaryInfo->id, tertiaryInfo->id);
+}
+
+TEST(DisplayIdentificationTest, getFallbackDisplayId) {
+ // Manufacturer ID should be invalid.
+ ASSERT_FALSE(getPnpId(getFallbackDisplayId(0)));
+ ASSERT_FALSE(getPnpId(getFallbackDisplayId(0xffu)));
+}
+
+TEST(DisplayIdentificationTest, getVirtualDisplayId) {
+ // Manufacturer ID should be invalid.
+ ASSERT_FALSE(getPnpId(getVirtualDisplayId(0)));
+ ASSERT_FALSE(getPnpId(getVirtualDisplayId(0xffff'ffffu)));
}
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.h b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.h
new file mode 100644
index 0000000..1c8e5cc
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "DisplayHardware/DisplayIdentification.h"
+
+namespace android {
+
+const DisplayIdentificationData& getInternalEdid();
+const DisplayIdentificationData& getExternalEdid();
+const DisplayIdentificationData& getExternalEedid();
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index d32627a..32fce67 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -17,12 +17,16 @@
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
+#include <type_traits>
+
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <log/log.h>
#include <ui/DebugUtils.h>
+
+#include "DisplayIdentificationTest.h"
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
#include "mock/DisplayHardware/MockDisplaySurface.h"
@@ -75,9 +79,11 @@
#define BOOL_SUBSTITUTE(TYPENAME) enum class TYPENAME : bool { FALSE = false, TRUE = true };
-BOOL_SUBSTITUTE(Critical);
BOOL_SUBSTITUTE(Async);
+BOOL_SUBSTITUTE(Critical);
+BOOL_SUBSTITUTE(Primary);
BOOL_SUBSTITUTE(Secure);
+BOOL_SUBSTITUTE(Virtual);
/* ------------------------------------------------------------------------
*
@@ -98,7 +104,7 @@
// --------------------------------------------------------------------
// Postcondition helpers
- bool hasHwcDisplay(hwc2_display_t displayId);
+ bool hasPhysicalHwcDisplay(hwc2_display_t hwcDisplayId);
bool hasTransactionFlagSet(int flag);
bool hasDisplayDevice(sp<IBinder> displayToken);
sp<DisplayDevice> getDisplayDevice(sp<IBinder> displayToken);
@@ -113,6 +119,7 @@
TestableSurfaceFlinger mFlinger;
mock::EventThread* mEventThread = new mock::EventThread();
mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
+ sp<mock::NativeWindow> mNativeWindow = new mock::NativeWindow();
// These mocks are created by the test, but are destroyed by SurfaceFlinger
// by virtue of being stored into a std::unique_ptr. However we still need
@@ -127,7 +134,6 @@
sp<mock::GraphicBufferConsumer> mConsumer;
sp<mock::GraphicBufferProducer> mProducer;
surfaceflinger::mock::NativeWindowSurface* mNativeWindowSurface = nullptr;
- sp<mock::NativeWindow> mNativeWindow;
renderengine::mock::Surface* mRenderSurface = nullptr;
};
@@ -197,15 +203,14 @@
ASSERT_TRUE(mNativeWindowSurface == nullptr);
mNativeWindowSurface = new surfaceflinger::mock::NativeWindowSurface();
- mNativeWindow = new mock::NativeWindow();
mFlinger.setCreateNativeWindowSurface([this](auto) {
return std::unique_ptr<surfaceflinger::NativeWindowSurface>(mNativeWindowSurface);
});
}
-bool DisplayTransactionTest::hasHwcDisplay(hwc2_display_t displayId) {
- return mFlinger.mutableHwcDisplaySlots().count(displayId) == 1;
+bool DisplayTransactionTest::hasPhysicalHwcDisplay(hwc2_display_t hwcDisplayId) {
+ return mFlinger.mutableHwcPhysicalDisplayIdMap().count(hwcDisplayId) == 1;
}
bool DisplayTransactionTest::hasTransactionFlagSet(int flag) {
@@ -240,20 +245,67 @@
*
*/
-template <DisplayDevice::DisplayType type, DisplayDevice::DisplayType displayId, int width,
- int height, Critical critical, Async async, Secure secure, int grallocUsage>
+template <typename PhysicalDisplay>
+struct PhysicalDisplayId {};
+
+template <DisplayId::Type displayId>
+using VirtualDisplayId = std::integral_constant<DisplayId::Type, displayId>;
+
+struct NoDisplayId {};
+
+template <typename>
+struct IsPhysicalDisplayId : std::bool_constant<false> {};
+
+template <typename PhysicalDisplay>
+struct IsPhysicalDisplayId<PhysicalDisplayId<PhysicalDisplay>> : std::bool_constant<true> {};
+
+template <typename>
+struct DisplayIdGetter;
+
+template <typename PhysicalDisplay>
+struct DisplayIdGetter<PhysicalDisplayId<PhysicalDisplay>> {
+ static std::optional<DisplayId> get() {
+ if (!PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
+ return getFallbackDisplayId(static_cast<bool>(PhysicalDisplay::PRIMARY)
+ ? HWC_DISPLAY_PRIMARY
+ : HWC_DISPLAY_EXTERNAL);
+ }
+
+ const auto info =
+ parseDisplayIdentificationData(PhysicalDisplay::PORT,
+ PhysicalDisplay::GET_IDENTIFICATION_DATA());
+ return info ? std::make_optional(info->id) : std::nullopt;
+ }
+};
+
+template <DisplayId::Type displayId>
+struct DisplayIdGetter<VirtualDisplayId<displayId>> {
+ static std::optional<DisplayId> get() { return DisplayId{displayId}; }
+};
+
+template <>
+struct DisplayIdGetter<NoDisplayId> {
+ static std::optional<DisplayId> get() { return {}; }
+};
+
+// DisplayIdType can be:
+// 1) PhysicalDisplayId<...> for generated ID of physical display backed by HWC.
+// 2) VirtualDisplayId<...> for hard-coded ID of virtual display backed by HWC.
+// 3) NoDisplayId for virtual display without HWC backing.
+template <typename DisplayIdType, int width, int height, Critical critical, Async async,
+ Secure secure, Primary primary, int grallocUsage>
struct DisplayVariant {
+ using DISPLAY_ID = DisplayIdGetter<DisplayIdType>;
+
// The display width and height
static constexpr int WIDTH = width;
static constexpr int HEIGHT = height;
static constexpr int GRALLOC_USAGE = grallocUsage;
- // The type for this display
- static constexpr DisplayDevice::DisplayType TYPE = type;
- static_assert(TYPE != DisplayDevice::DISPLAY_ID_INVALID);
-
- static constexpr DisplayDevice::DisplayType DISPLAY_ID = displayId;
+ // Whether the display is virtual or physical
+ static constexpr Virtual VIRTUAL =
+ IsPhysicalDisplayId<DisplayIdType>{} ? Virtual::FALSE : Virtual::TRUE;
// When creating native window surfaces for the framebuffer, whether those should be critical
static constexpr Critical CRITICAL = critical;
@@ -264,9 +316,23 @@
// Whether the display should be treated as secure
static constexpr Secure SECURE = secure;
+ // Whether the display is primary
+ static constexpr Primary PRIMARY = primary;
+
static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) {
- auto injector = FakeDisplayDeviceInjector(test->mFlinger, TYPE, DISPLAY_ID);
+ auto injector =
+ FakeDisplayDeviceInjector(test->mFlinger, DISPLAY_ID::get(),
+ static_cast<bool>(VIRTUAL), static_cast<bool>(PRIMARY));
+
injector.setSecure(static_cast<bool>(SECURE));
+ injector.setNativeWindow(test->mNativeWindow);
+
+ // Creating a DisplayDevice requires getting default dimensions from the
+ // native window.
+ EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(WIDTH), Return(0)));
+ EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(HEIGHT), Return(0)));
return injector;
}
@@ -283,11 +349,17 @@
EXPECT_CALL(*test->mRenderEngine, createSurface())
.WillOnce(Return(ByMove(
std::unique_ptr<renderengine::Surface>(test->mRenderSurface))));
+
+ // Creating a DisplayDevice requires getting default dimensions from the
+ // native window.
+ EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(WIDTH), Return(0)));
+ EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(HEIGHT), Return(0)));
+
EXPECT_CALL(*test->mRenderSurface, setAsync(static_cast<bool>(ASYNC))).Times(1);
EXPECT_CALL(*test->mRenderSurface, setCritical(static_cast<bool>(CRITICAL))).Times(1);
EXPECT_CALL(*test->mRenderSurface, setNativeWindow(test->mNativeWindow.get())).Times(1);
- EXPECT_CALL(*test->mRenderSurface, getWidth()).WillOnce(Return(WIDTH));
- EXPECT_CALL(*test->mRenderSurface, getHeight()).WillOnce(Return(HEIGHT));
}
static void setupFramebufferConsumerBufferQueueCallExpectations(DisplayTransactionTest* test) {
@@ -306,7 +378,8 @@
}
};
-template <hwc2_display_t hwcDisplayId, HWC2::DisplayType hwcDisplayType, typename DisplayVariant>
+template <hwc2_display_t hwcDisplayId, HWC2::DisplayType hwcDisplayType, typename DisplayVariant,
+ typename PhysicalDisplay = void>
struct HwcDisplayVariant {
// The display id supplied by the HWC
static constexpr hwc2_display_t HWC_DISPLAY_ID = hwcDisplayId;
@@ -325,7 +398,10 @@
// Called by tests to inject a HWC display setup
static void injectHwcDisplay(DisplayTransactionTest* test) {
- FakeHwcDisplayInjector(DisplayVariant::TYPE, HWC_DISPLAY_TYPE)
+ const auto displayId = DisplayVariant::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ FakeHwcDisplayInjector(*displayId, HWC_DISPLAY_TYPE,
+ static_cast<bool>(DisplayVariant::PRIMARY))
.setHwcDisplayId(HWC_DISPLAY_ID)
.setWidth(DisplayVariant::WIDTH)
.setHeight(DisplayVariant::HEIGHT)
@@ -362,8 +438,16 @@
getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
IComposerClient::Attribute::DPI_Y, _))
.WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
- EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
- .WillRepeatedly(Return(Error::UNSUPPORTED));
+
+ if (PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
+ EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
+ .WillOnce(DoAll(SetArgPointee<1>(PhysicalDisplay::PORT),
+ SetArgPointee<2>(PhysicalDisplay::GET_IDENTIFICATION_DATA()),
+ Return(Error::NONE)));
+ } else {
+ EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
+ .WillOnce(Return(Error::UNSUPPORTED));
+ }
}
// Called by tests to set up HWC call expectations
@@ -373,50 +457,67 @@
}
};
-struct NonHwcDisplayVariant {
- static void injectHwcDisplay(DisplayTransactionTest*) {}
-
- static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, getActiveConfig(_, _)).Times(0);
- }
-};
-
// Physical displays are expected to be synchronous, secure, and have a HWC display for output.
constexpr uint32_t GRALLOC_USAGE_PHYSICAL_DISPLAY =
GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_FB;
-template <hwc2_display_t hwcDisplayId, DisplayDevice::DisplayType type, int width, int height,
+template <hwc2_display_t hwcDisplayId, typename PhysicalDisplay, int width, int height,
Critical critical>
struct PhysicalDisplayVariant
- : public DisplayVariant<type, type, width, height, critical, Async::FALSE, Secure::TRUE,
- GRALLOC_USAGE_PHYSICAL_DISPLAY>,
- public HwcDisplayVariant<hwcDisplayId, HWC2::DisplayType::Physical,
- DisplayVariant<type, type, width, height, critical, Async::FALSE,
- Secure::TRUE, GRALLOC_USAGE_PHYSICAL_DISPLAY>> {};
+ : DisplayVariant<PhysicalDisplayId<PhysicalDisplay>, width, height, critical, Async::FALSE,
+ Secure::TRUE, PhysicalDisplay::PRIMARY, GRALLOC_USAGE_PHYSICAL_DISPLAY>,
+ HwcDisplayVariant<hwcDisplayId, HWC2::DisplayType::Physical,
+ DisplayVariant<PhysicalDisplayId<PhysicalDisplay>, width, height,
+ critical, Async::FALSE, Secure::TRUE,
+ PhysicalDisplay::PRIMARY, GRALLOC_USAGE_PHYSICAL_DISPLAY>,
+ PhysicalDisplay> {};
+
+template <bool hasIdentificationData>
+struct PrimaryDisplay {
+ static constexpr Primary PRIMARY = Primary::TRUE;
+ static constexpr uint8_t PORT = 255;
+ static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData;
+ static constexpr auto GET_IDENTIFICATION_DATA = getInternalEdid;
+};
+
+template <bool hasIdentificationData>
+struct ExternalDisplay {
+ static constexpr Primary PRIMARY = Primary::FALSE;
+ static constexpr uint8_t PORT = 254;
+ static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData;
+ static constexpr auto GET_IDENTIFICATION_DATA = getExternalEdid;
+};
+
+struct TertiaryDisplay {
+ static constexpr Primary PRIMARY = Primary::FALSE;
+};
// A primary display is a physical display that is critical
using PrimaryDisplayVariant =
- PhysicalDisplayVariant<1001, DisplayDevice::DISPLAY_PRIMARY, 3840, 2160, Critical::TRUE>;
+ PhysicalDisplayVariant<1001, PrimaryDisplay<false>, 3840, 2160, Critical::TRUE>;
// An external display is physical display that is not critical.
using ExternalDisplayVariant =
- PhysicalDisplayVariant<1002, DisplayDevice::DISPLAY_EXTERNAL, 1920, 1280, Critical::FALSE>;
+ PhysicalDisplayVariant<1002, ExternalDisplay<false>, 1920, 1280, Critical::FALSE>;
using TertiaryDisplayVariant =
- PhysicalDisplayVariant<1003, DisplayDevice::DISPLAY_EXTERNAL, 1600, 1200, Critical::FALSE>;
+ PhysicalDisplayVariant<1003, TertiaryDisplay, 1600, 1200, Critical::FALSE>;
// A virtual display not supported by the HWC.
constexpr uint32_t GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY = 0;
template <int width, int height, Secure secure>
struct NonHwcVirtualDisplayVariant
- : public DisplayVariant<DisplayDevice::DISPLAY_VIRTUAL, DisplayDevice::DISPLAY_ID_INVALID,
- width, height, Critical::FALSE, Async::TRUE, secure,
- GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY>,
- public NonHwcDisplayVariant {
- using Base = DisplayVariant<DisplayDevice::DISPLAY_VIRTUAL, DisplayDevice::DISPLAY_ID_INVALID,
- width, height, Critical::FALSE, Async::TRUE, secure,
- GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY>;
+ : DisplayVariant<NoDisplayId, width, height, Critical::FALSE, Async::TRUE, secure,
+ Primary::FALSE, GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY> {
+ using Base = DisplayVariant<NoDisplayId, width, height, Critical::FALSE, Async::TRUE, secure,
+ Primary::FALSE, GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY>;
+
+ static void injectHwcDisplay(DisplayTransactionTest*) {}
+
+ static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) {
+ EXPECT_CALL(*test->mComposer, getActiveConfig(_, _)).Times(0);
+ }
static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
Base::setupNativeWindowSurfaceCreationCallExpectations(test);
@@ -429,14 +530,14 @@
template <int width, int height, Secure secure>
struct HwcVirtualDisplayVariant
- : public DisplayVariant<DisplayDevice::DISPLAY_VIRTUAL, DisplayDevice::DISPLAY_VIRTUAL, width,
- height, Critical::FALSE, Async::TRUE, secure,
- GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>,
- public HwcDisplayVariant<1010, HWC2::DisplayType::Virtual,
- NonHwcVirtualDisplayVariant<width, height, secure>> {
- using Base =
- DisplayVariant<DisplayDevice::DISPLAY_VIRTUAL, DisplayDevice::DISPLAY_VIRTUAL, width,
- height, Critical::FALSE, Async::TRUE, secure, GRALLOC_USAGE_HW_COMPOSER>;
+ : DisplayVariant<VirtualDisplayId<42>, width, height, Critical::FALSE, Async::TRUE, secure,
+ Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>,
+ HwcDisplayVariant<
+ 1010, HWC2::DisplayType::Virtual,
+ DisplayVariant<VirtualDisplayId<42>, width, height, Critical::FALSE, Async::TRUE,
+ secure, Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>> {
+ using Base = DisplayVariant<VirtualDisplayId<42>, width, height, Critical::FALSE, Async::TRUE,
+ secure, Primary::FALSE, GRALLOC_USAGE_HW_COMPOSER>;
using Self = HwcVirtualDisplayVariant<width, height, secure>;
static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
@@ -850,8 +951,8 @@
// The display should have been added to the current state
ASSERT_TRUE(hasCurrentDisplayState(displayToken));
const auto& display = getCurrentDisplayState(displayToken);
- EXPECT_EQ(DisplayDevice::DISPLAY_VIRTUAL, display.type);
- EXPECT_EQ(false, display.isSecure);
+ EXPECT_TRUE(display.isVirtual());
+ EXPECT_FALSE(display.isSecure);
EXPECT_EQ(name.string(), display.displayName);
// --------------------------------------------------------------------
@@ -881,8 +982,8 @@
// The display should have been added to the current state
ASSERT_TRUE(hasCurrentDisplayState(displayToken));
const auto& display = getCurrentDisplayState(displayToken);
- EXPECT_EQ(DisplayDevice::DISPLAY_VIRTUAL, display.type);
- EXPECT_EQ(true, display.isSecure);
+ EXPECT_TRUE(display.isVirtual());
+ EXPECT_TRUE(display.isSecure);
EXPECT_EQ(name.string(), display.displayName);
// --------------------------------------------------------------------
@@ -1002,9 +1103,12 @@
*/
class GetBestColorModeTest : public DisplayTransactionTest {
public:
+ static constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{777};
+
GetBestColorModeTest()
: DisplayTransactionTest(),
- mInjector(FakeDisplayDeviceInjector(mFlinger, DisplayDevice::DISPLAY_PRIMARY, 0)) {}
+ mInjector(FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID, false /* isVirtual */,
+ true /* isPrimary */)) {}
void setHasWideColorGamut(bool hasWideColorGamut) { mHasWideColorGamut = hasWideColorGamut; }
@@ -1020,6 +1124,14 @@
void getBestColorMode() {
mInjector.setHwcColorModes(mHwcColorModes);
mInjector.setHasWideColorGamut(mHasWideColorGamut);
+ mInjector.setNativeWindow(mNativeWindow);
+
+ // Creating a DisplayDevice requires getting default dimensions from the
+ // native window.
+ EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(1080 /* arbitrary */), Return(0)));
+ EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(1920 /* arbitrary */), Return(0)));
auto displayDevice = mInjector.inject();
displayDevice->getBestColorMode(mInputDataspace, mInputRenderIntent, &mOutDataspace,
@@ -1127,18 +1239,22 @@
// Invocation
DisplayDeviceState state;
- state.type = Case::Display::TYPE;
+ state.displayId = static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
+ : Case::Display::DISPLAY_ID::get();
state.isSecure = static_cast<bool>(Case::Display::SECURE);
- auto device = mFlinger.setupNewDisplayDeviceInternal(displayToken, Case::Display::TYPE, state,
- displaySurface, producer);
+ auto device =
+ mFlinger.setupNewDisplayDeviceInternal(displayToken, Case::Display::DISPLAY_ID::get(),
+ state, displaySurface, producer);
// --------------------------------------------------------------------
// Postconditions
ASSERT_TRUE(device != nullptr);
- EXPECT_EQ(Case::Display::TYPE, device->getDisplayType());
+ EXPECT_EQ(Case::Display::DISPLAY_ID::get(), device->getId());
+ EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), device->isVirtual());
EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
+ EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary());
EXPECT_EQ(Case::Display::WIDTH, device->getWidth());
EXPECT_EQ(Case::Display::HEIGHT, device->getHeight());
EXPECT_EQ(Case::WideColorSupport::WIDE_COLOR_SUPPORTED, device->hasWideColorGamut());
@@ -1166,11 +1282,14 @@
}
TEST_F(SetupNewDisplayDeviceInternalTest, createHwcVirtualDisplay) {
- // We need to resize this so that the HWC thinks the virtual display
- // is something it created.
- mFlinger.mutableHwcDisplayData().resize(3);
+ using Case = HwcVirtualDisplayCase;
- setupNewDisplayDeviceInternalTest<HwcVirtualDisplayCase>();
+ // Insert display data so that the HWC thinks it created the virtual display.
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ mFlinger.mutableHwcDisplayData()[*displayId] = {};
+
+ setupNewDisplayDeviceInternalTest<Case>();
}
TEST_F(SetupNewDisplayDeviceInternalTest, createWideColorP3Display) {
@@ -1258,7 +1377,7 @@
EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
EXPECT_CALL(*mEventThread,
- onHotplugReceived(Case::Display::TYPE == DisplayDevice::DISPLAY_PRIMARY
+ onHotplugReceived(static_cast<bool>(Case::Display::PRIMARY)
? EventThread::DisplayType::Primary
: EventThread::DisplayType::External,
true))
@@ -1269,7 +1388,7 @@
void HandleTransactionLockedTest::setupCommonCallExpectationsForDisconnectProcessing() {
EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
EXPECT_CALL(*mEventThread,
- onHotplugReceived(Case::Display::TYPE == DisplayDevice::DISPLAY_PRIMARY
+ onHotplugReceived(static_cast<bool>(Case::Display::PRIMARY)
? EventThread::DisplayType::Primary
: EventThread::DisplayType::External,
false))
@@ -1282,30 +1401,35 @@
ASSERT_TRUE(hasDisplayDevice(displayToken));
const auto& device = getDisplayDevice(displayToken);
EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
- EXPECT_EQ(Case::Display::TYPE == DisplayDevice::DISPLAY_PRIMARY, device->isPrimary());
+ EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary());
// The display should have been set up in the current display state
ASSERT_TRUE(hasCurrentDisplayState(displayToken));
const auto& current = getCurrentDisplayState(displayToken);
- EXPECT_EQ(Case::Display::TYPE, current.type);
+ EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), current.isVirtual());
+ EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
+ : Case::Display::DISPLAY_ID::get(),
+ current.displayId);
// The display should have been set up in the drawing display state
ASSERT_TRUE(hasDrawingDisplayState(displayToken));
const auto& draw = getDrawingDisplayState(displayToken);
- EXPECT_EQ(Case::Display::TYPE, draw.type);
+ EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), draw.isVirtual());
+ EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
+ : Case::Display::DISPLAY_ID::get(),
+ draw.displayId);
}
template <typename Case>
void HandleTransactionLockedTest::verifyPhysicalDisplayIsConnected() {
// HWComposer should have an entry for the display
- EXPECT_TRUE(hasHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+ EXPECT_TRUE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
- // The display should be set up as a built-in display.
- static_assert(0 <= Case::Display::TYPE &&
- Case::Display::TYPE < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES,
- "Must use a valid physical display type index for the fixed-size array");
- auto& displayToken = mFlinger.mutableDisplayTokens()[Case::Display::TYPE];
- ASSERT_TRUE(displayToken != nullptr);
+ // SF should have a display token.
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(*displayId) == 1);
+ auto& displayToken = mFlinger.mutablePhysicalDisplayTokens()[*displayId];
verifyDisplayIsConnected<Case>(displayToken);
}
@@ -1371,7 +1495,7 @@
// Postconditions
// HWComposer should not have an entry for the display
- EXPECT_FALSE(hasHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+ EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
}
template <typename Case>
@@ -1407,13 +1531,12 @@
// Postconditions
// HWComposer should not have an entry for the display
- EXPECT_FALSE(hasHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+ EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
- // The display should not be set up as a built-in display.
- ASSERT_TRUE(0 <= Case::Display::TYPE &&
- Case::Display::TYPE < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES);
- auto displayToken = mFlinger.mutableDisplayTokens()[Case::Display::TYPE];
- EXPECT_TRUE(displayToken == nullptr);
+ // SF should not have a display token.
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(*displayId) == 0);
// The existing token should have been removed
verifyDisplayIsNotConnected(existing.token());
@@ -1500,13 +1623,12 @@
// Postconditions
// HWComposer should not have an entry for the display
- EXPECT_FALSE(hasHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+ EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
- // The display should not be set up as a primary built-in display.
- ASSERT_TRUE(0 <= Case::Display::TYPE &&
- Case::Display::TYPE < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES);
- auto displayToken = mFlinger.mutableDisplayTokens()[Case::Display::TYPE];
- EXPECT_TRUE(displayToken == nullptr);
+ // SF should not have a display token.
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(*displayId) == 0);
}
TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectThenConnectPrimary) {
@@ -1545,10 +1667,10 @@
// The existing token should have been removed
verifyDisplayIsNotConnected(existing.token());
- static_assert(0 <= Case::Display::TYPE &&
- Case::Display::TYPE < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES,
- "Display type must be a built-in display");
- EXPECT_NE(existing.token(), mFlinger.mutableDisplayTokens()[Case::Display::TYPE]);
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(*displayId) == 1);
+ EXPECT_NE(existing.token(), mFlinger.mutablePhysicalDisplayTokens()[*displayId]);
// A new display should be connected in its place
@@ -1578,13 +1700,12 @@
// surface(producer)
sp<BBinder> displayToken = new BBinder();
- DisplayDeviceState info;
- info.type = Case::Display::TYPE;
- info.isSecure = static_cast<bool>(Case::Display::SECURE);
+ DisplayDeviceState state;
+ state.isSecure = static_cast<bool>(Case::Display::SECURE);
sp<mock::GraphicBufferProducer> surface{new mock::GraphicBufferProducer()};
- info.surface = surface;
- mFlinger.mutableCurrentState().displays.add(displayToken, info);
+ state.surface = surface;
+ mFlinger.mutableCurrentState().displays.add(displayToken, state);
// --------------------------------------------------------------------
// Call Expectations
@@ -1646,11 +1767,10 @@
// surface.
sp<BBinder> displayToken = new BBinder();
- DisplayDeviceState info;
- info.type = Case::Display::TYPE;
- info.isSecure = static_cast<bool>(Case::Display::SECURE);
+ DisplayDeviceState state;
+ state.isSecure = static_cast<bool>(Case::Display::SECURE);
- mFlinger.mutableCurrentState().displays.add(displayToken, info);
+ mFlinger.mutableCurrentState().displays.add(displayToken, state);
// --------------------------------------------------------------------
// Call Expectations
@@ -1669,7 +1789,7 @@
// The drawing display state will be set from the current display state.
ASSERT_TRUE(hasDrawingDisplayState(displayToken));
const auto& draw = getDrawingDisplayState(displayToken);
- EXPECT_EQ(Case::Display::TYPE, draw.type);
+ EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), draw.isVirtual());
}
TEST_F(HandleTransactionLockedTest, processesVirtualDisplayRemoval) {
@@ -1679,7 +1799,9 @@
// Preconditions
// A virtual display is set up but is removed from the current state.
- mFlinger.mutableHwcDisplayData().resize(3);
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ mFlinger.mutableHwcDisplayData()[*displayId] = {};
Case::Display::injectHwcDisplay(this);
auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
existing.inject();
@@ -1846,8 +1968,6 @@
EXPECT_CALL(*renderSurface, setNativeWindow(nullptr)).Times(1);
EXPECT_CALL(*displaySurface, resizeBuffers(newWidth, oldHeight)).Times(1);
EXPECT_CALL(*renderSurface, setNativeWindow(nativeWindow)).Times(1);
- EXPECT_CALL(*renderSurface, getWidth()).WillOnce(Return(newWidth));
- EXPECT_CALL(*renderSurface, getHeight()).WillOnce(Return(oldHeight));
// --------------------------------------------------------------------
// Invocation
@@ -1887,8 +2007,6 @@
EXPECT_CALL(*renderSurface, setNativeWindow(nullptr)).Times(1);
EXPECT_CALL(*displaySurface, resizeBuffers(oldWidth, newHeight)).Times(1);
EXPECT_CALL(*renderSurface, setNativeWindow(nativeWindow)).Times(1);
- EXPECT_CALL(*renderSurface, getWidth()).WillOnce(Return(oldWidth));
- EXPECT_CALL(*renderSurface, getHeight()).WillOnce(Return(newHeight));
// --------------------------------------------------------------------
// Invocation
@@ -2799,9 +2917,10 @@
// --------------------------------------------------------------------
// Preconditions
- // We need to resize this so that the HWC thinks the virtual display
- // is something it created.
- mFlinger.mutableHwcDisplayData().resize(3);
+ // Insert display data so that the HWC thinks it created the virtual display.
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ mFlinger.mutableHwcDisplayData()[*displayId] = {};
// A virtual display device is set up
Case::Display::injectHwcDisplay(this);
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index c3534e8..a519f1f 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -175,13 +175,10 @@
auto& mutableLayerDrawingState(sp<Layer> layer) { return layer->mDrawingState; }
void setLayerSidebandStream(sp<Layer> layer, sp<NativeHandle> sidebandStream) {
+ layer->mDrawingState.sidebandStream = sidebandStream;
layer->getBE().compositionInfo.hwc.sidebandStream = sidebandStream;
}
- void setLayerCompositionType(sp<Layer> layer, HWC2::Composition type) {
- layer->getBE().mHwcLayers[DisplayDevice::DISPLAY_PRIMARY].compositionType = type;
- };
-
void setLayerPotentialCursor(sp<Layer> layer, bool potentialCursor) {
layer->mPotentialCursor = potentialCursor;
}
@@ -200,7 +197,8 @@
auto resetDisplayState() { return mFlinger->resetDisplayState(); }
- auto setupNewDisplayDeviceInternal(const wp<IBinder>& displayToken, int32_t displayId,
+ auto setupNewDisplayDeviceInternal(const wp<IBinder>& displayToken,
+ const std::optional<DisplayId>& displayId,
const DisplayDeviceState& state,
const sp<DisplaySurface>& dispSurface,
const sp<IGraphicBufferProducer>& producer) {
@@ -263,7 +261,6 @@
auto& mutableCurrentState() { return mFlinger->mCurrentState; }
auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; }
auto& mutableDisplays() { return mFlinger->mDisplays; }
- auto& mutableDisplayTokens() { return mFlinger->mDisplayTokens; }
auto& mutableDrawingState() { return mFlinger->mDrawingState; }
auto& mutableEventControlThread() { return mFlinger->mEventControlThread; }
auto& mutableEventQueue() { return mFlinger->mEventQueue; }
@@ -273,6 +270,7 @@
auto& mutableInterceptor() { return mFlinger->mInterceptor; }
auto& mutableMainThreadId() { return mFlinger->mMainThreadId; }
auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; }
+ auto& mutablePhysicalDisplayTokens() { return mFlinger->mPhysicalDisplayTokens; }
auto& mutablePrimaryDispSync() { return mFlinger->mPrimaryDispSync; }
auto& mutablePrimaryHWVsyncEnabled() { return mFlinger->mPrimaryHWVsyncEnabled; }
auto& mutableTexturePool() { return mFlinger->mTexturePool; }
@@ -280,8 +278,13 @@
auto& mutableUseHwcVirtualDisplays() { return mFlinger->mUseHwcVirtualDisplays; }
auto& mutableComposerSequenceId() { return mFlinger->getBE().mComposerSequenceId; }
- auto& mutableHwcDisplayData() { return mFlinger->getBE().mHwc->mDisplayData; }
- auto& mutableHwcDisplaySlots() { return mFlinger->getBE().mHwc->mHwcDisplaySlots; }
+ auto& mutableHwcDisplayData() { return mFlinger->getHwComposer().mDisplayData; }
+ auto& mutableHwcPhysicalDisplayIdMap() {
+ return mFlinger->getHwComposer().mPhysicalDisplayIdMap;
+ }
+
+ auto& mutableInternalHwcDisplayId() { return mFlinger->getHwComposer().mInternalHwcDisplayId; }
+ auto& mutableExternalHwcDisplayId() { return mFlinger->getHwComposer().mExternalHwcDisplayId; }
~TestableSurfaceFlinger() {
// All these pointer and container clears help ensure that GMock does
@@ -333,8 +336,9 @@
static constexpr int32_t DEFAULT_DPI = 320;
static constexpr int32_t DEFAULT_ACTIVE_CONFIG = 0;
- FakeHwcDisplayInjector(DisplayDevice::DisplayType type, HWC2::DisplayType hwcDisplayType)
- : mType(type), mHwcDisplayType(hwcDisplayType) {}
+ FakeHwcDisplayInjector(DisplayId displayId, HWC2::DisplayType hwcDisplayType,
+ bool isPrimary)
+ : mDisplayId(displayId), mHwcDisplayType(hwcDisplayType), mIsPrimary(isPrimary) {}
auto& setHwcDisplayId(hwc2_display_t displayId) {
mHwcDisplayId = displayId;
@@ -403,17 +407,22 @@
display->mutableConfigs().emplace(mActiveConfig, config.build());
display->mutableIsConnected() = true;
- ASSERT_TRUE(flinger->mutableHwcDisplayData().size() > static_cast<size_t>(mType));
- flinger->mutableHwcDisplayData()[mType] = HWComposer::DisplayData();
- flinger->mutableHwcDisplayData()[mType].hwcDisplay = display.get();
- flinger->mutableHwcDisplaySlots().emplace(mHwcDisplayId, mType);
+ flinger->mutableHwcDisplayData()[mDisplayId].hwcDisplay = display.get();
+
+ if (mHwcDisplayType == HWC2::DisplayType::Physical) {
+ flinger->mutableHwcPhysicalDisplayIdMap().emplace(mHwcDisplayId, mDisplayId);
+ (mIsPrimary ? flinger->mutableInternalHwcDisplayId()
+ : flinger->mutableExternalHwcDisplayId()) = mHwcDisplayId;
+ }
flinger->mFakeHwcDisplays.push_back(std::move(display));
}
private:
- DisplayDevice::DisplayType mType;
- HWC2::DisplayType mHwcDisplayType;
+ const DisplayId mDisplayId;
+ const HWC2::DisplayType mHwcDisplayType;
+ const bool mIsPrimary;
+
hwc2_display_t mHwcDisplayId = DEFAULT_HWC_DISPLAY_ID;
int32_t mWidth = DEFAULT_WIDTH;
int32_t mHeight = DEFAULT_HEIGHT;
@@ -427,10 +436,13 @@
class FakeDisplayDeviceInjector {
public:
- FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger, DisplayDevice::DisplayType type,
- int32_t displayId)
- : mFlinger(flinger),
- mCreationArgs(flinger.mFlinger.get(), mDisplayToken, type, displayId) {}
+ FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger,
+ const std::optional<DisplayId>& displayId, bool isVirtual,
+ bool isPrimary)
+ : mFlinger(flinger), mCreationArgs(flinger.mFlinger.get(), mDisplayToken, displayId) {
+ mCreationArgs.isVirtual = isVirtual;
+ mCreationArgs.isPrimary = isPrimary;
+ }
sp<IBinder> token() const { return mDisplayToken; }
@@ -472,12 +484,6 @@
return *this;
}
- auto& setDisplaySize(int width, int height) {
- mCreationArgs.displayWidth = width;
- mCreationArgs.displayHeight = height;
- return *this;
- }
-
auto& setPowerMode(int mode) {
mCreationArgs.initialPowerMode = mode;
return *this;
@@ -497,7 +503,7 @@
sp<DisplayDevice> inject() {
DisplayDeviceState state;
- state.type = mCreationArgs.type;
+ state.displayId = mCreationArgs.isVirtual ? std::nullopt : mCreationArgs.displayId;
state.isSecure = mCreationArgs.isSecure;
sp<DisplayDevice> device = new DisplayDevice(std::move(mCreationArgs));
@@ -505,9 +511,9 @@
mFlinger.mutableCurrentState().displays.add(mDisplayToken, state);
mFlinger.mutableDrawingState().displays.add(mDisplayToken, state);
- if (state.type >= DisplayDevice::DISPLAY_PRIMARY &&
- state.type < DisplayDevice::DISPLAY_VIRTUAL) {
- mFlinger.mutableDisplayTokens()[state.type] = mDisplayToken;
+ if (!mCreationArgs.isVirtual) {
+ LOG_ALWAYS_FATAL_IF(!state.displayId);
+ mFlinger.mutablePhysicalDisplayTokens()[*state.displayId] = mDisplayToken;
}
return device;
diff --git a/services/thermalservice/Android.bp b/services/thermalservice/Android.bp
deleted file mode 100644
index 2812c13..0000000
--- a/services/thermalservice/Android.bp
+++ /dev/null
@@ -1,63 +0,0 @@
-subdirs = [
- "libthermalcallback"
-]
-
-cc_library {
- name: "libthermalservice",
-
- srcs: [
- "aidl/android/os/IThermalEventListener.aidl",
- "aidl/android/os/IThermalService.aidl",
- "aidl/android/os/Temperature.cpp",
- ],
- aidl: {
- include_dirs: ["frameworks/native/services/thermalservice/aidl"],
- export_aidl_headers: true,
- },
- export_include_dirs: ["aidl"],
-
- shared_libs: [
- "libbinder",
- "libutils",
- ],
-
- cflags: [
- "-Wall",
- "-Werror",
- "-Wunused",
- "-Wunreachable-code",
- ],
-}
-
-cc_binary {
- name: "thermalserviced",
-
- srcs: [
- "ThermalService.cpp",
- "thermalserviced.cpp",
- ],
-
- include_dirs: ["frameworks/native"],
-
- shared_libs: [
- "libbase",
- "libthermalservice",
- "libbinder",
- "libutils",
- "libthermalcallback",
- "android.hardware.thermal@1.1",
- "android.hardware.thermal@2.0",
- "libhidlbase",
- "libhidltransport",
- "liblog",
- ],
-
- cflags: [
- "-Wall",
- "-Werror",
- "-Wunused",
- "-Wunreachable-code",
- ],
-
- init_rc: ["thermalservice.rc"],
-}
diff --git a/services/thermalservice/ThermalService.cpp b/services/thermalservice/ThermalService.cpp
deleted file mode 100644
index b1a80de..0000000
--- a/services/thermalservice/ThermalService.cpp
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "ThermalService.h"
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-#include <android/os/IThermalEventListener.h>
-#include <android/os/IThermalService.h>
-#include <android/os/Temperature.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <binder/PermissionCache.h>
-#include <log/log.h>
-#include <private/android_filesystem_config.h>
-#include <utils/Errors.h>
-#include <utils/Mutex.h>
-#include <utils/String16.h>
-
-namespace android {
-namespace os {
-
-/**
- * Dump thermal service
- * @param fd file descriptor for dumping
- * @param args not used
- */
-status_t ThermalService::dump(int fd, const Vector<String16>& /* args */) {
- status_t ret = OK;
- std::string result;
- const IPCThreadState* ipc = IPCThreadState::self();
- const int pid = ipc->getCallingPid();
- const int uid = ipc->getCallingUid();
- if ((uid != AID_SHELL) &&
- !PermissionCache::checkPermission(String16("android.permission.DUMP"), pid, uid)) {
- result = android::base::
- StringPrintf("Permission Denial: can't dump ThermalService from pid=%d, uid=%d\n",
- pid, uid);
- ret = PERMISSION_DENIED;
- } else {
- Mutex::Autolock _l(mListenersLock);
- result = android::base::StringPrintf("ThermalEventListener registered: %d\n",
- (int)mListeners.size());
- }
- if (!android::base::WriteStringToFd(result, fd)) {
- SLOGE("Failed to dump fd: %d", fd);
- ret = FDS_NOT_ALLOWED;
- }
- return ret;
-}
-
-/**
- * Notify registered listeners of a thermal throttling start/stop event.
- * @param temperature the temperature at which the event was generated
- */
-binder::Status ThermalService::notifyThrottling(
- const bool isThrottling, const Temperature& temperature) {
- Mutex::Autolock _l(mListenersLock);
-
- mThrottled = isThrottling;
- mThrottleTemperature = temperature;
-
- for (size_t i = 0; i < mListeners.size(); i++) {
- mListeners[i]->notifyThrottling(isThrottling, temperature);
- }
- return binder::Status::ok();
-}
-
-/**
- * Query whether the system is currently thermal throttling.
- * @return true if currently thermal throttling, else false
- */
-binder::Status ThermalService::isThrottling(bool* _aidl_return) {
- Mutex::Autolock _l(mListenersLock);
- *_aidl_return = mThrottled;
- return binder::Status::ok();
-}
-
-/**
- * Register a new thermal event listener.
- * @param listener the client's IThermalEventListener instance to which
- * notifications are to be sent
- */
-binder::Status ThermalService::registerThermalEventListener(
- const sp<IThermalEventListener>& listener) {
- {
- if (listener == NULL) {
- return binder::Status::ok();
- }
- Mutex::Autolock _l(mListenersLock);
- // check whether this is a duplicate
- for (size_t i = 0; i < mListeners.size(); i++) {
- if (IInterface::asBinder(mListeners[i]) ==
- IInterface::asBinder(listener)) {
- return binder::Status::ok();
- }
- }
-
- mListeners.add(listener);
- IInterface::asBinder(listener)->linkToDeath(this);
- }
-
- return binder::Status::ok();
-}
-
-/**
- * Unregister a previously-registered thermal event listener.
- * @param listener the client's IThermalEventListener instance to which
- * notifications are to no longer be sent
- */
-binder::Status ThermalService::unregisterThermalEventListener(
- const sp<IThermalEventListener>& listener) {
- if (listener == NULL) {
- return binder::Status::ok();
- }
- Mutex::Autolock _l(mListenersLock);
- for (size_t i = 0; i < mListeners.size(); i++) {
- if (IInterface::asBinder(mListeners[i]) ==
- IInterface::asBinder(listener)) {
- IInterface::asBinder(mListeners[i])->unlinkToDeath(this);
- mListeners.removeAt(i);
- break;
- }
- }
-
- return binder::Status::ok();
-}
-
-void ThermalService::binderDied(const wp<IBinder>& who) {
- Mutex::Autolock _l(mListenersLock);
-
- for (size_t i = 0; i < mListeners.size(); i++) {
- if (IInterface::asBinder(mListeners[i]) == who) {
- mListeners.removeAt(i);
- break;
- }
- }
-}
-
-/**
- * Publish the supplied ThermalService to servicemanager.
- */
-void ThermalService::publish(
- const sp<ThermalService>& service) {
- defaultServiceManager()->addService(String16("thermalservice"),
- service);
-}
-
-} // namespace os
-} // namespace android
diff --git a/services/thermalservice/ThermalService.h b/services/thermalservice/ThermalService.h
deleted file mode 100644
index d3da900..0000000
--- a/services/thermalservice/ThermalService.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_THERMALSERVICE_THERMALSERVICE_H
-#define ANDROID_THERMALSERVICE_THERMALSERVICE_H
-
-#include <android/os/BnThermalService.h>
-#include <android/os/IThermalEventListener.h>
-#include <android/os/Temperature.h>
-#include <utils/Mutex.h>
-#include <utils/String16.h>
-#include <utils/Vector.h>
-
-namespace android {
-namespace os {
-
-class ThermalService : public BnThermalService,
- public IBinder::DeathRecipient {
-public:
- ThermalService() : mThrottled(false) {};
- void publish(const sp<ThermalService>& service);
- binder::Status notifyThrottling(
- const bool isThrottling, const Temperature& temperature);
- status_t dump(int fd, const Vector<String16>& args) override;
-
-private:
- Mutex mListenersLock;
- Vector<sp<IThermalEventListener> > mListeners;
- bool mThrottled;
- Temperature mThrottleTemperature;
-
- binder::Status registerThermalEventListener(
- const sp<IThermalEventListener>& listener);
- binder::Status unregisterThermalEventListener(
- const sp<IThermalEventListener>& listener);
- binder::Status isThrottling(bool* _aidl_return);
- void binderDied(const wp<IBinder>& who);
-};
-
-}; // namespace os
-}; // namespace android
-
-#endif // ANDROID_THERMALSERVICE_THERMALSERVICE_H
diff --git a/services/thermalservice/aidl/android/os/IThermalEventListener.aidl b/services/thermalservice/aidl/android/os/IThermalEventListener.aidl
deleted file mode 100644
index 050325e..0000000
--- a/services/thermalservice/aidl/android/os/IThermalEventListener.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * Copyright (c) 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os;
-
-import android.os.Temperature;
-
-/**
- * Listener for thermal events.
- * {@hide}
- */
-oneway interface IThermalEventListener {
- /**
- * Called when a thermal throttling start/stop event is received.
- * @param temperature the temperature at which the event was generated.
- */
- void notifyThrottling(
- in boolean isThrottling, in Temperature temperature);
-}
diff --git a/services/thermalservice/aidl/android/os/IThermalService.aidl b/services/thermalservice/aidl/android/os/IThermalService.aidl
deleted file mode 100644
index e699202..0000000
--- a/services/thermalservice/aidl/android/os/IThermalService.aidl
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * Copyright (c) 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os;
-
-import android.os.IThermalEventListener;
-import android.os.Temperature;
-
-/** {@hide} */
-interface IThermalService {
- /**
- * Register a listener for thermal events.
- * @param listener the IThermalEventListener to be notified.
- * {@hide}
- */
- void registerThermalEventListener(in IThermalEventListener listener);
- /**
- * Unregister a previously-registered listener for thermal events.
- * @param listener the IThermalEventListener to no longer be notified.
- * {@hide}
- */
- void unregisterThermalEventListener(in IThermalEventListener listener);
- /**
- * Send a thermal throttling start/stop notification to all listeners.
- * @param temperature the temperature at which the event was generated.
- * {@hide}
- */
- oneway void notifyThrottling(
- in boolean isThrottling, in Temperature temperature);
- /**
- * Return whether system performance is currently thermal throttling.
- * {@hide}
- */
- boolean isThrottling();
-}
diff --git a/services/thermalservice/aidl/android/os/Temperature.aidl b/services/thermalservice/aidl/android/os/Temperature.aidl
deleted file mode 100644
index 0293c39..0000000
--- a/services/thermalservice/aidl/android/os/Temperature.aidl
+++ /dev/null
@@ -1,5 +0,0 @@
-package android.os;
-
-/* Encodes a temperature used by ThermalService. */
-
-parcelable Temperature cpp_header "android/os/Temperature.h";
diff --git a/services/thermalservice/aidl/android/os/Temperature.cpp b/services/thermalservice/aidl/android/os/Temperature.cpp
deleted file mode 100644
index df207b7..0000000
--- a/services/thermalservice/aidl/android/os/Temperature.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "android/os/Temperature.h"
-
-#include <math.h>
-#include <stdint.h>
-#include <binder/Parcel.h>
-#include <hardware/thermal.h>
-#include <sys/types.h>
-#include <utils/Errors.h>
-
-namespace android {
-namespace os {
-
-Temperature::Temperature() : value_(NAN), type_(DEVICE_TEMPERATURE_UNKNOWN) {}
-
-Temperature::Temperature(const float value, const int type) :
- value_(value), type_(type) {}
-
-Temperature::~Temperature() {}
-
-/*
- * Parcel read/write code must be kept in sync with
- * frameworks/base/core/java/android/os/Temperature.java
- */
-
-status_t Temperature::readFromParcel(const Parcel* p) {
- value_ = p->readFloat();
- type_ = p->readInt32();
- return OK;
-}
-
-status_t Temperature::writeToParcel(Parcel* p) const {
- p->writeFloat(value_);
- p->writeInt32(type_);
- return OK;
-}
-
-} // namespace os
-} // namespace android
diff --git a/services/thermalservice/aidl/android/os/Temperature.h b/services/thermalservice/aidl/android/os/Temperature.h
deleted file mode 100644
index bbc5607..0000000
--- a/services/thermalservice/aidl/android/os/Temperature.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef ANDROID_THERMALSERVICE_AIDL_ANDROID_OS_TEMPERATURE_H
-#define ANDROID_THERMALSERVICE_AIDL_ANDROID_OS_TEMPERATURE_H
-
-#include <binder/Parcelable.h>
-
-namespace android {
-namespace os {
-
-class Temperature : public Parcelable {
- public:
-
- Temperature();
- Temperature(const float value, const int type);
- ~Temperature() override;
-
- float getValue() const {return value_;};
- float getType() const {return type_;};
-
- status_t writeToParcel(Parcel* parcel) const override;
- status_t readFromParcel(const Parcel* parcel) override;
-
- private:
- // The value of the temperature as a float, or NAN if unknown.
- float value_;
- // The type of the temperature, an enum temperature_type from
- // hardware/thermal.h
- int type_;
-};
-
-} // namespace os
-} // namespace android
-
-#endif // ANDROID_THERMALSERVICE_AIDL_ANDROID_OS_TEMPERATURE_H
diff --git a/services/thermalservice/libthermalcallback/Android.bp b/services/thermalservice/libthermalcallback/Android.bp
deleted file mode 100644
index 312579c..0000000
--- a/services/thermalservice/libthermalcallback/Android.bp
+++ /dev/null
@@ -1,21 +0,0 @@
-cc_library_shared {
- name: "libthermalcallback",
- srcs: [
- "ThermalCallback.cpp",
- "ThermalChangedCallback.cpp",
- ],
- cflags: [
- "-Wall",
- "-Werror",
- ],
- include_dirs: ["frameworks/native"],
- shared_libs: [
- "android.hardware.thermal@1.1",
- "android.hardware.thermal@2.0",
- "libhidlbase",
- "libhidltransport",
- "liblog",
- "libthermalservice",
- "libutils",
- ],
-}
diff --git a/services/thermalservice/libthermalcallback/ThermalCallback.cpp b/services/thermalservice/libthermalcallback/ThermalCallback.cpp
deleted file mode 100644
index 0f3132c..0000000
--- a/services/thermalservice/libthermalcallback/ThermalCallback.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-#define LOG_TAG "android.hardware.thermal.thermalcallback@1.1-impl"
-#include <log/log.h>
-
-#include <android/os/Temperature.h>
-#include <hardware/thermal.h>
-#include <cmath>
-#include "ThermalCallback.h"
-#include "services/thermalservice/ThermalService.h"
-
-namespace android {
-namespace hardware {
-namespace thermal {
-namespace V1_1 {
-namespace implementation {
-
-using ::android::os::ThermalService;
-using ::android::hardware::thermal::V1_0::TemperatureType;
-
-// Register a binder ThermalService object for sending events
-void ThermalCallback::registerThermalService(sp<ThermalService> thermalService)
-{
- mThermalService = thermalService;
-}
-
-// Methods from IThermalCallback::V1_1 follow.
-Return<void> ThermalCallback::notifyThrottling(
- bool isThrottling,
- const android::hardware::thermal::V1_0::Temperature& temperature) {
-
- // Convert HIDL IThermal Temperature to binder IThermalService Temperature.
- if (mThermalService != nullptr) {
- float value = NAN;
- int type = DEVICE_TEMPERATURE_UNKNOWN;
-
- switch(temperature.type) {
- case TemperatureType::CPU:
- type = DEVICE_TEMPERATURE_CPU;
- break;
- case TemperatureType::GPU:
- type = DEVICE_TEMPERATURE_GPU;
- break;
- case TemperatureType::BATTERY:
- type = DEVICE_TEMPERATURE_BATTERY;
- break;
- case TemperatureType::SKIN:
- type = DEVICE_TEMPERATURE_SKIN;
- break;
- case TemperatureType::UNKNOWN:
- default:
- type = DEVICE_TEMPERATURE_UNKNOWN;
- break;
- }
-
- value = temperature.currentValue == UNKNOWN_TEMPERATURE ? NAN :
- temperature.currentValue;
-
- android::os::Temperature thermal_svc_temp(value, type);
- mThermalService->notifyThrottling(isThrottling, thermal_svc_temp);
- } else {
- SLOGE("IThermalService binder service not created, drop throttling event");
- }
- return Void();
-}
-
-} // namespace implementation
-} // namespace V1_1
-} // namespace thermal
-} // namespace hardware
-} // namespace android
diff --git a/services/thermalservice/libthermalcallback/ThermalCallback.h b/services/thermalservice/libthermalcallback/ThermalCallback.h
deleted file mode 100644
index 3d72c68..0000000
--- a/services/thermalservice/libthermalcallback/ThermalCallback.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef ANDROID_HARDWARE_THERMAL_V1_1_THERMALCALLBACK_H
-#define ANDROID_HARDWARE_THERMAL_V1_1_THERMALCALLBACK_H
-
-#include <android/hardware/thermal/1.1/IThermalCallback.h>
-#include <android/hardware/thermal/1.0/types.h>
-#include <android/os/Temperature.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-#include "services/thermalservice/ThermalService.h"
-
-namespace android {
-namespace hardware {
-namespace thermal {
-namespace V1_1 {
-namespace implementation {
-
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::os::ThermalService;
-
-class ThermalCallback : public IThermalCallback {
- public:
- // Register a binder ThermalService object for sending events
- void registerThermalService(sp<ThermalService> thermalService);
-
- // Methods from IThermalCallback::V1_1 follow.
- Return<void> notifyThrottling(
- bool isThrottling,
- const android::hardware::thermal::V1_0::Temperature& temperature)
- override;
-
- private:
- // Our registered binder ThermalService object to use for sending events
- sp<android::os::ThermalService> mThermalService;
-};
-
-} // namespace implementation
-} // namespace V1_1
-} // namespace thermal
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_THERMAL_V1_1_THERMALCALLBACK_H
diff --git a/services/thermalservice/libthermalcallback/ThermalChangedCallback.cpp b/services/thermalservice/libthermalcallback/ThermalChangedCallback.cpp
deleted file mode 100644
index bb48387..0000000
--- a/services/thermalservice/libthermalcallback/ThermalChangedCallback.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "android.hardware.thermal.thermalchangedcallback@2.0-impl"
-#include <log/log.h>
-
-#include <android/os/Temperature.h>
-#include <hardware/thermal.h>
-#include <cmath>
-#include "ThermalChangedCallback.h"
-#include "services/thermalservice/ThermalService.h"
-
-namespace android {
-namespace hardware {
-namespace thermal {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::thermal::V2_0::TemperatureType;
-using ::android::hardware::thermal::V2_0::ThrottlingSeverity;
-using ::android::os::ThermalService;
-
-// Register a binder ThermalService object for sending events
-void ThermalChangedCallback::registerThermalService(sp<ThermalService> thermalService) {
- mThermalService = thermalService;
-}
-
-// Methods from IThermalChangedCallback::V2_0 follow.
-Return<void> ThermalChangedCallback::notifyThrottling(
- const android::hardware::thermal::V2_0::Temperature& temperature) {
- // Convert HIDL IThermal Temperature to binder IThermalService Temperature.
- if (mThermalService != nullptr) {
- float value = NAN;
- int type = DEVICE_TEMPERATURE_UNKNOWN;
-
- switch (temperature.type) {
- case TemperatureType::CPU:
- type = DEVICE_TEMPERATURE_CPU;
- break;
- case TemperatureType::GPU:
- type = DEVICE_TEMPERATURE_GPU;
- break;
- case TemperatureType::BATTERY:
- type = DEVICE_TEMPERATURE_BATTERY;
- break;
- case TemperatureType::SKIN:
- type = DEVICE_TEMPERATURE_SKIN;
- break;
- case TemperatureType::UNKNOWN:
- default:
- type = DEVICE_TEMPERATURE_UNKNOWN;
- break;
- }
- bool isThrottling = (static_cast<size_t>(temperature.throttlingStatus) >=
- static_cast<size_t>(ThrottlingSeverity::SEVERE))
- ? true
- : false;
- value = temperature.value == UNKNOWN_TEMPERATURE ? NAN :
- temperature.value;
- android::os::Temperature thermal_svc_temp(value, type);
- mThermalService->notifyThrottling(isThrottling, thermal_svc_temp);
- } else {
- SLOGE("IThermalService binder service not created, drop throttling event");
- }
- return Void();
-}
-
-} // namespace implementation
-} // namespace V2_0
-} // namespace thermal
-} // namespace hardware
-} // namespace android
diff --git a/services/thermalservice/libthermalcallback/ThermalChangedCallback.h b/services/thermalservice/libthermalcallback/ThermalChangedCallback.h
deleted file mode 100644
index 03de049..0000000
--- a/services/thermalservice/libthermalcallback/ThermalChangedCallback.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_THERMAL_V1_1_THERMALCHANGEDCALLBACK_H
-#define ANDROID_HARDWARE_THERMAL_V1_1_THERMALCHANGEDCALLBACK_H
-
-#include <android/hardware/thermal/2.0/IThermalChangedCallback.h>
-#include <android/hardware/thermal/2.0/types.h>
-#include <android/os/Temperature.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-#include "services/thermalservice/ThermalService.h"
-
-namespace android {
-namespace hardware {
-namespace thermal {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::os::ThermalService;
-
-class ThermalChangedCallback : public IThermalChangedCallback {
-public:
- // Register a binder ThermalService object for sending events
- void registerThermalService(sp<ThermalService> thermalService);
-
- // Methods from I ThermalChangedCallback::V2_0 follow.
- Return<void> notifyThrottling(
- const android::hardware::thermal::V2_0::Temperature& temperature) override;
-
-private:
- // Our registered binder ThermalService object to use for sending events
- sp<android::os::ThermalService> mThermalService;
-};
-
-} // namespace implementation
-} // namespace V2_0
-} // namespace thermal
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_THERMAL_V1_1_THERMALCHANGEDCALLBACK_H
diff --git a/services/thermalservice/thermalservice.rc b/services/thermalservice/thermalservice.rc
deleted file mode 100644
index 5e20170..0000000
--- a/services/thermalservice/thermalservice.rc
+++ /dev/null
@@ -1,6 +0,0 @@
-service thermalservice /system/bin/thermalserviced
- class core
- user system
- group system
- onrestart restart zygote
- writepid /dev/cpuset/foreground/tasks
diff --git a/services/thermalservice/thermalserviced.cpp b/services/thermalservice/thermalserviced.cpp
deleted file mode 100644
index 0bfaaff..0000000
--- a/services/thermalservice/thermalserviced.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "thermalserviced"
-#include <log/log.h>
-
-#include "ThermalService.h"
-#include "libthermalcallback/ThermalCallback.h"
-#include "libthermalcallback/ThermalChangedCallback.h"
-#include "thermalserviced.h"
-
-#include <android/hardware/thermal/1.1/IThermal.h>
-#include <android/hardware/thermal/2.0/IThermal.h>
-#include <android/hardware/thermal/2.0/types.h>
-
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <hidl/HidlTransportSupport.h>
-
-using namespace android;
-using IThermal1_1 = ::android::hardware::thermal::V1_1::IThermal;
-using IThermal2_0 = ::android::hardware::thermal::V2_0::IThermal;
-using ::android::hardware::configureRpcThreadpool;
-using ::android::hardware::hidl_death_recipient;
-using ::android::hardware::Return;
-using ::android::hardware::thermal::V1_0::ThermalStatus;
-using ::android::hardware::thermal::V1_0::ThermalStatusCode;
-using ::android::hardware::thermal::V1_1::IThermalCallback;
-using ::android::hardware::thermal::V1_1::implementation::ThermalCallback;
-using ::android::hardware::thermal::V2_0::IThermalChangedCallback;
-using ::android::hardware::thermal::V2_0::TemperatureType;
-using ::android::hidl::base::V1_0::IBase;
-using ::android::os::ThermalService;
-
-namespace {
-
-// Our thermalserviced main object
-ThermalServiceDaemon* gThermalServiceDaemon;
-
-// Thermal HAL 1.1 client
-sp<IThermal1_1> gThermalHal1_1 = nullptr;
-// Thermal HAL 2.0 client
-sp<IThermal2_0> gThermalHal2_0 = nullptr;
-
-// Binder death notifier informing of Thermal HAL death.
-struct ThermalServiceDeathRecipient : hidl_death_recipient {
- virtual void serviceDied(
- uint64_t cookie __unused, const wp<IBase>& who __unused) {
- SLOGE("IThermal HAL died");
- gThermalHal1_1 = nullptr;
- gThermalHal2_0 = nullptr;
- gThermalServiceDaemon->getThermalHal();
- }
-};
-
-} // anonymous namespace
-
-void ThermalServiceDaemon::thermalServiceStartup() {
- // Binder IThermal1_1Service startup
- mThermalService = new android::os::ThermalService;
- mThermalService->publish(mThermalService);
- // Register IThermalService object to ThermalHAL callback
- if (mThermalCallback_2_0 != nullptr) {
- mThermalCallback_2_0->registerThermalService(mThermalService);
- } else if (mThermalCallback_1_1 != nullptr) {
- mThermalCallback_1_1->registerThermalService(mThermalService);
- }
- IPCThreadState::self()->joinThreadPool();
-}
-
-// Lookup Thermal HAL, register death notifier, register our
-// ThermalCallback with the Thermal HAL.
-void ThermalServiceDaemon::getThermalHal() {
- static sp<ThermalServiceDeathRecipient> gThermalHalDied = nullptr;
- // Binder death notifier for Thermal HAL
- if (gThermalHalDied == nullptr) {
- gThermalHalDied = new ThermalServiceDeathRecipient();
- }
-
- gThermalHal2_0 = IThermal2_0::getService();
- if (gThermalHal2_0 == nullptr) {
- SLOGW("Unable to get Thermal HAL V2.0, fallback to 1.1");
- gThermalHal1_1 = IThermal1_1::getService();
- if (gThermalHal1_1 == nullptr) {
- SLOGW("Unable to get Thermal HAL V1.1, vendor thermal event "
- "notification not available");
- return;
- }
- if (gThermalHalDied != nullptr) {
- gThermalHal1_1->linkToDeath(gThermalHalDied, 0x451F /* cookie */);
- }
-
- if (mThermalCallback_1_1 != nullptr) {
- Return<void> ret = gThermalHal1_1->registerThermalCallback(mThermalCallback_1_1);
- if (!ret.isOk()) {
- SLOGE("registerThermalCallback failed, status: %s", ret.description().c_str());
- }
- }
- } else {
- if (gThermalHalDied != nullptr) {
- gThermalHal2_0->linkToDeath(gThermalHalDied, 0x451F /* cookie */);
- }
-
- if (mThermalCallback_2_0 != nullptr) {
- Return<void> ret =
- gThermalHal2_0
- ->registerThermalChangedCallback(mThermalCallback_2_0, false,
- TemperatureType::SKIN, // not used
- [](ThermalStatus status) {
- if (ThermalStatusCode::SUCCESS !=
- status.code) {
- SLOGE("registerThermalChangedC"
- "allback failed, "
- "status: %s",
- status.debugMessage
- .c_str());
- }
- });
- if (!ret.isOk()) {
- SLOGE("registerThermalChangedCallback failed, status: %s",
- ret.description().c_str());
- }
- }
- }
-}
-
-ThermalServiceDaemon::~ThermalServiceDaemon() {
- if (mThermalCallback_2_0 != nullptr && gThermalHal2_0 != nullptr) {
- Return<void> ret =
- gThermalHal2_0
- ->unregisterThermalChangedCallback(
- mThermalCallback_2_0,
- [](ThermalStatus status) {
- if (ThermalStatusCode::SUCCESS !=
- status.code) {
- SLOGE("unregisterThermalChangedCallback failed, status: %s",
- status.debugMessage
- .c_str());
- }
- });
- if (!ret.isOk()) {
- SLOGE("unregisterThermalChangedCallback failed, status: %s", ret.description().c_str());
- }
- }
-}
-
-void ThermalServiceDaemon::thermalCallbackStartup() {
- // HIDL IThermal Callback startup
- // Need at least 2 threads in thread pool since we wait for dead HAL
- // to come back on the binder death notification thread and we need
- // another thread for the incoming service now available call.
- configureRpcThreadpool(2, false /* callerWillJoin */);
- mThermalCallback_1_1 = new ThermalCallback();
- mThermalCallback_2_0 = new ThermalChangedCallback();
- // Lookup Thermal HAL 1.1 and 2.0 to register our Callback.
- getThermalHal();
-}
-
-int main(int /*argc*/, char** /*argv*/) {
- gThermalServiceDaemon = new ThermalServiceDaemon();
- gThermalServiceDaemon->thermalCallbackStartup();
- gThermalServiceDaemon->thermalServiceStartup();
- /* NOTREACHED */
-}
diff --git a/services/thermalservice/thermalserviced.h b/services/thermalservice/thermalserviced.h
deleted file mode 100644
index ff7a483..0000000
--- a/services/thermalservice/thermalserviced.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_THERMALSERVICE_THERMALSERVICED_H
-#define ANDROID_THERMALSERVICE_THERMALSERVICED_H
-
-#include "ThermalService.h"
-#include "libthermalcallback/ThermalCallback.h"
-#include "libthermalcallback/ThermalChangedCallback.h"
-
-using namespace android;
-using ::android::hardware::thermal::V1_0::Temperature;
-using ::android::hardware::thermal::V1_1::implementation::ThermalCallback;
-using ::android::hardware::thermal::V2_0::implementation::ThermalChangedCallback;
-using ::android::os::ThermalService;
-
-class ThermalServiceDaemon {
- public:
- ~ThermalServiceDaemon();
- void thermalServiceStartup();
- void thermalCallbackStartup();
- void getThermalHal();
- ThermalServiceDaemon(){};
-
- private:
- sp<ThermalService> mThermalService;
- sp<ThermalCallback> mThermalCallback_1_1;
- sp<ThermalChangedCallback> mThermalCallback_2_0;
-};
-
-#endif // ANDROID_THERMALSERVICE_THERMALSERVICED_H
diff --git a/services/vr/bufferhubd/consumer_queue_channel.cpp b/services/vr/bufferhubd/consumer_queue_channel.cpp
index 74b549d..5d7d4e9 100644
--- a/services/vr/bufferhubd/consumer_queue_channel.cpp
+++ b/services/vr/bufferhubd/consumer_queue_channel.cpp
@@ -80,27 +80,35 @@
}
void ConsumerQueueChannel::RegisterNewBuffer(
- const std::shared_ptr<ProducerChannel>& producer_channel, size_t slot) {
- ALOGD_IF(TRACE,
- "ConsumerQueueChannel::RegisterNewBuffer: queue_id=%d buffer_id=%d "
- "slot=%zu silent=%d",
- buffer_id(), producer_channel->buffer_id(), slot, silent_);
+ const std::shared_ptr<ProducerChannel>& producer_channel,
+ size_t producer_slot) {
+ ALOGD_IF(TRACE, "%s: queue_id=%d buffer_id=%d slot=%zu silent=%d",
+ __FUNCTION__, buffer_id(), producer_channel->buffer_id(),
+ producer_slot, silent_);
// Only register buffers if the queue is not silent.
- if (!silent_) {
- pending_buffer_slots_.emplace(producer_channel, slot);
-
- // Signal the client that there is new buffer available.
- SignalAvailable();
+ if (silent_) {
+ return;
}
+
+ auto status = producer_channel->CreateConsumerStateMask();
+ if (!status.ok()) {
+ ALOGE("%s: Failed to create consumer state mask: %s", __FUNCTION__,
+ status.GetErrorMessage().c_str());
+ return;
+ }
+ uint64_t consumer_state_mask = status.get();
+
+ pending_buffer_slots_.emplace(producer_channel, producer_slot,
+ consumer_state_mask);
+ // Signal the client that there is new buffer available.
+ SignalAvailable();
}
Status<std::vector<std::pair<RemoteChannelHandle, size_t>>>
ConsumerQueueChannel::OnConsumerQueueImportBuffers(Message& message) {
std::vector<std::pair<RemoteChannelHandle, size_t>> buffer_handles;
- ATRACE_NAME("ConsumerQueueChannel::OnConsumerQueueImportBuffers");
- ALOGD_IF(TRACE,
- "ConsumerQueueChannel::OnConsumerQueueImportBuffers: "
- "pending_buffer_slots=%zu",
+ ATRACE_NAME(__FUNCTION__);
+ ALOGD_IF(TRACE, "%s: pending_buffer_slots=%zu", __FUNCTION__,
pending_buffer_slots_.size());
// Indicate this is a silent queue that will not import buffers.
@@ -108,30 +116,30 @@
return ErrorStatus(EBADR);
while (!pending_buffer_slots_.empty()) {
- auto producer_channel = pending_buffer_slots_.front().first.lock();
- size_t producer_slot = pending_buffer_slots_.front().second;
+ auto producer_channel =
+ pending_buffer_slots_.front().producer_channel.lock();
+ size_t producer_slot = pending_buffer_slots_.front().producer_slot;
+ uint64_t consumer_state_mask =
+ pending_buffer_slots_.front().consumer_state_mask;
pending_buffer_slots_.pop();
// It's possible that the producer channel has expired. When this occurs,
// ignore the producer channel.
if (producer_channel == nullptr) {
- ALOGW(
- "ConsumerQueueChannel::OnConsumerQueueImportBuffers: producer "
- "channel has already been expired.");
+ ALOGW("%s: producer channel has already been expired.", __FUNCTION__);
continue;
}
- auto status = producer_channel->CreateConsumer(message);
+ auto status =
+ producer_channel->CreateConsumer(message, consumer_state_mask);
// If no buffers are imported successfully, clear available and return an
// error. Otherwise, return all consumer handles already imported
// successfully, but keep available bits on, so that the client can retry
// importing remaining consumer buffers.
if (!status) {
- ALOGE(
- "ConsumerQueueChannel::OnConsumerQueueImportBuffers: Failed create "
- "consumer: %s",
- status.GetErrorMessage().c_str());
+ ALOGE("%s: Failed create consumer: %s", __FUNCTION__,
+ status.GetErrorMessage().c_str());
if (buffer_handles.empty()) {
ClearAvailable();
return status.error_status();
diff --git a/services/vr/bufferhubd/include/private/dvr/consumer_queue_channel.h b/services/vr/bufferhubd/include/private/dvr/consumer_queue_channel.h
index 8f35437..3a81b03 100644
--- a/services/vr/bufferhubd/include/private/dvr/consumer_queue_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/consumer_queue_channel.h
@@ -3,8 +3,8 @@
#include <queue>
-#include <private/dvr/bufferhub_rpc.h>
#include <private/dvr/buffer_hub.h>
+#include <private/dvr/bufferhub_rpc.h>
#include <private/dvr/consumer_channel.h>
#include <private/dvr/producer_queue_channel.h>
@@ -28,7 +28,8 @@
// Called by ProdcuerQueueChannel to notify consumer queue that a new
// buffer has been allocated.
void RegisterNewBuffer(
- const std::shared_ptr<ProducerChannel>& producer_channel, size_t slot);
+ const std::shared_ptr<ProducerChannel>& producer_channel,
+ size_t producer_slot);
// Called after clients been signaled by service that new buffer has been
// allocated. Clients uses kOpConsumerQueueImportBuffers to import new
@@ -40,14 +41,29 @@
void OnProducerClosed();
private:
+ // Data structure to store relavant info of a newly allocated producer buffer
+ // so that consumer channel and buffer can be created later.
+ struct PendingBuffer {
+ PendingBuffer(std::shared_ptr<ProducerChannel> channel, size_t slot,
+ uint64_t mask) {
+ producer_channel = channel;
+ producer_slot = slot;
+ consumer_state_mask = mask;
+ }
+ PendingBuffer() = delete;
+
+ std::weak_ptr<ProducerChannel> producer_channel;
+ size_t producer_slot;
+ uint64_t consumer_state_mask;
+ };
+
std::shared_ptr<ProducerQueueChannel> GetProducer() const;
// Pointer to the producer channel.
std::weak_ptr<Channel> producer_;
// Tracks newly allocated buffer producers along with it's slot number.
- std::queue<std::pair<std::weak_ptr<ProducerChannel>, size_t>>
- pending_buffer_slots_;
+ std::queue<PendingBuffer> pending_buffer_slots_;
// Tracks how many buffers have this queue imported.
size_t capacity_;
diff --git a/services/vr/bufferhubd/include/private/dvr/producer_channel.h b/services/vr/bufferhubd/include/private/dvr/producer_channel.h
index 5868b09..3ad9c70 100644
--- a/services/vr/bufferhubd/include/private/dvr/producer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/producer_channel.h
@@ -53,7 +53,9 @@
BufferDescription<BorrowedHandle> GetBuffer(uint64_t client_state_mask);
- pdx::Status<RemoteChannelHandle> CreateConsumer(Message& message);
+ pdx::Status<RemoteChannelHandle> CreateConsumer(Message& message,
+ uint64_t consumer_state_mask);
+ pdx::Status<uint64_t> CreateConsumerStateMask();
pdx::Status<RemoteChannelHandle> OnNewConsumer(Message& message);
pdx::Status<LocalFence> OnConsumerAcquire(Message& message);
@@ -93,7 +95,7 @@
LocalFence post_fence_;
LocalFence returned_fence_;
size_t user_metadata_size_; // size of user requested buffer buffer size.
- size_t metadata_buf_size_; // size of the ion buffer that holds metadata.
+ size_t metadata_buf_size_; // size of the ion buffer that holds metadata.
pdx::LocalHandle acquire_fence_fd_;
pdx::LocalHandle release_fence_fd_;
@@ -111,6 +113,10 @@
pdx::Status<void> OnProducerPost(Message& message, LocalFence acquire_fence);
pdx::Status<LocalFence> OnProducerGain(Message& message);
+ // Remove consumer from atomics in shared memory based on consumer_state_mask.
+ // This function is used for clean up for failures in CreateConsumer method.
+ void RemoveConsumerClientMask(uint64_t consumer_state_mask);
+
ProducerChannel(const ProducerChannel&) = delete;
void operator=(const ProducerChannel&) = delete;
};
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index 397c0ae..c6e8ea9 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -248,21 +248,7 @@
return {GetBuffer(BufferHubDefs::kFirstClientBitMask)};
}
-Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(Message& message) {
- ATRACE_NAME("ProducerChannel::CreateConsumer");
- ALOGD_IF(TRACE,
- "ProducerChannel::CreateConsumer: buffer_id=%d, producer_owns=%d",
- buffer_id(), producer_owns_);
-
- int channel_id;
- auto status = message.PushChannel(0, nullptr, &channel_id);
- if (!status) {
- ALOGE(
- "ProducerChannel::CreateConsumer: Failed to push consumer channel: %s",
- status.GetErrorMessage().c_str());
- return ErrorStatus(ENOMEM);
- }
-
+Status<uint64_t> ProducerChannel::CreateConsumerStateMask() {
// Try find the next consumer state bit which has not been claimed by any
// consumer yet.
// memory_order_acquire is chosen here because all writes in other threads
@@ -277,7 +263,6 @@
"consumers per producer: 63.");
return ErrorStatus(E2BIG);
}
-
uint64_t updated_active_clients_bit_mask =
current_active_clients_bit_mask | client_state_mask;
// Set the updated value only if the current value stays the same as what was
@@ -286,28 +271,71 @@
// thread, and the modification will be visible in other threads that acquire
// active_clients_bit_mask_. If the comparison fails, load the result of
// all writes from all threads to updated_active_clients_bit_mask.
- if (!active_clients_bit_mask_->compare_exchange_weak(
- current_active_clients_bit_mask, updated_active_clients_bit_mask,
- std::memory_order_acq_rel, std::memory_order_acquire)) {
+ // Keep on finding the next available slient state mask until succeed or out
+ // of memory.
+ while (!active_clients_bit_mask_->compare_exchange_weak(
+ current_active_clients_bit_mask, updated_active_clients_bit_mask,
+ std::memory_order_acq_rel, std::memory_order_acquire)) {
ALOGE("Current active clients bit mask is changed to %" PRIx64
- ", which was expected to be %" PRIx64 ".",
+ ", which was expected to be %" PRIx64
+ ". Trying to generate a new client state mask to resolve race "
+ "condition.",
updated_active_clients_bit_mask, current_active_clients_bit_mask);
- return ErrorStatus(EBUSY);
+ client_state_mask = BufferHubDefs::FindNextAvailableClientStateMask(
+ current_active_clients_bit_mask | orphaned_consumer_bit_mask_);
+ if (client_state_mask == 0ULL) {
+ ALOGE(
+ "ProducerChannel::CreateConsumer: reached the maximum mumber of "
+ "consumers per producer: 63.");
+ return ErrorStatus(E2BIG);
+ }
+ updated_active_clients_bit_mask =
+ current_active_clients_bit_mask | client_state_mask;
}
- auto consumer =
- std::make_shared<ConsumerChannel>(service(), buffer_id(), channel_id,
- client_state_mask, shared_from_this());
+ return {client_state_mask};
+}
+
+void ProducerChannel::RemoveConsumerClientMask(uint64_t consumer_state_mask) {
+ // Clear up the buffer state and fence state in case there is already
+ // something there due to possible race condition between producer post and
+ // consumer failed to create channel.
+ buffer_state_->fetch_and(~consumer_state_mask, std::memory_order_release);
+ fence_state_->fetch_and(~consumer_state_mask, std::memory_order_release);
+
+ // Restore the consumer state bit and make it visible in other threads that
+ // acquire the active_clients_bit_mask_.
+ active_clients_bit_mask_->fetch_and(~consumer_state_mask,
+ std::memory_order_release);
+}
+
+Status<RemoteChannelHandle> ProducerChannel::CreateConsumer(
+ Message& message, uint64_t consumer_state_mask) {
+ ATRACE_NAME("ProducerChannel::CreateConsumer");
+ ALOGD_IF(TRACE,
+ "ProducerChannel::CreateConsumer: buffer_id=%d, producer_owns=%d",
+ buffer_id(), producer_owns_);
+
+ int channel_id;
+ auto status = message.PushChannel(0, nullptr, &channel_id);
+ if (!status) {
+ ALOGE(
+ "ProducerChannel::CreateConsumer: Failed to push consumer channel: %s",
+ status.GetErrorMessage().c_str());
+ RemoveConsumerClientMask(consumer_state_mask);
+ return ErrorStatus(ENOMEM);
+ }
+
+ auto consumer = std::make_shared<ConsumerChannel>(
+ service(), buffer_id(), channel_id, consumer_state_mask,
+ shared_from_this());
const auto channel_status = service()->SetChannel(channel_id, consumer);
if (!channel_status) {
ALOGE(
"ProducerChannel::CreateConsumer: failed to set new consumer channel: "
"%s",
channel_status.GetErrorMessage().c_str());
- // Restore the consumer state bit and make it visible in other threads that
- // acquire the active_clients_bit_mask_.
- active_clients_bit_mask_->fetch_and(~client_state_mask,
- std::memory_order_release);
+ RemoveConsumerClientMask(consumer_state_mask);
return ErrorStatus(ENOMEM);
}
@@ -327,7 +355,11 @@
Status<RemoteChannelHandle> ProducerChannel::OnNewConsumer(Message& message) {
ATRACE_NAME("ProducerChannel::OnNewConsumer");
ALOGD_IF(TRACE, "ProducerChannel::OnNewConsumer: buffer_id=%d", buffer_id());
- return CreateConsumer(message);
+ auto status = CreateConsumerStateMask();
+ if (!status.ok()) {
+ return status.error_status();
+ }
+ return CreateConsumer(message, /*consumer_state_mask=*/status.get());
}
Status<void> ProducerChannel::OnProducerPost(Message&,
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 003775b..258b45b 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -55,7 +55,6 @@
"-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
"-Wall",
"-Werror",
- // mVrClient unused in vr_composer_client.cpp
"-Wno-error=unused-private-field",
// Warnings in vr_hwc.cpp to be fixed after sync of goog/master.
"-Wno-sign-compare",
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.cpp b/services/vr/hardware_composer/impl/vr_composer_client.cpp
index 4b90031..786d5fa 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.cpp
+++ b/services/vr/hardware_composer/impl/vr_composer_client.cpp
@@ -19,6 +19,8 @@
#include <hardware/gralloc1.h>
#include <log/log.h>
+#include <memory>
+
#include "impl/vr_hwc.h"
#include "impl/vr_composer_client.h"
@@ -39,11 +41,11 @@
std::unique_ptr<ComposerCommandEngine>
VrComposerClient::createCommandEngine() {
- return std::unique_ptr<VrCommandEngine>(new VrCommandEngine(*this));
+ return std::make_unique<VrCommandEngine>(*this);
}
VrComposerClient::VrCommandEngine::VrCommandEngine(VrComposerClient& client)
- : ComposerCommandEngine(client.mHal, client.mResources.get()), mVrClient(client),
+ : ComposerCommandEngine(client.mHal, client.mResources.get()),
mVrHal(client.mVrHal) {}
VrComposerClient::VrCommandEngine::~VrCommandEngine() {}
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.h b/services/vr/hardware_composer/impl/vr_composer_client.h
index 76b1c4f..de22640 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.h
+++ b/services/vr/hardware_composer/impl/vr_composer_client.h
@@ -54,7 +54,6 @@
IVrComposerClient::BufferMetadata readBufferMetadata();
- VrComposerClient& mVrClient;
android::dvr::VrHwc& mVrHal;
VrCommandEngine(const VrCommandEngine&) = delete;
diff --git a/services/vr/performanced/performance_service_tests.cpp b/services/vr/performanced/performance_service_tests.cpp
index 4065785..a24c889 100644
--- a/services/vr/performanced/performance_service_tests.cpp
+++ b/services/vr/performanced/performance_service_tests.cpp
@@ -12,16 +12,16 @@
#include <thread>
#include <utility>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <dvr/performance_client_api.h>
#include <gtest/gtest.h>
#include <private/android_filesystem_config.h>
#include "stdio_filebuf.h"
-#include "string_trim.h"
#include "unique_file.h"
-using android::dvr::Trim;
+using android::base::Trim;
using android::dvr::UniqueFile;
using android::dvr::stdio_filebuf;
diff --git a/services/vr/performanced/string_trim.h b/services/vr/performanced/string_trim.h
deleted file mode 100644
index 7094e9f..0000000
--- a/services/vr/performanced/string_trim.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef ANDROID_DVR_PERFORMANCED_STRING_TRIM_H_
-#define ANDROID_DVR_PERFORMANCED_STRING_TRIM_H_
-
-#include <functional>
-#include <locale>
-#include <string>
-
-namespace android {
-namespace dvr {
-
-// Trims whitespace from the left side of |subject| and returns the result as a
-// new string.
-inline std::string LeftTrim(std::string subject) {
- subject.erase(subject.begin(),
- std::find_if(subject.begin(), subject.end(),
- std::not1(std::ptr_fun<int, int>(std::isspace))));
- return subject;
-}
-
-// Trims whitespace from the right side of |subject| and returns the result as a
-// new string.
-inline std::string RightTrim(std::string subject) {
- subject.erase(std::find_if(subject.rbegin(), subject.rend(),
- std::not1(std::ptr_fun<int, int>(std::isspace)))
- .base(),
- subject.end());
- return subject;
-}
-
-// Trims whitespace from the both sides of |subject| and returns the result as a
-// new string.
-inline std::string Trim(std::string subject) {
- subject.erase(subject.begin(),
- std::find_if(subject.begin(), subject.end(),
- std::not1(std::ptr_fun<int, int>(std::isspace))));
- subject.erase(std::find_if(subject.rbegin(), subject.rend(),
- std::not1(std::ptr_fun<int, int>(std::isspace)))
- .base(),
- subject.end());
- return subject;
-}
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_PERFORMANCED_STRING_TRIM_H_
diff --git a/services/vr/performanced/task.cpp b/services/vr/performanced/task.cpp
index bda1682..2fc96bf 100644
--- a/services/vr/performanced/task.cpp
+++ b/services/vr/performanced/task.cpp
@@ -10,10 +10,10 @@
#include <memory>
#include <sstream>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include "stdio_filebuf.h"
-#include "string_trim.h"
namespace {
@@ -102,7 +102,7 @@
// The status file has lines with the format <field>:<value>. Extract the
// value after the colon.
- return Trim(line.substr(offset + field.size() + 1));
+ return android::base::Trim(line.substr(offset + field.size() + 1));
}
}
@@ -123,7 +123,7 @@
}
std::string key = line.substr(0, offset);
- std::string value = Trim(line.substr(offset + 1));
+ std::string value = android::base::Trim(line.substr(offset + 1));
ALOGD_IF(TRACE, "Task::ReadStatusFields: key=\"%s\" value=\"%s\"",
key.c_str(), value.c_str());
@@ -156,7 +156,7 @@
std::string line = "";
std::getline(file_stream, line);
- return Trim(line);
+ return android::base::Trim(line);
} else {
return "";
}