Merge "libui: print more fence information when fence is timeout"
diff --git a/build/phone-xhdpi-2048-dalvik-heap.mk b/build/phone-xhdpi-2048-dalvik-heap.mk
index 042a6e6..7ccfc13 100644
--- a/build/phone-xhdpi-2048-dalvik-heap.mk
+++ b/build/phone-xhdpi-2048-dalvik-heap.mk
@@ -14,7 +14,7 @@
# limitations under the License.
#
-# Provides overrides to configure the Dalvik heap for a 2G phone
+# Provides overrides to configure the Dalvik heap for a 2GB phone
# 192m of RAM gives enough space for 5 8 megapixel camera bitmaps in RAM.
PRODUCT_PROPERTY_OVERRIDES += \
diff --git a/build/phone-xhdpi-4096-dalvik-heap.mk b/build/phone-xhdpi-4096-dalvik-heap.mk
new file mode 100644
index 0000000..2b84841
--- /dev/null
+++ b/build/phone-xhdpi-4096-dalvik-heap.mk
@@ -0,0 +1,25 @@
+#
+# Copyright 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Provides overrides to configure the Dalvik heap for a 4GB phone
+
+PRODUCT_PROPERTY_OVERRIDES += \
+ dalvik.vm.heapstartsize=8m \
+ dalvik.vm.heapgrowthlimit=192m \
+ dalvik.vm.heapsize=512m \
+ dalvik.vm.heaptargetutilization=0.6 \
+ dalvik.vm.heapminfree=8m \
+ dalvik.vm.heapmaxfree=16m
diff --git a/build/phone-xhdpi-6144-dalvik-heap.mk b/build/phone-xhdpi-6144-dalvik-heap.mk
new file mode 100644
index 0000000..2bacc4a
--- /dev/null
+++ b/build/phone-xhdpi-6144-dalvik-heap.mk
@@ -0,0 +1,25 @@
+#
+# Copyright 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Provides overrides to configure the Dalvik heap for a 6GB phone
+
+PRODUCT_PROPERTY_OVERRIDES += \
+ dalvik.vm.heapstartsize=16m \
+ dalvik.vm.heapgrowthlimit=256m \
+ dalvik.vm.heapsize=512m \
+ dalvik.vm.heaptargetutilization=0.5 \
+ dalvik.vm.heapminfree=8m \
+ dalvik.vm.heapmaxfree=32m
diff --git a/cmds/idlcli/Android.bp b/cmds/idlcli/Android.bp
index 5476319..08a31c1 100644
--- a/cmds/idlcli/Android.bp
+++ b/cmds/idlcli/Android.bp
@@ -20,15 +20,16 @@
"android.hardware.vibrator@1.2",
"android.hardware.vibrator@1.3",
"libbase",
- "libbinder",
+ "libbinder_ndk",
"libhidlbase",
"liblog",
"libutils",
- "vintf-vibrator-cpp",
+ "vintf-vibrator-ndk_platform",
],
cflags: [
"-DLOG_TAG=\"idlcli\"",
],
+ vendor_available: true,
}
cc_library {
diff --git a/cmds/idlcli/vibrator.h b/cmds/idlcli/vibrator.h
index 2f11923..ca5142d 100644
--- a/cmds/idlcli/vibrator.h
+++ b/cmds/idlcli/vibrator.h
@@ -13,13 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
#ifndef FRAMEWORK_NATIVE_CMDS_IDLCLI_VIBRATOR_H_
#define FRAMEWORK_NATIVE_CMDS_IDLCLI_VIBRATOR_H_
+#include <aidl/android/hardware/vibrator/IVibrator.h>
+#include <android/binder_manager.h>
#include <android/hardware/vibrator/1.3/IVibrator.h>
-#include <android/hardware/vibrator/IVibrator.h>
-#include <binder/IServiceManager.h>
#include "utils.h"
@@ -39,22 +38,27 @@
}
template <>
-inline binder::Status NullptrStatus() {
- using binder::Status;
- return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+inline ndk::ScopedAStatus NullptrStatus() {
+ return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_NULL_POINTER));
}
template <typename I>
-inline sp<I> getService() {
+inline auto getService() {
return I::getService();
}
template <>
-inline sp<hardware::vibrator::IVibrator> getService() {
- return waitForVintfService<hardware::vibrator::IVibrator>();
+inline auto getService<aidl::android::hardware::vibrator::IVibrator>() {
+ const auto instance =
+ std::string() + aidl::android::hardware::vibrator::IVibrator::descriptor + "/default";
+ auto vibBinder = ndk::SpAIBinder(AServiceManager_getService(instance.c_str()));
+ return aidl::android::hardware::vibrator::IVibrator::fromBinder(vibBinder);
}
template <typename I>
+using shared_ptr = std::result_of_t<decltype(getService<I>)&()>;
+
+template <typename I>
class HalWrapper {
public:
static std::unique_ptr<HalWrapper> Create() {
@@ -70,10 +74,10 @@
}
private:
- HalWrapper(sp<I>&& hal) : mHal(std::move(hal)) {}
+ HalWrapper(shared_ptr<I>&& hal) : mHal(std::move(hal)) {}
private:
- sp<I> mHal;
+ shared_ptr<I> mHal;
};
template <typename I>
@@ -95,7 +99,7 @@
namespace V1_1 = ::android::hardware::vibrator::V1_1;
namespace V1_2 = ::android::hardware::vibrator::V1_2;
namespace V1_3 = ::android::hardware::vibrator::V1_3;
-namespace aidl = ::android::hardware::vibrator;
+namespace aidl = ::aidl::android::hardware::vibrator;
} // namespace vibrator
} // namespace idlcli
diff --git a/cmds/idlcli/vibrator/CommandCompose.cpp b/cmds/idlcli/vibrator/CommandCompose.cpp
index 705e40b..4721a5f 100644
--- a/cmds/idlcli/vibrator/CommandCompose.cpp
+++ b/cmds/idlcli/vibrator/CommandCompose.cpp
@@ -80,7 +80,7 @@
Status ret;
if (auto hal = getHal<aidl::IVibrator>()) {
auto status = hal->call(&aidl::IVibrator::compose, mComposite, nullptr);
- statusStr = status.toString8();
+ statusStr = status.getDescription();
ret = status.isOk() ? OK : ERROR;
} else {
return UNAVAILABLE;
diff --git a/cmds/idlcli/vibrator/CommandGetCapabilities.cpp b/cmds/idlcli/vibrator/CommandGetCapabilities.cpp
index 30d8587..303a989 100644
--- a/cmds/idlcli/vibrator/CommandGetCapabilities.cpp
+++ b/cmds/idlcli/vibrator/CommandGetCapabilities.cpp
@@ -48,7 +48,7 @@
if (auto hal = getHal<aidl::IVibrator>()) {
auto status = hal->call(&aidl::IVibrator::getCapabilities, &cap);
- statusStr = status.toString8();
+ statusStr = status.getDescription();
ret = status.isOk() ? OK : ERROR;
} else {
return UNAVAILABLE;
diff --git a/cmds/idlcli/vibrator/CommandGetCompositionDelayMax.cpp b/cmds/idlcli/vibrator/CommandGetCompositionDelayMax.cpp
index b414307..10508bd 100644
--- a/cmds/idlcli/vibrator/CommandGetCompositionDelayMax.cpp
+++ b/cmds/idlcli/vibrator/CommandGetCompositionDelayMax.cpp
@@ -50,7 +50,7 @@
if (auto hal = getHal<aidl::IVibrator>()) {
auto status = hal->call(&aidl::IVibrator::getCompositionDelayMax, &maxDelayMs);
- statusStr = status.toString8();
+ statusStr = status.getDescription();
ret = status.isOk() ? OK : ERROR;
} else {
return UNAVAILABLE;
diff --git a/cmds/idlcli/vibrator/CommandGetCompositionSizeMax.cpp b/cmds/idlcli/vibrator/CommandGetCompositionSizeMax.cpp
index 360fc9d..900cb18 100644
--- a/cmds/idlcli/vibrator/CommandGetCompositionSizeMax.cpp
+++ b/cmds/idlcli/vibrator/CommandGetCompositionSizeMax.cpp
@@ -50,7 +50,7 @@
if (auto hal = getHal<aidl::IVibrator>()) {
auto status = hal->call(&aidl::IVibrator::getCompositionSizeMax, &maxSize);
- statusStr = status.toString8();
+ statusStr = status.getDescription();
ret = status.isOk() ? OK : ERROR;
} else {
return UNAVAILABLE;
diff --git a/cmds/idlcli/vibrator/CommandOff.cpp b/cmds/idlcli/vibrator/CommandOff.cpp
index 53fada0..cedb9fe 100644
--- a/cmds/idlcli/vibrator/CommandOff.cpp
+++ b/cmds/idlcli/vibrator/CommandOff.cpp
@@ -47,7 +47,7 @@
if (auto hal = getHal<aidl::IVibrator>()) {
auto status = hal->call(&aidl::IVibrator::off);
- statusStr = status.toString8();
+ statusStr = status.getDescription();
ret = status.isOk() ? OK : ERROR;
} else if (auto hal = getHal<V1_0::IVibrator>()) {
auto status = hal->call(&V1_0::IVibrator::off);
diff --git a/cmds/idlcli/vibrator/CommandOn.cpp b/cmds/idlcli/vibrator/CommandOn.cpp
index ccb3c19..4e7e493 100644
--- a/cmds/idlcli/vibrator/CommandOn.cpp
+++ b/cmds/idlcli/vibrator/CommandOn.cpp
@@ -55,7 +55,7 @@
if (auto hal = getHal<aidl::IVibrator>()) {
auto status = hal->call(&aidl::IVibrator::on, mDuration, nullptr);
- statusStr = status.toString8();
+ statusStr = status.getDescription();
ret = status.isOk() ? OK : ERROR;
} else if (auto hal = getHal<V1_0::IVibrator>()) {
auto status = hal->call(&V1_0::IVibrator::on, mDuration);
diff --git a/cmds/idlcli/vibrator/CommandPerform.cpp b/cmds/idlcli/vibrator/CommandPerform.cpp
index 58d4e0a..69c7e37 100644
--- a/cmds/idlcli/vibrator/CommandPerform.cpp
+++ b/cmds/idlcli/vibrator/CommandPerform.cpp
@@ -99,7 +99,7 @@
auto status =
hal->call(&aidl::IVibrator::perform, static_cast<aidl::Effect>(mEffect),
static_cast<aidl::EffectStrength>(mStrength), nullptr, &aidlLengthMs);
- statusStr = status.toString8();
+ statusStr = status.getDescription();
lengthMs = static_cast<uint32_t>(aidlLengthMs);
ret = status.isOk() ? OK : ERROR;
} else {
diff --git a/cmds/idlcli/vibrator/CommandSetAmplitude.cpp b/cmds/idlcli/vibrator/CommandSetAmplitude.cpp
index 33d7eed..8b8058c 100644
--- a/cmds/idlcli/vibrator/CommandSetAmplitude.cpp
+++ b/cmds/idlcli/vibrator/CommandSetAmplitude.cpp
@@ -56,7 +56,7 @@
if (auto hal = getHal<aidl::IVibrator>()) {
auto status = hal->call(&aidl::IVibrator::setAmplitude,
static_cast<float>(mAmplitude) / UINT8_MAX);
- statusStr = status.toString8();
+ statusStr = status.getDescription();
ret = status.isOk() ? OK : ERROR;
} else if (auto hal = getHal<V1_0::IVibrator>()) {
auto status = hal->call(&V1_0::IVibrator::setAmplitude, mAmplitude);
diff --git a/cmds/idlcli/vibrator/CommandSetExternalControl.cpp b/cmds/idlcli/vibrator/CommandSetExternalControl.cpp
index 5bc827e..1795793 100644
--- a/cmds/idlcli/vibrator/CommandSetExternalControl.cpp
+++ b/cmds/idlcli/vibrator/CommandSetExternalControl.cpp
@@ -53,7 +53,7 @@
if (auto hal = getHal<aidl::IVibrator>()) {
auto status = hal->call(&aidl::IVibrator::setExternalControl, mEnable);
- statusStr = status.toString8();
+ statusStr = status.getDescription();
ret = status.isOk() ? OK : ERROR;
} else if (auto hal = getHal<V1_3::IVibrator>()) {
auto status = hal->call(&V1_3::IVibrator::setExternalControl, mEnable);
diff --git a/cmds/installd/.gitignore b/cmds/installd/.gitignore
new file mode 100644
index 0000000..abc921c
--- /dev/null
+++ b/cmds/installd/.gitignore
@@ -0,0 +1,2 @@
+# ignore the files generated by intellij
+.idea
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 75dec37..8ff4dd8 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -13,6 +13,7 @@
srcs: [
"CacheItem.cpp",
"CacheTracker.cpp",
+ "CrateManager.cpp",
"InstalldNativeService.cpp",
"QuotaUtils.cpp",
"dexopt.cpp",
@@ -163,6 +164,7 @@
name: "installd_aidl",
srcs: [
"binder/android/os/IInstalld.aidl",
+ "binder/android/os/storage/CrateMetadata.aidl",
],
path: "binder",
}
diff --git a/cmds/installd/CrateManager.cpp b/cmds/installd/CrateManager.cpp
new file mode 100644
index 0000000..344aefb
--- /dev/null
+++ b/cmds/installd/CrateManager.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CrateManager.h"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android/log.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/xattr.h>
+#include <unistd.h>
+
+#include <fstream>
+#include <string>
+#include <utils.h>
+
+#include "utils.h"
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace installd {
+
+CrateManager::CrateManager(const char* uuid, userid_t userId, const std::string& packageName) {
+ mPackageName = packageName;
+ mRoot = create_data_user_ce_package_path(uuid, userId, (const char*)packageName.c_str());
+ mCratedFoldersRoot = StringPrintf("%s/crates", mRoot.c_str());
+}
+
+CrateManager::~CrateManager() {}
+
+static std::string getValidatedCratedPath(std::string path) {
+ size_t pos = path.rfind("/");
+ if (pos == std::string::npos) {
+ return path;
+ }
+
+ return path.substr(pos + 1, path.length());
+}
+
+void CrateManager::traverseChildDir(const std::string& targetDir,
+ std::function<void(FTSENT*)>& onVisitChildDir) {
+ char* argv[] = {(char*)targetDir.c_str(), nullptr};
+ FTS* fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr);
+ if (fts == nullptr) {
+ PLOG(WARNING) << "Failed to fts_open " << targetDir;
+ return;
+ }
+
+ FTSENT* p;
+ while ((p = fts_read(fts)) != nullptr) {
+ switch (p->fts_info) {
+ case FTS_D:
+ if (p->fts_level == 1) {
+ onVisitChildDir(p);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (p->fts_level == 1) {
+ fts_set(fts, p, FTS_SKIP);
+ }
+ }
+ fts_close(fts);
+}
+
+void CrateManager::traverseAllPackagesForUser(
+ const std::unique_ptr<std::string>& uuid, userid_t userId,
+ std::function<void(FTSENT*)>& onHandlingPackage) {
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+
+ auto ce_path = create_data_user_ce_path(uuid_, userId);
+ traverseChildDir(ce_path, onHandlingPackage);
+}
+
+void CrateManager::createCrate(
+ CratedFolder cratedFolder,
+ std::function<void(CratedFolder, std::unique_ptr<CrateMetadata>&)>& onCreateCrate) {
+ const char* path = cratedFolder->fts_path;
+ if (path == nullptr || *path == '\0') {
+ return;
+ }
+
+ std::unique_ptr<CrateMetadata> crateMetadata = std::make_unique<CrateMetadata>();
+ crateMetadata->uid = cratedFolder->fts_statp->st_uid;
+ crateMetadata->packageName = mPackageName;
+ crateMetadata->id = getValidatedCratedPath(path);
+
+ onCreateCrate(cratedFolder, crateMetadata);
+}
+
+void CrateManager::traverseAllCrates(std::function<void(CratedFolder, std::unique_ptr<CrateMetadata>&)>& onCreateCrate) {
+ std::function<void(FTSENT*)> onVisitCrateDir = [&](FTSENT* cratedFolder) -> void {
+ createCrate(cratedFolder, onCreateCrate);
+ };
+ traverseChildDir(mCratedFoldersRoot, onVisitCrateDir);
+}
+
+#if CRATE_DEBUG
+void CrateManager::dump(std::unique_ptr<CrateMetadata>& CrateMetadata) {
+ LOG(DEBUG) << "CrateMetadata = {"
+ << "uid : \"" << CrateMetadata->uid
+ << "\", packageName : \"" << CrateMetadata->packageName
+ << "\", id : \"" << CrateMetadata->id
+ << "\"}";
+}
+#endif
+
+} // namespace installd
+} // namespace android
diff --git a/cmds/installd/CrateManager.h b/cmds/installd/CrateManager.h
new file mode 100644
index 0000000..1776622
--- /dev/null
+++ b/cmds/installd/CrateManager.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_INSTALLD_CRATE_INFO_MANAGER_H
+#define ANDROID_INSTALLD_CRATE_INFO_MANAGER_H
+
+#include <android/os/storage/CrateMetadata.h>
+#include <cutils/multiuser.h>
+#include <fts.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#ifndef CRATE_DEBUG
+#define CRATE_DEBUG 1
+#endif
+
+namespace android {
+namespace installd {
+
+using android::os::storage::CrateMetadata;
+
+/**
+ * The crated folder actually is a folder that is the first level child director. In order to
+ * distingish between the crated folder and the other FTSENT*, to define the type "CratedFolder"
+ * make the code easy to identify the difference.
+ */
+typedef FTSENT* CratedFolder;
+
+/**
+ * In order to give the users more fine-grained files controlling, the crate information can help
+ * applications' developers to show the more detail information to the users. The crate information
+ * include the Label, Expiration etc..
+ */
+class CrateManager {
+public:
+ CrateManager(const char* uuid, userid_t userId, const std::string& packageName);
+ ~CrateManager();
+
+ void traverseAllCrates(std::function<void(CratedFolder, std::unique_ptr<CrateMetadata>&)>& onCreateCrate);
+
+ static void traverseChildDir(const std::string& targetDir,
+ std::function<void(FTSENT*)>& onVisitChildDir);
+
+ static void traverseAllPackagesForUser(
+ const std::unique_ptr<std::string>& uuid,
+ userid_t userId,
+ std::function<void(FTSENT*)>& onHandlingPackage);
+
+#if CRATE_DEBUG
+ static void dump(std::unique_ptr<CrateMetadata>& CrateMetadata);
+#endif
+private:
+ std::string mRoot;
+ std::string mCratedFoldersRoot;
+ std::string mPackageName;
+
+ void createCrate(
+ CratedFolder cratedFolder,
+ std::function<void(CratedFolder, std::unique_ptr<CrateMetadata>&)>& onCreateCrate);
+};
+
+} // namespace installd
+} // namespace android
+
+#endif // ANDROID_INSTALLD_CRATE_INFO_MANAGER_H
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 72b9850..f8a68b4 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -66,6 +66,7 @@
#include "view_compiler.h"
#include "CacheTracker.h"
+#include "CrateManager.h"
#include "MatchExtensionGen.h"
#include "QuotaUtils.h"
@@ -2045,6 +2046,82 @@
return ok();
}
+binder::Status InstalldNativeService::getAppCrates(
+ const std::unique_ptr<std::string>& uuid,
+ const std::vector<std::string>& packageNames, int32_t userId,
+ std::unique_ptr<std::vector<std::unique_ptr<CrateMetadata>>>* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ for (const auto& packageName : packageNames) {
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ }
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ auto retVector = std::make_unique<std::vector<std::unique_ptr<CrateMetadata>>>();
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+
+ std::function<void(CratedFolder, std::unique_ptr<CrateMetadata> &)> onCreateCrate =
+ [&](CratedFolder cratedFolder, std::unique_ptr<CrateMetadata> &crateMetadata) -> void {
+ if (cratedFolder == nullptr) {
+ return;
+ }
+ retVector->push_back(std::move(crateMetadata));
+ };
+
+ for (const auto& packageName : packageNames) {
+#if CRATE_DEBUG
+ LOG(DEBUG) << "packageName = " << packageName;
+#endif
+ auto crateManager = std::make_unique<CrateManager>(uuid_, userId, packageName);
+ crateManager->traverseAllCrates(onCreateCrate);
+ }
+
+#if CRATE_DEBUG
+ LOG(WARNING) << "retVector->size() =" << retVector->size();
+ for (auto iter = retVector->begin(); iter != retVector->end(); ++iter) {
+ CrateManager::dump(*iter);
+ }
+#endif
+
+ *_aidl_return = std::move(retVector);
+ return ok();
+}
+
+binder::Status InstalldNativeService::getUserCrates(
+ const std::unique_ptr<std::string>& uuid, int32_t userId,
+ std::unique_ptr<std::vector<std::unique_ptr<CrateMetadata>>>* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+ auto retVector = std::make_unique<std::vector<std::unique_ptr<CrateMetadata>>>();
+
+ std::function<void(CratedFolder, std::unique_ptr<CrateMetadata> &)> onCreateCrate =
+ [&](CratedFolder cratedFolder, std::unique_ptr<CrateMetadata> &crateMetadata) -> void {
+ if (cratedFolder == nullptr) {
+ return;
+ }
+ retVector->push_back(std::move(crateMetadata));
+ };
+
+ std::function<void(FTSENT*)> onHandingPackage = [&](FTSENT* packageDir) -> void {
+ auto crateManager = std::make_unique<CrateManager>(uuid_, userId, packageDir->fts_name);
+ crateManager->traverseAllCrates(onCreateCrate);
+ };
+ CrateManager::traverseAllPackagesForUser(uuid, userId, onHandingPackage);
+
+#if CRATE_DEBUG
+ LOG(DEBUG) << "retVector->size() =" << retVector->size();
+ for (auto iter = retVector->begin(); iter != retVector->end(); ++iter) {
+ CrateManager::dump(*iter);
+ }
+#endif
+
+ *_aidl_return = std::move(retVector);
+ return ok();
+}
+
binder::Status InstalldNativeService::setAppQuota(const std::unique_ptr<std::string>& uuid,
int32_t userId, int32_t appId, int64_t cacheQuota) {
ENFORCE_UID(AID_SYSTEM);
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index daacd26..bf11002 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -81,6 +81,16 @@
int32_t userId, int32_t flags, const std::vector<int32_t>& appIds,
std::vector<int64_t>* _aidl_return);
+ binder::Status getAppCrates(const std::unique_ptr<std::string>& uuid,
+ const std::vector<std::string>& packageNames,
+ int32_t userId,
+ std::unique_ptr<std::vector<std::unique_ptr<android::os::storage::CrateMetadata>>>*
+ _aidl_return);
+ binder::Status getUserCrates(
+ const std::unique_ptr<std::string>& uuid, int32_t userId,
+ std::unique_ptr<std::vector<std::unique_ptr<android::os::storage::CrateMetadata>>>*
+ _aidl_return);
+
binder::Status setAppQuota(const std::unique_ptr<std::string>& uuid,
int32_t userId, int32_t appId, int64_t cacheQuota);
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index fda6559..891b26d 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -40,6 +40,14 @@
long[] getUserSize(@nullable @utf8InCpp String uuid, int userId, int flags, in int[] appIds);
long[] getExternalSize(@nullable @utf8InCpp String uuid, int userId, int flags, in int[] appIds);
+ @nullable
+ android.os.storage.CrateMetadata[] getAppCrates(
+ @nullable @utf8InCpp String uuid, in @utf8InCpp String[] packageNames,
+ int userId);
+ @nullable
+ android.os.storage.CrateMetadata[] getUserCrates(
+ @nullable @utf8InCpp String uuid, int userId);
+
void setAppQuota(@nullable @utf8InCpp String uuid, int userId, int appId, long cacheQuota);
void moveCompleteApp(@nullable @utf8InCpp String fromUuid, @nullable @utf8InCpp String toUuid,
diff --git a/cmds/installd/binder/android/os/storage/CrateMetadata.aidl b/cmds/installd/binder/android/os/storage/CrateMetadata.aidl
new file mode 100644
index 0000000..bd6d12d
--- /dev/null
+++ b/cmds/installd/binder/android/os/storage/CrateMetadata.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.os.storage;
+
+/** {@hide} */
+parcelable CrateMetadata {
+ /**
+ * To tell which uid the crate belong to.
+ * <p>Because installd query all of crates in specified userId, the install may return the list
+ * whose elements have the same crate id but different uid and package name.
+ * It needs to tell the caller the difference between these elements.
+ */
+ int uid;
+
+ /**
+ * To tell which the package the crate belong to.
+ * <p>Because installd query all of crates in specified uid, the install may return the list
+ * whose elements have the same uid and crate id but different package name.
+ * It needs to tell the caller the difference between these elements.
+ */
+ @utf8InCpp String packageName;
+
+ /**
+ * To tell the crate id that is the child directory/folder name in crates
+ * root.
+ */
+ @utf8InCpp String id;
+}
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 4eb1df0..6012822 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -278,6 +278,15 @@
return "/data/dalvik-cache";
}
+std::string create_system_user_ce_path(userid_t userId) {
+ return StringPrintf("%s/system_ce/%u", create_data_path(nullptr).c_str(), userId);
+}
+
+std::string create_system_user_ce_package_path(userid_t userId, const char* package_name) {
+ check_package_name(package_name);
+ return StringPrintf("%s/%s", create_system_user_ce_path(userId).c_str(), package_name);
+}
+
// Keep profile paths in sync with ActivityThread and LoadedApk.
const std::string PROFILE_EXT = ".prof";
const std::string CURRENT_PROFILE_EXT = ".cur";
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 6a42026..6a39adc 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -82,6 +82,10 @@
std::string create_data_dalvik_cache_path();
+std::string create_system_user_ce_path(userid_t userId);
+
+std::string create_system_user_ce_package_path(userid_t userId, const char* package_name);
+
std::string create_primary_cur_profile_dir_path(userid_t userid);
std::string create_primary_current_profile_package_dir_path(
userid_t user, const std::string& package_name);
diff --git a/data/etc/android.hardware.reboot_escrow.xml b/data/etc/android.hardware.reboot_escrow.xml
new file mode 100644
index 0000000..5db9f4c
--- /dev/null
+++ b/data/etc/android.hardware.reboot_escrow.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!--
+ This is the feature indicating that the device has support for the
+ RebootEscrow HAL.
+-->
+
+<permissions>
+ <feature name="android.hardware.reboot_escrow" />
+</permissions>
diff --git a/include/android/configuration.h b/include/android/configuration.h
index 3310722..05f4340 100644
--- a/include/android/configuration.h
+++ b/include/android/configuration.h
@@ -645,10 +645,14 @@
*/
void AConfiguration_setScreenLong(AConfiguration* config, int32_t screenLong);
+#if __ANDROID_API__ >= 30
/**
* Return the current ACONFIGURATION_SCREENROUND_* set in the configuration.
+ *
+ * Available since API level 30.
*/
-int32_t AConfiguration_getScreenRound(AConfiguration* config);
+int32_t AConfiguration_getScreenRound(AConfiguration* config) __INTRODUCED_IN(30);
+#endif
/**
* Set the current screen round in the configuration.
diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp
index 4f0b7d3..ca9c608 100644
--- a/libs/binder/AppOpsManager.cpp
+++ b/libs/binder/AppOpsManager.cpp
@@ -44,16 +44,16 @@
} // namespace
static String16 _appops("appops");
-static pthread_mutex_t gTokenMutex = PTHREAD_MUTEX_INITIALIZER;
-static sp<IBinder> gToken;
+static pthread_mutex_t gClientIdMutex = PTHREAD_MUTEX_INITIALIZER;
+static sp<IBinder> gClientId;
-static const sp<IBinder>& getToken(const sp<IAppOpsService>& service) {
- pthread_mutex_lock(&gTokenMutex);
- if (gToken == nullptr || gToken->pingBinder() != NO_ERROR) {
- gToken = service->getToken(new BBinder());
+static const sp<IBinder>& getClientId() {
+ pthread_mutex_lock(&gClientIdMutex);
+ if (gClientId == nullptr) {
+ gClientId = new BBinder();
}
- pthread_mutex_unlock(&gTokenMutex);
- return gToken;
+ pthread_mutex_unlock(&gClientIdMutex);
+ return gClientId;
}
thread_local uint64_t notedAppOpsInThisBinderTransaction[2];
@@ -144,7 +144,7 @@
const String16& message) {
sp<IAppOpsService> service = getService();
int32_t mode = service != nullptr
- ? service->startOperation(getToken(service), op, uid, callingPackage,
+ ? service->startOperation(getClientId(), op, uid, callingPackage,
featureId, startIfModeDefault) : APP_OPS_MANAGER_UNAVAILABLE_MODE;
if (mode == AppOpsManager::MODE_ALLOWED) {
@@ -162,7 +162,7 @@
const std::unique_ptr<String16>& callingFeatureId) {
sp<IAppOpsService> service = getService();
if (service != nullptr) {
- service->finishOperation(getToken(service), op, uid, callingPackage, callingFeatureId);
+ service->finishOperation(getClientId(), op, uid, callingPackage, callingFeatureId);
}
}
diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp
index b85a5f2..7384466 100644
--- a/libs/binder/IAppOpsService.cpp
+++ b/libs/binder/IAppOpsService.cpp
@@ -106,16 +106,6 @@
remote()->transact(STOP_WATCHING_MODE_TRANSACTION, data, &reply);
}
- virtual sp<IBinder> getToken(const sp<IBinder>& clientToken) {
- Parcel data, reply;
- data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
- data.writeStrongBinder(clientToken);
- remote()->transact(GET_TOKEN_TRANSACTION, data, &reply);
- // fail on exception
- if (reply.readExceptionCode() != 0) return nullptr;
- return reply.readStrongBinder();
- }
-
virtual int32_t permissionToOpCode(const String16& permission) {
Parcel data, reply;
data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
@@ -251,14 +241,6 @@
reply->writeNoException();
return NO_ERROR;
} break;
- case GET_TOKEN_TRANSACTION: {
- CHECK_INTERFACE(IAppOpsService, data, reply);
- sp<IBinder> clientToken = data.readStrongBinder();
- sp<IBinder> token = getToken(clientToken);
- reply->writeNoException();
- reply->writeStrongBinder(token);
- return NO_ERROR;
- } break;
case PERMISSION_TO_OP_CODE_TRANSACTION: {
CHECK_INTERFACE(IAppOpsService, data, reply);
String16 permission = data.readString16();
diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h
index 15ba005..68a917e 100644
--- a/libs/binder/include/binder/IAppOpsService.h
+++ b/libs/binder/include/binder/IAppOpsService.h
@@ -45,7 +45,6 @@
virtual void startWatchingMode(int32_t op, const String16& packageName,
const sp<IAppOpsCallback>& callback) = 0;
virtual void stopWatchingMode(const sp<IAppOpsCallback>& callback) = 0;
- virtual sp<IBinder> getToken(const sp<IBinder>& clientToken) = 0;
virtual int32_t permissionToOpCode(const String16& permission) = 0;
virtual int32_t checkAudioOperation(int32_t code, int32_t usage,int32_t uid,
const String16& packageName) = 0;
@@ -62,12 +61,11 @@
FINISH_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+3,
START_WATCHING_MODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+4,
STOP_WATCHING_MODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+5,
- GET_TOKEN_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+6,
- PERMISSION_TO_OP_CODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+7,
- CHECK_AUDIO_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+8,
- NOTE_ASYNC_OP_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+9,
- SHOULD_COLLECT_NOTES_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+10,
- SET_CAMERA_AUDIO_RESTRICTION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+11,
+ PERMISSION_TO_OP_CODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+6,
+ CHECK_AUDIO_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+7,
+ NOTE_ASYNC_OP_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+8,
+ SHOULD_COLLECT_NOTES_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+9,
+ SET_CAMERA_AUDIO_RESTRICTION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+10,
};
enum {
diff --git a/libs/gralloc/types/Gralloc4.cpp b/libs/gralloc/types/Gralloc4.cpp
index b762f1e..d02e839 100644
--- a/libs/gralloc/types/Gralloc4.cpp
+++ b/libs/gralloc/types/Gralloc4.cpp
@@ -28,6 +28,7 @@
using aidl::android::hardware::graphics::common::BlendMode;
using aidl::android::hardware::graphics::common::ChromaSiting;
using aidl::android::hardware::graphics::common::Compression;
+using aidl::android::hardware::graphics::common::Cta861_3;
using aidl::android::hardware::graphics::common::Dataspace;
using aidl::android::hardware::graphics::common::ExtendableType;
using aidl::android::hardware::graphics::common::Interlaced;
@@ -35,7 +36,9 @@
using aidl::android::hardware::graphics::common::PlaneLayoutComponent;
using aidl::android::hardware::graphics::common::PlaneLayoutComponentType;
using aidl::android::hardware::graphics::common::Rect;
+using aidl::android::hardware::graphics::common::Smpte2086;
using aidl::android::hardware::graphics::common::StandardMetadataType;
+using aidl::android::hardware::graphics::common::XyColor;
using MetadataType = android::hardware::graphics::mapper::V4_0::IMapper::MetadataType;
@@ -154,6 +157,13 @@
return mVec->size() > mOffset;
}
+ size_t getRemainingSize() {
+ if (!mVec) {
+ return 0;
+ }
+ return mVec->size() - mOffset;
+ }
+
private:
const hidl_vec<uint8_t>* mVec;
size_t mOffset = 0;
@@ -218,6 +228,15 @@
return encodeHelper(input, &outputHidlVec);
}
+template <class T>
+status_t encodeOptional(const MetadataType& metadataType, const std::optional<T>& input,
+ hidl_vec<uint8_t>* output, EncodeHelper<T> encodeHelper) {
+ if (!input) {
+ return NO_ERROR;
+ }
+ return encode(metadataType, *input, output, encodeHelper);
+}
+
/**
* decode is the main decode function. It takes in a hidl_vec and uses the decodeHelper function to
* turn the hidl_vec byte stream into T. If an error occurs, the errorHandler function cleans up
@@ -249,13 +268,32 @@
return NO_ERROR;
}
+template <class T>
+status_t decodeOptional(const MetadataType& metadataType, const hidl_vec<uint8_t>& input,
+ std::optional<T>* output, DecodeHelper<T> decodeHelper) {
+ if (!output) {
+ return BAD_VALUE;
+ }
+ if (input.size() <= 0) {
+ output->reset();
+ return NO_ERROR;
+ }
+ T tmp;
+ status_t err = decode(metadataType, input, &tmp, decodeHelper);
+ if (!err) {
+ *output = tmp;
+ }
+ return err;
+}
+
/**
* Private helper functions
*/
template <class T>
status_t encodeInteger(const T& input, OutputHidlVec* output) {
static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
- std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value);
+ std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
+ std::is_same<T, float>::value || std::is_same<T, double>::value);
if (!output) {
return BAD_VALUE;
}
@@ -267,7 +305,8 @@
template <class T>
status_t decodeInteger(InputHidlVec* input, T* output) {
static_assert(std::is_same<T, uint32_t>::value || std::is_same<T, int32_t>::value ||
- std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value);
+ std::is_same<T, uint64_t>::value || std::is_same<T, int64_t>::value ||
+ std::is_same<T, float>::value || std::is_same<T, double>::value);
if (!output) {
return BAD_VALUE;
}
@@ -306,6 +345,38 @@
return input->decode(output, size);
}
+status_t encodeByteVector(const std::vector<uint8_t>& input, OutputHidlVec* output) {
+ if (!output) {
+ return BAD_VALUE;
+ }
+
+ status_t err = encodeInteger<int64_t>(input.size(), output);
+ if (err) {
+ return err;
+ }
+
+ return output->encode(input.data(), input.size());
+}
+
+status_t decodeByteVector(InputHidlVec* input, std::vector<uint8_t>* output) {
+ if (!output) {
+ return BAD_VALUE;
+ }
+
+ int64_t size = 0;
+ status_t err = decodeInteger<int64_t>(input, &size);
+ if (err || size < 0) {
+ return err;
+ }
+
+ if (size > input->getRemainingSize()) {
+ return BAD_VALUE;
+ }
+ output->resize(size);
+
+ return input->decode(output->data(), size);
+}
+
status_t encodeExtendableType(const ExtendableType& input, OutputHidlVec* output) {
status_t err = encodeString(input.name, output);
if (err) {
@@ -391,6 +462,30 @@
return NO_ERROR;
}
+status_t encodeXyColor(const XyColor& input, OutputHidlVec* output) {
+ status_t err = encodeInteger<float>(input.x, output);
+ if (err) {
+ return err;
+ }
+ return encodeInteger<float>(input.y, output);
+}
+
+status_t decodeXyColor(InputHidlVec* input, XyColor* output) {
+ status_t err = decodeInteger<float>(input, &output->x);
+ if (err) {
+ return err;
+ }
+ return decodeInteger<float>(input, &output->y);
+}
+
+void clearXyColor(XyColor* output) {
+ if (!output) {
+ return;
+ }
+ output->x = 0;
+ output->y = 0;
+}
+
status_t encodeRect(const Rect& input, OutputHidlVec* output) {
status_t err = encodeInteger<int32_t>(static_cast<int32_t>(input.left), output);
if (err) {
@@ -635,6 +730,70 @@
output->clear();
}
+status_t encodeSmpte2086Helper(const Smpte2086& smpte2086, OutputHidlVec* outOutputHidlVec) {
+ status_t err = encodeXyColor(smpte2086.primaryRed, outOutputHidlVec);
+ if (err) {
+ return err;
+ }
+ err = encodeXyColor(smpte2086.primaryGreen, outOutputHidlVec);
+ if (err) {
+ return err;
+ }
+ err = encodeXyColor(smpte2086.primaryBlue, outOutputHidlVec);
+ if (err) {
+ return err;
+ }
+ err = encodeXyColor(smpte2086.whitePoint, outOutputHidlVec);
+ if (err) {
+ return err;
+ }
+ err = encodeInteger<float>(smpte2086.maxLuminance, outOutputHidlVec);
+ if (err) {
+ return err;
+ }
+ return encodeInteger<float>(smpte2086.minLuminance, outOutputHidlVec);
+}
+
+status_t decodeSmpte2086Helper(InputHidlVec* inputHidlVec, Smpte2086* outSmpte2086) {
+ status_t err = decodeXyColor(inputHidlVec, &outSmpte2086->primaryRed);
+ if (err) {
+ return err;
+ }
+ err = decodeXyColor(inputHidlVec, &outSmpte2086->primaryGreen);
+ if (err) {
+ return err;
+ }
+ err = decodeXyColor(inputHidlVec, &outSmpte2086->primaryBlue);
+ if (err) {
+ return err;
+ }
+ err = decodeXyColor(inputHidlVec, &outSmpte2086->whitePoint);
+ if (err) {
+ return err;
+ }
+ err = decodeInteger<float>(inputHidlVec, &outSmpte2086->maxLuminance);
+ if (err) {
+ return err;
+ }
+ return decodeInteger<float>(inputHidlVec, &outSmpte2086->minLuminance);
+}
+
+status_t encodeCta861_3Helper(const Cta861_3& cta861_3, OutputHidlVec* outOutputHidlVec) {
+ status_t err = encodeInteger<float>(cta861_3.maxContentLightLevel, outOutputHidlVec);
+ if (err) {
+ return err;
+ }
+ return encodeInteger<float>(cta861_3.maxFrameAverageLightLevel, outOutputHidlVec);
+}
+
+status_t decodeCta861_3Helper(InputHidlVec* inputHidlVec, Cta861_3* outCta861_3) {
+ status_t err = decodeInteger<float>(inputHidlVec, &outCta861_3->maxContentLightLevel);
+ if (err) {
+ return err;
+ }
+ return decodeInteger<float>(inputHidlVec, &outCta861_3->maxFrameAverageLightLevel);
+}
+
/**
* Public API functions
*/
@@ -798,6 +957,36 @@
decodeInteger);
}
+status_t encodeSmpte2086(const std::optional<Smpte2086>& smpte2086,
+ hidl_vec<uint8_t>* outSmpte2086) {
+ return encodeOptional(MetadataType_Smpte2086, smpte2086, outSmpte2086, encodeSmpte2086Helper);
+}
+
+status_t decodeSmpte2086(const hidl_vec<uint8_t>& smpte2086,
+ std::optional<Smpte2086>* outSmpte2086) {
+ return decodeOptional(MetadataType_Smpte2086, smpte2086, outSmpte2086, decodeSmpte2086Helper);
+}
+
+status_t encodeCta861_3(const std::optional<Cta861_3>& cta861_3, hidl_vec<uint8_t>* outCta861_3) {
+ return encodeOptional(MetadataType_Cta861_3, cta861_3, outCta861_3, encodeCta861_3Helper);
+}
+
+status_t decodeCta861_3(const hidl_vec<uint8_t>& cta861_3, std::optional<Cta861_3>* outCta861_3) {
+ return decodeOptional(MetadataType_Cta861_3, cta861_3, outCta861_3, decodeCta861_3Helper);
+}
+
+status_t encodeSmpte2094_40(const std::optional<std::vector<uint8_t>>& smpte2094_40,
+ hidl_vec<uint8_t>* outSmpte2094_40) {
+ return encodeOptional(MetadataType_Smpte2094_40, smpte2094_40, outSmpte2094_40,
+ encodeByteVector);
+}
+
+status_t decodeSmpte2094_40(const hidl_vec<uint8_t>& smpte2094_40,
+ std::optional<std::vector<uint8_t>>* outSmpte2094_40) {
+ return decodeOptional(MetadataType_Smpte2094_40, smpte2094_40, outSmpte2094_40,
+ decodeByteVector);
+}
+
bool isStandardMetadataType(const MetadataType& metadataType) {
return !std::strncmp(metadataType.name.c_str(), GRALLOC4_STANDARD_METADATA_TYPE,
metadataType.name.size());
diff --git a/libs/gralloc/types/fuzzer/gralloctypes.cpp b/libs/gralloc/types/fuzzer/gralloctypes.cpp
index 23c90b8..da8cf97 100644
--- a/libs/gralloc/types/fuzzer/gralloctypes.cpp
+++ b/libs/gralloc/types/fuzzer/gralloctypes.cpp
@@ -60,5 +60,8 @@
GRALLOCTYPES_DECODE(std::vector<aidl::android::hardware::graphics::common::PlaneLayout>, ::android::gralloc4::decodePlaneLayouts),
GRALLOCTYPES_DECODE(aidl::android::hardware::graphics::common::Dataspace, ::android::gralloc4::decodeDataspace),
GRALLOCTYPES_DECODE(aidl::android::hardware::graphics::common::BlendMode, ::android::gralloc4::decodeBlendMode),
+ GRALLOCTYPES_DECODE(std::optional<aidl::android::hardware::graphics::common::Smpte2086>, ::android::gralloc4::decodeSmpte2086),
+ GRALLOCTYPES_DECODE(std::optional<aidl::android::hardware::graphics::common::Cta861_3>, ::android::gralloc4::decodeCta861_3),
+ GRALLOCTYPES_DECODE(std::optional<std::vector<uint8_t>>, ::android::gralloc4::decodeSmpte2094_40),
};
// clang-format on
diff --git a/libs/gralloc/types/include/gralloctypes/Gralloc4.h b/libs/gralloc/types/include/gralloctypes/Gralloc4.h
index a5d3bb2..94de8f1 100644
--- a/libs/gralloc/types/include/gralloctypes/Gralloc4.h
+++ b/libs/gralloc/types/include/gralloctypes/Gralloc4.h
@@ -17,16 +17,17 @@
#pragma once
#include <aidl/android/hardware/graphics/common/BlendMode.h>
+#include <aidl/android/hardware/graphics/common/ChromaSiting.h>
+#include <aidl/android/hardware/graphics/common/Compression.h>
+#include <aidl/android/hardware/graphics/common/Cta861_3.h>
#include <aidl/android/hardware/graphics/common/Dataspace.h>
#include <aidl/android/hardware/graphics/common/ExtendableType.h>
#include <aidl/android/hardware/graphics/common/Interlaced.h>
#include <aidl/android/hardware/graphics/common/PlaneLayout.h>
-#include <aidl/android/hardware/graphics/common/ChromaSiting.h>
-#include <aidl/android/hardware/graphics/common/Compression.h>
-#include <aidl/android/hardware/graphics/common/Interlaced.h>
-#include <aidl/android/hardware/graphics/common/StandardMetadataType.h>
#include <aidl/android/hardware/graphics/common/PlaneLayoutComponentType.h>
-
+#include <aidl/android/hardware/graphics/common/Smpte2086.h>
+#include <aidl/android/hardware/graphics/common/StandardMetadataType.h>
+#include <aidl/android/hardware/graphics/common/XyColor.h>
#include <android/hardware/graphics/mapper/4.0/IMapper.h>
namespace android {
@@ -113,6 +114,22 @@
GRALLOC4_STANDARD_METADATA_TYPE, static_cast<int64_t>(aidl::android::hardware::graphics::common::StandardMetadataType::BLEND_MODE)
};
+static const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType
+ MetadataType_Smpte2086 = {GRALLOC4_STANDARD_METADATA_TYPE,
+ static_cast<int64_t>(aidl::android::hardware::graphics::common::
+ StandardMetadataType::SMPTE2086)};
+
+static const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType
+ MetadataType_Cta861_3 = {GRALLOC4_STANDARD_METADATA_TYPE,
+ static_cast<int64_t>(aidl::android::hardware::graphics::common::
+ StandardMetadataType::CTA861_3)};
+
+static const android::hardware::graphics::mapper::V4_0::IMapper::MetadataType
+ MetadataType_Smpte2094_40 = {GRALLOC4_STANDARD_METADATA_TYPE,
+ static_cast<int64_t>(
+ aidl::android::hardware::graphics::common::
+ StandardMetadataType::SMPTE2094_40)};
+
/*---------------------------------------------------------------------------------------------*/
/**
@@ -272,6 +289,25 @@
status_t encodeBlendMode(const aidl::android::hardware::graphics::common::BlendMode& blendMode, android::hardware::hidl_vec<uint8_t>* outBlendMode);
status_t decodeBlendMode(const android::hardware::hidl_vec<uint8_t>& blendMode, aidl::android::hardware::graphics::common::BlendMode* outBlendMode);
+status_t encodeSmpte2086(
+ const std::optional<aidl::android::hardware::graphics::common::Smpte2086>& smpte2086,
+ android::hardware::hidl_vec<uint8_t>* outSmpte2086);
+status_t decodeSmpte2086(
+ const android::hardware::hidl_vec<uint8_t>& smpte2086,
+ std::optional<aidl::android::hardware::graphics::common::Smpte2086>* outSmpte2086);
+
+status_t encodeCta861_3(
+ const std::optional<aidl::android::hardware::graphics::common::Cta861_3>& cta861_3,
+ android::hardware::hidl_vec<uint8_t>* outCta861_3);
+status_t decodeCta861_3(
+ const android::hardware::hidl_vec<uint8_t>& cta861_3,
+ std::optional<aidl::android::hardware::graphics::common::Cta861_3>* outCta861_3);
+
+status_t encodeSmpte2094_40(const std::optional<std::vector<uint8_t>>& smpte2094_40,
+ android::hardware::hidl_vec<uint8_t>* outSmpte2094_40);
+status_t decodeSmpte2094_40(const android::hardware::hidl_vec<uint8_t>& smpte2094_40,
+ std::optional<std::vector<uint8_t>>* outSmpte2094_40);
+
/**
* The functions below can be used to parse extendable types.
*/
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index b9cf9e1..a5e5693 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -17,10 +17,14 @@
#undef LOG_TAG
#define LOG_TAG "BLASTBufferQueue"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include <gui/BLASTBufferQueue.h>
#include <gui/BufferItemConsumer.h>
#include <gui/GLConsumer.h>
+#include <utils/Trace.h>
+
#include <chrono>
using namespace std::chrono_literals;
@@ -29,23 +33,29 @@
BLASTBufferQueue::BLASTBufferQueue(const sp<SurfaceControl>& surface, int width, int height)
: mSurfaceControl(surface),
- mPendingCallbacks(0),
mWidth(width),
mHeight(height),
mNextTransaction(nullptr) {
BufferQueue::createBufferQueue(&mProducer, &mConsumer);
mConsumer->setMaxBufferCount(MAX_BUFFERS);
mProducer->setMaxDequeuedBufferCount(MAX_BUFFERS - 1);
+ mConsumer->setMaxAcquiredBufferCount(MAX_ACQUIRED_BUFFERS);
mBufferItemConsumer =
new BufferItemConsumer(mConsumer, AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER, 1, true);
- mBufferItemConsumer->setName(String8("BLAST Consumer"));
+ static int32_t id = 0;
+ auto name = std::string("BLAST Consumer") + std::to_string(id);
+ id++;
+ mBufferItemConsumer->setName(String8(name.c_str()));
mBufferItemConsumer->setFrameAvailableListener(this);
mBufferItemConsumer->setBufferFreedListener(this);
mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight);
mBufferItemConsumer->setDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888);
mBufferItemConsumer->setTransformHint(mSurfaceControl->getTransformHint());
- mAcquired = false;
+ mNumAcquired = 0;
+ mNumFrameAvailable = 0;
+ mPendingReleaseItem.item = BufferItem();
+ mPendingReleaseItem.releaseFence = nullptr;
}
void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, int width, int height) {
@@ -70,34 +80,46 @@
void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence>& /*presentFence*/,
const std::vector<SurfaceControlStats>& stats) {
std::unique_lock _lock{mMutex};
+ ATRACE_CALL();
- if (stats.size() > 0 && !mShadowQueue.empty()) {
- mBufferItemConsumer->releaseBuffer(mNextCallbackBufferItem,
- stats[0].previousReleaseFence
- ? stats[0].previousReleaseFence
+ if (mPendingReleaseItem.item.mGraphicBuffer != nullptr) {
+ if (stats.size() > 0) {
+ mPendingReleaseItem.releaseFence = stats[0].previousReleaseFence;
+ mTransformHint = stats[0].transformHint;
+ } else {
+ ALOGE("Warning: no SurfaceControlStats returned in BLASTBufferQueue callback");
+ mPendingReleaseItem.releaseFence = nullptr;
+ }
+ mBufferItemConsumer->releaseBuffer(mPendingReleaseItem.item,
+ mPendingReleaseItem.releaseFence
+ ? mPendingReleaseItem.releaseFence
: Fence::NO_FENCE);
- mAcquired = false;
- mNextCallbackBufferItem = BufferItem();
- mBufferItemConsumer->setTransformHint(stats[0].transformHint);
+ mNumAcquired--;
+ mPendingReleaseItem.item = BufferItem();
+ mPendingReleaseItem.releaseFence = nullptr;
}
- mPendingCallbacks--;
+
+ if (mSubmitted.empty()) {
+ ALOGE("ERROR: callback with no corresponding submitted buffer item");
+ }
+ mPendingReleaseItem.item = std::move(mSubmitted.front());
+ mSubmitted.pop();
processNextBufferLocked();
mCallbackCV.notify_all();
decStrong((void*)transactionCallbackThunk);
}
void BLASTBufferQueue::processNextBufferLocked() {
- if (mShadowQueue.empty()) {
+ ATRACE_CALL();
+ if (mNumFrameAvailable == 0) {
return;
}
- if (mAcquired) {
+ if (mSurfaceControl == nullptr) {
+ ALOGE("ERROR : surface control is null");
return;
}
- BufferItem item = std::move(mShadowQueue.front());
- mShadowQueue.pop();
-
SurfaceComposerClient::Transaction localTransaction;
bool applyTransaction = true;
SurfaceComposerClient::Transaction* t = &localTransaction;
@@ -107,33 +129,34 @@
applyTransaction = false;
}
- mNextCallbackBufferItem = mLastSubmittedBufferItem;
- mLastSubmittedBufferItem = BufferItem();
+ BufferItem bufferItem;
- status_t status = mBufferItemConsumer->acquireBuffer(&mLastSubmittedBufferItem, -1, false);
- mAcquired = true;
+ status_t status = mBufferItemConsumer->acquireBuffer(&bufferItem, -1, false);
if (status != OK) {
- ALOGE("Failed to acquire?");
- }
-
- auto buffer = mLastSubmittedBufferItem.mGraphicBuffer;
-
- if (buffer == nullptr) {
- ALOGE("Null buffer");
return;
}
+ auto buffer = bufferItem.mGraphicBuffer;
+ mNumFrameAvailable--;
+
+ if (buffer == nullptr) {
+ mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE);
+ return;
+ }
+
+ mNumAcquired++;
+ mSubmitted.push(bufferItem);
// Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback.
incStrong((void*)transactionCallbackThunk);
t->setBuffer(mSurfaceControl, buffer);
t->setAcquireFence(mSurfaceControl,
- item.mFence ? new Fence(item.mFence->dup()) : Fence::NO_FENCE);
+ 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->setCrop(mSurfaceControl, computeCrop(mLastSubmittedBufferItem));
- t->setTransform(mSurfaceControl, mLastSubmittedBufferItem.mTransform);
+ t->setCrop(mSurfaceControl, computeCrop(bufferItem));
+ t->setTransform(mSurfaceControl, bufferItem.mTransform);
if (applyTransaction) {
t->apply();
@@ -147,13 +170,13 @@
return item.mCrop;
}
-void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
+void BLASTBufferQueue::onFrameAvailable(const BufferItem& /*item*/) {
+ ATRACE_CALL();
std::lock_guard _lock{mMutex};
// add to shadow queue
- mShadowQueue.push(item);
+ mNumFrameAvailable++;
processNextBufferLocked();
- mPendingCallbacks++;
}
void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t) {
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index dd0b470..0a0a03c 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -68,23 +68,25 @@
std::mutex mMutex;
std::condition_variable mCallbackCV;
- uint64_t mPendingCallbacks GUARDED_BY(mMutex);
static const int MAX_BUFFERS = 3;
- struct BufferInfo {
- sp<GraphicBuffer> buffer;
- int fence;
+ static const int MAX_ACQUIRED_BUFFERS = 2;
+
+ int32_t mNumFrameAvailable GUARDED_BY(mMutex);
+ int32_t mNumAcquired GUARDED_BY(mMutex);
+
+ struct PendingReleaseItem {
+ BufferItem item;
+ sp<Fence> releaseFence;
};
- std::queue<const BufferItem> mShadowQueue GUARDED_BY(mMutex);
- bool mAcquired GUARDED_BY(mMutex);
+ std::queue<const BufferItem> mSubmitted GUARDED_BY(mMutex);
+ PendingReleaseItem mPendingReleaseItem GUARDED_BY(mMutex);
int mWidth GUARDED_BY(mMutex);
int mHeight GUARDED_BY(mMutex);
- BufferItem mLastSubmittedBufferItem GUARDED_BY(mMutex);
- BufferItem mNextCallbackBufferItem GUARDED_BY(mMutex);
- sp<Fence> mLastFence GUARDED_BY(mMutex);
+ uint32_t mTransformHint GUARDED_BY(mMutex);
sp<IGraphicBufferConsumer> mConsumer;
sp<IGraphicBufferProducer> mProducer;
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 48a5cb6..0f618f1 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -69,7 +69,7 @@
void waitForCallbacks() {
std::unique_lock lock{mBlastBufferQueueAdapter->mMutex};
- while (mBlastBufferQueueAdapter->mPendingCallbacks > 0) {
+ while (mBlastBufferQueueAdapter->mSubmitted.size() > 0) {
mBlastBufferQueueAdapter->mCallbackCV.wait(lock);
}
}
@@ -302,7 +302,7 @@
igbProducer->cancelBuffer(allocated[i].first, allocated[i].second);
}
- for (int i = 0; i < 10; i++) {
+ for (int i = 0; i < 100; i++) {
int slot;
sp<Fence> fence;
sp<GraphicBuffer> buf;
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 200e1f3..d53a557 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -301,8 +301,8 @@
if (nWrite < 0) {
int error = errno;
#if DEBUG_CHANNEL_MESSAGES
- ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", mName.c_str(),
- msg->header.type, error);
+ ALOGD("channel '%s' ~ error sending message of type %d, %s", mName.c_str(),
+ msg->header.type, strerror(error));
#endif
if (error == EAGAIN || error == EWOULDBLOCK) {
return WOULD_BLOCK;
diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp
index 2c897cf..30c48c8 100644
--- a/libs/ui/Gralloc4.cpp
+++ b/libs/ui/Gralloc4.cpp
@@ -614,6 +614,24 @@
outBlendMode);
}
+status_t Gralloc4Mapper::getSmpte2086(buffer_handle_t bufferHandle,
+ std::optional<ui::Smpte2086>* outSmpte2086) const {
+ return get(bufferHandle, gralloc4::MetadataType_Smpte2086, gralloc4::decodeSmpte2086,
+ outSmpte2086);
+}
+
+status_t Gralloc4Mapper::getCta861_3(buffer_handle_t bufferHandle,
+ std::optional<ui::Cta861_3>* outCta861_3) const {
+ return get(bufferHandle, gralloc4::MetadataType_Cta861_3, gralloc4::decodeCta861_3,
+ outCta861_3);
+}
+
+status_t Gralloc4Mapper::getSmpte2094_40(
+ buffer_handle_t bufferHandle, std::optional<std::vector<uint8_t>>* outSmpte2094_40) const {
+ return get(bufferHandle, gralloc4::MetadataType_Smpte2094_40, gralloc4::decodeSmpte2094_40,
+ outSmpte2094_40);
+}
+
template <class T>
status_t Gralloc4Mapper::getDefault(uint32_t width, uint32_t height, PixelFormat format,
uint32_t layerCount, uint64_t usage,
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index 8540fd3..d20bd7a 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -286,6 +286,21 @@
return mMapper->getBlendMode(bufferHandle, outBlendMode);
}
+status_t GraphicBufferMapper::getSmpte2086(buffer_handle_t bufferHandle,
+ std::optional<ui::Smpte2086>* outSmpte2086) {
+ return mMapper->getSmpte2086(bufferHandle, outSmpte2086);
+}
+
+status_t GraphicBufferMapper::getCta861_3(buffer_handle_t bufferHandle,
+ std::optional<ui::Cta861_3>* outCta861_3) {
+ return mMapper->getCta861_3(bufferHandle, outCta861_3);
+}
+
+status_t GraphicBufferMapper::getSmpte2094_40(
+ buffer_handle_t bufferHandle, std::optional<std::vector<uint8_t>>* outSmpte2094_40) {
+ return mMapper->getSmpte2094_40(bufferHandle, outSmpte2094_40);
+}
+
status_t GraphicBufferMapper::getDefaultPixelFormatFourCC(uint32_t width, uint32_t height,
PixelFormat format, uint32_t layerCount,
uint64_t usage,
diff --git a/libs/ui/include/ui/Gralloc.h b/libs/ui/include/ui/Gralloc.h
index fcd959c..e199648 100644
--- a/libs/ui/include/ui/Gralloc.h
+++ b/libs/ui/include/ui/Gralloc.h
@@ -165,6 +165,19 @@
ui::BlendMode* /*outBlendMode*/) const {
return INVALID_OPERATION;
}
+ virtual status_t getSmpte2086(buffer_handle_t /*bufferHandle*/,
+ std::optional<ui::Smpte2086>* /*outSmpte2086*/) const {
+ return INVALID_OPERATION;
+ }
+ virtual status_t getCta861_3(buffer_handle_t /*bufferHandle*/,
+ std::optional<ui::Cta861_3>* /*outCta861_3*/) const {
+ return INVALID_OPERATION;
+ }
+ virtual status_t getSmpte2094_40(
+ buffer_handle_t /*bufferHandle*/,
+ std::optional<std::vector<uint8_t>>* /*outSmpte2094_40*/) const {
+ return INVALID_OPERATION;
+ }
virtual status_t getDefaultPixelFormatFourCC(uint32_t /*width*/, uint32_t /*height*/,
PixelFormat /*format*/, uint32_t /*layerCount*/,
diff --git a/libs/ui/include/ui/Gralloc4.h b/libs/ui/include/ui/Gralloc4.h
index af7c076..4729cba 100644
--- a/libs/ui/include/ui/Gralloc4.h
+++ b/libs/ui/include/ui/Gralloc4.h
@@ -102,6 +102,12 @@
std::vector<ui::PlaneLayout>* outPlaneLayouts) const override;
status_t getDataspace(buffer_handle_t bufferHandle, ui::Dataspace* outDataspace) const override;
status_t getBlendMode(buffer_handle_t bufferHandle, ui::BlendMode* outBlendMode) const override;
+ status_t getSmpte2086(buffer_handle_t bufferHandle,
+ std::optional<ui::Smpte2086>* outSmpte2086) const override;
+ status_t getCta861_3(buffer_handle_t bufferHandle,
+ std::optional<ui::Cta861_3>* outCta861_3) const override;
+ status_t getSmpte2094_40(buffer_handle_t bufferHandle,
+ std::optional<std::vector<uint8_t>>* outSmpte2094_40) const override;
status_t getDefaultPixelFormatFourCC(uint32_t width, uint32_t height, PixelFormat format,
uint32_t layerCount, uint64_t usage,
diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h
index 77c00ae..837e3d8 100644
--- a/libs/ui/include/ui/GraphicBufferMapper.h
+++ b/libs/ui/include/ui/GraphicBufferMapper.h
@@ -122,6 +122,10 @@
std::vector<ui::PlaneLayout>* outPlaneLayouts);
status_t getDataspace(buffer_handle_t bufferHandle, ui::Dataspace* outDataspace);
status_t getBlendMode(buffer_handle_t bufferHandle, ui::BlendMode* outBlendMode);
+ status_t getSmpte2086(buffer_handle_t bufferHandle, std::optional<ui::Smpte2086>* outSmpte2086);
+ status_t getCta861_3(buffer_handle_t bufferHandle, std::optional<ui::Cta861_3>* outCta861_3);
+ status_t getSmpte2094_40(buffer_handle_t bufferHandle,
+ std::optional<std::vector<uint8_t>>* outSmpte2094_40);
/**
* Gets the default metadata for a gralloc buffer allocated with the given parameters.
diff --git a/libs/ui/include/ui/GraphicTypes.h b/libs/ui/include/ui/GraphicTypes.h
index ad5ee80..4bdacb0 100644
--- a/libs/ui/include/ui/GraphicTypes.h
+++ b/libs/ui/include/ui/GraphicTypes.h
@@ -19,8 +19,10 @@
#include <aidl/android/hardware/graphics/common/BlendMode.h>
#include <aidl/android/hardware/graphics/common/ChromaSiting.h>
#include <aidl/android/hardware/graphics/common/Compression.h>
+#include <aidl/android/hardware/graphics/common/Cta861_3.h>
#include <aidl/android/hardware/graphics/common/Interlaced.h>
#include <aidl/android/hardware/graphics/common/PlaneLayout.h>
+#include <aidl/android/hardware/graphics/common/Smpte2086.h>
#include <android/hardware/graphics/common/1.1/types.h>
#include <android/hardware/graphics/common/1.2/types.h>
#include <system/graphics.h>
@@ -47,7 +49,9 @@
* Stable AIDL types
*/
using aidl::android::hardware::graphics::common::BlendMode;
+using aidl::android::hardware::graphics::common::Cta861_3;
using aidl::android::hardware::graphics::common::PlaneLayout;
+using aidl::android::hardware::graphics::common::Smpte2086;
/**
* The following stable AIDL types below have standard platform definitions
diff --git a/libs/vr/OWNERS b/libs/vr/OWNERS
index ec2d712..098c80e 100644
--- a/libs/vr/OWNERS
+++ b/libs/vr/OWNERS
@@ -1,4 +1,4 @@
hendrikw@google.com
jwcai@google.com
steventhomas@google.com
-
+patplunkett@google.com
diff --git a/libs/vr/libpdx/Android.bp b/libs/vr/libpdx/Android.bp
index 1a9d727..23a4224 100644
--- a/libs/vr/libpdx/Android.bp
+++ b/libs/vr/libpdx/Android.bp
@@ -53,6 +53,8 @@
"libpdx",
"liblog",
"libutils",
+ ],
+ shared_libs: [
"libvndksupport",
],
}
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index ada2266..09ecb13 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -4,6 +4,7 @@
name: "inputflinger_tests",
srcs: [
"BlockingQueue_test.cpp",
+ "EventHub_test.cpp",
"TestInputListener.cpp",
"InputClassifier_test.cpp",
"InputClassifierConverter_test.cpp",
@@ -36,4 +37,5 @@
header_libs: [
"libinputreader_headers",
],
+ require_root: true,
}
diff --git a/services/inputflinger/tests/EventHub_test.cpp b/services/inputflinger/tests/EventHub_test.cpp
new file mode 100644
index 0000000..6504738
--- /dev/null
+++ b/services/inputflinger/tests/EventHub_test.cpp
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "EventHub.h"
+
+#include <android-base/stringprintf.h>
+#include <gtest/gtest.h>
+#include <inttypes.h>
+#include <linux/uinput.h>
+#include <log/log.h>
+#include <chrono>
+
+#define TAG "EventHub_test"
+
+using android::EventHub;
+using android::EventHubInterface;
+using android::InputDeviceIdentifier;
+using android::RawEvent;
+using android::sp;
+using android::base::StringPrintf;
+using std::chrono_literals::operator""ms;
+
+static constexpr bool DEBUG = false;
+static const char* DEVICE_NAME = "EventHub Test Device";
+
+static void dumpEvents(const std::vector<RawEvent>& events) {
+ for (const RawEvent& event : events) {
+ if (event.type >= EventHubInterface::FIRST_SYNTHETIC_EVENT) {
+ switch (event.type) {
+ case EventHubInterface::DEVICE_ADDED:
+ ALOGI("Device added: %i", event.deviceId);
+ break;
+ case EventHubInterface::DEVICE_REMOVED:
+ ALOGI("Device removed: %i", event.deviceId);
+ break;
+ case EventHubInterface::FINISHED_DEVICE_SCAN:
+ ALOGI("Finished device scan.");
+ break;
+ }
+ } else {
+ ALOGI("Device %" PRId32 " : time = %" PRId64 ", type %i, code %i, value %i",
+ event.deviceId, event.when, event.type, event.code, event.value);
+ }
+ }
+}
+
+// --- EventHubTest ---
+class EventHubTest : public testing::Test {
+protected:
+ std::unique_ptr<EventHubInterface> mEventHub;
+ // We are only going to emulate a single input device currently.
+ android::base::unique_fd mDeviceFd;
+ int32_t mDeviceId;
+ virtual void SetUp() override {
+ mEventHub = std::make_unique<EventHub>();
+ consumeInitialDeviceAddedEvents();
+ createDevice();
+ mDeviceId = waitForDeviceCreation();
+ }
+ virtual void TearDown() override {
+ mDeviceFd.reset();
+ waitForDeviceClose(mDeviceId);
+ }
+
+ void createDevice();
+ /**
+ * Return the device id of the created device.
+ */
+ int32_t waitForDeviceCreation();
+ void waitForDeviceClose(int32_t deviceId);
+ void consumeInitialDeviceAddedEvents();
+ void sendEvent(uint16_t type, uint16_t code, int32_t value);
+ std::vector<RawEvent> getEvents(std::chrono::milliseconds timeout = 5ms);
+};
+
+std::vector<RawEvent> EventHubTest::getEvents(std::chrono::milliseconds timeout) {
+ static constexpr size_t EVENT_BUFFER_SIZE = 256;
+ std::array<RawEvent, EVENT_BUFFER_SIZE> eventBuffer;
+ std::vector<RawEvent> events;
+
+ while (true) {
+ size_t count =
+ mEventHub->getEvents(timeout.count(), eventBuffer.data(), eventBuffer.size());
+ if (count == 0) {
+ break;
+ }
+ events.insert(events.end(), eventBuffer.begin(), eventBuffer.begin() + count);
+ }
+ if (DEBUG) {
+ dumpEvents(events);
+ }
+ return events;
+}
+
+void EventHubTest::createDevice() {
+ mDeviceFd = android::base::unique_fd(open("/dev/uinput", O_WRONLY | O_NONBLOCK));
+ if (mDeviceFd < 0) {
+ FAIL() << "Can't open /dev/uinput :" << strerror(errno);
+ }
+
+ /**
+ * Signal which type of events this input device supports.
+ * We will emulate a keyboard here.
+ */
+ // enable key press/release event
+ if (ioctl(mDeviceFd, UI_SET_EVBIT, EV_KEY)) {
+ ADD_FAILURE() << "Error in ioctl : UI_SET_EVBIT : EV_KEY: " << strerror(errno);
+ }
+
+ // enable set of KEY events
+ if (ioctl(mDeviceFd, UI_SET_KEYBIT, KEY_HOME)) {
+ ADD_FAILURE() << "Error in ioctl : UI_SET_KEYBIT : KEY_HOME: " << strerror(errno);
+ }
+
+ // enable synchronization event
+ if (ioctl(mDeviceFd, UI_SET_EVBIT, EV_SYN)) {
+ ADD_FAILURE() << "Error in ioctl : UI_SET_EVBIT : EV_SYN: " << strerror(errno);
+ }
+
+ struct uinput_user_dev keyboard = {};
+ strlcpy(keyboard.name, DEVICE_NAME, UINPUT_MAX_NAME_SIZE);
+ keyboard.id.bustype = BUS_USB;
+ keyboard.id.vendor = 0x01;
+ keyboard.id.product = 0x01;
+ keyboard.id.version = 1;
+
+ if (write(mDeviceFd, &keyboard, sizeof(keyboard)) < 0) {
+ FAIL() << "Could not write uinput_user_dev struct into uinput file descriptor: "
+ << strerror(errno);
+ }
+
+ if (ioctl(mDeviceFd, UI_DEV_CREATE)) {
+ FAIL() << "Error in ioctl : UI_DEV_CREATE: " << strerror(errno);
+ }
+}
+
+/**
+ * Since the test runs on a real platform, there will be existing devices
+ * in addition to the test devices being added. Therefore, when EventHub is first created,
+ * it will return a lot of "device added" type of events.
+ */
+void EventHubTest::consumeInitialDeviceAddedEvents() {
+ std::vector<RawEvent> events = getEvents(0ms);
+ std::set<int32_t /*deviceId*/> existingDevices;
+ // All of the events should be DEVICE_ADDED type, except the last one.
+ for (size_t i = 0; i < events.size() - 1; i++) {
+ const RawEvent& event = events[i];
+ EXPECT_EQ(EventHubInterface::DEVICE_ADDED, event.type);
+ existingDevices.insert(event.deviceId);
+ }
+ // None of the existing system devices should be changing while this test is run.
+ // Check that the returned device ids are unique for all of the existing devices.
+ EXPECT_EQ(existingDevices.size(), events.size() - 1);
+ // The last event should be "finished device scan"
+ EXPECT_EQ(EventHubInterface::FINISHED_DEVICE_SCAN, events[events.size() - 1].type);
+}
+
+int32_t EventHubTest::waitForDeviceCreation() {
+ // Wait a little longer than usual, to ensure input device has time to be created
+ std::vector<RawEvent> events = getEvents(20ms);
+ EXPECT_EQ(2U, events.size()); // Using "expect" because the function is non-void.
+ const RawEvent& deviceAddedEvent = events[0];
+ EXPECT_EQ(static_cast<int32_t>(EventHubInterface::DEVICE_ADDED), deviceAddedEvent.type);
+ InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceAddedEvent.deviceId);
+ const int32_t deviceId = deviceAddedEvent.deviceId;
+ EXPECT_EQ(identifier.name, DEVICE_NAME);
+ const RawEvent& finishedDeviceScanEvent = events[1];
+ EXPECT_EQ(static_cast<int32_t>(EventHubInterface::FINISHED_DEVICE_SCAN),
+ finishedDeviceScanEvent.type);
+ return deviceId;
+}
+
+void EventHubTest::waitForDeviceClose(int32_t deviceId) {
+ std::vector<RawEvent> events = getEvents(20ms);
+ ASSERT_EQ(2U, events.size());
+ const RawEvent& deviceRemovedEvent = events[0];
+ EXPECT_EQ(static_cast<int32_t>(EventHubInterface::DEVICE_REMOVED), deviceRemovedEvent.type);
+ EXPECT_EQ(deviceId, deviceRemovedEvent.deviceId);
+ const RawEvent& finishedDeviceScanEvent = events[1];
+ EXPECT_EQ(static_cast<int32_t>(EventHubInterface::FINISHED_DEVICE_SCAN),
+ finishedDeviceScanEvent.type);
+}
+
+void EventHubTest::sendEvent(uint16_t type, uint16_t code, int32_t value) {
+ struct input_event event = {};
+ event.type = type;
+ event.code = code;
+ event.value = value;
+ event.time = {}; // uinput ignores the timestamp
+
+ if (write(mDeviceFd, &event, sizeof(input_event)) < 0) {
+ std::string msg = StringPrintf("Could not write event %" PRIu16 " %" PRIu16
+ " with value %" PRId32 " : %s",
+ type, code, value, strerror(errno));
+ ALOGE("%s", msg.c_str());
+ ADD_FAILURE() << msg.c_str();
+ }
+}
+
+/**
+ * Ensure that input_events are generated with monotonic clock.
+ * That means input_event should receive a timestamp that is in the future of the time
+ * before the event was sent.
+ * Input system uses CLOCK_MONOTONIC everywhere in the code base.
+ */
+TEST_F(EventHubTest, InputEvent_TimestampIsMonotonic) {
+ nsecs_t lastEventTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ // key press
+ sendEvent(EV_KEY, KEY_HOME, 1);
+ sendEvent(EV_SYN, SYN_REPORT, 0);
+
+ // key release
+ sendEvent(EV_KEY, KEY_HOME, 0);
+ sendEvent(EV_SYN, SYN_REPORT, 0);
+
+ std::vector<RawEvent> events = getEvents();
+ ASSERT_EQ(4U, events.size()) << "Expected to receive 2 keys and 2 syncs, total of 4 events";
+ for (const RawEvent& event : events) {
+ // Cannot use strict comparison because the events may happen too quickly
+ ASSERT_LE(lastEventTime, event.when) << "Event must have occurred after the key was sent";
+ ASSERT_LT(std::chrono::nanoseconds(event.when - lastEventTime), 100ms)
+ << "Event times are too far apart";
+ lastEventTime = event.when; // Ensure all returned events are monotonic
+ }
+}
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 0701f3b..994010b 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -418,7 +418,7 @@
std::chrono::time_point start = std::chrono::steady_clock::now();
status_t status = WOULD_BLOCK;
while (status == WOULD_BLOCK) {
- status = mConsumer->consume(&mEventFactory, false /*consumeBatches*/, -1, &consumeSeq,
+ status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq,
&event);
std::chrono::duration elapsed = std::chrono::steady_clock::now() - start;
if (elapsed > 100ms) {
@@ -932,6 +932,32 @@
monitor->consumeMotionUp(ADISPLAY_ID_DEFAULT);
}
+TEST_F(InputDispatcherTest, TestMoveEvent) {
+ sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+
+ mDispatcher->setInputWindows({window}, ADISPLAY_ID_DEFAULT);
+
+ NotifyMotionArgs motionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT);
+
+ mDispatcher->notifyMotion(&motionArgs);
+ // Window should receive motion down event.
+ window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+
+ motionArgs.action = AMOTION_EVENT_ACTION_MOVE;
+ motionArgs.sequenceNum += 1;
+ motionArgs.eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
+ motionArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X,
+ motionArgs.pointerCoords[0].getX() - 10);
+
+ mDispatcher->notifyMotion(&motionArgs);
+ window->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_MOVE, ADISPLAY_ID_DEFAULT,
+ 0 /*expectedFlags*/);
+}
+
/* Test InputDispatcher for MultiDisplay */
class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest {
public:
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 34254e0..4f96ad3 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -62,8 +62,11 @@
class ComposerCallbackBridge : public Hwc2::IComposerCallback {
public:
- ComposerCallbackBridge(ComposerCallback* callback, int32_t sequenceId)
- : mCallback(callback), mSequenceId(sequenceId) {}
+ ComposerCallbackBridge(ComposerCallback* callback, int32_t sequenceId,
+ bool vsyncSwitchingSupported)
+ : mCallback(callback),
+ mSequenceId(sequenceId),
+ mVsyncSwitchingSupported(vsyncSwitchingSupported) {}
Return<void> onHotplug(Hwc2::Display display,
IComposerCallback::Connection conn) override
@@ -81,15 +84,23 @@
Return<void> onVsync(Hwc2::Display display, int64_t timestamp) override
{
- mCallback->onVsyncReceived(mSequenceId, display, timestamp, std::nullopt);
+ if (!mVsyncSwitchingSupported) {
+ mCallback->onVsyncReceived(mSequenceId, display, timestamp, std::nullopt);
+ } else {
+ ALOGW("Unexpected onVsync callback on composer >= 2.4, ignoring.");
+ }
return Void();
}
Return<void> onVsync_2_4(Hwc2::Display display, int64_t timestamp,
Hwc2::VsyncPeriodNanos vsyncPeriodNanos) override {
- // TODO(b/140201379): use vsyncPeriodNanos in the new DispSync
- mCallback->onVsyncReceived(mSequenceId, display, timestamp,
- std::make_optional(vsyncPeriodNanos));
+ if (mVsyncSwitchingSupported) {
+ // TODO(b/140201379): use vsyncPeriodNanos in the new DispSync
+ mCallback->onVsyncReceived(mSequenceId, display, timestamp,
+ std::make_optional(vsyncPeriodNanos));
+ } else {
+ ALOGW("Unexpected onVsync_2_4 callback on composer <= 2.3, ignoring.");
+ }
return Void();
}
@@ -107,6 +118,7 @@
private:
ComposerCallback* mCallback;
int32_t mSequenceId;
+ const bool mVsyncSwitchingSupported;
};
} // namespace anonymous
@@ -126,7 +138,8 @@
}
mRegisteredCallback = true;
sp<ComposerCallbackBridge> callbackBridge(
- new ComposerCallbackBridge(callback, sequenceId));
+ new ComposerCallbackBridge(callback, sequenceId,
+ mComposer->isVsyncPeriodSwitchSupported()));
mComposer->registerCallback(callbackBridge);
}
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatch.h b/services/surfaceflinger/Scheduler/VSyncDispatch.h
index e001080..56b3252 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatch.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatch.h
@@ -26,7 +26,7 @@
class TimeKeeper;
class VSyncTracker;
-enum class ScheduleResult { Scheduled, ReScheduled, CannotSchedule, Error };
+enum class ScheduleResult { Scheduled, CannotSchedule, Error };
enum class CancelResult { Cancelled, TooLate, Error };
/*
@@ -83,7 +83,6 @@
* \param [in] earliestVsync The targeted display time. This will be snapped to the closest
* predicted vsync time after earliestVsync.
* \return A ScheduleResult::Scheduled if callback was scheduled.
- * A ScheduleResult::ReScheduled if callback was rescheduled.
* A ScheduleResult::CannotSchedule
* if (workDuration - earliestVsync) is in the past, or
* if a callback was dispatched for the predictedVsync already.
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index a79fe98..48f2abb 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -29,8 +29,13 @@
TimeKeeper::~TimeKeeper() = default;
VSyncDispatchTimerQueueEntry::VSyncDispatchTimerQueueEntry(std::string const& name,
- std::function<void(nsecs_t)> const& cb)
- : mName(name), mCallback(cb), mWorkDuration(0), mEarliestVsync(0) {}
+ std::function<void(nsecs_t)> const& cb,
+ nsecs_t minVsyncDistance)
+ : mName(name),
+ mCallback(cb),
+ mWorkDuration(0),
+ mEarliestVsync(0),
+ mMinVsyncDistance(minVsyncDistance) {}
std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::lastExecutedVsyncTarget() const {
return mLastDispatchTime;
@@ -49,18 +54,28 @@
ScheduleResult VSyncDispatchTimerQueueEntry::schedule(nsecs_t workDuration, nsecs_t earliestVsync,
VSyncTracker& tracker, nsecs_t now) {
- auto const nextVsyncTime =
+ auto nextVsyncTime =
tracker.nextAnticipatedVSyncTimeFrom(std::max(earliestVsync, now + workDuration));
- if (mLastDispatchTime >= nextVsyncTime) { // already dispatched a callback for this vsync
- return ScheduleResult::CannotSchedule;
+
+ bool const wouldSkipAVsyncTarget =
+ mArmedInfo && (nextVsyncTime > (mArmedInfo->mActualVsyncTime + mMinVsyncDistance));
+ if (wouldSkipAVsyncTarget) {
+ return ScheduleResult::Scheduled;
+ }
+
+ bool const alreadyDispatchedForVsync = mLastDispatchTime &&
+ ((*mLastDispatchTime + mMinVsyncDistance) >= nextVsyncTime &&
+ (*mLastDispatchTime - mMinVsyncDistance) <= nextVsyncTime);
+ if (alreadyDispatchedForVsync) {
+ nextVsyncTime =
+ tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + mMinVsyncDistance);
}
auto const nextWakeupTime = nextVsyncTime - workDuration;
- auto result = mArmedInfo ? ScheduleResult::ReScheduled : ScheduleResult::Scheduled;
mWorkDuration = workDuration;
mEarliestVsync = earliestVsync;
mArmedInfo = {nextWakeupTime, nextVsyncTime};
- return result;
+ return ScheduleResult::Scheduled;
}
void VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now) {
@@ -101,8 +116,12 @@
}
VSyncDispatchTimerQueue::VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper> tk,
- VSyncTracker& tracker, nsecs_t timerSlack)
- : mTimeKeeper(std::move(tk)), mTracker(tracker), mTimerSlack(timerSlack) {}
+ VSyncTracker& tracker, nsecs_t timerSlack,
+ nsecs_t minVsyncDistance)
+ : mTimeKeeper(std::move(tk)),
+ mTracker(tracker),
+ mTimerSlack(timerSlack),
+ mMinVsyncDistance(minVsyncDistance) {}
VSyncDispatchTimerQueue::~VSyncDispatchTimerQueue() {
std::lock_guard<decltype(mMutex)> lk(mMutex);
@@ -187,7 +206,8 @@
mCallbacks
.emplace(++mCallbackToken,
std::make_shared<VSyncDispatchTimerQueueEntry>(callbackName,
- callbackFn))
+ callbackFn,
+ mMinVsyncDistance))
.first->first};
}
@@ -277,12 +297,16 @@
}
ScheduleResult VSyncCallbackRegistration::schedule(nsecs_t workDuration, nsecs_t earliestVsync) {
- if (!mValidToken) return ScheduleResult::Error;
+ if (!mValidToken) {
+ return ScheduleResult::Error;
+ }
return mDispatch.get().schedule(mToken, workDuration, earliestVsync);
}
CancelResult VSyncCallbackRegistration::cancel() {
- if (!mValidToken) return CancelResult::Error;
+ if (!mValidToken) {
+ return CancelResult::Error;
+ }
return mDispatch.get().cancel(mToken);
}
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
index fc78da3..0c9b4fe 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
@@ -36,7 +36,8 @@
// Valid transition: disarmed -> armed ( when scheduled )
// Valid transition: armed -> running -> disarmed ( when timer is called)
// Valid transition: armed -> disarmed ( when cancelled )
- VSyncDispatchTimerQueueEntry(std::string const& name, std::function<void(nsecs_t)> const& fn);
+ VSyncDispatchTimerQueueEntry(std::string const& name, std::function<void(nsecs_t)> const& fn,
+ nsecs_t minVsyncDistance);
std::string_view name() const;
// Start: functions that are not threadsafe.
@@ -72,6 +73,7 @@
nsecs_t mWorkDuration;
nsecs_t mEarliestVsync;
+ nsecs_t const mMinVsyncDistance;
struct ArmingInfo {
nsecs_t mActualWakeupTime;
@@ -91,8 +93,15 @@
*/
class VSyncDispatchTimerQueue : public VSyncDispatch {
public:
+ // Constructs a VSyncDispatchTimerQueue.
+ // \param[in] tk A timekeeper.
+ // \param[in] tracker A tracker.
+ // \param[in] timerSlack The threshold at which different similarly timed callbacks
+ // should be grouped into one wakeup.
+ // \param[in] minVsyncDistance The minimum distance between two vsync estimates before the
+ // vsyncs are considered the same vsync event.
explicit VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper> tk, VSyncTracker& tracker,
- nsecs_t timerSlack);
+ nsecs_t timerSlack, nsecs_t minVsyncDistance);
~VSyncDispatchTimerQueue();
CallbackToken registerCallback(std::function<void(nsecs_t)> const& callbackFn,
@@ -119,6 +128,7 @@
std::unique_ptr<TimeKeeper> const mTimeKeeper;
VSyncTracker& mTracker;
nsecs_t const mTimerSlack;
+ nsecs_t const mMinVsyncDistance;
std::mutex mutable mMutex;
size_t mCallbackToken GUARDED_BY(mMutex) = 0;
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index f2a7791..47e3f4f 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -14,7 +14,11 @@
* limitations under the License.
*/
+#undef LOG_TAG
+#define LOG_TAG "VSyncReactor"
+//#define LOG_NDEBUG 0
#include "VSyncReactor.h"
+#include <log/log.h>
#include "TimeKeeper.h"
#include "VSyncDispatch.h"
#include "VSyncTracker.h"
@@ -30,6 +34,87 @@
mTracker(std::move(tracker)),
mPendingLimit(pendingFenceLimit) {}
+VSyncReactor::~VSyncReactor() = default;
+
+// The DispSync interface has a 'repeat this callback at rate' semantic. This object adapts
+// VSyncDispatch's individually-scheduled callbacks so as to meet DispSync's existing semantic
+// for now.
+class CallbackRepeater {
+public:
+ CallbackRepeater(VSyncDispatch& dispatch, DispSync::Callback* cb, const char* name,
+ nsecs_t period, nsecs_t offset, nsecs_t notBefore)
+ : mCallback(cb),
+ mRegistration(dispatch,
+ std::bind(&CallbackRepeater::callback, this, std::placeholders::_1),
+ std::string(name)),
+ mPeriod(period),
+ mOffset(offset),
+ mLastCallTime(notBefore) {}
+
+ ~CallbackRepeater() {
+ std::lock_guard<std::mutex> lk(mMutex);
+ mRegistration.cancel();
+ }
+
+ void start(nsecs_t offset) {
+ std::lock_guard<std::mutex> lk(mMutex);
+ mStopped = false;
+ mOffset = offset;
+
+ auto const schedule_result = mRegistration.schedule(calculateWorkload(), mLastCallTime);
+ LOG_ALWAYS_FATAL_IF((schedule_result != ScheduleResult::Scheduled),
+ "Error scheduling callback: rc %X", schedule_result);
+ }
+
+ void setPeriod(nsecs_t period) {
+ std::lock_guard<std::mutex> lk(mMutex);
+ if (period == mPeriod) {
+ return;
+ }
+ mPeriod = period;
+ }
+
+ void stop() {
+ std::lock_guard<std::mutex> lk(mMutex);
+ LOG_ALWAYS_FATAL_IF(mStopped, "DispSyncInterface misuse: callback already stopped");
+ mStopped = true;
+ mRegistration.cancel();
+ }
+
+private:
+ void callback(nsecs_t vsynctime) {
+ nsecs_t period = 0;
+ {
+ std::lock_guard<std::mutex> lk(mMutex);
+ period = mPeriod;
+ mLastCallTime = vsynctime;
+ }
+
+ mCallback->onDispSyncEvent(vsynctime - period);
+
+ {
+ std::lock_guard<std::mutex> lk(mMutex);
+ auto const schedule_result = mRegistration.schedule(calculateWorkload(), vsynctime);
+ LOG_ALWAYS_FATAL_IF((schedule_result != ScheduleResult::Scheduled),
+ "Error rescheduling callback: rc %X", schedule_result);
+ }
+ }
+
+ // DispSync offsets are defined as time after the vsync before presentation.
+ // VSyncReactor workloads are defined as time before the intended presentation vsync.
+ // Note change in sign between the two defnitions.
+ nsecs_t calculateWorkload() REQUIRES(mMutex) { return mPeriod - mOffset; }
+
+ DispSync::Callback* const mCallback;
+
+ std::mutex mutable mMutex;
+ VSyncCallbackRegistration mRegistration GUARDED_BY(mMutex);
+ bool mStopped GUARDED_BY(mMutex) = false;
+ nsecs_t mPeriod GUARDED_BY(mMutex);
+ nsecs_t mOffset GUARDED_BY(mMutex);
+ nsecs_t mLastCallTime GUARDED_BY(mMutex);
+};
+
bool VSyncReactor::addPresentFence(const std::shared_ptr<FenceTime>& fence) {
if (!fence) {
return false;
@@ -92,6 +177,9 @@
{
std::lock_guard<std::mutex> lk(mMutex);
mPeriodChangeInProgress = true;
+ for (auto& entry : mCallbacks) {
+ entry.second->setPeriod(period);
+ }
}
}
@@ -114,4 +202,47 @@
return false;
}
+status_t VSyncReactor::addEventListener(const char* name, nsecs_t phase,
+ DispSync::Callback* callback,
+ nsecs_t /* lastCallbackTime */) {
+ std::lock_guard<std::mutex> lk(mMutex);
+ auto it = mCallbacks.find(callback);
+ if (it == mCallbacks.end()) {
+ // TODO (b/146557561): resolve lastCallbackTime semantics in DispSync i/f.
+ static auto constexpr maxListeners = 3;
+ if (mCallbacks.size() >= maxListeners) {
+ ALOGE("callback %s not added, exceeded callback limit of %i (currently %zu)", name,
+ maxListeners, mCallbacks.size());
+ return NO_MEMORY;
+ }
+
+ auto const period = mTracker->currentPeriod();
+ auto repeater = std::make_unique<CallbackRepeater>(*mDispatch, callback, name, period,
+ phase, mClock->now());
+ it = mCallbacks.emplace(std::pair(callback, std::move(repeater))).first;
+ }
+
+ it->second->start(phase);
+ return NO_ERROR;
+}
+
+status_t VSyncReactor::removeEventListener(DispSync::Callback* callback,
+ nsecs_t* /* outLastCallback */) {
+ std::lock_guard<std::mutex> lk(mMutex);
+ auto const it = mCallbacks.find(callback);
+ LOG_ALWAYS_FATAL_IF(it == mCallbacks.end(), "callback %p not registered", callback);
+
+ it->second->stop();
+ return NO_ERROR;
+}
+
+status_t VSyncReactor::changePhaseOffset(DispSync::Callback* callback, nsecs_t phase) {
+ std::lock_guard<std::mutex> lk(mMutex);
+ auto const it = mCallbacks.find(callback);
+ LOG_ALWAYS_FATAL_IF(it == mCallbacks.end(), "callback was %p not registered", callback);
+
+ it->second->start(phase);
+ return NO_ERROR;
+}
+
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h
index 786ee98..837eb75 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.h
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.h
@@ -20,19 +20,23 @@
#include <ui/FenceTime.h>
#include <memory>
#include <mutex>
+#include <unordered_map>
#include <vector>
+#include "DispSync.h"
namespace android::scheduler {
class Clock;
class VSyncDispatch;
class VSyncTracker;
+class CallbackRepeater;
// TODO (b/145217110): consider renaming.
class VSyncReactor /* TODO (b/140201379): : public android::DispSync */ {
public:
VSyncReactor(std::unique_ptr<Clock> clock, std::unique_ptr<VSyncDispatch> dispatch,
std::unique_ptr<VSyncTracker> tracker, size_t pendingFenceLimit);
+ ~VSyncReactor();
bool addPresentFence(const std::shared_ptr<FenceTime>& fence);
void setIgnorePresentFences(bool ignoration);
@@ -48,6 +52,11 @@
bool addResyncSample(nsecs_t timestamp, bool* periodFlushed);
void endResync();
+ status_t addEventListener(const char* name, nsecs_t phase, DispSync::Callback* callback,
+ nsecs_t lastCallbackTime);
+ status_t removeEventListener(DispSync::Callback* callback, nsecs_t* outLastCallback);
+ status_t changePhaseOffset(DispSync::Callback* callback, nsecs_t phase);
+
private:
std::unique_ptr<Clock> const mClock;
std::unique_ptr<VSyncDispatch> const mDispatch;
@@ -58,6 +67,8 @@
bool mIgnorePresentFences GUARDED_BY(mMutex) = false;
std::vector<std::shared_ptr<FenceTime>> mUnfiredFences GUARDED_BY(mMutex);
bool mPeriodChangeInProgress GUARDED_BY(mMutex) = false;
+ std::unordered_map<DispSync::Callback*, std::unique_ptr<CallbackRepeater>> mCallbacks
+ GUARDED_BY(mMutex);
};
} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
index 484947d..5846c77 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
@@ -92,6 +92,7 @@
struct VSyncDispatchRealtimeTest : testing::Test {
static nsecs_t constexpr mDispatchGroupThreshold = toNs(100us);
+ static nsecs_t constexpr mVsyncMoveThreshold = toNs(500us);
static size_t constexpr mIterations = 20;
};
@@ -148,7 +149,8 @@
TEST_F(VSyncDispatchRealtimeTest, triple_alarm) {
FixedRateIdealStubTracker tracker;
- VSyncDispatchTimerQueue dispatch(std::make_unique<Timer>(), tracker, mDispatchGroupThreshold);
+ VSyncDispatchTimerQueue dispatch(std::make_unique<Timer>(), tracker, mDispatchGroupThreshold,
+ mVsyncMoveThreshold);
static size_t constexpr num_clients = 3;
std::array<RepeatingCallbackReceiver, num_clients>
@@ -176,7 +178,8 @@
TEST_F(VSyncDispatchRealtimeTest, vascillating_vrr) {
auto next_vsync_interval = toNs(3ms);
VRRStubTracker tracker(next_vsync_interval);
- VSyncDispatchTimerQueue dispatch(std::make_unique<Timer>(), tracker, mDispatchGroupThreshold);
+ VSyncDispatchTimerQueue dispatch(std::make_unique<Timer>(), tracker, mDispatchGroupThreshold,
+ mVsyncMoveThreshold);
RepeatingCallbackReceiver cb_receiver(dispatch, toNs(1ms));
@@ -193,7 +196,8 @@
// starts at 333hz, jumps to 200hz at frame 10
TEST_F(VSyncDispatchRealtimeTest, fixed_jump) {
VRRStubTracker tracker(toNs(3ms));
- VSyncDispatchTimerQueue dispatch(std::make_unique<Timer>(), tracker, mDispatchGroupThreshold);
+ VSyncDispatchTimerQueue dispatch(std::make_unique<Timer>(), tracker, mDispatchGroupThreshold,
+ mVsyncMoveThreshold);
RepeatingCallbackReceiver cb_receiver(dispatch, toNs(1ms));
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
index d668a41..5aff429 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -196,16 +196,18 @@
NiceMock<ControllableClock> mMockClock;
static nsecs_t constexpr mDispatchGroupThreshold = 5;
nsecs_t const mPeriod = 1000;
+ nsecs_t const mVsyncMoveThreshold = 300;
NiceMock<MockVSyncTracker> mStubTracker{mPeriod};
- VSyncDispatchTimerQueue mDispatch{createTimeKeeper(), mStubTracker, mDispatchGroupThreshold};
+ VSyncDispatchTimerQueue mDispatch{createTimeKeeper(), mStubTracker, mDispatchGroupThreshold,
+ mVsyncMoveThreshold};
};
TEST_F(VSyncDispatchTimerQueueTest, unregistersSetAlarmOnDestruction) {
EXPECT_CALL(mMockClock, alarmIn(_, 900));
EXPECT_CALL(mMockClock, alarmCancel());
{
- VSyncDispatchTimerQueue mDispatch{createTimeKeeper(), mStubTracker,
- mDispatchGroupThreshold};
+ VSyncDispatchTimerQueue mDispatch{createTimeKeeper(), mStubTracker, mDispatchGroupThreshold,
+ mVsyncMoveThreshold};
CountingCallback cb(mDispatch);
EXPECT_EQ(mDispatch.schedule(cb, 100, 1000), ScheduleResult::Scheduled);
}
@@ -468,14 +470,24 @@
TEST_F(VSyncDispatchTimerQueueTest, callbackReentrantWithPastWakeup) {
VSyncDispatch::CallbackToken tmp;
+ std::optional<nsecs_t> lastTarget;
tmp = mDispatch.registerCallback(
- [&](auto) {
- EXPECT_EQ(mDispatch.schedule(tmp, 400, 1000), ScheduleResult::CannotSchedule);
+ [&](auto timestamp) {
+ EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp - mVsyncMoveThreshold),
+ ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp + mVsyncMoveThreshold),
+ ScheduleResult::Scheduled);
+ lastTarget = timestamp;
},
"oo");
mDispatch.schedule(tmp, 999, 1000);
advanceToNextCallback();
+ EXPECT_THAT(lastTarget, Eq(1000));
+
+ advanceToNextCallback();
+ EXPECT_THAT(lastTarget, Eq(2000));
}
TEST_F(VSyncDispatchTimerQueueTest, modificationsAroundVsyncTime) {
@@ -547,10 +559,33 @@
EXPECT_THAT(mDispatch.cancel(token), Eq(CancelResult::Error));
}
-TEST_F(VSyncDispatchTimerQueueTest, distinguishesScheduleAndReschedule) {
+TEST_F(VSyncDispatchTimerQueueTest, canMoveCallbackBackwardsInTime) {
CountingCallback cb0(mDispatch);
EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled);
- EXPECT_EQ(mDispatch.schedule(cb0, 100, 1000), ScheduleResult::ReScheduled);
+ EXPECT_EQ(mDispatch.schedule(cb0, 100, 1000), ScheduleResult::Scheduled);
+}
+
+// b/1450138150
+TEST_F(VSyncDispatchTimerQueueTest, doesNotMoveCallbackBackwardsAndSkipAScheduledTargetVSync) {
+ EXPECT_CALL(mMockClock, alarmIn(_, 500));
+ CountingCallback cb(mDispatch);
+ EXPECT_EQ(mDispatch.schedule(cb, 500, 1000), ScheduleResult::Scheduled);
+ mMockClock.advanceBy(400);
+
+ EXPECT_EQ(mDispatch.schedule(cb, 800, 1000), ScheduleResult::Scheduled);
+ advanceToNextCallback();
+ ASSERT_THAT(cb.mCalls.size(), Eq(1));
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, targetOffsetMovingBackALittleCanStillSchedule) {
+ EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000))
+ .Times(2)
+ .WillOnce(Return(1000))
+ .WillOnce(Return(1002));
+ CountingCallback cb(mDispatch);
+ EXPECT_EQ(mDispatch.schedule(cb, 500, 1000), ScheduleResult::Scheduled);
+ mMockClock.advanceBy(400);
+ EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled);
}
TEST_F(VSyncDispatchTimerQueueTest, canScheduleNegativeOffsetAgainstDifferentPeriods) {
@@ -570,13 +605,15 @@
EXPECT_EQ(mDispatch.schedule(cb0, 1900, 2000), ScheduleResult::Scheduled);
}
-TEST_F(VSyncDispatchTimerQueueTest, cannotScheduleDoesNotAffectSchedulingState) {
+TEST_F(VSyncDispatchTimerQueueTest, scheduleUpdatesDoesNotAffectSchedulingState) {
EXPECT_CALL(mMockClock, alarmIn(_, 600));
CountingCallback cb(mDispatch);
EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled);
+
+ EXPECT_EQ(mDispatch.schedule(cb, 1400, 1000), ScheduleResult::Scheduled);
+
advanceToNextCallback();
- EXPECT_EQ(mDispatch.schedule(cb, 100, 1000), ScheduleResult::CannotSchedule);
}
TEST_F(VSyncDispatchTimerQueueTest, helperMove) {
@@ -612,19 +649,22 @@
class VSyncDispatchTimerQueueEntryTest : public testing::Test {
protected:
nsecs_t const mPeriod = 1000;
+ nsecs_t const mVsyncMoveThreshold = 200;
NiceMock<MockVSyncTracker> mStubTracker{mPeriod};
};
TEST_F(VSyncDispatchTimerQueueEntryTest, stateAfterInitialization) {
std::string name("basicname");
- VSyncDispatchTimerQueueEntry entry(name, [](auto) {});
+ VSyncDispatchTimerQueueEntry entry(
+ name, [](auto) {}, mVsyncMoveThreshold);
EXPECT_THAT(entry.name(), Eq(name));
EXPECT_FALSE(entry.lastExecutedVsyncTarget());
EXPECT_FALSE(entry.wakeupTime());
}
TEST_F(VSyncDispatchTimerQueueEntryTest, stateScheduling) {
- VSyncDispatchTimerQueueEntry entry("test", [](auto) {});
+ VSyncDispatchTimerQueueEntry entry(
+ "test", [](auto) {}, mVsyncMoveThreshold);
EXPECT_FALSE(entry.wakeupTime());
EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
@@ -643,7 +683,8 @@
EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(now + duration))
.Times(1)
.WillOnce(Return(10000));
- VSyncDispatchTimerQueueEntry entry("test", [](auto) {});
+ VSyncDispatchTimerQueueEntry entry(
+ "test", [](auto) {}, mVsyncMoveThreshold);
EXPECT_FALSE(entry.wakeupTime());
EXPECT_THAT(entry.schedule(500, 994, mStubTracker, now), Eq(ScheduleResult::Scheduled));
@@ -655,10 +696,13 @@
TEST_F(VSyncDispatchTimerQueueEntryTest, runCallback) {
auto callCount = 0;
auto calledTime = 0;
- VSyncDispatchTimerQueueEntry entry("test", [&](auto time) {
- callCount++;
- calledTime = time;
- });
+ VSyncDispatchTimerQueueEntry entry(
+ "test",
+ [&](auto time) {
+ callCount++;
+ calledTime = time;
+ },
+ mVsyncMoveThreshold);
EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
auto const wakeup = entry.wakeupTime();
@@ -681,7 +725,8 @@
.WillOnce(Return(1000))
.WillOnce(Return(1020));
- VSyncDispatchTimerQueueEntry entry("test", [](auto) {});
+ VSyncDispatchTimerQueueEntry entry(
+ "test", [](auto) {}, mVsyncMoveThreshold);
EXPECT_FALSE(entry.wakeupTime());
entry.update(mStubTracker, 0);
@@ -699,7 +744,8 @@
}
TEST_F(VSyncDispatchTimerQueueEntryTest, skipsUpdateIfJustScheduled) {
- VSyncDispatchTimerQueueEntry entry("test", [](auto) {});
+ VSyncDispatchTimerQueueEntry entry(
+ "test", [](auto) {}, mVsyncMoveThreshold);
EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
entry.update(mStubTracker, 0);
@@ -708,19 +754,52 @@
EXPECT_THAT(*wakeup, Eq(wakeup));
}
-TEST_F(VSyncDispatchTimerQueueEntryTest, reportsCannotScheduleIfMissedOpportunity) {
- VSyncDispatchTimerQueueEntry entry("test", [](auto) {});
+TEST_F(VSyncDispatchTimerQueueEntryTest, willSnapToNextTargettableVSync) {
+ VSyncDispatchTimerQueueEntry entry(
+ "test", [](auto) {}, mVsyncMoveThreshold);
EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
- entry.executing();
- EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::CannotSchedule));
- EXPECT_THAT(entry.schedule(50, 500, mStubTracker, 0), Eq(ScheduleResult::CannotSchedule));
+ entry.executing(); // 1000 is executing
+ // had 1000 not been executing, this could have been scheduled for time 800.
+ EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+ EXPECT_THAT(*entry.wakeupTime(), Eq(1800));
+
+ EXPECT_THAT(entry.schedule(50, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+ EXPECT_THAT(*entry.wakeupTime(), Eq(1950));
+
EXPECT_THAT(entry.schedule(200, 1001, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+ EXPECT_THAT(*entry.wakeupTime(), Eq(1800));
}
-TEST_F(VSyncDispatchTimerQueueEntryTest, reportsReScheduleIfStillTime) {
- VSyncDispatchTimerQueueEntry entry("test", [](auto) {});
+TEST_F(VSyncDispatchTimerQueueEntryTest,
+ willRequestNextEstimateWhenSnappingToNextTargettableVSync) {
+ VSyncDispatchTimerQueueEntry entry(
+ "test", [](auto) {}, mVsyncMoveThreshold);
+
+ Sequence seq;
+ EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(500))
+ .InSequence(seq)
+ .WillOnce(Return(1000));
+ EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(500))
+ .InSequence(seq)
+ .WillOnce(Return(1000));
+ EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000 + mVsyncMoveThreshold))
+ .InSequence(seq)
+ .WillOnce(Return(2000));
+
EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
- EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::ReScheduled));
+
+ entry.executing(); // 1000 is executing
+
+ EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+}
+
+TEST_F(VSyncDispatchTimerQueueEntryTest, reportsScheduledIfStillTime) {
+ VSyncDispatchTimerQueueEntry entry(
+ "test", [](auto) {}, mVsyncMoveThreshold);
+ EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+ EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+ EXPECT_THAT(entry.schedule(50, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+ EXPECT_THAT(entry.schedule(1200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
}
} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index 84df019..537cc80 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -122,21 +122,53 @@
return ft;
}
+class StubCallback : public DispSync::Callback {
+public:
+ void onDispSyncEvent(nsecs_t when) final {
+ std::lock_guard<std::mutex> lk(mMutex);
+ mLastCallTime = when;
+ }
+ std::optional<nsecs_t> lastCallTime() const {
+ std::lock_guard<std::mutex> lk(mMutex);
+ return mLastCallTime;
+ }
+
+private:
+ std::mutex mutable mMutex;
+ std::optional<nsecs_t> mLastCallTime GUARDED_BY(mMutex);
+};
+
class VSyncReactorTest : public testing::Test {
protected:
VSyncReactorTest()
- : mMockDispatch(std::make_shared<MockVSyncDispatch>()),
+ : mMockDispatch(std::make_shared<NiceMock<MockVSyncDispatch>>()),
mMockTracker(std::make_shared<NiceMock<MockVSyncTracker>>()),
mMockClock(std::make_shared<NiceMock<MockClock>>()),
mReactor(std::make_unique<ClockWrapper>(mMockClock),
std::make_unique<VSyncDispatchWrapper>(mMockDispatch),
- std::make_unique<VSyncTrackerWrapper>(mMockTracker), kPendingLimit) {}
+ std::make_unique<VSyncTrackerWrapper>(mMockTracker), kPendingLimit) {
+ ON_CALL(*mMockClock, now()).WillByDefault(Return(mFakeNow));
+ ON_CALL(*mMockTracker, currentPeriod()).WillByDefault(Return(period));
+ }
std::shared_ptr<MockVSyncDispatch> mMockDispatch;
std::shared_ptr<MockVSyncTracker> mMockTracker;
std::shared_ptr<MockClock> mMockClock;
static constexpr size_t kPendingLimit = 3;
- static constexpr nsecs_t dummyTime = 47;
+ static constexpr nsecs_t mDummyTime = 47;
+ static constexpr nsecs_t mPhase = 3000;
+ static constexpr nsecs_t mAnotherPhase = 5200;
+ static constexpr nsecs_t period = 10000;
+ static constexpr nsecs_t mAnotherPeriod = 23333;
+ static constexpr nsecs_t mFakeCbTime = 2093;
+ static constexpr nsecs_t mFakeNow = 2214;
+ static constexpr const char mName[] = "callbacky";
+ VSyncDispatch::CallbackToken const mFakeToken{2398};
+
+ nsecs_t lastCallbackTime = 0;
+ StubCallback outerCb;
+ std::function<void(nsecs_t)> innerCb;
+
VSyncReactor mReactor;
};
@@ -149,8 +181,8 @@
}
TEST_F(VSyncReactorTest, addingSignalledFenceAddsToTracker) {
- EXPECT_CALL(*mMockTracker, addVsyncTimestamp(dummyTime));
- EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(dummyTime)));
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(mDummyTime));
+ EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(mDummyTime)));
}
TEST_F(VSyncReactorTest, addingPendingFenceAddsSignalled) {
@@ -161,9 +193,9 @@
EXPECT_FALSE(mReactor.addPresentFence(pendingFence));
Mock::VerifyAndClearExpectations(mMockTracker.get());
- signalFenceWithTime(pendingFence, dummyTime);
+ signalFenceWithTime(pendingFence, mDummyTime);
- EXPECT_CALL(*mMockTracker, addVsyncTimestamp(dummyTime));
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(mDummyTime));
EXPECT_CALL(*mMockTracker, addVsyncTimestamp(anotherDummyTime));
EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(anotherDummyTime)));
}
@@ -193,15 +225,15 @@
TEST_F(VSyncReactorTest, ignoresPresentFencesWhenToldTo) {
static constexpr size_t aFewTimes = 8;
- EXPECT_CALL(*mMockTracker, addVsyncTimestamp(dummyTime)).Times(1);
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(mDummyTime)).Times(1);
mReactor.setIgnorePresentFences(true);
for (auto i = 0; i < aFewTimes; i++) {
- mReactor.addPresentFence(generateSignalledFenceWithTime(dummyTime));
+ mReactor.addPresentFence(generateSignalledFenceWithTime(mDummyTime));
}
mReactor.setIgnorePresentFences(false);
- EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(dummyTime)));
+ EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(mDummyTime)));
}
TEST_F(VSyncReactorTest, queriesTrackerForNextRefreshNow) {
@@ -227,11 +259,11 @@
TEST_F(VSyncReactorTest, queriesTrackerForNextRefreshFuture) {
nsecs_t const fakeTimestamp = 4839;
nsecs_t const fakePeriod = 1010;
- nsecs_t const fakeNow = 2214;
+ nsecs_t const mFakeNow = 2214;
int const numPeriodsOut = 3;
- EXPECT_CALL(*mMockClock, now()).WillOnce(Return(fakeNow));
+ EXPECT_CALL(*mMockClock, now()).WillOnce(Return(mFakeNow));
EXPECT_CALL(*mMockTracker, currentPeriod()).WillOnce(Return(fakePeriod));
- EXPECT_CALL(*mMockTracker, nextAnticipatedVSyncTimeFrom(fakeNow + numPeriodsOut * fakePeriod))
+ EXPECT_CALL(*mMockTracker, nextAnticipatedVSyncTimeFrom(mFakeNow + numPeriodsOut * fakePeriod))
.WillOnce(Return(fakeTimestamp));
EXPECT_THAT(mReactor.computeNextRefresh(numPeriodsOut), Eq(fakeTimestamp));
}
@@ -267,4 +299,194 @@
EXPECT_TRUE(periodFlushed);
}
+static nsecs_t computeWorkload(nsecs_t period, nsecs_t phase) {
+ return period - phase;
+}
+
+TEST_F(VSyncReactorTest, addEventListener) {
+ Sequence seq;
+ EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+ .InSequence(seq)
+ .WillOnce(Return(mFakeToken));
+ EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
+ .InSequence(seq);
+ EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).Times(2).InSequence(seq);
+ EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
+
+ mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+ mReactor.removeEventListener(&outerCb, &lastCallbackTime);
+}
+
+TEST_F(VSyncReactorTest, addEventListenerTwiceChangesPhase) {
+ Sequence seq;
+ EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+ .InSequence(seq)
+ .WillOnce(Return(mFakeToken));
+ EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
+ .InSequence(seq);
+ EXPECT_CALL(*mMockDispatch,
+ schedule(mFakeToken, computeWorkload(period, mAnotherPhase), _)) // mFakeNow))
+ .InSequence(seq);
+ EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq);
+ EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
+
+ mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+ mReactor.addEventListener(mName, mAnotherPhase, &outerCb, lastCallbackTime);
+}
+
+TEST_F(VSyncReactorTest, eventListenerGetsACallbackAndReschedules) {
+ Sequence seq;
+ EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+ .InSequence(seq)
+ .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
+ EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
+ .InSequence(seq);
+ EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeCbTime))
+ .Times(2)
+ .InSequence(seq);
+ EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq);
+ EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
+
+ mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+ ASSERT_TRUE(innerCb);
+ innerCb(mFakeCbTime);
+ innerCb(mFakeCbTime);
+}
+
+TEST_F(VSyncReactorTest, callbackTimestampReadapted) {
+ Sequence seq;
+ EXPECT_CALL(*mMockDispatch, registerCallback(_, _))
+ .InSequence(seq)
+ .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
+ EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
+ .InSequence(seq);
+ EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeCbTime))
+ .InSequence(seq);
+
+ mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+ ASSERT_TRUE(innerCb);
+ innerCb(mFakeCbTime);
+ EXPECT_THAT(outerCb.lastCallTime(), Optional(mFakeCbTime - period));
+}
+
+TEST_F(VSyncReactorTest, eventListenersRemovedOnDestruction) {
+ Sequence seq;
+ EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+ .InSequence(seq)
+ .WillOnce(Return(mFakeToken));
+ EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
+ .InSequence(seq);
+ EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq);
+ EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
+
+ mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+}
+
+TEST_F(VSyncReactorTest, addEventListenerChangePeriod) {
+ Sequence seq;
+ EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+ .InSequence(seq)
+ .WillOnce(Return(mFakeToken));
+ EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
+ .InSequence(seq);
+ EXPECT_CALL(*mMockDispatch,
+ schedule(mFakeToken, computeWorkload(period, mAnotherPhase), mFakeNow))
+ .InSequence(seq);
+ EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq);
+ EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
+
+ mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+ mReactor.addEventListener(mName, mAnotherPhase, &outerCb, lastCallbackTime);
+}
+
+TEST_F(VSyncReactorTest, changingPeriodChangesOfsetsOnNextCb) {
+ Sequence seq;
+ EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+ .InSequence(seq)
+ .WillOnce(Return(mFakeToken));
+ EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
+ .InSequence(seq);
+ EXPECT_CALL(*mMockTracker, setPeriod(mAnotherPeriod));
+ EXPECT_CALL(*mMockDispatch,
+ schedule(mFakeToken, computeWorkload(mAnotherPeriod, mPhase), mFakeNow))
+ .InSequence(seq);
+
+ mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+ mReactor.setPeriod(mAnotherPeriod);
+ mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+}
+
+TEST_F(VSyncReactorTest, offsetsAppliedOnNextOpportunity) {
+ Sequence seq;
+ EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+ .InSequence(seq)
+ .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
+ EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), _))
+ .InSequence(seq)
+ .WillOnce(Return(ScheduleResult::Scheduled));
+
+ EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mAnotherPhase), _))
+ .InSequence(seq)
+ .WillOnce(Return(ScheduleResult::Scheduled));
+
+ EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mAnotherPhase), _))
+ .InSequence(seq)
+ .WillOnce(Return(ScheduleResult::Scheduled));
+
+ mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+ mReactor.changePhaseOffset(&outerCb, mAnotherPhase);
+ ASSERT_TRUE(innerCb);
+ innerCb(mFakeCbTime);
+}
+
+TEST_F(VSyncReactorTest, negativeOffsetsApplied) {
+ nsecs_t const negativePhase = -4000;
+ Sequence seq;
+ EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+ .InSequence(seq)
+ .WillOnce(Return(mFakeToken));
+ EXPECT_CALL(*mMockDispatch,
+ schedule(mFakeToken, computeWorkload(period, negativePhase), mFakeNow))
+ .InSequence(seq);
+ mReactor.addEventListener(mName, negativePhase, &outerCb, lastCallbackTime);
+}
+
+using VSyncReactorDeathTest = VSyncReactorTest;
+TEST_F(VSyncReactorDeathTest, invalidRemoval) {
+ mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+ mReactor.removeEventListener(&outerCb, &lastCallbackTime);
+ EXPECT_DEATH(mReactor.removeEventListener(&outerCb, &lastCallbackTime), ".*");
+}
+
+TEST_F(VSyncReactorDeathTest, invalidChange) {
+ EXPECT_DEATH(mReactor.changePhaseOffset(&outerCb, mPhase), ".*");
+
+ // the current DispSync-interface usage pattern has evolved around an implementation quirk,
+ // which is a callback is assumed to always exist, and it is valid api usage to change the
+ // offset of an object that is in the removed state.
+ mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+ mReactor.removeEventListener(&outerCb, &lastCallbackTime);
+ mReactor.changePhaseOffset(&outerCb, mPhase);
+}
+
+TEST_F(VSyncReactorDeathTest, cannotScheduleOnRegistration) {
+ ON_CALL(*mMockDispatch, schedule(_, _, _))
+ .WillByDefault(Return(ScheduleResult::CannotSchedule));
+ EXPECT_DEATH(mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime), ".*");
+}
+
+TEST_F(VSyncReactorDeathTest, cannotScheduleOnCallback) {
+ EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+ .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
+ EXPECT_CALL(*mMockDispatch, schedule(_, _, _)).WillOnce(Return(ScheduleResult::Scheduled));
+
+ mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+ ASSERT_TRUE(innerCb);
+ Mock::VerifyAndClearExpectations(mMockDispatch.get());
+
+ ON_CALL(*mMockDispatch, schedule(_, _, _))
+ .WillByDefault(Return(ScheduleResult::CannotSchedule));
+ EXPECT_DEATH(innerCb(mFakeCbTime), ".*");
+}
+
} // namespace android::scheduler
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index aa7c19a..a44b9e7 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -24,6 +24,7 @@
#include <system/window.h>
#include <ui/BufferQueueDefs.h>
#include <utils/StrongPointer.h>
+#include <utils/Timers.h>
#include <utils/Trace.h>
#include <algorithm>
@@ -228,8 +229,10 @@
mailbox_mode(present_mode == VK_PRESENT_MODE_MAILBOX_KHR),
pre_transform(pre_transform_),
frame_timestamps_enabled(false),
+ acquire_next_image_timeout(-1),
shared(present_mode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR ||
- present_mode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) {
+ present_mode ==
+ VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) {
ANativeWindow* window = surface.window.get();
native_window_get_refresh_cycle_duration(
window,
@@ -251,6 +254,7 @@
int pre_transform;
bool frame_timestamps_enabled;
int64_t refresh_duration;
+ nsecs_t acquire_next_image_timeout;
bool shared;
struct Image {
@@ -363,7 +367,7 @@
int64_t composition_latch_time = 0;
int64_t actual_present_time = 0;
// Obtain timestamps:
- int ret = native_window_get_frame_timestamps(
+ int err = native_window_get_frame_timestamps(
swapchain.surface.window.get(), ti.native_frame_id_,
&desired_present_time, &render_complete_time,
&composition_latch_time,
@@ -374,7 +378,7 @@
nullptr, //&dequeue_ready_time,
nullptr /*&reads_done_time*/);
- if (ret != android::NO_ERROR) {
+ if (err != android::OK) {
continue;
}
@@ -530,7 +534,7 @@
surface->swapchain_handle = VK_NULL_HANDLE;
int err = native_window_get_consumer_usage(surface->window.get(),
&surface->consumer_usage);
- if (err != android::NO_ERROR) {
+ if (err != android::OK) {
ALOGE("native_window_get_consumer_usage() failed: %s (%d)",
strerror(-err), err);
surface->~Surface();
@@ -540,7 +544,7 @@
err =
native_window_api_connect(surface->window.get(), NATIVE_WINDOW_API_EGL);
- if (err != 0) {
+ if (err != android::OK) {
ALOGE("native_window_api_connect() failed: %s (%d)", strerror(-err),
err);
surface->~Surface();
@@ -588,7 +592,7 @@
int query_value;
int err = window->query(window, NATIVE_WINDOW_FORMAT, &query_value);
- if (err != 0 || query_value < 0) {
+ if (err != android::OK || query_value < 0) {
ALOGE("NATIVE_WINDOW_FORMAT query failed: %s (%d) value=%d",
strerror(-err), err, query_value);
return VK_ERROR_SURFACE_LOST_KHR;
@@ -629,13 +633,13 @@
int width, height;
err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
- if (err != 0) {
+ if (err != android::OK) {
ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
}
err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
- if (err != 0) {
+ if (err != android::OK) {
ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
@@ -643,7 +647,7 @@
int transform_hint;
err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &transform_hint);
- if (err != 0) {
+ if (err != android::OK) {
ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)",
strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
@@ -651,7 +655,7 @@
int max_buffer_count;
err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &max_buffer_count);
- if (err != 0) {
+ if (err != android::OK) {
ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d)",
strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
@@ -856,7 +860,7 @@
ANativeWindow* window = SurfaceFromHandle(surface)->window.get();
err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value);
- if (err != 0 || query_value < 0) {
+ if (err != android::OK || query_value < 0) {
ALOGE("NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d) value=%d",
strerror(-err), err, query_value);
return VK_ERROR_SURFACE_LOST_KHR;
@@ -864,7 +868,7 @@
uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &query_value);
- if (err != 0 || query_value < 0) {
+ if (err != android::OK || query_value < 0) {
ALOGE("NATIVE_WINDOW_MAX_BUFFER_COUNT query failed: %s (%d) value=%d",
strerror(-err), err, query_value);
return VK_ERROR_SURFACE_LOST_KHR;
@@ -956,12 +960,12 @@
int width = 0, height = 0;
err = window->query(window, NATIVE_WINDOW_DEFAULT_WIDTH, &width);
- if (err != 0) {
+ if (err != android::OK) {
ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
strerror(-err), err);
}
err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
- if (err != 0) {
+ if (err != android::OK) {
ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
strerror(-err), err);
}
@@ -1085,17 +1089,23 @@
// dequeue all buffers.
//
// TODO(http://b/134186185) recycle swapchain images more efficiently
- err = native_window_api_disconnect(surface.window.get(),
- NATIVE_WINDOW_API_EGL);
- ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)",
+ ANativeWindow* window = surface.window.get();
+ err = native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+ ALOGW_IF(err != android::OK, "native_window_api_disconnect failed: %s (%d)",
strerror(-err), err);
- err =
- native_window_api_connect(surface.window.get(), NATIVE_WINDOW_API_EGL);
- ALOGW_IF(err != 0, "native_window_api_connect failed: %s (%d)",
+ err = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
+ ALOGW_IF(err != android::OK, "native_window_api_connect failed: %s (%d)",
strerror(-err), err);
- err = native_window_set_buffer_count(surface.window.get(), 0);
- if (err != 0) {
+ err = window->perform(window, NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT, -1);
+ if (err != android::OK) {
+ ALOGE("window->perform(SET_DEQUEUE_TIMEOUT) failed: %s (%d)",
+ strerror(-err), err);
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+
+ err = native_window_set_buffer_count(window, 0);
+ if (err != android::OK) {
ALOGE("native_window_set_buffer_count(0) failed: %s (%d)",
strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
@@ -1103,22 +1113,22 @@
int swap_interval =
create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR ? 0 : 1;
- err = surface.window->setSwapInterval(surface.window.get(), swap_interval);
- if (err != 0) {
+ err = window->setSwapInterval(window, swap_interval);
+ if (err != android::OK) {
ALOGE("native_window->setSwapInterval(1) failed: %s (%d)",
strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
}
- err = native_window_set_shared_buffer_mode(surface.window.get(), false);
- if (err != 0) {
+ err = native_window_set_shared_buffer_mode(window, false);
+ if (err != android::OK) {
ALOGE("native_window_set_shared_buffer_mode(false) failed: %s (%d)",
strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
}
- err = native_window_set_auto_refresh(surface.window.get(), false);
- if (err != 0) {
+ err = native_window_set_auto_refresh(window, false);
+ if (err != android::OK) {
ALOGE("native_window_set_auto_refresh(false) failed: %s (%d)",
strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
@@ -1128,25 +1138,23 @@
const auto& dispatch = GetData(device).driver;
- err = native_window_set_buffers_format(surface.window.get(),
- native_pixel_format);
- if (err != 0) {
+ err = native_window_set_buffers_format(window, native_pixel_format);
+ if (err != android::OK) {
ALOGE("native_window_set_buffers_format(%d) failed: %s (%d)",
native_pixel_format, strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
}
- err = native_window_set_buffers_data_space(surface.window.get(),
- native_dataspace);
- if (err != 0) {
+ err = native_window_set_buffers_data_space(window, native_dataspace);
+ if (err != android::OK) {
ALOGE("native_window_set_buffers_data_space(%d) failed: %s (%d)",
native_dataspace, strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
}
err = native_window_set_buffers_dimensions(
- surface.window.get(), static_cast<int>(create_info->imageExtent.width),
+ window, static_cast<int>(create_info->imageExtent.width),
static_cast<int>(create_info->imageExtent.height));
- if (err != 0) {
+ if (err != android::OK) {
ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)",
create_info->imageExtent.width, create_info->imageExtent.height,
strerror(-err), err);
@@ -1162,9 +1170,8 @@
// it's job the two transforms cancel each other out and the compositor ends
// up applying an identity transform to the app's buffer.
err = native_window_set_buffers_transform(
- surface.window.get(),
- InvertTransformToNative(create_info->preTransform));
- if (err != 0) {
+ window, InvertTransformToNative(create_info->preTransform));
+ if (err != android::OK) {
ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)",
InvertTransformToNative(create_info->preTransform),
strerror(-err), err);
@@ -1172,8 +1179,8 @@
}
err = native_window_set_scaling_mode(
- surface.window.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- if (err != 0) {
+ window, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ if (err != android::OK) {
ALOGE("native_window_set_scaling_mode(SCALE_TO_WINDOW) failed: %s (%d)",
strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
@@ -1183,26 +1190,25 @@
if (create_info->presentMode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR ||
create_info->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) {
swapchain_image_usage |= VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID;
- err = native_window_set_shared_buffer_mode(surface.window.get(), true);
- if (err != 0) {
+ err = native_window_set_shared_buffer_mode(window, true);
+ if (err != android::OK) {
ALOGE("native_window_set_shared_buffer_mode failed: %s (%d)", strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
}
}
if (create_info->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) {
- err = native_window_set_auto_refresh(surface.window.get(), true);
- if (err != 0) {
+ err = native_window_set_auto_refresh(window, true);
+ if (err != android::OK) {
ALOGE("native_window_set_auto_refresh failed: %s (%d)", strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
}
}
int query_value;
- err = surface.window->query(surface.window.get(),
- NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
- &query_value);
- if (err != 0 || query_value < 0) {
+ err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+ &query_value);
+ if (err != android::OK || query_value < 0) {
ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err,
query_value);
return VK_ERROR_SURFACE_LOST_KHR;
@@ -1218,8 +1224,8 @@
// in place for that to work yet. Note we only lie to the lower layer-- we
// don't want to give the app back a swapchain with extra images (which they
// can't actually use!).
- err = native_window_set_buffer_count(surface.window.get(), std::max(2u, num_images));
- if (err != 0) {
+ err = native_window_set_buffer_count(window, std::max(2u, num_images));
+ if (err != android::OK) {
ALOGE("native_window_set_buffer_count(%d) failed: %s (%d)", num_images,
strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
@@ -1257,16 +1263,15 @@
createProtectedSwapchain = true;
native_usage |= BufferUsage::PROTECTED;
}
- err = native_window_set_usage(surface.window.get(), native_usage);
- if (err != 0) {
+ err = native_window_set_usage(window, native_usage);
+ if (err != android::OK) {
ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
}
int transform_hint;
- err = surface.window->query(surface.window.get(),
- NATIVE_WINDOW_TRANSFORM_HINT, &transform_hint);
- if (err != 0) {
+ err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &transform_hint);
+ if (err != android::OK) {
ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)",
strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
@@ -1322,9 +1327,8 @@
Swapchain::Image& img = swapchain->images[i];
ANativeWindowBuffer* buffer;
- err = surface.window->dequeueBuffer(surface.window.get(), &buffer,
- &img.dequeue_fence);
- if (err != 0) {
+ err = window->dequeueBuffer(window, &buffer, &img.dequeue_fence);
+ if (err != android::OK) {
ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err);
switch (-err) {
case ENOMEM:
@@ -1368,8 +1372,8 @@
Swapchain::Image& img = swapchain->images[i];
if (img.dequeued) {
if (!swapchain->shared) {
- surface.window->cancelBuffer(surface.window.get(), img.buffer.get(),
- img.dequeue_fence);
+ window->cancelBuffer(window, img.buffer.get(),
+ img.dequeue_fence);
img.dequeue_fence = -1;
img.dequeued = false;
}
@@ -1447,10 +1451,6 @@
if (swapchain.surface.swapchain_handle != swapchain_handle)
return VK_ERROR_OUT_OF_DATE_KHR;
- ALOGW_IF(
- timeout != UINT64_MAX,
- "vkAcquireNextImageKHR: non-infinite timeouts not yet implemented");
-
if (swapchain.shared) {
// In shared mode, we keep the buffer dequeued all the time, so we don't
// want to dequeue a buffer here. Instead, just ask the driver to ensure
@@ -1461,10 +1461,27 @@
return result;
}
+ const nsecs_t acquire_next_image_timeout =
+ timeout > (uint64_t)std::numeric_limits<nsecs_t>::max() ? -1 : timeout;
+ if (acquire_next_image_timeout != swapchain.acquire_next_image_timeout) {
+ // Cache the timeout to avoid the duplicate binder cost.
+ err = window->perform(window, NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT,
+ acquire_next_image_timeout);
+ if (err != android::OK) {
+ ALOGE("window->perform(SET_DEQUEUE_TIMEOUT) failed: %s (%d)",
+ strerror(-err), err);
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+ swapchain.acquire_next_image_timeout = acquire_next_image_timeout;
+ }
+
ANativeWindowBuffer* buffer;
int fence_fd;
err = window->dequeueBuffer(window, &buffer, &fence_fd);
- if (err != 0) {
+ if (err == android::TIMED_OUT) {
+ ALOGW("dequeueBuffer timed out: %s (%d)", strerror(-err), err);
+ return timeout ? VK_TIMEOUT : VK_NOT_READY;
+ } else if (err != android::OK) {
ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
}
@@ -1671,7 +1688,7 @@
uint64_t nativeFrameId = 0;
err = native_window_get_next_frame_id(
window, &nativeFrameId);
- if (err != android::NO_ERROR) {
+ if (err != android::OK) {
ALOGE("Failed to get next native frame ID.");
}
@@ -1695,7 +1712,7 @@
err = window->queueBuffer(window, img.buffer.get(), fence);
// queueBuffer always closes fence, even on error
- if (err != 0) {
+ if (err != android::OK) {
ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
swapchain_result = WorstPresentResult(
swapchain_result, VK_ERROR_OUT_OF_DATE_KHR);
@@ -1715,17 +1732,15 @@
ANativeWindowBuffer* buffer;
int fence_fd;
err = window->dequeueBuffer(window, &buffer, &fence_fd);
- if (err != 0) {
+ if (err != android::OK) {
ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
swapchain_result = WorstPresentResult(swapchain_result,
VK_ERROR_SURFACE_LOST_KHR);
- }
- else if (img.buffer != buffer) {
+ } else if (img.buffer != buffer) {
ALOGE("got wrong image back for shared swapchain");
swapchain_result = WorstPresentResult(swapchain_result,
VK_ERROR_SURFACE_LOST_KHR);
- }
- else {
+ } else {
img.dequeue_fence = fence_fd;
img.dequeued = true;
}
@@ -1737,7 +1752,7 @@
int window_transform_hint;
err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT,
&window_transform_hint);
- if (err != 0) {
+ if (err != android::OK) {
ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)",
strerror(-err), err);
swapchain_result = WorstPresentResult(