Merge "CE: Use distinct source and destination clip rectangles"
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index e61eb6e..d236f76 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -104,12 +104,12 @@
EXPECT_EQ(-1, validate_apk_path(badint2))
<< badint2 << " should be rejected as a invalid path";
- // Only one subdir should be allowed.
- const char *bad_path3 = TEST_APP_DIR "example.com/subdir/pkg.apk";
+ // Should not have more than two sub directories
+ const char *bad_path3 = TEST_APP_DIR "random/example.com/subdir/pkg.apk";
EXPECT_EQ(-1, validate_apk_path(bad_path3))
<< bad_path3 << " should be rejected as a invalid path";
- const char *bad_path4 = TEST_APP_DIR "example.com/subdir/../pkg.apk";
+ const char *bad_path4 = TEST_APP_DIR "random/example.com/subdir/pkg.apk";
EXPECT_EQ(-1, validate_apk_path(bad_path4))
<< bad_path4 << " should be rejected as a invalid path";
@@ -120,6 +120,7 @@
TEST_F(UtilsTest, IsValidApkPath_TopDir) {
EXPECT_EQ(0, validate_apk_path(TEST_DATA_DIR "app/com.example"));
+ EXPECT_EQ(0, validate_apk_path(TEST_DATA_DIR "app/random/com.example"));
EXPECT_EQ(0, validate_apk_path(TEST_EXPAND_DIR "app/com.example"));
EXPECT_EQ(-1, validate_apk_path(TEST_DATA_DIR "data/com.example"));
EXPECT_EQ(-1, validate_apk_path(TEST_EXPAND_DIR "data/com.example"));
@@ -127,6 +128,7 @@
TEST_F(UtilsTest, IsValidApkPath_TopFile) {
EXPECT_EQ(0, validate_apk_path(TEST_DATA_DIR "app/com.example/base.apk"));
+ EXPECT_EQ(0, validate_apk_path(TEST_DATA_DIR "app/random/com.example/base.apk"));
EXPECT_EQ(0, validate_apk_path(TEST_EXPAND_DIR "app/com.example/base.apk"));
EXPECT_EQ(-1, validate_apk_path(TEST_DATA_DIR "data/com.example/base.apk"));
EXPECT_EQ(-1, validate_apk_path(TEST_EXPAND_DIR "data/com.example/base.apk"));
@@ -134,6 +136,7 @@
TEST_F(UtilsTest, IsValidApkPath_OatDir) {
EXPECT_EQ(0, validate_apk_path_subdirs(TEST_DATA_DIR "app/com.example/oat"));
+ EXPECT_EQ(0, validate_apk_path_subdirs(TEST_DATA_DIR "app/random/com.example/oat"));
EXPECT_EQ(0, validate_apk_path_subdirs(TEST_EXPAND_DIR "app/com.example/oat"));
EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_DATA_DIR "data/com.example/oat"));
EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_EXPAND_DIR "data/com.example/oat"));
@@ -141,6 +144,7 @@
TEST_F(UtilsTest, IsValidApkPath_OatDirDir) {
EXPECT_EQ(0, validate_apk_path_subdirs(TEST_DATA_DIR "app/com.example/oat/arm64"));
+ EXPECT_EQ(0, validate_apk_path_subdirs(TEST_DATA_DIR "app/random/com.example/oat/arm64"));
EXPECT_EQ(0, validate_apk_path_subdirs(TEST_EXPAND_DIR "app/com.example/oat/arm64"));
EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_DATA_DIR "data/com.example/oat/arm64"));
EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_EXPAND_DIR "data/com.example/oat/arm64"));
@@ -148,6 +152,7 @@
TEST_F(UtilsTest, IsValidApkPath_OatDirDirFile) {
EXPECT_EQ(0, validate_apk_path_subdirs(TEST_DATA_DIR "app/com.example/oat/arm64/base.odex"));
+ EXPECT_EQ(0, validate_apk_path_subdirs(TEST_DATA_DIR "app/random/com.example/oat/arm64/base.odex"));
EXPECT_EQ(0, validate_apk_path_subdirs(TEST_EXPAND_DIR "app/com.example/oat/arm64/base.odex"));
EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_DATA_DIR "data/com.example/oat/arm64/base.odex"));
EXPECT_EQ(-1, validate_apk_path_subdirs(TEST_EXPAND_DIR "data/com.example/oat/arm64/base.odex"));
@@ -164,6 +169,10 @@
EXPECT_EQ(0, validate_apk_path(path2))
<< path2 << " should be allowed as a valid path";
+ const char *path3 = TEST_APP_DIR "random/example.com/example.apk";
+ EXPECT_EQ(0, validate_apk_path(path3))
+ << path3 << " should be allowed as a valid path";
+
const char *badpriv1 = TEST_APP_PRIVATE_DIR "../example.apk";
EXPECT_EQ(-1, validate_apk_path(badpriv1))
<< badpriv1 << " should be rejected as a invalid path";
@@ -172,16 +181,16 @@
EXPECT_EQ(-1, validate_apk_path(badpriv2))
<< badpriv2 << " should be rejected as a invalid path";
- // Only one subdir should be allowed.
- const char *bad_path3 = TEST_APP_PRIVATE_DIR "example.com/subdir/pkg.apk";
+ // Only one or two subdir should be allowed.
+ const char *bad_path3 = TEST_APP_PRIVATE_DIR "random/example.com/subdir/pkg.apk";
EXPECT_EQ(-1, validate_apk_path(bad_path3))
<< bad_path3 << " should be rejected as a invalid path";
- const char *bad_path4 = TEST_APP_PRIVATE_DIR "example.com/subdir/../pkg.apk";
+ const char *bad_path4 = TEST_APP_PRIVATE_DIR "random/example.com/subdir/../pkg.apk";
EXPECT_EQ(-1, validate_apk_path(bad_path4))
<< bad_path4 << " should be rejected as a invalid path";
- const char *bad_path5 = TEST_APP_PRIVATE_DIR "example.com1/../example.com2/pkg.apk";
+ const char *bad_path5 = TEST_APP_PRIVATE_DIR "random/example.com1/../example.com2/pkg.apk";
EXPECT_EQ(-1, validate_apk_path(bad_path5))
<< bad_path5 << " should be rejected as a invalid path";
}
@@ -229,10 +238,16 @@
<< badasec6 << " should be rejected as a invalid path";
}
-TEST_F(UtilsTest, IsValidApkPath_TwoSubdirFail) {
- const char *badasec7 = TEST_ASEC_DIR "com.example.asec/subdir1/pkg.apk";
- EXPECT_EQ(-1, validate_apk_path(badasec7))
- << badasec7 << " should be rejected as a invalid path";
+TEST_F(UtilsTest, IsValidApkPath_TwoSubdir) {
+ const char *badasec7 = TEST_ASEC_DIR "random/com.example.asec/pkg.apk";
+ EXPECT_EQ(0, validate_apk_path(badasec7))
+ << badasec7 << " should be allowed as a valid path";
+}
+
+TEST_F(UtilsTest, IsValidApkPath_ThreeSubdirFail) {
+ const char *badasec8 = TEST_ASEC_DIR "random/com.example.asec/subdir/pkg.apk";
+ EXPECT_EQ(-1, validate_apk_path(badasec8))
+ << badasec8 << " should be rejcted as an invalid path";
}
TEST_F(UtilsTest, CheckSystemApp_Dir1) {
@@ -511,8 +526,8 @@
EXPECT_EQ(0, validate_apk_path("/data/app/com.example"));
EXPECT_EQ(0, validate_apk_path("/data/app/com.example/file"));
EXPECT_EQ(0, validate_apk_path("/data/app/com.example//file"));
- EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/"));
- EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/file"));
+ EXPECT_EQ(0, validate_apk_path("/data/app/random/com.example/"));
+ EXPECT_EQ(0, validate_apk_path("/data/app/random/com.example/file"));
EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/dir/file"));
EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/dir//file"));
EXPECT_NE(0, validate_apk_path("/data/app/com.example/dir/dir/dir/file"));
@@ -527,8 +542,10 @@
EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/dir/file"));
EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir/file"));
EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir//file"));
- EXPECT_NE(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir/dir/file"));
- EXPECT_NE(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir/dir//file"));
+ EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir/dir/file"));
+ EXPECT_EQ(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir/dir//file"));
+ EXPECT_NE(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir/dir/dir/file"));
+ EXPECT_NE(0, validate_apk_path_subdirs("/data/app/com.example/dir/dir/dir/dir//file"));
}
TEST_F(UtilsTest, MatchExtension_Valid) {
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 6012822..939cf90 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -954,11 +954,11 @@
}
int validate_apk_path(const char* path) {
- return validate_apk_path_internal(path, 1 /* maxSubdirs */);
+ return validate_apk_path_internal(path, 2 /* maxSubdirs */);
}
int validate_apk_path_subdirs(const char* path) {
- return validate_apk_path_internal(path, 3 /* maxSubdirs */);
+ return validate_apk_path_internal(path, 4 /* maxSubdirs */);
}
int ensure_config_user_dirs(userid_t userid) {
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index ae74ac3..abe6436 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -423,11 +423,12 @@
void ServiceManager::handleClientCallbacks() {
for (const auto& [name, service] : mNameToService) {
- handleServiceClientCallback(name);
+ handleServiceClientCallback(name, true);
}
}
-ssize_t ServiceManager::handleServiceClientCallback(const std::string& serviceName) {
+ssize_t ServiceManager::handleServiceClientCallback(const std::string& serviceName,
+ bool isCalledOnInterval) {
auto serviceIt = mNameToService.find(serviceName);
if (serviceIt == mNameToService.end() || mNameToClientCallback.count(serviceName) < 1) {
return -1;
@@ -451,14 +452,17 @@
service.guaranteeClient = false;
}
- if (hasClients && !service.hasClients) {
- // client was retrieved in some other way
- sendClientCallbackNotifications(serviceName, true);
- }
+ // only send notifications if this was called via the interval checking workflow
+ if (isCalledOnInterval) {
+ if (hasClients && !service.hasClients) {
+ // client was retrieved in some other way
+ sendClientCallbackNotifications(serviceName, true);
+ }
- // there are no more clients, but the callback has not been called yet
- if (!hasClients && service.hasClients) {
- sendClientCallbackNotifications(serviceName, false);
+ // there are no more clients, but the callback has not been called yet
+ if (!hasClients && service.hasClients) {
+ sendClientCallbackNotifications(serviceName, false);
+ }
}
return count;
@@ -518,7 +522,7 @@
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
- int clients = handleServiceClientCallback(name);
+ int clients = handleServiceClientCallback(name, false);
// clients < 0: feature not implemented or other error. Assume clients.
// Otherwise:
@@ -527,7 +531,7 @@
// So, if clients > 2, then at least one other service on the system must hold a refcount.
if (clients < 0 || clients > 2) {
// client callbacks are either disabled or there are other clients
- LOG(INFO) << "Tried to unregister " << name << " but there are clients: " << clients;
+ LOG(INFO) << "Tried to unregister " << name << ", but there are clients: " << clients;
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index 77f5250..a2fc5a8 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -75,7 +75,7 @@
void removeRegistrationCallback(const wp<IBinder>& who,
ServiceCallbackMap::iterator* it,
bool* found);
- ssize_t handleServiceClientCallback(const std::string& serviceName);
+ ssize_t handleServiceClientCallback(const std::string& serviceName, bool isCalledOnInterval);
// Also updates mHasClients (of what the last callback was)
void sendClientCallbackNotifications(const std::string& serviceName, bool hasClients);
// removes a callback from mNameToClientCallback, deleting the entry if the vector is empty
diff --git a/include/input/Input.h b/include/input/Input.h
index 1cf58ef..cf0814c 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -354,9 +354,9 @@
inline int32_t getDeviceId() const { return mDeviceId; }
- inline int32_t getSource() const { return mSource; }
+ inline uint32_t getSource() const { return mSource; }
- inline void setSource(int32_t source) { mSource = source; }
+ inline void setSource(uint32_t source) { mSource = source; }
inline int32_t getDisplayId() const { return mDisplayId; }
@@ -365,12 +365,12 @@
inline std::array<uint8_t, 32> getHmac() const { return mHmac; }
protected:
- void initialize(int32_t deviceId, int32_t source, int32_t displayId,
+ void initialize(int32_t deviceId, uint32_t source, int32_t displayId,
std::array<uint8_t, 32> hmac);
void initialize(const InputEvent& from);
int32_t mDeviceId;
- int32_t mSource;
+ uint32_t mSource;
int32_t mDisplayId;
std::array<uint8_t, 32> mHmac;
};
@@ -405,7 +405,7 @@
static const char* getLabel(int32_t keyCode);
static int32_t getKeyCodeFromLabel(const char* label);
- void initialize(int32_t deviceId, int32_t source, int32_t displayId,
+ void initialize(int32_t deviceId, uint32_t source, int32_t displayId,
std::array<uint8_t, 32> hmac, int32_t action, int32_t flags, int32_t keyCode,
int32_t scanCode, int32_t metaState, int32_t repeatCount, nsecs_t downTime,
nsecs_t eventTime);
@@ -629,7 +629,7 @@
ssize_t findPointerIndex(int32_t pointerId) const;
- void initialize(int32_t deviceId, int32_t source, int32_t displayId,
+ void initialize(int32_t deviceId, uint32_t source, int32_t displayId,
std::array<uint8_t, 32> hmac, int32_t action, int32_t actionButton,
int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState,
MotionClassification classification, float xScale, float yScale, float xOffset,
@@ -657,7 +657,7 @@
status_t writeToParcel(Parcel* parcel) const;
#endif
- static bool isTouchEvent(int32_t source, int32_t action);
+ static bool isTouchEvent(uint32_t source, int32_t action);
inline bool isTouchEvent() const {
return isTouchEvent(mSource, mAction);
}
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 238c9dc..f16c39c 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -435,7 +435,8 @@
Vector<Obituary>* obits = mObituaries;
if(obits != nullptr) {
if (!obits->isEmpty()) {
- ALOGI("onLastStrongRef automatically unlinking death recipients");
+ ALOGI("onLastStrongRef automatically unlinking death recipients: %s",
+ mDescriptorCache.size() ? String8(mDescriptorCache).c_str() : "<uncached descriptor>");
}
if (ipc) ipc->clearDeathNotification(mHandle, this);
diff --git a/libs/binder/LazyServiceRegistrar.cpp b/libs/binder/LazyServiceRegistrar.cpp
index dc9482c..f064bd7 100644
--- a/libs/binder/LazyServiceRegistrar.cpp
+++ b/libs/binder/LazyServiceRegistrar.cpp
@@ -53,14 +53,13 @@
struct Service {
sp<IBinder> service;
- std::string name;
bool allowIsolated;
int dumpFlags;
};
/**
- * Number of services that have been registered.
+ * Map of registered names and services
*/
- std::vector<Service> mRegisteredServices;
+ std::map<std::string, Service> mRegisteredServices;
};
bool ClientCounterCallback::registerService(const sp<IBinder>& service, const std::string& name,
@@ -68,20 +67,24 @@
auto manager = interface_cast<AidlServiceManager>(
ProcessState::self()->getContextObject(nullptr));
- ALOGI("Registering service %s", name.c_str());
+ bool reRegister = mRegisteredServices.count(name) > 0;
+ std::string regStr = (reRegister) ? "Re-registering" : "Registering";
+ ALOGI("%s service %s", regStr.c_str(), name.c_str());
if (!manager->addService(name.c_str(), service, allowIsolated, dumpFlags).isOk()) {
ALOGE("Failed to register service %s", name.c_str());
return false;
}
- if (!manager->registerClientCallback(name, service, this).isOk())
- {
- ALOGE("Failed to add client callback for service %s", name.c_str());
- return false;
+ if (!manager->registerClientCallback(name, service, this).isOk()) {
+ ALOGE("Failed to add client callback for service %s", name.c_str());
+ return false;
}
- mRegisteredServices.push_back({service, name, allowIsolated, dumpFlags});
+ if (!reRegister) {
+ // Only add this when a service is added for the first time, as it is not removed
+ mRegisteredServices[name] = {service, allowIsolated, dumpFlags};
+ }
return true;
}
@@ -119,10 +122,11 @@
for (; unRegisterIt != mRegisteredServices.end(); ++unRegisterIt) {
auto& entry = (*unRegisterIt);
- bool success = manager->tryUnregisterService(entry.name, entry.service).isOk();
+ bool success = manager->tryUnregisterService(entry.first, entry.second.service).isOk();
+
if (!success) {
- ALOGI("Failed to unregister service %s", entry.name.c_str());
+ ALOGI("Failed to unregister service %s", entry.first.c_str());
break;
}
}
@@ -137,7 +141,8 @@
auto& entry = (*reRegisterIt);
// re-register entry
- if (!registerService(entry.service, entry.name, entry.allowIsolated, entry.dumpFlags)) {
+ if (!registerService(entry.second.service, entry.first, entry.second.allowIsolated,
+ entry.second.dumpFlags)) {
// Must restart. Otherwise, clients will never be able to get a hold of this service.
ALOGE("Bad state: could not re-register services");
}
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 55419eb..7489afa 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -23,6 +23,9 @@
},
{
"name": "CtsNdkBinderTestCases"
+ },
+ {
+ "name": "aidl_lazy_test"
}
]
}
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp
index 8c8382d..513d8c2 100644
--- a/libs/binder/ndk/test/Android.bp
+++ b/libs/binder/ndk/test/Android.bp
@@ -59,7 +59,14 @@
name: "libbinder_ndk_unit_test",
defaults: ["test_libbinder_ndk_test_defaults"],
srcs: ["libbinder_ndk_unit_test.cpp"],
+ static_libs: [
+ "IBinderNdkUnitTest-ndk_platform",
+ ],
test_suites: ["general-tests"],
+ require_root: true,
+
+ // force since binderVendorDoubleLoadTest has its own
+ auto_gen_config: true,
}
cc_test {
@@ -89,3 +96,11 @@
"IBinderVendorDoubleLoadTest.aidl",
],
}
+
+aidl_interface {
+ name: "IBinderNdkUnitTest",
+ srcs: [
+ "IBinderNdkUnitTest.aidl",
+ "IEmpty.aidl",
+ ],
+}
diff --git a/libs/binder/ndk/test/IBinderNdkUnitTest.aidl b/libs/binder/ndk/test/IBinderNdkUnitTest.aidl
new file mode 100644
index 0000000..6e8e463
--- /dev/null
+++ b/libs/binder/ndk/test/IBinderNdkUnitTest.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This AIDL is to test things that can't be tested in CtsNdkBinderTestCases
+// because it requires libbinder_ndk implementation details or APIs not
+// available to apps. Please prefer adding tests to CtsNdkBinderTestCases
+// over here.
+
+import IEmpty;
+
+interface IBinderNdkUnitTest {
+ void takeInterface(IEmpty test);
+ void forceFlushCommands();
+}
diff --git a/libs/binder/ndk/test/IEmpty.aidl b/libs/binder/ndk/test/IEmpty.aidl
new file mode 100644
index 0000000..95e4341
--- /dev/null
+++ b/libs/binder/ndk/test/IEmpty.aidl
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+interface IEmpty { }
diff --git a/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp
index 8aba411..51dd169 100644
--- a/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <aidl/BnBinderNdkUnitTest.h>
+#include <aidl/BnEmpty.h>
#include <android-base/logging.h>
#include <android/binder_ibinder_jni.h>
#include <android/binder_manager.h>
@@ -21,6 +23,10 @@
#include <gtest/gtest.h>
#include <iface/iface.h>
+// warning: this is assuming that libbinder_ndk is using the same copy
+// of libbinder that we are.
+#include <binder/IPCThreadState.h>
+
#include <sys/prctl.h>
#include <chrono>
#include <condition_variable>
@@ -29,7 +35,38 @@
using ::android::sp;
constexpr char kExistingNonNdkService[] = "SurfaceFlinger";
+constexpr char kBinderNdkUnitTestService[] = "BinderNdkUnitTest";
+class MyBinderNdkUnitTest : public aidl::BnBinderNdkUnitTest {
+ ndk::ScopedAStatus takeInterface(const std::shared_ptr<aidl::IEmpty>& empty) {
+ (void)empty;
+ return ndk::ScopedAStatus::ok();
+ }
+ ndk::ScopedAStatus forceFlushCommands() {
+ // warning: this is assuming that libbinder_ndk is using the same copy
+ // of libbinder that we are.
+ android::IPCThreadState::self()->flushCommands();
+ return ndk::ScopedAStatus::ok();
+ }
+};
+
+int generatedService() {
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+ auto service = ndk::SharedRefBase::make<MyBinderNdkUnitTest>();
+ binder_status_t status =
+ AServiceManager_addService(service->asBinder().get(), kBinderNdkUnitTestService);
+
+ if (status != STATUS_OK) {
+ LOG(FATAL) << "Could not register: " << status << " " << kBinderNdkUnitTestService;
+ }
+
+ ABinderProcess_joinThreadPool();
+
+ return 1; // should not return
+}
+
+// manually-written parceling class considered bad practice
class MyFoo : public IFoo {
binder_status_t doubleNumber(int32_t in, int32_t* out) override {
*out = 2 * in;
@@ -43,7 +80,7 @@
}
};
-int service(const char* instance) {
+int manualService(const char* instance) {
ABinderProcess_setThreadPoolMaxThreadCount(0);
// Strong reference to MyFoo kept by service manager.
@@ -225,16 +262,54 @@
EXPECT_EQ(IFoo::getService(kInstanceName1), IFoo::getService(kInstanceName2));
}
+TEST(NdkBinder, SentAidlBinderCanBeDestroyed) {
+ static volatile bool destroyed = false;
+ static std::mutex dMutex;
+ static std::condition_variable cv;
+
+ class MyEmpty : public aidl::BnEmpty {
+ virtual ~MyEmpty() {
+ destroyed = true;
+ cv.notify_one();
+ }
+ };
+
+ std::shared_ptr<MyEmpty> empty = ndk::SharedRefBase::make<MyEmpty>();
+
+ ndk::SpAIBinder binder(AServiceManager_getService(kBinderNdkUnitTestService));
+ std::shared_ptr<aidl::IBinderNdkUnitTest> service =
+ aidl::IBinderNdkUnitTest::fromBinder(binder);
+
+ EXPECT_FALSE(destroyed);
+
+ service->takeInterface(empty);
+ service->forceFlushCommands();
+ empty = nullptr;
+
+ // give other binder thread time to process commands
+ {
+ using namespace std::chrono_literals;
+ std::unique_lock<std::mutex> lk(dMutex);
+ cv.wait_for(lk, 1s, [] { return destroyed; });
+ }
+
+ EXPECT_TRUE(destroyed);
+}
+
int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
if (fork() == 0) {
prctl(PR_SET_PDEATHSIG, SIGHUP);
- return service(IFoo::kInstanceNameToDieFor);
+ return manualService(IFoo::kInstanceNameToDieFor);
}
if (fork() == 0) {
prctl(PR_SET_PDEATHSIG, SIGHUP);
- return service(IFoo::kSomeInstanceName);
+ return manualService(IFoo::kSomeInstanceName);
+ }
+ if (fork() == 0) {
+ prctl(PR_SET_PDEATHSIG, SIGHUP);
+ return generatedService();
}
ABinderProcess_setThreadPoolMaxThreadCount(1); // to recieve death notifications/callbacks
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 3f359f5..4e62da7 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -83,6 +83,7 @@
if (stats.size() > 0) {
mPendingReleaseItem.releaseFence = stats[0].previousReleaseFence;
mTransformHint = stats[0].transformHint;
+ mBufferItemConsumer->setTransformHint(mTransformHint);
} else {
ALOGE("Warning: no SurfaceControlStats returned in BLASTBufferQueue callback");
mPendingReleaseItem.releaseFence = nullptr;
@@ -151,7 +152,7 @@
bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE);
t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast<void*>(this));
- t->setFrame(mSurfaceControl, {0, 0, (int32_t)buffer->getWidth(), (int32_t)buffer->getHeight()});
+ t->setFrame(mSurfaceControl, {0, 0, mWidth, mHeight});
t->setCrop(mSurfaceControl, computeCrop(bufferItem));
t->setTransform(mSurfaceControl, bufferItem.mTransform);
t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse);
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 3b0120b..9e5d681 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -84,54 +84,54 @@
return INVALID_OPERATION;
}
-BufferQueueCore::BufferQueueCore() :
- mMutex(),
- mIsAbandoned(false),
- mConsumerControlledByApp(false),
- mConsumerName(getUniqueName()),
- mConsumerListener(),
- mConsumerUsageBits(0),
- mConsumerIsProtected(false),
- mConnectedApi(NO_CONNECTED_API),
- mLinkedToDeath(),
- mConnectedProducerListener(),
- mBufferReleasedCbEnabled(false),
- mSlots(),
- mQueue(),
- mFreeSlots(),
- mFreeBuffers(),
- mUnusedSlots(),
- mActiveBuffers(),
- mDequeueCondition(),
- mDequeueBufferCannotBlock(false),
- mQueueBufferCanDrop(false),
- mLegacyBufferDrop(true),
- mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
- mDefaultWidth(1),
- mDefaultHeight(1),
- mDefaultBufferDataSpace(HAL_DATASPACE_UNKNOWN),
- mMaxBufferCount(BufferQueueDefs::NUM_BUFFER_SLOTS),
- mMaxAcquiredBufferCount(1),
- mMaxDequeuedBufferCount(1),
- mBufferHasBeenQueued(false),
- mFrameCounter(0),
- mTransformHint(0),
- mIsAllocating(false),
- mIsAllocatingCondition(),
- mAllowAllocation(true),
- mBufferAge(0),
- mGenerationNumber(0),
- mAsyncMode(false),
- mSharedBufferMode(false),
- mAutoRefresh(false),
- mSharedBufferSlot(INVALID_BUFFER_SLOT),
- mSharedBufferCache(Rect::INVALID_RECT, 0, NATIVE_WINDOW_SCALING_MODE_FREEZE,
- HAL_DATASPACE_UNKNOWN),
- mLastQueuedSlot(INVALID_BUFFER_SLOT),
- mUniqueId(getUniqueId()),
- mAutoPrerotation(false),
- mTransformHintInUse(0)
-{
+BufferQueueCore::BufferQueueCore()
+ : mMutex(),
+ mIsAbandoned(false),
+ mConsumerControlledByApp(false),
+ mConsumerName(getUniqueName()),
+ mConsumerListener(),
+ mConsumerUsageBits(0),
+ mConsumerIsProtected(false),
+ mConnectedApi(NO_CONNECTED_API),
+ mLinkedToDeath(),
+ mConnectedProducerListener(),
+ mBufferReleasedCbEnabled(false),
+ mSlots(),
+ mQueue(),
+ mFreeSlots(),
+ mFreeBuffers(),
+ mUnusedSlots(),
+ mActiveBuffers(),
+ mDequeueCondition(),
+ mDequeueBufferCannotBlock(false),
+ mQueueBufferCanDrop(false),
+ mLegacyBufferDrop(true),
+ mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
+ mDefaultWidth(1),
+ mDefaultHeight(1),
+ mDefaultBufferDataSpace(HAL_DATASPACE_UNKNOWN),
+ mMaxBufferCount(BufferQueueDefs::NUM_BUFFER_SLOTS),
+ mMaxAcquiredBufferCount(1),
+ mMaxDequeuedBufferCount(1),
+ mBufferHasBeenQueued(false),
+ mFrameCounter(0),
+ mTransformHint(0),
+ mIsAllocating(false),
+ mIsAllocatingCondition(),
+ mAllowAllocation(true),
+ mBufferAge(0),
+ mGenerationNumber(0),
+ mAsyncMode(false),
+ mSharedBufferMode(false),
+ mAutoRefresh(false),
+ mSharedBufferSlot(INVALID_BUFFER_SLOT),
+ mSharedBufferCache(Rect::INVALID_RECT, 0, NATIVE_WINDOW_SCALING_MODE_FREEZE,
+ HAL_DATASPACE_UNKNOWN),
+ mLastQueuedSlot(INVALID_BUFFER_SLOT),
+ mUniqueId(getUniqueId()),
+ mAutoPrerotation(false),
+ mTransformHintInUse(0),
+ mFrameRate(0) {
int numStartingBuffers = getMaxBufferCountLocked();
for (int s = 0; s < numStartingBuffers; s++) {
mFreeSlots.insert(s);
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index bff1b97..85b0fd0 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -57,7 +57,7 @@
return "UNKNOWN";
}
-void InputEvent::initialize(int32_t deviceId, int32_t source, int32_t displayId,
+void InputEvent::initialize(int32_t deviceId, uint32_t source, int32_t displayId,
std::array<uint8_t, 32> hmac) {
mDeviceId = deviceId;
mSource = source;
@@ -82,7 +82,7 @@
return getKeyCodeByLabel(label);
}
-void KeyEvent::initialize(int32_t deviceId, int32_t source, int32_t displayId,
+void KeyEvent::initialize(int32_t deviceId, uint32_t source, int32_t displayId,
std::array<uint8_t, 32> hmac, int32_t action, int32_t flags,
int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount,
nsecs_t downTime, nsecs_t eventTime) {
@@ -245,7 +245,7 @@
// --- MotionEvent ---
-void MotionEvent::initialize(int32_t deviceId, int32_t source, int32_t displayId,
+void MotionEvent::initialize(int32_t deviceId, uint32_t source, int32_t displayId,
std::array<uint8_t, 32> hmac, int32_t action, int32_t actionButton,
int32_t flags, int32_t edgeFlags, int32_t metaState,
int32_t buttonState, MotionClassification classification, float xScale,
@@ -321,17 +321,17 @@
float MotionEvent::getXCursorPosition() const {
const float rawX = getRawXCursorPosition();
- return rawX + mXOffset;
+ return rawX * mXScale + mXOffset;
}
float MotionEvent::getYCursorPosition() const {
const float rawY = getRawYCursorPosition();
- return rawY + mYOffset;
+ return rawY * mYScale + mYOffset;
}
void MotionEvent::setCursorPosition(float x, float y) {
- mRawXCursorPosition = x - mXOffset;
- mRawYCursorPosition = y - mYOffset;
+ mRawXCursorPosition = (x - mXOffset) / mXScale;
+ mRawYCursorPosition = (y - mYOffset) / mYScale;
}
const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const {
@@ -346,9 +346,9 @@
float value = getRawPointerCoords(pointerIndex)->getAxisValue(axis);
switch (axis) {
case AMOTION_EVENT_AXIS_X:
- return value + mXOffset;
+ return value * mXScale + mXOffset;
case AMOTION_EVENT_AXIS_Y:
- return value + mYOffset;
+ return value * mYScale + mYOffset;
}
return value;
}
@@ -368,9 +368,9 @@
float value = getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis);
switch (axis) {
case AMOTION_EVENT_AXIS_X:
- return value + mXOffset;
+ return value * mXScale + mXOffset;
case AMOTION_EVENT_AXIS_Y:
- return value + mYOffset;
+ return value * mYScale + mYOffset;
}
return value;
}
@@ -442,11 +442,11 @@
float oldXOffset = mXOffset;
float oldYOffset = mYOffset;
float newX, newY;
- float rawX = getRawX(0);
- float rawY = getRawY(0);
- transformPoint(matrix, rawX + oldXOffset, rawY + oldYOffset, &newX, &newY);
- mXOffset = newX - rawX;
- mYOffset = newY - rawY;
+ float scaledRawX = getRawX(0) * mXScale;
+ float scaledRawY = getRawY(0) * mYScale;
+ transformPoint(matrix, scaledRawX + oldXOffset, scaledRawY + oldYOffset, &newX, &newY);
+ mXOffset = newX - scaledRawX;
+ mYOffset = newY - scaledRawY;
// Determine how the origin is transformed by the matrix so that we
// can transform orientation vectors.
@@ -455,22 +455,22 @@
// Apply the transformation to cursor position.
if (isValidCursorPosition(mRawXCursorPosition, mRawYCursorPosition)) {
- float x = mRawXCursorPosition + oldXOffset;
- float y = mRawYCursorPosition + oldYOffset;
+ float x = mRawXCursorPosition * mXScale + oldXOffset;
+ float y = mRawYCursorPosition * mYScale + oldYOffset;
transformPoint(matrix, x, y, &x, &y);
- mRawXCursorPosition = x - mXOffset;
- mRawYCursorPosition = y - mYOffset;
+ mRawXCursorPosition = (x - mXOffset) / mXScale;
+ mRawYCursorPosition = (y - mYOffset) / mYScale;
}
// Apply the transformation to all samples.
size_t numSamples = mSamplePointerCoords.size();
for (size_t i = 0; i < numSamples; i++) {
PointerCoords& c = mSamplePointerCoords.editItemAt(i);
- float x = c.getAxisValue(AMOTION_EVENT_AXIS_X) + oldXOffset;
- float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y) + oldYOffset;
+ float x = c.getAxisValue(AMOTION_EVENT_AXIS_X) * mXScale + oldXOffset;
+ float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y) * mYScale + oldYOffset;
transformPoint(matrix, x, y, &x, &y);
- c.setAxisValue(AMOTION_EVENT_AXIS_X, x - mXOffset);
- c.setAxisValue(AMOTION_EVENT_AXIS_Y, y - mYOffset);
+ c.setAxisValue(AMOTION_EVENT_AXIS_X, (x - mXOffset) / mXScale);
+ c.setAxisValue(AMOTION_EVENT_AXIS_Y, (y - mYOffset) / mYScale);
float orientation = c.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION,
@@ -488,7 +488,7 @@
}
mDeviceId = parcel->readInt32();
- mSource = parcel->readInt32();
+ mSource = parcel->readUint32();
mDisplayId = parcel->readInt32();
std::vector<uint8_t> hmac;
status_t result = parcel->readByteVector(&hmac);
@@ -549,7 +549,7 @@
parcel->writeInt32(sampleCount);
parcel->writeInt32(mDeviceId);
- parcel->writeInt32(mSource);
+ parcel->writeUint32(mSource);
parcel->writeInt32(mDisplayId);
std::vector<uint8_t> hmac(mHmac.begin(), mHmac.end());
parcel->writeByteVector(hmac);
@@ -590,7 +590,7 @@
}
#endif
-bool MotionEvent::isTouchEvent(int32_t source, int32_t action) {
+bool MotionEvent::isTouchEvent(uint32_t source, int32_t action) {
if (source & AINPUT_SOURCE_CLASS_POINTER) {
// Specifically excludes HOVER_MOVE and SCROLL.
switch (action & AMOTION_EVENT_ACTION_MASK) {
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index 8c6890f..dce1f29 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -189,7 +189,7 @@
ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, event.getType());
ASSERT_EQ(2, event.getDeviceId());
- ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_GAMEPAD), event.getSource());
+ ASSERT_EQ(AINPUT_SOURCE_GAMEPAD, event.getSource());
ASSERT_EQ(DISPLAY_ID, event.getDisplayId());
EXPECT_EQ(HMAC, event.getHmac());
ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, event.getAction());
@@ -203,7 +203,7 @@
// Set source.
event.setSource(AINPUT_SOURCE_JOYSTICK);
- ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_JOYSTICK), event.getSource());
+ ASSERT_EQ(AINPUT_SOURCE_JOYSTICK, event.getSource());
// Set display id.
constexpr int32_t newDisplayId = 2;
@@ -311,7 +311,7 @@
// Check properties.
ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType());
ASSERT_EQ(2, event->getDeviceId());
- ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_TOUCHSCREEN), event->getSource());
+ ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, event->getSource());
ASSERT_EQ(DISPLAY_ID, event->getDisplayId());
EXPECT_EQ(HMAC, event->getHmac());
ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, event->getAction());
@@ -375,19 +375,19 @@
ASSERT_EQ(211, event->getRawY(0));
ASSERT_EQ(221, event->getRawY(1));
- ASSERT_EQ(X_OFFSET + 10, event->getHistoricalX(0, 0));
- ASSERT_EQ(X_OFFSET + 20, event->getHistoricalX(1, 0));
- ASSERT_EQ(X_OFFSET + 110, event->getHistoricalX(0, 1));
- ASSERT_EQ(X_OFFSET + 120, event->getHistoricalX(1, 1));
- ASSERT_EQ(X_OFFSET + 210, event->getX(0));
- ASSERT_EQ(X_OFFSET + 220, event->getX(1));
+ ASSERT_EQ(X_OFFSET + 10 * X_SCALE, event->getHistoricalX(0, 0));
+ ASSERT_EQ(X_OFFSET + 20 * X_SCALE, event->getHistoricalX(1, 0));
+ ASSERT_EQ(X_OFFSET + 110 * X_SCALE, event->getHistoricalX(0, 1));
+ ASSERT_EQ(X_OFFSET + 120 * X_SCALE, event->getHistoricalX(1, 1));
+ ASSERT_EQ(X_OFFSET + 210 * X_SCALE, event->getX(0));
+ ASSERT_EQ(X_OFFSET + 220 * X_SCALE, event->getX(1));
- ASSERT_EQ(Y_OFFSET + 11, event->getHistoricalY(0, 0));
- ASSERT_EQ(Y_OFFSET + 21, event->getHistoricalY(1, 0));
- ASSERT_EQ(Y_OFFSET + 111, event->getHistoricalY(0, 1));
- ASSERT_EQ(Y_OFFSET + 121, event->getHistoricalY(1, 1));
- ASSERT_EQ(Y_OFFSET + 211, event->getY(0));
- ASSERT_EQ(Y_OFFSET + 221, event->getY(1));
+ ASSERT_EQ(Y_OFFSET + 11 * Y_SCALE, event->getHistoricalY(0, 0));
+ ASSERT_EQ(Y_OFFSET + 21 * Y_SCALE, event->getHistoricalY(1, 0));
+ ASSERT_EQ(Y_OFFSET + 111 * Y_SCALE, event->getHistoricalY(0, 1));
+ ASSERT_EQ(Y_OFFSET + 121 * Y_SCALE, event->getHistoricalY(1, 1));
+ ASSERT_EQ(Y_OFFSET + 211 * Y_SCALE, event->getY(0));
+ ASSERT_EQ(Y_OFFSET + 221 * Y_SCALE, event->getY(1));
ASSERT_EQ(12, event->getHistoricalPressure(0, 0));
ASSERT_EQ(22, event->getHistoricalPressure(1, 0));
@@ -448,7 +448,7 @@
// Set source.
event.setSource(AINPUT_SOURCE_JOYSTICK);
- ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_JOYSTICK), event.getSource());
+ ASSERT_EQ(AINPUT_SOURCE_JOYSTICK, event.getSource());
// Set displayId.
constexpr int32_t newDisplayId = 2;
@@ -513,8 +513,8 @@
ASSERT_EQ(210 * 2, event.getRawX(0));
ASSERT_EQ(211 * 2, event.getRawY(0));
- ASSERT_EQ((X_OFFSET + 210) * 2, event.getX(0));
- ASSERT_EQ((Y_OFFSET + 211) * 2, event.getY(0));
+ ASSERT_EQ((X_OFFSET + 210 * X_SCALE) * 2, event.getX(0));
+ ASSERT_EQ((Y_OFFSET + 211 * Y_SCALE) * 2, event.getY(0));
ASSERT_EQ(212, event.getPressure(0));
ASSERT_EQ(213, event.getSize(0));
ASSERT_EQ(214 * 2, event.getTouchMajor(0));
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 1e51ea8..d4bbf6c 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -73,7 +73,7 @@
constexpr uint32_t seq = 15;
constexpr int32_t deviceId = 1;
- constexpr int32_t source = AINPUT_SOURCE_KEYBOARD;
+ constexpr uint32_t source = AINPUT_SOURCE_KEYBOARD;
constexpr int32_t displayId = ADISPLAY_ID_DEFAULT;
constexpr std::array<uint8_t, 32> hmac = {31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21,
20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10,
@@ -139,7 +139,7 @@
constexpr uint32_t seq = 15;
constexpr int32_t deviceId = 1;
- constexpr int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
+ constexpr uint32_t source = AINPUT_SOURCE_TOUCHSCREEN;
constexpr int32_t displayId = ADISPLAY_ID_DEFAULT;
constexpr std::array<uint8_t, 32> hmac = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
@@ -221,8 +221,8 @@
EXPECT_EQ(yPrecision, motionEvent->getYPrecision());
EXPECT_EQ(xCursorPosition, motionEvent->getRawXCursorPosition());
EXPECT_EQ(yCursorPosition, motionEvent->getRawYCursorPosition());
- EXPECT_EQ(xCursorPosition + xOffset, motionEvent->getXCursorPosition());
- EXPECT_EQ(yCursorPosition + yOffset, motionEvent->getYCursorPosition());
+ EXPECT_EQ(xCursorPosition * xScale + xOffset, motionEvent->getXCursorPosition());
+ EXPECT_EQ(yCursorPosition * yScale + yOffset, motionEvent->getYCursorPosition());
EXPECT_EQ(downTime, motionEvent->getDownTime());
EXPECT_EQ(eventTime, motionEvent->getEventTime());
EXPECT_EQ(pointerCount, motionEvent->getPointerCount());
@@ -237,10 +237,10 @@
motionEvent->getRawX(i));
EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
motionEvent->getRawY(i));
- EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X) + xOffset,
- motionEvent->getX(i));
- EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y) + yOffset,
- motionEvent->getY(i));
+ EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X) * xScale + xOffset,
+ motionEvent->getX(i));
+ EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y) * yScale + yOffset,
+ motionEvent->getY(i));
EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
motionEvent->getPressure(i));
EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index 15d937e..58fff8f 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -60,7 +60,7 @@
void postFrameCallbackDelayed(AChoreographer_frameCallback cb,
AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay);
void registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data);
- void unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb);
+ void unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data);
enum {
MSG_SCHEDULE_CALLBACKS = 0,
@@ -152,21 +152,34 @@
void Choreographer::registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data) {
{
AutoMutex _l{mLock};
+ for (const auto& callback : mRefreshRateCallbacks) {
+ // Don't re-add callbacks.
+ if (cb == callback.callback && data == callback.data) {
+ return;
+ }
+ }
mRefreshRateCallbacks.emplace_back(RefreshRateCallback{cb, data});
toggleConfigEvents(ISurfaceComposer::ConfigChanged::eConfigChangedDispatch);
}
}
-void Choreographer::unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb) {
+void Choreographer::unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb,
+ void* data) {
{
AutoMutex _l{mLock};
mRefreshRateCallbacks.erase(std::remove_if(mRefreshRateCallbacks.begin(),
mRefreshRateCallbacks.end(),
[&](const RefreshRateCallback& callback) {
- return cb == callback.callback;
- }));
+ return cb == callback.callback &&
+ data == callback.data;
+ }),
+ mRefreshRateCallbacks.end());
if (mRefreshRateCallbacks.empty()) {
toggleConfigEvents(ISurfaceComposer::ConfigChanged::eConfigChangedSuppress);
+ // If callbacks are empty then clear out the most recently seen
+ // vsync period so that when another callback is registered then the
+ // up-to-date refresh rate can be communicated to the app again.
+ mVsyncPeriod = 0;
}
}
}
@@ -224,9 +237,9 @@
// on every single configuration change.
if (mVsyncPeriod != vsyncPeriod) {
cb.callback(vsyncPeriod, cb.data);
- mVsyncPeriod = vsyncPeriod;
}
}
+ mVsyncPeriod = vsyncPeriod;
}
}
@@ -285,8 +298,9 @@
AChoreographer_to_Choreographer(choreographer)->registerRefreshRateCallback(callback, data);
}
void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer,
- AChoreographer_refreshRateCallback callback) {
- AChoreographer_to_Choreographer(choreographer)->unregisterRefreshRateCallback(callback);
+ AChoreographer_refreshRateCallback callback,
+ void* data) {
+ AChoreographer_to_Choreographer(choreographer)->unregisterRefreshRateCallback(callback, data);
}
AChoreographer* AChoreographer_create() {
diff --git a/libs/nativedisplay/include/android/choreographer.h b/libs/nativedisplay/include/android/choreographer.h
index 0d97e8c..5fd3de9 100644
--- a/libs/nativedisplay/include/android/choreographer.h
+++ b/libs/nativedisplay/include/android/choreographer.h
@@ -54,6 +54,13 @@
*/
typedef void (*AChoreographer_frameCallback64)(int64_t frameTimeNanos, void* data);
+/**
+ * Prototype of the function that is called when the display refresh rate
+ * changes. It's passed the new vsync period in nanoseconds, as well as the data
+ * pointer provided by the application that registered a callback.
+ */
+typedef void (*AChoreographer_refreshRateCallback)(int64_t vsyncPeriodNanos, void* data);
+
#if __ANDROID_API__ >= 24
/**
@@ -102,6 +109,42 @@
#endif /* __ANDROID_API__ >= 29 */
+#if __ANDROID_API__ >= 30
+
+/**
+ * Registers a callback to be run when the display refresh rate changes. The
+ * data pointer provided will be passed to the callback function when it's
+ * called. The same callback may be registered multiple times, provided that a
+ * different data pointer is provided each time.
+ *
+ * If an application registers a callback for this choreographer instance when
+ * no new callbacks were previously registered, that callback is guaranteed to
+ * be dispatched. However, if the callback and associated data pointer are
+ * unregistered prior to running the callback, then the callback may be silently
+ * dropped.
+ *
+ * This api is thread-safe. Any thread is allowed to register a new refresh
+ * rate callback for the choreographer instance.
+ */
+void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer,
+ AChoreographer_refreshRateCallback, void* data);
+
+/**
+ * Unregisters a callback to be run when the display refresh rate changes, along
+ * with the data pointer previously provided when registering the callback. The
+ * callback is only unregistered when the data pointer matches one that was
+ * previously registered.
+ *
+ * This api is thread-safe. Any thread is allowed to unregister an existing
+ * refresh rate callback for the choreographer instance. When a refresh rate
+ * callback and associated data pointer are unregistered, then there is a
+ * guarantee that when the unregistration completes that that callback will not
+ * be run with the data pointer passed.
+ */
+void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer,
+ AChoreographer_refreshRateCallback, void* data);
+#endif /* __ANDROID_API__ >= 30 */
+
__END_DECLS
#endif // ANDROID_CHOREOGRAPHER_H
diff --git a/libs/nativedisplay/include/apex/choreographer.h b/libs/nativedisplay/include/apex/choreographer.h
index 5251fd3..b17b497 100644
--- a/libs/nativedisplay/include/apex/choreographer.h
+++ b/libs/nativedisplay/include/apex/choreographer.h
@@ -22,25 +22,6 @@
__BEGIN_DECLS
/**
- * Prototype of the function that is called when the display refresh rate
- * changes. It's passed the new vsync period in nanoseconds, as well as the data
- * pointer provided by the application that registered a callback.
- */
-typedef void (*AChoreographer_refreshRateCallback)(int64_t vsyncPeriodNanos, void* data);
-
-/**
- * Registers a callback to be run when the display refresh rate changes.
- */
-void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer,
- AChoreographer_refreshRateCallback, void* data);
-
-/**
- * Unregisters a callback to be run when the display refresh rate changes.
- */
-void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer,
- AChoreographer_refreshRateCallback);
-
-/**
* Creates an instance of AChoreographer.
*
* The key differences between this method and AChoreographer_getInstance are:
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index f6b5935..308e93a 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -83,6 +83,7 @@
srcs: [
"InputListener.cpp",
"InputReaderBase.cpp",
+ "InputThread.cpp",
],
shared_libs: [
diff --git a/services/inputflinger/InputThread.cpp b/services/inputflinger/InputThread.cpp
new file mode 100644
index 0000000..b87f7a1
--- /dev/null
+++ b/services/inputflinger/InputThread.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "InputThread.h"
+
+namespace android {
+
+namespace {
+
+// Implementation of Thread from libutils.
+class InputThreadImpl : public Thread {
+public:
+ explicit InputThreadImpl(std::function<void()> loop)
+ : Thread(/* canCallJava */ true), mThreadLoop(loop) {}
+
+ ~InputThreadImpl() {}
+
+private:
+ std::function<void()> mThreadLoop;
+
+ bool threadLoop() override {
+ mThreadLoop();
+ return true;
+ }
+};
+
+} // namespace
+
+InputThread::InputThread(std::string name, std::function<void()> loop, std::function<void()> wake)
+ : mName(name), mThreadWake(wake) {
+ mThread = new InputThreadImpl(loop);
+ mThread->run(mName.c_str(), ANDROID_PRIORITY_URGENT_DISPLAY);
+}
+
+InputThread::~InputThread() {
+ mThread->requestExit();
+ if (mThreadWake) {
+ mThreadWake();
+ }
+ mThread->requestExitAndWait();
+}
+
+bool InputThread::isCallingThread() {
+ return gettid() == mThread->getTid();
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 5ae2419..b2b5145 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -325,24 +325,6 @@
return dispatchEntry;
}
-// --- InputDispatcherThread ---
-
-class InputDispatcher::InputDispatcherThread : public Thread {
-public:
- explicit InputDispatcherThread(InputDispatcher* dispatcher)
- : Thread(/* canCallJava */ true), mDispatcher(dispatcher) {}
-
- ~InputDispatcherThread() {}
-
-private:
- InputDispatcher* mDispatcher;
-
- virtual bool threadLoop() override {
- mDispatcher->dispatchOnce();
- return true;
- }
-};
-
// --- InputDispatcher ---
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy)
@@ -367,8 +349,6 @@
mKeyRepeatState.lastKeyEntry = nullptr;
policy->getDispatcherConfiguration(&mConfig);
-
- mThread = new InputDispatcherThread(this);
}
InputDispatcher::~InputDispatcher() {
@@ -387,25 +367,21 @@
}
status_t InputDispatcher::start() {
- if (mThread->isRunning()) {
+ if (mThread) {
return ALREADY_EXISTS;
}
- return mThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
+ mThread = std::make_unique<InputThread>(
+ "InputDispatcher", [this]() { dispatchOnce(); }, [this]() { mLooper->wake(); });
+ return OK;
}
status_t InputDispatcher::stop() {
- if (!mThread->isRunning()) {
- return OK;
- }
- if (gettid() == mThread->getTid()) {
- ALOGE("InputDispatcher can only be stopped from outside of the InputDispatcherThread!");
+ if (mThread && mThread->isCallingThread()) {
+ ALOGE("InputDispatcher cannot be stopped from its own thread!");
return INVALID_OPERATION;
}
- // Directly calling requestExitAndWait() causes the thread to not exit
- // if mLooper is waiting for a long timeout.
- mThread->requestExit();
- mLooper->wake();
- return mThread->requestExitAndWait();
+ mThread.reset();
+ return OK;
}
void InputDispatcher::dispatchOnce() {
@@ -2424,26 +2400,28 @@
PointerCoords scaledCoords[MAX_POINTERS];
const PointerCoords* usingCoords = motionEntry->pointerCoords;
- // Set the X and Y offset depending on the input source.
- float xOffset, yOffset;
+ // Set the X and Y offset and X and Y scale depending on the input source.
+ float xOffset = 0.0f, yOffset = 0.0f;
+ float xScale = 1.0f, yScale = 1.0f;
if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) &&
!(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
float globalScaleFactor = dispatchEntry->globalScaleFactor;
- float wxs = dispatchEntry->windowXScale;
- float wys = dispatchEntry->windowYScale;
- xOffset = dispatchEntry->xOffset * wxs;
- yOffset = dispatchEntry->yOffset * wys;
- if (wxs != 1.0f || wys != 1.0f || globalScaleFactor != 1.0f) {
+ xScale = dispatchEntry->windowXScale;
+ yScale = dispatchEntry->windowYScale;
+ xOffset = dispatchEntry->xOffset * xScale;
+ yOffset = dispatchEntry->yOffset * yScale;
+ if (globalScaleFactor != 1.0f) {
for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
scaledCoords[i] = motionEntry->pointerCoords[i];
- scaledCoords[i].scale(globalScaleFactor, wxs, wys);
+ // Don't apply window scale here since we don't want scale to affect raw
+ // coordinates. The scale will be sent back to the client and applied
+ // later when requesting relative coordinates.
+ scaledCoords[i].scale(globalScaleFactor, 1 /* windowXScale */,
+ 1 /* windowYScale */);
}
usingCoords = scaledCoords;
}
} else {
- xOffset = 0.0f;
- yOffset = 0.0f;
-
// We don't want the dispatch target to know.
if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) {
for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
@@ -2462,10 +2440,8 @@
dispatchEntry->resolvedFlags,
motionEntry->edgeFlags, motionEntry->metaState,
motionEntry->buttonState,
- motionEntry->classification,
- dispatchEntry->windowXScale,
- dispatchEntry->windowYScale, xOffset, yOffset,
- motionEntry->xPrecision,
+ motionEntry->classification, xScale, yScale,
+ xOffset, yOffset, motionEntry->xPrecision,
motionEntry->yPrecision,
motionEntry->xCursorPosition,
motionEntry->yCursorPosition,
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index a4ba0de..93de18d 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -25,6 +25,7 @@
#include "InputDispatcherPolicyInterface.h"
#include "InputState.h"
#include "InputTarget.h"
+#include "InputThread.h"
#include "Monitor.h"
#include "TouchState.h"
#include "TouchedWindow.h"
@@ -124,8 +125,7 @@
STALE,
};
- class InputDispatcherThread;
- sp<InputDispatcherThread> mThread;
+ std::unique_ptr<InputThread> mThread;
sp<InputDispatcherPolicyInterface> mPolicy;
android::InputDispatcherConfiguration mConfig;
diff --git a/services/inputflinger/include/InputThread.h b/services/inputflinger/include/InputThread.h
new file mode 100644
index 0000000..407365a
--- /dev/null
+++ b/services/inputflinger/include/InputThread.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UI_INPUT_THREAD_H
+#define _UI_INPUT_THREAD_H
+
+#include <utils/Thread.h>
+
+namespace android {
+
+/* A thread that loops continuously until destructed to process input events.
+ *
+ * Creating the InputThread starts it immediately. The thread begins looping the loop
+ * function until the InputThread is destroyed. The wake function is used to wake anything
+ * that sleeps in the loop when it is time for the thread to be destroyed.
+ */
+class InputThread {
+public:
+ explicit InputThread(std::string name, std::function<void()> loop,
+ std::function<void()> wake = nullptr);
+ virtual ~InputThread();
+
+ bool isCallingThread();
+
+private:
+ std::string mName;
+ std::function<void()> mThreadWake;
+ sp<Thread> mThread;
+};
+
+} // namespace android
+
+#endif // _UI_INPUT_THREAD_H
\ No newline at end of file
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 05f0db1..2023c6e 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -49,25 +49,6 @@
namespace android {
-// --- InputReader::InputReaderThread ---
-
-/* Thread that reads raw events from the event hub and processes them, endlessly. */
-class InputReader::InputReaderThread : public Thread {
-public:
- explicit InputReaderThread(InputReader* reader)
- : Thread(/* canCallJava */ true), mReader(reader) {}
-
- ~InputReaderThread() {}
-
-private:
- InputReader* mReader;
-
- bool threadLoop() override {
- mReader->loopOnce();
- return true;
- }
-};
-
// --- InputReader ---
InputReader::InputReader(std::shared_ptr<EventHubInterface> eventHub,
@@ -83,7 +64,6 @@
mNextTimeout(LLONG_MAX),
mConfigurationChangesToRefresh(0) {
mQueuedListener = new QueuedInputListener(listener);
- mThread = new InputReaderThread(this);
{ // acquire lock
AutoMutex _l(mLock);
@@ -100,25 +80,21 @@
}
status_t InputReader::start() {
- if (mThread->isRunning()) {
+ if (mThread) {
return ALREADY_EXISTS;
}
- return mThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
+ mThread = std::make_unique<InputThread>(
+ "InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); });
+ return OK;
}
status_t InputReader::stop() {
- if (!mThread->isRunning()) {
- return OK;
- }
- if (gettid() == mThread->getTid()) {
- ALOGE("InputReader can only be stopped from outside of the InputReaderThread!");
+ if (mThread && mThread->isCallingThread()) {
+ ALOGE("InputReader cannot be stopped from its own thread!");
return INVALID_OPERATION;
}
- // Directly calling requestExitAndWait() causes the thread to not exit
- // if mEventHub is waiting for a long timeout.
- mThread->requestExit();
- mEventHub->wake();
- return mThread->requestExitAndWait();
+ mThread.reset();
+ return OK;
}
void InputReader::loopOnce() {
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 5024906..02957cd 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -21,6 +21,7 @@
#include "InputListener.h"
#include "InputReaderBase.h"
#include "InputReaderContext.h"
+#include "InputThread.h"
#include <utils/Condition.h>
#include <utils/Mutex.h>
@@ -116,8 +117,7 @@
friend class ContextImpl;
private:
- class InputReaderThread;
- sp<InputReaderThread> mThread;
+ std::unique_ptr<InputThread> mThread;
Mutex mLock;
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index e85281d..46bbbe1 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -130,8 +130,10 @@
}
std::optional<float> BufferQueueLayer::getFrameRate() const {
- if (mLatchedFrameRate > 0.f || mLatchedFrameRate == FRAME_RATE_NO_VOTE)
- return mLatchedFrameRate;
+ const auto frameRate = mLatchedFrameRate.load();
+ if (frameRate > 0.f || frameRate == FRAME_RATE_NO_VOTE) {
+ return frameRate;
+ }
return {};
}
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index cd4227c..c86c538 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -239,7 +239,7 @@
mReleasePreviousBuffer = true;
}
- mFrameCounter++;
+ mCurrentState.frameNumber++;
mCurrentState.buffer = buffer;
mCurrentState.clientCacheId = clientCacheId;
@@ -247,10 +247,11 @@
setTransactionFlags(eTransactionNeeded);
const int32_t layerId = getSequence();
- mFlinger->mTimeStats->setPostTime(layerId, mFrameNumber, getName().c_str(), postTime);
+ mFlinger->mTimeStats->setPostTime(layerId, mCurrentState.frameNumber, getName().c_str(),
+ postTime);
mFlinger->mFrameTracer->traceNewLayer(layerId, getName().c_str());
- mFlinger->mFrameTracer->traceTimestamp(layerId, buffer->getId(), mFrameNumber, postTime,
- FrameTracer::FrameEvent::POST);
+ mFlinger->mFrameTracer->traceTimestamp(layerId, buffer->getId(), mCurrentState.frameNumber,
+ postTime, FrameTracer::FrameEvent::POST);
mCurrentState.desiredPresentTime = desiredPresentTime;
mFlinger->mScheduler->recordLayerHistory(this,
@@ -414,7 +415,7 @@
}
uint64_t BufferStateLayer::getFrameNumber(nsecs_t /*expectedPresentTime*/) const {
- return mFrameNumber;
+ return mDrawingState.frameNumber;
}
bool BufferStateLayer::getAutoRefresh() const {
@@ -491,7 +492,7 @@
ALOGE("[%s] rejecting buffer: "
"bufferWidth=%d, bufferHeight=%d, front.active.{w=%d, h=%d}",
getDebugName(), bufferWidth, bufferHeight, s.active.w, s.active.h);
- mFlinger->mTimeStats->removeTimeRecord(layerId, mFrameNumber);
+ mFlinger->mTimeStats->removeTimeRecord(layerId, mDrawingState.frameNumber);
return BAD_VALUE;
}
@@ -499,8 +500,6 @@
handle->latchTime = latchTime;
}
- mFrameNumber = mFrameCounter;
-
if (!SyncFeatures::getInstance().useNativeFenceSync()) {
// Bind the new buffer to the GL texture.
//
@@ -517,11 +516,13 @@
}
const uint64_t bufferID = getCurrentBufferId();
- mFlinger->mTimeStats->setAcquireFence(layerId, mFrameNumber, mBufferInfo.mFenceTime);
- mFlinger->mFrameTracer->traceFence(layerId, bufferID, mFrameNumber, mBufferInfo.mFenceTime,
+ mFlinger->mTimeStats->setAcquireFence(layerId, mDrawingState.frameNumber,
+ mBufferInfo.mFenceTime);
+ mFlinger->mFrameTracer->traceFence(layerId, bufferID, mDrawingState.frameNumber,
+ mBufferInfo.mFenceTime,
FrameTracer::FrameEvent::ACQUIRE_FENCE);
- mFlinger->mTimeStats->setLatchTime(layerId, mFrameNumber, latchTime);
- mFlinger->mFrameTracer->traceTimestamp(layerId, bufferID, mFrameNumber, latchTime,
+ mFlinger->mTimeStats->setLatchTime(layerId, mDrawingState.frameNumber, latchTime);
+ mFlinger->mFrameTracer->traceTimestamp(layerId, bufferID, mDrawingState.frameNumber, latchTime,
FrameTracer::FrameEvent::LATCH);
mCurrentStateModified = false;
@@ -548,7 +549,7 @@
status_t BufferStateLayer::updateFrameNumber(nsecs_t /*latchTime*/) {
// TODO(marissaw): support frame history events
mPreviousFrameNumber = mCurrentFrameNumber;
- mCurrentFrameNumber = mFrameNumber;
+ mCurrentFrameNumber = mDrawingState.frameNumber;
return NO_ERROR;
}
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 04854d0..dbdfd5b 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -61,7 +61,7 @@
}
bool ColorLayer::isVisible() const {
- return !isHiddenByPolicy() && getAlpha() > 0.0f;
+ return !isHiddenByPolicy() && getAlpha() > 0.0_hf;
}
bool ColorLayer::setColor(const half3& color) {
@@ -104,7 +104,9 @@
}
bool ColorLayer::isOpaque(const Layer::State& s) const {
- return (s.flags & layer_state_t::eLayerOpaque) != 0;
+ // Consider the layer to be opaque if its opaque flag is set or its effective
+ // alpha (considering the alpha of its parents as well) is 1.0;
+ return (s.flags & layer_state_t::eLayerOpaque) != 0 || getAlpha() == 1.0_hf;
}
ui::Dataspace ColorLayer::getDataSpace() const {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 6f8df95..cedab59 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -101,6 +101,7 @@
mCurrentState.active.w = UINT32_MAX;
mCurrentState.active.h = UINT32_MAX;
mCurrentState.active.transform.set(0, 0);
+ mCurrentState.frameNumber = 0;
mCurrentState.transform = 0;
mCurrentState.transformToDisplayInverse = false;
mCurrentState.crop.makeInvalid();
@@ -1803,6 +1804,15 @@
}
}
+void Layer::traverse(LayerVector::StateSet state, const LayerVector::Visitor& visitor) {
+ visitor(this);
+ const LayerVector& children =
+ state == LayerVector::StateSet::Drawing ? mDrawingChildren : mCurrentChildren;
+ for (const sp<Layer>& child : children) {
+ child->traverse(state, visitor);
+ }
+}
+
LayerVector Layer::makeChildrenTraversalList(LayerVector::StateSet stateSet,
const std::vector<Layer*>& layersInTree) {
LOG_ALWAYS_FATAL_IF(stateSet == LayerVector::StateSet::Invalid,
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index c75a570..da3df8f 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -189,6 +189,7 @@
ui::Dataspace dataspace;
// The fields below this point are only used by BufferStateLayer
+ uint64_t frameNumber;
Geometry active;
uint32_t transform;
@@ -678,6 +679,15 @@
renderengine::ShadowSettings getShadowSettings(const Rect& viewport) const;
+ /**
+ * Traverse this layer and it's hierarchy of children directly. Unlike traverseInZOrder
+ * which will not emit children who have relativeZOrder to another layer, this method
+ * just directly emits all children. It also emits them in no particular order.
+ * So this method is not suitable for graphical operations, as it doesn't represent
+ * the scene state, but it's also more efficient than traverseInZOrder and so useful for
+ * book-keeping.
+ */
+ void traverse(LayerVector::StateSet stateSet, const LayerVector::Visitor& visitor);
void traverseInReverseZOrder(LayerVector::StateSet stateSet,
const LayerVector::Visitor& visitor);
void traverseInZOrder(LayerVector::StateSet stateSet, const LayerVector::Visitor& visitor);
diff --git a/services/surfaceflinger/LayerVector.cpp b/services/surfaceflinger/LayerVector.cpp
index 7c959b9..9b94920 100644
--- a/services/surfaceflinger/LayerVector.cpp
+++ b/services/surfaceflinger/LayerVector.cpp
@@ -86,6 +86,14 @@
layer->traverseInReverseZOrder(stateSet, visitor);
}
}
+
+void LayerVector::traverse(const Visitor& visitor) const {
+ for (auto i = static_cast<int64_t>(size()) - 1; i >= 0; i--) {
+ const auto& layer = (*this)[i];
+ layer->traverse(mStateSet, visitor);
+ }
+}
+
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/LayerVector.h b/services/surfaceflinger/LayerVector.h
index 88d7711..a531f4f 100644
--- a/services/surfaceflinger/LayerVector.h
+++ b/services/surfaceflinger/LayerVector.h
@@ -50,7 +50,7 @@
using Visitor = std::function<void(Layer*)>;
void traverseInReverseZOrder(StateSet stateSet, const Visitor& visitor) const;
void traverseInZOrder(StateSet stateSet, const Visitor& visitor) const;
-
+ void traverse(const Visitor& visitor) const;
private:
const StateSet mStateSet;
};
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
index d94d758..f309d4d 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
@@ -57,7 +57,7 @@
bool LayerInfoV2::isFrequent(nsecs_t now) const {
// Assume layer is infrequent if too few present times have been recorded.
if (mFrameTimes.size() < FREQUENT_LAYER_WINDOW_SIZE) {
- return true;
+ return false;
}
// Layer is frequent if the earliest value in the window of most recent present times is
@@ -100,8 +100,7 @@
static_cast<float>(totalPresentTimeDeltas) / (mFrameTimes.size() - 1);
// Now once we calculated the refresh rate we need to make sure that all the frames we captured
- // are evenly distrubuted and we don't calculate the average across some burst of frames.
-
+ // are evenly distributed and we don't calculate the average across some burst of frames.
for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) {
const nsecs_t presentTimeDeltas =
std::max(((it + 1)->presetTime - it->presetTime), mHighRefreshRatePeriod);
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index c187049..e4b0287 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -125,12 +125,13 @@
}
for (const auto& layer : layers) {
+ ALOGV("Calculating score for %s (type: %d)", layer.name.c_str(), layer.vote);
if (layer.vote == LayerVoteType::NoVote || layer.vote == LayerVoteType::Min ||
layer.vote == LayerVoteType::Max) {
continue;
}
- // If we have Explicit layers, ignore the Huristic ones
+ // If we have Explicit layers, ignore the Hueristic ones
if (explicitVoteLayers > 0 && layer.vote == LayerVoteType::Heuristic) {
continue;
}
@@ -148,24 +149,26 @@
}
float layerScore;
+ static constexpr size_t MAX_FRAMES_TO_FIT = 10; // Stop calculating when score < 0.1
if (displayFramesRem == 0) {
// Layer desired refresh rate matches the display rate.
layerScore = layer.weight * 1.0f;
} else if (displayFramesQuot == 0) {
// Layer desired refresh rate is higher the display rate.
- layerScore = layer.weight * layerPeriod / displayPeriod;
+ layerScore = layer.weight *
+ (static_cast<float>(layerPeriod) / static_cast<float>(displayPeriod)) *
+ (1.0f / (MAX_FRAMES_TO_FIT + 1));
} else {
// Layer desired refresh rate is lower the display rate. Check how well it fits the
// cadence
auto diff = std::abs(displayFramesRem - (displayPeriod - displayFramesRem));
int iter = 2;
- static constexpr size_t MAX_ITERATOR = 10; // Stop calculating when score < 0.1
- while (diff > MARGIN && iter < MAX_ITERATOR) {
+ while (diff > MARGIN && iter < MAX_FRAMES_TO_FIT) {
diff = diff - (displayPeriod - diff);
iter++;
}
- layerScore = layer.weight * 1.0f / iter;
+ layerScore = layer.weight * (1.0f / iter);
}
ALOGV("%s (weight %.2f) %.2fHz gives %s score of %.2f", layer.name.c_str(),
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index ac32633..e688415 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -71,12 +71,12 @@
return std::get<0>(mRateMap.find(mIdealPeriod)->second);
}
-void VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) {
+bool VSyncPredictor::addVsyncTimestamp(nsecs_t timestamp) {
std::lock_guard<std::mutex> lk(mMutex);
if (!validate(timestamp)) {
ALOGV("timestamp was too far off the last known timestamp");
- return;
+ return false;
}
if (timestamps.size() != kHistorySize) {
@@ -89,7 +89,7 @@
if (timestamps.size() < kMinimumSamplesForPrediction) {
mRateMap[mIdealPeriod] = {mIdealPeriod, 0};
- return;
+ return true;
}
// This is a 'simple linear regression' calculation of Y over X, with Y being the
@@ -143,7 +143,7 @@
if (CC_UNLIKELY(bottom == 0)) {
it->second = {mIdealPeriod, 0};
- return;
+ return false;
}
nsecs_t const anticipatedPeriod = top / bottom * kScalingFactor;
@@ -156,6 +156,7 @@
ALOGV("model update ts: %" PRId64 " slope: %" PRId64 " intercept: %" PRId64, timestamp,
anticipatedPeriod, intercept);
+ return true;
}
nsecs_t VSyncPredictor::nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const {
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h
index e366555..532fe9e 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.h
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h
@@ -38,7 +38,7 @@
uint32_t outlierTolerancePercent);
~VSyncPredictor();
- void addVsyncTimestamp(nsecs_t timestamp) final;
+ bool addVsyncTimestamp(nsecs_t timestamp) final;
nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const final;
nsecs_t currentPeriod() const final;
void resetModel() final;
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index 53fa212..70e4760 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -130,10 +130,11 @@
}
std::lock_guard<std::mutex> lk(mMutex);
- if (mIgnorePresentFences) {
+ if (mExternalIgnoreFences || mInternalIgnoreFences) {
return true;
}
+ bool timestampAccepted = true;
for (auto it = mUnfiredFences.begin(); it != mUnfiredFences.end();) {
auto const time = (*it)->getCachedSignalTime();
if (time == Fence::SIGNAL_TIME_PENDING) {
@@ -141,7 +142,8 @@
} else if (time == Fence::SIGNAL_TIME_INVALID) {
it = mUnfiredFences.erase(it);
} else {
- mTracker->addVsyncTimestamp(time);
+ timestampAccepted &= mTracker->addVsyncTimestamp(time);
+
it = mUnfiredFences.erase(it);
}
}
@@ -152,7 +154,13 @@
}
mUnfiredFences.push_back(fence);
} else {
- mTracker->addVsyncTimestamp(signalTime);
+ timestampAccepted &= mTracker->addVsyncTimestamp(signalTime);
+ }
+
+ if (!timestampAccepted) {
+ mMoreSamplesNeeded = true;
+ setIgnorePresentFencesInternal(true);
+ mPeriodConfirmationInProgress = true;
}
return mMoreSamplesNeeded;
@@ -160,8 +168,17 @@
void VSyncReactor::setIgnorePresentFences(bool ignoration) {
std::lock_guard<std::mutex> lk(mMutex);
- mIgnorePresentFences = ignoration;
- if (mIgnorePresentFences == true) {
+ mExternalIgnoreFences = ignoration;
+ updateIgnorePresentFencesInternal();
+}
+
+void VSyncReactor::setIgnorePresentFencesInternal(bool ignoration) {
+ mInternalIgnoreFences = ignoration;
+ updateIgnorePresentFencesInternal();
+}
+
+void VSyncReactor::updateIgnorePresentFencesInternal() {
+ if (mExternalIgnoreFences || mInternalIgnoreFences) {
mUnfiredFences.clear();
}
}
@@ -177,14 +194,18 @@
}
void VSyncReactor::startPeriodTransition(nsecs_t newPeriod) {
+ mPeriodConfirmationInProgress = true;
mPeriodTransitioningTo = newPeriod;
mMoreSamplesNeeded = true;
+ setIgnorePresentFencesInternal(true);
}
void VSyncReactor::endPeriodTransition() {
- mPeriodTransitioningTo.reset();
- mLastHwVsync.reset();
+ setIgnorePresentFencesInternal(false);
mMoreSamplesNeeded = false;
+ mPeriodTransitioningTo.reset();
+ mPeriodConfirmationInProgress = false;
+ mLastHwVsync.reset();
}
void VSyncReactor::setPeriod(nsecs_t period) {
@@ -208,27 +229,33 @@
void VSyncReactor::endResync() {}
-bool VSyncReactor::periodChangeDetected(nsecs_t vsync_timestamp) {
- if (!mLastHwVsync || !mPeriodTransitioningTo) {
+bool VSyncReactor::periodConfirmed(nsecs_t vsync_timestamp) {
+ if (!mLastHwVsync || !mPeriodConfirmationInProgress) {
return false;
}
+ auto const period = mPeriodTransitioningTo ? *mPeriodTransitioningTo : getPeriod();
+
+ static constexpr int allowancePercent = 10;
+ static constexpr std::ratio<allowancePercent, 100> allowancePercentRatio;
+ auto const allowance = period * allowancePercentRatio.num / allowancePercentRatio.den;
auto const distance = vsync_timestamp - *mLastHwVsync;
- return std::abs(distance - *mPeriodTransitioningTo) < std::abs(distance - getPeriod());
+ return std::abs(distance - period) < allowance;
}
bool VSyncReactor::addResyncSample(nsecs_t timestamp, bool* periodFlushed) {
assert(periodFlushed);
std::lock_guard<std::mutex> lk(mMutex);
- if (periodChangeDetected(timestamp)) {
- mTracker->setPeriod(*mPeriodTransitioningTo);
- for (auto& entry : mCallbacks) {
- entry.second->setPeriod(*mPeriodTransitioningTo);
+ if (periodConfirmed(timestamp)) {
+ if (mPeriodTransitioningTo) {
+ mTracker->setPeriod(*mPeriodTransitioningTo);
+ for (auto& entry : mCallbacks) {
+ entry.second->setPeriod(*mPeriodTransitioningTo);
+ }
+ *periodFlushed = true;
}
-
endPeriodTransition();
- *periodFlushed = true;
- } else if (mPeriodTransitioningTo) {
+ } else if (mPeriodConfirmationInProgress) {
mLastHwVsync = timestamp;
mMoreSamplesNeeded = true;
*periodFlushed = false;
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h
index f318dcb..5b79f35 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.h
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.h
@@ -61,9 +61,11 @@
void reset() final;
private:
+ void setIgnorePresentFencesInternal(bool ignoration) REQUIRES(mMutex);
+ void updateIgnorePresentFencesInternal() REQUIRES(mMutex);
void startPeriodTransition(nsecs_t newPeriod) REQUIRES(mMutex);
void endPeriodTransition() REQUIRES(mMutex);
- bool periodChangeDetected(nsecs_t vsync_timestamp) REQUIRES(mMutex);
+ bool periodConfirmed(nsecs_t vsync_timestamp) REQUIRES(mMutex);
std::unique_ptr<Clock> const mClock;
std::unique_ptr<VSyncTracker> const mTracker;
@@ -71,10 +73,12 @@
size_t const mPendingLimit;
std::mutex mMutex;
- bool mIgnorePresentFences GUARDED_BY(mMutex) = false;
+ bool mInternalIgnoreFences GUARDED_BY(mMutex) = false;
+ bool mExternalIgnoreFences GUARDED_BY(mMutex) = false;
std::vector<std::shared_ptr<FenceTime>> mUnfiredFences GUARDED_BY(mMutex);
bool mMoreSamplesNeeded GUARDED_BY(mMutex) = false;
+ bool mPeriodConfirmationInProgress GUARDED_BY(mMutex) = false;
std::optional<nsecs_t> mPeriodTransitioningTo GUARDED_BY(mMutex);
std::optional<nsecs_t> mLastHwVsync GUARDED_BY(mMutex);
diff --git a/services/surfaceflinger/Scheduler/VSyncTracker.h b/services/surfaceflinger/Scheduler/VSyncTracker.h
index 2b27884..a25b8a9 100644
--- a/services/surfaceflinger/Scheduler/VSyncTracker.h
+++ b/services/surfaceflinger/Scheduler/VSyncTracker.h
@@ -33,8 +33,10 @@
* to the model.
*
* \param [in] timestamp The timestamp when the vsync signal was.
+ * \return True if the timestamp was consistent with the internal model,
+ * False otherwise
*/
- virtual void addVsyncTimestamp(nsecs_t timestamp) = 0;
+ virtual bool addVsyncTimestamp(nsecs_t timestamp) = 0;
/*
* Access the next anticipated vsync time such that the anticipated time >= timePoint.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 62d47e1..61d197c 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2059,7 +2059,7 @@
compositorTiming = getBE().mCompositorTiming;
}
- mDrawingState.traverseInZOrder([&](Layer* layer) {
+ mDrawingState.traverse([&](Layer* layer) {
bool frameLatched = layer->onPostComposition(displayDevice, glCompositionDoneFenceTime,
presentFenceTime, compositorTiming);
if (frameLatched) {
@@ -2496,7 +2496,7 @@
const nsecs_t expectedPresentTime = mExpectedPresentTime.load();
// Notify all layers of available frames
- mCurrentState.traverseInZOrder([expectedPresentTime](Layer* layer) {
+ mCurrentState.traverse([expectedPresentTime](Layer* layer) {
layer->notifyAvailableFrames(expectedPresentTime);
});
@@ -2506,7 +2506,7 @@
*/
if ((transactionFlags & eTraversalNeeded) || mTraversalNeededMainThread) {
- mCurrentState.traverseInZOrder([&](Layer* layer) {
+ mCurrentState.traverse([&](Layer* layer) {
uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
if (!trFlags) return;
@@ -2553,7 +2553,7 @@
sp<const DisplayDevice> hintDisplay;
uint32_t currentlayerStack = 0;
bool first = true;
- mCurrentState.traverseInZOrder([&](Layer* layer) {
+ mCurrentState.traverse([&](Layer* layer) {
// NOTE: we rely on the fact that layers are sorted by
// layerStack first (so we don't have to traverse the list
// of displays for every layer).
@@ -2781,7 +2781,7 @@
// clear the "changed" flags in current state
mCurrentState.colorMatrixChanged = false;
- mDrawingState.traverseInZOrder([&](Layer* layer) {
+ mDrawingState.traverse([&](Layer* layer) {
layer->commitChildList();
// If the layer can be reached when traversing mDrawingState, then the layer is no
@@ -2792,7 +2792,7 @@
});
commitOffscreenLayers();
- mDrawingState.traverseInZOrder([&](Layer* layer) { layer->updateMirrorInfo(); });
+ mDrawingState.traverse([&](Layer* layer) { layer->updateMirrorInfo(); });
}
void SurfaceFlinger::withTracingLock(std::function<void()> lockedOperation) {
@@ -2817,7 +2817,7 @@
void SurfaceFlinger::commitOffscreenLayers() {
for (Layer* offscreenLayer : mOffscreenLayers) {
- offscreenLayer->traverseInZOrder(LayerVector::StateSet::Drawing, [](Layer* layer) {
+ offscreenLayer->traverse(LayerVector::StateSet::Drawing, [](Layer* layer) {
uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
if (!trFlags) return;
@@ -2858,7 +2858,7 @@
// 3.) Layer 1 is latched.
// Display is now waiting on Layer 1's frame, which is behind layer 0's
// second frame. But layer 0's second frame could be waiting on display.
- mDrawingState.traverseInZOrder([&](Layer* layer) {
+ mDrawingState.traverse([&](Layer* layer) {
if (layer->hasReadyFrame()) {
frameQueued = true;
if (layer->shouldPresentNow(expectedPresentTime)) {
@@ -2876,7 +2876,7 @@
// be shown on screen. Therefore, we need to latch and release buffers of offscreen
// layers to ensure dequeueBuffer doesn't block indefinitely.
for (Layer* offscreenLayer : mOffscreenLayers) {
- offscreenLayer->traverseInZOrder(LayerVector::StateSet::Drawing,
+ offscreenLayer->traverse(LayerVector::StateSet::Drawing,
[&](Layer* l) { l->latchAndReleaseBuffer(); });
}
@@ -2911,7 +2911,7 @@
mBootStage = BootStage::BOOTANIMATION;
}
- mDrawingState.traverseInZOrder([&](Layer* layer) { layer->updateCloneBufferInfo(); });
+ mDrawingState.traverse([&](Layer* layer) { layer->updateCloneBufferInfo(); });
// Only continue with the refresh if there is actually new work to do
return !mLayersWithQueuedFrames.empty() && newDataLatched;
@@ -3733,7 +3733,7 @@
bool matchFound = true;
while (matchFound) {
matchFound = false;
- mCurrentState.traverseInZOrder([&](Layer* layer) {
+ mCurrentState.traverse([&](Layer* layer) {
if (layer->getName() == uniqueName) {
matchFound = true;
uniqueName = base::StringPrintf("%s#%u", name, ++dupeCounter);
@@ -4104,7 +4104,7 @@
const bool clearAll = args.size() < 2;
const auto name = clearAll ? String8() : String8(args[1]);
- mCurrentState.traverseInZOrder([&](Layer* layer) {
+ mCurrentState.traverse([&](Layer* layer) {
if (clearAll || layer->getName() == name.string()) {
layer->clearFrameStats();
}
@@ -4120,7 +4120,7 @@
// This should only be called from the main thread. Otherwise it would need
// the lock and should use mCurrentState rather than mDrawingState.
void SurfaceFlinger::logFrameStats() {
- mDrawingState.traverseInZOrder([&](Layer* layer) {
+ mDrawingState.traverse([&](Layer* layer) {
layer->logFrameStats();
});
@@ -4355,7 +4355,7 @@
result.append("Offscreen Layers:\n");
postMessageSync(new LambdaMessage([&]() {
for (Layer* offscreenLayer : mOffscreenLayers) {
- offscreenLayer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
+ offscreenLayer->traverse(LayerVector::StateSet::Drawing, [&](Layer* layer) {
layer->dumpCallingUidPid(result);
});
}
@@ -5588,6 +5588,10 @@
// ---------------------------------------------------------------------------
+void SurfaceFlinger::State::traverse(const LayerVector::Visitor& visitor) const {
+ layersSortedByZ.traverse(visitor);
+}
+
void SurfaceFlinger::State::traverseInZOrder(const LayerVector::Visitor& visitor) const {
layersSortedByZ.traverseInZOrder(stateSet, visitor);
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index f8980a5..4c8775d 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -384,6 +384,7 @@
renderengine::ShadowSettings globalShadowSettings;
+ void traverse(const LayerVector::Visitor& visitor) const;
void traverseInZOrder(const LayerVector::Visitor& visitor) const;
void traverseInReverseZOrder(const LayerVector::Visitor& visitor) const;
};
diff --git a/services/surfaceflinger/TEST_MAPPING b/services/surfaceflinger/TEST_MAPPING
index cab33ae..eed975e 100644
--- a/services/surfaceflinger/TEST_MAPPING
+++ b/services/surfaceflinger/TEST_MAPPING
@@ -1,7 +1,13 @@
{
"presubmit": [
{
- "name": "libsurfaceflinger_unittest"
+ "name": "libsurfaceflinger_unittest",
+ // TODO(b/148517641): re-enable once this test is fixed
+ "options": [
+ {
+ "exclude-filter": "FrameTracerTest.*"
+ }
+ ]
},
{
"name": "libcompositionengine_test"
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 12c98da..130e99a 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -40,13 +40,18 @@
status_pull_atom_return_t TimeStats::pullAtomCallback(int32_t atom_tag,
pulled_stats_event_list* data, void* cookie) {
impl::TimeStats* timeStats = reinterpret_cast<impl::TimeStats*>(cookie);
+ status_pull_atom_return_t result = STATS_PULL_SKIP;
if (atom_tag == android::util::SURFACEFLINGER_STATS_GLOBAL_INFO) {
- return timeStats->populateGlobalAtom(data);
+ result = timeStats->populateGlobalAtom(data);
} else if (atom_tag == android::util::SURFACEFLINGER_STATS_LAYER_INFO) {
- return timeStats->populateLayerAtom(data);
+ result = timeStats->populateLayerAtom(data);
}
- return STATS_PULL_SKIP;
+ // Enable timestats now. The first full pull for a given build is expected to
+ // have empty or very little stats, as stats are first enabled after the
+ // first pull is completed for either the global or layer stats.
+ timeStats->enable();
+ return result;
}
status_pull_atom_return_t TimeStats::populateGlobalAtom(pulled_stats_event_list* data) {
@@ -167,13 +172,19 @@
}
}
+TimeStats::~TimeStats() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mStatsDelegate->unregisterStatsPullAtomCallback(
+ android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
+ mStatsDelegate->unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO);
+}
+
void TimeStats::onBootFinished() {
- // Temporarily enable TimeStats by default. Telemetry is disabled while
- // we move onto statsd, so TimeStats is currently not exercised at all
- // during testing without enabling by default.
- // TODO: remove this, as we should only be paying this overhead on devices
- // where statsd exists.
- enable();
+ std::lock_guard<std::mutex> lock(mMutex);
+ mStatsDelegate->registerStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ TimeStats::pullAtomCallback, nullptr, this);
+ mStatsDelegate->registerStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
+ TimeStats::pullAtomCallback, nullptr, this);
}
void TimeStats::parseArgs(bool asProto, const Vector<String16>& args, std::string& result) {
@@ -735,10 +746,6 @@
mEnabled.store(true);
mTimeStats.statsStart = static_cast<int64_t>(std::time(0));
mPowerTime.prevTime = systemTime();
- mStatsDelegate->registerStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
- TimeStats::pullAtomCallback, nullptr, this);
- mStatsDelegate->registerStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
- TimeStats::pullAtomCallback, nullptr, this);
ALOGD("Enabled");
}
@@ -751,9 +758,6 @@
flushPowerTimeLocked();
mEnabled.store(false);
mTimeStats.statsEnd = static_cast<int64_t>(std::time(0));
- mStatsDelegate->unregisterStatsPullAtomCallback(
- android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
- mStatsDelegate->unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO);
ALOGD("Disabled");
}
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 71f06af..67b9d10 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -182,6 +182,8 @@
std::optional<size_t> maxPulledLayers,
std::optional<size_t> maxPulledHistogramBuckets);
+ ~TimeStats() override;
+
void onBootFinished() override;
void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) override;
bool isEnabled() override;
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index d046f76..7681283 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -32,6 +32,7 @@
// option to false temporarily.
address: true,
},
+ data: ["libsurfaceflinger_unittest.filter"],
srcs: [
":libsurfaceflinger_sources",
"libsurfaceflinger_unittest_main.cpp",
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
index 11ace05..922966a 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
@@ -34,6 +34,7 @@
class LayerHistoryTestV2 : public testing::Test {
protected:
+ static constexpr auto FREQUENT_LAYER_WINDOW_SIZE = LayerInfoV2::FREQUENT_LAYER_WINDOW_SIZE;
static constexpr auto PRESENT_TIME_HISTORY_SIZE = LayerInfoV2::HISTORY_SIZE;
static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = LayerInfoV2::MAX_FREQUENT_LAYER_PERIOD_NS;
@@ -105,7 +106,10 @@
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
history().record(layer.get(), 0, mTime);
ASSERT_EQ(1, history().summarize(mTime).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(mTime)[0].vote);
+ const auto expectedType = (i + 1 < FREQUENT_LAYER_WINDOW_SIZE)
+ ? LayerHistory::LayerVoteType::Min
+ : LayerHistory::LayerVoteType::Max;
+ EXPECT_EQ(expectedType, history().summarize(mTime)[0].vote);
EXPECT_EQ(1, activeLayerCount());
}
@@ -129,7 +133,8 @@
history().record(layer.get(), 0, mTime);
auto summary = history().summarize(mTime);
ASSERT_EQ(1, history().summarize(mTime).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(mTime)[0].vote);
+ // Layer is still considered inactive so we expect to get Min
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(mTime)[0].vote);
EXPECT_EQ(1, activeLayerCount());
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(false));
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 78009b8..19a58dc 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -495,7 +495,7 @@
EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
lr.desiredRefreshRate = 45.0f;
- EXPECT_EQ(expected30Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
lr.desiredRefreshRate = 30.0f;
EXPECT_EQ(expected30Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
@@ -702,6 +702,32 @@
ASSERT_FALSE(expectedDefaultConfig.inPolicy(50.0f, 59.998f));
}
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_75HzContent) {
+ std::vector<RefreshRateConfigs::InputConfig> configs{
+ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
+ {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+
+ RefreshRate expected30Config = {HWC_CONFIG_ID_30, VSYNC_30, HWC_GROUP_ID_0, "30fps", 30};
+ RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
+ RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90};
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ lr.vote = LayerVoteType::Explicit;
+ for (float fps = 75.0f; fps < 100.0f; fps += 0.1f) {
+ lr.desiredRefreshRate = fps;
+ const auto& refreshRate = refreshRateConfigs->getRefreshRateForContentV2(layers);
+ printf("%.2fHz chooses %s\n", fps, refreshRate.name.c_str());
+ EXPECT_EQ(expected90Config, refreshRate);
+ }
+}
+
} // namespace
} // namespace scheduler
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index 68e6697..f65af77 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -258,22 +258,25 @@
ASSERT_FALSE(mTimeStats->isEnabled());
}
-TEST_F(TimeStatsTest, enabledAfterBoot) {
+TEST_F(TimeStatsTest, registersCallbacksAfterBoot) {
mTimeStats->onBootFinished();
- ASSERT_TRUE(mTimeStats->isEnabled());
+ EXPECT_THAT(mDelegate->mAtomTags,
+ UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+}
+
+TEST_F(TimeStatsTest, unregistersCallbacksOnDestruction) {
+ EXPECT_CALL(*mDelegate,
+ unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO));
+ EXPECT_CALL(*mDelegate,
+ unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+ mTimeStats.reset();
}
TEST_F(TimeStatsTest, canEnableAndDisableTimeStats) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
ASSERT_TRUE(mTimeStats->isEnabled());
- EXPECT_THAT(mDelegate->mAtomTags,
- UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
- android::util::SURFACEFLINGER_STATS_LAYER_INFO));
- EXPECT_CALL(*mDelegate,
- unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO));
- EXPECT_CALL(*mDelegate,
- unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO));
EXPECT_TRUE(inputCommand(InputCommand::DISABLE, FMT_STRING).empty());
ASSERT_FALSE(mTimeStats->isEnabled());
}
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
index acf852d..caac61d 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
@@ -37,7 +37,7 @@
public:
FixedRateIdealStubTracker() : mPeriod{toNs(3ms)} {}
- void addVsyncTimestamp(nsecs_t) final {}
+ bool addVsyncTimestamp(nsecs_t) final { return true; }
nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const final {
auto const floor = timePoint % mPeriod;
@@ -60,7 +60,7 @@
public:
VRRStubTracker(nsecs_t period) : mPeriod{period} {}
- void addVsyncTimestamp(nsecs_t) final {}
+ bool addVsyncTimestamp(nsecs_t) final { return true; }
nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t time_point) const final {
std::lock_guard<decltype(mMutex)> lk(mMutex);
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
index 70c9225..3ab38e4 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -39,9 +39,10 @@
MockVSyncTracker(nsecs_t period) : mPeriod{period} {
ON_CALL(*this, nextAnticipatedVSyncTimeFrom(_))
.WillByDefault(Invoke(this, &MockVSyncTracker::nextVSyncTime));
+ ON_CALL(*this, addVsyncTimestamp(_)).WillByDefault(Return(true));
}
- MOCK_METHOD1(addVsyncTimestamp, void(nsecs_t));
+ MOCK_METHOD1(addVsyncTimestamp, bool(nsecs_t));
MOCK_CONST_METHOD1(nextAnticipatedVSyncTimeFrom, nsecs_t(nsecs_t));
MOCK_CONST_METHOD0(currentPeriod, nsecs_t());
MOCK_METHOD1(setPeriod, void(nsecs_t));
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index ce1fafe..1de72b9 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -35,7 +35,8 @@
class MockVSyncTracker : public VSyncTracker {
public:
- MOCK_METHOD1(addVsyncTimestamp, void(nsecs_t));
+ MockVSyncTracker() { ON_CALL(*this, addVsyncTimestamp(_)).WillByDefault(Return(true)); }
+ MOCK_METHOD1(addVsyncTimestamp, bool(nsecs_t));
MOCK_CONST_METHOD1(nextAnticipatedVSyncTimeFrom, nsecs_t(nsecs_t));
MOCK_CONST_METHOD0(currentPeriod, nsecs_t());
MOCK_METHOD1(setPeriod, void(nsecs_t));
@@ -46,7 +47,9 @@
public:
VSyncTrackerWrapper(std::shared_ptr<VSyncTracker> const& tracker) : mTracker(tracker) {}
- void addVsyncTimestamp(nsecs_t timestamp) final { mTracker->addVsyncTimestamp(timestamp); }
+ bool addVsyncTimestamp(nsecs_t timestamp) final {
+ return mTracker->addVsyncTimestamp(timestamp);
+ }
nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const final {
return mTracker->nextAnticipatedVSyncTimeFrom(timePoint);
}
@@ -239,6 +242,22 @@
EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(mDummyTime)));
}
+TEST_F(VSyncReactorTest, ignoresProperlyAfterAPeriodConfirmation) {
+ bool periodFlushed = true;
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(2);
+ mReactor.setIgnorePresentFences(true);
+
+ nsecs_t const newPeriod = 5000;
+ mReactor.setPeriod(newPeriod);
+
+ EXPECT_TRUE(mReactor.addResyncSample(0, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+ EXPECT_FALSE(mReactor.addResyncSample(newPeriod, &periodFlushed));
+ EXPECT_TRUE(periodFlushed);
+
+ EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
+}
+
TEST_F(VSyncReactorTest, queriesTrackerForNextRefreshNow) {
nsecs_t const fakeTimestamp = 4839;
EXPECT_CALL(*mMockTracker, currentPeriod()).Times(0);
@@ -330,6 +349,35 @@
EXPECT_TRUE(periodFlushed);
}
+TEST_F(VSyncReactorTest, reportedBadTimestampFromPredictorWillReactivateHwVSync) {
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_))
+ .WillOnce(Return(false))
+ .WillOnce(Return(true))
+ .WillOnce(Return(true));
+ EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
+ EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
+
+ nsecs_t skewyPeriod = period >> 1;
+ bool periodFlushed = false;
+ nsecs_t sampleTime = 0;
+ EXPECT_TRUE(mReactor.addResyncSample(sampleTime += skewyPeriod, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+ EXPECT_FALSE(mReactor.addResyncSample(sampleTime += period, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+}
+
+TEST_F(VSyncReactorTest, reportedBadTimestampFromPredictorWillReactivateHwVSyncPendingFence) {
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_))
+ .Times(2)
+ .WillOnce(Return(false))
+ .WillOnce(Return(true));
+
+ auto fence = generatePendingFence();
+ EXPECT_FALSE(mReactor.addPresentFence(fence));
+ signalFenceWithTime(fence, period >> 1);
+ EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
+}
+
TEST_F(VSyncReactorTest, presentFenceAdditionDoesNotInterruptConfirmationProcess) {
nsecs_t const newPeriod = 5000;
mReactor.setPeriod(newPeriod);
diff --git a/services/surfaceflinger/tests/unittests/libsurfaceflinger_unittest.filter b/services/surfaceflinger/tests/unittests/libsurfaceflinger_unittest.filter
new file mode 100644
index 0000000..8e9c3cf
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/libsurfaceflinger_unittest.filter
@@ -0,0 +1,6 @@
+{
+ // TODO(b/148517641): re-enable once this test is fixed
+ "presubmit": {
+ "filter": "*:-FrameTracerTest.*"
+ }
+}
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 90a73e2..a7ec4ae 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -164,6 +164,11 @@
"ro.board.platform",
}};
+// LoadDriver returns:
+// * 0 when succeed, or
+// * -ENOENT when fail to open binary libraries, or
+// * -EINVAL when fail to find HAL_MODULE_INFO_SYM_AS_STR or
+// HWVULKAN_HARDWARE_MODULE_ID in the library.
int LoadDriver(android_namespace_t* library_namespace,
const hwvulkan_module_t** module) {
ATRACE_CALL();
@@ -221,7 +226,13 @@
return -ENOENT;
android::GraphicsEnv::getInstance().setDriverToLoad(
android::GpuStatsInfo::Driver::VULKAN_UPDATED);
- return LoadDriver(ns, module);
+ int result = LoadDriver(ns, module);
+ if (result != 0) {
+ LOG_ALWAYS_FATAL(
+ "couldn't find an updated Vulkan implementation from %s",
+ android::GraphicsEnv::getInstance().getDriverPath().c_str());
+ }
+ return result;
}
bool Hal::Open() {