Merge "Update ANGLE namespace creation"
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index 28aeff4..ee32cb4 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -157,3 +157,22 @@
],
static_libs: ["libgmock"],
}
+
+
+// =======================#
+// dumpstate_test_fixture #
+// =======================#
+cc_test {
+
+ name: "dumpstate_test_fixture",
+ test_suites: ["device-tests"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-missing-field-initializers",
+ "-Wno-unused-variable",
+ "-Wunused-parameter",
+ ],
+ srcs: ["tests/dumpstate_test_fixture.cpp"],
+ data: ["tests/testdata/**/*"],
+}
diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk
deleted file mode 100644
index ea5fbf1..0000000
--- a/cmds/dumpstate/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# =======================#
-# dumpstate_test_fixture #
-# =======================#
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := dumpstate_test_fixture
-LOCAL_COMPATIBILITY_SUITE := device-tests
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_CFLAGS := \
- -Wall -Werror -Wno-missing-field-initializers -Wno-unused-variable -Wunused-parameter
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_SRC_FILES := \
- tests/dumpstate_test_fixture.cpp
-
-LOCAL_TEST_DATA := $(call find-test-data-in-subdirs, $(LOCAL_PATH), *, tests/testdata)
-
-include $(BUILD_NATIVE_TEST)
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index b13478c..bb089e6 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -18,8 +18,9 @@
#include "DumpstateService.h"
-#include <android-base/stringprintf.h>
+#include <memory>
+#include <android-base/stringprintf.h>
#include "android/os/BnDumpstate.h"
#include "DumpstateInternal.h"
@@ -48,9 +49,10 @@
return binder::Status::fromServiceSpecificError(code, String8(msg.c_str()));
}
+// Takes ownership of data.
static void* callAndNotify(void* data) {
- DumpstateInfo& ds_info = *static_cast<DumpstateInfo*>(data);
- ds_info.ds->Run(ds_info.calling_uid, ds_info.calling_package);
+ std::unique_ptr<DumpstateInfo> ds_info(static_cast<DumpstateInfo*>(data));
+ ds_info->ds->Run(ds_info->calling_uid, ds_info->calling_package);
MYLOGD("Finished Run()\n");
return nullptr;
}
@@ -59,7 +61,7 @@
} // namespace
-DumpstateService::DumpstateService() : ds_(Dumpstate::GetInstance()) {
+DumpstateService::DumpstateService() : ds_(nullptr) {
}
char const* DumpstateService::getServiceName() {
@@ -78,6 +80,8 @@
return android::OK;
}
+// Note: this method is part of the old flow and is not expected to be used in combination
+// with startBugreport.
binder::Status DumpstateService::setListener(const std::string& name,
const sp<IDumpstateListener>& listener,
bool getSectionDetails,
@@ -92,20 +96,22 @@
return binder::Status::ok();
}
std::lock_guard<std::mutex> lock(lock_);
- if (ds_.listener_ != nullptr) {
- MYLOGE("setListener(%s): already set (%s)\n", name.c_str(), ds_.listener_name_.c_str());
+ if (ds_ == nullptr) {
+ ds_ = &(Dumpstate::GetInstance());
+ }
+ if (ds_->listener_ != nullptr) {
+ MYLOGE("setListener(%s): already set (%s)\n", name.c_str(), ds_->listener_name_.c_str());
return binder::Status::ok();
}
- ds_.listener_name_ = name;
- ds_.listener_ = listener;
- ds_.report_section_ = getSectionDetails;
+ ds_->listener_name_ = name;
+ ds_->listener_ = listener;
+ ds_->report_section_ = getSectionDetails;
*returned_token = new DumpstateToken();
return binder::Status::ok();
}
-// TODO(b/111441001): Hook up to consent service & copy final br only if user approves.
binder::Status DumpstateService::startBugreport(int32_t calling_uid,
const std::string& calling_package,
const android::base::unique_fd& bugreport_fd,
@@ -133,21 +139,29 @@
options->Initialize(static_cast<Dumpstate::BugreportMode>(bugreport_mode), bugreport_fd,
screenshot_fd);
+ // This is the bugreporting API flow, so ensure there is only one bugreport in progress at a
+ // time.
std::lock_guard<std::mutex> lock(lock_);
- // TODO(b/111441001): Disallow multiple simultaneous bugreports.
- ds_.SetOptions(std::move(options));
+ if (ds_ != nullptr) {
+ return exception(binder::Status::EX_SERVICE_SPECIFIC,
+ "There is already a bugreport in progress");
+ }
+ ds_ = &(Dumpstate::GetInstance());
+ ds_->SetOptions(std::move(options));
if (listener != nullptr) {
- ds_.listener_ = listener;
+ ds_->listener_ = listener;
}
- DumpstateInfo ds_info;
- ds_info.ds = &ds_;
- ds_info.calling_uid = calling_uid;
- ds_info.calling_package = calling_package;
+ DumpstateInfo* ds_info = new DumpstateInfo();
+ ds_info->ds = ds_;
+ ds_info->calling_uid = calling_uid;
+ ds_info->calling_package = calling_package;
pthread_t thread;
- status_t err = pthread_create(&thread, nullptr, callAndNotify, &ds_);
+ status_t err = pthread_create(&thread, nullptr, callAndNotify, ds_info);
if (err != 0) {
+ delete ds_info;
+ ds_info = nullptr;
return error(err, "Could not create a background thread.");
}
return binder::Status::ok();
@@ -162,32 +176,36 @@
}
status_t DumpstateService::dump(int fd, const Vector<String16>&) {
- std::string destination = ds_.options_->bugreport_fd.get() != -1
- ? StringPrintf("[fd:%d]", ds_.options_->bugreport_fd.get())
- : ds_.bugreport_internal_dir_.c_str();
- dprintf(fd, "id: %d\n", ds_.id_);
- dprintf(fd, "pid: %d\n", ds_.pid_);
- dprintf(fd, "update_progress: %s\n", ds_.options_->do_progress_updates ? "true" : "false");
- dprintf(fd, "update_progress_threshold: %d\n", ds_.update_progress_threshold_);
- dprintf(fd, "last_updated_progress: %d\n", ds_.last_updated_progress_);
+ if (ds_ == nullptr) {
+ dprintf(fd, "Bugreport not in progress yet");
+ return NO_ERROR;
+ }
+ std::string destination = ds_->options_->bugreport_fd.get() != -1
+ ? StringPrintf("[fd:%d]", ds_->options_->bugreport_fd.get())
+ : ds_->bugreport_internal_dir_.c_str();
+ dprintf(fd, "id: %d\n", ds_->id_);
+ dprintf(fd, "pid: %d\n", ds_->pid_);
+ dprintf(fd, "update_progress: %s\n", ds_->options_->do_progress_updates ? "true" : "false");
+ dprintf(fd, "update_progress_threshold: %d\n", ds_->update_progress_threshold_);
+ dprintf(fd, "last_updated_progress: %d\n", ds_->last_updated_progress_);
dprintf(fd, "progress:\n");
- ds_.progress_->Dump(fd, " ");
- dprintf(fd, "args: %s\n", ds_.options_->args.c_str());
- dprintf(fd, "extra_options: %s\n", ds_.options_->extra_options.c_str());
- dprintf(fd, "version: %s\n", ds_.version_.c_str());
+ ds_->progress_->Dump(fd, " ");
+ dprintf(fd, "args: %s\n", ds_->options_->args.c_str());
+ dprintf(fd, "extra_options: %s\n", ds_->options_->extra_options.c_str());
+ dprintf(fd, "version: %s\n", ds_->version_.c_str());
dprintf(fd, "bugreport_dir: %s\n", destination.c_str());
- dprintf(fd, "screenshot_path: %s\n", ds_.screenshot_path_.c_str());
- dprintf(fd, "log_path: %s\n", ds_.log_path_.c_str());
- dprintf(fd, "tmp_path: %s\n", ds_.tmp_path_.c_str());
- dprintf(fd, "path: %s\n", ds_.path_.c_str());
- dprintf(fd, "extra_options: %s\n", ds_.options_->extra_options.c_str());
- dprintf(fd, "base_name: %s\n", ds_.base_name_.c_str());
- dprintf(fd, "name: %s\n", ds_.name_.c_str());
- dprintf(fd, "now: %ld\n", ds_.now_);
- dprintf(fd, "is_zipping: %s\n", ds_.IsZipping() ? "true" : "false");
- dprintf(fd, "listener: %s\n", ds_.listener_name_.c_str());
- dprintf(fd, "notification title: %s\n", ds_.options_->notification_title.c_str());
- dprintf(fd, "notification description: %s\n", ds_.options_->notification_description.c_str());
+ dprintf(fd, "screenshot_path: %s\n", ds_->screenshot_path_.c_str());
+ dprintf(fd, "log_path: %s\n", ds_->log_path_.c_str());
+ dprintf(fd, "tmp_path: %s\n", ds_->tmp_path_.c_str());
+ dprintf(fd, "path: %s\n", ds_->path_.c_str());
+ dprintf(fd, "extra_options: %s\n", ds_->options_->extra_options.c_str());
+ dprintf(fd, "base_name: %s\n", ds_->base_name_.c_str());
+ dprintf(fd, "name: %s\n", ds_->name_.c_str());
+ dprintf(fd, "now: %ld\n", ds_->now_);
+ dprintf(fd, "is_zipping: %s\n", ds_->IsZipping() ? "true" : "false");
+ dprintf(fd, "listener: %s\n", ds_->listener_name_.c_str());
+ dprintf(fd, "notification title: %s\n", ds_->options_->notification_title.c_str());
+ dprintf(fd, "notification description: %s\n", ds_->options_->notification_description.c_str());
return NO_ERROR;
}
diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h
index faeea53..68eda47 100644
--- a/cmds/dumpstate/DumpstateService.h
+++ b/cmds/dumpstate/DumpstateService.h
@@ -51,7 +51,11 @@
binder::Status cancelBugreport();
private:
- Dumpstate& ds_;
+ // Dumpstate object which contains all the bugreporting logic.
+ // Note that dumpstate is a oneshot service, so this object is meant to be used at most for
+ // one bugreport.
+ // This service does not own this object.
+ Dumpstate* ds_;
std::mutex lock_;
};
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 41c42d7..49d8fe9 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -2481,6 +2481,13 @@
// bugreport is not shared but made available for manual retrieval.
return status;
}
+ if (options_->screenshot_fd.get() != -1) {
+ bool copy_succeeded = android::os::CopyFileToFd(screenshot_path_,
+ options_->screenshot_fd.get());
+ if (copy_succeeded) {
+ android::os::UnlinkAndLogOnError(screenshot_path_);
+ }
+ }
}
/* vibrate a few but shortly times to let user know it's finished */
@@ -2566,9 +2573,9 @@
return HandleUserConsentDenied();
}
if (consent_result == UserConsentResult::APPROVED) {
- bool copy_succeeded = android::os::CopyFileToFd(ds.path_, ds.options_->bugreport_fd.get());
- if (copy_succeeded && remove(ds.path_.c_str())) {
- MYLOGE("remove(%s): %s", ds.path_.c_str(), strerror(errno));
+ bool copy_succeeded = android::os::CopyFileToFd(path_, options_->bugreport_fd.get());
+ if (copy_succeeded) {
+ android::os::UnlinkAndLogOnError(path_);
}
return copy_succeeded ? Dumpstate::RunStatus::OK : Dumpstate::RunStatus::ERROR;
} else if (consent_result == UserConsentResult::UNAVAILABLE) {
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 4766d82..7fb2f3b 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -347,7 +347,6 @@
// File descriptor to output zip file.
android::base::unique_fd bugreport_fd;
// File descriptor to screenshot file.
- // TODO(b/111441001): Use this fd.
android::base::unique_fd screenshot_fd;
// TODO: rename to MODE.
// Extra options passed as system property.
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index c309364..488070d 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -229,3 +229,23 @@
"libutils",
],
}
+
+// OTA slot script
+cc_prebuilt_binary {
+ name: "otapreopt_slot",
+ srcs: ["otapreopt_slot.sh"],
+ init_rc: ["otapreopt.rc"],
+}
+
+// OTA postinstall script
+cc_prebuilt_binary {
+ name: "otapreopt_script",
+ srcs: ["otapreopt_script.sh"],
+ // Let this depend on otapreopt, the chroot tool and the slot script,
+ // so we just have to mention one in a configuration.
+ required: [
+ "otapreopt",
+ "otapreopt_chroot",
+ "otapreopt_slot",
+ ],
+}
diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk
deleted file mode 100644
index 30de0b3..0000000
--- a/cmds/installd/Android.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-# OTA slot script
-
-include $(CLEAR_VARS)
-LOCAL_MODULE:= otapreopt_slot
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_SRC_FILES := otapreopt_slot.sh
-LOCAL_INIT_RC := otapreopt.rc
-
-include $(BUILD_PREBUILT)
-
-# OTA postinstall script
-
-include $(CLEAR_VARS)
-LOCAL_MODULE:= otapreopt_script
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_SRC_FILES := otapreopt_script.sh
-
-# Let this depend on otapreopt, the chroot tool and the slot script, so we just have to mention one
-# in a configuration.
-LOCAL_REQUIRED_MODULES := otapreopt otapreopt_chroot otapreopt_slot
-
-include $(BUILD_PREBUILT)
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 8c2bcc5..00f9f42 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -158,6 +158,15 @@
}
}
+binder::Status checkArgumentUuidTestOrNull(const std::unique_ptr<std::string>& uuid) {
+ if (!uuid || strcmp(uuid->c_str(), kTestUuid) == 0) {
+ return ok();
+ } else {
+ return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
+ StringPrintf("UUID must be null or \"%s\", got: %s", kTestUuid, uuid->c_str()));
+ }
+}
+
binder::Status checkArgumentPackageName(const std::string& packageName) {
if (is_valid_package_name(packageName.c_str())) {
return ok();
@@ -210,6 +219,13 @@
} \
}
+#define CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(uuid) { \
+ auto status = checkArgumentUuidTestOrNull(uuid); \
+ if (!status.isOk()) { \
+ return status; \
+ } \
+} \
+
#define CHECK_ARGUMENT_PACKAGE_NAME(packageName) { \
binder::Status status = \
checkArgumentPackageName((packageName)); \
@@ -804,25 +820,23 @@
return android_fork_execvp(ARRAY_SIZE(argv), argv, nullptr, false, true);
}
-// TODO(narayan): We should pass through the ceDataInode so that we can call
-// clearAppData(FLAG_CLEAR_CACHE_ONLY | FLAG_CLEAR_CODE_CACHE before we commence
-// the copy.
binder::Status InstalldNativeService::snapshotAppData(
const std::unique_ptr<std::string>& volumeUuid,
- const std::string& packageName, int32_t user, int32_t storageFlags) {
+ const std::string& packageName, int32_t user, int32_t storageFlags,
+ int64_t* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
std::lock_guard<std::recursive_mutex> lock(mLock);
const char* volume_uuid = volumeUuid ? volumeUuid->c_str() : nullptr;
const char* package_name = packageName.c_str();
- if (volume_uuid && strcmp(volume_uuid, kTestUuid)) {
- return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
- StringPrintf("volumeUuid must be null or \"%s\", got: %s", kTestUuid, volume_uuid));
- }
-
binder::Status res = ok();
+ // Default result to 0, it will be populated with inode of ce data snapshot
+ // if FLAG_STORAGE_CE has been passed.
+ if (_aidl_return != nullptr) *_aidl_return = 0;
+
bool clear_ce_on_exit = false;
bool clear_de_on_exit = false;
@@ -851,6 +865,24 @@
return ok();
}
+ // ce_data_inode is not needed when FLAG_CLEAR_CACHE_ONLY is set.
+ binder::Status clear_cache_result = clearAppData(volumeUuid, packageName, user,
+ storageFlags | FLAG_CLEAR_CACHE_ONLY, 0);
+ if (!clear_cache_result.isOk()) {
+ // It should be fine to continue snapshot if we for some reason failed
+ // to clear cache.
+ LOG(WARNING) << "Failed to clear cache of app " << packageName;
+ }
+
+ // ce_data_inode is not needed when FLAG_CLEAR_CODE_CACHE_ONLY is set.
+ binder::Status clear_code_cache_result = clearAppData(volumeUuid, packageName, user,
+ storageFlags | FLAG_CLEAR_CODE_CACHE_ONLY, 0);
+ if (!clear_code_cache_result.isOk()) {
+ // It should be fine to continue snapshot if we for some reason failed
+ // to clear code_cache.
+ LOG(WARNING) << "Failed to clear code_cache of app " << packageName;
+ }
+
if (storageFlags & FLAG_STORAGE_DE) {
auto from = create_data_user_de_package_path(volume_uuid, user, package_name);
auto to = create_data_misc_de_rollback_path(volume_uuid, user);
@@ -885,6 +917,16 @@
clear_ce_on_exit = true;
return res;
}
+ if (_aidl_return != nullptr) {
+ auto ce_snapshot_path = create_data_misc_ce_rollback_package_path(volume_uuid, user,
+ package_name);
+ rc = get_path_inode(ce_snapshot_path, reinterpret_cast<ino_t*>(_aidl_return));
+ if (rc != 0) {
+ res = error(rc, "Failed to get_path_inode for " + ce_snapshot_path);
+ clear_ce_on_exit = true;
+ return res;
+ }
+ }
}
return res;
@@ -895,17 +937,13 @@
const int32_t appId, const int64_t ceDataInode, const std::string& seInfo,
const int32_t user, int32_t storageFlags) {
ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
std::lock_guard<std::recursive_mutex> lock(mLock);
const char* volume_uuid = volumeUuid ? volumeUuid->c_str() : nullptr;
const char* package_name = packageName.c_str();
- if (volume_uuid && strcmp(volume_uuid, kTestUuid)) {
- return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
- StringPrintf("volumeUuid must be null or \"%s\", got: %s", kTestUuid, volume_uuid));
- }
-
auto from_ce = create_data_misc_ce_rollback_package_path(volume_uuid,
user, package_name);
auto from_de = create_data_misc_de_rollback_package_path(volume_uuid,
@@ -956,6 +994,39 @@
return restoreconAppData(volumeUuid, packageName, user, storageFlags, appId, seInfo);
}
+binder::Status InstalldNativeService::destroyAppDataSnapshot(
+ const std::unique_ptr<std::string> &volumeUuid, const std::string& packageName,
+ const int32_t user, const int64_t ceSnapshotInode, int32_t storageFlags) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ const char* volume_uuid = volumeUuid ? volumeUuid->c_str() : nullptr;
+ const char* package_name = packageName.c_str();
+
+ if (storageFlags & FLAG_STORAGE_DE) {
+ auto de_snapshot_path = create_data_misc_de_rollback_package_path(volume_uuid,
+ user, package_name);
+
+ int res = delete_dir_contents_and_dir(de_snapshot_path, true /* ignore_if_missing */);
+ if (res != 0) {
+ return error(res, "Failed clearing snapshot " + de_snapshot_path);
+ }
+ }
+
+ if (storageFlags & FLAG_STORAGE_CE) {
+ auto ce_snapshot_path = create_data_misc_ce_rollback_package_path(volume_uuid,
+ user, package_name, ceSnapshotInode);
+ int res = delete_dir_contents_and_dir(ce_snapshot_path, true /* ignore_if_missing */);
+ if (res != 0) {
+ return error(res, "Failed clearing snapshot " + ce_snapshot_path);
+ }
+ }
+ return ok();
+}
+
+
binder::Status InstalldNativeService::moveCompleteApp(const std::unique_ptr<std::string>& fromUuid,
const std::unique_ptr<std::string>& toUuid, const std::string& packageName,
const std::string& dataAppName, int32_t appId, const std::string& seInfo,
@@ -2071,8 +2142,14 @@
return error("Failed to stat " + _pkgdir);
}
+ char *con = nullptr;
+ if (lgetfilecon(pkgdir, &con) < 0) {
+ return error("Failed to lgetfilecon " + _pkgdir);
+ }
+
if (chown(pkgdir, AID_INSTALL, AID_INSTALL) < 0) {
- return error("Failed to chown " + _pkgdir);
+ res = error("Failed to chown " + _pkgdir);
+ goto out;
}
if (chmod(pkgdir, 0700) < 0) {
@@ -2104,7 +2181,13 @@
goto out;
}
+ if (lsetfilecon(libsymlink, con) < 0) {
+ res = error("Failed to lsetfilecon " + _libsymlink);
+ goto out;
+ }
+
out:
+ free(con);
if (chmod(pkgdir, s.st_mode) < 0) {
auto msg = "Failed to cleanup chmod " + _pkgdir;
if (res.isOk()) {
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 098a0c2..578132d 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -61,10 +61,14 @@
binder::Status fixupAppData(const std::unique_ptr<std::string>& uuid, int32_t flags);
binder::Status snapshotAppData(const std::unique_ptr<std::string>& volumeUuid,
- const std::string& packageName, const int32_t user, int32_t storageFlags);
+ const std::string& packageName, const int32_t user, int32_t storageFlags,
+ int64_t* _aidl_return);
binder::Status restoreAppDataSnapshot(const std::unique_ptr<std::string>& volumeUuid,
const std::string& packageName, const int32_t appId, const int64_t ceDataInode,
const std::string& seInfo, const int32_t user, int32_t storageFlags);
+ binder::Status destroyAppDataSnapshot(const std::unique_ptr<std::string> &volumeUuid,
+ const std::string& packageName, const int32_t user, const int64_t ceSnapshotInode,
+ int32_t storageFlags);
binder::Status getAppSize(const std::unique_ptr<std::string>& uuid,
const std::vector<std::string>& packageNames, int32_t userId, int32_t flags,
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 3d093b8..b345210 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -105,14 +105,12 @@
int userId, int appId, @utf8InCpp String profileName, @utf8InCpp String codePath,
@nullable @utf8InCpp String dexMetadata);
- void snapshotAppData(@nullable @utf8InCpp String uuid, in @utf8InCpp String packageName,
+ long snapshotAppData(@nullable @utf8InCpp String uuid, in @utf8InCpp String packageName,
int userId, int storageFlags);
void restoreAppDataSnapshot(@nullable @utf8InCpp String uuid, in @utf8InCpp String packageName,
int appId, long ceDataInode, @utf8InCpp String seInfo, int user, int storageflags);
-
- // TODO(narayan) we need an API to delete the app data snapshot as well.
- // void destroyAppDataSnapshot(@nullable @utf8InCpp String uuid,
- // in @utf8InCpp String packageName, int userId, int storageFlags);
+ void destroyAppDataSnapshot(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
+ int userId, long ceSnapshotInode, int storageFlags);
const int FLAG_STORAGE_DE = 0x1;
const int FLAG_STORAGE_CE = 0x2;
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index 9965d58..c0f8e91 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -151,11 +151,26 @@
// chown root root /apex
// restorecon /apex
//
+ // except we perform the `restorecon` step just after mounting the tmpfs
+ // filesystem in /postinstall/apex, so that this directory is correctly
+ // labeled (with type `postinstall_apex_mnt_dir`) and may be manipulated in
+ // following operations (`chmod`, `chown`, etc.) following policies
+ // restricted to `postinstall_apex_mnt_dir`:
+ //
+ // mount tmpfs tmpfs /postinstall/apex nodev noexec nosuid
+ // restorecon /postinstall/apex
+ // chmod 0755 /postinstall/apex
+ // chown root root /postinstall/apex
+ //
if (mount("tmpfs", kPostinstallApexDir, "tmpfs", MS_NODEV | MS_NOEXEC | MS_NOSUID, nullptr)
!= 0) {
PLOG(ERROR) << "Failed to mount tmpfs in " << kPostinstallApexDir;
exit(209);
}
+ if (selinux_android_restorecon(kPostinstallApexDir, 0) < 0) {
+ PLOG(ERROR) << "Failed to restorecon " << kPostinstallApexDir;
+ exit(214);
+ }
if (chmod(kPostinstallApexDir, 0755) != 0) {
PLOG(ERROR) << "Failed to chmod " << kPostinstallApexDir << " to 0755";
exit(210);
@@ -164,10 +179,6 @@
PLOG(ERROR) << "Failed to chown " << kPostinstallApexDir << " to root:root";
exit(211);
}
- if (selinux_android_restorecon(kPostinstallApexDir, 0) < 0) {
- PLOG(ERROR) << "Failed to restorecon " << kPostinstallApexDir;
- exit(212);
- }
// Chdir into /postinstall.
if (chdir("/postinstall") != 0) {
diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp
index d17cf5f..1d50737 100644
--- a/cmds/installd/tests/installd_service_test.cpp
+++ b/cmds/installd/tests/installd_service_test.cpp
@@ -287,8 +287,13 @@
0700, 10000, 20000, false /* follow_symlinks */));
// Request a snapshot of the CE content but not the DE content.
+ int64_t ce_snapshot_inode;
ASSERT_TRUE(service->snapshotAppData(std::make_unique<std::string>("TEST"),
- "com.foo", 0, FLAG_STORAGE_CE).isOk());
+ "com.foo", 0, FLAG_STORAGE_CE, &ce_snapshot_inode).isOk());
+ struct stat buf;
+ memset(&buf, 0, sizeof(buf));
+ ASSERT_EQ(0, stat((rollback_ce_dir + "/com.foo").c_str(), &buf));
+ ASSERT_EQ(ce_snapshot_inode, (int64_t) buf.st_ino);
std::string ce_content, de_content;
// At this point, we should have the CE content but not the DE content.
@@ -306,7 +311,9 @@
// Request a snapshot of the DE content but not the CE content.
ASSERT_TRUE(service->snapshotAppData(std::make_unique<std::string>("TEST"),
- "com.foo", 0, FLAG_STORAGE_DE).isOk());
+ "com.foo", 0, FLAG_STORAGE_DE, &ce_snapshot_inode).isOk());
+ // Only DE content snapshot was requested.
+ ASSERT_EQ(ce_snapshot_inode, 0);
// At this point, both the CE as well as the DE content should be fully
// populated.
@@ -325,7 +332,7 @@
// Request a snapshot of both the CE as well as the DE content.
ASSERT_TRUE(service->snapshotAppData(std::make_unique<std::string>("TEST"),
- "com.foo", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
+ "com.foo", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr).isOk());
ASSERT_TRUE(android::base::ReadFileToString(
rollback_ce_dir + "/com.foo/file1", &ce_content, false /* follow_symlinks */));
@@ -351,10 +358,13 @@
auto scope_guard = android::base::make_scope_guard(deleter);
+ int64_t ce_snapshot_inode;
ASSERT_TRUE(service->snapshotAppData(std::make_unique<std::string>("TEST"),
- "com.foo", 0, FLAG_STORAGE_CE).isOk());
+ "com.foo", 0, FLAG_STORAGE_CE, &ce_snapshot_inode).isOk());
ASSERT_TRUE(service->snapshotAppData(std::make_unique<std::string>("TEST"),
- "com.foo", 0, FLAG_STORAGE_DE).isOk());
+ "com.foo", 0, FLAG_STORAGE_DE, nullptr).isOk());
+ // No CE content snapshot was performed.
+ ASSERT_EQ(ce_snapshot_inode, 0);
// The snapshot calls must succeed but there should be no snapshot
// created.
@@ -404,7 +414,7 @@
0700, 10000, 20000, false /* follow_symlinks */));
ASSERT_TRUE(service->snapshotAppData(std::make_unique<std::string>("TEST"),
- "com.foo", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
+ "com.foo", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE, nullptr).isOk());
// Previous snapshot (with data for file1) must be cleared.
struct stat sb;
@@ -430,7 +440,62 @@
auto scope_guard = android::base::make_scope_guard(deleter);
ASSERT_FALSE(service->snapshotAppData(std::make_unique<std::string>("FOO"),
- "com.foo", 0, FLAG_STORAGE_DE).isOk());
+ "com.foo", 0, FLAG_STORAGE_DE, nullptr).isOk());
+}
+
+TEST_F(ServiceTest, CreateAppDataSnapshot_ClearsCache) {
+ auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
+ auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
+ auto fake_package_ce_cache_path = read_path_inode(fake_package_ce_path,
+ "cache", kXattrInodeCache);
+ auto fake_package_ce_code_cache_path = read_path_inode(fake_package_ce_path,
+ "code_cache", kXattrInodeCache);
+ auto fake_package_de_cache_path = fake_package_de_path + "/cache";
+ auto fake_package_de_code_cache_path = fake_package_de_path + "/code_cache";
+
+ ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
+ ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
+ ASSERT_TRUE(mkdirs(fake_package_ce_cache_path, 700));
+ ASSERT_TRUE(mkdirs(fake_package_ce_code_cache_path, 700));
+ ASSERT_TRUE(mkdirs(fake_package_de_cache_path, 700));
+ ASSERT_TRUE(mkdirs(fake_package_de_code_cache_path, 700));
+
+ auto deleter = [&fake_package_ce_path, &fake_package_de_path,
+ &fake_package_ce_cache_path, &fake_package_ce_code_cache_path,
+ &fake_package_de_cache_path, &fake_package_de_code_cache_path]() {
+ delete_dir_contents(fake_package_ce_path, true);
+ delete_dir_contents(fake_package_de_path, true);
+ delete_dir_contents(fake_package_ce_cache_path, true);
+ delete_dir_contents(fake_package_ce_code_cache_path, true);
+ delete_dir_contents(fake_package_de_cache_path, true);
+ delete_dir_contents(fake_package_de_code_cache_path, true);
+ rmdir(fake_package_ce_cache_path.c_str());
+ rmdir(fake_package_ce_code_cache_path.c_str());
+ rmdir(fake_package_de_cache_path.c_str());
+ rmdir(fake_package_de_code_cache_path.c_str());
+ };
+ auto scope_guard = android::base::make_scope_guard(deleter);
+
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "TEST_CONTENT_CE", fake_package_ce_cache_path + "/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "TEST_CONTENT_CE", fake_package_ce_code_cache_path + "/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "TEST_CONTENT_DE", fake_package_de_cache_path + "/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "TEST_CONTENT_DE", fake_package_de_code_cache_path + "/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+ ASSERT_TRUE(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+ "com.foo", 0, FLAG_STORAGE_CE | FLAG_STORAGE_DE, nullptr).isOk());
+ // The snapshot call must clear cache.
+ struct stat sb;
+ ASSERT_EQ(-1, stat((fake_package_ce_cache_path + "/file1").c_str(), &sb));
+ ASSERT_EQ(-1, stat((fake_package_ce_code_cache_path + "/file1").c_str(), &sb));
+ ASSERT_EQ(-1, stat((fake_package_de_cache_path + "/file1").c_str(), &sb));
+ ASSERT_EQ(-1, stat((fake_package_de_code_cache_path + "/file1").c_str(), &sb));
}
TEST_F(ServiceTest, RestoreAppDataSnapshot) {
@@ -486,6 +551,133 @@
ASSERT_EQ("DE_RESTORE_CONTENT", de_content);
}
+TEST_F(ServiceTest, CreateSnapshotThenDestroyIt) {
+ auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
+ auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+
+ ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
+ ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
+
+ auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
+ auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
+
+ ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
+ ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
+
+ auto deleter = [&rollback_ce_dir, &rollback_de_dir,
+ &fake_package_ce_path, &fake_package_de_path]() {
+ delete_dir_contents(rollback_ce_dir, true);
+ delete_dir_contents(rollback_de_dir, true);
+ delete_dir_contents(fake_package_ce_path, true);
+ delete_dir_contents(fake_package_de_path, true);
+ rmdir(rollback_ce_dir.c_str());
+ rmdir(rollback_de_dir.c_str());
+ };
+ auto scope_guard = android::base::make_scope_guard(deleter);
+
+ // Prepare data for snapshot.
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "TEST_CONTENT_CE", fake_package_ce_path + "/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "TEST_CONTENT_DE", fake_package_de_path + "/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+
+ int64_t ce_snapshot_inode;
+ // Request a snapshot of both the CE as well as the DE content.
+ ASSERT_TRUE(service->snapshotAppData(std::make_unique<std::string>("TEST"),
+ "com.foo", 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE, &ce_snapshot_inode).isOk());
+ // Because CE data snapshot was requested, ce_snapshot_inode can't be null.
+ ASSERT_NE(0, ce_snapshot_inode);
+ // Check snapshot is there.
+ struct stat sb;
+ ASSERT_EQ(0, stat((rollback_ce_dir + "/com.foo").c_str(), &sb));
+ ASSERT_EQ(0, stat((rollback_de_dir + "/com.foo").c_str(), &sb));
+
+
+ ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique<std::string>("TEST"),
+ "com.foo", 0, ce_snapshot_inode, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
+ // Check snapshot is deleted.
+ ASSERT_EQ(-1, stat((rollback_ce_dir + "/com.foo").c_str(), &sb));
+ ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo").c_str(), &sb));
+}
+
+TEST_F(ServiceTest, DestroyAppDataSnapshot_CeSnapshotInodeIsZero) {
+ auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
+ auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+
+ ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
+ ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
+
+ auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
+ auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
+
+ ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
+ ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
+
+ auto deleter = [&rollback_ce_dir, &rollback_de_dir,
+ &fake_package_ce_path, &fake_package_de_path]() {
+ delete_dir_contents(rollback_ce_dir, true);
+ delete_dir_contents(rollback_de_dir, true);
+ delete_dir_contents(fake_package_ce_path, true);
+ delete_dir_contents(fake_package_de_path, true);
+ rmdir(rollback_ce_dir.c_str());
+ rmdir(rollback_de_dir.c_str());
+ };
+ auto scope_guard = android::base::make_scope_guard(deleter);
+
+ // Create a snapshot
+ ASSERT_TRUE(mkdirs(rollback_ce_dir + "/com.foo/", 700));
+ ASSERT_TRUE(mkdirs(rollback_de_dir + "/com.foo/", 700));
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "CE_RESTORE_CONTENT", rollback_ce_dir + "/com.foo/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+ ASSERT_TRUE(android::base::WriteStringToFile(
+ "DE_RESTORE_CONTENT", rollback_de_dir + "/com.foo/file1",
+ 0700, 10000, 20000, false /* follow_symlinks */));
+
+ ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique<std::string>("TEST"),
+ "com.foo", 0, 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
+
+ // Check snapshot is deleted.
+ struct stat sb;
+ ASSERT_EQ(-1, stat((rollback_ce_dir + "/com.foo").c_str(), &sb));
+ ASSERT_EQ(-1, stat((rollback_de_dir + "/com.foo").c_str(), &sb));
+
+ // Check that deleting already deleted snapshot is no-op.
+ ASSERT_TRUE(service->destroyAppDataSnapshot(std::make_unique<std::string>("TEST"),
+ "com.foo", 0, 0, FLAG_STORAGE_DE | FLAG_STORAGE_CE).isOk());
+}
+
+TEST_F(ServiceTest, DestroyAppDataSnapshot_WrongVolumeUuid) {
+ // Setup rollback data to make sure that test fails due to wrong volumeUuid
+ // being passed, not because of some other reason.
+ auto rollback_ce_dir = create_data_misc_ce_rollback_path("TEST", 0);
+ auto rollback_de_dir = create_data_misc_de_rollback_path("TEST", 0);
+
+ ASSERT_TRUE(mkdirs(rollback_ce_dir, 700));
+ ASSERT_TRUE(mkdirs(rollback_de_dir, 700));
+
+ auto fake_package_ce_path = create_data_user_ce_package_path("TEST", 0, "com.foo");
+ auto fake_package_de_path = create_data_user_de_package_path("TEST", 0, "com.foo");
+
+ ASSERT_TRUE(mkdirs(fake_package_ce_path, 700));
+ ASSERT_TRUE(mkdirs(fake_package_de_path, 700));
+
+ auto deleter = [&rollback_ce_dir, &rollback_de_dir,
+ &fake_package_ce_path, &fake_package_de_path]() {
+ delete_dir_contents(rollback_ce_dir, true);
+ delete_dir_contents(rollback_de_dir, true);
+ delete_dir_contents(fake_package_ce_path, true);
+ delete_dir_contents(fake_package_de_path, true);
+ rmdir(rollback_ce_dir.c_str());
+ rmdir(rollback_de_dir.c_str());
+ };
+ auto scope_guard = android::base::make_scope_guard(deleter);
+
+ ASSERT_FALSE(service->destroyAppDataSnapshot(std::make_unique<std::string>("BAR"),
+ "com.foo", 0, 0, FLAG_STORAGE_DE).isOk());
+}
TEST_F(ServiceTest, RestoreAppDataSnapshot_WrongVolumeUuid) {
// Setup rollback data to make sure that fails due to wrong volumeUuid being
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index ce99fff..1782aa2 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -18,6 +18,7 @@
#include <string.h>
#include <android-base/logging.h>
+#include <android-base/scopeguard.h>
#include <gtest/gtest.h>
#include "InstalldNativeService.h"
@@ -565,6 +566,29 @@
EXPECT_EQ("/data/misc_de/10/rollback",
create_data_misc_de_rollback_path(nullptr, 10));
+ EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
+ create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo", 0));
+ EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
+ create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo", 239));
+
+ auto rollback_ce_package_path = create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo");
+ auto deleter = [&rollback_ce_package_path]() {
+ delete_dir_contents_and_dir(rollback_ce_package_path, true /* ignore_if_missing */);
+ };
+ auto scope_guard = android::base::make_scope_guard(deleter);
+
+ ASSERT_NE(-1, mkdir(rollback_ce_package_path.c_str(), 700));
+
+ ino_t ce_data_inode;
+ ASSERT_EQ(0, get_path_inode(rollback_ce_package_path, &ce_data_inode));
+
+ EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
+ create_data_misc_ce_rollback_package_path(nullptr, 0, "com.foo", ce_data_inode));
+ // Check that path defined by inode is picked even if it's not the same as
+ // the fallback one.
+ EXPECT_EQ("/data/misc_ce/0/rollback/com.foo",
+ create_data_misc_ce_rollback_package_path(nullptr, 0, "com.bar", ce_data_inode));
+
// These last couple of cases are never exercised in production because we
// only snapshot apps in the primary data partition. Exercise them here for
// the sake of completeness.
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 24f5eab..5b487bb 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -70,6 +70,35 @@
CHECK(is_valid_package_name(package_name));
}
+static std::string resolve_ce_path_by_inode_or_fallback(const std::string& root_path,
+ ino_t ce_data_inode, const std::string& fallback) {
+ if (ce_data_inode != 0) {
+ DIR* dir = opendir(root_path.c_str());
+ if (dir == nullptr) {
+ PLOG(ERROR) << "Failed to opendir " << root_path;
+ return fallback;
+ }
+
+ struct dirent* ent;
+ while ((ent = readdir(dir))) {
+ if (ent->d_ino == ce_data_inode) {
+ auto resolved = StringPrintf("%s/%s", root_path.c_str(), ent->d_name);
+ if (resolved != fallback) {
+ LOG(DEBUG) << "Resolved path " << resolved << " for inode " << ce_data_inode
+ << " instead of " << fallback;
+ }
+ closedir(dir);
+ return resolved;
+ }
+ }
+ LOG(WARNING) << "Failed to resolve inode " << ce_data_inode << "; using " << fallback;
+ closedir(dir);
+ return fallback;
+ } else {
+ return fallback;
+ }
+}
+
/**
* Create the path name where package app contents should be stored for
* the given volume UUID and package name. An empty UUID is assumed to
@@ -113,34 +142,8 @@
// For testing purposes, rely on the inode when defined; this could be
// optimized to use access() in the future.
auto fallback = create_data_user_ce_package_path(volume_uuid, user, package_name);
- if (ce_data_inode != 0) {
- auto user_path = create_data_user_ce_path(volume_uuid, user);
- DIR* dir = opendir(user_path.c_str());
- if (dir == nullptr) {
- PLOG(ERROR) << "Failed to opendir " << user_path;
- return fallback;
- }
-
- struct dirent* ent;
- while ((ent = readdir(dir))) {
- if (ent->d_ino == ce_data_inode) {
- auto resolved = StringPrintf("%s/%s", user_path.c_str(), ent->d_name);
-#if DEBUG_XATTRS
- if (resolved != fallback) {
- LOG(DEBUG) << "Resolved path " << resolved << " for inode " << ce_data_inode
- << " instead of " << fallback;
- }
-#endif
- closedir(dir);
- return resolved;
- }
- }
- LOG(WARNING) << "Failed to resolve inode " << ce_data_inode << "; using " << fallback;
- closedir(dir);
- return fallback;
- } else {
- return fallback;
- }
+ auto user_path = create_data_user_ce_path(volume_uuid, user);
+ return resolve_ce_path_by_inode_or_fallback(user_path, ce_data_inode, fallback);
}
std::string create_data_user_de_package_path(const char* volume_uuid,
@@ -209,6 +212,13 @@
create_data_misc_ce_rollback_path(volume_uuid, user).c_str(), package_name);
}
+std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
+ userid_t user, const char* package_name, ino_t ce_rollback_inode) {
+ auto fallback = create_data_misc_ce_rollback_package_path(volume_uuid, user, package_name);
+ auto user_path = create_data_misc_ce_rollback_path(volume_uuid, user);
+ return resolve_ce_path_by_inode_or_fallback(user_path, ce_rollback_inode, fallback);
+}
+
std::string create_data_misc_de_rollback_package_path(const char* volume_uuid,
userid_t user, const char* package_name) {
return StringPrintf("%s/%s",
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 5afe059..0711b34 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -65,6 +65,8 @@
std::string create_data_misc_de_rollback_path(const char* volume_uuid, userid_t user);
std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
userid_t user, const char* package_name);
+std::string create_data_misc_ce_rollback_package_path(const char* volume_uuid,
+ userid_t user, const char* package_name, ino_t ce_rollback_inode);
std::string create_data_misc_de_rollback_package_path(const char* volume_uuid,
userid_t user, const char* package_name);
diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h
index 2b8cc57..a065a4c 100644
--- a/include/input/InputWindow.h
+++ b/include/input/InputWindow.h
@@ -163,6 +163,7 @@
int32_t ownerUid;
int32_t inputFeatures;
int32_t displayId;
+ int32_t portalToDisplayId = ADISPLAY_ID_NONE;
InputApplicationInfo applicationInfo;
void addTouchableRegion(const Rect& region);
diff --git a/libs/binder/include/binder/ActivityManager.h b/libs/binder/include/binder/ActivityManager.h
index 26dafd0..7b086d0 100644
--- a/libs/binder/include/binder/ActivityManager.h
+++ b/libs/binder/include/binder/ActivityManager.h
@@ -46,23 +46,24 @@
PROCESS_STATE_PERSISTENT = 0,
PROCESS_STATE_PERSISTENT_UI = 1,
PROCESS_STATE_TOP = 2,
- PROCESS_STATE_FOREGROUND_SERVICE = 3,
- PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 4,
- PROCESS_STATE_IMPORTANT_FOREGROUND = 5,
- PROCESS_STATE_IMPORTANT_BACKGROUND = 6,
- PROCESS_STATE_TRANSIENT_BACKGROUND = 7,
- PROCESS_STATE_BACKUP = 8,
- PROCESS_STATE_SERVICE = 9,
- PROCESS_STATE_RECEIVER = 10,
- PROCESS_STATE_TOP_SLEEPING = 11,
- PROCESS_STATE_HEAVY_WEIGHT = 12,
- PROCESS_STATE_HOME = 13,
- PROCESS_STATE_LAST_ACTIVITY = 14,
- PROCESS_STATE_CACHED_ACTIVITY = 15,
- PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 16,
- PROCESS_STATE_CACHED_RECENT = 17,
- PROCESS_STATE_CACHED_EMPTY = 18,
- PROCESS_STATE_NONEXISTENT = 19,
+ PROCESS_STATE_FOREGROUND_SERVICE_LOCATION = 3,
+ PROCESS_STATE_FOREGROUND_SERVICE = 4,
+ PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 5,
+ PROCESS_STATE_IMPORTANT_FOREGROUND = 6,
+ PROCESS_STATE_IMPORTANT_BACKGROUND = 7,
+ PROCESS_STATE_TRANSIENT_BACKGROUND = 8,
+ PROCESS_STATE_BACKUP = 9,
+ PROCESS_STATE_SERVICE = 10,
+ PROCESS_STATE_RECEIVER = 11,
+ PROCESS_STATE_TOP_SLEEPING = 12,
+ PROCESS_STATE_HEAVY_WEIGHT = 13,
+ PROCESS_STATE_HOME = 14,
+ PROCESS_STATE_LAST_ACTIVITY = 15,
+ PROCESS_STATE_CACHED_ACTIVITY = 16,
+ PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 17,
+ PROCESS_STATE_CACHED_RECENT = 18,
+ PROCESS_STATE_CACHED_EMPTY = 19,
+ PROCESS_STATE_NONEXISTENT = 20,
};
ActivityManager();
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 0826544..68011bb 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -65,12 +65,10 @@
"include_ndk/android/*.h",
],
license: "NOTICE",
- draft: true,
}
ndk_library {
name: "libbinder_ndk",
symbol_file: "libbinder_ndk.map.txt",
first_version: "29",
- draft: true,
}
diff --git a/libs/input/InputWindow.cpp b/libs/input/InputWindow.cpp
index aa1371f..5c5613d 100644
--- a/libs/input/InputWindow.cpp
+++ b/libs/input/InputWindow.cpp
@@ -95,6 +95,7 @@
output.writeInt32(ownerUid);
output.writeInt32(inputFeatures);
output.writeInt32(displayId);
+ output.writeInt32(portalToDisplayId);
applicationInfo.write(output);
output.write(touchableRegion);
@@ -136,6 +137,7 @@
ret.ownerUid = from.readInt32();
ret.inputFeatures = from.readInt32();
ret.displayId = from.readInt32();
+ ret.portalToDisplayId = from.readInt32();
ret.applicationInfo = InputApplicationInfo::read(from);
from.read(ret.touchableRegion);
diff --git a/libs/input/tests/InputWindow_test.cpp b/libs/input/tests/InputWindow_test.cpp
index 5e5893f..09dd72b 100644
--- a/libs/input/tests/InputWindow_test.cpp
+++ b/libs/input/tests/InputWindow_test.cpp
@@ -61,6 +61,7 @@
i.ownerUid = 24;
i.inputFeatures = 29;
i.displayId = 34;
+ i.portalToDisplayId = 2;
Parcel p;
i.write(p);
@@ -90,6 +91,7 @@
ASSERT_EQ(i.ownerUid, i2.ownerUid);
ASSERT_EQ(i.inputFeatures, i2.inputFeatures);
ASSERT_EQ(i.displayId, i2.displayId);
+ ASSERT_EQ(i.portalToDisplayId, i2.portalToDisplayId);
}
} // namespace test
diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp
index 9669135..4b20772 100644
--- a/libs/ui/BufferHubBuffer.cpp
+++ b/libs/ui/BufferHubBuffer.cpp
@@ -167,32 +167,30 @@
return -EINVAL;
}
+ // Import fds. Dup fds because hidl_handle owns the fds.
+ unique_fd ashmemFd(fcntl(bufferTraits.bufferInfo->data[0], F_DUPFD_CLOEXEC, 0));
+ mMetadata = BufferHubMetadata::Import(std::move(ashmemFd));
+ if (!mMetadata.IsValid()) {
+ ALOGE("%s: Received an invalid metadata.", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ mEventFd = BufferHubEventFd(fcntl(bufferTraits.bufferInfo->data[1], F_DUPFD_CLOEXEC, 0));
+ if (!mEventFd.isValid()) {
+ ALOGE("%s: Received ad invalid event fd.", __FUNCTION__);
+ return -EINVAL;
+ }
+
int bufferId = bufferTraits.bufferInfo->data[2];
if (bufferId < 0) {
- ALOGE("%s: Received an invalid (negative) id!", __FUNCTION__);
+ ALOGE("%s: Received an invalid (negative) id.", __FUNCTION__);
return -EINVAL;
}
uint32_t clientBitMask;
memcpy(&clientBitMask, &bufferTraits.bufferInfo->data[3], sizeof(clientBitMask));
if (clientBitMask == 0U) {
- ALOGE("%s: Received a invalid client state mask!", __FUNCTION__);
- return -EINVAL;
- }
-
- const int eventFd = bufferTraits.bufferInfo->data[1];
- if (eventFd < 0) {
- ALOGE("%s: Received a invalid event fd!", __FUNCTION__);
- return -EINVAL;
- }
- mEventFd = BufferHubEventFd(eventFd);
-
- // Import the metadata. Dup since hidl_handle owns the fd
- unique_fd ashmemFd(fcntl(bufferTraits.bufferInfo->data[0], F_DUPFD_CLOEXEC, 0));
- mMetadata = BufferHubMetadata::Import(std::move(ashmemFd));
-
- if (!mMetadata.IsValid()) {
- ALOGE("%s: invalid metadata.", __FUNCTION__);
+ ALOGE("%s: Received an invalid client state mask.", __FUNCTION__);
return -EINVAL;
}
@@ -320,6 +318,11 @@
return 0;
}
+bool BufferHubBuffer::IsReleased() const {
+ return (buffer_state_->load(std::memory_order_acquire) &
+ active_clients_bit_mask_->load(std::memory_order_acquire)) == 0;
+}
+
bool BufferHubBuffer::IsValid() const {
return mBufferHandle.getNativeHandle() != nullptr && mId >= 0 && mClientStateMask != 0U &&
mEventFd.get() >= 0 && mMetadata.IsValid() && mBufferClient != nullptr;
diff --git a/libs/ui/include/ui/BufferHubBuffer.h b/libs/ui/include/ui/BufferHubBuffer.h
index 42d9320..0b6d75a 100644
--- a/libs/ui/include/ui/BufferHubBuffer.h
+++ b/libs/ui/include/ui/BufferHubBuffer.h
@@ -59,9 +59,7 @@
const BufferHubEventFd& eventFd() const { return mEventFd; }
// Returns the current value of MetadataHeader::buffer_state.
- uint32_t buffer_state() {
- return mMetadata.metadata_header()->buffer_state.load(std::memory_order_acquire);
- }
+ uint32_t buffer_state() const { return buffer_state_->load(std::memory_order_acquire); }
// A state mask which is unique to a buffer hub client among all its siblings sharing the same
// concrete graphic buffer.
@@ -97,6 +95,9 @@
// current cycle of the usage of the buffer.
int Release();
+ // Returns whether the buffer is released by all active clients or not.
+ bool IsReleased() const;
+
// Creates a token that stands for this BufferHubBuffer client and could be used for Import to
// create another BufferHubBuffer. The new BufferHubBuffer will share the same underlying
// gralloc buffer and ashmem region for metadata. Note that the caller owns the token and
diff --git a/libs/ui/include/ui/BufferHubDefs.h b/libs/ui/include/ui/BufferHubDefs.h
index 43d900c..ff970cb 100644
--- a/libs/ui/include/ui/BufferHubDefs.h
+++ b/libs/ui/include/ui/BufferHubDefs.h
@@ -106,11 +106,6 @@
return high_bits == 0U;
}
-// Returns true if all clients are in released state.
-static inline bool IsBufferReleased(uint32_t state) {
- return state == 0U;
-}
-
// Returns true if the input client is in released state.
static inline bool IsClientReleased(uint32_t state, uint32_t client_bit_mask) {
return (state & client_bit_mask) == 0U;
diff --git a/libs/ui/tests/BufferHubBuffer_test.cpp b/libs/ui/tests/BufferHubBuffer_test.cpp
index 9e687d2..3bcd935 100644
--- a/libs/ui/tests/BufferHubBuffer_test.cpp
+++ b/libs/ui/tests/BufferHubBuffer_test.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "BufferHubBufferTest"
+#include <errno.h>
#include <sys/epoll.h>
#include <android/hardware_buffer.h>
@@ -34,7 +35,6 @@
using ::android::BufferHubDefs::AnyClientAcquired;
using ::android::BufferHubDefs::AnyClientGained;
using ::android::BufferHubDefs::AnyClientPosted;
-using ::android::BufferHubDefs::IsBufferReleased;
using ::android::BufferHubDefs::IsClientAcquired;
using ::android::BufferHubDefs::IsClientGained;
using ::android::BufferHubDefs::IsClientPosted;
@@ -161,19 +161,21 @@
EXPECT_NE(b1->client_state_mask(), b2->client_state_mask());
// Both buffer instances should be in released state currently.
- EXPECT_TRUE(IsBufferReleased(b1->buffer_state()));
- EXPECT_TRUE(IsBufferReleased(b2->buffer_state()));
+ EXPECT_TRUE(b1->IsReleased());
+ EXPECT_TRUE(b2->IsReleased());
// The event fd should behave like duped event fds.
const BufferHubEventFd& eventFd1 = b1->eventFd();
+ ASSERT_GE(eventFd1.get(), 0);
const BufferHubEventFd& eventFd2 = b2->eventFd();
+ ASSERT_GE(eventFd2.get(), 0);
base::unique_fd epollFd(epoll_create(64));
ASSERT_GE(epollFd.get(), 0);
// Add eventFd1 to epoll set, and signal eventFd2.
epoll_event e = {.events = EPOLLIN | EPOLLET, .data = {.u32 = 0}};
- ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd1.get(), &e), 0);
+ ASSERT_EQ(epoll_ctl(epollFd.get(), EPOLL_CTL_ADD, eventFd1.get(), &e), 0) << strerror(errno);
std::array<epoll_event, 1> events;
EXPECT_EQ(epoll_wait(epollFd.get(), events.data(), events.size(), 0), 0);
@@ -227,7 +229,7 @@
}
TEST_F(BufferHubBufferStateTransitionTest, GainBuffer_fromReleasedState) {
- ASSERT_TRUE(IsBufferReleased(b1->buffer_state()));
+ ASSERT_TRUE(b1->IsReleased());
// Successful gaining the buffer should change the buffer state bit of b1 to
// gained state, other client state bits to released state.
@@ -316,7 +318,7 @@
}
TEST_F(BufferHubBufferStateTransitionTest, PostBuffer_fromReleasedState) {
- ASSERT_TRUE(IsBufferReleased(b1->buffer_state()));
+ ASSERT_TRUE(b1->IsReleased());
// Posting from released state should fail.
EXPECT_EQ(b1->Post(), -EBUSY);
@@ -354,7 +356,7 @@
}
TEST_F(BufferHubBufferStateTransitionTest, AcquireBuffer_fromReleasedState) {
- ASSERT_TRUE(IsBufferReleased(b1->buffer_state()));
+ ASSERT_TRUE(b1->IsReleased());
// Acquiring form released state should fail.
EXPECT_EQ(b1->Acquire(), -EBUSY);
@@ -371,13 +373,13 @@
}
TEST_F(BufferHubBufferStateTransitionTest, ReleaseBuffer_fromSelfInReleasedState) {
- ASSERT_TRUE(IsBufferReleased(b1->buffer_state()));
+ ASSERT_TRUE(b1->IsReleased());
EXPECT_EQ(b1->Release(), 0);
}
TEST_F(BufferHubBufferStateTransitionTest, ReleaseBuffer_fromSelfInGainedState) {
- ASSERT_TRUE(IsBufferReleased(b1->buffer_state()));
+ ASSERT_TRUE(b1->IsReleased());
ASSERT_EQ(b1->Gain(), 0);
ASSERT_TRUE(AnyClientGained(b1->buffer_state()));
diff --git a/libs/ui/tests/BufferHubMetadata_test.cpp b/libs/ui/tests/BufferHubMetadata_test.cpp
index 11f8e57..b7f0b4b 100644
--- a/libs/ui/tests/BufferHubMetadata_test.cpp
+++ b/libs/ui/tests/BufferHubMetadata_test.cpp
@@ -17,8 +17,6 @@
#include <gtest/gtest.h>
#include <ui/BufferHubMetadata.h>
-using android::BufferHubDefs::IsBufferReleased;
-
namespace android {
namespace dvr {
@@ -52,13 +50,17 @@
BufferHubDefs::MetadataHeader* mh1 = m1.metadata_header();
EXPECT_NE(mh1, nullptr);
- EXPECT_TRUE(IsBufferReleased(mh1->buffer_state.load()));
+ // Check if the newly allocated buffer is initialized in released state (i.e.
+ // state equals to 0U).
+ EXPECT_TRUE(mh1->buffer_state.load() == 0U);
EXPECT_TRUE(m2.IsValid());
BufferHubDefs::MetadataHeader* mh2 = m2.metadata_header();
EXPECT_NE(mh2, nullptr);
- EXPECT_TRUE(IsBufferReleased(mh2->buffer_state.load()));
+ // Check if the newly allocated buffer is initialized in released state (i.e.
+ // state equals to 0U).
+ EXPECT_TRUE(mh2->buffer_state.load() == 0U);
}
TEST_F(BufferHubMetadataTest, MoveMetadataInvalidatesOldOne) {
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index ed5a992..a47a98f 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -22,7 +22,6 @@
using android::BufferHubDefs::AnyClientAcquired;
using android::BufferHubDefs::AnyClientGained;
using android::BufferHubDefs::AnyClientPosted;
-using android::BufferHubDefs::IsBufferReleased;
using android::BufferHubDefs::IsClientAcquired;
using android::BufferHubDefs::IsClientPosted;
using android::BufferHubDefs::IsClientReleased;
@@ -284,7 +283,7 @@
EXPECT_EQ(0, c->ReleaseAsync(&metadata, invalid_fence));
EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
EXPECT_EQ(p->buffer_state(), c->buffer_state());
- EXPECT_TRUE(IsBufferReleased(p->buffer_state()));
+ EXPECT_TRUE(p->is_released());
// Acquire and post in released state should fail.
EXPECT_EQ(-EBUSY, c->AcquireAsync(&metadata, &invalid_fence));
@@ -356,7 +355,7 @@
// Producer state bit is in released state after post, other clients shall be
// in posted state although there is no consumer of this buffer yet.
ASSERT_TRUE(IsClientReleased(p->buffer_state(), p->client_state_mask()));
- ASSERT_FALSE(IsBufferReleased(p->buffer_state()));
+ ASSERT_TRUE(p->is_released());
ASSERT_TRUE(AnyClientPosted(p->buffer_state()));
// Gain in released state should succeed.
@@ -374,7 +373,7 @@
for (size_t i = 0; i < kMaxConsumerCount; ++i) {
cs[i] = ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(cs[i].get() != nullptr);
- EXPECT_TRUE(IsBufferReleased(cs[i]->buffer_state()));
+ EXPECT_TRUE(cs[i]->is_released());
EXPECT_NE(producer_state_mask, cs[i]->client_state_mask());
}
@@ -397,12 +396,12 @@
// All consumers have to release before the buffer is considered to be
// released.
for (size_t i = 0; i < kMaxConsumerCount; i++) {
- EXPECT_FALSE(IsBufferReleased(p->buffer_state()));
+ EXPECT_FALSE(p->is_released());
EXPECT_EQ(0, cs[i]->ReleaseAsync(&metadata, invalid_fence));
}
EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
- EXPECT_TRUE(IsBufferReleased(p->buffer_state()));
+ EXPECT_TRUE(p->is_released());
// Buffer state cross all clients must be consistent.
for (size_t i = 0; i < kMaxConsumerCount; i++) {
@@ -445,7 +444,7 @@
// Post the gained buffer before any consumer gets created.
EXPECT_EQ(0, p->PostAsync(&metadata, invalid_fence));
- EXPECT_FALSE(IsBufferReleased(p->buffer_state()));
+ EXPECT_TRUE(p->is_released());
EXPECT_EQ(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
// Newly created consumer will be signalled for the posted buffer although it
@@ -481,7 +480,7 @@
// need to wait until the releasd is confirmed before creating another
// consumer.
EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
- EXPECT_TRUE(IsBufferReleased(p->buffer_state()));
+ EXPECT_TRUE(p->is_released());
// Create another consumer immediately after the release, should not make the
// buffer un-released.
@@ -489,7 +488,7 @@
ConsumerBuffer::Import(p->CreateConsumer());
ASSERT_TRUE(c2.get() != nullptr);
- EXPECT_TRUE(IsBufferReleased(p->buffer_state()));
+ EXPECT_TRUE(p->is_released());
EXPECT_EQ(0, p->GainAsync(&metadata, &invalid_fence));
EXPECT_TRUE(AnyClientGained(p->buffer_state()));
}
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
index f5761d5..bab7367 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
@@ -51,10 +51,6 @@
return android::BufferHubDefs::IsClientAcquired(state, client_bit_mask);
}
-static inline bool IsBufferReleased(uint32_t state) {
- return android::BufferHubDefs::IsBufferReleased(state);
-}
-
static inline bool IsClientReleased(uint32_t state, uint32_t client_bit_mask) {
return android::BufferHubDefs::IsClientReleased(state, client_bit_mask);
}
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
deleted file mode 100644
index 2f42ab6..0000000
--- a/opengl/libs/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
diff --git a/opengl/tests/Android.mk b/opengl/tests/Android.mk
deleted file mode 100644
index 134854a..0000000
--- a/opengl/tests/Android.mk
+++ /dev/null
@@ -1,28 +0,0 @@
-dirs := \
- linetex \
- swapinterval \
- textures \
- tritex \
-
-ifneq (,$(TARGET_BUILD_JAVA_SUPPORT_LEVEL))
-dirs += \
- gl2_cameraeye \
- gl2_java \
- gl2_jni \
- gldual \
- gl_jni \
- gl_perfapp \
- lighting1709 \
- testLatency \
- testPauseResume \
- testViewport \
-
-endif # JAVA_SUPPORT
-
-ifeq (platform,$(TARGET_BUILD_JAVA_SUPPORT_LEVEL))
-dirs += \
- testFramerate
-
-endif # JAVA_SUPPORT platform
-
-include $(call all-named-subdir-makefiles, $(dirs))
diff --git a/opengl/tests/gl2_cameraeye/Android.bp b/opengl/tests/gl2_cameraeye/Android.bp
new file mode 100644
index 0000000..00e00df
--- /dev/null
+++ b/opengl/tests/gl2_cameraeye/Android.bp
@@ -0,0 +1,6 @@
+android_app {
+ name: "GL2CameraEye",
+ // Only compile source java files in this apk.
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+}
diff --git a/opengl/tests/gl2_cameraeye/Android.mk b/opengl/tests/gl2_cameraeye/Android.mk
deleted file mode 100644
index 4a43a9e..0000000
--- a/opengl/tests/gl2_cameraeye/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-# Only compile source java files in this apk.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := GL2CameraEye
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_PACKAGE)
-
-# Use the following include to make our test apk.
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/opengl/tests/gl2_java/Android.bp b/opengl/tests/gl2_java/Android.bp
new file mode 100644
index 0000000..a8e5d7d
--- /dev/null
+++ b/opengl/tests/gl2_java/Android.bp
@@ -0,0 +1,8 @@
+//########################################################################
+// OpenGL ES 2.0 Java sample
+//########################################################################
+android_app {
+ name: "GL2Java",
+ srcs: ["**/*.java"],
+ sdk_version: "current",
+}
diff --git a/opengl/tests/gl2_java/Android.mk b/opengl/tests/gl2_java/Android.mk
deleted file mode 100644
index 71aa5a0..0000000
--- a/opengl/tests/gl2_java/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-#########################################################################
-# OpenGL ES 2.0 Java sample
-#########################################################################
-
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := GL2Java
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_PACKAGE)
diff --git a/opengl/tests/gl2_jni/Android.bp b/opengl/tests/gl2_jni/Android.bp
new file mode 100644
index 0000000..65f89b1
--- /dev/null
+++ b/opengl/tests/gl2_jni/Android.bp
@@ -0,0 +1,27 @@
+//########################################################################
+// OpenGL ES JNI sample
+// This makefile builds both an activity and a shared library.
+//########################################################################
+
+android_app {
+ name: "GL2JNI",
+ srcs: ["**/*.java"],
+ sdk_version: "current",
+ jni_libs: ["libgl2jni"],
+}
+
+// Build JNI Shared Library
+cc_library_shared {
+ name: "libgl2jni",
+ cflags: [
+ "-Werror",
+ "-Wno-error=unused-parameter",
+ ],
+ srcs: ["jni/gl_code.cpp"],
+ shared_libs: [
+ "liblog",
+ "libEGL",
+ "libGLESv2",
+ ],
+ sdk_version: "current",
+}
diff --git a/opengl/tests/gl2_jni/Android.mk b/opengl/tests/gl2_jni/Android.mk
deleted file mode 100644
index b0081c2..0000000
--- a/opengl/tests/gl2_jni/Android.mk
+++ /dev/null
@@ -1,49 +0,0 @@
-#########################################################################
-# OpenGL ES JNI sample
-# This makefile builds both an activity and a shared library.
-#########################################################################
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := GL2JNI
-LOCAL_SDK_VERSION := current
-
-LOCAL_JNI_SHARED_LIBRARIES := libgl2jni
-
-include $(BUILD_PACKAGE)
-
-#########################################################################
-# Build JNI Shared Library
-#########################################################################
-
-LOCAL_PATH:= $(LOCAL_PATH)/jni
-
-include $(CLEAR_VARS)
-
-# Optional tag would mean it doesn't get installed by default
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -Werror -Wno-error=unused-parameter
-
-LOCAL_SRC_FILES:= \
- gl_code.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- liblog \
- libEGL \
- libGLESv2
-
-LOCAL_MODULE := libgl2jni
-
-LOCAL_SDK_VERSION := current
-
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/tests/gl_jni/Android.bp b/opengl/tests/gl_jni/Android.bp
new file mode 100644
index 0000000..5bec336
--- /dev/null
+++ b/opengl/tests/gl_jni/Android.bp
@@ -0,0 +1,34 @@
+//########################################################################
+// OpenGL ES JNI sample
+// This makefile builds both an activity and a shared library.
+//########################################################################
+// Build activity
+
+android_app {
+ name: "GLJNI",
+ srcs: ["**/*.java"],
+ sdk_version: "current",
+ jni_libs: ["libgljni"],
+}
+
+// Build JNI Shared Library
+
+cc_library_shared {
+ name: "libgljni",
+ cflags: [
+ "-Werror",
+ "-Wno-error=unused-parameter",
+ ],
+ srcs: ["jni/gl_code.cpp"],
+ shared_libs: [
+ "liblog",
+ "libEGL",
+ "libGLESv1_CM",
+ ],
+ sdk_version: "current",
+ arch: {
+ arm: {
+ instruction_set: "arm",
+ },
+ },
+}
diff --git a/opengl/tests/gl_jni/Android.mk b/opengl/tests/gl_jni/Android.mk
deleted file mode 100644
index d64dfcf..0000000
--- a/opengl/tests/gl_jni/Android.mk
+++ /dev/null
@@ -1,52 +0,0 @@
-#########################################################################
-# OpenGL ES JNI sample
-# This makefile builds both an activity and a shared library.
-#########################################################################
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := GLJNI
-LOCAL_SDK_VERSION := current
-
-LOCAL_JNI_SHARED_LIBRARIES := libgljni
-
-include $(BUILD_PACKAGE)
-
-#########################################################################
-# Build JNI Shared Library
-#########################################################################
-
-LOCAL_PATH:= $(LOCAL_PATH)/jni
-
-include $(CLEAR_VARS)
-
-# Optional tag would mean it doesn't get installed by default
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -Werror -Wno-error=unused-parameter
-
-LOCAL_SRC_FILES:= \
- gl_code.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- liblog \
- libEGL \
- libGLESv1_CM
-
-LOCAL_MODULE := libgljni
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_ARM_MODE := arm
-
-
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/tests/gl_perfapp/Android.bp b/opengl/tests/gl_perfapp/Android.bp
new file mode 100644
index 0000000..cf899ac
--- /dev/null
+++ b/opengl/tests/gl_perfapp/Android.bp
@@ -0,0 +1,27 @@
+//########################################################################
+// OpenGL ES Perf App
+// This makefile builds both an activity and a shared library.
+//########################################################################
+android_app {
+ name: "GLPerf",
+ srcs: ["**/*.java"],
+ jni_libs: ["libglperf"],
+ // Run on Eclair
+ sdk_version: "7",
+}
+
+// Build JNI Shared Library
+cc_library_shared {
+ name: "libglperf",
+ cflags: [
+ "-Werror",
+ "-Wno-error=unused-parameter",
+ ],
+ srcs: ["jni/gl_code.cpp"],
+ shared_libs: [
+ "liblog",
+ "libEGL",
+ "libGLESv2",
+ ],
+ sdk_version: "current",
+}
diff --git a/opengl/tests/gl_perfapp/Android.mk b/opengl/tests/gl_perfapp/Android.mk
deleted file mode 100644
index 3f411ea..0000000
--- a/opengl/tests/gl_perfapp/Android.mk
+++ /dev/null
@@ -1,52 +0,0 @@
-#########################################################################
-# OpenGL ES Perf App
-# This makefile builds both an activity and a shared library.
-#########################################################################
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := GLPerf
-
-LOCAL_JNI_SHARED_LIBRARIES := libglperf
-
-# Run on Eclair
-LOCAL_SDK_VERSION := 7
-
-include $(BUILD_PACKAGE)
-
-#########################################################################
-# Build JNI Shared Library
-#########################################################################
-
-LOCAL_PATH:= $(LOCAL_PATH)/jni
-
-include $(CLEAR_VARS)
-
-# Optional tag would mean it doesn't get installed by default
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -Werror -Wno-error=unused-parameter
-
-LOCAL_SRC_FILES:= \
- gl_code.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- liblog \
- libEGL \
- libGLESv2
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_MODULE := libglperf
-
-
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/tests/gldual/Android.bp b/opengl/tests/gldual/Android.bp
new file mode 100644
index 0000000..2432566
--- /dev/null
+++ b/opengl/tests/gldual/Android.bp
@@ -0,0 +1,30 @@
+//########################################################################
+// OpenGL ES JNI sample
+// This makefile builds both an activity and a shared library.
+//########################################################################
+// Build activity
+
+android_app {
+ name: "GLDual",
+ srcs: ["**/*.java"],
+ sdk_version: "current",
+ jni_libs: ["libgldualjni"],
+}
+
+//########################################################################
+// Build JNI Shared Library
+//########################################################################
+cc_library_shared {
+ name: "libgldualjni",
+ cflags: [
+ "-Werror",
+ "-Wno-error=unused-parameter",
+ ],
+ srcs: ["jni/gl_code.cpp"],
+ shared_libs: [
+ "liblog",
+ "libEGL",
+ "libGLESv2",
+ ],
+ sdk_version: "current",
+}
diff --git a/opengl/tests/gldual/Android.mk b/opengl/tests/gldual/Android.mk
deleted file mode 100644
index 5bdc0a8..0000000
--- a/opengl/tests/gldual/Android.mk
+++ /dev/null
@@ -1,49 +0,0 @@
-#########################################################################
-# OpenGL ES JNI sample
-# This makefile builds both an activity and a shared library.
-#########################################################################
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := GLDual
-LOCAL_SDK_VERSION := current
-
-LOCAL_JNI_SHARED_LIBRARIES := libgldualjni
-
-include $(BUILD_PACKAGE)
-
-#########################################################################
-# Build JNI Shared Library
-#########################################################################
-
-LOCAL_PATH:= $(LOCAL_PATH)/jni
-
-include $(CLEAR_VARS)
-
-# Optional tag would mean it doesn't get installed by default
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -Werror -Wno-error=unused-parameter
-
-LOCAL_SRC_FILES:= \
- gl_code.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- liblog \
- libEGL \
- libGLESv2
-
-LOCAL_MODULE := libgldualjni
-
-LOCAL_SDK_VERSION := current
-
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/tests/lighting1709/Android.bp b/opengl/tests/lighting1709/Android.bp
new file mode 100644
index 0000000..e734dd1
--- /dev/null
+++ b/opengl/tests/lighting1709/Android.bp
@@ -0,0 +1,6 @@
+android_test {
+ name: "LightingTest",
+ srcs: ["**/*.java"],
+ sdk_version: "current",
+ certificate: "platform",
+}
diff --git a/opengl/tests/lighting1709/Android.mk b/opengl/tests/lighting1709/Android.mk
deleted file mode 100644
index 0047231..0000000
--- a/opengl/tests/lighting1709/Android.mk
+++ /dev/null
@@ -1,12 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := LightingTest
-LOCAL_SDK_VERSION := current
-LOCAL_CERTIFICATE := platform
-
-include $(BUILD_PACKAGE)
diff --git a/opengl/tests/linetex/Android.bp b/opengl/tests/linetex/Android.bp
new file mode 100644
index 0000000..dbc2cdb
--- /dev/null
+++ b/opengl/tests/linetex/Android.bp
@@ -0,0 +1,17 @@
+cc_binary {
+ name: "test-opengl-linetex",
+ srcs: ["linetex.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "libcutils",
+ "libEGL",
+ "libGLESv1_CM",
+ "libui",
+ "libgui",
+ "libutils",
+ ],
+ static_libs: ["libglTest"],
+}
diff --git a/opengl/tests/linetex/Android.mk b/opengl/tests/linetex/Android.mk
deleted file mode 100644
index 3df0a0f..0000000
--- a/opengl/tests/linetex/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- linetex.cpp
-
-LOCAL_CFLAGS := -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libEGL \
- libGLESv1_CM \
- libui \
- libgui \
- libutils
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-linetex
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/swapinterval/Android.bp b/opengl/tests/swapinterval/Android.bp
new file mode 100644
index 0000000..eed4dff
--- /dev/null
+++ b/opengl/tests/swapinterval/Android.bp
@@ -0,0 +1,17 @@
+cc_binary {
+ name: "test-opengl-swapinterval",
+ srcs: ["swapinterval.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "libcutils",
+ "libutils",
+ "libEGL",
+ "libGLESv1_CM",
+ "libui",
+ "libgui",
+ ],
+ static_libs: ["libglTest"],
+}
diff --git a/opengl/tests/swapinterval/Android.mk b/opengl/tests/swapinterval/Android.mk
deleted file mode 100644
index 2a2c12f..0000000
--- a/opengl/tests/swapinterval/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- swapinterval.cpp
-
-LOCAL_CFLAGS := -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libutils \
- libEGL \
- libGLESv1_CM \
- libui \
- libgui
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-swapinterval
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/testFramerate/Android.bp b/opengl/tests/testFramerate/Android.bp
new file mode 100644
index 0000000..5aa83b0
--- /dev/null
+++ b/opengl/tests/testFramerate/Android.bp
@@ -0,0 +1,9 @@
+//########################################################################
+// Test framerate and look for hiccups
+//########################################################################
+
+android_app {
+ name: "TestFramerate",
+ srcs: ["**/*.java"],
+ sdk_version: "system_current",
+}
diff --git a/opengl/tests/testFramerate/Android.mk b/opengl/tests/testFramerate/Android.mk
deleted file mode 100644
index ca6654a..0000000
--- a/opengl/tests/testFramerate/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-#########################################################################
-# Test framerate and look for hiccups
-#########################################################################
-
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := TestFramerate
-LOCAL_SDK_VERSION := system_current
-
-include $(BUILD_PACKAGE)
diff --git a/opengl/tests/testLatency/Android.bp b/opengl/tests/testLatency/Android.bp
new file mode 100644
index 0000000..c516dc3
--- /dev/null
+++ b/opengl/tests/testLatency/Android.bp
@@ -0,0 +1,8 @@
+//########################################################################
+// Test end-to-end latency.
+//########################################################################
+android_app {
+ name: "TestLatency",
+ sdk_version: "8",
+ srcs: ["**/*.java"],
+}
diff --git a/opengl/tests/testLatency/Android.mk b/opengl/tests/testLatency/Android.mk
deleted file mode 100644
index 96417c7..0000000
--- a/opengl/tests/testLatency/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-#########################################################################
-# Test end-to-end latency.
-#########################################################################
-
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SDK_VERSION := 8
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := TestLatency
-
-include $(BUILD_PACKAGE)
diff --git a/opengl/tests/testPauseResume/Android.bp b/opengl/tests/testPauseResume/Android.bp
new file mode 100644
index 0000000..810e895
--- /dev/null
+++ b/opengl/tests/testPauseResume/Android.bp
@@ -0,0 +1,6 @@
+// OpenGL ES JNI sample
+android_app {
+ name: "TestEGL",
+ srcs: ["**/*.java"],
+ sdk_version: "current",
+}
diff --git a/opengl/tests/testPauseResume/Android.mk b/opengl/tests/testPauseResume/Android.mk
deleted file mode 100644
index dda5424..0000000
--- a/opengl/tests/testPauseResume/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-#########################################################################
-# OpenGL ES JNI sample
-# This makefile builds both an activity and a shared library.
-#########################################################################
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := TestEGL
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_PACKAGE)
diff --git a/opengl/tests/testViewport/Android.bp b/opengl/tests/testViewport/Android.bp
new file mode 100644
index 0000000..629b573
--- /dev/null
+++ b/opengl/tests/testViewport/Android.bp
@@ -0,0 +1,9 @@
+//########################################################################
+// OpenGL ES JNI sample
+// This makefile builds both an activity and a shared library.
+//########################################################################
+android_app {
+ name: "TestViewport",
+ srcs: ["**/*.java"],
+ sdk_version: "8",
+}
diff --git a/opengl/tests/testViewport/Android.mk b/opengl/tests/testViewport/Android.mk
deleted file mode 100644
index 9980e7d..0000000
--- a/opengl/tests/testViewport/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-#########################################################################
-# OpenGL ES JNI sample
-# This makefile builds both an activity and a shared library.
-#########################################################################
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := TestViewport
-
-# Set a specific SDK version so we can run on Froyo.
-
-LOCAL_SDK_VERSION := 8
-
-include $(BUILD_PACKAGE)
diff --git a/opengl/tests/textures/Android.bp b/opengl/tests/textures/Android.bp
new file mode 100644
index 0000000..84adda2
--- /dev/null
+++ b/opengl/tests/textures/Android.bp
@@ -0,0 +1,18 @@
+cc_binary {
+ name: "test-opengl-textures",
+ srcs: ["textures.cpp"],
+ shared_libs: [
+ "libcutils",
+ "libEGL",
+ "libGLESv1_CM",
+ "libui",
+ "libgui",
+ "libutils",
+ ],
+ static_libs: ["libglTest"],
+ cflags: [
+ "-DGL_GLEXT_PROTOTYPES",
+ "-Wall",
+ "-Werror",
+ ],
+}
diff --git a/opengl/tests/textures/Android.mk b/opengl/tests/textures/Android.mk
deleted file mode 100644
index 629a2d2..0000000
--- a/opengl/tests/textures/Android.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- textures.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libEGL \
- libGLESv1_CM \
- libui \
- libgui \
- libutils
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-textures
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
-LOCAL_CFLAGS += -Wall -Werror
-
-include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/tritex/Android.bp b/opengl/tests/tritex/Android.bp
new file mode 100644
index 0000000..390397b
--- /dev/null
+++ b/opengl/tests/tritex/Android.bp
@@ -0,0 +1,17 @@
+cc_binary {
+ name: "test-opengl-tritex",
+ srcs: ["tritex.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "libcutils",
+ "libEGL",
+ "libGLESv1_CM",
+ "libui",
+ "libgui",
+ "libutils",
+ ],
+ static_libs: ["libglTest"],
+}
diff --git a/opengl/tests/tritex/Android.mk b/opengl/tests/tritex/Android.mk
deleted file mode 100644
index 7055afa..0000000
--- a/opengl/tests/tritex/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- tritex.cpp
-
-LOCAL_CFLAGS := -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- libEGL \
- libGLESv1_CM \
- libui \
- libgui \
- libutils
-
-LOCAL_STATIC_LIBRARIES += libglTest
-
-LOCAL_C_INCLUDES += $(call include-path-for, opengl-tests-includes)
-
-LOCAL_MODULE:= test-opengl-tritex
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h
index 8133623..1f7dd41 100644
--- a/services/inputflinger/InputClassifier.h
+++ b/services/inputflinger/InputClassifier.h
@@ -93,7 +93,7 @@
* NotifyMotionArgs::videoFrames field to drive the classification decisions.
* The HAL is called from a separate thread.
*/
-class MotionClassifier : public MotionClassifierInterface {
+class MotionClassifier final : public MotionClassifierInterface {
public:
MotionClassifier(sp<android::hardware::input::classifier::V1_0::IInputClassifier> service);
~MotionClassifier();
@@ -201,4 +201,4 @@
};
} // namespace android
-#endif
\ No newline at end of file
+#endif
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 57181c2..9702fb2 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -521,7 +521,7 @@
}
sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId,
- int32_t x, int32_t y) {
+ int32_t x, int32_t y, bool addOutsideTargets, bool addPortalWindows) {
// Traverse windows from front to back to find touched window.
const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
size_t numWindows = windowHandles.size();
@@ -536,10 +536,25 @@
bool isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE
| InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;
if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
+ int32_t portalToDisplayId = windowInfo->portalToDisplayId;
+ if (portalToDisplayId != ADISPLAY_ID_NONE
+ && portalToDisplayId != displayId) {
+ if (addPortalWindows) {
+ // For the monitoring channels of the display.
+ mTempTouchState.addPortalWindow(windowHandle);
+ }
+ return findTouchedWindowAtLocked(
+ portalToDisplayId, x, y, addOutsideTargets, addPortalWindows);
+ }
// Found window.
return windowHandle;
}
}
+
+ if (addOutsideTargets && (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) {
+ mTempTouchState.addOrUpdateWindow(
+ windowHandle, InputTarget::FLAG_DISPATCH_AS_OUTSIDE, BitSet32(0));
+ }
}
}
}
@@ -926,6 +941,22 @@
// Add monitor channels from event's or focused display.
addMonitoringTargetsLocked(inputTargets, getTargetDisplayId(entry));
+ if (isPointerEvent) {
+ ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(entry->displayId);
+ if (stateIndex >= 0) {
+ const TouchState& state = mTouchStatesByDisplay.valueAt(stateIndex);
+ if (!state.portalWindows.isEmpty()) {
+ // The event has gone through these portal windows, so we add monitoring targets of
+ // the corresponding displays as well.
+ for (size_t i = 0; i < state.portalWindows.size(); i++) {
+ const InputWindowInfo* windowInfo = state.portalWindows.itemAt(i)->getInfo();
+ addMonitoringTargetsLocked(inputTargets, windowInfo->portalToDisplayId,
+ -windowInfo->frameLeft, -windowInfo->frameTop);
+ }
+ }
+ }
+ }
+
// Dispatch the motion.
if (conflictingPointerActions) {
CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
@@ -1293,37 +1324,8 @@
getAxisValue(AMOTION_EVENT_AXIS_X));
int32_t y = int32_t(entry->pointerCoords[pointerIndex].
getAxisValue(AMOTION_EVENT_AXIS_Y));
- sp<InputWindowHandle> newTouchedWindowHandle;
- bool isTouchModal = false;
-
- // Traverse windows from front to back to find touched window and outside targets.
- const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
- size_t numWindows = windowHandles.size();
- for (size_t i = 0; i < numWindows; i++) {
- sp<InputWindowHandle> windowHandle = windowHandles.itemAt(i);
- const InputWindowInfo* windowInfo = windowHandle->getInfo();
- if (windowInfo->displayId != displayId) {
- continue; // wrong display
- }
-
- int32_t flags = windowInfo->layoutParamsFlags;
- if (windowInfo->visible) {
- if (! (flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) {
- isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE
- | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;
- if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
- newTouchedWindowHandle = windowHandle;
- break; // found touched window, exit window loop
- }
- }
-
- if (maskedAction == AMOTION_EVENT_ACTION_DOWN
- && (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) {
- mTempTouchState.addOrUpdateWindow(
- windowHandle, InputTarget::FLAG_DISPATCH_AS_OUTSIDE, BitSet32(0));
- }
- }
- }
+ sp<InputWindowHandle> newTouchedWindowHandle = findTouchedWindowAtLocked(
+ displayId, x, y, maskedAction == AMOTION_EVENT_ACTION_DOWN, true);
// Figure out whether splitting will be allowed for this window.
if (newTouchedWindowHandle != nullptr
@@ -1685,7 +1687,7 @@
}
void InputDispatcher::addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets,
- int32_t displayId) {
+ int32_t displayId, float xOffset, float yOffset) {
std::unordered_map<int32_t, Vector<sp<InputChannel>>>::const_iterator it =
mMonitoringChannelsByDisplay.find(displayId);
@@ -1698,8 +1700,8 @@
InputTarget& target = inputTargets.editTop();
target.inputChannel = monitoringChannels[i];
target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
- target.xOffset = 0;
- target.yOffset = 0;
+ target.xOffset = xOffset;
+ target.yOffset = yOffset;
target.pointerIds.clear();
target.globalScaleFactor = 1.0f;
}
@@ -3102,7 +3104,8 @@
Vector<sp<InputWindowHandle>> newHandles;
for (size_t i = 0; i < numWindows; i++) {
const sp<InputWindowHandle>& handle = inputWindowHandles.itemAt(i);
- if (!handle->updateInfo() || getInputChannelLocked(handle->getToken()) == nullptr) {
+ if (!handle->updateInfo() || (getInputChannelLocked(handle->getToken()) == nullptr
+ && handle->getInfo()->portalToDisplayId == ADISPLAY_ID_NONE)) {
ALOGE("Window handle %s has no registered input channel",
handle->getName().c_str());
continue;
@@ -3537,6 +3540,14 @@
} else {
dump += INDENT3 "Windows: <none>\n";
}
+ if (!state.portalWindows.isEmpty()) {
+ dump += INDENT3 "Portal windows:\n";
+ for (size_t i = 0; i < state.portalWindows.size(); i++) {
+ const sp<InputWindowHandle> portalWindowHandle = state.portalWindows.itemAt(i);
+ dump += StringPrintf(INDENT4 "%zu: name='%s'\n",
+ i, portalWindowHandle->getName().c_str());
+ }
+ }
}
} else {
dump += INDENT "TouchStates: <no displays touched>\n";
@@ -3553,11 +3564,12 @@
const InputWindowInfo* windowInfo = windowHandle->getInfo();
dump += StringPrintf(INDENT3 "%zu: name='%s', displayId=%d, "
- "paused=%s, hasFocus=%s, hasWallpaper=%s, "
+ "portalToDisplayId=%d, paused=%s, hasFocus=%s, hasWallpaper=%s, "
"visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
"frame=[%d,%d][%d,%d], globalScale=%f, windowScale=(%f,%f), "
"touchableRegion=",
i, windowInfo->name.c_str(), windowInfo->displayId,
+ windowInfo->portalToDisplayId,
toString(windowInfo->paused),
toString(windowInfo->hasFocus),
toString(windowInfo->hasWallpaper),
@@ -4906,6 +4918,7 @@
source = 0;
displayId = ADISPLAY_ID_NONE;
windows.clear();
+ portalWindows.clear();
}
void InputDispatcher::TouchState::copyFrom(const TouchState& other) {
@@ -4915,6 +4928,7 @@
source = other.source;
displayId = other.displayId;
windows = other.windows;
+ portalWindows = other.portalWindows;
}
void InputDispatcher::TouchState::addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle,
@@ -4943,6 +4957,17 @@
touchedWindow.pointerIds = pointerIds;
}
+void InputDispatcher::TouchState::addPortalWindow(const sp<InputWindowHandle>& windowHandle) {
+ size_t numWindows = portalWindows.size();
+ for (size_t i = 0; i < numWindows; i++) {
+ sp<InputWindowHandle> portalWindowHandle = portalWindows.itemAt(i);
+ if (portalWindowHandle == windowHandle) {
+ return;
+ }
+ }
+ portalWindows.push_back(windowHandle);
+}
+
void InputDispatcher::TouchState::removeWindow(const sp<InputWindowHandle>& windowHandle) {
for (size_t i = 0; i < windows.size(); i++) {
if (windows.itemAt(i).windowHandle == windowHandle) {
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 327dbbd..2d8df5c 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -921,7 +921,8 @@
// to transfer focus to a new application.
EventEntry* mNextUnblockedEvent;
- sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y);
+ sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y,
+ bool addOutsideTargets = false, bool addPortalWindows = false);
// All registered connections mapped by channel file descriptor.
KeyedVector<int, sp<Connection> > mConnectionsByFd;
@@ -1016,12 +1017,18 @@
int32_t displayId; // id to the display that currently has a touch, others are rejected
Vector<TouchedWindow> windows;
+ // This collects the portal windows that the touch has gone through. Each portal window
+ // targets a display (embedded display for most cases). With this info, we can add the
+ // monitoring channels of the displays touched.
+ Vector<sp<InputWindowHandle>> portalWindows;
+
TouchState();
~TouchState();
void reset();
void copyFrom(const TouchState& other);
void addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle,
int32_t targetFlags, BitSet32 pointerIds);
+ void addPortalWindow(const sp<InputWindowHandle>& windowHandle);
void removeWindow(const sp<InputWindowHandle>& windowHandle);
void removeWindowByToken(const sp<IBinder>& token);
void filterNonAsIsTouchWindows();
@@ -1096,7 +1103,8 @@
void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
int32_t targetFlags, BitSet32 pointerIds, Vector<InputTarget>& inputTargets);
- void addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets, int32_t displayId);
+ void addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets, int32_t displayId,
+ float xOffset = 0, float yOffset = 0);
void pokeUserActivityLocked(const EventEntry* eventEntry);
bool checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 64070e3..f84aa34 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -805,6 +805,30 @@
return false;
}
+bool InputReader::canDispatchToDisplay(int32_t deviceId, int32_t displayId) {
+ AutoMutex _l(mLock);
+
+ ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
+ if (deviceIndex < 0) {
+ ALOGW("Ignoring invalid device id %" PRId32 ".", deviceId);
+ return false;
+ }
+
+ InputDevice* device = mDevices.valueAt(deviceIndex);
+ std::optional<int32_t> associatedDisplayId = device->getAssociatedDisplay();
+ // No associated display. By default, can dispatch to all displays.
+ if (!associatedDisplayId) {
+ return true;
+ }
+
+ if (*associatedDisplayId == ADISPLAY_ID_NONE) {
+ ALOGW("Device has associated, but no associated display id.");
+ return true;
+ }
+
+ return *associatedDisplayId == displayId;
+}
+
void InputReader::dump(std::string& dump) {
AutoMutex _l(mLock);
@@ -1275,6 +1299,18 @@
mContext->getListener()->notifyDeviceReset(&args);
}
+std::optional<int32_t> InputDevice::getAssociatedDisplay() {
+ size_t numMappers = mMappers.size();
+ for (size_t i = 0; i < numMappers; i++) {
+ InputMapper* mapper = mMappers[i];
+ std::optional<int32_t> associatedDisplayId = mapper->getAssociatedDisplay();
+ if (associatedDisplayId) {
+ return associatedDisplayId;
+ }
+ }
+
+ return std::nullopt;
+}
// --- CursorButtonAccumulator ---
@@ -2647,7 +2683,7 @@
}
// Update the PointerController if viewports changed.
- if (mParameters.hasAssociatedDisplay) {
+ if (mParameters.mode == Parameters::MODE_POINTER) {
getPolicy()->obtainPointerController(getDeviceId());
}
bumpGeneration();
@@ -2919,6 +2955,19 @@
}
}
+std::optional<int32_t> CursorInputMapper::getAssociatedDisplay() {
+ if (mParameters.hasAssociatedDisplay) {
+ if (mParameters.mode == Parameters::MODE_POINTER) {
+ return std::make_optional(mPointerController->getDisplayId());
+ } else {
+ // If the device is orientationAware and not a mouse,
+ // it expects to dispatch events to any display
+ return std::make_optional(ADISPLAY_ID_NONE);
+ }
+ }
+ return std::nullopt;
+}
+
// --- RotaryEncoderInputMapper ---
RotaryEncoderInputMapper::RotaryEncoderInputMapper(InputDevice* device) :
@@ -6511,9 +6560,7 @@
ALOG_ASSERT(false);
}
}
- const int32_t displayId = mPointerController != nullptr ?
- mPointerController->getDisplayId() : mViewport.displayId;
-
+ const int32_t displayId = getAssociatedDisplay().value_or(ADISPLAY_ID_NONE);
const int32_t deviceId = getDeviceId();
std::vector<TouchVideoFrame> frames = mDevice->getEventHub()->getVideoFrames(deviceId);
NotifyMotionArgs args(mContext->getNextSequenceNum(), when, deviceId,
@@ -6830,6 +6877,16 @@
return true;
}
+std::optional<int32_t> TouchInputMapper::getAssociatedDisplay() {
+ if (mParameters.hasAssociatedDisplay) {
+ if (mDeviceMode == DEVICE_MODE_POINTER) {
+ return std::make_optional(mPointerController->getDisplayId());
+ } else {
+ return std::make_optional(mViewport.displayId);
+ }
+ }
+ return std::nullopt;
+}
// --- SingleTouchInputMapper ---
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index aaffce2..fed55ac 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -146,6 +146,7 @@
ssize_t repeat, int32_t token);
virtual void cancelVibrate(int32_t deviceId, int32_t token);
+ virtual bool canDispatchToDisplay(int32_t deviceId, int32_t displayId);
protected:
// These members are protected so they can be instrumented by test cases.
virtual InputDevice* createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
@@ -320,6 +321,7 @@
return value;
}
+ std::optional<int32_t> getAssociatedDisplay();
private:
InputReaderContext* mContext;
int32_t mId;
@@ -778,7 +780,9 @@
virtual void updateExternalStylusState(const StylusState& state);
virtual void fadePointer();
-
+ virtual std::optional<int32_t> getAssociatedDisplay() {
+ return std::nullopt;
+ }
protected:
InputDevice* mDevice;
InputReaderContext* mContext;
@@ -932,6 +936,7 @@
virtual void fadePointer();
+ virtual std::optional<int32_t> getAssociatedDisplay();
private:
// Amount that trackball needs to move in order to generate a key event.
static const int32_t TRACKBALL_MOVEMENT_THRESHOLD = 6;
@@ -1025,7 +1030,7 @@
virtual void cancelTouch(nsecs_t when);
virtual void timeoutExpired(nsecs_t when);
virtual void updateExternalStylusState(const StylusState& state);
-
+ virtual std::optional<int32_t> getAssociatedDisplay();
protected:
CursorButtonAccumulator mCursorButtonAccumulator;
CursorScrollAccumulator mCursorScrollAccumulator;
diff --git a/services/inputflinger/OWNERS b/services/inputflinger/OWNERS
new file mode 100644
index 0000000..0313a40
--- /dev/null
+++ b/services/inputflinger/OWNERS
@@ -0,0 +1,2 @@
+michaelwr@google.com
+svv@google.com
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index fe1c50b..c411ec0 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -100,6 +100,9 @@
virtual void vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize,
ssize_t repeat, int32_t token) = 0;
virtual void cancelVibrate(int32_t deviceId, int32_t token) = 0;
+
+ /* Return true if the device can send input events to the specified display. */
+ virtual bool canDispatchToDisplay(int32_t deviceId, int32_t displayId) = 0;
};
/* Reads raw events from the event hub and processes them, endlessly. */
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 0b86555..84c5ad6 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -841,6 +841,7 @@
bool mResetWasCalled;
bool mProcessWasCalled;
+ std::optional<DisplayViewport> mViewport;
public:
FakeInputMapper(InputDevice* device, uint32_t sources) :
InputMapper(device),
@@ -909,8 +910,14 @@
}
}
- virtual void configure(nsecs_t, const InputReaderConfiguration*, uint32_t) {
+ virtual void configure(nsecs_t, const InputReaderConfiguration* config, uint32_t changes) {
mConfigureWasCalled = true;
+
+ // Find the associated viewport if exist.
+ const std::optional<uint8_t> displayPort = mDevice->getAssociatedDisplayPort();
+ if (displayPort && (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
+ mViewport = config->getDisplayViewportByPort(*displayPort);
+ }
}
virtual void reset(nsecs_t) {
@@ -957,6 +964,13 @@
virtual void fadePointer() {
}
+
+ virtual std::optional<int32_t> getAssociatedDisplay() {
+ if (mViewport) {
+ return std::make_optional(mViewport->displayId);
+ }
+ return std::nullopt;
+ }
};
@@ -984,9 +998,10 @@
}
InputDevice* newDevice(int32_t deviceId, int32_t controllerNumber, const std::string& name,
- uint32_t classes) {
+ uint32_t classes, const std::string& location = "") {
InputDeviceIdentifier identifier;
identifier.name = name;
+ identifier.location = location;
int32_t generation = deviceId + 1;
return new InputDevice(&mContext, deviceId, generation, controllerNumber, identifier,
classes);
@@ -1286,7 +1301,7 @@
TEST_F(InputReaderTest, WhenEnabledChanges_SendsDeviceResetNotification) {
constexpr int32_t deviceId = 1;
constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
- InputDevice* device = mReader->newDevice(deviceId, 0, "fake", deviceClass);
+ InputDevice* device = mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass);
// Must add at least one mapper or the device will be ignored!
FakeInputMapper* mapper = new FakeInputMapper(device, AINPUT_SOURCE_KEYBOARD);
device->addMapper(mapper);
@@ -1470,7 +1485,7 @@
TEST_F(InputReaderTest, DeviceReset_IncrementsSequenceNumber) {
constexpr int32_t deviceId = 1;
constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
- InputDevice* device = mReader->newDevice(deviceId, 0, "fake", deviceClass);
+ InputDevice* device = mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass);
// Must add at least one mapper or the device will be ignored!
FakeInputMapper* mapper = new FakeInputMapper(device, AINPUT_SOURCE_KEYBOARD);
device->addMapper(mapper);
@@ -1500,6 +1515,36 @@
prevSequenceNum = resetArgs.sequenceNum;
}
+TEST_F(InputReaderTest, Device_CanDispatchToDisplay) {
+ constexpr int32_t deviceId = 1;
+ constexpr uint32_t deviceClass = INPUT_DEVICE_CLASS_KEYBOARD;
+ const char* DEVICE_LOCATION = "USB1";
+ InputDevice* device = mReader->newDevice(deviceId, 0 /*controllerNumber*/, "fake", deviceClass,
+ DEVICE_LOCATION);
+ FakeInputMapper* mapper = new FakeInputMapper(device, AINPUT_SOURCE_TOUCHSCREEN);
+ device->addMapper(mapper);
+ mReader->setNextDevice(device);
+ addDevice(deviceId, "fake", deviceClass, nullptr);
+
+ const uint8_t hdmi1 = 1;
+
+ // Associated touch screen with second display.
+ mFakePolicy->addInputPortAssociation(DEVICE_LOCATION, hdmi1);
+
+ // Add default and second display.
+ mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+ DISPLAY_ORIENTATION_0, "local:0", NO_PORT, ViewportType::VIEWPORT_INTERNAL);
+ mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+ DISPLAY_ORIENTATION_0, "local:1", hdmi1, ViewportType::VIEWPORT_EXTERNAL);
+ mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+ mReader->loopOnce();
+
+ // Check device.
+ ASSERT_EQ(deviceId, device->getId());
+ ASSERT_FALSE(mReader->canDispatchToDisplay(deviceId, DISPLAY_ID));
+ ASSERT_TRUE(mReader->canDispatchToDisplay(deviceId, SECONDARY_DISPLAY_ID));
+}
+
// --- InputDeviceTest ---
diff --git a/services/nativeperms/Android.bp b/services/nativeperms/Android.bp
new file mode 100644
index 0000000..cbc7d66
--- /dev/null
+++ b/services/nativeperms/Android.bp
@@ -0,0 +1,34 @@
+// Copyright 2016 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.
+//
+
+cc_binary {
+ name: "nativeperms",
+ srcs: [
+ "nativeperms.cpp",
+ "android/os/IPermissionController.aidl",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "libbinder",
+ "libbrillo",
+ "libbrillo-binder",
+ "libchrome",
+ "libutils",
+ ],
+ init_rc: ["nativeperms.rc"],
+}
diff --git a/services/nativeperms/Android.mk b/services/nativeperms/Android.mk
deleted file mode 100644
index 34ccd0b..0000000
--- a/services/nativeperms/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright 2016 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := nativeperms
-LOCAL_SRC_FILES := \
- nativeperms.cpp \
- android/os/IPermissionController.aidl
-LOCAL_CFLAGS := -Wall -Werror
-LOCAL_SHARED_LIBRARIES := \
- libbinder \
- libbrillo \
- libbrillo-binder \
- libchrome \
- libutils
-LOCAL_INIT_RC := nativeperms.rc
-include $(BUILD_EXECUTABLE)
diff --git a/services/sensorservice/tests/Android.bp b/services/sensorservice/tests/Android.bp
new file mode 100644
index 0000000..d33c0ca
--- /dev/null
+++ b/services/sensorservice/tests/Android.bp
@@ -0,0 +1,13 @@
+cc_binary {
+ name: "test-sensorservice",
+ srcs: ["sensorservicetest.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "libutils",
+ "libsensor",
+ "libandroid",
+ ],
+}
diff --git a/services/sensorservice/tests/Android.mk b/services/sensorservice/tests/Android.mk
deleted file mode 100644
index 8a9c36b..0000000
--- a/services/sensorservice/tests/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- sensorservicetest.cpp
-
-LOCAL_CFLAGS := -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES := \
- libutils libsensor libandroid
-
-LOCAL_MODULE:= test-sensorservice
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 2132f59..83b9585 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -20,6 +20,7 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include "BufferStateLayer.h"
+#include "ColorLayer.h"
#include "TimeStats/TimeStats.h"
@@ -302,6 +303,48 @@
return true;
}
+bool BufferStateLayer::setColor(const half3& color) {
+ // create color layer if one does not yet exist
+ if (!mCurrentState.bgColorLayer) {
+ uint32_t flags = ISurfaceComposerClient::eFXSurfaceColor;
+ const String8& name = mName + "BackgroundColorLayer";
+ mCurrentState.bgColorLayer =
+ new ColorLayer(LayerCreationArgs(mFlinger.get(), nullptr, name, 0, 0, flags));
+
+ // add to child list
+ addChild(mCurrentState.bgColorLayer);
+ mFlinger->mLayersAdded = true;
+ // set up SF to handle added color layer
+ if (isRemovedFromCurrentState()) {
+ mCurrentState.bgColorLayer->onRemovedFromCurrentState();
+ }
+ mFlinger->setTransactionFlags(eTransactionNeeded);
+ }
+
+ mCurrentState.bgColorLayer->setColor(color);
+ mCurrentState.bgColorLayer->setLayer(std::numeric_limits<int32_t>::min());
+
+ return true;
+}
+
+bool BufferStateLayer::setColorAlpha(float alpha) {
+ if (!mCurrentState.bgColorLayer) {
+ ALOGE("Attempting to set color alpha on a buffer state layer with no background color");
+ return false;
+ }
+ mCurrentState.bgColorLayer->setAlpha(alpha);
+ return true;
+}
+
+bool BufferStateLayer::setColorDataspace(ui::Dataspace dataspace) {
+ if (!mCurrentState.bgColorLayer) {
+ ALOGE("Attempting to set color dataspace on a buffer state layer with no background color");
+ return false;
+ }
+ mCurrentState.bgColorLayer->setDataspace(dataspace);
+ return true;
+}
+
Rect BufferStateLayer::getBufferSize(const State& s) const {
// for buffer state layers we use the display frame size as the buffer size.
if (getActiveWidth(s) < UINT32_MAX && getActiveHeight(s) < UINT32_MAX) {
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 3f891d3..64d6a85 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -82,6 +82,9 @@
}
bool setCrop_legacy(const Rect& /*crop*/, bool /*immediate*/) override { return false; }
bool setOverrideScalingMode(int32_t /*overrideScalingMode*/) override { return false; }
+ bool setColor(const half3& color) override;
+ bool setColorAlpha(float alpha) override;
+ bool setColorDataspace(ui::Dataspace dataspace) override;
void deferTransactionUntil_legacy(const sp<IBinder>& /*barrierHandle*/,
uint64_t /*frameNumber*/) override {}
void deferTransactionUntil_legacy(const sp<Layer>& /*barrierLayer*/,
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f181220..fde90f4 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2147,6 +2147,10 @@
InputWindowInfo Layer::fillInputInfo() {
InputWindowInfo info = mDrawingState.inputInfo;
+ if (info.displayId == ADISPLAY_ID_NONE) {
+ info.displayId = mDrawingState.layerStack;
+ }
+
ui::Transform t = getTransform();
const float xScale = t.sx();
const float yScale = t.sy();
@@ -2157,7 +2161,10 @@
}
// Transform layer size to screen space and inset it by surface insets.
- Rect layerBounds = getBufferSize(getDrawingState());
+ // If this is a portal window, set the touchableRegion to the layerBounds.
+ Rect layerBounds = info.portalToDisplayId == ADISPLAY_ID_NONE
+ ? getBufferSize(getDrawingState())
+ : info.touchableRegion.getBounds();
if (!layerBounds.isValid()) {
layerBounds = getCroppedBufferSize(getDrawingState());
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index d30961a..b3979e2 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -201,6 +201,10 @@
mat4 colorTransform;
bool hasColorTransform;
+ // pointer to background color layer that, if set, appears below the buffer state layer
+ // and the buffer state layer's children. Z order will be set to
+ // INT_MIN
+ sp<Layer> bgColorLayer;
ui::Dataspace colorDataspace; // The dataspace of the background color layer
// The deque of callback handles for this frame. The back of the deque contains the most
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 281f6b7..52abe9c 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -163,6 +163,7 @@
if (src == nullptr) {
mVSyncSource = mVSyncSourceUnique.get();
}
+ mVSyncSource->setCallback(this);
mThread = std::thread([this]() NO_THREAD_SAFETY_ANALYSIS {
std::unique_lock<std::mutex> lock(mMutex);
@@ -185,9 +186,11 @@
}
EventThread::~EventThread() {
+ mVSyncSource->setCallback(nullptr);
+
{
std::lock_guard<std::mutex> lock(mMutex);
- mKeepRunning = false;
+ mState = State::Quit;
mCondition.notify_all();
}
mThread.join();
@@ -261,24 +264,29 @@
void EventThread::onScreenReleased() {
std::lock_guard<std::mutex> lock(mMutex);
- if (!mVSyncState.synthetic) {
- mVSyncState.synthetic = true;
- mCondition.notify_all();
+ if (!mVSyncState || mVSyncState->synthetic) {
+ return;
}
+
+ mVSyncState->synthetic = true;
+ mCondition.notify_all();
}
void EventThread::onScreenAcquired() {
std::lock_guard<std::mutex> lock(mMutex);
- if (mVSyncState.synthetic) {
- mVSyncState.synthetic = false;
- mCondition.notify_all();
+ if (!mVSyncState || !mVSyncState->synthetic) {
+ return;
}
+
+ mVSyncState->synthetic = false;
+ mCondition.notify_all();
}
void EventThread::onVSyncEvent(nsecs_t timestamp) {
std::lock_guard<std::mutex> lock(mMutex);
- mPendingEvents.push_back(makeVSync(mVSyncState.displayId, timestamp, ++mVSyncState.count));
+ LOG_FATAL_IF(!mVSyncState);
+ mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count));
mCondition.notify_all();
}
@@ -293,20 +301,30 @@
void EventThread::threadMain(std::unique_lock<std::mutex>& lock) {
DisplayEventConsumers consumers;
- while (mKeepRunning) {
+ while (mState != State::Quit) {
std::optional<DisplayEventReceiver::Event> event;
// Determine next event to dispatch.
if (!mPendingEvents.empty()) {
event = mPendingEvents.front();
mPendingEvents.pop_front();
- }
- const bool vsyncPending =
- event && event->header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
+ switch (event->header.type) {
+ case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
+ if (event->hotplug.connected && !mVSyncState) {
+ mVSyncState.emplace(event->header.id);
+ } else if (!event->hotplug.connected && mVSyncState &&
+ mVSyncState->displayId == event->header.id) {
+ mVSyncState.reset();
+ }
+ break;
- if (mInterceptVSyncsCallback && vsyncPending) {
- mInterceptVSyncsCallback(event->header.timestamp);
+ case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
+ if (mInterceptVSyncsCallback) {
+ mInterceptVSyncsCallback(event->header.timestamp);
+ }
+ break;
+ }
}
bool vsyncRequested = false;
@@ -332,19 +350,22 @@
consumers.clear();
}
- // Here we figure out if we need to enable or disable vsyncs
- if (vsyncPending && !vsyncRequested) {
- // we received a VSYNC but we have no clients
- // don't report it, and disable VSYNC events
- disableVSyncLocked();
- } else if (!vsyncPending && vsyncRequested) {
- // we have at least one client, so we want vsync enabled
- // (TODO: this function is called right after we finish
- // notifying clients of a vsync, so this call will be made
- // at the vsync rate, e.g. 60fps. If we can accurately
- // track the current state we could avoid making this call
- // so often.)
- enableVSyncLocked();
+ State nextState;
+ if (mVSyncState && vsyncRequested) {
+ nextState = mVSyncState->synthetic ? State::SyntheticVSync : State::VSync;
+ } else {
+ ALOGW_IF(!mVSyncState, "Ignoring VSYNC request while display is disconnected");
+ nextState = State::Idle;
+ }
+
+ if (mState != nextState) {
+ if (mState == State::VSync) {
+ mVSyncSource->setVSyncEnabled(false);
+ } else if (nextState == State::VSync) {
+ mVSyncSource->setVSyncEnabled(true);
+ }
+
+ mState = nextState;
}
if (event) {
@@ -352,19 +373,20 @@
}
// Wait for event or client registration/request.
- if (vsyncRequested) {
+ if (mState == State::Idle) {
+ mCondition.wait(lock);
+ } else {
// Generate a fake VSYNC after a long timeout in case the driver stalls. When the
// display is off, keep feeding clients at 60 Hz.
- const auto timeout = mVSyncState.synthetic ? 16ms : 1000ms;
+ const auto timeout = mState == State::SyntheticVSync ? 16ms : 1000ms;
if (mCondition.wait_for(lock, timeout) == std::cv_status::timeout) {
- ALOGW_IF(!mVSyncState.synthetic, "Faking VSYNC due to driver stall");
+ ALOGW_IF(mState == State::VSync, "Faking VSYNC due to driver stall");
- mPendingEvents.push_back(makeVSync(mVSyncState.displayId,
+ LOG_FATAL_IF(!mVSyncState);
+ mPendingEvents.push_back(makeVSync(mVSyncState->displayId,
systemTime(SYSTEM_TIME_MONOTONIC),
- ++mVSyncState.count));
+ ++mVSyncState->count));
}
- } else {
- mCondition.wait(lock);
}
}
}
@@ -413,31 +435,16 @@
}
}
-void EventThread::enableVSyncLocked() {
- if (!mVSyncState.synthetic) {
- if (!mVsyncEnabled) {
- mVsyncEnabled = true;
- mVSyncSource->setCallback(this);
- mVSyncSource->setVSyncEnabled(true);
- }
- }
- mDebugVsyncEnabled = true;
-}
-
-void EventThread::disableVSyncLocked() {
- if (mVsyncEnabled) {
- mVsyncEnabled = false;
- mVSyncSource->setVSyncEnabled(false);
- mDebugVsyncEnabled = false;
- }
-}
-
void EventThread::dump(std::string& result) const {
std::lock_guard<std::mutex> lock(mMutex);
- StringAppendF(&result, "%s: VSYNC %s\n", mThreadName, mDebugVsyncEnabled ? "on" : "off");
- StringAppendF(&result, " VSyncState{displayId=%u, count=%u%s}\n", mVSyncState.displayId,
- mVSyncState.count, mVSyncState.synthetic ? ", synthetic" : "");
+ StringAppendF(&result, "%s: state=%s VSyncState=", mThreadName, toCString(mState));
+ if (mVSyncState) {
+ StringAppendF(&result, "{displayId=%u, count=%u%s}\n", mVSyncState->displayId,
+ mVSyncState->count, mVSyncState->synthetic ? ", synthetic" : "");
+ } else {
+ StringAppendF(&result, "none\n");
+ }
StringAppendF(&result, " pending events (count=%zu):\n", mPendingEvents.size());
for (const auto& event : mPendingEvents) {
@@ -452,5 +459,18 @@
}
}
+const char* EventThread::toCString(State state) {
+ switch (state) {
+ case State::Idle:
+ return "Idle";
+ case State::Quit:
+ return "Quit";
+ case State::SyntheticVSync:
+ return "SyntheticVSync";
+ case State::VSync:
+ return "VSync";
+ }
+}
+
} // namespace impl
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 1a8ebb7..89b799e 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -22,6 +22,7 @@
#include <cstdint>
#include <deque>
#include <mutex>
+#include <optional>
#include <thread>
#include <vector>
@@ -176,9 +177,6 @@
void removeDisplayEventConnectionLocked(const wp<EventThreadConnection>& connection)
REQUIRES(mMutex);
- void enableVSyncLocked() REQUIRES(mMutex);
- void disableVSyncLocked() REQUIRES(mMutex);
-
// Implements VSyncSource::Callback
void onVSyncEvent(nsecs_t timestamp) override;
@@ -201,7 +199,9 @@
// VSYNC state of connected display.
struct VSyncState {
- uint32_t displayId = 0;
+ explicit VSyncState(uint32_t displayId) : displayId(displayId) {}
+
+ const uint32_t displayId;
// Number of VSYNC events since display was connected.
uint32_t count = 0;
@@ -210,13 +210,21 @@
bool synthetic = false;
};
- VSyncState mVSyncState GUARDED_BY(mMutex);
+ // TODO(b/74619554): Create per-display threads waiting on respective VSYNC signals,
+ // and support headless mode by injecting a fake display with synthetic VSYNC.
+ std::optional<VSyncState> mVSyncState GUARDED_BY(mMutex);
- bool mVsyncEnabled GUARDED_BY(mMutex) = false;
- bool mKeepRunning GUARDED_BY(mMutex) = true;
+ // State machine for event loop.
+ enum class State {
+ Idle,
+ Quit,
+ SyntheticVSync,
+ VSync,
+ };
- // for debugging
- bool mDebugVsyncEnabled GUARDED_BY(mMutex) = false;
+ State mState GUARDED_BY(mMutex) = State::Idle;
+
+ static const char* toCString(State);
// Callback that resets the idle timer when the next vsync is received.
ResetIdleTimerCallback mResetIdleTimer;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 2ed2866..b003451 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -84,14 +84,14 @@
Scheduler::~Scheduler() = default;
sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
- const std::string& connectionName, int64_t phaseOffsetNs, ResyncCallback resyncCallback,
+ const char* connectionName, int64_t phaseOffsetNs, ResyncCallback resyncCallback,
impl::EventThread::InterceptVSyncsCallback interceptCallback) {
const int64_t id = sNextId++;
ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id);
std::unique_ptr<EventThread> eventThread =
makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs,
- interceptCallback);
+ std::move(interceptCallback));
auto connection = std::make_unique<Connection>(new ConnectionHandle(id),
eventThread->createEventConnection(
std::move(resyncCallback)),
@@ -102,14 +102,13 @@
}
std::unique_ptr<EventThread> Scheduler::makeEventThread(
- const std::string& connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+ const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
impl::EventThread::InterceptVSyncsCallback interceptCallback) {
- const std::string sourceName = connectionName + "Source";
std::unique_ptr<VSyncSource> eventThreadSource =
- std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, true, sourceName.c_str());
- const std::string threadName = connectionName + "Thread";
- return std::make_unique<impl::EventThread>(std::move(eventThreadSource), interceptCallback,
- [this] { resetIdleTimer(); }, threadName.c_str());
+ std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, true, connectionName);
+ return std::make_unique<impl::EventThread>(std::move(eventThreadSource),
+ std::move(interceptCallback),
+ [this] { resetIdleTimer(); }, connectionName);
}
sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index e992398..b717605 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -73,7 +73,7 @@
/** Creates an EventThread connection. */
sp<ConnectionHandle> createConnection(
- const std::string& connectionName, int64_t phaseOffsetNs, ResyncCallback resyncCallback,
+ const char* connectionName, int64_t phaseOffsetNs, ResyncCallback resyncCallback,
impl::EventThread::InterceptVSyncsCallback interceptCallback);
sp<IDisplayEventConnection> createDisplayEventConnection(const sp<ConnectionHandle>& handle,
@@ -123,7 +123,7 @@
protected:
virtual std::unique_ptr<EventThread> makeEventThread(
- const std::string& connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+ const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
impl::EventThread::InterceptVSyncsCallback interceptCallback);
private:
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 14feb43..acf0013 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2564,6 +2564,17 @@
mPendingHotplugEvents.clear();
}
+void SurfaceFlinger::dispatchDisplayHotplugEvent(EventThread::DisplayType displayType,
+ bool connected) {
+ if (mUseScheduler) {
+ mScheduler->hotplugReceived(mAppConnectionHandle, displayType, connected);
+ mScheduler->hotplugReceived(mSfConnectionHandle, displayType, connected);
+ } else {
+ mEventThread->onHotplugReceived(displayType, connected);
+ mSFEventThread->onHotplugReceived(displayType, connected);
+ }
+}
+
sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
const wp<IBinder>& displayToken, const std::optional<DisplayId>& displayId,
const DisplayDeviceState& state, const sp<compositionengine::DisplaySurface>& dispSurface,
@@ -2668,19 +2679,9 @@
display->disconnect();
}
if (internalDisplayId && internalDisplayId == draw[i].displayId) {
- if (mUseScheduler) {
- mScheduler->hotplugReceived(mAppConnectionHandle,
- EventThread::DisplayType::Primary, false);
- } else {
- mEventThread->onHotplugReceived(EventThread::DisplayType::Primary, false);
- }
+ dispatchDisplayHotplugEvent(EventThread::DisplayType::Primary, false);
} else if (externalDisplayId && externalDisplayId == draw[i].displayId) {
- if (mUseScheduler) {
- mScheduler->hotplugReceived(mAppConnectionHandle,
- EventThread::DisplayType::External, false);
- } else {
- mEventThread->onHotplugReceived(EventThread::DisplayType::External, false);
- }
+ dispatchDisplayHotplugEvent(EventThread::DisplayType::External, false);
}
mDisplays.erase(draw.keyAt(i));
} else {
@@ -2786,23 +2787,9 @@
LOG_ALWAYS_FATAL_IF(!displayId);
if (displayId == getInternalDisplayId()) {
- if (mUseScheduler) {
- mScheduler->hotplugReceived(mAppConnectionHandle,
- EventThread::DisplayType::Primary,
- true);
- } else {
- mEventThread->onHotplugReceived(EventThread::DisplayType::Primary,
- true);
- }
+ dispatchDisplayHotplugEvent(EventThread::DisplayType::Primary, true);
} else if (displayId == getExternalDisplayId()) {
- if (mUseScheduler) {
- mScheduler->hotplugReceived(mAppConnectionHandle,
- EventThread::DisplayType::External,
- true);
- } else {
- mEventThread->onHotplugReceived(EventThread::DisplayType::External,
- true);
- }
+ dispatchDisplayHotplugEvent(EventThread::DisplayType::External, true);
}
}
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index c62f852..4d84144 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -294,10 +294,6 @@
// starts SurfaceFlinger main loop in the current thread
void run() ANDROID_API;
- enum {
- EVENT_VSYNC = HWC_EVENT_VSYNC
- };
-
// post an asynchronous message to the main thread
status_t postMessageAsync(const sp<MessageBase>& msg, nsecs_t reltime = 0, uint32_t flags = 0);
@@ -754,6 +750,8 @@
void processDisplayChangesLocked();
void processDisplayHotplugEventsLocked();
+ void dispatchDisplayHotplugEvent(EventThread::DisplayType displayType, bool connected);
+
/* ------------------------------------------------------------------------
* VSync
*/
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 396fc55..56d3bd4 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -26,6 +26,8 @@
#include <android/native_window.h>
+#include <binder/ProcessState.h>
+#include <gui/BufferItemConsumer.h>
#include <gui/ISurfaceComposer.h>
#include <gui/LayerState.h>
#include <gui/Surface.h>
@@ -495,10 +497,6 @@
// leave room for ~256 layers
const int32_t mLayerZBase = std::numeric_limits<int32_t>::max() - 256;
- void setRelativeZBasicHelper(uint32_t layerType);
- void setRelativeZGroupHelper(uint32_t layerType);
- void setAlphaBasicHelper(uint32_t layerType);
-
sp<SurfaceControl> mBlackBgSurface;
bool mColorManagementUsed;
@@ -544,15 +542,72 @@
}
int32_t mBufferPostDelay;
+
+ friend class LayerRenderPathTestHarness;
+};
+enum class RenderPath { SCREENSHOT, VIRTUAL_DISPLAY };
+
+class LayerRenderPathTestHarness {
+public:
+ LayerRenderPathTestHarness(LayerTransactionTest* delegate, RenderPath renderPath)
+ : mDelegate(delegate), mRenderPath(renderPath) {}
+
+ std::unique_ptr<ScreenCapture> getScreenCapture() {
+ switch (mRenderPath) {
+ case RenderPath::SCREENSHOT:
+ return mDelegate->screenshot();
+ case RenderPath::VIRTUAL_DISPLAY:
+
+ sp<IBinder> mainDisplay =
+ SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
+ DisplayInfo mainDisplayInfo;
+ SurfaceComposerClient::getDisplayInfo(mainDisplay, &mainDisplayInfo);
+
+ sp<IBinder> vDisplay;
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ sp<BufferItemConsumer> itemConsumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+
+ consumer->setConsumerName(String8("Virtual disp consumer"));
+ consumer->setDefaultBufferSize(mainDisplayInfo.w, mainDisplayInfo.h);
+
+ itemConsumer = new BufferItemConsumer(consumer,
+ // Sample usage bits from screenrecord
+ GRALLOC_USAGE_HW_VIDEO_ENCODER |
+ GRALLOC_USAGE_SW_READ_OFTEN);
+
+ vDisplay = SurfaceComposerClient::createDisplay(String8("VirtualDisplay"),
+ false /*secure*/);
+
+ SurfaceComposerClient::Transaction t;
+ t.setDisplaySurface(vDisplay, producer);
+ t.setDisplayLayerStack(vDisplay, 0);
+ t.setDisplayProjection(vDisplay, mainDisplayInfo.orientation,
+ Rect(mainDisplayInfo.viewportW, mainDisplayInfo.viewportH),
+ Rect(mainDisplayInfo.w, mainDisplayInfo.h));
+ t.apply();
+ SurfaceComposerClient::Transaction().apply(true);
+ BufferItem item;
+ itemConsumer->acquireBuffer(&item, 0, true);
+ auto sc = std::make_unique<ScreenCapture>(item.mGraphicBuffer);
+ itemConsumer->releaseBuffer(item);
+ SurfaceComposerClient::destroyDisplay(vDisplay);
+ return sc;
+ }
+ }
+
+protected:
+ LayerTransactionTest* mDelegate;
+ RenderPath mRenderPath;
};
-class LayerTypeTransactionTest : public LayerTransactionTest,
- public ::testing::WithParamInterface<uint32_t> {
+class LayerTypeTransactionHarness : public LayerTransactionTest {
public:
- LayerTypeTransactionTest() { mLayerType = GetParam(); }
+ LayerTypeTransactionHarness(uint32_t layerType) : mLayerType(layerType) {}
sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
- uint32_t flags = 0, SurfaceControl* parent = nullptr) override {
+ uint32_t flags = 0, SurfaceControl* parent = nullptr) {
// if the flags already have a layer type specified, return an error
if (flags & ISurfaceComposerClient::eFXSurfaceMask) {
return nullptr;
@@ -579,12 +634,69 @@
uint32_t mLayerType;
};
+class LayerTypeTransactionTest : public LayerTypeTransactionHarness,
+ public ::testing::WithParamInterface<uint32_t> {
+public:
+ LayerTypeTransactionTest() : LayerTypeTransactionHarness(GetParam()) {}
+};
+
+class LayerTypeAndRenderTypeTransactionTest
+ : public LayerTypeTransactionHarness,
+ public ::testing::WithParamInterface<std::tuple<uint32_t, RenderPath>> {
+public:
+ LayerTypeAndRenderTypeTransactionTest()
+ : LayerTypeTransactionHarness(std::get<0>(GetParam())),
+ mRenderPathHarness(LayerRenderPathTestHarness(this, std::get<1>(GetParam()))) {}
+
+ std::unique_ptr<ScreenCapture> getScreenCapture() {
+ return mRenderPathHarness.getScreenCapture();
+ }
+
+protected:
+ LayerRenderPathTestHarness mRenderPathHarness;
+};
+
+// Environment for starting up binder threads. This is required for testing
+// virtual displays, as BufferQueue parameters may be queried over binder.
+class BinderEnvironment : public ::testing::Environment {
+public:
+ void SetUp() override { ProcessState::self()->startThreadPool(); }
+};
+
+::testing::Environment* const binderEnv =
+ ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+class LayerRenderTypeTransactionTest : public LayerTransactionTest,
+ public ::testing::WithParamInterface<RenderPath> {
+public:
+ LayerRenderTypeTransactionTest() : mHarness(LayerRenderPathTestHarness(this, GetParam())) {}
+
+ std::unique_ptr<ScreenCapture> getScreenCapture() { return mHarness.getScreenCapture(); }
+ void setRelativeZBasicHelper(uint32_t layerType);
+ void setRelativeZGroupHelper(uint32_t layerType);
+ void setAlphaBasicHelper(uint32_t layerType);
+
+protected:
+ LayerRenderPathTestHarness mHarness;
+};
+
+INSTANTIATE_TEST_CASE_P(
+ LayerTypeAndRenderTypeTransactionTests, LayerTypeAndRenderTypeTransactionTest,
+ ::testing::Combine(
+ ::testing::Values(
+ static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferQueue),
+ static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferState)),
+ ::testing::Values(RenderPath::VIRTUAL_DISPLAY, RenderPath::SCREENSHOT)));
+
+INSTANTIATE_TEST_CASE_P(LayerRenderTypeTransactionTests, LayerRenderTypeTransactionTest,
+ ::testing::Values(RenderPath::VIRTUAL_DISPLAY, RenderPath::SCREENSHOT));
+
INSTANTIATE_TEST_CASE_P(
LayerTypeTransactionTests, LayerTypeTransactionTest,
::testing::Values(static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferQueue),
static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferState)));
-TEST_F(LayerTransactionTest, SetPositionBasic_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetPositionBasic_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -592,7 +704,7 @@
{
SCOPED_TRACE("default position");
const Rect rect(0, 0, 32, 32);
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(rect, Color::RED);
shot->expectBorder(rect, Color::BLACK);
}
@@ -601,13 +713,13 @@
{
SCOPED_TRACE("new position");
const Rect rect(5, 10, 37, 42);
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(rect, Color::RED);
shot->expectBorder(rect, Color::BLACK);
}
}
-TEST_F(LayerTransactionTest, SetPositionRounding_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetPositionRounding_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -619,17 +731,17 @@
Transaction().setPosition(layer, 0.5f - epsilon, 0.5f - epsilon).apply();
{
SCOPED_TRACE("rounding down");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
Transaction().setPosition(layer, 0.5f + epsilon, 0.5f + epsilon).apply();
{
SCOPED_TRACE("rounding up");
- screenshot()->expectColor(Rect(1, 1, 33, 33), Color::RED);
+ getScreenCapture()->expectColor(Rect(1, 1, 33, 33), Color::RED);
}
}
-TEST_F(LayerTransactionTest, SetPositionOutOfBounds_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetPositionOutOfBounds_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -637,17 +749,17 @@
Transaction().setPosition(layer, -32, -32).apply();
{
SCOPED_TRACE("negative coordinates");
- screenshot()->expectColor(mDisplayRect, Color::BLACK);
+ getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
}
Transaction().setPosition(layer, mDisplayWidth, mDisplayHeight).apply();
{
SCOPED_TRACE("positive coordinates");
- screenshot()->expectColor(mDisplayRect, Color::BLACK);
+ getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
}
}
-TEST_F(LayerTransactionTest, SetPositionPartiallyOutOfBounds_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetPositionPartiallyOutOfBounds_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -656,19 +768,19 @@
Transaction().setPosition(layer, -30, -30).apply();
{
SCOPED_TRACE("negative coordinates");
- screenshot()->expectColor(Rect(0, 0, 2, 2), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 2, 2), Color::RED);
}
Transaction().setPosition(layer, mDisplayWidth - 2, mDisplayHeight - 2).apply();
{
SCOPED_TRACE("positive coordinates");
- screenshot()->expectColor(Rect(mDisplayWidth - 2, mDisplayHeight - 2, mDisplayWidth,
- mDisplayHeight),
- Color::RED);
+ getScreenCapture()->expectColor(Rect(mDisplayWidth - 2, mDisplayHeight - 2, mDisplayWidth,
+ mDisplayHeight),
+ Color::RED);
}
}
-TEST_F(LayerTransactionTest, SetPositionWithResize_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetPositionWithResize_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -678,7 +790,7 @@
Transaction().setPosition(layer, 5, 10).setSize(layer, 64, 64).apply();
{
SCOPED_TRACE("resize pending");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
const Rect rect(5, 10, 37, 42);
shot->expectColor(rect, Color::RED);
shot->expectBorder(rect, Color::BLACK);
@@ -687,11 +799,11 @@
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
{
SCOPED_TRACE("resize applied");
- screenshot()->expectColor(Rect(5, 10, 69, 74), Color::RED);
+ getScreenCapture()->expectColor(Rect(5, 10, 69, 74), Color::RED);
}
}
-TEST_F(LayerTransactionTest, SetPositionWithNextResize_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetPositionWithNextResize_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -700,30 +812,30 @@
Transaction().setPosition(layer, 5, 10).setGeometryAppliesWithResize(layer).apply();
{
SCOPED_TRACE("new position pending");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
Transaction().setPosition(layer, 15, 20).apply();
{
SCOPED_TRACE("pending new position modified");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
Transaction().setSize(layer, 64, 64).apply();
{
SCOPED_TRACE("resize pending");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
// finally resize and latch the buffer
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
{
SCOPED_TRACE("new position applied");
- screenshot()->expectColor(Rect(15, 20, 79, 84), Color::RED);
+ getScreenCapture()->expectColor(Rect(15, 20, 79, 84), Color::RED);
}
}
-TEST_F(LayerTransactionTest, SetPositionWithNextResizeScaleToWindow_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetPositionWithNextResizeScaleToWindow_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -737,17 +849,17 @@
.apply();
{
SCOPED_TRACE("new position pending");
- screenshot()->expectColor(Rect(0, 0, 64, 64), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 64, 64), Color::RED);
}
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
{
SCOPED_TRACE("new position applied");
- screenshot()->expectColor(Rect(5, 10, 69, 74), Color::RED);
+ getScreenCapture()->expectColor(Rect(5, 10, 69, 74), Color::RED);
}
}
-TEST_F(LayerTransactionTest, SetSizeBasic_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetSizeBasic_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -755,7 +867,7 @@
Transaction().setSize(layer, 64, 64).apply();
{
SCOPED_TRACE("resize pending");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
const Rect rect(0, 0, 32, 32);
shot->expectColor(rect, Color::RED);
shot->expectBorder(rect, Color::BLACK);
@@ -764,18 +876,18 @@
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
{
SCOPED_TRACE("resize applied");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
const Rect rect(0, 0, 64, 64);
shot->expectColor(rect, Color::RED);
shot->expectBorder(rect, Color::BLACK);
}
}
-TEST_P(LayerTypeTransactionTest, SetSizeInvalid) {
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetSizeInvalid) {
// cannot test robustness against invalid sizes (zero or really huge)
}
-TEST_F(LayerTransactionTest, SetSizeWithScaleToWindow_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetSizeWithScaleToWindow_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -785,10 +897,10 @@
.setSize(layer, 64, 64)
.setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
.apply();
- screenshot()->expectColor(Rect(0, 0, 64, 64), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 64, 64), Color::RED);
}
-TEST_P(LayerTypeTransactionTest, SetZBasic) {
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetZBasic) {
sp<SurfaceControl> layerR;
sp<SurfaceControl> layerG;
ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
@@ -799,17 +911,17 @@
Transaction().setLayer(layerR, mLayerZBase + 1).apply();
{
SCOPED_TRACE("layerR");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
Transaction().setLayer(layerG, mLayerZBase + 2).apply();
{
SCOPED_TRACE("layerG");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::GREEN);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::GREEN);
}
}
-TEST_P(LayerTypeTransactionTest, SetZNegative) {
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetZNegative) {
sp<SurfaceControl> parent =
LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
ISurfaceComposerClient::eFXSurfaceContainer);
@@ -828,19 +940,19 @@
Transaction().setLayer(layerR, -1).setLayer(layerG, -2).apply();
{
SCOPED_TRACE("layerR");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
Transaction().setLayer(layerR, -3).apply();
{
SCOPED_TRACE("layerG");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::GREEN);
}
}
-void LayerTransactionTest::setRelativeZBasicHelper(uint32_t layerType) {
+void LayerRenderTypeTransactionTest::setRelativeZBasicHelper(uint32_t layerType) {
sp<SurfaceControl> layerR;
sp<SurfaceControl> layerG;
ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32, layerType));
@@ -867,7 +979,7 @@
}
{
SCOPED_TRACE("layerG above");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 16, 16), Color::RED);
shot->expectColor(Rect(16, 16, 48, 48), Color::GREEN);
}
@@ -875,17 +987,17 @@
Transaction().setRelativeLayer(layerG, layerR->getHandle(), -1).apply();
{
SCOPED_TRACE("layerG below");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectColor(Rect(32, 32, 48, 48), Color::GREEN);
}
}
-TEST_F(LayerTransactionTest, SetRelativeZBasic_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetRelativeZBasic_BufferQueue) {
ASSERT_NO_FATAL_FAILURE(setRelativeZBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
}
-TEST_F(LayerTransactionTest, SetRelativeZBasic_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetRelativeZBasic_BufferState) {
ASSERT_NO_FATAL_FAILURE(setRelativeZBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
}
@@ -918,7 +1030,7 @@
screenshot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
}
-void LayerTransactionTest::setRelativeZGroupHelper(uint32_t layerType) {
+void LayerRenderTypeTransactionTest::setRelativeZGroupHelper(uint32_t layerType) {
sp<SurfaceControl> layerR;
sp<SurfaceControl> layerG;
sp<SurfaceControl> layerB;
@@ -954,7 +1066,7 @@
{
SCOPED_TRACE("(layerR < layerG) < layerB");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 8, 8), Color::RED);
shot->expectColor(Rect(8, 8, 16, 16), Color::GREEN);
shot->expectColor(Rect(16, 16, 48, 48), Color::BLUE);
@@ -964,7 +1076,7 @@
Transaction().setLayer(layerR, mLayerZBase + 4).apply();
{
SCOPED_TRACE("layerB < (layerR < layerG)");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 8, 8), Color::RED);
shot->expectColor(Rect(8, 8, 40, 40), Color::GREEN);
shot->expectColor(Rect(40, 40, 48, 48), Color::BLUE);
@@ -974,7 +1086,7 @@
Transaction().setRelativeLayer(layerG, layerR->getHandle(), -3).apply();
{
SCOPED_TRACE("layerB < (layerG < layerR)");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectColor(Rect(32, 32, 40, 40), Color::GREEN);
shot->expectColor(Rect(40, 40, 48, 48), Color::BLUE);
@@ -985,7 +1097,7 @@
Transaction().setLayer(layerG, mLayerZBase).apply();
{
SCOPED_TRACE("layerG < layerB < layerR");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectColor(Rect(32, 32, 48, 48), Color::BLUE);
}
@@ -995,21 +1107,21 @@
Transaction().setLayer(layerR, mLayerZBase + 1).apply();
{
SCOPED_TRACE("layerG < layerR < layerB");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 16, 16), Color::RED);
shot->expectColor(Rect(16, 16, 48, 48), Color::BLUE);
}
}
-TEST_F(LayerTransactionTest, SetRelativeZGroup_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetRelativeZGroup_BufferQueue) {
ASSERT_NO_FATAL_FAILURE(setRelativeZGroupHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
}
-TEST_F(LayerTransactionTest, SetRelativeZGroup_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetRelativeZGroup_BufferState) {
ASSERT_NO_FATAL_FAILURE(setRelativeZGroupHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
}
-TEST_P(LayerTypeTransactionTest, SetRelativeZBug64572777) {
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetRelativeZBug64572777) {
sp<SurfaceControl> layerR;
sp<SurfaceControl> layerG;
@@ -1025,10 +1137,10 @@
layerG->clear();
// layerG should have been removed
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
-TEST_P(LayerTypeTransactionTest, SetFlagsHidden) {
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetFlagsHidden) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
@@ -1036,17 +1148,17 @@
Transaction().setFlags(layer, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden).apply();
{
SCOPED_TRACE("layer hidden");
- screenshot()->expectColor(mDisplayRect, Color::BLACK);
+ getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
}
Transaction().setFlags(layer, 0, layer_state_t::eLayerHidden).apply();
{
SCOPED_TRACE("layer shown");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
}
-TEST_P(LayerTypeTransactionTest, SetFlagsOpaque) {
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetFlagsOpaque) {
const Color translucentRed = {100, 0, 0, 100};
sp<SurfaceControl> layerR;
sp<SurfaceControl> layerG;
@@ -1061,14 +1173,14 @@
.apply();
{
SCOPED_TRACE("layerR opaque");
- screenshot()->expectColor(Rect(0, 0, 32, 32), {100, 0, 0, 255});
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {100, 0, 0, 255});
}
Transaction().setFlags(layerR, 0, layer_state_t::eLayerOpaque).apply();
{
SCOPED_TRACE("layerR translucent");
const uint8_t g = uint8_t(255 - translucentRed.a);
- screenshot()->expectColor(Rect(0, 0, 32, 32), {100, g, 0, 255});
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {100, g, 0, 255});
}
}
@@ -1090,7 +1202,7 @@
composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
}
-TEST_F(LayerTransactionTest, SetTransparentRegionHintBasic_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintBasic_BufferQueue) {
const Rect top(0, 0, 32, 16);
const Rect bottom(0, 16, 32, 32);
sp<SurfaceControl> layer;
@@ -1105,7 +1217,7 @@
ASSERT_NO_FATAL_FAILURE(postBufferQueueLayerBuffer(layer));
{
SCOPED_TRACE("top transparent");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(top, Color::BLACK);
shot->expectColor(bottom, Color::RED);
}
@@ -1113,7 +1225,7 @@
Transaction().setTransparentRegionHint(layer, Region(bottom)).apply();
{
SCOPED_TRACE("transparent region hint pending");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(top, Color::BLACK);
shot->expectColor(bottom, Color::RED);
}
@@ -1124,13 +1236,13 @@
ASSERT_NO_FATAL_FAILURE(postBufferQueueLayerBuffer(layer));
{
SCOPED_TRACE("bottom transparent");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(top, Color::RED);
shot->expectColor(bottom, Color::BLACK);
}
}
-TEST_F(LayerTransactionTest, SetTransparentRegionHintBasic_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintBasic_BufferState) {
const Rect top(0, 0, 32, 16);
const Rect bottom(0, 16, 32, 32);
sp<SurfaceControl> layer;
@@ -1152,7 +1264,7 @@
.apply();
{
SCOPED_TRACE("top transparent");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(top, Color::BLACK);
shot->expectColor(bottom, Color::RED);
}
@@ -1160,7 +1272,7 @@
Transaction().setTransparentRegionHint(layer, Region(bottom)).apply();
{
SCOPED_TRACE("transparent region hint intermediate");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(top, Color::BLACK);
shot->expectColor(bottom, Color::BLACK);
}
@@ -1175,13 +1287,13 @@
Transaction().setBuffer(layer, buffer).apply();
{
SCOPED_TRACE("bottom transparent");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(top, Color::RED);
shot->expectColor(bottom, Color::BLACK);
}
}
-TEST_F(LayerTransactionTest, SetTransparentRegionHintOutOfBounds_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintOutOfBounds_BufferQueue) {
sp<SurfaceControl> layerTransparent;
sp<SurfaceControl> layerR;
ASSERT_NO_FATAL_FAILURE(layerTransparent = createLayer("test transparent", 32, 32));
@@ -1196,10 +1308,10 @@
ASSERT_NO_FATAL_FAILURE(
fillBufferQueueLayerColor(layerTransparent, Color::TRANSPARENT, 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layerR, Color::RED, 32, 32));
- screenshot()->expectColor(Rect(16, 16, 48, 48), Color::RED);
+ getScreenCapture()->expectColor(Rect(16, 16, 48, 48), Color::RED);
}
-TEST_F(LayerTransactionTest, SetTransparentRegionHintOutOfBounds_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintOutOfBounds_BufferState) {
sp<SurfaceControl> layerTransparent;
sp<SurfaceControl> layerR;
ASSERT_NO_FATAL_FAILURE(layerTransparent = createLayer("test transparent", 32, 32));
@@ -1215,10 +1327,96 @@
ASSERT_NO_FATAL_FAILURE(
fillBufferQueueLayerColor(layerTransparent, Color::TRANSPARENT, 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layerR, Color::RED, 32, 32));
- screenshot()->expectColor(Rect(16, 16, 48, 48), Color::RED);
+ getScreenCapture()->expectColor(Rect(16, 16, 48, 48), Color::RED);
}
-void LayerTransactionTest::setAlphaBasicHelper(uint32_t layerType) {
+TEST_P(LayerRenderTypeTransactionTest, SetColorAlpha_Color_NoEffect) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 0, 0, ISurfaceComposerClient::eFXSurfaceColor));
+
+ half3 color;
+ color.r = 1.0f;
+ color.g = 0.0f;
+ color.b = 0.0f;
+ Transaction()
+ .setCrop_legacy(layer, Rect(0, 0, 32, 32))
+ .setAlpha(layer, 1.0f)
+ .setColor(layer, color)
+ .setColorAlpha(layer, 0.5f)
+ .apply();
+
+ screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorAlpha_BufferQueue_NoEffect) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ Transaction().setAlpha(layer, 1.0f).setColorAlpha(layer, 0.5f).apply();
+
+ screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorAlpha_BufferState_ColorLayer) {
+ sp<SurfaceControl> bgLayer;
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(bgLayer = createLayer("test bg", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bgLayer, Color::RED, 32, 32));
+
+ // create color layer
+ half3 color;
+ color.r = 0.0f;
+ color.g = 1.0f;
+ color.b = 0.0f;
+ Transaction().setFrame(layer, Rect(0, 0, 32, 32)).setColor(layer, color).apply();
+
+ {
+ SCOPED_TRACE("before alpha");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::GREEN);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+
+ // apply alpha
+ Transaction().setAlpha(layer, 0.0f).apply();
+ {
+ SCOPED_TRACE("set alpha");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorAlpha_BufferState_NoColorLayer) {
+ sp<SurfaceControl> bgLayer;
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(bgLayer = createLayer("test bg", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bgLayer, Color::RED, 32, 32));
+
+ {
+ SCOPED_TRACE("before alpha");
+ screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ }
+
+ // setting alpha without creating color layer should have no effect
+ Transaction().setFrame(layer, Rect(0, 0, 32, 32)).setAlpha(layer, 0.5f).apply();
+ {
+ SCOPED_TRACE("alpha");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+}
+
+void LayerRenderTypeTransactionTest::setAlphaBasicHelper(uint32_t layerType) {
sp<SurfaceControl> layer1;
sp<SurfaceControl> layer2;
ASSERT_NO_FATAL_FAILURE(layer1 = createLayer("test 1", 32, 32, layerType));
@@ -1248,7 +1446,7 @@
ASSERT_FALSE(true) << "Unsupported layer type";
}
{
- auto shot = screenshot();
+ auto shot = getScreenCapture();
uint8_t r = 16; // 64 * 0.25f
uint8_t g = 48; // 64 * 0.75f
shot->expectColor(Rect(0, 0, 16, 32), {r, 0, 0, 255});
@@ -1259,15 +1457,15 @@
}
}
-TEST_F(LayerTransactionTest, SetAlphaBasic_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetAlphaBasic_BufferQueue) {
ASSERT_NO_FATAL_FAILURE(setAlphaBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
}
-TEST_F(LayerTransactionTest, SetAlphaBasic_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetAlphaBasic_BufferState) {
ASSERT_NO_FATAL_FAILURE(setAlphaBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
}
-TEST_P(LayerTypeTransactionTest, SetAlphaClamped) {
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetAlphaClamped) {
const Color color = {64, 0, 0, 255};
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
@@ -1276,17 +1474,17 @@
Transaction().setAlpha(layer, 2.0f).apply();
{
SCOPED_TRACE("clamped to 1.0f");
- screenshot()->expectColor(Rect(0, 0, 32, 32), color);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), color);
}
Transaction().setAlpha(layer, -1.0f).apply();
{
SCOPED_TRACE("clamped to 0.0f");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
}
}
-TEST_P(LayerTypeTransactionTest, SetCornerRadius) {
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadius) {
sp<SurfaceControl> layer;
const uint8_t size = 64;
const uint8_t testArea = 4;
@@ -1300,7 +1498,7 @@
{
const uint8_t bottom = size - 1;
const uint8_t right = size - 1;
- auto shot = screenshot();
+ auto shot = getScreenCapture();
// Transparent corners
shot->expectColor(Rect(0, 0, testArea, testArea), Color::BLACK);
shot->expectColor(Rect(size - testArea, 0, right, testArea), Color::BLACK);
@@ -1309,7 +1507,7 @@
}
}
-TEST_P(LayerTypeTransactionTest, SetCornerRadiusChildCrop) {
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusChildCrop) {
sp<SurfaceControl> parent;
sp<SurfaceControl> child;
const uint8_t size = 64;
@@ -1328,7 +1526,7 @@
{
const uint8_t bottom = size - 1;
const uint8_t right = size - 1;
- auto shot = screenshot();
+ auto shot = getScreenCapture();
// Top edge of child should not have rounded corners because it's translated in the parent
shot->expectColor(Rect(0, size / 2, right, static_cast<int>(bottom - cornerRadius)),
Color::GREEN);
@@ -1338,7 +1536,7 @@
}
}
-TEST_F(LayerTransactionTest, SetColorBasic) {
+TEST_P(LayerRenderTypeTransactionTest, SetColorBasic) {
sp<SurfaceControl> bufferLayer;
sp<SurfaceControl> colorLayer;
ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
@@ -1354,7 +1552,7 @@
{
SCOPED_TRACE("default color");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
}
const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
@@ -1365,11 +1563,82 @@
Transaction().setColor(colorLayer, color).apply();
{
SCOPED_TRACE("new color");
- screenshot()->expectColor(Rect(0, 0, 32, 32), expected, tolerance);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expected, tolerance);
}
}
-TEST_F(LayerTransactionTest, SetColorClamped) {
+TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_BufferState_NoPriorColor) {
+ sp<SurfaceControl> bufferQueueLayer;
+ sp<SurfaceControl> bufferStateLayer;
+ ASSERT_NO_FATAL_FAILURE(bufferQueueLayer = createLayer("test bg", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(
+ bufferStateLayer =
+ createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferQueueLayer, Color::RED, 32, 32));
+
+ {
+ SCOPED_TRACE("default color");
+ screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ }
+
+ half3 color;
+ color.r = 0.0f;
+ color.g = 1.0f;
+ color.b = 0.0f;
+ Transaction()
+ .setFrame(bufferStateLayer, Rect(0, 0, 32, 32))
+ .setLayer(bufferStateLayer, mLayerZBase + 1)
+ .setColor(bufferStateLayer, color)
+ .apply();
+
+ {
+ SCOPED_TRACE("set color");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::GREEN);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_BufferState_PriorColor) {
+ sp<SurfaceControl> bufferQueueLayer;
+ sp<SurfaceControl> bufferStateLayer;
+ ASSERT_NO_FATAL_FAILURE(bufferQueueLayer = createLayer("test bg", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(
+ bufferStateLayer =
+ createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferQueueLayer, Color::RED, 32, 32));
+
+ half3 color;
+ color.r = 0.0f;
+ color.g = 1.0f;
+ color.b = 0.0f;
+ Transaction()
+ .setFrame(bufferStateLayer, Rect(0, 0, 32, 32))
+ .setLayer(bufferStateLayer, mLayerZBase + 1)
+ .setColor(bufferStateLayer, color)
+ .apply();
+ {
+ SCOPED_TRACE("default color");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::GREEN);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+
+ color.r = 0.0f;
+ color.g = 0.0f;
+ color.b = 1.0f;
+ Transaction().setColor(bufferStateLayer, color).apply();
+ {
+ SCOPED_TRACE("new color");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorClamped) {
sp<SurfaceControl> colorLayer;
ASSERT_NO_FATAL_FAILURE(colorLayer =
createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
@@ -1379,10 +1648,10 @@
.setColor(colorLayer, half3(2.0f, -1.0f, 0.0f))
.apply();
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
-TEST_F(LayerTransactionTest, SetColorWithAlpha) {
+TEST_P(LayerRenderTypeTransactionTest, SetColorWithAlpha) {
sp<SurfaceControl> bufferLayer;
sp<SurfaceControl> colorLayer;
ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
@@ -1403,11 +1672,11 @@
.setAlpha(colorLayer, alpha)
.setLayer(colorLayer, mLayerZBase + 1)
.apply();
- screenshot()->expectColor(Rect(0, 0, 32, 32), {expected.r, expected.g, expected.b, 255},
- tolerance);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {expected.r, expected.g, expected.b, 255},
+ tolerance);
}
-TEST_F(LayerTransactionTest, SetColorWithParentAlpha_Bug74220420) {
+TEST_P(LayerRenderTypeTransactionTest, SetColorWithParentAlpha_Bug74220420) {
sp<SurfaceControl> bufferLayer;
sp<SurfaceControl> parentLayer;
sp<SurfaceControl> colorLayer;
@@ -1430,21 +1699,21 @@
.setAlpha(parentLayer, alpha)
.setLayer(parentLayer, mLayerZBase + 1)
.apply();
- screenshot()->expectColor(Rect(0, 0, 32, 32), {expected.r, expected.g, expected.b, 255},
- tolerance);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {expected.r, expected.g, expected.b, 255},
+ tolerance);
}
-TEST_P(LayerTypeTransactionTest, SetColorWithBuffer) {
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetColorWithBuffer) {
sp<SurfaceControl> bufferLayer;
ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(bufferLayer, Color::RED, 32, 32));
// color is ignored
Transaction().setColor(bufferLayer, half3(0.0f, 1.0f, 0.0f)).apply();
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
-TEST_P(LayerTypeTransactionTest, SetLayerStackBasic) {
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetLayerStackBasic) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
@@ -1452,17 +1721,17 @@
Transaction().setLayerStack(layer, mDisplayLayerStack + 1).apply();
{
SCOPED_TRACE("non-existing layer stack");
- screenshot()->expectColor(mDisplayRect, Color::BLACK);
+ getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
}
Transaction().setLayerStack(layer, mDisplayLayerStack).apply();
{
SCOPED_TRACE("original layer stack");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
}
-TEST_F(LayerTransactionTest, SetMatrixBasic_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetMatrixBasic_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
@@ -1471,40 +1740,40 @@
Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f).setPosition(layer, 0, 0).apply();
{
SCOPED_TRACE("IDENTITY");
- screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, Color::BLUE,
- Color::WHITE);
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE);
}
Transaction().setMatrix(layer, -1.0f, 0.0f, 0.0f, 1.0f).setPosition(layer, 32, 0).apply();
{
SCOPED_TRACE("FLIP_H");
- screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::GREEN, Color::RED, Color::WHITE,
- Color::BLUE);
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::GREEN, Color::RED,
+ Color::WHITE, Color::BLUE);
}
Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, -1.0f).setPosition(layer, 0, 32).apply();
{
SCOPED_TRACE("FLIP_V");
- screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::WHITE, Color::RED,
- Color::GREEN);
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::WHITE,
+ Color::RED, Color::GREEN);
}
Transaction().setMatrix(layer, 0.0f, 1.0f, -1.0f, 0.0f).setPosition(layer, 32, 0).apply();
{
SCOPED_TRACE("ROT_90");
- screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::RED, Color::WHITE,
- Color::GREEN);
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::RED,
+ Color::WHITE, Color::GREEN);
}
Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).setPosition(layer, 0, 0).apply();
{
SCOPED_TRACE("SCALE");
- screenshot()->expectQuadrant(Rect(0, 0, 64, 64), Color::RED, Color::GREEN, Color::BLUE,
- Color::WHITE, true /* filtered */);
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 64, 64), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE, true /* filtered */);
}
}
-TEST_F(LayerTransactionTest, SetMatrixBasic_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetMatrixBasic_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -1517,40 +1786,40 @@
.apply();
{
SCOPED_TRACE("IDENTITY");
- screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, Color::BLUE,
- Color::WHITE);
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE);
}
Transaction().setMatrix(layer, -1.0f, 0.0f, 0.0f, 1.0f).apply();
{
SCOPED_TRACE("FLIP_H");
- screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, Color::BLUE,
- Color::WHITE);
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE);
}
Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, -1.0f).apply();
{
SCOPED_TRACE("FLIP_V");
- screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, Color::BLUE,
- Color::WHITE);
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE);
}
Transaction().setMatrix(layer, 0.0f, 1.0f, -1.0f, 0.0f).apply();
{
SCOPED_TRACE("ROT_90");
- screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, Color::BLUE,
- Color::WHITE);
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE);
}
Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).apply();
{
SCOPED_TRACE("SCALE");
- screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN, Color::BLUE,
- Color::WHITE);
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE);
}
}
-TEST_F(LayerTransactionTest, SetMatrixRot45_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetMatrixRot45_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
@@ -1560,7 +1829,7 @@
const float trans = M_SQRT2 * 16.0f;
Transaction().setMatrix(layer, rot, rot, -rot, rot).setPosition(layer, trans, 0).apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
// check a 8x8 region inside each color
auto get8x8Rect = [](int32_t centerX, int32_t centerY) {
const int32_t halfL = 4;
@@ -1573,7 +1842,7 @@
shot->expectColor(get8x8Rect(2 * unit, 3 * unit), Color::WHITE);
}
-TEST_F(LayerTransactionTest, SetMatrixWithResize_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetMatrixWithResize_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -1582,7 +1851,7 @@
Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).setSize(layer, 64, 64).apply();
{
SCOPED_TRACE("resize pending");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
const Rect rect(0, 0, 32, 32);
shot->expectColor(rect, Color::RED);
shot->expectBorder(rect, Color::BLACK);
@@ -1592,11 +1861,11 @@
{
SCOPED_TRACE("resize applied");
const Rect rect(0, 0, 128, 128);
- screenshot()->expectColor(rect, Color::RED);
+ getScreenCapture()->expectColor(rect, Color::RED);
}
}
-TEST_F(LayerTransactionTest, SetMatrixWithScaleToWindow_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetMatrixWithScaleToWindow_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -1607,10 +1876,10 @@
.setSize(layer, 64, 64)
.setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
.apply();
- screenshot()->expectColor(Rect(0, 0, 128, 128), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 128, 128), Color::RED);
}
-TEST_F(LayerTransactionTest, SetOverrideScalingModeBasic_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetOverrideScalingModeBasic_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
@@ -1625,8 +1894,8 @@
.apply();
{
SCOPED_TRACE("SCALE_TO_WINDOW");
- screenshot()->expectQuadrant(Rect(0, 0, 64, 16), Color::RED, Color::GREEN, Color::BLUE,
- Color::WHITE, true /* filtered */);
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 64, 16), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE, true /* filtered */);
}
}
@@ -1643,19 +1912,19 @@
ASSERT_GT(frameStats.refreshPeriodNano, static_cast<nsecs_t>(0));
}
-TEST_F(LayerTransactionTest, SetCropBasic_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetCropBasic_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
const Rect crop(8, 8, 24, 24);
Transaction().setCrop_legacy(layer, crop).apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(crop, Color::RED);
shot->expectBorder(crop, Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetCropBasic_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetCropBasic_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -1663,12 +1932,12 @@
const Rect crop(8, 8, 24, 24);
Transaction().setCrop(layer, crop).apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetCropEmpty_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetCropEmpty_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -1676,17 +1945,17 @@
{
SCOPED_TRACE("empty rect");
Transaction().setCrop_legacy(layer, Rect(8, 8, 8, 8)).apply();
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
{
SCOPED_TRACE("negative rect");
Transaction().setCrop_legacy(layer, Rect(8, 8, 0, 0)).apply();
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
}
-TEST_F(LayerTransactionTest, SetCropEmpty_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetCropEmpty_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -1695,28 +1964,28 @@
{
SCOPED_TRACE("empty rect");
Transaction().setCrop(layer, Rect(8, 8, 8, 8)).apply();
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
{
SCOPED_TRACE("negative rect");
Transaction().setCrop(layer, Rect(8, 8, 0, 0)).apply();
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
}
-TEST_F(LayerTransactionTest, SetCropOutOfBounds_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
Transaction().setCrop_legacy(layer, Rect(-128, -64, 128, 64)).apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetCropOutOfBounds_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", mDisplayWidth, mDisplayHeight / 2,
ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -1735,7 +2004,7 @@
Transaction().setCrop(layer, Rect(-128, -128, mDisplayWidth, mDisplayHeight / 4)).apply();
{
SCOPED_TRACE("out of bounds, negative (upper left) direction");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight / 2), Color::BLUE);
shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight / 2), Color::BLACK);
}
@@ -1746,7 +2015,7 @@
.apply();
{
SCOPED_TRACE("out of bounds, positive (lower right) direction");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight / 2), Color::RED);
shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight / 2), Color::BLACK);
}
@@ -1755,14 +2024,14 @@
Transaction().setCrop(layer, Rect(-128, -128, -1, -1)).apply();
{
SCOPED_TRACE("Fully out of bounds");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight / 4), Color::BLUE);
shot->expectColor(Rect(0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2),
Color::RED);
}
}
-TEST_F(LayerTransactionTest, SetCropWithTranslation_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetCropWithTranslation_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -1770,12 +2039,12 @@
const Point position(32, 32);
const Rect crop(8, 8, 24, 24);
Transaction().setPosition(layer, position.x, position.y).setCrop_legacy(layer, crop).apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(crop + position, Color::RED);
shot->expectBorder(crop + position, Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetCropWithTranslation_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetCropWithTranslation_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -1784,12 +2053,12 @@
const Rect frame(32, 32, 64, 64);
const Rect crop(8, 8, 24, 24);
Transaction().setFrame(layer, frame).setCrop(layer, crop).apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(frame, Color::RED);
shot->expectBorder(frame, Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetCropWithScale_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetCropWithScale_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -1799,12 +2068,12 @@
.setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f)
.setCrop_legacy(layer, Rect(8, 8, 24, 24))
.apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(16, 16, 48, 48), Color::RED);
shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetCropWithResize_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetCropWithResize_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -1813,7 +2082,7 @@
Transaction().setCrop_legacy(layer, Rect(8, 8, 24, 24)).setSize(layer, 16, 16).apply();
{
SCOPED_TRACE("resize pending");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(8, 8, 24, 24), Color::RED);
shot->expectBorder(Rect(8, 8, 24, 24), Color::BLACK);
}
@@ -1821,13 +2090,13 @@
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
{
SCOPED_TRACE("resize applied");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(8, 8, 16, 16), Color::RED);
shot->expectBorder(Rect(8, 8, 16, 16), Color::BLACK);
}
}
-TEST_F(LayerTransactionTest, SetCropWithNextResize_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetCropWithNextResize_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -1839,32 +2108,32 @@
.apply();
{
SCOPED_TRACE("waiting for next resize");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
Transaction().setCrop_legacy(layer, Rect(4, 4, 12, 12)).apply();
{
SCOPED_TRACE("pending crop modified");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
Transaction().setSize(layer, 16, 16).apply();
{
SCOPED_TRACE("resize pending");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
// finally resize
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
{
SCOPED_TRACE("new crop applied");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(4, 4, 12, 12), Color::RED);
shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK);
}
}
-TEST_F(LayerTransactionTest, SetCropWithNextResizeScaleToWindow_BufferQueue) {
+TEST_P(LayerRenderTypeTransactionTest, SetCropWithNextResizeScaleToWindow_BufferQueue) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
@@ -1878,7 +2147,7 @@
.apply();
{
SCOPED_TRACE("new crop pending");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 16, 16), Color::RED);
shot->expectBorder(Rect(0, 0, 16, 16), Color::BLACK);
}
@@ -1889,13 +2158,13 @@
Transaction().setPosition(layer, 0, 0).apply();
{
SCOPED_TRACE("new crop applied");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(4, 4, 12, 12), Color::RED);
shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK);
}
}
-TEST_F(LayerTransactionTest, SetFrameBasic_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetFrameBasic_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -1903,12 +2172,12 @@
const Rect frame(8, 8, 24, 24);
Transaction().setFrame(layer, frame).apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(frame, Color::RED);
shot->expectBorder(frame, Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetFrameEmpty_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetFrameEmpty_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -1917,29 +2186,29 @@
{
SCOPED_TRACE("empty rect");
Transaction().setFrame(layer, Rect(8, 8, 8, 8)).apply();
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
}
{
SCOPED_TRACE("negative rect");
Transaction().setFrame(layer, Rect(8, 8, 0, 0)).apply();
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
}
}
-TEST_F(LayerTransactionTest, SetFrameDefaultParentless_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultParentless_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 10, 10));
// A parentless layer will default to a frame with the same size as the buffer
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 10, 10), Color::RED);
shot->expectBorder(Rect(0, 0, 10, 10), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetFrameDefaultBSParent_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBSParent_BufferState) {
sp<SurfaceControl> parent, child;
ASSERT_NO_FATAL_FAILURE(
parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -1953,12 +2222,12 @@
Transaction().reparent(child, parent->getHandle()).apply();
// A layer will default to the frame of its parent
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetFrameDefaultBQParent_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBQParent_BufferState) {
sp<SurfaceControl> parent, child;
ASSERT_NO_FATAL_FAILURE(parent = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(parent, Color::RED, 32, 32));
@@ -1970,12 +2239,12 @@
Transaction().reparent(child, parent->getHandle()).apply();
// A layer will default to the frame of its parent
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetFrameUpdate_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetFrameUpdate_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -1986,12 +2255,12 @@
Transaction().setFrame(layer, Rect(16, 16, 48, 48)).apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(16, 16, 48, 48), Color::RED);
shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetFrameOutsideBounds_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetFrameOutsideBounds_BufferState) {
sp<SurfaceControl> parent, child;
ASSERT_NO_FATAL_FAILURE(
parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -2005,25 +2274,25 @@
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10));
Transaction().setFrame(child, Rect(0, 16, 32, 32)).apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 16), Color::RED);
shot->expectColor(Rect(0, 16, 32, 32), Color::BLUE);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetBufferBasic_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetBufferBasic_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetBufferMultipleBuffers_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -2032,7 +2301,7 @@
{
SCOPED_TRACE("set buffer 1");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
@@ -2041,7 +2310,7 @@
{
SCOPED_TRACE("set buffer 2");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
@@ -2050,13 +2319,13 @@
{
SCOPED_TRACE("set buffer 3");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
}
-TEST_F(LayerTransactionTest, SetBufferMultipleLayers_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleLayers_BufferState) {
sp<SurfaceControl> layer1;
ASSERT_NO_FATAL_FAILURE(
layer1 = createLayer("test", 64, 64, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -2070,7 +2339,7 @@
Transaction().setFrame(layer1, Rect(0, 0, 64, 64)).apply();
{
SCOPED_TRACE("set layer 1 buffer red");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 64, 64), Color::RED);
}
@@ -2079,7 +2348,7 @@
Transaction().setFrame(layer2, Rect(0, 0, 32, 32)).apply();
{
SCOPED_TRACE("set layer 2 buffer blue");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
shot->expectColor(Rect(0, 32, 64, 64), Color::RED);
shot->expectColor(Rect(0, 32, 32, 64), Color::RED);
@@ -2088,7 +2357,7 @@
ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer1, Color::GREEN, 64, 64));
{
SCOPED_TRACE("set layer 1 buffer green");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
shot->expectColor(Rect(0, 32, 64, 64), Color::GREEN);
shot->expectColor(Rect(0, 32, 32, 64), Color::GREEN);
@@ -2098,14 +2367,14 @@
{
SCOPED_TRACE("set layer 2 buffer white");
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::WHITE);
shot->expectColor(Rect(0, 32, 64, 64), Color::GREEN);
shot->expectColor(Rect(0, 32, 32, 64), Color::GREEN);
}
}
-TEST_F(LayerTransactionTest, SetTransformRotate90_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetTransformRotate90_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -2118,11 +2387,11 @@
.setTransform(layer, NATIVE_WINDOW_TRANSFORM_ROT_90)
.apply();
- screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::RED, Color::WHITE,
- Color::GREEN, true /* filtered */);
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::RED, Color::WHITE,
+ Color::GREEN, true /* filtered */);
}
-TEST_F(LayerTransactionTest, SetTransformFlipH_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetTransformFlipH_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -2135,11 +2404,11 @@
.setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_H)
.apply();
- screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::GREEN, Color::RED, Color::WHITE,
- Color::BLUE, true /* filtered */);
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::GREEN, Color::RED, Color::WHITE,
+ Color::BLUE, true /* filtered */);
}
-TEST_F(LayerTransactionTest, SetTransformFlipV_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetTransformFlipV_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -2152,8 +2421,8 @@
.setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_V)
.apply();
- screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::WHITE, Color::RED,
- Color::GREEN, true /* filtered */);
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::WHITE, Color::RED,
+ Color::GREEN, true /* filtered */);
}
TEST_F(LayerTransactionTest, SetTransformToDisplayInverse_BufferState) {
@@ -2168,7 +2437,7 @@
Transaction().setTransformToDisplayInverse(layer, true).apply();
}
-TEST_F(LayerTransactionTest, SetFenceBasic_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetFenceBasic_BufferState) {
sp<SurfaceControl> layer;
Transaction transaction;
ASSERT_NO_FATAL_FAILURE(
@@ -2193,12 +2462,12 @@
ASSERT_NE(static_cast<status_t>(Fence::Status::Unsignaled), status);
std::this_thread::sleep_for(200ms);
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetFenceNull_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetFenceNull_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -2217,12 +2486,77 @@
.setAcquireFence(layer, fence)
.apply();
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorDataspace_ColorLayer_NoEffect) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 0, 0, ISurfaceComposerClient::eFXSurfaceColor));
+ half3 color;
+ color.r = 1.0f;
+ color.g = 0.0f;
+ color.b = 0.0f;
+ Transaction()
+ .setCrop_legacy(layer, Rect(0, 0, 32, 32))
+ .setColor(layer, color)
+ .setDataspace(layer, ui::Dataspace::UNKNOWN)
+ .setColorDataspace(layer, ui::Dataspace::BT2020_ITU)
+ .apply();
+
+ screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorDataspace_BufferQueue_NoEffect) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ Transaction()
+ .setDataspace(layer, ui::Dataspace::UNKNOWN)
+ .setColorDataspace(layer, ui::Dataspace::BT2020_ITU)
+ .apply();
+
+ screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorDataspace_BufferState_ColorLayer) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ half3 color;
+ color.r = 1.0f;
+ color.g = 0.0f;
+ color.b = 0.0f;
+ Transaction()
+ .setFrame(layer, Rect(0, 0, 32, 32))
+ .setColor(layer, color)
+ .setColorDataspace(layer, ui::Dataspace::BT2020_ITU)
+ .apply();
auto shot = screenshot();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetDataspaceBasic_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetColorDataspace_BufferState_NoColorLayer) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+
+ Transaction()
+ .setFrame(layer, Rect(0, 0, 32, 32))
+ .setDataspace(layer, ui::Dataspace::UNKNOWN)
+ .setColorDataspace(layer, ui::Dataspace::DCI_P3)
+ .apply();
+
+ screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetDataspaceBasic_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -2239,12 +2573,12 @@
.setDataspace(layer, ui::Dataspace::UNKNOWN)
.apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetHdrMetadataBasic_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetHdrMetadataBasic_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -2263,12 +2597,12 @@
.setHdrMetadata(layer, hdrMetadata)
.apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetSurfaceDamageRegionBasic_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetSurfaceDamageRegionBasic_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -2287,12 +2621,12 @@
.setSurfaceDamageRegion(layer, region)
.apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
-TEST_F(LayerTransactionTest, SetApiBasic_BufferState) {
+TEST_P(LayerRenderTypeTransactionTest, SetApiBasic_BufferState) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(
layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
@@ -2309,7 +2643,7 @@
.setApi(layer, NATIVE_WINDOW_API_CPU)
.apply();
- auto shot = screenshot();
+ auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
}
@@ -2518,7 +2852,7 @@
}
};
-TEST_F(LayerTransactionTest, SetColorTransformBasic) {
+TEST_P(LayerRenderTypeTransactionTest, SetColorTransformBasic) {
sp<SurfaceControl> colorLayer;
ASSERT_NO_FATAL_FAILURE(colorLayer =
createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
@@ -2529,7 +2863,7 @@
.apply();
{
SCOPED_TRACE("default color");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
}
const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
@@ -2561,11 +2895,11 @@
.setColorTransform(colorLayer, matrix, vec3()).apply();
{
SCOPED_TRACE("new color");
- screenshot()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
}
}
-TEST_F(LayerTransactionTest, SetColorTransformOnParent) {
+TEST_P(LayerRenderTypeTransactionTest, SetColorTransformOnParent) {
sp<SurfaceControl> parentLayer;
sp<SurfaceControl> colorLayer;
ASSERT_NO_FATAL_FAILURE(parentLayer = createLayer("parent", 0 /* buffer width */,
@@ -2582,7 +2916,7 @@
.apply();
{
SCOPED_TRACE("default color");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
}
const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
@@ -2616,11 +2950,11 @@
.apply();
{
SCOPED_TRACE("new color");
- screenshot()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
}
}
-TEST_F(LayerTransactionTest, SetColorTransformOnChildAndParent) {
+TEST_P(LayerRenderTypeTransactionTest, SetColorTransformOnChildAndParent) {
sp<SurfaceControl> parentLayer;
sp<SurfaceControl> colorLayer;
ASSERT_NO_FATAL_FAILURE(parentLayer = createLayer("parent", 0 /* buffer width */,
@@ -2637,7 +2971,7 @@
.apply();
{
SCOPED_TRACE("default color");
- screenshot()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
}
const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
@@ -2677,7 +3011,7 @@
.apply();
{
SCOPED_TRACE("new color");
- screenshot()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
}
}
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 8201704..2c1833b 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -118,6 +118,7 @@
TestableSurfaceFlinger mFlinger;
mock::EventThread* mEventThread = new mock::EventThread();
+ mock::EventThread* mSFEventThread = new mock::EventThread();
mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
sp<mock::NativeWindow> mNativeWindow = new mock::NativeWindow();
sp<GraphicBuffer> mBuffer = new GraphicBuffer();
@@ -161,6 +162,7 @@
mFlinger.mutableEventControlThread().reset(mEventControlThread);
mFlinger.mutableEventThread().reset(mEventThread);
+ mFlinger.mutableSFEventThread().reset(mSFEventThread);
mFlinger.mutableEventQueue().reset(mMessageQueue);
mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
mFlinger.mutableInterceptor().reset(mSurfaceInterceptor);
@@ -319,6 +321,11 @@
// Whether the display is primary
static constexpr Primary PRIMARY = primary;
+ static constexpr auto displayType() {
+ return static_cast<bool>(PRIMARY) ? EventThread::DisplayType::Primary
+ : EventThread::DisplayType::External;
+ }
+
static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) {
auto injector =
FakeDisplayDeviceInjector(test->mFlinger, DISPLAY_ID::get(),
@@ -1404,23 +1411,17 @@
Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
- EXPECT_CALL(*mEventThread,
- onHotplugReceived(static_cast<bool>(Case::Display::PRIMARY)
- ? EventThread::DisplayType::Primary
- : EventThread::DisplayType::External,
- true))
- .Times(1);
+
+ EXPECT_CALL(*mEventThread, onHotplugReceived(Case::Display::displayType(), true)).Times(1);
+ EXPECT_CALL(*mSFEventThread, onHotplugReceived(Case::Display::displayType(), true)).Times(1);
}
template <typename Case>
void HandleTransactionLockedTest::setupCommonCallExpectationsForDisconnectProcessing() {
EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
- EXPECT_CALL(*mEventThread,
- onHotplugReceived(static_cast<bool>(Case::Display::PRIMARY)
- ? EventThread::DisplayType::Primary
- : EventThread::DisplayType::External,
- false))
- .Times(1);
+
+ EXPECT_CALL(*mEventThread, onHotplugReceived(Case::Display::displayType(), false)).Times(1);
+ EXPECT_CALL(*mSFEventThread, onHotplugReceived(Case::Display::displayType(), false)).Times(1);
}
template <typename Case>
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index c18068f..dd90063 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -83,6 +83,7 @@
ConnectionEventRecorder mConnectionEventCallRecorder{0};
MockVSyncSource mVSyncSource;
+ VSyncSource::Callback* mCallback = nullptr;
std::unique_ptr<android::impl::EventThread> mThread;
sp<MockEventThreadConnection> mConnection;
};
@@ -103,12 +104,19 @@
createThread();
mConnection = createConnection(mConnectionEventCallRecorder);
+
+ // A display must be connected for VSYNC events to be delivered.
+ mThread->onHotplugReceived(EventThread::DisplayType::Primary, true);
+ expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, true);
}
EventThreadTest::~EventThreadTest() {
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+
+ // EventThread should unregister itself as VSyncSource callback.
+ EXPECT_FALSE(expectVSyncSetCallbackCallReceived());
}
void EventThreadTest::createThread() {
@@ -116,6 +124,10 @@
std::make_unique<android::impl::EventThread>(&mVSyncSource,
mInterceptVSyncCallRecorder.getInvocable(),
"unit-test-event-thread");
+
+ // EventThread should register itself as VSyncSource callback.
+ mCallback = expectVSyncSetCallbackCallReceived();
+ ASSERT_TRUE(mCallback);
}
sp<EventThreadTest::MockEventThreadConnection> EventThreadTest::createConnection(
@@ -199,6 +211,17 @@
EXPECT_FALSE(mConnectionEventCallRecorder.waitForCall(0us).has_value());
}
+TEST_F(EventThreadTest, vsyncRequestIsIgnoredIfDisplayIsDisconnected) {
+ mThread->onHotplugReceived(EventThread::DisplayType::Primary, false);
+ expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, false);
+
+ // Signal that we want the next vsync event to be posted to the connection.
+ mThread->requestNextVsync(mConnection, false);
+
+ // EventThread should not enable vsync callbacks.
+ EXPECT_FALSE(mVSyncSetEnabledCallRecorder.waitForUnexpectedCall().has_value());
+}
+
TEST_F(EventThreadTest, requestNextVsyncPostsASingleVSyncEventToTheConnection) {
// Signal that we want the next vsync event to be posted to the connection
mThread->requestNextVsync(mConnection, false);
@@ -206,22 +229,19 @@
// EventThread should immediately request a resync.
EXPECT_TRUE(mResyncCallRecorder.waitForCall().has_value());
- // EventThread should enable vsync callbacks, and set a callback interface
- // pointer to use them with the VSync source.
+ // EventThread should enable vsync callbacks.
expectVSyncSetEnabledCallReceived(true);
- auto callback = expectVSyncSetCallbackCallReceived();
- ASSERT_TRUE(callback);
// Use the received callback to signal a first vsync event.
// The interceptor should receive the event, as well as the connection.
- callback->onVSyncEvent(123);
+ mCallback->onVSyncEvent(123);
expectInterceptCallReceived(123);
expectVsyncEventReceivedByConnection(123, 1u);
// Use the received callback to signal a second vsync event.
// The interceptor should receive the event, but the the connection should
// not as it was only interested in the first.
- callback->onVSyncEvent(456);
+ mCallback->onVSyncEvent(456);
expectInterceptCallReceived(456);
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
@@ -246,16 +266,13 @@
createConnection(secondConnectionEventRecorder);
mThread->setVsyncRate(1, secondConnection);
- // EventThread should enable vsync callbacks, and set a callback interface
- // pointer to use them with the VSync source.
+ // EventThread should enable vsync callbacks.
expectVSyncSetEnabledCallReceived(true);
- auto callback = expectVSyncSetCallbackCallReceived();
- ASSERT_TRUE(callback);
// Send a vsync event. EventThread should then make a call to the
// interceptor, and the second connection. The first connection should not
// get the event.
- callback->onVSyncEvent(123);
+ mCallback->onVSyncEvent(123);
expectInterceptCallReceived(123);
EXPECT_FALSE(firstConnectionEventRecorder.waitForUnexpectedCall().has_value());
expectVsyncEventReceivedByConnection("secondConnection", secondConnectionEventRecorder, 123,
@@ -265,25 +282,22 @@
TEST_F(EventThreadTest, setVsyncRateOnePostsAllEventsToThatConnection) {
mThread->setVsyncRate(1, mConnection);
- // EventThread should enable vsync callbacks, and set a callback interface
- // pointer to use them with the VSync source.
+ // EventThread should enable vsync callbacks.
expectVSyncSetEnabledCallReceived(true);
- auto callback = expectVSyncSetCallbackCallReceived();
- ASSERT_TRUE(callback);
// Send a vsync event. EventThread should then make a call to the
// interceptor, and the connection.
- callback->onVSyncEvent(123);
+ mCallback->onVSyncEvent(123);
expectInterceptCallReceived(123);
expectVsyncEventReceivedByConnection(123, 1u);
// A second event should go to the same places.
- callback->onVSyncEvent(456);
+ mCallback->onVSyncEvent(456);
expectInterceptCallReceived(456);
expectVsyncEventReceivedByConnection(456, 2u);
// A third event should go to the same places.
- callback->onVSyncEvent(789);
+ mCallback->onVSyncEvent(789);
expectInterceptCallReceived(789);
expectVsyncEventReceivedByConnection(789, 3u);
}
@@ -291,29 +305,26 @@
TEST_F(EventThreadTest, setVsyncRateTwoPostsEveryOtherEventToThatConnection) {
mThread->setVsyncRate(2, mConnection);
- // EventThread should enable vsync callbacks, and set a callback interface
- // pointer to use them with the VSync source.
+ // EventThread should enable vsync callbacks.
expectVSyncSetEnabledCallReceived(true);
- auto callback = expectVSyncSetCallbackCallReceived();
- ASSERT_TRUE(callback);
// The first event will be seen by the interceptor, and not the connection.
- callback->onVSyncEvent(123);
+ mCallback->onVSyncEvent(123);
expectInterceptCallReceived(123);
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
// The second event will be seen by the interceptor and the connection.
- callback->onVSyncEvent(456);
+ mCallback->onVSyncEvent(456);
expectInterceptCallReceived(456);
expectVsyncEventReceivedByConnection(456, 2u);
// The third event will be seen by the interceptor, and not the connection.
- callback->onVSyncEvent(789);
+ mCallback->onVSyncEvent(789);
expectInterceptCallReceived(789);
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
// The fourth event will be seen by the interceptor and the connection.
- callback->onVSyncEvent(101112);
+ mCallback->onVSyncEvent(101112);
expectInterceptCallReceived(101112);
expectVsyncEventReceivedByConnection(101112, 4u);
}
@@ -321,17 +332,14 @@
TEST_F(EventThreadTest, connectionsRemovedIfInstanceDestroyed) {
mThread->setVsyncRate(1, mConnection);
- // EventThread should enable vsync callbacks, and set a callback interface
- // pointer to use them with the VSync source.
+ // EventThread should enable vsync callbacks.
expectVSyncSetEnabledCallReceived(true);
- auto callback = expectVSyncSetCallbackCallReceived();
- ASSERT_TRUE(callback);
// Destroy the only (strong) reference to the connection.
mConnection = nullptr;
// The first event will be seen by the interceptor, and not the connection.
- callback->onVSyncEvent(123);
+ mCallback->onVSyncEvent(123);
expectInterceptCallReceived(123);
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
@@ -344,21 +352,18 @@
sp<MockEventThreadConnection> errorConnection = createConnection(errorConnectionEventRecorder);
mThread->setVsyncRate(1, errorConnection);
- // EventThread should enable vsync callbacks, and set a callback interface
- // pointer to use them with the VSync source.
+ // EventThread should enable vsync callbacks.
expectVSyncSetEnabledCallReceived(true);
- auto callback = expectVSyncSetCallbackCallReceived();
- ASSERT_TRUE(callback);
// The first event will be seen by the interceptor, and by the connection,
// which then returns an error.
- callback->onVSyncEvent(123);
+ mCallback->onVSyncEvent(123);
expectInterceptCallReceived(123);
expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
// A subsequent event will be seen by the interceptor and not by the
// connection.
- callback->onVSyncEvent(456);
+ mCallback->onVSyncEvent(456);
expectInterceptCallReceived(456);
EXPECT_FALSE(errorConnectionEventRecorder.waitForUnexpectedCall().has_value());
@@ -371,21 +376,18 @@
sp<MockEventThreadConnection> errorConnection = createConnection(errorConnectionEventRecorder);
mThread->setVsyncRate(1, errorConnection);
- // EventThread should enable vsync callbacks, and set a callback interface
- // pointer to use them with the VSync source.
+ // EventThread should enable vsync callbacks.
expectVSyncSetEnabledCallReceived(true);
- auto callback = expectVSyncSetCallbackCallReceived();
- ASSERT_TRUE(callback);
// The first event will be seen by the interceptor, and by the connection,
// which then returns an non-fatal error.
- callback->onVSyncEvent(123);
+ mCallback->onVSyncEvent(123);
expectInterceptCallReceived(123);
expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
// A subsequent event will be seen by the interceptor, and by the connection,
// which still then returns an non-fatal error.
- callback->onVSyncEvent(456);
+ mCallback->onVSyncEvent(456);
expectInterceptCallReceived(456);
expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 456, 2u);
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 3dd5143..4d9aec6 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -41,7 +41,7 @@
: Scheduler([](bool) {}), mEventThread(std::move(eventThread)) {}
std::unique_ptr<EventThread> makeEventThread(
- const std::string& /* connectionName */, DispSync* /* dispSync */,
+ const char* /* connectionName */, DispSync* /* dispSync */,
nsecs_t /* phaseOffsetNs */,
impl::EventThread::InterceptVSyncsCallback /* interceptCallback */) override {
return std::move(mEventThread);
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 2a8dda6..9c5c967 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -290,6 +290,7 @@
auto& mutableEventControlThread() { return mFlinger->mEventControlThread; }
auto& mutableEventQueue() { return mFlinger->mEventQueue; }
auto& mutableEventThread() { return mFlinger->mEventThread; }
+ auto& mutableSFEventThread() { return mFlinger->mSFEventThread; }
auto& mutableGeometryInvalid() { return mFlinger->mGeometryInvalid; }
auto& mutableHWVsyncAvailable() { return mFlinger->mHWVsyncAvailable; }
auto& mutableInterceptor() { return mFlinger->mInterceptor; }
@@ -317,6 +318,7 @@
mutableEventControlThread().reset();
mutableEventQueue().reset();
mutableEventThread().reset();
+ mutableSFEventThread().reset();
mutableInterceptor().reset();
mutablePrimaryDispSync().reset();
mFlinger->mCompositionEngine->setHwComposer(std::unique_ptr<HWComposer>());
diff --git a/services/vr/bufferhubd/include/private/dvr/producer_channel.h b/services/vr/bufferhubd/include/private/dvr/producer_channel.h
index 96ef1a2..45593ad 100644
--- a/services/vr/bufferhubd/include/private/dvr/producer_channel.h
+++ b/services/vr/bufferhubd/include/private/dvr/producer_channel.h
@@ -69,7 +69,7 @@
bool CheckParameters(uint32_t width, uint32_t height, uint32_t layer_count,
uint32_t format, uint64_t usage,
- size_t user_metadata_size);
+ size_t user_metadata_size) const;
private:
std::vector<ConsumerChannel*> consumer_channels_;
@@ -112,6 +112,10 @@
// This function is used for clean up for failures in CreateConsumer method.
void RemoveConsumerClientMask(uint32_t consumer_state_mask);
+ // Checks whether the buffer is released by all active clients, excluding
+ // orphaned consumers.
+ bool IsBufferReleasedByAllActiveClientsExceptForOrphans() const;
+
ProducerChannel(const ProducerChannel&) = delete;
void operator=(const ProducerChannel&) = delete;
};
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index 895dee0..164d9e6 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -333,7 +333,10 @@
uint32_t current_buffer_state =
buffer_state_->load(std::memory_order_acquire);
- if (BufferHubDefs::IsBufferReleased(current_buffer_state) ||
+ // Return the consumer channel handle without signal when adding the new
+ // consumer to a buffer that is available to producer (a.k.a a fully-released
+ // buffer) or a gained buffer.
+ if (current_buffer_state == 0U ||
BufferHubDefs::AnyClientGained(current_buffer_state)) {
return {status.take()};
}
@@ -356,7 +359,7 @@
". About to try again if the buffer is still not gained nor fully "
"released.",
__FUNCTION__, current_buffer_state, updated_buffer_state);
- if (BufferHubDefs::IsBufferReleased(current_buffer_state) ||
+ if (current_buffer_state == 0U ||
BufferHubDefs::AnyClientGained(current_buffer_state)) {
ALOGI("%s: buffer is gained or fully released, state=%" PRIx32 ".",
__FUNCTION__, current_buffer_state);
@@ -536,14 +539,7 @@
}
}
- uint32_t current_buffer_state =
- buffer_state_->load(std::memory_order_acquire);
- uint32_t current_active_clients_bit_mask =
- active_clients_bit_mask_->load(std::memory_order_acquire);
- // Signal producer if all current active consumers have released the buffer.
- if (BufferHubDefs::IsBufferReleased(current_buffer_state &
- ~orphaned_consumer_bit_mask_ &
- current_active_clients_bit_mask)) {
+ if (IsBufferReleasedByAllActiveClientsExceptForOrphans()) {
buffer_state_->store(0U);
SignalAvailable();
if (orphaned_consumer_bit_mask_) {
@@ -568,14 +564,7 @@
__FUNCTION__, consumer_state_mask);
orphaned_consumer_bit_mask_ |= consumer_state_mask;
- uint32_t current_buffer_state =
- buffer_state_->load(std::memory_order_acquire);
- uint32_t current_active_clients_bit_mask =
- active_clients_bit_mask_->load(std::memory_order_acquire);
- // Signal producer if all current active consumers have released the buffer.
- if (BufferHubDefs::IsBufferReleased(current_buffer_state &
- ~orphaned_consumer_bit_mask_ &
- current_active_clients_bit_mask)) {
+ if (IsBufferReleasedByAllActiveClientsExceptForOrphans()) {
buffer_state_->store(0U);
SignalAvailable();
}
@@ -667,12 +656,19 @@
bool ProducerChannel::CheckParameters(uint32_t width, uint32_t height,
uint32_t layer_count, uint32_t format,
uint64_t usage,
- size_t user_metadata_size) {
+ size_t user_metadata_size) const {
return user_metadata_size == user_metadata_size_ &&
buffer_.width() == width && buffer_.height() == height &&
buffer_.layer_count() == layer_count && buffer_.format() == format &&
buffer_.usage() == usage;
}
+bool ProducerChannel::IsBufferReleasedByAllActiveClientsExceptForOrphans()
+ const {
+ return (buffer_state_->load(std::memory_order_acquire) &
+ ~orphaned_consumer_bit_mask_ &
+ active_clients_bit_mask_->load(std::memory_order_acquire)) == 0U;
+}
+
} // namespace dvr
} // namespace android
diff --git a/vulkan/libvulkan/layers_extensions.h b/vulkan/libvulkan/layers_extensions.h
index 1dae456..9e2ff5b 100644
--- a/vulkan/libvulkan/layers_extensions.h
+++ b/vulkan/libvulkan/layers_extensions.h
@@ -33,6 +33,7 @@
LayerRef& operator=(const LayerRef&) = delete;
// provides bool-like behavior
+ // NOLINTNEXTLINE(google-explicit-constructor)
operator const Layer*() const { return layer_; }
PFN_vkGetInstanceProcAddr GetGetInstanceProcAddr() const;