Merge "Cleanup dumpsys for refresh configs for non-90hz devices."
diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
index 37ff442..347856d 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
@@ -61,7 +61,6 @@
// Default mode.
const int BUGREPORT_MODE_DEFAULT = 6;
- // TODO(b/111441001): Should the args be for the consuming application rather than triggering?
/*
* Starts a bugreport in the background.
*
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 738c20f..1fbd2b3 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1583,6 +1583,9 @@
RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
SEC_TO_MSEC(10));
+ RunDumpsys("DUMPSYS", {"connmetrics"}, CommandOptions::WithTimeout(90).Build(),
+ SEC_TO_MSEC(10));
+ RunDumpsys("DUMPSYS", {"netd"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10));
RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
SEC_TO_MSEC(10));
RunDumpsys("DUMPSYS", {"wifi"}, CommandOptions::WithTimeout(90).Build(),
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index b60bbc0..d66066e 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -146,9 +146,11 @@
],
shared_libs: [
"libbase",
+ "libbinder",
"liblog",
"libprotobuf-cpp-full",
"libselinux",
+ "libutils",
"libziparchive",
],
static_libs: [
@@ -157,6 +159,7 @@
"lib_apex_manifest_proto",
"libavb",
"libdm",
+ "libvold_binder",
],
}
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 2efcf11..c730ab9 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -171,7 +171,7 @@
}
binder::Status checkArgumentPackageName(const std::string& packageName) {
- if (is_valid_package_name(packageName.c_str())) {
+ if (is_valid_package_name(packageName)) {
return ok();
} else {
return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
@@ -1648,7 +1648,8 @@
ATRACE_BEGIN("obb");
for (const auto& packageName : packageNames) {
- auto obbCodePath = create_data_media_obb_path(uuid_, packageName.c_str());
+ auto obbCodePath = create_data_media_package_path(uuid_, userId,
+ "obb", packageName.c_str());
calculate_tree_size(obbCodePath, &extStats.codeSize);
}
ATRACE_END();
@@ -1982,7 +1983,8 @@
ATRACE_END();
ATRACE_BEGIN("obb");
- auto obbPath = create_data_media_obb_path(uuid_, "");
+ auto obbPath = StringPrintf("%s/Android/obb",
+ create_data_media_path(uuid_, userId).c_str());
calculate_tree_size(obbPath, &obbSize);
ATRACE_END();
}
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 72571cf..a5cc0df 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -58,6 +58,7 @@
using android::base::EndsWith;
using android::base::GetBoolProperty;
using android::base::GetProperty;
+using android::base::ReadFdToString;
using android::base::ReadFully;
using android::base::StringPrintf;
using android::base::WriteFully;
@@ -319,6 +320,7 @@
bool background_job_compile,
int profile_fd,
const char* class_loader_context,
+ const std::string& class_loader_context_fds,
int target_sdk_version,
bool enable_hidden_api_checks,
bool generate_compact_dex,
@@ -423,9 +425,14 @@
target_sdk_version_arg = StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version);
}
std::string class_loader_context_arg;
+ std::string class_loader_context_fds_arg;
if (class_loader_context != nullptr) {
class_loader_context_arg = StringPrintf("--class-loader-context=%s",
class_loader_context);
+ if (!class_loader_context_fds.empty()) {
+ class_loader_context_fds_arg = StringPrintf("--class-loader-context-fds=%s",
+ class_loader_context_fds.c_str());
+ }
}
if (swap_fd >= 0) {
@@ -518,6 +525,7 @@
AddArg(profile_arg);
AddArg(base_dir);
AddArg(class_loader_context_arg);
+ AddArg(class_loader_context_fds_arg);
if (generate_minidebug_info) {
AddArg(kMinidebugDex2oatFlag);
}
@@ -1514,14 +1522,15 @@
class RunDexoptAnalyzer : public ExecVHelper {
public:
RunDexoptAnalyzer(const std::string& dex_file,
- int vdex_fd,
- int oat_fd,
- int zip_fd,
- const std::string& instruction_set,
- const std::string& compiler_filter,
- bool profile_was_updated,
- bool downgrade,
- const char* class_loader_context) {
+ int vdex_fd,
+ int oat_fd,
+ int zip_fd,
+ const std::string& instruction_set,
+ const std::string& compiler_filter,
+ bool profile_was_updated,
+ bool downgrade,
+ const char* class_loader_context,
+ const std::string& class_loader_context_fds) {
CHECK_GE(zip_fd, 0);
// We always run the analyzer in the background job.
@@ -1540,6 +1549,10 @@
if (class_loader_context != nullptr) {
class_loader_context_arg += class_loader_context;
}
+ std::string class_loader_context_fds_arg = "--class-loader-context-fds=";
+ if (!class_loader_context_fds.empty()) {
+ class_loader_context_fds_arg += class_loader_context_fds;
+ }
// program name, dex file, isa, filter
AddArg(dex_file_arg);
@@ -1551,7 +1564,7 @@
if (vdex_fd >= 0) {
AddArg(vdex_fd_arg);
}
- AddArg(zip_fd_arg.c_str());
+ AddArg(zip_fd_arg);
if (profile_was_updated) {
AddArg(assume_profile_changed);
}
@@ -1559,11 +1572,28 @@
AddArg(downgrade_flag);
}
if (class_loader_context != nullptr) {
- AddArg(class_loader_context_arg.c_str());
+ AddArg(class_loader_context_arg);
+ if (!class_loader_context_fds.empty()) {
+ AddArg(class_loader_context_fds_arg);
+ }
}
PrepareArgs(dexoptanalyzer_bin);
}
+
+ // Dexoptanalyzer mode which flattens the given class loader context and
+ // prints a list of its dex files in that flattened order.
+ RunDexoptAnalyzer(const char* class_loader_context) {
+ CHECK(class_loader_context != nullptr);
+
+ // We always run the analyzer in the background job.
+ const char* dexoptanalyzer_bin = select_execution_binary(
+ kDexoptanalyzerPath, kDexoptanalyzerDebugPath, /*background_job_compile=*/ true);
+
+ AddArg("--flatten-class-loader-context");
+ AddArg(std::string("--class-loader-context=") + class_loader_context);
+ PrepareArgs(dexoptanalyzer_bin);
+ }
};
// Prepares the oat dir for the secondary dex files.
@@ -1743,6 +1773,95 @@
return true;
}
+static bool get_class_loader_context_dex_paths(const char* class_loader_context, int uid,
+ /* out */ std::vector<std::string>* context_dex_paths) {
+ if (class_loader_context == nullptr) {
+ return true;
+ }
+
+ LOG(DEBUG) << "Getting dex paths for context " << class_loader_context;
+
+ // Pipe to get the hash result back from our child process.
+ unique_fd pipe_read, pipe_write;
+ if (!Pipe(&pipe_read, &pipe_write)) {
+ PLOG(ERROR) << "Failed to create pipe";
+ return false;
+ }
+
+ pid_t pid = fork();
+ if (pid == 0) {
+ // child -- drop privileges before continuing.
+ drop_capabilities(uid);
+
+ // Route stdout to `pipe_write`
+ while ((dup2(pipe_write, STDOUT_FILENO) == -1) && (errno == EINTR)) {}
+ pipe_write.reset();
+ pipe_read.reset();
+
+ RunDexoptAnalyzer run_dexopt_analyzer(class_loader_context);
+ run_dexopt_analyzer.Exec(kSecondaryDexDexoptAnalyzerSkippedFailExec);
+ }
+
+ /* parent */
+ pipe_write.reset();
+
+ std::string str_dex_paths;
+ if (!ReadFdToString(pipe_read, &str_dex_paths)) {
+ PLOG(ERROR) << "Failed to read from pipe";
+ return false;
+ }
+ pipe_read.reset();
+
+ int return_code = wait_child(pid);
+ if (!WIFEXITED(return_code)) {
+ PLOG(ERROR) << "Error waiting for child dexoptanalyzer process";
+ return false;
+ }
+
+ constexpr int kFlattenClassLoaderContextSuccess = 50;
+ return_code = WEXITSTATUS(return_code);
+ if (return_code != kFlattenClassLoaderContextSuccess) {
+ LOG(ERROR) << "Dexoptanalyzer could not flatten class loader context, code=" << return_code;
+ return false;
+ }
+
+ if (!str_dex_paths.empty()) {
+ *context_dex_paths = android::base::Split(str_dex_paths, ":");
+ }
+ return true;
+}
+
+static int open_dex_paths(const std::vector<std::string>& dex_paths,
+ /* out */ std::vector<unique_fd>* zip_fds, /* out */ std::string* error_msg) {
+ for (const std::string& dex_path : dex_paths) {
+ zip_fds->emplace_back(open(dex_path.c_str(), O_RDONLY));
+ if (zip_fds->back().get() < 0) {
+ *error_msg = StringPrintf(
+ "installd cannot open '%s' for input during dexopt", dex_path.c_str());
+ if (errno == ENOENT) {
+ return kSecondaryDexDexoptAnalyzerSkippedNoFile;
+ } else {
+ return kSecondaryDexDexoptAnalyzerSkippedOpenZip;
+ }
+ }
+ }
+ return 0;
+}
+
+static std::string join_fds(const std::vector<unique_fd>& fds) {
+ std::stringstream ss;
+ bool is_first = true;
+ for (const unique_fd& fd : fds) {
+ if (is_first) {
+ is_first = false;
+ } else {
+ ss << ":";
+ }
+ ss << fd.get();
+ }
+ return ss.str();
+}
+
// Processes the dex_path as a secondary dex files and return true if the path dex file should
// be compiled. Returns false for errors (logged) or true if the secondary dex path was process
// successfully.
@@ -1754,7 +1873,7 @@
int dexopt_flags, const char* volume_uuid, int uid, const char* instruction_set,
const char* compiler_filter, bool* is_public_out, int* dexopt_needed_out,
std::string* oat_dir_out, bool downgrade, const char* class_loader_context,
- /* out */ std::string* error_msg) {
+ const std::vector<std::string>& context_dex_paths, /* out */ std::string* error_msg) {
LOG(DEBUG) << "Processing secondary dex path " << dex_path;
int storage_flag;
if (!validate_dexopt_storage_flags(dexopt_flags, &storage_flag, error_msg)) {
@@ -1794,6 +1913,13 @@
}
}
+ // Open class loader context dex files.
+ std::vector<unique_fd> context_zip_fds;
+ int open_dex_paths_rc = open_dex_paths(context_dex_paths, &context_zip_fds, error_msg);
+ if (open_dex_paths_rc != 0) {
+ _exit(open_dex_paths_rc);
+ }
+
// Prepare the oat directories.
if (!prepare_secondary_dex_oat_dir(dex_path, uid, instruction_set)) {
_exit(kSecondaryDexDexoptAnalyzerSkippedPrepareDir);
@@ -1825,7 +1951,8 @@
instruction_set,
compiler_filter, profile_was_updated,
downgrade,
- class_loader_context);
+ class_loader_context,
+ join_fds(context_zip_fds));
run_dexopt_analyzer.Exec(kSecondaryDexDexoptAnalyzerSkippedFailExec);
}
@@ -1913,10 +2040,16 @@
// Check if we're dealing with a secondary dex file and if we need to compile it.
std::string oat_dir_str;
+ std::vector<std::string> context_dex_paths;
if (is_secondary_dex) {
+ if (!get_class_loader_context_dex_paths(class_loader_context, uid, &context_dex_paths)) {
+ *error_msg = "Failed acquiring context dex paths";
+ return -1; // We had an error, logged in the process method.
+ }
+
if (process_secondary_dex_dexopt(dex_path, pkgname, dexopt_flags, volume_uuid, uid,
instruction_set, compiler_filter, &is_public, &dexopt_needed, &oat_dir_str,
- downgrade, class_loader_context, error_msg)) {
+ downgrade, class_loader_context, context_dex_paths, error_msg)) {
oat_dir = oat_dir_str.c_str();
if (dexopt_needed == NO_DEXOPT_NEEDED) {
return 0; // Nothing to do, report success.
@@ -1928,7 +2061,7 @@
return -1; // We had an error, logged in the process method.
}
} else {
- // Currently these flags are only use for secondary dex files.
+ // Currently these flags are only used for secondary dex files.
// Verify that they are not set for primary apks.
CHECK((dexopt_flags & DEXOPT_STORAGE_CE) == 0);
CHECK((dexopt_flags & DEXOPT_STORAGE_DE) == 0);
@@ -1942,6 +2075,13 @@
return -1;
}
+ // Open class loader context dex files.
+ std::vector<unique_fd> context_input_fds;
+ if (open_dex_paths(context_dex_paths, &context_input_fds, error_msg) != 0) {
+ LOG(ERROR) << *error_msg;
+ return -1;
+ }
+
// Create the output OAT file.
char out_oat_path[PKG_PATH_MAX];
Dex2oatFileWrapper out_oat_fd = open_oat_out_file(dex_path, oat_dir, is_public, uid,
@@ -2010,6 +2150,7 @@
background_job_compile,
reference_profile_fd.get(),
class_loader_context,
+ join_fds(context_input_fds),
target_sdk_version,
enable_hidden_api_checks,
generate_compact_dex,
@@ -2118,7 +2259,7 @@
drop_capabilities(uid);
const char* volume_uuid_cstr = volume_uuid == nullptr ? nullptr : volume_uuid->c_str();
- if (!validate_secondary_dex_path(pkgname.c_str(), dex_path.c_str(), volume_uuid_cstr,
+ if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid_cstr,
uid, storage_flag)) {
LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
_exit(kReconcileSecondaryDexValidationError);
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index 0fdc9d6..2e2cc18 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -25,6 +25,7 @@
#include <android-base/logging.h>
#include <android-base/macros.h>
#include <android-base/stringprintf.h>
+#include <libdm/dm.h>
#include <selinux/android.h>
#include <apexd.h>
@@ -77,6 +78,37 @@
}
}
+static void TryExtraMount(const char* name, const char* slot, const char* target) {
+ std::string partition_name = StringPrintf("%s%s", name, slot);
+
+ // See whether update_engine mounted a logical partition.
+ {
+ auto& dm = dm::DeviceMapper::Instance();
+ if (dm.GetState(partition_name) != dm::DmDeviceState::INVALID) {
+ std::string path;
+ if (dm.GetDmDevicePathByName(partition_name, &path)) {
+ int mount_result = mount(path.c_str(),
+ target,
+ "ext4",
+ MS_RDONLY,
+ /* data */ nullptr);
+ if (mount_result == 0) {
+ return;
+ }
+ }
+ }
+ }
+
+ // Fall back and attempt a direct mount.
+ std::string block_device = StringPrintf("/dev/block/by-name/%s", partition_name.c_str());
+ int mount_result = mount(block_device.c_str(),
+ target,
+ "ext4",
+ MS_RDONLY,
+ /* data */ nullptr);
+ UNUSED(mount_result);
+}
+
// Entry for otapreopt_chroot. Expected parameters are:
// [cmd] [status-fd] [target-slot] "dexopt" [dexopt-params]
// The file descriptor denoted by status-fd will be closed. The rest of the parameters will
@@ -137,29 +169,11 @@
LOG(ERROR) << "Target slot suffix not legal: " << arg[2];
exit(207);
}
- {
- std::string vendor_partition = StringPrintf("/dev/block/by-name/vendor%s",
- arg[2]);
- int vendor_result = mount(vendor_partition.c_str(),
- "/postinstall/vendor",
- "ext4",
- MS_RDONLY,
- /* data */ nullptr);
- UNUSED(vendor_result);
- }
+ TryExtraMount("vendor", arg[2], "/postinstall/vendor");
// Try to mount the product partition. update_engine doesn't do this for us, but we
// want it for product APKs. Same notes as vendor above.
- {
- std::string product_partition = StringPrintf("/dev/block/by-name/product%s",
- arg[2]);
- int product_result = mount(product_partition.c_str(),
- "/postinstall/product",
- "ext4",
- MS_RDONLY,
- /* data */ nullptr);
- UNUSED(product_result);
- }
+ TryExtraMount("product", arg[2], "/postinstall/product");
// Setup APEX mount point and its security context.
static constexpr const char* kPostinstallApexDir = "/postinstall/apex";
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 1ed49a0..aa79fdc 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -15,6 +15,7 @@
"libinstalld",
"liblog",
],
+ test_config: "installd_utils_test.xml",
}
cc_test {
@@ -39,6 +40,7 @@
"liblog",
"liblogwrap",
],
+ test_config: "installd_cache_test.xml",
}
cc_test {
@@ -63,6 +65,7 @@
"liblog",
"liblogwrap",
],
+ test_config: "installd_service_test.xml",
}
cc_test {
@@ -87,6 +90,7 @@
"liblog",
"liblogwrap",
],
+ test_config: "installd_dexopt_test.xml",
}
cc_test {
diff --git a/cmds/installd/tests/installd_cache_test.xml b/cmds/installd/tests/installd_cache_test.xml
new file mode 100644
index 0000000..97af514
--- /dev/null
+++ b/cmds/installd/tests/installd_cache_test.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- Note: this is derived from the autogenerated configuration. We require
+ root support. -->
+<configuration description="Runs installd_cache_test.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="installd_cache_test->/data/local/tmp/installd_cache_test" />
+ </target_preparer>
+
+ <!-- The test requires root for file access. -->
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="installd_cache_test" />
+ </test>
+</configuration>
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 71b710b..fa2b0d9 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -327,16 +327,21 @@
void CompileSecondaryDex(const std::string& path, int32_t dex_storage_flag,
bool should_binder_call_succeed, bool should_dex_be_compiled = true,
- /*out */ binder::Status* binder_result = nullptr, int32_t uid = -1) {
+ /*out */ binder::Status* binder_result = nullptr, int32_t uid = -1,
+ const char* class_loader_context = nullptr) {
if (uid == -1) {
uid = kTestAppUid;
}
+ if (class_loader_context == nullptr) {
+ class_loader_context = "&";
+ }
std::unique_ptr<std::string> package_name_ptr(new std::string(package_name_));
int32_t dexopt_needed = 0; // does not matter;
std::unique_ptr<std::string> out_path = nullptr; // does not matter
int32_t dex_flags = DEXOPT_SECONDARY_DEX | dex_storage_flag;
std::string compiler_filter = "speed-profile";
- std::unique_ptr<std::string> class_loader_context_ptr(new std::string("&"));
+ std::unique_ptr<std::string> class_loader_context_ptr(
+ new std::string(class_loader_context));
std::unique_ptr<std::string> se_info_ptr(new std::string(se_info_));
bool downgrade = false;
int32_t target_sdk_version = 0; // default
@@ -555,12 +560,26 @@
/*binder_ok*/ true, /*compile_ok*/ true);
}
+TEST_F(DexoptTest, DexoptSecondaryCeWithContext) {
+ LOG(INFO) << "DexoptSecondaryCeWithContext";
+ std::string class_loader_context = "PCL[" + secondary_dex_ce_ + "]";
+ CompileSecondaryDex(secondary_dex_ce_, DEXOPT_STORAGE_CE,
+ /*binder_ok*/ true, /*compile_ok*/ true, nullptr, -1, class_loader_context.c_str());
+}
+
TEST_F(DexoptTest, DexoptSecondaryDe) {
LOG(INFO) << "DexoptSecondaryDe";
CompileSecondaryDex(secondary_dex_de_, DEXOPT_STORAGE_DE,
/*binder_ok*/ true, /*compile_ok*/ true);
}
+TEST_F(DexoptTest, DexoptSecondaryDeWithContext) {
+ LOG(INFO) << "DexoptSecondaryDeWithContext";
+ std::string class_loader_context = "PCL[" + secondary_dex_de_ + "]";
+ CompileSecondaryDex(secondary_dex_de_, DEXOPT_STORAGE_DE,
+ /*binder_ok*/ true, /*compile_ok*/ true, nullptr, -1, class_loader_context.c_str());
+}
+
TEST_F(DexoptTest, DexoptSecondaryDoesNotExist) {
LOG(INFO) << "DexoptSecondaryDoesNotExist";
// If the file validates but does not exist we do not treat it as an error.
@@ -576,7 +595,7 @@
CompileSecondaryDex(secondary_dex_ce_, DEXOPT_STORAGE_DE,
/*binder_ok*/ false, /*compile_ok*/ false, &status);
EXPECT_STREQ(status.toString8().c_str(),
- "Status(-8): '-1: Dexoptanalyzer path validation failed'");
+ "Status(-8, EX_SERVICE_SPECIFIC): '-1: Dexoptanalyzer path validation failed'");
}
TEST_F(DexoptTest, DexoptSecondaryAppOwnershipValidationError) {
@@ -585,7 +604,7 @@
CompileSecondaryDex("/data/data/random.app/secondary.jar", DEXOPT_STORAGE_CE,
/*binder_ok*/ false, /*compile_ok*/ false, &status);
EXPECT_STREQ(status.toString8().c_str(),
- "Status(-8): '-1: Dexoptanalyzer path validation failed'");
+ "Status(-8, EX_SERVICE_SPECIFIC): '-1: Dexoptanalyzer path validation failed'");
}
TEST_F(DexoptTest, DexoptSecondaryAcessViaDifferentUidError) {
@@ -593,7 +612,8 @@
binder::Status status;
CompileSecondaryDex(secondary_dex_ce_, DEXOPT_STORAGE_CE,
/*binder_ok*/ false, /*compile_ok*/ false, &status, kSystemUid);
- EXPECT_STREQ(status.toString8().c_str(), "Status(-8): '-1: Dexoptanalyzer open zip failed'");
+ EXPECT_STREQ(status.toString8().c_str(),
+ "Status(-8, EX_SERVICE_SPECIFIC): '-1: Dexoptanalyzer open zip failed'");
}
TEST_F(DexoptTest, DexoptPrimaryPublic) {
@@ -615,7 +635,7 @@
DEX2OAT_FROM_SCRATCH,
&status);
EXPECT_STREQ(status.toString8().c_str(),
- "Status(-8): \'256: Dex2oat invocation for "
+ "Status(-8, EX_SERVICE_SPECIFIC): \'256: Dex2oat invocation for "
"/data/app/com.installd.test.dexopt/base.jar failed: unspecified dex2oat error'");
}
@@ -916,8 +936,7 @@
protected:
void TransitionToSystemServer() {
ASSERT_TRUE(DropCapabilities(kSystemUid, kSystemGid));
- int32_t res = selinux_android_setcontext(
- kSystemUid, true, se_info_.c_str(), "system_server");
+ int32_t res = selinux_android_setcon("u:r:system_server:s0");
ASSERT_EQ(0, res) << "Failed to setcon " << strerror(errno);
}
diff --git a/cmds/installd/tests/installd_dexopt_test.xml b/cmds/installd/tests/installd_dexopt_test.xml
new file mode 100644
index 0000000..24526cc
--- /dev/null
+++ b/cmds/installd/tests/installd_dexopt_test.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- Note: this is derived from the autogenerated configuration. We require
+ root support. -->
+<configuration description="Runs installd_dexopt_test.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="installd_dexopt_test->/data/local/tmp/installd_dexopt_test" />
+ </target_preparer>
+
+ <!-- The test runs as root to prepare the temporary directory, make selinux adjustments
+ and so on. -->
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="installd_dexopt_test" />
+ </test>
+</configuration>
diff --git a/cmds/installd/tests/installd_service_test.xml b/cmds/installd/tests/installd_service_test.xml
new file mode 100644
index 0000000..b838f4f
--- /dev/null
+++ b/cmds/installd/tests/installd_service_test.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- Note: this is derived from the autogenerated configuration. We require
+ root support. -->
+<configuration description="Runs installd_service_test.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="installd_service_test->/data/local/tmp/installd_service_test" />
+ </target_preparer>
+
+ <!-- The test requires root for file access. -->
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="installd_service_test" />
+ </test>
+</configuration>
diff --git a/cmds/installd/tests/installd_utils_test.xml b/cmds/installd/tests/installd_utils_test.xml
new file mode 100644
index 0000000..92aba50
--- /dev/null
+++ b/cmds/installd/tests/installd_utils_test.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- Note: this is derived from the autogenerated configuration. We require
+ root support. -->
+<configuration description="Runs installd_utils_test.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="installd_utils_test->/data/local/tmp/installd_utils_test" />
+ </target_preparer>
+
+ <!-- The test requires root for file access (rollback paths). -->
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="installd_utils_test" />
+ </test>
+</configuration>
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index da097db..4eb1df0 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -244,10 +244,6 @@
return StringPrintf("%s/media/%u", create_data_path(volume_uuid).c_str(), userid);
}
-std::string create_data_media_obb_path(const char* volume_uuid, const char* package_name) {
- return StringPrintf("%s/media/obb/%s", create_data_path(volume_uuid).c_str(), package_name);
-}
-
std::string create_data_media_package_path(const char* volume_uuid, userid_t userid,
const char* data_type, const char* package_name) {
return StringPrintf("%s/Android/%s/%s", create_data_media_path(volume_uuid, userid).c_str(),
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 955d524..6a42026 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -75,7 +75,6 @@
userid_t user, int32_t snapshot_id, const char* package_name);
std::string create_data_media_path(const char* volume_uuid, userid_t userid);
-std::string create_data_media_obb_path(const char* volume_uuid, const char* package_name);
std::string create_data_media_package_path(const char* volume_uuid, userid_t userid,
const char* data_type, const char* package_name);
diff --git a/cmds/servicemanager/binder.h b/cmds/servicemanager/binder.h
index 70be3b4..a9ccc74 100644
--- a/cmds/servicemanager/binder.h
+++ b/cmds/servicemanager/binder.h
@@ -4,10 +4,9 @@
#ifndef _BINDER_H_
#define _BINDER_H_
+#include <linux/android/binder.h>
#include <sys/ioctl.h>
-#include "binder_kernel.h"
-
struct binder_state;
struct binder_io
diff --git a/cmds/servicemanager/binder_kernel.h b/cmds/servicemanager/binder_kernel.h
deleted file mode 100644
index 19fd773..0000000
--- a/cmds/servicemanager/binder_kernel.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_BINDER_KERNEL_H
-#define ANDROID_BINDER_KERNEL_H
-
-#include <linux/android/binder.h>
-
-/**
- * This file exists because the uapi kernel headers in bionic are built
- * from upstream kernel headers only, and not all of the hwbinder kernel changes
- * have made it upstream yet. Therefore, the modifications to the
- * binder header are added locally in this file.
- */
-
-enum {
- FLAT_BINDER_FLAG_TXN_SECURITY_CTX = 0x1000,
-};
-
-#define BINDER_SET_CONTEXT_MGR_EXT _IOW('b', 13, struct flat_binder_object)
-
-struct binder_transaction_data_secctx {
- struct binder_transaction_data transaction_data;
- binder_uintptr_t secctx;
-};
-
-enum {
- BR_TRANSACTION_SEC_CTX = _IOR('r', 2,
- struct binder_transaction_data_secctx),
-};
-
-
-#endif // ANDROID_BINDER_KERNEL_H
diff --git a/data/etc/car_core_hardware.xml b/data/etc/car_core_hardware.xml
index 5c1cab6..ad7791e 100644
--- a/data/etc/car_core_hardware.xml
+++ b/data/etc/car_core_hardware.xml
@@ -46,12 +46,6 @@
<feature name="android.software.cant_save_state" />
<feature name="android.software.secure_lock_screen" />
- <!-- Feature to specify if the device supports adding device admins. -->
- <feature name="android.software.device_admin" />
-
- <!-- Feature to specify if the device support managed users. -->
- <feature name="android.software.managed_users" />
-
<!-- devices with GPS must include android.hardware.location.gps.xml -->
<!-- devices with an autofocus camera and/or flash must include either
android.hardware.camera.autofocus.xml or
diff --git a/include/input/IInputFlinger.h b/include/input/IInputFlinger.h
index cd12fcd..4365a3c 100644
--- a/include/input/IInputFlinger.h
+++ b/include/input/IInputFlinger.h
@@ -22,7 +22,6 @@
#include <binder/IInterface.h>
-#include <utils/Vector.h>
#include <input/InputWindow.h>
#include <input/ISetInputWindowsListener.h>
@@ -36,7 +35,7 @@
public:
DECLARE_META_INTERFACE(InputFlinger)
- virtual void setInputWindows(const Vector<InputWindowInfo>& inputHandles,
+ virtual void setInputWindows(const std::vector<InputWindowInfo>& inputHandles,
const sp<ISetInputWindowsListener>& setInputWindowsListener) = 0;
virtual void transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) = 0;
virtual void registerInputChannel(const sp<InputChannel>& channel) = 0;
diff --git a/include/input/InputApplication.h b/include/input/InputApplication.h
index 71a8f20..7f04611 100644
--- a/include/input/InputApplication.h
+++ b/include/input/InputApplication.h
@@ -50,19 +50,19 @@
class InputApplicationHandle : public RefBase {
public:
inline const InputApplicationInfo* getInfo() const {
- return mInfo;
+ return &mInfo;
}
inline std::string getName() const {
- return mInfo ? mInfo->name : "<invalid>";
+ return !mInfo.name.empty() ? mInfo.name : "<invalid>";
}
inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {
- return mInfo ? mInfo->dispatchingTimeout : defaultValue;
+ return mInfo.token ? mInfo.dispatchingTimeout : defaultValue;
}
inline sp<IBinder> getApplicationToken() const {
- return mInfo ? mInfo->token : nullptr;
+ return mInfo.token;
}
/**
@@ -75,18 +75,11 @@
* Returns true on success, or false if the handle is no longer valid.
*/
virtual bool updateInfo() = 0;
-
- /**
- * Releases the storage used by the associated information when it is
- * no longer needed.
- */
- void releaseInfo();
-
protected:
InputApplicationHandle();
virtual ~InputApplicationHandle();
- InputApplicationInfo* mInfo;
+ InputApplicationInfo mInfo;
};
} // namespace android
diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h
index 48ac88d..b6efc82 100644
--- a/include/input/InputDevice.h
+++ b/include/input/InputDevice.h
@@ -19,6 +19,7 @@
#include <input/Input.h>
#include <input/KeyCharacterMap.h>
+#include <vector>
namespace android {
@@ -121,7 +122,7 @@
inline void setButtonUnderPad(bool hasButton) { mHasButtonUnderPad = hasButton; }
inline bool hasButtonUnderPad() const { return mHasButtonUnderPad; }
- inline const Vector<MotionRange>& getMotionRanges() const {
+ inline const std::vector<MotionRange>& getMotionRanges() const {
return mMotionRanges;
}
@@ -139,7 +140,7 @@
bool mHasVibrator;
bool mHasButtonUnderPad;
- Vector<MotionRange> mMotionRanges;
+ std::vector<MotionRange> mMotionRanges;
};
/* Types of input device configuration files. */
diff --git a/include/input/KeyLayoutMap.h b/include/input/KeyLayoutMap.h
index 73815fe..26f3501 100644
--- a/include/input/KeyLayoutMap.h
+++ b/include/input/KeyLayoutMap.h
@@ -66,7 +66,7 @@
status_t mapKey(int32_t scanCode, int32_t usageCode,
int32_t* outKeyCode, uint32_t* outFlags) const;
- status_t findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const;
+ status_t findScanCodesForKey(int32_t keyCode, std::vector<int32_t>* outScanCodes) const;
status_t findScanCodeForLed(int32_t ledCode, int32_t* outScanCode) const;
status_t findUsageCodeForLed(int32_t ledCode, int32_t* outUsageCode) const;
diff --git a/include/input/VirtualKeyMap.h b/include/input/VirtualKeyMap.h
index 4f7cfb6..6e8e2c9 100644
--- a/include/input/VirtualKeyMap.h
+++ b/include/input/VirtualKeyMap.h
@@ -24,6 +24,7 @@
#include <utils/KeyedVector.h>
#include <utils/Tokenizer.h>
#include <utils/Unicode.h>
+#include <vector>
namespace android {
@@ -51,7 +52,7 @@
static std::unique_ptr<VirtualKeyMap> load(const std::string& filename);
- inline const Vector<VirtualKeyDefinition>& getVirtualKeys() const {
+ inline const std::vector<VirtualKeyDefinition>& getVirtualKeys() const {
return mVirtualKeys;
}
@@ -70,7 +71,7 @@
bool parseNextIntField(int32_t* outValue);
};
- Vector<VirtualKeyDefinition> mVirtualKeys;
+ std::vector<VirtualKeyDefinition> mVirtualKeys;
VirtualKeyMap();
};
diff --git a/libs/android_runtime_lazy/Android.bp b/libs/android_runtime_lazy/Android.bp
new file mode 100644
index 0000000..b200314
--- /dev/null
+++ b/libs/android_runtime_lazy/Android.bp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// libandroid_runtime_lazy is a shim library.
+// This provides very limited small set of APIs from libandroid_runtime.
+//
+// By depending on this instead of libandroid_runtime,
+// a library can be loaded without paying the cost of libandroid_runtime
+// which is quite huge. The cost will be paid when libandroid_runtime is actually used.
+//
+// For Partial-source PDK build, there is a constraint that
+// frameworks/native modules should not depend on frameworks/base.
+// This library can be used to cut down the dependency between them.
+// (e.g. libbinder_ndk)
+//
+// Some libraries which serve as LL-NDK and NDK as well may depend on this
+// instead of libandroid_runtime. When they are used by a vendor process,
+// depending on libandroid_runtime is meaningless. In this case,
+// they can depend on libandroid_runtime_lazy.
+cc_library {
+ name: "libandroid_runtime_lazy",
+ vendor_available: true,
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+
+ srcs: [
+ "android_runtime_lazy.cpp",
+ ],
+
+ shared_libs: [
+ "liblog",
+ "libutils",
+ ],
+
+ required: [
+ "libandroid_runtime",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
+ header_libs: [
+ "jni_headers",
+ "libbinder_headers",
+ ],
+}
diff --git a/libs/android_runtime_lazy/android_runtime_lazy.cpp b/libs/android_runtime_lazy/android_runtime_lazy.cpp
new file mode 100644
index 0000000..98d8e8a
--- /dev/null
+++ b/libs/android_runtime_lazy/android_runtime_lazy.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "ANDROID_RUNTIME_LAZY"
+#include "android_runtime/AndroidRuntime.h"
+#include "android_util_Binder.h"
+
+#include <dlfcn.h>
+#include <mutex>
+
+#include <log/log.h>
+
+namespace android {
+namespace {
+
+std::once_flag loadFlag;
+
+typedef JNIEnv* (*getJNIEnv_t)();
+typedef sp<IBinder> (*ibinderForJavaObject_t)(JNIEnv* env, jobject obj);
+typedef jobject (*javaObjectForIBinder_t)(JNIEnv* env, const sp<IBinder>& val);
+
+getJNIEnv_t _getJNIEnv;
+ibinderForJavaObject_t _ibinderForJavaObject;
+javaObjectForIBinder_t _javaObjectForIBinder;
+
+void load() {
+ std::call_once(loadFlag, []() {
+ void* handle = dlopen("libandroid_runtime.so", RTLD_LAZY);
+ if (handle == nullptr) {
+ ALOGE("Could not open libandroid_runtime.");
+ return;
+ }
+
+ _getJNIEnv = reinterpret_cast<getJNIEnv_t>(
+ dlsym(handle, "_ZN7android14AndroidRuntime9getJNIEnvEv"));
+ if (_getJNIEnv == nullptr) {
+ ALOGW("Could not find getJNIEnv.");
+ // no return
+ }
+
+ _ibinderForJavaObject = reinterpret_cast<ibinderForJavaObject_t>(
+ dlsym(handle, "_ZN7android20ibinderForJavaObjectEP7_JNIEnvP8_jobject"));
+ if (_ibinderForJavaObject == nullptr) {
+ ALOGW("Could not find ibinderForJavaObject.");
+ // no return
+ }
+
+ _javaObjectForIBinder = reinterpret_cast<javaObjectForIBinder_t>(
+ dlsym(handle,
+ "_ZN7android20javaObjectForIBinderEP7_JNIEnvRKNS_2spINS_7IBinderEEE"));
+ if (_javaObjectForIBinder == nullptr) {
+ ALOGW("Could not find javaObjectForIBinder.");
+ // no return
+ }
+ });
+}
+
+} // namespace
+
+// exports delegate functions
+
+JNIEnv* AndroidRuntime::getJNIEnv() {
+ load();
+ if (_getJNIEnv == nullptr) {
+ return nullptr;
+ }
+ return _getJNIEnv();
+}
+
+sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj) {
+ load();
+ if (_ibinderForJavaObject == nullptr) {
+ return nullptr;
+ }
+ return _ibinderForJavaObject(env, obj);
+}
+
+jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val) {
+ load();
+ if (_javaObjectForIBinder == nullptr) {
+ return nullptr;
+ }
+ return _javaObjectForIBinder(env, val);
+}
+
+} // namespace android
diff --git a/libs/android_runtime_lazy/include/android_runtime/AndroidRuntime.h b/libs/android_runtime_lazy/include/android_runtime/AndroidRuntime.h
new file mode 100644
index 0000000..85231fa
--- /dev/null
+++ b/libs/android_runtime_lazy/include/android_runtime/AndroidRuntime.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "jni.h"
+
+namespace android {
+
+// Intentionally use the same name with AndroidRuntime in frameworks/base/core/jni/
+// to make the client use this in the same way with the original class.
+class AndroidRuntime {
+public:
+ static JNIEnv* getJNIEnv();
+};
+
+} // namespace android
diff --git a/libs/android_runtime_lazy/include/android_util_Binder.h b/libs/android_runtime_lazy/include/android_util_Binder.h
new file mode 100644
index 0000000..e47390e
--- /dev/null
+++ b/libs/android_runtime_lazy/include/android_util_Binder.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/IBinder.h>
+#include "jni.h"
+
+namespace android {
+
+// The name of this file is same with the file in frameworks/base/core/jni/
+// This is intentional to make the client use these exported functions
+// in the same way with the original.
+
+jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val);
+sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj);
+
+} // namespace android
diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp
index a3f8755..8b33a56 100644
--- a/libs/binder/Status.cpp
+++ b/libs/binder/Status.cpp
@@ -63,6 +63,26 @@
return ret;
}
+std::string Status::exceptionToString(int32_t exceptionCode) {
+ switch (exceptionCode) {
+ #define EXCEPTION_TO_CASE(EXCEPTION) case EXCEPTION: return #EXCEPTION;
+ EXCEPTION_TO_CASE(EX_NONE)
+ EXCEPTION_TO_CASE(EX_SECURITY)
+ EXCEPTION_TO_CASE(EX_BAD_PARCELABLE)
+ EXCEPTION_TO_CASE(EX_ILLEGAL_ARGUMENT)
+ EXCEPTION_TO_CASE(EX_NULL_POINTER)
+ EXCEPTION_TO_CASE(EX_ILLEGAL_STATE)
+ EXCEPTION_TO_CASE(EX_NETWORK_MAIN_THREAD)
+ EXCEPTION_TO_CASE(EX_UNSUPPORTED_OPERATION)
+ EXCEPTION_TO_CASE(EX_SERVICE_SPECIFIC)
+ EXCEPTION_TO_CASE(EX_PARCELABLE)
+ EXCEPTION_TO_CASE(EX_HAS_REPLY_HEADER)
+ EXCEPTION_TO_CASE(EX_TRANSACTION_FAILED)
+ #undef EXCEPTION_TO_CASE
+ default: return std::to_string(exceptionCode);
+ }
+}
+
Status::Status(int32_t exceptionCode, int32_t errorCode)
: mException(exceptionCode),
mErrorCode(errorCode) {}
@@ -184,7 +204,7 @@
if (mException == EX_NONE) {
ret.append("No error");
} else {
- ret.appendFormat("Status(%d): '", mException);
+ ret.appendFormat("Status(%d, %s): '", mException, exceptionToString(mException).c_str());
if (mException == EX_SERVICE_SPECIFIC ||
mException == EX_TRANSACTION_FAILED) {
ret.appendFormat("%d: ", mErrorCode);
diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
index 1674516..aa44285 100644
--- a/libs/binder/include/binder/IBinder.h
+++ b/libs/binder/include/binder/IBinder.h
@@ -143,6 +143,9 @@
* dies. The @a cookie is optional. If non-NULL, you can
* supply a NULL @a recipient, and the recipient previously
* added with that cookie will be unlinked.
+ *
+ * If the binder is dead, this will return DEAD_OBJECT. Deleting
+ * the object will also unlink all death recipients.
*/
// NOLINTNEXTLINE(google-default-arguments)
virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index afdfe4f..e5219a5 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -20,6 +20,8 @@
#include <string>
#include <vector>
+#include <linux/android/binder.h>
+
#include <android-base/unique_fd.h>
#include <cutils/native_handle.h>
#include <utils/Errors.h>
@@ -28,7 +30,6 @@
#include <utils/Vector.h>
#include <utils/Flattenable.h>
-#include <binder/binder_kernel.h>
#include <binder/IInterface.h>
#include <binder/Parcelable.h>
#include <binder/Map.h>
diff --git a/libs/binder/include/binder/Status.h b/libs/binder/include/binder/Status.h
index c3738f8..7d889b6 100644
--- a/libs/binder/include/binder/Status.h
+++ b/libs/binder/include/binder/Status.h
@@ -22,6 +22,7 @@
#include <binder/Parcel.h>
#include <utils/String8.h>
+#include <string>
namespace android {
namespace binder {
@@ -97,6 +98,8 @@
static Status fromStatusT(status_t status);
+ static std::string exceptionToString(status_t exceptionCode);
+
Status() = default;
~Status() = default;
diff --git a/libs/binder/include/binder/binder_kernel.h b/libs/binder/include/binder/binder_kernel.h
deleted file mode 100644
index c7f6b4b..0000000
--- a/libs/binder/include/binder/binder_kernel.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#ifndef ANDROID_BINDER_KERNEL_H
-#define ANDROID_BINDER_KERNEL_H
-
-#include <linux/android/binder.h>
-
-/**
- * This file exists because the uapi kernel headers in bionic are built
- * from upstream kernel headers only, and not all of the hwbinder kernel changes
- * have made it upstream yet. Therefore, the modifications to the
- * binder header are added locally in this file.
- */
-
-enum {
- FLAT_BINDER_FLAG_TXN_SECURITY_CTX = 0x1000,
-};
-
-#define BINDER_SET_CONTEXT_MGR_EXT _IOW('b', 13, struct flat_binder_object)
-
-struct binder_transaction_data_secctx {
- struct binder_transaction_data transaction_data;
- binder_uintptr_t secctx;
-};
-
-enum {
- BR_TRANSACTION_SEC_CTX = _IOR('r', 2,
- struct binder_transaction_data_secctx),
-};
-
-#endif // ANDROID_BINDER_KERNEL_H
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index a96c9a0..21bef2e 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -39,17 +39,12 @@
],
shared_libs: [
+ "libandroid_runtime_lazy",
"libbase",
"libbinder",
"libutils",
],
- required: [
- // libbinder_ndk may be used by Java and non-Java things. When lower-level things use it,
- // they shouldn't have to take on the cost of loading libandroid_runtime.
- "libandroid_runtime",
- ],
-
header_libs: [
"jni_headers",
],
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index bdbc0d3..bd6886d 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -269,6 +269,18 @@
CHECK(who == mWho);
mOnDied(mCookie);
+
+ sp<AIBinder_DeathRecipient> recipient = mParentRecipient.promote();
+ sp<IBinder> strongWho = who.promote();
+
+ // otherwise this will be cleaned up later with pruneDeadTransferEntriesLocked
+ if (recipient != nullptr && strongWho != nullptr) {
+ status_t result = recipient->unlinkToDeath(strongWho, mCookie);
+ if (result != ::android::DEAD_OBJECT) {
+ LOG(WARNING) << "Unlinking to dead binder resulted in: " << result;
+ }
+ }
+
mWho = nullptr;
}
@@ -277,24 +289,34 @@
CHECK(onDied != nullptr);
}
-binder_status_t AIBinder_DeathRecipient::linkToDeath(AIBinder* binder, void* cookie) {
+void AIBinder_DeathRecipient::pruneDeadTransferEntriesLocked() {
+ mDeathRecipients.erase(std::remove_if(mDeathRecipients.begin(), mDeathRecipients.end(),
+ [](const sp<TransferDeathRecipient>& tdr) {
+ return tdr->getWho() == nullptr;
+ }),
+ mDeathRecipients.end());
+}
+
+binder_status_t AIBinder_DeathRecipient::linkToDeath(sp<IBinder> binder, void* cookie) {
CHECK(binder != nullptr);
std::lock_guard<std::mutex> l(mDeathRecipientsMutex);
sp<TransferDeathRecipient> recipient =
- new TransferDeathRecipient(binder->getBinder(), cookie, mOnDied);
+ new TransferDeathRecipient(binder, cookie, this, mOnDied);
- status_t status = binder->getBinder()->linkToDeath(recipient, cookie, 0 /*flags*/);
+ status_t status = binder->linkToDeath(recipient, cookie, 0 /*flags*/);
if (status != STATUS_OK) {
return PruneStatusT(status);
}
mDeathRecipients.push_back(recipient);
+
+ pruneDeadTransferEntriesLocked();
return STATUS_OK;
}
-binder_status_t AIBinder_DeathRecipient::unlinkToDeath(AIBinder* binder, void* cookie) {
+binder_status_t AIBinder_DeathRecipient::unlinkToDeath(sp<IBinder> binder, void* cookie) {
CHECK(binder != nullptr);
std::lock_guard<std::mutex> l(mDeathRecipientsMutex);
@@ -302,10 +324,10 @@
for (auto it = mDeathRecipients.rbegin(); it != mDeathRecipients.rend(); ++it) {
sp<TransferDeathRecipient> recipient = *it;
- if (recipient->getCookie() == cookie && recipient->getWho() == binder->getBinder()) {
+ if (recipient->getCookie() == cookie && recipient->getWho() == binder) {
mDeathRecipients.erase(it.base() - 1);
- status_t status = binder->getBinder()->unlinkToDeath(recipient, cookie, 0 /*flags*/);
+ status_t status = binder->unlinkToDeath(recipient, cookie, 0 /*flags*/);
if (status != ::android::OK) {
LOG(ERROR) << __func__
<< ": removed reference to death recipient but unlink failed.";
@@ -390,7 +412,7 @@
}
// returns binder_status_t
- return recipient->linkToDeath(binder, cookie);
+ return recipient->linkToDeath(binder->getBinder(), cookie);
}
binder_status_t AIBinder_unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
@@ -401,7 +423,7 @@
}
// returns binder_status_t
- return recipient->unlinkToDeath(binder, cookie);
+ return recipient->unlinkToDeath(binder->getBinder(), cookie);
}
uid_t AIBinder_getCallingUid() {
@@ -555,9 +577,15 @@
LOG(ERROR) << __func__ << ": requires non-null onBinderDied parameter.";
return nullptr;
}
- return new AIBinder_DeathRecipient(onBinderDied);
+ auto ret = new AIBinder_DeathRecipient(onBinderDied);
+ ret->incStrong(nullptr);
+ return ret;
}
void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient* recipient) {
- delete recipient;
+ if (recipient == nullptr) {
+ return;
+ }
+
+ recipient->decStrong(nullptr);
}
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index 202d6d2..5cb68c2 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -128,13 +128,14 @@
//
// When the AIBinder_DeathRecipient is dropped, so are the actual underlying death recipients. When
// the IBinder dies, only a wp to it is kept.
-struct AIBinder_DeathRecipient {
+struct AIBinder_DeathRecipient : ::android::RefBase {
// One of these is created for every linkToDeath. This is to be able to recover data when a
// binderDied receipt only gives us information about the IBinder.
struct TransferDeathRecipient : ::android::IBinder::DeathRecipient {
TransferDeathRecipient(const ::android::wp<::android::IBinder>& who, void* cookie,
+ const ::android::wp<AIBinder_DeathRecipient>& parentRecipient,
const AIBinder_DeathRecipient_onBinderDied onDied)
- : mWho(who), mCookie(cookie), mOnDied(onDied) {}
+ : mWho(who), mCookie(cookie), mParentRecipient(parentRecipient), mOnDied(onDied) {}
void binderDied(const ::android::wp<::android::IBinder>& who) override;
@@ -144,14 +145,24 @@
private:
::android::wp<::android::IBinder> mWho;
void* mCookie;
+
+ ::android::wp<AIBinder_DeathRecipient> mParentRecipient;
+
+ // This is kept separately from AIBinder_DeathRecipient in case the death recipient is
+ // deleted while the death notification is fired
const AIBinder_DeathRecipient_onBinderDied mOnDied;
};
explicit AIBinder_DeathRecipient(AIBinder_DeathRecipient_onBinderDied onDied);
- binder_status_t linkToDeath(AIBinder* binder, void* cookie);
- binder_status_t unlinkToDeath(AIBinder* binder, void* cookie);
+ binder_status_t linkToDeath(::android::sp<::android::IBinder>, void* cookie);
+ binder_status_t unlinkToDeath(::android::sp<::android::IBinder> binder, void* cookie);
private:
+ // When the user of this API deletes a Bp object but not the death recipient, the
+ // TransferDeathRecipient object can't be cleaned up. This is called whenever a new
+ // TransferDeathRecipient is linked, and it ensures that mDeathRecipients can't grow unbounded.
+ void pruneDeadTransferEntriesLocked();
+
std::mutex mDeathRecipientsMutex;
std::vector<::android::sp<TransferDeathRecipient>> mDeathRecipients;
AIBinder_DeathRecipient_onBinderDied mOnDied;
diff --git a/libs/binder/ndk/ibinder_jni.cpp b/libs/binder/ndk/ibinder_jni.cpp
index 4a31080..d931785 100644
--- a/libs/binder/ndk/ibinder_jni.cpp
+++ b/libs/binder/ndk/ibinder_jni.cpp
@@ -17,69 +17,19 @@
#include <android/binder_ibinder_jni.h>
#include "ibinder_internal.h"
-#include <android-base/logging.h>
-#include <binder/IBinder.h>
-
-#include <mutex>
-
-#include <dlfcn.h>
+#include <android_util_Binder.h>
using ::android::IBinder;
+using ::android::ibinderForJavaObject;
+using ::android::javaObjectForIBinder;
using ::android::sp;
-struct LazyAndroidRuntime {
- typedef sp<IBinder> (*FromJava)(JNIEnv* env, jobject obj);
- typedef jobject (*ToJava)(JNIEnv* env, const sp<IBinder>& val);
-
- static FromJava ibinderForJavaObject;
- static ToJava javaObjectForIBinder;
-
- static void load() {
- std::call_once(mLoadFlag, []() {
- void* handle = dlopen("libandroid_runtime.so", RTLD_LAZY);
- if (handle == nullptr) {
- LOG(WARNING) << "Could not open libandroid_runtime.";
- return;
- }
-
- ibinderForJavaObject = reinterpret_cast<FromJava>(
- dlsym(handle, "_ZN7android20ibinderForJavaObjectEP7_JNIEnvP8_jobject"));
- if (ibinderForJavaObject == nullptr) {
- LOG(WARNING) << "Could not find ibinderForJavaObject.";
- // no return
- }
-
- javaObjectForIBinder = reinterpret_cast<ToJava>(dlsym(
- handle, "_ZN7android20javaObjectForIBinderEP7_JNIEnvRKNS_2spINS_7IBinderEEE"));
- if (javaObjectForIBinder == nullptr) {
- LOG(WARNING) << "Could not find javaObjectForIBinder.";
- // no return
- }
- });
- }
-
- private:
- static std::once_flag mLoadFlag;
-
- LazyAndroidRuntime(){};
-};
-
-LazyAndroidRuntime::FromJava LazyAndroidRuntime::ibinderForJavaObject = nullptr;
-LazyAndroidRuntime::ToJava LazyAndroidRuntime::javaObjectForIBinder = nullptr;
-std::once_flag LazyAndroidRuntime::mLoadFlag;
-
AIBinder* AIBinder_fromJavaBinder(JNIEnv* env, jobject binder) {
if (binder == nullptr) {
return nullptr;
}
- LazyAndroidRuntime::load();
- if (LazyAndroidRuntime::ibinderForJavaObject == nullptr) {
- return nullptr;
- }
-
- sp<IBinder> ibinder = (LazyAndroidRuntime::ibinderForJavaObject)(env, binder);
-
+ sp<IBinder> ibinder = ibinderForJavaObject(env, binder);
sp<AIBinder> cbinder = ABpBinder::lookupOrCreateFromBinder(ibinder);
AIBinder_incStrong(cbinder.get());
@@ -91,10 +41,5 @@
return nullptr;
}
- LazyAndroidRuntime::load();
- if (LazyAndroidRuntime::javaObjectForIBinder == nullptr) {
- return nullptr;
- }
-
- return (LazyAndroidRuntime::javaObjectForIBinder)(env, binder->getBinder());
+ return javaObjectForIBinder(env, binder->getBinder());
}
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index bddc10d..80d1254 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -301,6 +301,11 @@
* may return a binder transaction failure and in case the death recipient cannot be found, it
* returns STATUS_NAME_NOT_FOUND.
*
+ * This only ever needs to be called when the AIBinder_DeathRecipient remains for use with other
+ * AIBinder objects. If the death recipient is deleted, all binders will automatically be unlinked.
+ * If the binder dies, it will automatically unlink. If the binder is deleted, it will be
+ * automatically unlinked.
+ *
* \param binder the binder object to remove a previously linked death recipient from.
* \param recipient the callback to remove.
* \param cookie the cookie used to link to death.
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp
index b29b6e7..8cd4e03 100644
--- a/libs/binder/ndk/test/Android.bp
+++ b/libs/binder/ndk/test/Android.bp
@@ -41,7 +41,7 @@
name: "test_libbinder_ndk_test_defaults",
defaults: ["test_libbinder_ndk_defaults"],
shared_libs: [
- "libandroid_runtime",
+ "libandroid_runtime_lazy",
"libbase",
"libbinder",
"libutils",
diff --git a/libs/binder/ndk/test/main_client.cpp b/libs/binder/ndk/test/main_client.cpp
index bff601e..8467734 100644
--- a/libs/binder/ndk/test/main_client.cpp
+++ b/libs/binder/ndk/test/main_client.cpp
@@ -86,12 +86,15 @@
// the binder driver should return this if the service dies during the transaction
EXPECT_EQ(STATUS_DEAD_OBJECT, foo->die());
+ foo = nullptr;
+ AIBinder_decStrong(binder);
+ binder = nullptr;
+
std::unique_lock<std::mutex> lock(deathMutex);
EXPECT_TRUE(deathCv.wait_for(lock, 1s, [&] { return deathRecieved; }));
EXPECT_TRUE(deathRecieved);
AIBinder_DeathRecipient_delete(recipient);
- AIBinder_decStrong(binder);
}
TEST(NdkBinder, RetrieveNonNdkService) {
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 0510492..4c2e653 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -31,44 +31,7 @@
"-Werror",
],
cppflags: [
- "-Weverything",
-
- // The static constructors and destructors in this library have not been noted to
- // introduce significant overheads
- "-Wno-exit-time-destructors",
- "-Wno-global-constructors",
-
- // We only care about compiling as C++14
- "-Wno-c++98-compat-pedantic",
-
- // We don't need to enumerate every case in a switch as long as a default case
- // is present
- "-Wno-switch-enum",
-
- // Allow calling variadic macros without a __VA_ARGS__ list
- "-Wno-gnu-zero-variadic-macro-arguments",
-
- // Don't warn about struct padding
- "-Wno-padded",
-
- // We are aware of the risks inherent in comparing floats for equality
- "-Wno-float-equal",
-
- // Pure abstract classes trigger this warning
- "-Wno-weak-vtables",
-
- // Allow four-character integer literals
- "-Wno-four-char-constants",
-
- // Allow documentation warnings
- "-Wno-documentation",
-
- // Allow implicit instantiation for templated class function
- "-Wno-undefined-func-template",
-
- // Allow explicitly marking struct as packed even when unnecessary
- "-Wno-packed",
-
+ "-Wextra",
"-DDEBUG_ONLY_CODE=0",
],
@@ -91,6 +54,7 @@
"BufferQueueConsumer.cpp",
"BufferQueueCore.cpp",
"BufferQueueProducer.cpp",
+ "BufferQueueThreadState.cpp",
"BufferSlot.cpp",
"ConsumerBase.cpp",
"CpuConsumer.cpp",
@@ -120,35 +84,48 @@
"view/Surface.cpp",
"bufferqueue/1.0/B2HProducerListener.cpp",
"bufferqueue/1.0/H2BGraphicBufferProducer.cpp",
+ "bufferqueue/1.0/H2BProducerListener.cpp",
+ "bufferqueue/2.0/B2HGraphicBufferProducer.cpp",
+ "bufferqueue/2.0/B2HProducerListener.cpp",
+ "bufferqueue/2.0/H2BGraphicBufferProducer.cpp",
+ "bufferqueue/2.0/H2BProducerListener.cpp",
+ "bufferqueue/2.0/types.cpp",
],
shared_libs: [
"android.frameworks.bufferhub@1.0",
+ "android.hardware.graphics.bufferqueue@1.0",
+ "android.hardware.graphics.bufferqueue@2.0",
"android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
+ "android.hidl.token@1.0-utils",
"libbase",
- "libsync",
"libbinder",
"libbufferhub",
"libbufferhubqueue", // TODO(b/70046255): Remove this once BufferHub is integrated into libgui.
- "libpdx_default_transport",
"libcutils",
"libEGL",
"libGLESv2",
- "libui",
- "libutils",
- "libnativewindow",
- "liblog",
- "libinput",
"libhidlbase",
"libhidltransport",
- "android.hidl.token@1.0-utils",
- "android.hardware.graphics.bufferqueue@1.0",
+ "libhwbinder",
+ "libinput",
+ "liblog",
+ "libnativewindow",
+ "libpdx_default_transport",
+ "libsync",
+ "libui",
+ "libutils",
+ "libvndksupport",
],
// bufferhub is not used when building libgui for vendors
target: {
vendor: {
- cflags: ["-DNO_BUFFERHUB", "-DNO_INPUT"],
+ cflags: [
+ "-DNO_BUFFERHUB",
+ "-DNO_INPUT",
+ ],
exclude_srcs: [
"BufferHubConsumer.cpp",
"BufferHubProducer.cpp",
@@ -157,16 +134,16 @@
"android.frameworks.bufferhub@1.0",
"libbufferhub",
"libbufferhubqueue",
+ "libinput",
"libpdx_default_transport",
- "libinput"
],
},
},
header_libs: [
"libdvr_headers",
- "libnativebase_headers",
"libgui_headers",
+ "libnativebase_headers",
"libpdx_headers",
],
@@ -175,9 +152,11 @@
"libEGL",
"libnativewindow",
"libui",
- "android.hidl.token@1.0-utils",
"android.hardware.graphics.bufferqueue@1.0",
+ "android.hardware.graphics.bufferqueue@2.0",
"android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
+ "android.hidl.token@1.0-utils",
],
export_header_lib_headers: [
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 3837c3e..f2d5c8e 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -34,9 +34,10 @@
#include <gui/IConsumerListener.h>
#include <gui/IProducerListener.h>
-#include <binder/IPCThreadState.h>
+#include <private/gui/BufferQueueThreadState.h>
#ifndef __ANDROID_VNDK__
#include <binder/PermissionCache.h>
+#include <vndksupport/linker.h>
#endif
#include <system/window.h>
@@ -758,19 +759,29 @@
return savedErrno ? -savedErrno : UNKNOWN_ERROR;
}
- const IPCThreadState* ipc = IPCThreadState::self();
- const uid_t uid = ipc->getCallingUid();
+ bool denied = false;
+ const uid_t uid = BufferQueueThreadState::getCallingUid();
#ifndef __ANDROID_VNDK__
// permission check can't be done for vendors as vendors have no access to
- // the PermissionController
- const pid_t pid = ipc->getCallingPid();
- if ((uid != shellUid) &&
- !PermissionCache::checkPermission(String16("android.permission.DUMP"), pid, uid)) {
- outResult->appendFormat("Permission Denial: can't dump BufferQueueConsumer "
- "from pid=%d, uid=%d\n", pid, uid);
+ // the PermissionController. We need to do a runtime check as well, since
+ // the system variant of libgui can be loaded in a vendor process. For eg:
+ // if a HAL uses an llndk library that depends on libgui (libmediandk etc).
+ if (!android_is_in_vendor_process()) {
+ const pid_t pid = BufferQueueThreadState::getCallingPid();
+ if ((uid != shellUid) &&
+ !PermissionCache::checkPermission(String16("android.permission.DUMP"), pid, uid)) {
+ outResult->appendFormat("Permission Denial: can't dump BufferQueueConsumer "
+ "from pid=%d, uid=%d\n",
+ pid, uid);
+ denied = true;
+ }
+ }
#else
if (uid != shellUid) {
+ denied = true;
+ }
#endif
+ if (denied) {
android_errorWriteWithInfoLog(0x534e4554, "27046057",
static_cast<int32_t>(uid), nullptr, 0);
return PERMISSION_DENIED;
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 5e250a4..a462b03 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -35,6 +35,7 @@
#include <gui/GLConsumer.h>
#include <gui/IConsumerListener.h>
#include <gui/IProducerListener.h>
+#include <private/gui/BufferQueueThreadState.h>
#include <utils/Log.h>
#include <utils/Trace.h>
@@ -1210,7 +1211,7 @@
status = BAD_VALUE;
break;
}
- mCore->mConnectedPid = IPCThreadState::self()->getCallingPid();
+ mCore->mConnectedPid = BufferQueueThreadState::getCallingPid();
mCore->mBufferHasBeenQueued = false;
mCore->mDequeueBufferCannotBlock = false;
if (mDequeueTimeout < 0) {
@@ -1233,7 +1234,7 @@
Mutex::Autolock lock(mCore->mMutex);
if (mode == DisconnectMode::AllLocal) {
- if (IPCThreadState::self()->getCallingPid() != mCore->mConnectedPid) {
+ if (BufferQueueThreadState::getCallingPid() != mCore->mConnectedPid) {
return NO_ERROR;
}
api = BufferQueueCore::CURRENTLY_CONNECTED_API;
diff --git a/libs/gui/BufferQueueThreadState.cpp b/libs/gui/BufferQueueThreadState.cpp
new file mode 100644
index 0000000..3b531ec
--- /dev/null
+++ b/libs/gui/BufferQueueThreadState.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/IPCThreadState.h>
+#include <hwbinder/IPCThreadState.h>
+#include <private/gui/BufferQueueThreadState.h>
+#include <unistd.h>
+
+namespace android {
+
+uid_t BufferQueueThreadState::getCallingUid() {
+ if (hardware::IPCThreadState::self()->isServingCall()) {
+ return hardware::IPCThreadState::self()->getCallingUid();
+ }
+ return IPCThreadState::self()->getCallingUid();
+}
+
+pid_t BufferQueueThreadState::getCallingPid() {
+ if (hardware::IPCThreadState::self()->isServingCall()) {
+ return hardware::IPCThreadState::self()->getCallingPid();
+ }
+ return IPCThreadState::self()->getCallingPid();
+}
+
+} // namespace android
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 8907de4..9dde15d 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -30,16 +30,21 @@
#ifndef NO_BUFFERHUB
#include <gui/BufferHubProducer.h>
#endif
+
+#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
+#include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h>
#include <gui/BufferQueueDefs.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/IProducerListener.h>
-#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
-
namespace android {
// ----------------------------------------------------------------------------
-using ::android::hardware::graphics::bufferqueue::V1_0::utils::
+using H2BGraphicBufferProducerV1_0 =
+ ::android::hardware::graphics::bufferqueue::V1_0::utils::
+ H2BGraphicBufferProducer;
+using H2BGraphicBufferProducerV2_0 =
+ ::android::hardware::graphics::bufferqueue::V2_0::utils::
H2BGraphicBufferProducer;
enum {
@@ -534,7 +539,9 @@
BpGraphicBufferProducer::~BpGraphicBufferProducer() {}
class HpGraphicBufferProducer : public HpInterface<
- BpGraphicBufferProducer, H2BGraphicBufferProducer> {
+ BpGraphicBufferProducer,
+ H2BGraphicBufferProducerV1_0,
+ H2BGraphicBufferProducerV2_0> {
public:
explicit HpGraphicBufferProducer(const sp<IBinder>& base) : PBase(base) {}
diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp
index 62abfa8..936063a 100644
--- a/libs/gui/IProducerListener.cpp
+++ b/libs/gui/IProducerListener.cpp
@@ -15,7 +15,8 @@
*/
#include <binder/Parcel.h>
-
+#include <gui/bufferqueue/1.0/H2BProducerListener.h>
+#include <gui/bufferqueue/2.0/H2BProducerListener.h>
#include <gui/IProducerListener.h>
namespace android {
@@ -61,7 +62,24 @@
// translation unit (see clang warning -Wweak-vtables)
BpProducerListener::~BpProducerListener() {}
-IMPLEMENT_META_INTERFACE(ProducerListener, "android.gui.IProducerListener")
+class HpProducerListener : public HpInterface<
+ BpProducerListener,
+ hardware::graphics::bufferqueue::V1_0::utils::H2BProducerListener,
+ hardware::graphics::bufferqueue::V2_0::utils::H2BProducerListener> {
+public:
+ explicit HpProducerListener(const sp<IBinder>& base) : PBase{base} {}
+
+ virtual void onBufferReleased() override {
+ mBase->onBufferReleased();
+ }
+
+ virtual bool needsReleaseNotify() override {
+ return mBase->needsReleaseNotify();
+ }
+};
+
+IMPLEMENT_HYBRID_META_INTERFACE(ProducerListener,
+ "android.gui.IProducerListener")
status_t BnProducerListener::onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags) {
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 247dc8d..bc63d31 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -68,7 +68,8 @@
const Vector<DisplayState>& displays, uint32_t flags,
const sp<IBinder>& applyToken,
const InputWindowCommands& commands,
- int64_t desiredPresentTime) {
+ int64_t desiredPresentTime,
+ const cached_buffer_t& uncacheBuffer) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -86,6 +87,8 @@
data.writeStrongBinder(applyToken);
commands.write(data);
data.writeInt64(desiredPresentTime);
+ data.writeStrongBinder(uncacheBuffer.token);
+ data.writeUint64(uncacheBuffer.cacheId);
remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply);
}
@@ -970,8 +973,13 @@
inputWindowCommands.read(data);
int64_t desiredPresentTime = data.readInt64();
+
+ cached_buffer_t uncachedBuffer;
+ uncachedBuffer.token = data.readStrongBinder();
+ uncachedBuffer.cacheId = data.readUint64();
+
setTransactionState(state, displays, stateFlags, applyToken, inputWindowCommands,
- desiredPresentTime);
+ desiredPresentTime, uncachedBuffer);
return NO_ERROR;
}
case BOOT_FINISHED: {
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 84ba644..f6ca9e8 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -95,7 +95,7 @@
}
output.writeStrongBinder(cachedBuffer.token);
- output.writeInt32(cachedBuffer.bufferId);
+ output.writeUint64(cachedBuffer.cacheId);
output.writeParcelable(metadata);
output.writeFloat(bgColorAlpha);
@@ -173,7 +173,7 @@
}
cachedBuffer.token = input.readStrongBinder();
- cachedBuffer.bufferId = input.readInt32();
+ cachedBuffer.cacheId = input.readUint64();
input.readParcelable(&metadata);
bgColorAlpha = input.readFloat();
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index b0e8275..39cd62f 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -233,6 +233,8 @@
// ---------------------------------------------------------------------------
+void bufferCacheCallback(void* /*context*/, uint64_t graphicBufferId);
+
class BufferCache : public Singleton<BufferCache> {
public:
BufferCache() : token(new BBinder()) {}
@@ -241,77 +243,57 @@
return IInterface::asBinder(TransactionCompletedListener::getIInstance());
}
- int32_t getId(const sp<GraphicBuffer>& buffer) {
+ status_t getCacheId(const sp<GraphicBuffer>& buffer, uint64_t* cacheId) {
std::lock_guard<std::mutex> lock(mMutex);
- auto itr = mBuffers.find(buffer);
+ auto itr = mBuffers.find(buffer->getId());
if (itr == mBuffers.end()) {
- return -1;
+ return BAD_VALUE;
}
- itr->second.counter = getCounter();
- return itr->second.id;
+ itr->second = getCounter();
+ *cacheId = buffer->getId();
+ return NO_ERROR;
}
- int32_t cache(const sp<GraphicBuffer>& buffer) {
+ uint64_t cache(const sp<GraphicBuffer>& buffer) {
std::lock_guard<std::mutex> lock(mMutex);
- int32_t bufferId = getNextAvailableId();
+ if (mBuffers.size() >= BUFFER_CACHE_MAX_SIZE) {
+ evictLeastRecentlyUsedBuffer();
+ }
- mBuffers[buffer].id = bufferId;
- mBuffers[buffer].counter = getCounter();
- return bufferId;
+ buffer->addDeathCallback(bufferCacheCallback, nullptr);
+
+ mBuffers[buffer->getId()] = getCounter();
+ return buffer->getId();
+ }
+
+ void uncache(uint64_t cacheId) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ uncacheLocked(cacheId);
+ }
+
+ void uncacheLocked(uint64_t cacheId) REQUIRES(mMutex) {
+ mBuffers.erase(cacheId);
+ SurfaceComposerClient::doUncacheBufferTransaction(cacheId);
}
private:
- int32_t evictDestroyedBuffer() REQUIRES(mMutex) {
+ void evictLeastRecentlyUsedBuffer() REQUIRES(mMutex) {
auto itr = mBuffers.begin();
- while (itr != mBuffers.end()) {
- auto& buffer = itr->first;
- if (buffer == nullptr || buffer.promote() == nullptr) {
- int32_t bufferId = itr->second.id;
- mBuffers.erase(itr);
- return bufferId;
- }
- itr++;
- }
- return -1;
- }
-
- int32_t evictLeastRecentlyUsedBuffer() REQUIRES(mMutex) {
- if (mBuffers.size() < 0) {
- return -1;
- }
- auto itr = mBuffers.begin();
- uint64_t minCounter = itr->second.counter;
+ uint64_t minCounter = itr->second;
auto minBuffer = itr;
itr++;
while (itr != mBuffers.end()) {
- uint64_t counter = itr->second.counter;
+ uint64_t counter = itr->second;
if (counter < minCounter) {
minCounter = counter;
minBuffer = itr;
}
itr++;
}
- int32_t minBufferId = minBuffer->second.id;
- mBuffers.erase(minBuffer);
- return minBufferId;
- }
-
- int32_t getNextAvailableId() REQUIRES(mMutex) {
- static int32_t id = 0;
- if (id + 1 < BUFFER_CACHE_MAX_SIZE) {
- return id++;
- }
-
- // There are no more valid cache ids. To set additional buffers, evict existing buffers
- // and reuse their cache ids.
- int32_t bufferId = evictDestroyedBuffer();
- if (bufferId > 0) {
- return bufferId;
- }
- return evictLeastRecentlyUsedBuffer();
+ uncacheLocked(minBuffer->first);
}
uint64_t getCounter() REQUIRES(mMutex) {
@@ -319,18 +301,8 @@
return counter++;
}
- struct Metadata {
- // The cache id of a buffer that can be set to ISurfaceComposer. When ISurfaceComposer
- // recieves this id, it can retrieve the buffer from its cache. Caching GraphicBuffers
- // is important because sending them across processes is expensive.
- int32_t id = 0;
- // When a buffer is set, a counter is incremented and stored in the cache's metadata.
- // When an buffer must be evicted, the entry with the lowest counter value is chosen.
- uint64_t counter = 0;
- };
-
std::mutex mMutex;
- std::map<wp<GraphicBuffer>, Metadata> mBuffers GUARDED_BY(mMutex);
+ std::map<uint64_t /*Cache id*/, uint64_t /*counter*/> mBuffers GUARDED_BY(mMutex);
// Used by ISurfaceComposer to identify which process is sending the cached buffer.
sp<IBinder> token;
@@ -338,6 +310,11 @@
ANDROID_SINGLETON_STATIC_INSTANCE(BufferCache);
+void bufferCacheCallback(void* /*context*/, uint64_t graphicBufferId) {
+ // GraphicBuffer id's are used as the cache ids.
+ BufferCache::getInstance().uncache(graphicBufferId);
+}
+
// ---------------------------------------------------------------------------
SurfaceComposerClient::Transaction::Transaction(const Transaction& other)
@@ -385,6 +362,9 @@
mInputWindowCommands.merge(other.mInputWindowCommands);
other.mInputWindowCommands.clear();
+ mContainsBuffer = other.mContainsBuffer;
+ other.mContainsBuffer = false;
+
return *this;
}
@@ -401,7 +381,50 @@
s.state.parentHandleForChild = nullptr;
composerStates.add(s);
- sf->setTransactionState(composerStates, displayStates, 0, nullptr, {}, -1);
+ sf->setTransactionState(composerStates, displayStates, 0, nullptr, {}, -1, {});
+}
+
+void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) {
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+
+ cached_buffer_t uncacheBuffer;
+ uncacheBuffer.token = BufferCache::getInstance().getToken();
+ uncacheBuffer.cacheId = cacheId;
+
+ sf->setTransactionState({}, {}, 0, nullptr, {}, -1, uncacheBuffer);
+}
+
+void SurfaceComposerClient::Transaction::cacheBuffers() {
+ if (!mContainsBuffer) {
+ return;
+ }
+
+ size_t count = 0;
+ for (auto& [sc, cs] : mComposerStates) {
+ layer_state_t* s = getLayerState(sc);
+ if (!(s->what & layer_state_t::eBufferChanged)) {
+ continue;
+ }
+
+ uint64_t cacheId = 0;
+ status_t ret = BufferCache::getInstance().getCacheId(s->buffer, &cacheId);
+ if (ret == NO_ERROR) {
+ s->what &= ~static_cast<uint32_t>(layer_state_t::eBufferChanged);
+ s->buffer = nullptr;
+ } else {
+ cacheId = BufferCache::getInstance().cache(s->buffer);
+ }
+ s->what |= layer_state_t::eCachedBufferChanged;
+ s->cachedBuffer.token = BufferCache::getInstance().getToken();
+ s->cachedBuffer.cacheId = cacheId;
+
+ // If we have more buffers than the size of the cache, we should stop caching so we don't
+ // evict other buffers in this transaction
+ count++;
+ if (count >= BUFFER_CACHE_MAX_SIZE) {
+ break;
+ }
+ }
}
status_t SurfaceComposerClient::Transaction::apply(bool synchronous) {
@@ -437,6 +460,8 @@
}
mListenerCallbacks.clear();
+ cacheBuffers();
+
Vector<ComposerState> composerStates;
Vector<DisplayState> displayStates;
uint32_t flags = 0;
@@ -468,7 +493,8 @@
sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
sf->setTransactionState(composerStates, displayStates, flags, applyToken, mInputWindowCommands,
- mDesiredPresentTime);
+ mDesiredPresentTime,
+ {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/);
mInputWindowCommands.clear();
mStatus = NO_ERROR;
return NO_ERROR;
@@ -882,20 +908,12 @@
mStatus = BAD_INDEX;
return *this;
}
-
- int32_t bufferId = BufferCache::getInstance().getId(buffer);
- if (bufferId < 0) {
- bufferId = BufferCache::getInstance().cache(buffer);
-
- s->what |= layer_state_t::eBufferChanged;
- s->buffer = buffer;
- }
-
- s->what |= layer_state_t::eCachedBufferChanged;
- s->cachedBuffer.token = BufferCache::getInstance().getToken();
- s->cachedBuffer.bufferId = bufferId;
+ s->what |= layer_state_t::eBufferChanged;
+ s->buffer = buffer;
registerSurfaceControlForCallback(sc);
+
+ mContainsBuffer = true;
return *this;
}
diff --git a/libs/gui/bufferqueue/1.0/H2BProducerListener.cpp b/libs/gui/bufferqueue/1.0/H2BProducerListener.cpp
new file mode 100644
index 0000000..2712f42
--- /dev/null
+++ b/libs/gui/bufferqueue/1.0/H2BProducerListener.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "H2BProducerListener@1.0"
+
+#include <android-base/logging.h>
+
+#include <gui/bufferqueue/1.0/H2BProducerListener.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V1_0 {
+namespace utils {
+
+using ::android::hardware::Return;
+
+H2BProducerListener::H2BProducerListener(sp<HProducerListener> const& base)
+ : CBase{base} {
+}
+
+void H2BProducerListener::onBufferReleased() {
+ if (!mBase->onBufferReleased().isOk()) {
+ LOG(ERROR) << "onBufferReleased: transaction failed.";
+ }
+}
+
+bool H2BProducerListener::needsReleaseNotify() {
+ Return<bool> transResult = mBase->needsReleaseNotify();
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "needsReleaseNotify: transaction failed.";
+ return false;
+ }
+ return static_cast<bool>(transResult);
+}
+
+} // namespace utils
+} // namespace V1_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
diff --git a/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp b/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp
new file mode 100644
index 0000000..e039593
--- /dev/null
+++ b/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp
@@ -0,0 +1,331 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "H2BGraphicBufferProducer@2.0"
+
+#include <android-base/logging.h>
+
+#include <android/hardware/graphics/bufferqueue/2.0/types.h>
+#include <android/hardware/graphics/common/1.2/types.h>
+#include <gui/bufferqueue/2.0/H2BProducerListener.h>
+#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
+#include <gui/bufferqueue/2.0/types.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <vndk/hardware_buffer.h>
+
+namespace android {
+
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+// B2HGraphicBufferProducer
+// ========================
+
+B2HGraphicBufferProducer::B2HGraphicBufferProducer(
+ sp<BGraphicBufferProducer> const& base)
+ : mBase{base} {
+}
+
+Return<HStatus> B2HGraphicBufferProducer::setMaxDequeuedBufferCount(
+ int32_t maxDequeuedBuffers) {
+ HStatus hStatus{};
+ bool converted = b2h(
+ mBase->setMaxDequeuedBufferCount(
+ static_cast<int>(maxDequeuedBuffers)),
+ &hStatus);
+ return {converted ? hStatus : HStatus::UNKNOWN_ERROR};
+}
+
+Return<void> B2HGraphicBufferProducer::requestBuffer(
+ int32_t slot,
+ requestBuffer_cb _hidl_cb) {
+ sp<GraphicBuffer> bBuffer;
+ HStatus hStatus{};
+ HardwareBuffer hBuffer{};
+ uint32_t hGenerationNumber{};
+ bool converted =
+ b2h(mBase->requestBuffer(
+ static_cast<int>(slot), &bBuffer),
+ &hStatus) &&
+ b2h(bBuffer, &hBuffer, &hGenerationNumber);
+ _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR,
+ hBuffer, hGenerationNumber);
+ return {};
+}
+
+Return<HStatus> B2HGraphicBufferProducer::setAsyncMode(bool async) {
+ HStatus hStatus{};
+ bool converted = b2h(mBase->setAsyncMode(async), &hStatus);
+ return {converted ? hStatus : HStatus::UNKNOWN_ERROR};
+}
+
+Return<void> B2HGraphicBufferProducer::dequeueBuffer(
+ DequeueBufferInput const& input,
+ dequeueBuffer_cb _hidl_cb) {
+ int bSlot{};
+ sp<BFence> bFence;
+ HStatus hStatus{};
+ DequeueBufferOutput hOutput{};
+ HFenceWrapper hFenceWrapper;
+ bool converted =
+ b2h(mBase->dequeueBuffer(
+ &bSlot,
+ &bFence,
+ input.width,
+ input.height,
+ static_cast<PixelFormat>(input.format),
+ input.usage,
+ &hOutput.bufferAge,
+ nullptr /* outTimestamps */),
+ &hStatus,
+ &hOutput.bufferNeedsReallocation,
+ &hOutput.releaseAllBuffers) &&
+ b2h(bFence, &hFenceWrapper);
+ hOutput.fence = hFenceWrapper.getHandle();
+ _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR,
+ static_cast<int32_t>(bSlot),
+ hOutput);
+ return {};
+}
+
+Return<HStatus> B2HGraphicBufferProducer::detachBuffer(int32_t slot) {
+ HStatus hStatus{};
+ bool converted = b2h(
+ mBase->detachBuffer(static_cast<int>(slot)), &hStatus);
+ return {converted ? hStatus : HStatus::UNKNOWN_ERROR};
+}
+
+Return<void> B2HGraphicBufferProducer::detachNextBuffer(
+ detachNextBuffer_cb _hidl_cb) {
+ sp<GraphicBuffer> bBuffer;
+ sp<BFence> bFence;
+ HStatus hStatus{};
+ HardwareBuffer hBuffer{};
+ HFenceWrapper hFenceWrapper;
+ bool converted =
+ b2h(mBase->detachNextBuffer(&bBuffer, &bFence), &hStatus) &&
+ b2h(bBuffer, &hBuffer) &&
+ b2h(bFence, &hFenceWrapper);
+ _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR,
+ hBuffer,
+ hFenceWrapper.getHandle());
+ return {};
+}
+
+Return<void> B2HGraphicBufferProducer::attachBuffer(
+ HardwareBuffer const& hBuffer,
+ uint32_t generationNumber,
+ attachBuffer_cb _hidl_cb) {
+ sp<GraphicBuffer> bBuffer;
+ if (!h2b(hBuffer, &bBuffer) || !bBuffer) {
+ _hidl_cb(HStatus::UNKNOWN_ERROR,
+ static_cast<int32_t>(SlotIndex::INVALID),
+ false);
+ return {};
+ }
+ bBuffer->setGenerationNumber(generationNumber);
+
+ int bSlot{};
+ HStatus hStatus{};
+ bool releaseAllBuffers{};
+ bool converted = b2h(
+ mBase->attachBuffer(&bSlot, bBuffer), &hStatus,
+ nullptr /* bufferNeedsReallocation */,
+ &releaseAllBuffers);
+ _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR,
+ static_cast<int32_t>(bSlot),
+ releaseAllBuffers);
+ return {};
+}
+
+Return<void> B2HGraphicBufferProducer::queueBuffer(
+ int32_t slot,
+ QueueBufferInput const& hInput,
+ queueBuffer_cb _hidl_cb) {
+ using HOutput = QueueBufferOutput;
+ using BInput = BGraphicBufferProducer::QueueBufferInput;
+ using BOutput = BGraphicBufferProducer::QueueBufferOutput;
+
+ BInput bInput{
+ hInput.timestamp,
+ hInput.isAutoTimestamp,
+ static_cast<android_dataspace>(hInput.dataSpace),
+ {}, /* crop */
+ 0 /* scalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE */,
+ static_cast<uint32_t>(hInput.transform),
+ {}, /* fence */
+ static_cast<uint32_t>(hInput.stickyTransform),
+ false /* getFrameTimestamps */};
+
+ // Convert crop.
+ if (!h2b(hInput.crop, &bInput.crop)) {
+ _hidl_cb(HStatus::UNKNOWN_ERROR, HOutput{});
+ return {};
+ }
+
+ // Convert surfaceDamage.
+ if (!h2b(hInput.surfaceDamage, &bInput.surfaceDamage)) {
+ _hidl_cb(HStatus::UNKNOWN_ERROR, HOutput{});
+ return {};
+ }
+
+ // Convert fence.
+ if (!h2b(hInput.fence, &bInput.fence)) {
+ _hidl_cb(HStatus::UNKNOWN_ERROR, HOutput{});
+ return {};
+ }
+
+ BOutput bOutput{};
+ HStatus hStatus{};
+ bool converted = b2h(
+ mBase->queueBuffer(static_cast<int>(slot), bInput, &bOutput),
+ &hStatus);
+
+ _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR,
+ HOutput{bOutput.width,
+ bOutput.height,
+ static_cast<int32_t>(bOutput.transformHint),
+ bOutput.numPendingBuffers,
+ bOutput.nextFrameNumber,
+ bOutput.bufferReplaced});
+ return {};
+}
+
+Return<HStatus> B2HGraphicBufferProducer::cancelBuffer(
+ int32_t slot,
+ hidl_handle const& fence) {
+ sp<BFence> bFence;
+ if (!h2b(fence.getNativeHandle(), &bFence)) {
+ return {HStatus::UNKNOWN_ERROR};
+ }
+ HStatus hStatus{};
+ bool converted = b2h(
+ mBase->cancelBuffer(static_cast<int>(slot), bFence),
+ &hStatus);
+ return {converted ? hStatus : HStatus::UNKNOWN_ERROR};
+}
+
+Return<void> B2HGraphicBufferProducer::query(int32_t what, query_cb _hidl_cb) {
+ int value{};
+ int result = mBase->query(static_cast<int>(what), &value);
+ _hidl_cb(static_cast<int32_t>(result), static_cast<int32_t>(value));
+ return {};
+}
+
+Return<void> B2HGraphicBufferProducer::connect(
+ sp<HProducerListener> const& hListener,
+ HConnectionType hConnectionType,
+ bool producerControlledByApp,
+ connect_cb _hidl_cb) {
+ using BOutput = BGraphicBufferProducer::QueueBufferOutput;
+ using HOutput = HGraphicBufferProducer::QueueBufferOutput;
+ sp<BProducerListener> bListener = new H2BProducerListener(hListener);
+ if (!bListener) {
+ _hidl_cb(HStatus::UNKNOWN_ERROR, HOutput{});
+ return {};
+ }
+ int bConnectionType;
+ if (!h2b(hConnectionType, &bConnectionType)) {
+ _hidl_cb(HStatus::UNKNOWN_ERROR, HOutput{});
+ return {};
+ }
+ BOutput bOutput{};
+ HStatus hStatus{};
+ bool converted = b2h(
+ mBase->connect(bListener,
+ bConnectionType,
+ producerControlledByApp,
+ &bOutput),
+ &hStatus);
+ _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR,
+ HOutput{bOutput.width,
+ bOutput.height,
+ static_cast<int32_t>(bOutput.transformHint),
+ bOutput.numPendingBuffers,
+ bOutput.nextFrameNumber,
+ bOutput.bufferReplaced});
+ return {};
+}
+
+Return<HStatus> B2HGraphicBufferProducer::disconnect(
+ HConnectionType hConnectionType) {
+ int bConnectionType;
+ if (!h2b(hConnectionType, &bConnectionType)) {
+ return {HStatus::UNKNOWN_ERROR};
+ }
+ HStatus hStatus{};
+ bool converted = b2h(mBase->disconnect(bConnectionType), &hStatus);
+ return {converted ? hStatus : HStatus::UNKNOWN_ERROR};
+}
+
+Return<HStatus> B2HGraphicBufferProducer::allocateBuffers(
+ uint32_t width, uint32_t height,
+ uint32_t format, uint64_t usage) {
+ mBase->allocateBuffers(
+ width, height, static_cast<PixelFormat>(format), usage);
+ return {HStatus::OK};
+}
+
+Return<HStatus> B2HGraphicBufferProducer::allowAllocation(bool allow) {
+ HStatus hStatus{};
+ bool converted = b2h(mBase->allowAllocation(allow), &hStatus);
+ return {converted ? hStatus : HStatus::UNKNOWN_ERROR};
+}
+
+Return<HStatus> B2HGraphicBufferProducer::setGenerationNumber(
+ uint32_t generationNumber) {
+ HStatus hStatus{};
+ bool converted = b2h(
+ mBase->setGenerationNumber(generationNumber),
+ &hStatus);
+ return {converted ? hStatus : HStatus::UNKNOWN_ERROR};
+}
+
+Return<HStatus> B2HGraphicBufferProducer::setDequeueTimeout(
+ int64_t timeoutNs) {
+ HStatus hStatus{};
+ bool converted = b2h(
+ mBase->setDequeueTimeout(static_cast<nsecs_t>(timeoutNs)),
+ &hStatus);
+ return {converted ? hStatus : HStatus::UNKNOWN_ERROR};
+}
+
+Return<uint64_t> B2HGraphicBufferProducer::getUniqueId() {
+ uint64_t outId{};
+ HStatus hStatus{};
+ bool converted = b2h(mBase->getUniqueId(&outId), &hStatus);
+ return {converted ? outId : 0};
+}
+
+Return<void> B2HGraphicBufferProducer::getConsumerName(
+ getConsumerName_cb _hidl_cb) {
+ _hidl_cb(hidl_string{mBase->getConsumerName().c_str()});
+ return {};
+}
+
+} // namespace utils
+} // namespace V2_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
diff --git a/libs/gui/bufferqueue/2.0/B2HProducerListener.cpp b/libs/gui/bufferqueue/2.0/B2HProducerListener.cpp
new file mode 100644
index 0000000..c4c96eb
--- /dev/null
+++ b/libs/gui/bufferqueue/2.0/B2HProducerListener.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gui/bufferqueue/2.0/B2HProducerListener.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+// B2HProducerListener
+B2HProducerListener::B2HProducerListener(sp<BProducerListener> const& base)
+ : mBase{base},
+ mNeedsReleaseNotify{base ? base->needsReleaseNotify() : false} {
+}
+
+Return<void> B2HProducerListener::onBuffersReleased(uint32_t count) {
+ if (mNeedsReleaseNotify) {
+ for (; count > 0; --count) {
+ mBase->onBufferReleased();
+ }
+ }
+ return {};
+}
+
+} // namespace utils
+} // namespace V2_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
diff --git a/libs/gui/bufferqueue/2.0/H2BGraphicBufferProducer.cpp b/libs/gui/bufferqueue/2.0/H2BGraphicBufferProducer.cpp
new file mode 100644
index 0000000..1023ef1
--- /dev/null
+++ b/libs/gui/bufferqueue/2.0/H2BGraphicBufferProducer.cpp
@@ -0,0 +1,514 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "H2BGraphicBufferProducer@2.0"
+
+#include <android-base/logging.h>
+
+#include <android/hardware/graphics/common/1.2/types.h>
+#include <gui/bufferqueue/2.0/B2HProducerListener.h>
+#include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h>
+#include <gui/bufferqueue/2.0/types.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <vndk/hardware_buffer.h>
+
+namespace android {
+
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+// H2BGraphicBufferProducer
+// ========================
+
+status_t H2BGraphicBufferProducer::requestBuffer(int slot,
+ sp<GraphicBuffer>* bBuffer) {
+ bool converted{};
+ status_t bStatus{};
+ Return<void> transResult = mBase->requestBuffer(slot,
+ [&converted, &bStatus, bBuffer](
+ HStatus hStatus,
+ HardwareBuffer const& hBuffer,
+ uint32_t generationNumber) {
+ converted =
+ h2b(hStatus, &bStatus) &&
+ h2b(hBuffer, bBuffer);
+ if (*bBuffer) {
+ (*bBuffer)->setGenerationNumber(generationNumber);
+ }
+ });
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "requestBuffer: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ if (!converted) {
+ LOG(ERROR) << "requestBuffer: corrupted transaction.";
+ return FAILED_TRANSACTION;
+ }
+ return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::setMaxDequeuedBufferCount(
+ int maxDequeuedBuffers) {
+ status_t bStatus{};
+ Return<HStatus> transResult = mBase->setMaxDequeuedBufferCount(
+ static_cast<int32_t>(maxDequeuedBuffers));
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "setMaxDequeuedBufferCount: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ if (!h2b(static_cast<HStatus>(transResult), &bStatus)) {
+ LOG(ERROR) << "setMaxDequeuedBufferCount: corrupted transaction.";
+ return FAILED_TRANSACTION;
+ }
+ return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::setAsyncMode(bool async) {
+ status_t bStatus{};
+ Return<HStatus> transResult = mBase->setAsyncMode(async);
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "setAsyncMode: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ if (!h2b(static_cast<HStatus>(transResult), &bStatus)) {
+ LOG(ERROR) << "setAsyncMode: corrupted transaction.";
+ return FAILED_TRANSACTION;
+ }
+ return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::dequeueBuffer(
+ int* slot, sp<BFence>* fence,
+ uint32_t w, uint32_t h,
+ PixelFormat format, uint64_t usage,
+ uint64_t* outBufferAge, FrameEventHistoryDelta* /* outTimestamps */) {
+
+ using HInput = HGraphicBufferProducer::DequeueBufferInput;
+ HInput input{w, h, static_cast<uint32_t>(format), usage};
+
+ using HOutput = HGraphicBufferProducer::DequeueBufferOutput;
+ bool converted{};
+ status_t bStatus{};
+ Return<void> transResult = mBase->dequeueBuffer(input,
+ [&converted, &bStatus, slot, fence, outBufferAge] (
+ HStatus hStatus, int32_t hSlot, HOutput const& hOutput) {
+ converted = h2b(hStatus, &bStatus);
+ if (!converted || bStatus != OK) {
+ return;
+ }
+ *slot = hSlot;
+ *outBufferAge = hOutput.bufferAge;
+ bStatus =
+ (hOutput.bufferNeedsReallocation ?
+ BUFFER_NEEDS_REALLOCATION : 0) |
+ (hOutput.releaseAllBuffers ?
+ RELEASE_ALL_BUFFERS : 0);
+ converted = h2b(hOutput.fence, fence);
+ });
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "dequeueBuffer: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ if (!converted) {
+ LOG(ERROR) << "dequeueBuffer: corrupted transaction.";
+ return FAILED_TRANSACTION;
+ }
+ return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::detachBuffer(int slot) {
+ status_t bStatus{};
+ Return<HStatus> transResult = mBase->detachBuffer(
+ static_cast<int32_t>(slot));
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "detachBuffer: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ if (!h2b(static_cast<HStatus>(transResult), &bStatus)) {
+ LOG(ERROR) << "detachBuffer: corrupted transaction.";
+ return FAILED_TRANSACTION;
+ }
+ return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::detachNextBuffer(
+ sp<GraphicBuffer>* outBuffer, sp<BFence>* outFence) {
+ bool converted{};
+ status_t bStatus{};
+ Return<void> transResult = mBase->detachNextBuffer(
+ [&converted, &bStatus, outBuffer, outFence] (
+ HStatus hStatus,
+ HardwareBuffer const& hBuffer,
+ hidl_handle const& hFence) {
+ converted = h2b(hStatus, &bStatus) &&
+ h2b(hBuffer, outBuffer) &&
+ h2b(hFence, outFence);
+ });
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "detachNextBuffer: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ if (!converted) {
+ LOG(ERROR) << "detachNextBuffer: corrupted transaction.";
+ return FAILED_TRANSACTION;
+ }
+ return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::attachBuffer(
+ int* outSlot, sp<GraphicBuffer> const& buffer) {
+ HardwareBuffer hBuffer{};
+ uint32_t hGenerationNumber{};
+ if (!b2h(buffer, &hBuffer, &hGenerationNumber)) {
+ LOG(ERROR) << "attachBuffer: invalid input buffer.";
+ return BAD_VALUE;
+ }
+
+ bool converted{};
+ status_t bStatus{};
+ Return<void> transResult = mBase->attachBuffer(hBuffer, hGenerationNumber,
+ [&converted, &bStatus, outSlot](
+ HStatus hStatus, int32_t hSlot, bool releaseAllBuffers) {
+ converted = h2b(hStatus, &bStatus);
+ *outSlot = static_cast<int>(hSlot);
+ if (converted && releaseAllBuffers && bStatus == OK) {
+ bStatus = IGraphicBufferProducer::RELEASE_ALL_BUFFERS;
+ }
+ });
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "attachBuffer: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ if (!converted) {
+ LOG(ERROR) << "attachBuffer: corrupted transaction.";
+ return FAILED_TRANSACTION;
+ }
+ return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::queueBuffer(
+ int slot,
+ QueueBufferInput const& input,
+ QueueBufferOutput* output) {
+ HRect hCrop{};
+ (void)b2h(input.crop, &hCrop);
+
+ using HInput = HGraphicBufferProducer::QueueBufferInput;
+ HInput hInput{
+ input.timestamp,
+ static_cast<bool>(input.isAutoTimestamp),
+ static_cast<int32_t>(input.dataSpace),
+ {}, // crop
+ static_cast<int32_t>(input.transform),
+ static_cast<int32_t>(input.stickyTransform),
+ {}, // fence
+ {} // surfaceDamage
+ };
+
+ // Convert crop.
+ if (!b2h(input.crop, &hInput.crop)) {
+ LOG(ERROR) << "queueBuffer: corrupted input crop rectangle.";
+ return UNKNOWN_ERROR;
+ }
+
+ // Convert surfaceDamage.
+ size_t numRects;
+ Rect const* rectArray = input.surfaceDamage.getArray(&numRects);
+ hInput.surfaceDamage.resize(numRects);
+ for (size_t i = 0; i < numRects; ++i) {
+ if (!b2h(rectArray[i], &hInput.surfaceDamage[i])) {
+ LOG(ERROR) << "queueBuffer: corrupted input surface damage.";
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ // Convert fence.
+ HFenceWrapper hFenceWrapper;
+ if (!b2h(input.fence, &hFenceWrapper)) {
+ LOG(ERROR) << "queueBuffer: corrupted input fence.";
+ return UNKNOWN_ERROR;
+ }
+ hInput.fence = hFenceWrapper.getHandle();
+
+ using HOutput = HGraphicBufferProducer::QueueBufferOutput;
+ bool converted{};
+ status_t bStatus{};
+ Return<void> transResult = mBase->queueBuffer(
+ static_cast<int32_t>(slot),
+ hInput,
+ [&converted, &bStatus, output](
+ HStatus hStatus,
+ HOutput const& hOutput) {
+ converted = h2b(hStatus, &bStatus);
+ output->width = hOutput.width;
+ output->height = hOutput.height;
+ output->transformHint =
+ static_cast<uint32_t>(hOutput.transformHint);
+ output->numPendingBuffers = hOutput.numPendingBuffers;
+ output->nextFrameNumber = hOutput.nextFrameNumber;
+ output->bufferReplaced = hOutput.bufferReplaced;
+ });
+
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "queueBuffer: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ if (!converted) {
+ LOG(ERROR) << "queueBuffer: corrupted transaction.";
+ return FAILED_TRANSACTION;
+ }
+ return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::cancelBuffer(int slot, sp<BFence> const& fence) {
+ HFenceWrapper hFenceWrapper;
+ if (!b2h(fence, &hFenceWrapper)) {
+ LOG(ERROR) << "cancelBuffer: corrupted input fence.";
+ return UNKNOWN_ERROR;
+ }
+ status_t bStatus{};
+ Return<HStatus> transResult = mBase->cancelBuffer(
+ static_cast<int32_t>(slot),
+ hFenceWrapper.getHandle());
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "cancelBuffer: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ if (!h2b(static_cast<HStatus>(transResult), &bStatus)) {
+ LOG(ERROR) << "cancelBuffer: corrupted transaction.";
+ return FAILED_TRANSACTION;
+ }
+ return bStatus;
+}
+
+int H2BGraphicBufferProducer::query(int what, int* value) {
+ int result{};
+ Return<void> transResult = mBase->query(
+ static_cast<int32_t>(what),
+ [&result, value](int32_t r, int32_t v) {
+ result = static_cast<int>(r);
+ *value = static_cast<int>(v);
+ });
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "query: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ return result;
+}
+
+status_t H2BGraphicBufferProducer::connect(
+ sp<IProducerListener> const& listener, int api,
+ bool producerControlledByApp, QueueBufferOutput* output) {
+ HConnectionType hConnectionType;
+ if (!b2h(api, &hConnectionType)) {
+ LOG(ERROR) << "connect: corrupted input connection type.";
+ return UNKNOWN_ERROR;
+ }
+ sp<HProducerListener> hListener = nullptr;
+ if (listener && listener->needsReleaseNotify()) {
+ hListener = new B2HProducerListener(listener);
+ if (!hListener) {
+ LOG(ERROR) << "connect: failed to wrap listener.";
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ using HOutput = HGraphicBufferProducer::QueueBufferOutput;
+ bool converted{};
+ status_t bStatus{};
+ Return<void> transResult = mBase->connect(
+ hListener,
+ hConnectionType,
+ producerControlledByApp,
+ [&converted, &bStatus, output](
+ HStatus hStatus,
+ HOutput hOutput) {
+ converted = h2b(hStatus, &bStatus);
+ output->width = hOutput.width;
+ output->height = hOutput.height;
+ output->transformHint =
+ static_cast<uint32_t>(hOutput.transformHint);
+ output->numPendingBuffers = hOutput.numPendingBuffers;
+ output->nextFrameNumber = hOutput.nextFrameNumber;
+ output->bufferReplaced = hOutput.bufferReplaced;
+ });
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "connect: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ if (!converted) {
+ LOG(ERROR) << "connect: corrupted transaction.";
+ return FAILED_TRANSACTION;
+ }
+ return bStatus;
+
+}
+
+status_t H2BGraphicBufferProducer::disconnect(int api, DisconnectMode mode) {
+ HConnectionType hConnectionType;
+ if (mode == DisconnectMode::AllLocal) {
+ hConnectionType = HConnectionType::CURRENTLY_CONNECTED;
+ } else if (!b2h(api, &hConnectionType)) {
+ LOG(ERROR) << "connect: corrupted input connection type.";
+ return UNKNOWN_ERROR;
+ }
+
+ status_t bStatus{};
+ Return<HStatus> transResult = mBase->disconnect(hConnectionType);
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "disconnect: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ if (!h2b(static_cast<HStatus>(transResult), &bStatus)) {
+ LOG(ERROR) << "disconnect: corrupted transaction.";
+ return FAILED_TRANSACTION;
+ }
+ return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::setSidebandStream(
+ sp<NativeHandle> const& stream) {
+ if (stream) {
+ LOG(INFO) << "setSidebandStream: not supported.";
+ return INVALID_OPERATION;
+ }
+ return OK;
+}
+
+void H2BGraphicBufferProducer::allocateBuffers(
+ uint32_t width, uint32_t height,
+ PixelFormat format, uint64_t usage) {
+ status_t bStatus{};
+ Return<HStatus> transResult = mBase->allocateBuffers(
+ width, height, static_cast<uint32_t>(format), usage);
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "allocateBuffer: transaction failed.";
+ return;
+ }
+ if (!h2b(static_cast<HStatus>(transResult), &bStatus)) {
+ LOG(ERROR) << "allocateBuffer: corrupted transaction.";
+ return;
+ }
+}
+
+status_t H2BGraphicBufferProducer::allowAllocation(bool allow) {
+ status_t bStatus{};
+ Return<HStatus> transResult = mBase->allowAllocation(allow);
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "allowAllocation: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ if (!h2b(static_cast<HStatus>(transResult), &bStatus)) {
+ LOG(ERROR) << "allowAllocation: corrupted transaction.";
+ return FAILED_TRANSACTION;
+ }
+ return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::setGenerationNumber(
+ uint32_t generationNumber) {
+ status_t bStatus{};
+ Return<HStatus> transResult = mBase->setGenerationNumber(generationNumber);
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "setGenerationNumber: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ if (!h2b(static_cast<HStatus>(transResult), &bStatus)) {
+ LOG(ERROR) << "setGenerationNumber: corrupted transaction.";
+ return FAILED_TRANSACTION;
+ }
+ return bStatus;
+}
+
+String8 H2BGraphicBufferProducer::getConsumerName() const {
+ String8 bName;
+ Return<void> transResult = mBase->getConsumerName(
+ [&bName](hidl_string const& name) {
+ bName = name.c_str();
+ });
+ return bName;
+}
+
+status_t H2BGraphicBufferProducer::setSharedBufferMode(bool sharedBufferMode) {
+ if (sharedBufferMode) {
+ LOG(INFO) << "setSharedBufferMode: not supported.";
+ return INVALID_OPERATION;
+ }
+ return OK;
+}
+
+status_t H2BGraphicBufferProducer::setAutoRefresh(bool autoRefresh) {
+ if (autoRefresh) {
+ LOG(INFO) << "setAutoRefresh: not supported.";
+ return INVALID_OPERATION;
+ }
+ return OK;
+}
+
+status_t H2BGraphicBufferProducer::setDequeueTimeout(nsecs_t timeout) {
+ status_t bStatus{};
+ Return<HStatus> transResult = mBase->setDequeueTimeout(
+ static_cast<int64_t>(timeout));
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "setDequeueTimeout: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ if (!h2b(static_cast<HStatus>(transResult), &bStatus)) {
+ LOG(ERROR) << "setDequeueTimeout: corrupted transaction.";
+ return FAILED_TRANSACTION;
+ }
+ return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::getLastQueuedBuffer(
+ sp<GraphicBuffer>*,
+ sp<BFence>*,
+ float[16]) {
+ LOG(INFO) << "getLastQueuedBuffer: not supported.";
+ return INVALID_OPERATION;
+}
+
+void H2BGraphicBufferProducer::getFrameTimestamps(FrameEventHistoryDelta*) {
+ LOG(INFO) << "getFrameTimestamps: not supported.";
+}
+
+status_t H2BGraphicBufferProducer::getUniqueId(uint64_t* outId) const {
+ Return<uint64_t> transResult = mBase->getUniqueId();
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "getUniqueId: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ *outId = static_cast<uint64_t>(transResult);
+ return OK;
+}
+
+status_t H2BGraphicBufferProducer::getConsumerUsage(uint64_t*) const {
+ LOG(INFO) << "getConsumerUsage: not supported.";
+ return INVALID_OPERATION;
+}
+
+} // namespace utils
+} // namespace V2_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/libs/gui/bufferqueue/2.0/H2BProducerListener.cpp b/libs/gui/bufferqueue/2.0/H2BProducerListener.cpp
new file mode 100644
index 0000000..b81a357
--- /dev/null
+++ b/libs/gui/bufferqueue/2.0/H2BProducerListener.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "H2BProducerListener@2.0"
+
+#include <android-base/logging.h>
+
+#include <gui/bufferqueue/2.0/H2BProducerListener.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+using ::android::hardware::Return;
+
+H2BProducerListener::H2BProducerListener(sp<HProducerListener> const& base)
+ : CBase{base} {
+}
+
+void H2BProducerListener::onBufferReleased() {
+ if (mBase) {
+ Return<void> transResult = mBase->onBuffersReleased(1);
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "onBuffersReleased: transaction failed.";
+ }
+ }
+}
+
+bool H2BProducerListener::needsReleaseNotify() {
+ return static_cast<bool>(mBase);
+}
+
+} // namespace utils
+} // namespace V2_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
diff --git a/libs/gui/bufferqueue/2.0/types.cpp b/libs/gui/bufferqueue/2.0/types.cpp
new file mode 100644
index 0000000..a110517
--- /dev/null
+++ b/libs/gui/bufferqueue/2.0/types.cpp
@@ -0,0 +1,301 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cutils/native_handle.h>
+#include <gui/BufferQueueCore.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/bufferqueue/2.0/types.h>
+#include <system/window.h>
+#include <vndk/hardware_buffer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+// Status
+// ======
+
+bool b2h(status_t from, HStatus* to,
+ bool* bufferNeedsReallocation, bool* releaseAllBuffers) {
+ switch (from) {
+ case OK:
+ *to = HStatus::OK; break;
+ case NO_MEMORY:
+ *to = HStatus::NO_MEMORY; break;
+ case NO_INIT:
+ *to = HStatus::NO_INIT; break;
+ case BAD_VALUE:
+ *to = HStatus::BAD_VALUE; break;
+ case DEAD_OBJECT:
+ *to = HStatus::DEAD_OBJECT; break;
+ case INVALID_OPERATION:
+ *to = HStatus::INVALID_OPERATION; break;
+ case TIMED_OUT:
+ *to = HStatus::TIMED_OUT; break;
+ case WOULD_BLOCK:
+ *to = HStatus::WOULD_BLOCK; break;
+ case UNKNOWN_ERROR:
+ *to = HStatus::UNKNOWN_ERROR; break;
+ default:
+ using BGBP = ::android::IGraphicBufferProducer;
+ status_t mask =
+ (bufferNeedsReallocation ? BGBP::BUFFER_NEEDS_REALLOCATION : 0)
+ | (releaseAllBuffers ? BGBP::RELEASE_ALL_BUFFERS : 0);
+ if (from & ~mask) {
+ *to = static_cast<HStatus>(from);
+ } else {
+ *to = HStatus::OK;
+ if (bufferNeedsReallocation) {
+ *bufferNeedsReallocation = from & BGBP::BUFFER_NEEDS_REALLOCATION;
+ }
+ if (releaseAllBuffers) {
+ *releaseAllBuffers = from & BGBP::RELEASE_ALL_BUFFERS;
+ }
+ }
+ }
+ return true;
+}
+
+bool h2b(HStatus from, status_t* to) {
+ switch (from) {
+ case HStatus::OK:
+ *to = OK; break;
+ case HStatus::NO_MEMORY:
+ *to = NO_MEMORY; break;
+ case HStatus::NO_INIT:
+ *to = NO_INIT; break;
+ case HStatus::BAD_VALUE:
+ *to = BAD_VALUE; break;
+ case HStatus::DEAD_OBJECT:
+ *to = DEAD_OBJECT; break;
+ case HStatus::INVALID_OPERATION:
+ *to = INVALID_OPERATION; break;
+ case HStatus::TIMED_OUT:
+ *to = TIMED_OUT; break;
+ case HStatus::WOULD_BLOCK:
+ *to = WOULD_BLOCK; break;
+ case HStatus::UNKNOWN_ERROR:
+ *to = UNKNOWN_ERROR; break;
+ default:
+ *to = static_cast<status_t>(from);
+ }
+ return true;
+}
+
+// Fence
+// =====
+
+HFenceWrapper::HFenceWrapper(native_handle_t* h) : mHandle{h} {
+}
+
+HFenceWrapper::~HFenceWrapper() {
+ native_handle_delete(mHandle);
+}
+
+HFenceWrapper& HFenceWrapper::set(native_handle_t* h) {
+ native_handle_delete(mHandle);
+ mHandle = h;
+ return *this;
+}
+
+HFenceWrapper& HFenceWrapper::operator=(native_handle_t* h) {
+ return set(h);
+}
+
+hidl_handle HFenceWrapper::getHandle() const {
+ return hidl_handle{mHandle};
+}
+
+HFenceWrapper::operator hidl_handle() const {
+ return getHandle();
+}
+
+bool b2h(sp<BFence> const& from, HFenceWrapper* to) {
+ if (!from) {
+ to->set(nullptr);
+ return true;
+ }
+ int fenceFd = from->get();
+ if (fenceFd == -1) {
+ to->set(nullptr);
+ return true;
+ }
+ native_handle_t* nh = native_handle_create(1, 0);
+ if (!nh) {
+ return false;
+ }
+ nh->data[0] = fenceFd;
+ to->set(nh);
+ return true;
+}
+
+bool h2b(native_handle_t const* from, sp<BFence>* to) {
+ if (!from || from->numFds == 0) {
+ *to = new ::android::Fence();
+ return true;
+ }
+ if (from->numFds != 1 || from->numInts != 0) {
+ return false;
+ }
+ *to = new BFence(dup(from->data[0]));
+ return true;
+}
+
+// ConnectionType
+// ==============
+
+bool b2h(int from, HConnectionType* to) {
+ *to = static_cast<HConnectionType>(from);
+ switch (from) {
+ case BufferQueueCore::CURRENTLY_CONNECTED_API:
+ *to = HConnectionType::CURRENTLY_CONNECTED; break;
+ case NATIVE_WINDOW_API_EGL:
+ *to = HConnectionType::EGL; break;
+ case NATIVE_WINDOW_API_CPU:
+ *to = HConnectionType::CPU; break;
+ case NATIVE_WINDOW_API_MEDIA:
+ *to = HConnectionType::MEDIA; break;
+ case NATIVE_WINDOW_API_CAMERA:
+ *to = HConnectionType::CAMERA; break;
+ }
+ return true;
+}
+
+bool h2b(HConnectionType from, int* to) {
+ *to = static_cast<int>(from);
+ switch (from) {
+ case HConnectionType::CURRENTLY_CONNECTED:
+ *to = BufferQueueCore::CURRENTLY_CONNECTED_API; break;
+ case HConnectionType::EGL:
+ *to = NATIVE_WINDOW_API_EGL; break;
+ case HConnectionType::CPU:
+ *to = NATIVE_WINDOW_API_CPU; break;
+ case HConnectionType::MEDIA:
+ *to = NATIVE_WINDOW_API_MEDIA; break;
+ case HConnectionType::CAMERA:
+ *to = NATIVE_WINDOW_API_CAMERA; break;
+ }
+ return true;
+}
+
+// Rect
+// ====
+
+bool b2h(BRect const& from, HRect* to) {
+ BRect* dst = reinterpret_cast<BRect*>(to->data());
+ dst->left = from.left;
+ dst->top = from.top;
+ dst->right = from.right;
+ dst->bottom = from.bottom;
+ return true;
+}
+
+bool h2b(HRect const& from, BRect* to) {
+ BRect const* src = reinterpret_cast<BRect const*>(from.data());
+ to->left = src->left;
+ to->top = src->top;
+ to->right = src->right;
+ to->bottom = src->bottom;
+ return true;
+}
+
+// Region
+// ======
+
+bool b2h(BRegion const& from, HRegion* to) {
+ size_t numRects;
+ BRect const* rectArray = from.getArray(&numRects);
+ to->resize(numRects);
+ for (size_t i = 0; i < numRects; ++i) {
+ if (!b2h(rectArray[i], &(*to)[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool h2b(HRegion const& from, BRegion* to) {
+ if (from.size() > 0) {
+ BRect bRect;
+ if (!h2b(from[0], &bRect)) {
+ return false;
+ }
+ to->set(bRect);
+ for (size_t i = 1; i < from.size(); ++i) {
+ if (!h2b(from[i], &bRect)) {
+ return false;
+ }
+ to->addRectUnchecked(
+ static_cast<int>(bRect.left),
+ static_cast<int>(bRect.top),
+ static_cast<int>(bRect.right),
+ static_cast<int>(bRect.bottom));
+ }
+ } else {
+ to->clear();
+ }
+ return true;
+}
+
+// GraphicBuffer
+// =============
+
+// The handle is not cloned. Its lifetime is tied to the original GraphicBuffer.
+bool b2h(sp<GraphicBuffer> const& from, HardwareBuffer* to,
+ uint32_t* toGenerationNumber) {
+ if (!from) {
+ return false;
+ }
+ AHardwareBuffer* hwBuffer = from->toAHardwareBuffer();
+ to->nativeHandle.setTo(
+ const_cast<native_handle_t*>(
+ AHardwareBuffer_getNativeHandle(hwBuffer)),
+ false);
+ AHardwareBuffer_describe(
+ hwBuffer,
+ reinterpret_cast<AHardwareBuffer_Desc*>(to->description.data()));
+ if (toGenerationNumber) {
+ *toGenerationNumber = from->getGenerationNumber();
+ }
+ return true;
+}
+
+// The handle is cloned.
+bool h2b(HardwareBuffer const& from, sp<GraphicBuffer>* to) {
+ AHardwareBuffer_Desc const* desc =
+ reinterpret_cast<AHardwareBuffer_Desc const*>(
+ from.description.data());
+ native_handle_t const* handle = from.nativeHandle;
+ AHardwareBuffer* hwBuffer;
+ if (AHardwareBuffer_createFromHandle(
+ desc, handle, AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE,
+ &hwBuffer) != OK) {
+ return false;
+ }
+ *to = GraphicBuffer::fromAHardwareBuffer(hwBuffer);
+ return true;
+}
+
+} // namespace utils
+} // namespace V2_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h
index 8ff8d81..2f538ad 100644
--- a/libs/gui/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -35,6 +35,7 @@
#include <hidl/HybridInterface.h>
#include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h>
+#include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
namespace android {
// ----------------------------------------------------------------------------
@@ -42,8 +43,6 @@
class IProducerListener;
class NativeHandle;
class Surface;
-typedef ::android::hardware::graphics::bufferqueue::V1_0::IGraphicBufferProducer
- HGraphicBufferProducer;
/*
* This class defines the Binder IPC interface for the producer side of
@@ -62,7 +61,16 @@
class IGraphicBufferProducer : public IInterface
{
public:
- DECLARE_HYBRID_META_INTERFACE(GraphicBufferProducer, HGraphicBufferProducer)
+ using HGraphicBufferProducerV1_0 =
+ ::android::hardware::graphics::bufferqueue::V1_0::
+ IGraphicBufferProducer;
+ using HGraphicBufferProducerV2_0 =
+ ::android::hardware::graphics::bufferqueue::V2_0::
+ IGraphicBufferProducer;
+
+ DECLARE_HYBRID_META_INTERFACE(GraphicBufferProducer,
+ HGraphicBufferProducerV1_0,
+ HGraphicBufferProducerV2_0)
enum {
// A flag returned by dequeueBuffer when the client needs to call
@@ -366,7 +374,6 @@
const HdrMetadata& getHdrMetadata() const { return hdrMetadata; }
void setHdrMetadata(const HdrMetadata& metadata) { hdrMetadata = metadata; }
- private:
int64_t timestamp{0};
int isAutoTimestamp{0};
android_dataspace dataSpace{HAL_DATASPACE_UNKNOWN};
diff --git a/libs/gui/include/gui/IProducerListener.h b/libs/gui/include/gui/IProducerListener.h
index e808bd3..a13d8e4 100644
--- a/libs/gui/include/gui/IProducerListener.h
+++ b/libs/gui/include/gui/IProducerListener.h
@@ -17,8 +17,10 @@
#ifndef ANDROID_GUI_IPRODUCERLISTENER_H
#define ANDROID_GUI_IPRODUCERLISTENER_H
+#include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h>
+#include <android/hardware/graphics/bufferqueue/2.0/IProducerListener.h>
#include <binder/IInterface.h>
-
+#include <hidl/HybridInterface.h>
#include <utils/RefBase.h>
namespace android {
@@ -47,7 +49,14 @@
class IProducerListener : public ProducerListener, public IInterface
{
public:
- DECLARE_META_INTERFACE(ProducerListener)
+ using HProducerListener1 =
+ ::android::hardware::graphics::bufferqueue::V1_0::IProducerListener;
+ using HProducerListener2 =
+ ::android::hardware::graphics::bufferqueue::V2_0::IProducerListener;
+ DECLARE_HYBRID_META_INTERFACE(
+ ProducerListener,
+ HProducerListener1,
+ HProducerListener2)
};
class BnProducerListener : public BnInterface<IProducerListener>
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 3dffa8f..0ef5b39 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -40,6 +40,7 @@
namespace android {
// ----------------------------------------------------------------------------
+struct cached_buffer_t;
struct ComposerState;
struct DisplayState;
struct DisplayInfo;
@@ -131,7 +132,8 @@
const Vector<DisplayState>& displays, uint32_t flags,
const sp<IBinder>& applyToken,
const InputWindowCommands& inputWindowCommands,
- int64_t desiredPresentTime) = 0;
+ int64_t desiredPresentTime,
+ const cached_buffer_t& uncacheBuffer) = 0;
/* signal that we're done booting.
* Requires ACCESS_SURFACE_FLINGER permission
@@ -194,8 +196,7 @@
* of the buffer. The caller should pick the data space and pixel format
* that it can consume.
*
- * At the moment, sourceCrop is ignored and is always set to the visible
- * region (projected display viewport) of the screen.
+ * sourceCrop is the crop on the logical display.
*
* reqWidth and reqHeight specifies the size of the buffer. When either
* of them is 0, they are set to the size of the logical display viewport.
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 35e795c..77bf8f1 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -41,6 +41,11 @@
class Parcel;
class ISurfaceComposerClient;
+struct cached_buffer_t {
+ sp<IBinder> token = nullptr;
+ uint64_t cacheId;
+};
+
/*
* Used to communicate layer information between SurfaceFlinger and its clients.
*/
@@ -133,10 +138,6 @@
float dtdy{0};
float dsdy{0};
};
- struct cached_buffer_t {
- sp<IBinder> token = nullptr;
- int32_t bufferId = -1;
- };
sp<IBinder> surface;
uint64_t what;
float x;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 39d6d13..593a5e7 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -165,6 +165,12 @@
static void doDropReferenceTransaction(const sp<IBinder>& handle,
const sp<ISurfaceComposerClient>& client);
+ /**
+ * Uncaches a buffer in ISurfaceComposer. It must be uncached via a transaction so that it is
+ * in order with other transactions that use buffers.
+ */
+ static void doUncacheBufferTransaction(uint64_t cacheId);
+
// Queries whether a given display is wide color display.
static status_t isWideColorDisplay(const sp<IBinder>& display, bool* outIsWideColorDisplay);
@@ -279,6 +285,9 @@
bool mAnimation = false;
bool mEarlyWakeup = false;
+ // Indicates that the Transaction contains a buffer that should be cached
+ bool mContainsBuffer = false;
+
// mDesiredPresentTime is the time in nanoseconds that the client would like the transaction
// to be presented. When it is not possible to present at exactly that time, it will be
// presented after the time has passed.
@@ -297,6 +306,7 @@
layer_state_t* getLayerState(const sp<SurfaceControl>& sc);
DisplayState& getDisplayState(const sp<IBinder>& token);
+ void cacheBuffers();
void registerSurfaceControlForCallback(const sp<SurfaceControl>& sc);
public:
diff --git a/libs/gui/include/gui/bufferqueue/1.0/H2BProducerListener.h b/libs/gui/include/gui/bufferqueue/1.0/H2BProducerListener.h
new file mode 100644
index 0000000..211fdd5
--- /dev/null
+++ b/libs/gui/include/gui/bufferqueue/1.0/H2BProducerListener.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_H2BPRODUCERLISTENER_H
+#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_H2BPRODUCERLISTENER_H
+
+#include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h>
+#include <gui/IProducerListener.h>
+#include <hidl/HybridInterface.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V1_0 {
+namespace utils {
+
+using HProducerListener = ::android::hardware::graphics::bufferqueue::V1_0::
+ IProducerListener;
+
+using BProducerListener = ::android::IProducerListener;
+
+class H2BProducerListener
+ : public H2BConverter<HProducerListener, BnProducerListener> {
+public:
+ H2BProducerListener(sp<HProducerListener> const& base);
+ virtual void onBufferReleased() override;
+ virtual bool needsReleaseNotify() override;
+};
+
+} // namespace utils
+} // namespace V1_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_H2BPRODUCERLISTENER_H
+
diff --git a/libs/gui/include/gui/bufferqueue/2.0/B2HGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/2.0/B2HGraphicBufferProducer.h
new file mode 100644
index 0000000..1c58167
--- /dev/null
+++ b/libs/gui/include/gui/bufferqueue/2.0/B2HGraphicBufferProducer.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_B2HGRAPHICBUFFERPRODUCER_H
+#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_B2HGRAPHICBUFFERPRODUCER_H
+
+#include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/bufferqueue/2.0/types.h>
+#include <hidl/HidlSupport.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+using HGraphicBufferProducer =
+ ::android::hardware::graphics::bufferqueue::V2_0::
+ IGraphicBufferProducer;
+using BGraphicBufferProducer =
+ ::android::
+ IGraphicBufferProducer;
+using HProducerListener =
+ ::android::hardware::graphics::bufferqueue::V2_0::
+ IProducerListener;
+
+using ::android::hardware::Return;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+
+using ::android::hardware::graphics::common::V1_2::HardwareBuffer;
+
+class B2HGraphicBufferProducer : public HGraphicBufferProducer {
+public:
+ B2HGraphicBufferProducer(sp<BGraphicBufferProducer> const& base);
+
+ virtual Return<HStatus> setMaxDequeuedBufferCount(
+ int32_t maxDequeuedBuffers) override;
+
+ virtual Return<void> requestBuffer(
+ int32_t slot,
+ requestBuffer_cb _hidl_cb) override;
+
+ virtual Return<HStatus> setAsyncMode(bool async) override;
+
+ virtual Return<void> dequeueBuffer(
+ DequeueBufferInput const& input,
+ dequeueBuffer_cb _hidl_cb) override;
+
+ virtual Return<HStatus> detachBuffer(int32_t slot) override;
+
+ virtual Return<void> detachNextBuffer(
+ detachNextBuffer_cb _hidl_cb) override;
+
+ virtual Return<void> attachBuffer(
+ HardwareBuffer const& buffer,
+ uint32_t generationNumber,
+ attachBuffer_cb _hidl_cb) override;
+
+ virtual Return<void> queueBuffer(
+ int32_t slot,
+ QueueBufferInput const& input,
+ queueBuffer_cb _hidl_cb) override;
+
+ virtual Return<HStatus> cancelBuffer(
+ int32_t slot,
+ hidl_handle const& fence) override;
+
+ virtual Return<void> query(int32_t what, query_cb _hidl_cb) override;
+
+ virtual Return<void> connect(
+ sp<HProducerListener> const& listener,
+ HConnectionType api,
+ bool producerControlledByApp,
+ connect_cb _hidl_cb) override;
+
+ virtual Return<HStatus> disconnect(HConnectionType api) override;
+
+ virtual Return<HStatus> allocateBuffers(
+ uint32_t width, uint32_t height,
+ uint32_t format, uint64_t usage) override;
+
+ virtual Return<HStatus> allowAllocation(bool allow) override;
+
+ virtual Return<HStatus> setGenerationNumber(uint32_t generationNumber) override;
+
+ virtual Return<HStatus> setDequeueTimeout(int64_t timeoutNs) override;
+
+ virtual Return<uint64_t> getUniqueId() override;
+
+ virtual Return<void> getConsumerName(getConsumerName_cb _hidl_cb) override;
+
+protected:
+ sp<BGraphicBufferProducer> mBase;
+};
+
+
+} // namespace utils
+} // namespace V2_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_B2HGRAPHICBUFFERPRODUCER_H
diff --git a/libs/gui/include/gui/bufferqueue/2.0/B2HProducerListener.h b/libs/gui/include/gui/bufferqueue/2.0/B2HProducerListener.h
new file mode 100644
index 0000000..b48a473
--- /dev/null
+++ b/libs/gui/include/gui/bufferqueue/2.0/B2HProducerListener.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_B2HPRODUCERLISTENER_H
+#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_B2HPRODUCERLISTENER_H
+
+#include <android/hidl/base/1.0/IBase.h>
+#include <binder/IBinder.h>
+#include <gui/IProducerListener.h>
+#include <hidl/Status.h>
+
+#include <android/hardware/graphics/bufferqueue/2.0/IProducerListener.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+using ::android::hardware::Return;
+
+using HProducerListener = ::android::hardware::graphics::bufferqueue::V2_0::
+ IProducerListener;
+
+using BProducerListener = ::android::IProducerListener;
+
+struct B2HProducerListener : public HProducerListener {
+ explicit B2HProducerListener(sp<BProducerListener> const& base);
+ Return<void> onBuffersReleased(uint32_t count) override;
+protected:
+ sp<BProducerListener> mBase;
+ bool mNeedsReleaseNotify;
+};
+
+} // namespace utils
+} // namespace V2_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_B2HPRODUCERLISTENER_H
+
diff --git a/libs/gui/include/gui/bufferqueue/2.0/H2BGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/2.0/H2BGraphicBufferProducer.h
new file mode 100644
index 0000000..7dd1617
--- /dev/null
+++ b/libs/gui/include/gui/bufferqueue/2.0/H2BGraphicBufferProducer.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_H2BGRAPHICBUFFERPRODUCER_H
+#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_H2BGRAPHICBUFFERPRODUCER_H
+
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/IProducerListener.h>
+#include <hidl/HybridInterface.h>
+#include <ui/Fence.h>
+
+#include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+using ::android::BnGraphicBufferProducer;
+using ::android::IProducerListener;
+using Fence = ::android::Fence;
+
+using HGraphicBufferProducer =
+ ::android::hardware::graphics::bufferqueue::V2_0::
+ IGraphicBufferProducer;
+using HProducerListener =
+ ::android::hardware::graphics::bufferqueue::V2_0::
+ IProducerListener;
+using BGraphicBufferProducer =
+ ::android::IGraphicBufferProducer;
+
+struct H2BGraphicBufferProducer
+ : public ::android::H2BConverter<HGraphicBufferProducer,
+ BnGraphicBufferProducer> {
+ explicit H2BGraphicBufferProducer(
+ sp<HGraphicBufferProducer> const& base) : CBase(base) {}
+
+ virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override;
+ virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) override;
+ virtual status_t setAsyncMode(bool async) override;
+ virtual status_t dequeueBuffer(
+ int* slot, sp<Fence>* fence,
+ uint32_t width, uint32_t height,
+ PixelFormat format, uint64_t usage,
+ uint64_t* outBufferAge,
+ FrameEventHistoryDelta* outTimestamps) override;
+ virtual status_t detachBuffer(int slot) override;
+ virtual status_t detachNextBuffer(
+ sp<GraphicBuffer>* outBuffer,
+ sp<Fence>* outFence) override;
+ virtual status_t attachBuffer(
+ int* outSlot,
+ sp<GraphicBuffer> const& buffer) override;
+ virtual status_t queueBuffer(
+ int slot,
+ QueueBufferInput const& input,
+ QueueBufferOutput* output) override;
+ virtual status_t cancelBuffer(int slot, sp<Fence> const& fence) override;
+ virtual int query(int what, int* value) override;
+ virtual status_t connect(
+ sp<IProducerListener> const& listener,
+ int api,
+ bool producerControlledByApp,
+ QueueBufferOutput* output) override;
+ virtual status_t disconnect(
+ int api,
+ DisconnectMode mode = DisconnectMode::Api) override;
+ virtual status_t setSidebandStream(sp<NativeHandle> const& stream) override;
+ virtual void allocateBuffers(
+ uint32_t width, uint32_t height,
+ PixelFormat format, uint64_t usage) override;
+ virtual status_t allowAllocation(bool allow) override;
+ virtual status_t setGenerationNumber(uint32_t generationNumber) override;
+ virtual String8 getConsumerName() const override;
+ virtual status_t setSharedBufferMode(bool sharedBufferMode) override;
+ virtual status_t setAutoRefresh(bool autoRefresh) override;
+ virtual status_t setDequeueTimeout(nsecs_t timeout) override;
+ virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
+ sp<Fence>* outFence, float outTransformMatrix[16]) override;
+ virtual void getFrameTimestamps(FrameEventHistoryDelta* outDelta) override;
+ virtual status_t getUniqueId(uint64_t* outId) const override;
+ virtual status_t getConsumerUsage(uint64_t* outUsage) const override;
+};
+
+} // namespace utils
+} // namespace V2_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_H2BGRAPHICBUFFERPRODUCER_H
diff --git a/libs/gui/include/gui/bufferqueue/2.0/H2BProducerListener.h b/libs/gui/include/gui/bufferqueue/2.0/H2BProducerListener.h
new file mode 100644
index 0000000..898920b
--- /dev/null
+++ b/libs/gui/include/gui/bufferqueue/2.0/H2BProducerListener.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_H2BPRODUCERLISTENER_H
+#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_H2BPRODUCERLISTENER_H
+
+#include <android/hardware/graphics/bufferqueue/2.0/IProducerListener.h>
+#include <gui/IProducerListener.h>
+#include <hidl/HybridInterface.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+using HProducerListener = ::android::hardware::graphics::bufferqueue::V2_0::
+ IProducerListener;
+
+using BProducerListener = ::android::IProducerListener;
+
+class H2BProducerListener
+ : public H2BConverter<HProducerListener, BnProducerListener> {
+public:
+ H2BProducerListener(sp<HProducerListener> const& base);
+ virtual void onBufferReleased() override;
+ virtual bool needsReleaseNotify() override;
+};
+
+} // namespace utils
+} // namespace V2_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_H2BPRODUCERLISTENER_H
+
diff --git a/libs/gui/include/gui/bufferqueue/2.0/types.h b/libs/gui/include/gui/bufferqueue/2.0/types.h
new file mode 100644
index 0000000..62176ce
--- /dev/null
+++ b/libs/gui/include/gui/bufferqueue/2.0/types.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_TYPES_H
+#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_TYPES_H
+
+#include <android/hardware/graphics/bufferqueue/2.0/types.h>
+#include <android/hardware/graphics/common/1.2/types.h>
+#include <hidl/HidlSupport.h>
+#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+// Status
+// ======
+
+using HStatus = ::android::hardware::graphics::bufferqueue::V2_0::
+ Status;
+
+// A status_t value may have flags encoded. These flags are decoded into boolean
+// values if their corresponding output pointers are not null.
+bool b2h(status_t from, HStatus* to,
+ bool* bufferNeedsReallocation = nullptr,
+ bool* releaseAllBuffers = nullptr);
+// Simple 1-to-1 mapping. If BUFFER_NEEDS_REALLOCATION or RELEASE_ALL_BUFFERS
+// needs to be added, it must be done manually afterwards.
+bool h2b(HStatus from, status_t* to);
+
+// Fence
+// =====
+
+using BFence = ::android::Fence;
+// This class manages the lifetime of a copied handle. Its destructor calls
+// native_handle_delete() but not native_handle_close().
+struct HFenceWrapper {
+ HFenceWrapper() = default;
+ // Sets mHandle to a new value.
+ HFenceWrapper(native_handle_t* h);
+ // Deletes mHandle without closing.
+ ~HFenceWrapper();
+ // Deletes mHandle without closing, then sets mHandle to a new value.
+ HFenceWrapper& set(native_handle_t* h);
+ HFenceWrapper& operator=(native_handle_t* h);
+ // Returns a non-owning hidl_handle pointing to mHandle.
+ hidl_handle getHandle() const;
+ operator hidl_handle() const;
+protected:
+ native_handle_t* mHandle{nullptr};
+};
+
+// Does not clone the fd---only copy the fd. The returned HFenceWrapper should
+// not outlive the input Fence object.
+bool b2h(sp<BFence> const& from, HFenceWrapper* to);
+// Clones the fd and puts it in a new Fence object.
+bool h2b(native_handle_t const* from, sp<BFence>* to);
+
+// ConnectionType
+// ==============
+
+using HConnectionType = ::android::hardware::graphics::bufferqueue::V2_0::
+ ConnectionType;
+
+bool b2h(int from, HConnectionType* to);
+bool h2b(HConnectionType from, int* to);
+
+// Rect
+// ====
+
+using BRect = ::android::Rect;
+using HRect = ::android::hardware::graphics::common::V1_2::Rect;
+
+bool b2h(BRect const& from, HRect* to);
+bool h2b(HRect const& from, BRect* to);
+
+// Region
+// ======
+
+using BRegion = ::android::Region;
+using HRegion = ::android::hardware::hidl_vec<HRect>;
+
+bool b2h(BRegion const& from, HRegion* to);
+bool h2b(HRegion const& from, BRegion* to);
+
+// GraphicBuffer
+// =============
+
+using HardwareBuffer = ::android::hardware::graphics::common::V1_2::
+ HardwareBuffer;
+using HardwareBufferDescription = ::android::hardware::graphics::common::V1_2::
+ HardwareBufferDescription;
+
+// Does not clone the handle. The returned HardwareBuffer should not outlive the
+// input GraphicBuffer. Note that HardwareBuffer does not carry the generation
+// number, so this function needs another output argument.
+bool b2h(sp<GraphicBuffer> const& from, HardwareBuffer* to,
+ uint32_t* toGenerationNumber = nullptr);
+// Clones the handle and creates a new GraphicBuffer from the cloned handle.
+// Note that the generation number of the GraphicBuffer has to be set manually
+// afterwards because HardwareBuffer does not have such information.
+bool h2b(HardwareBuffer const& from, sp<GraphicBuffer>* to);
+
+} // namespace utils
+} // namespace V2_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_TYPES_H
+
diff --git a/libs/gui/include/private/gui/BufferQueueThreadState.h b/libs/gui/include/private/gui/BufferQueueThreadState.h
new file mode 100644
index 0000000..67dcf62
--- /dev/null
+++ b/libs/gui/include/private/gui/BufferQueueThreadState.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace android {
+
+// TODO: Replace this with b/127962003
+class BufferQueueThreadState {
+public:
+ static pid_t getCallingPid();
+ static uid_t getCallingUid();
+};
+
+} // namespace android
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 06fe86c..94b669d 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -560,7 +560,8 @@
const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/,
const sp<IBinder>& /*applyToken*/,
const InputWindowCommands& /*inputWindowCommands*/,
- int64_t /*desiredPresentTime*/) override {}
+ int64_t /*desiredPresentTime*/,
+ const cached_buffer_t& /*cachedBuffer*/) override {}
void bootFinished() override {}
bool authenticateSurfaceTexture(
diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp
index 4ce5a10..d6a73bf 100644
--- a/libs/input/IInputFlinger.cpp
+++ b/libs/input/IInputFlinger.cpp
@@ -30,7 +30,7 @@
explicit BpInputFlinger(const sp<IBinder>& impl) :
BpInterface<IInputFlinger>(impl) { }
- virtual void setInputWindows(const Vector<InputWindowInfo>& inputInfo,
+ virtual void setInputWindows(const std::vector<InputWindowInfo>& inputInfo,
const sp<ISetInputWindowsListener>& setInputWindowsListener) {
Parcel data, reply;
data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
@@ -81,10 +81,9 @@
if (count > data.dataSize()) {
return BAD_VALUE;
}
- Vector<InputWindowInfo> handles;
- handles.setCapacity(count);
+ std::vector<InputWindowInfo> handles;
for (size_t i = 0; i < count; i++) {
- handles.add(InputWindowInfo(data));
+ handles.push_back(InputWindowInfo::read(data));
}
const sp<ISetInputWindowsListener> setInputWindowsListener =
ISetInputWindowsListener::asInterface(data.readStrongBinder());
diff --git a/libs/input/InputApplication.cpp b/libs/input/InputApplication.cpp
index 7936f50..1d9f8a7 100644
--- a/libs/input/InputApplication.cpp
+++ b/libs/input/InputApplication.cpp
@@ -24,19 +24,10 @@
// --- InputApplicationHandle ---
-InputApplicationHandle::InputApplicationHandle() :
- mInfo(nullptr) {
+InputApplicationHandle::InputApplicationHandle() {
}
InputApplicationHandle::~InputApplicationHandle() {
- delete mInfo;
-}
-
-void InputApplicationHandle::releaseInfo() {
- if (mInfo) {
- delete mInfo;
- mInfo = nullptr;
- }
}
InputApplicationInfo InputApplicationInfo::read(const Parcel& from) {
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index dab6eac..4db9e06 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -186,7 +186,7 @@
int32_t axis, uint32_t source) const {
size_t numRanges = mMotionRanges.size();
for (size_t i = 0; i < numRanges; i++) {
- const MotionRange& range = mMotionRanges.itemAt(i);
+ const MotionRange& range = mMotionRanges[i];
if (range.axis == axis && range.source == source) {
return ⦥
}
@@ -201,11 +201,11 @@
void InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max,
float flat, float fuzz, float resolution) {
MotionRange range = { axis, source, min, max, flat, fuzz, resolution };
- mMotionRanges.add(range);
+ mMotionRanges.push_back(range);
}
void InputDeviceInfo::addMotionRange(const MotionRange& range) {
- mMotionRanges.add(range);
+ mMotionRanges.push_back(range);
}
} // namespace android
diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp
index 88cb0db..efca68d 100644
--- a/libs/input/KeyLayoutMap.cpp
+++ b/libs/input/KeyLayoutMap.cpp
@@ -120,11 +120,12 @@
return nullptr;
}
-status_t KeyLayoutMap::findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const {
+status_t KeyLayoutMap::findScanCodesForKey(
+ int32_t keyCode, std::vector<int32_t>* outScanCodes) const {
const size_t N = mKeysByScanCode.size();
for (size_t i=0; i<N; i++) {
if (mKeysByScanCode.valueAt(i).keyCode == keyCode) {
- outScanCodes->add(mKeysByScanCode.keyAt(i));
+ outScanCodes->push_back(mKeysByScanCode.keyAt(i));
}
}
return NO_ERROR;
diff --git a/libs/input/VirtualKeyMap.cpp b/libs/input/VirtualKeyMap.cpp
index 624f152..865366b 100644
--- a/libs/input/VirtualKeyMap.cpp
+++ b/libs/input/VirtualKeyMap.cpp
@@ -112,7 +112,7 @@
"width=%d, height=%d",
defn.scanCode, defn.centerX, defn.centerY, defn.width, defn.height);
#endif
- mMap->mVirtualKeys.push(defn);
+ mMap->mVirtualKeys.push_back(defn);
} while (consumeFieldDelimiterAndSkipWhitespace());
if (!mTokenizer->isEol()) {
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 994e953..9bd3095 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -93,8 +93,66 @@
outDesc->rfu1 = 0;
}
+int AHardwareBuffer_lockAndGetInfo(AHardwareBuffer* buffer, uint64_t usage,
+ int32_t fence, const ARect* rect, void** outVirtualAddress,
+ int32_t* outBytesPerPixel, int32_t* outBytesPerStride) {
+ if (outBytesPerPixel) *outBytesPerPixel = -1;
+ if (outBytesPerStride) *outBytesPerStride = -1;
+
+ if (!buffer) {
+ return BAD_VALUE;
+ }
+
+ if (usage & ~(AHARDWAREBUFFER_USAGE_CPU_READ_MASK |
+ AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK)) {
+ ALOGE("Invalid usage flags passed to AHardwareBuffer_lock; only "
+ "AHARDWAREBUFFER_USAGE_CPU_* flags are allowed");
+ return BAD_VALUE;
+ }
+
+ usage = AHardwareBuffer_convertToGrallocUsageBits(usage);
+ GraphicBuffer* gbuffer = AHardwareBuffer_to_GraphicBuffer(buffer);
+
+ //Mapper implementations before 3.0 will not return bytes per pixel or
+ //bytes per stride information.
+ if (gbuffer->getBufferMapperVersion() == GraphicBufferMapper::Version::GRALLOC_2) {
+ ALOGE("Mapper versions before 3.0 cannot retrieve bytes per pixel and bytes per stride info");
+ return INVALID_OPERATION;
+ }
+
+ if (gbuffer->getLayerCount() > 1) {
+ ALOGE("Buffer with multiple layers passed to AHardwareBuffer_lock; "
+ "only buffers with one layer are allowed");
+ return INVALID_OPERATION;
+ }
+
+ Rect bounds;
+ if (!rect) {
+ bounds.set(Rect(gbuffer->getWidth(), gbuffer->getHeight()));
+ } else {
+ bounds.set(Rect(rect->left, rect->top, rect->right, rect->bottom));
+ }
+ int32_t bytesPerPixel;
+ int32_t bytesPerStride;
+ int result = gbuffer->lockAsync(usage, usage, bounds, outVirtualAddress, fence, &bytesPerPixel, &bytesPerStride);
+
+ // if hardware returns -1 for bytes per pixel or bytes per stride, we fail
+ // and unlock the buffer
+ if (bytesPerPixel == -1 || bytesPerStride == -1) {
+ gbuffer->unlock();
+ return INVALID_OPERATION;
+ }
+
+ if (outBytesPerPixel) *outBytesPerPixel = bytesPerPixel;
+ if (outBytesPerStride) *outBytesPerStride = bytesPerStride;
+ return result;
+}
+
int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage,
- int32_t fence, const ARect* rect, void** outVirtualAddress) {
+ int32_t fence, const ARect* rect, void** outVirtualAddress) {
+ int32_t bytesPerPixel;
+ int32_t bytesPerStride;
+
if (!buffer) return BAD_VALUE;
if (usage & ~(AHARDWAREBUFFER_USAGE_CPU_READ_MASK |
@@ -119,7 +177,7 @@
} else {
bounds.set(Rect(rect->left, rect->top, rect->right, rect->bottom));
}
- return gbuffer->lockAsync(usage, usage, bounds, outVirtualAddress, fence);
+ return gbuffer->lockAsync(usage, usage, bounds, outVirtualAddress, fence, &bytesPerPixel, &bytesPerStride);
}
int AHardwareBuffer_lockPlanes(AHardwareBuffer* buffer, uint64_t usage,
@@ -636,11 +694,11 @@
}
const GraphicBuffer* AHardwareBuffer_to_GraphicBuffer(const AHardwareBuffer* buffer) {
- return reinterpret_cast<const GraphicBuffer*>(buffer);
+ return GraphicBuffer::fromAHardwareBuffer(buffer);
}
GraphicBuffer* AHardwareBuffer_to_GraphicBuffer(AHardwareBuffer* buffer) {
- return reinterpret_cast<GraphicBuffer*>(buffer);
+ return GraphicBuffer::fromAHardwareBuffer(buffer);
}
const ANativeWindowBuffer* AHardwareBuffer_to_ANativeWindowBuffer(const AHardwareBuffer* buffer) {
@@ -652,7 +710,7 @@
}
AHardwareBuffer* AHardwareBuffer_from_GraphicBuffer(GraphicBuffer* buffer) {
- return reinterpret_cast<AHardwareBuffer*>(buffer);
+ return buffer->toAHardwareBuffer();
}
} // namespace android
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index d847884..27ab482 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -24,7 +24,7 @@
cc_library_headers {
name: "libnativewindow_headers",
export_include_dirs: ["include"],
- vendor_available: false,
+ vendor_available: true,
}
ndk_library {
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index 02c7c1b..da959e3 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -506,6 +506,18 @@
*/
int AHardwareBuffer_isSupported(const AHardwareBuffer_Desc* desc) __INTRODUCED_IN(29);
+/**
+ * Lock an AHardwareBuffer for direct CPU access.
+ *
+ * This function is the same as the above lock function, but passes back
+ * additional information about the bytes per pixel and the bytes per stride
+ * of the locked buffer. If the bytes per pixel or bytes per stride are unknown
+ * or variable, or if the underlying mapper implementation does not support returning
+ * additional information, then this call will fail with INVALID_OPERATION
+ */
+int AHardwareBuffer_lockAndGetInfo(AHardwareBuffer* buffer, uint64_t usage,
+ int32_t fence, const ARect* rect, void** outVirtualAddress,
+ int32_t* outBytesPerPixel, int32_t* outBytesPerStride) __INTRODUCED_IN(29);
#endif // __ANDROID_API__ >= 29
__END_DECLS
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index a796e97..23a05f3 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -7,6 +7,7 @@
AHardwareBuffer_getNativeHandle; # vndk
AHardwareBuffer_isSupported; # introduced=29
AHardwareBuffer_lock;
+ AHardwareBuffer_lockAndGetInfo; # introduced=29
AHardwareBuffer_recvHandleFromUnixSocket;
AHardwareBuffer_release;
AHardwareBuffer_sendHandleToUnixSocket;
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index f651309..1980f50 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -595,11 +595,7 @@
}
void GLESRenderEngine::setScissor(const Rect& region) {
- // Invert y-coordinate to map to GL-space.
- int32_t canvasHeight = mFboHeight;
- int32_t glBottom = canvasHeight - region.bottom;
-
- glScissor(region.left, glBottom, region.getWidth(), region.getHeight());
+ glScissor(region.left, region.top, region.getWidth(), region.getHeight());
glEnable(GL_SCISSOR_TEST);
}
@@ -719,6 +715,36 @@
return cropWin;
}
+void GLESRenderEngine::handleRoundedCorners(const DisplaySettings& display,
+ const LayerSettings& layer, const Mesh& mesh) {
+ // We separate the layer into 3 parts essentially, such that we only turn on blending for the
+ // top rectangle and the bottom rectangle, and turn off blending for the middle rectangle.
+ FloatRect bounds = layer.geometry.roundedCornersCrop;
+ const auto transformMatrix = display.globalTransform * layer.geometry.positionTransform;
+ const vec4 leftTopCoordinate(bounds.left, bounds.top, 1.0, 1.0);
+ const vec4 rightBottomCoordinate(bounds.right, bounds.bottom, 1.0, 1.0);
+ const vec4 leftTopCoordinateInBuffer = transformMatrix * leftTopCoordinate;
+ const vec4 rightBottomCoordinateInBuffer = transformMatrix * rightBottomCoordinate;
+ bounds = FloatRect(leftTopCoordinateInBuffer[0], leftTopCoordinateInBuffer[1],
+ rightBottomCoordinateInBuffer[0], rightBottomCoordinateInBuffer[1]);
+ const int32_t radius = ceil(layer.geometry.roundedCornersRadius);
+
+ const Rect topRect(bounds.left, bounds.top, bounds.right, bounds.top + radius);
+ setScissor(topRect);
+ drawMesh(mesh);
+ const Rect bottomRect(bounds.left, bounds.bottom - radius, bounds.right, bounds.bottom);
+ setScissor(bottomRect);
+ drawMesh(mesh);
+
+ // The middle part of the layer can turn off blending.
+ const Rect middleRect(bounds.left, bounds.top + radius, bounds.right, bounds.bottom - radius);
+ setScissor(middleRect);
+ mState.cornerRadius = 0.0;
+ disableBlending();
+ drawMesh(mesh);
+ disableScissor();
+}
+
status_t GLESRenderEngine::bindFrameBuffer(Framebuffer* framebuffer) {
ATRACE_CALL();
GLFramebuffer* glFramebuffer = static_cast<GLFramebuffer*>(framebuffer);
@@ -738,8 +764,6 @@
glBindFramebuffer(GL_FRAMEBUFFER, framebufferName);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureName, 0);
- mFboHeight = glFramebuffer->getBufferHeight();
-
uint32_t glStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
ALOGE_IF(glStatus != GL_FRAMEBUFFER_COMPLETE_OES, "glCheckFramebufferStatusOES error %d",
@@ -750,7 +774,6 @@
void GLESRenderEngine::unbindFrameBuffer(Framebuffer* /* framebuffer */) {
ATRACE_CALL();
- mFboHeight = 0;
// back to main framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
@@ -917,7 +940,14 @@
}
setSourceDataSpace(layer.sourceDataspace);
- drawMesh(mesh);
+ // We only want to do a special handling for rounded corners when having rounded corners
+ // is the only reason it needs to turn on blending, otherwise, we handle it like the
+ // usual way since it needs to turn on blending anyway.
+ if (layer.geometry.roundedCornersRadius > 0.0 && color.a >= 1.0f && isOpaque) {
+ handleRoundedCorners(display, layer, mesh);
+ } else {
+ drawMesh(mesh);
+ }
// Cleanup if there's a buffer source
if (layer.source.buffer.buffer != nullptr) {
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index efb6ef0..8c8f308 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -69,8 +69,6 @@
void clearWithColor(float red, float green, float blue, float alpha) override;
void fillRegionWithColor(const Region& region, float red, float green, float blue,
float alpha) override;
- void setScissor(const Rect& region) override;
- void disableScissor() override;
void genTextures(size_t count, uint32_t* names) override;
void deleteTextures(size_t count, uint32_t const* names) override;
void bindExternalTextureImage(uint32_t texName, const Image& image) override;
@@ -141,6 +139,8 @@
Protection protection);
static EGLSurface createDummyEglPbufferSurface(EGLDisplay display, EGLConfig config,
int hwcFormat, Protection protection);
+ void setScissor(const Rect& region);
+ void disableScissor();
bool waitSync(EGLSyncKHR sync, EGLint flags);
// A data space is considered HDR data space if it has BT2020 color space
@@ -156,6 +156,13 @@
// coordinates for the mesh.
FloatRect setupLayerCropping(const LayerSettings& layer, Mesh& mesh);
+ // We do a special handling for rounded corners when it's possible to turn off blending
+ // for the majority of the layer. The rounded corners needs to turn on blending such that
+ // we can set the alpha value correctly, however, only the corners need this, and since
+ // blending is an expensive operation, we want to turn off blending when it's not necessary.
+ void handleRoundedCorners(const DisplaySettings& display, const LayerSettings& layer,
+ const Mesh& mesh);
+
EGLDisplay mEGLDisplay;
EGLConfig mEGLConfig;
EGLContext mEGLContext;
@@ -185,7 +192,6 @@
bool mInProtectedContext = false;
// If set to true, then enables tracing flush() and finish() to systrace.
bool mTraceGpuCompletion = false;
- int32_t mFboHeight = 0;
// Maximum size of mFramebufferImageCache. If more images would be cached, then (approximately)
// the last recently used buffer should be kicked out.
uint32_t mFramebufferImageCacheSize = 0;
diff --git a/libs/renderengine/gl/ProgramCache.cpp b/libs/renderengine/gl/ProgramCache.cpp
index 49bdd2a..cd1182c 100644
--- a/libs/renderengine/gl/ProgramCache.cpp
+++ b/libs/renderengine/gl/ProgramCache.cpp
@@ -102,14 +102,21 @@
// Prime for sRGB->P3 conversion
if (useColorManagement) {
Key shaderKey;
- shaderKey.set(Key::BLEND_MASK | Key::TEXTURE_MASK | Key::OUTPUT_TRANSFORM_MATRIX_MASK |
- Key::INPUT_TF_MASK | Key::OUTPUT_TF_MASK,
- Key::BLEND_PREMULT | Key::TEXTURE_EXT | Key::OUTPUT_TRANSFORM_MATRIX_ON |
- Key::INPUT_TF_SRGB | Key::OUTPUT_TF_SRGB);
- for (int i = 0; i < 4; i++) {
+ shaderKey.set(Key::BLEND_MASK | Key::OUTPUT_TRANSFORM_MATRIX_MASK | Key::INPUT_TF_MASK |
+ Key::OUTPUT_TF_MASK,
+ Key::BLEND_PREMULT | Key::OUTPUT_TRANSFORM_MATRIX_ON | Key::INPUT_TF_SRGB |
+ Key::OUTPUT_TF_SRGB);
+ for (int i = 0; i < 16; i++) {
shaderKey.set(Key::OPACITY_MASK,
(i & 1) ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT);
shaderKey.set(Key::ALPHA_MASK, (i & 2) ? Key::ALPHA_LT_ONE : Key::ALPHA_EQ_ONE);
+
+ // Cache rounded corners
+ shaderKey.set(Key::ROUNDED_CORNERS_MASK,
+ (i & 4) ? Key::ROUNDED_CORNERS_ON : Key::ROUNDED_CORNERS_OFF);
+
+ // Cache texture off option for window transition
+ shaderKey.set(Key::TEXTURE_MASK, (i & 8) ? Key::TEXTURE_EXT : Key::TEXTURE_OFF);
if (cache.count(shaderKey) == 0) {
cache.emplace(shaderKey, generateProgram(shaderKey));
shaderCount++;
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index ab34274..b211551 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -103,9 +103,6 @@
virtual void clearWithColor(float red, float green, float blue, float alpha) = 0;
virtual void fillRegionWithColor(const Region& region, float red, float green, float blue,
float alpha) = 0;
-
- virtual void setScissor(const Rect& region) = 0;
- virtual void disableScissor() = 0;
virtual void genTextures(size_t count, uint32_t* names) = 0;
virtual void deleteTextures(size_t count, uint32_t const* names) = 0;
virtual void bindExternalTextureImage(uint32_t texName, const Image& image) = 0;
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index ddf7420..479c7ac 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -48,8 +48,6 @@
bool waitFence(base::unique_fd fd) override { return waitFence(&fd); };
MOCK_METHOD4(clearWithColor, void(float, float, float, float));
MOCK_METHOD5(fillRegionWithColor, void(const Region&, float, float, float, float));
- MOCK_METHOD1(setScissor, void(const Rect&));
- MOCK_METHOD0(disableScissor, void());
MOCK_METHOD2(genTextures, void(size_t, uint32_t*));
MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*));
MOCK_METHOD2(bindExternalTextureImage, void(uint32_t, const renderengine::Image&));
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 4ca1781..755418e 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -124,7 +124,6 @@
exclude_header_libs: [
"libbufferhub_headers",
"libdvr_headers",
- "libnativewindow_headers",
],
exclude_shared_libs: [
"android.frameworks.bufferhub@1.0",
@@ -152,6 +151,7 @@
export_header_lib_headers: [
"libbase_headers",
"libnativebase_headers",
+ "libnativewindow_headers",
"libhardware_headers",
"libui_headers",
],
@@ -167,6 +167,12 @@
override_export_include_dirs: ["include_vndk"],
},
},
+ header_libs: [
+ "libnativewindow_headers",
+ ],
+ export_header_lib_headers: [
+ "libnativewindow_headers",
+ ],
}
subdirs = [
diff --git a/libs/ui/ColorSpace.cpp b/libs/ui/ColorSpace.cpp
index 5b4bf23..7a14af1 100644
--- a/libs/ui/ColorSpace.cpp
+++ b/libs/ui/ColorSpace.cpp
@@ -351,13 +351,12 @@
};
}
-std::unique_ptr<float3> ColorSpace::createLUT(uint32_t size,
- const ColorSpace& src, const ColorSpace& dst) {
-
+std::unique_ptr<float3[]> ColorSpace::createLUT(uint32_t size, const ColorSpace& src,
+ const ColorSpace& dst) {
size = clamp(size, 2u, 256u);
float m = 1.0f / float(size - 1);
- std::unique_ptr<float3> lut(new float3[size * size * size]);
+ std::unique_ptr<float3[]> lut(new float3[size * size * size]);
float3* data = lut.get();
ColorSpaceConnector connector(src, dst);
diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp
index ed7ccb0b..4ce891e 100644
--- a/libs/ui/Fence.cpp
+++ b/libs/ui/Fence.cpp
@@ -110,7 +110,7 @@
}
struct sync_file_info* finfo = sync_file_info(mFenceFd);
- if (finfo == NULL) {
+ if (finfo == nullptr) {
ALOGE("sync_file_info returned NULL for fd %d", mFenceFd.get());
return SIGNAL_TIME_INVALID;
}
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 79958ec..2fb1099 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -49,6 +49,22 @@
return static_cast<GraphicBuffer *>(anwb);
}
+GraphicBuffer* GraphicBuffer::fromAHardwareBuffer(AHardwareBuffer* buffer) {
+ return reinterpret_cast<GraphicBuffer*>(buffer);
+}
+
+GraphicBuffer const* GraphicBuffer::fromAHardwareBuffer(AHardwareBuffer const* buffer) {
+ return reinterpret_cast<GraphicBuffer const*>(buffer);
+}
+
+AHardwareBuffer* GraphicBuffer::toAHardwareBuffer() {
+ return reinterpret_cast<AHardwareBuffer*>(this);
+}
+
+AHardwareBuffer const* GraphicBuffer::toAHardwareBuffer() const {
+ return reinterpret_cast<AHardwareBuffer const*>(this);
+}
+
GraphicBuffer::GraphicBuffer()
: BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0)
@@ -60,7 +76,7 @@
usage_deprecated = 0;
usage = 0;
layerCount = 0;
- handle = NULL;
+ handle = nullptr;
}
// deprecated
@@ -117,6 +133,9 @@
if (handle) {
free_handle();
}
+ for (auto& [callback, context] : mDeathCallbacks) {
+ callback(context, mId);
+ }
}
void GraphicBuffer::free_handle()
@@ -127,7 +146,7 @@
GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
allocator.free(handle);
}
- handle = NULL;
+ handle = nullptr;
}
status_t GraphicBuffer::initCheck() const {
@@ -162,7 +181,7 @@
if (handle) {
GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
allocator.free(handle);
- handle = 0;
+ handle = nullptr;
}
return initWithSize(inWidth, inHeight, inFormat, inLayerCount, inUsage, "[Reallocation]");
}
@@ -355,14 +374,29 @@
}
size_t GraphicBuffer::getFlattenedSize() const {
+#ifndef LIBUI_IN_VNDK
+ if (mBufferHubBuffer != nullptr) {
+ return 48;
+ }
+#endif
return static_cast<size_t>(13 + (handle ? mTransportNumInts : 0)) * sizeof(int);
}
size_t GraphicBuffer::getFdCount() const {
+#ifndef LIBUI_IN_VNDK
+ if (mBufferHubBuffer != nullptr) {
+ return 0;
+ }
+#endif
return static_cast<size_t>(handle ? mTransportNumFds : 0);
}
status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const {
+#ifndef LIBUI_IN_VNDK
+ if (mBufferHubBuffer != nullptr) {
+ return flattenBufferHubBuffer(buffer, size);
+ }
+#endif
size_t sizeNeeded = GraphicBuffer::getFlattenedSize();
if (size < sizeNeeded) return NO_MEMORY;
@@ -389,7 +423,7 @@
buf[11] = int32_t(mTransportNumInts);
memcpy(fds, handle->data, static_cast<size_t>(mTransportNumFds) * sizeof(int));
memcpy(buf + 13, handle->data + handle->numFds,
- static_cast<size_t>(mTransportNumInts) * sizeof(int));
+ static_cast<size_t>(mTransportNumInts) * sizeof(int));
}
buffer = static_cast<void*>(static_cast<uint8_t*>(buffer) + sizeNeeded);
@@ -398,14 +432,13 @@
fds += mTransportNumFds;
count -= static_cast<size_t>(mTransportNumFds);
}
-
return NO_ERROR;
}
-status_t GraphicBuffer::unflatten(
- void const*& buffer, size_t& size, int const*& fds, size_t& count) {
- if (size < 12 * sizeof(int)) {
- android_errorWriteLog(0x534e4554, "114223584");
+status_t GraphicBuffer::unflatten(void const*& buffer, size_t& size, int const*& fds,
+ size_t& count) {
+ // Check if size is not smaller than buf[0] is supposed to take.
+ if (size < sizeof(int)) {
return NO_MEMORY;
}
@@ -420,10 +453,21 @@
} else if (buf[0] == 'GBFR') {
// old version, when usage bits were 32-bits
flattenWordCount = 12;
+ } else if (buf[0] == 'BHBB') { // BufferHub backed buffer.
+#ifndef LIBUI_IN_VNDK
+ return unflattenBufferHubBuffer(buffer, size);
+#else
+ return BAD_TYPE;
+#endif
} else {
return BAD_TYPE;
}
+ if (size < 12 * sizeof(int)) {
+ android_errorWriteLog(0x534e4554, "114223584");
+ return NO_MEMORY;
+ }
+
const size_t numFds = static_cast<size_t>(buf[10]);
const size_t numInts = static_cast<size_t>(buf[11]);
@@ -436,7 +480,7 @@
width = height = stride = format = usage_deprecated = 0;
layerCount = 0;
usage = 0;
- handle = NULL;
+ handle = nullptr;
ALOGE("unflatten: numFds or numInts is too large: %zd, %zd", numFds, numInts);
return BAD_VALUE;
}
@@ -464,13 +508,13 @@
} else {
usage = uint64_t(usage_deprecated);
}
- native_handle* h = native_handle_create(
- static_cast<int>(numFds), static_cast<int>(numInts));
+ native_handle* h =
+ native_handle_create(static_cast<int>(numFds), static_cast<int>(numInts));
if (!h) {
width = height = stride = format = usage_deprecated = 0;
layerCount = 0;
usage = 0;
- handle = NULL;
+ handle = nullptr;
ALOGE("unflatten: native_handle_create failed");
return NO_MEMORY;
}
@@ -481,7 +525,7 @@
width = height = stride = format = usage_deprecated = 0;
layerCount = 0;
usage = 0;
- handle = NULL;
+ handle = nullptr;
}
mId = static_cast<uint64_t>(buf[7]) << 32;
@@ -491,7 +535,7 @@
mOwner = ownHandle;
- if (handle != 0) {
+ if (handle != nullptr) {
buffer_handle_t importedHandle;
status_t err = mBufferMapper.importBuffer(handle, uint32_t(width), uint32_t(height),
uint32_t(layerCount), format, usage, uint32_t(stride), &importedHandle);
@@ -499,7 +543,7 @@
width = height = stride = format = usage_deprecated = 0;
layerCount = 0;
usage = 0;
- handle = NULL;
+ handle = nullptr;
ALOGE("unflatten: registerBuffer failed: %s (%d)", strerror(-err), err);
return err;
}
@@ -514,11 +558,78 @@
size -= sizeNeeded;
fds += numFds;
count -= numFds;
+ return NO_ERROR;
+}
+
+void GraphicBuffer::addDeathCallback(GraphicBufferDeathCallback deathCallback, void* context) {
+ mDeathCallbacks.emplace_back(deathCallback, context);
+}
+
+#ifndef LIBUI_IN_VNDK
+status_t GraphicBuffer::flattenBufferHubBuffer(void*& buffer, size_t& size) const {
+ sp<NativeHandle> tokenHandle = mBufferHubBuffer->duplicate();
+ if (tokenHandle == nullptr || tokenHandle->handle() == nullptr ||
+ tokenHandle->handle()->numFds != 0) {
+ return BAD_VALUE;
+ }
+
+ // Size needed for one label, one number of ints inside the token, one generation number and
+ // the token itself.
+ int numIntsInToken = tokenHandle->handle()->numInts;
+ const size_t sizeNeeded = static_cast<size_t>(3 + numIntsInToken) * sizeof(int);
+ if (size < sizeNeeded) {
+ ALOGE("%s: needed size %d, given size %d. Not enough memory.", __FUNCTION__,
+ static_cast<int>(sizeNeeded), static_cast<int>(size));
+ return NO_MEMORY;
+ }
+ size -= sizeNeeded;
+
+ int* buf = static_cast<int*>(buffer);
+ buf[0] = 'BHBB';
+ buf[1] = numIntsInToken;
+ memcpy(buf + 2, tokenHandle->handle()->data, static_cast<size_t>(numIntsInToken) * sizeof(int));
+ buf[2 + numIntsInToken] = static_cast<int32_t>(mGenerationNumber);
return NO_ERROR;
}
-#ifndef LIBUI_IN_VNDK
+status_t GraphicBuffer::unflattenBufferHubBuffer(void const*& buffer, size_t& size) {
+ const int* buf = static_cast<const int*>(buffer);
+ int numIntsInToken = buf[1];
+ // Size needed for one label, one number of ints inside the token, one generation number and
+ // the token itself.
+ const size_t sizeNeeded = static_cast<size_t>(3 + numIntsInToken) * sizeof(int);
+ if (size < sizeNeeded) {
+ ALOGE("%s: needed size %d, given size %d. Not enough memory.", __FUNCTION__,
+ static_cast<int>(sizeNeeded), static_cast<int>(size));
+ return NO_MEMORY;
+ }
+ size -= sizeNeeded;
+ native_handle_t* importToken = native_handle_create(/*numFds=*/0, /*numInts=*/numIntsInToken);
+ memcpy(importToken->data, buf + 2, static_cast<size_t>(buf[1]) * sizeof(int));
+ sp<NativeHandle> importTokenHandle = NativeHandle::create(importToken, /*ownHandle=*/true);
+ std::unique_ptr<BufferHubBuffer> bufferHubBuffer = BufferHubBuffer::import(importTokenHandle);
+ if (bufferHubBuffer == nullptr || bufferHubBuffer.get() == nullptr) {
+ return BAD_VALUE;
+ }
+ // Reconstruct this GraphicBuffer object using the new BufferHubBuffer object.
+ if (handle) {
+ free_handle();
+ }
+ mId = 0;
+ mGenerationNumber = static_cast<uint32_t>(buf[2 + numIntsInToken]);
+ mInitCheck =
+ initWithHandle(bufferHubBuffer->duplicateHandle(), /*method=*/TAKE_UNREGISTERED_HANDLE,
+ bufferHubBuffer->desc().width, bufferHubBuffer->desc().height,
+ static_cast<PixelFormat>(bufferHubBuffer->desc().format),
+ bufferHubBuffer->desc().layers, bufferHubBuffer->desc().usage,
+ bufferHubBuffer->desc().stride);
+ mBufferId = bufferHubBuffer->id();
+ mBufferHubBuffer.reset(std::move(bufferHubBuffer.get()));
+
+ return NO_ERROR;
+}
+
bool GraphicBuffer::isBufferHubBuffer() const {
return mBufferHubBuffer != nullptr;
}
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index 06981c3..25b7247 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -53,6 +53,9 @@
mMapper = std::make_unique<const Gralloc3Mapper>();
if (!mMapper->isLoaded()) {
mMapper = std::make_unique<const Gralloc2Mapper>();
+ mMapperVersion = Version::GRALLOC_2;
+ } else {
+ mMapperVersion = Version::GRALLOC_3;
}
if (!mMapper->isLoaded()) {
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index 3bd3748..224dc2c 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -820,7 +820,7 @@
}
if (numRects > (UINT32_MAX / sizeof(Rect))) {
- android_errorWriteWithInfoLog(0x534e4554, "29983260", -1, NULL, 0);
+ android_errorWriteWithInfoLog(0x534e4554, "29983260", -1, nullptr, 0);
return NO_MEMORY;
}
diff --git a/libs/ui/include/ui/ColorSpace.h b/libs/ui/include/ui/ColorSpace.h
index 8ccf6d3..241ec10 100644
--- a/libs/ui/include/ui/ColorSpace.h
+++ b/libs/ui/include/ui/ColorSpace.h
@@ -250,8 +250,8 @@
// axis is thus already flipped
// The source color space must define its values in the domain [0..1]
// The generated LUT transforms from gamma space to gamma space
- static std::unique_ptr<float3> createLUT(uint32_t size,
- const ColorSpace& src, const ColorSpace& dst);
+ static std::unique_ptr<float3[]> createLUT(uint32_t size, const ColorSpace& src,
+ const ColorSpace& dst);
private:
static constexpr mat3 computeXYZMatrix(
diff --git a/libs/ui/include/ui/Fence.h b/libs/ui/include/ui/Fence.h
index ec67fa9..6efecd3 100644
--- a/libs/ui/include/ui/Fence.h
+++ b/libs/ui/include/ui/Fence.h
@@ -99,6 +99,12 @@
// be returned and errno will indicate the problem.
int dup() const;
+ // Return the underlying file descriptor without giving up ownership. The
+ // returned file descriptor is only valid for as long as the owning Fence
+ // object lives. (If the situation is unclear, dup() is always a safer
+ // option.)
+ int get() const { return mFenceFd.get(); }
+
// getSignalTime returns the system monotonic clock time at which the
// fence transitioned to the signaled state. If the fence is not signaled
// then SIGNAL_TIME_PENDING is returned. If the fence is invalid or if an
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index 4d4ee68..c195342 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -21,8 +21,12 @@
#include <sys/types.h>
#include <string>
+#include <utility>
+#include <vector>
+#include <android/hardware_buffer.h>
#include <ui/ANativeObjectBase.h>
+#include <ui/GraphicBufferMapper.h>
#include <ui/PixelFormat.h>
#include <ui/Rect.h>
#include <utils/Flattenable.h>
@@ -40,6 +44,8 @@
class GraphicBufferMapper;
+using GraphicBufferDeathCallback = std::function<void(void* /*context*/, uint64_t bufferId)>;
+
// ===========================================================================
// GraphicBuffer
// ===========================================================================
@@ -78,6 +84,10 @@
static sp<GraphicBuffer> from(ANativeWindowBuffer *);
+ static GraphicBuffer* fromAHardwareBuffer(AHardwareBuffer*);
+ static GraphicBuffer const* fromAHardwareBuffer(AHardwareBuffer const*);
+ AHardwareBuffer* toAHardwareBuffer();
+ AHardwareBuffer const* toAHardwareBuffer() const;
// Create a GraphicBuffer to be unflatten'ed into or be reallocated.
GraphicBuffer();
@@ -209,6 +219,12 @@
status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const;
status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count);
+ GraphicBufferMapper::Version getBufferMapperVersion() const {
+ return mBufferMapper.getMapperVersion();
+ }
+
+ void addDeathCallback(GraphicBufferDeathCallback deathCallback, void* context);
+
#ifndef LIBUI_IN_VNDK
// Returns whether this GraphicBuffer is backed by BufferHubBuffer.
bool isBufferHubBuffer() const;
@@ -270,7 +286,32 @@
// IGBP::setGenerationNumber), attempts to attach the buffer will fail.
uint32_t mGenerationNumber;
+ // Send a callback when a GraphicBuffer dies.
+ //
+ // This is used for BufferStateLayer caching. GraphicBuffers are refcounted per process. When
+ // A GraphicBuffer doesn't have any more sp<> in a process, it is destroyed. This causes
+ // problems when trying to implicitcly cache across process boundaries. Ideally, both sides
+ // of the cache would hold onto wp<> references. When an app dropped its sp<>, the GraphicBuffer
+ // would be destroyed. Unfortunately, when SurfaceFlinger has only a wp<> reference to the
+ // GraphicBuffer, it immediately goes out of scope in the SurfaceFlinger process. SurfaceFlinger
+ // must hold onto a sp<> to the buffer. When the GraphicBuffer goes out of scope in the app's
+ // process, the client side cache will get this callback. It erases the buffer from its cache
+ // and informs SurfaceFlinger that it should drop its strong pointer reference to the buffer.
+ std::vector<std::pair<GraphicBufferDeathCallback, void* /*mDeathCallbackContext*/>>
+ mDeathCallbacks;
+
#ifndef LIBUI_IN_VNDK
+ // Flatten this GraphicBuffer object if backed by BufferHubBuffer.
+ status_t flattenBufferHubBuffer(void*& buffer, size_t& size) const;
+
+ // Unflatten into BufferHubBuffer backed GraphicBuffer.
+ // Unflatten will fail if the original GraphicBuffer object is destructed. For instance, a
+ // GraphicBuffer backed by BufferHubBuffer_1 flatten in process/thread A, transport the token
+ // to process/thread B through a socket, BufferHubBuffer_1 dies and bufferhub invalidated the
+ // token. Race condition occurs between the invalidation of the token in bufferhub process and
+ // process/thread B trying to unflatten and import the buffer with that token.
+ status_t unflattenBufferHubBuffer(void const*& buffer, size_t& size);
+
// Stores a BufferHubBuffer that handles buffer signaling, identification.
std::unique_ptr<BufferHubBuffer> mBufferHubBuffer;
#endif // LIBUI_IN_VNDK
diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h
index 77c99cc..2461454 100644
--- a/libs/ui/include/ui/GraphicBufferMapper.h
+++ b/libs/ui/include/ui/GraphicBufferMapper.h
@@ -41,6 +41,10 @@
class GraphicBufferMapper : public Singleton<GraphicBufferMapper>
{
public:
+ enum Version {
+ GRALLOC_2,
+ GRALLOC_3,
+ };
static void preloadHal();
static inline GraphicBufferMapper& get() { return getInstance(); }
@@ -85,12 +89,16 @@
return reinterpret_cast<const GrallocMapper&>(*mMapper);
}
+ Version getMapperVersion() const { return mMapperVersion; }
+
private:
friend class Singleton<GraphicBufferMapper>;
GraphicBufferMapper();
std::unique_ptr<const GrallocMapper> mMapper;
+
+ Version mMapperVersion;
};
// ---------------------------------------------------------------------------
diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp
index c767ce0..a7c248c 100644
--- a/libs/ui/tests/GraphicBuffer_test.cpp
+++ b/libs/ui/tests/GraphicBuffer_test.cpp
@@ -74,4 +74,49 @@
EXPECT_EQ(gb->getBufferId(), b1_id);
}
+TEST_F(GraphicBufferTest, flattenAndUnflatten) {
+ std::unique_ptr<BufferHubBuffer> b1 =
+ BufferHubBuffer::create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat,
+ kTestUsage, /*userMetadataSize=*/0);
+ ASSERT_NE(b1, nullptr);
+ sp<GraphicBuffer> gb1(new GraphicBuffer(std::move(b1)));
+ gb1->setGenerationNumber(42);
+
+ size_t flattenedSize = gb1->getFlattenedSize();
+ EXPECT_EQ(flattenedSize, 48);
+ size_t fdCount = gb1->getFdCount();
+ EXPECT_EQ(fdCount, 0);
+
+ int data[flattenedSize];
+ int fds[0];
+
+ // Make copies of needed items since flatten modifies them.
+ size_t flattenedSizeCopy = flattenedSize;
+ size_t fdCountCopy = fdCount;
+ void* dataStart = data;
+ int* fdsStart = fds;
+ status_t err = gb1->flatten(dataStart, flattenedSizeCopy, fdsStart, fdCountCopy);
+ ASSERT_EQ(err, NO_ERROR);
+ EXPECT_EQ(flattenedSizeCopy, 0);
+ EXPECT_EQ(fdCountCopy, 0);
+
+ size_t unflattenSize = flattenedSize;
+ size_t unflattenFdCount = fdCount;
+ const void* unflattenData = static_cast<const void*>(dataStart);
+ const int* unflattenFdData = static_cast<const int*>(fdsStart);
+
+ GraphicBuffer* gb2 = new GraphicBuffer();
+ err = gb2->unflatten(unflattenData, unflattenSize, unflattenFdData, unflattenFdCount);
+ ASSERT_EQ(err, NO_ERROR);
+ EXPECT_TRUE(gb2->isBufferHubBuffer());
+
+ EXPECT_EQ(gb2->getWidth(), kTestWidth);
+ EXPECT_EQ(gb2->getHeight(), kTestHeight);
+ EXPECT_EQ(static_cast<uint32_t>(gb2->getPixelFormat()), kTestFormat);
+ EXPECT_EQ(gb2->getUsage(), kTestUsage);
+ EXPECT_EQ(gb2->getLayerCount(), kTestLayerCount);
+ EXPECT_EQ(gb1->getBufferId(), gb2->getBufferId());
+ EXPECT_EQ(gb2->getGenerationNumber(), 42);
+}
+
} // namespace android
diff --git a/libs/ui/tools/lutgen.cpp b/libs/ui/tools/lutgen.cpp
index 97b0822..85a1ceb 100644
--- a/libs/ui/tools/lutgen.cpp
+++ b/libs/ui/tools/lutgen.cpp
@@ -85,11 +85,11 @@
static int handleCommandLineArgments(int argc, char* argv[]) {
static constexpr const char* OPTSTR = "h:d:s:t:";
static const struct option OPTIONS[] = {
- { "help", no_argument, 0, 'h' },
- { "dimension", required_argument, 0, 'd' },
- { "source", required_argument, 0, 's' },
- { "target", required_argument, 0, 't' },
- { 0, 0, 0, 0 } // termination of the option list
+ { "help", no_argument, nullptr, 'h' },
+ { "dimension", required_argument, nullptr, 'd' },
+ { "source", required_argument, nullptr, 's' },
+ { "target", required_argument, nullptr, 't' },
+ { nullptr, 0, nullptr, 0 } // termination of the option list
};
int opt;
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index c100db7..54fa89f 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -314,6 +314,24 @@
}
}
+ if (cnx->minor == 5) {
+ // full list in egl_entries.in
+ if (!cnx->egl.eglCreateImage ||
+ !cnx->egl.eglDestroyImage ||
+ !cnx->egl.eglGetPlatformDisplay ||
+ !cnx->egl.eglCreatePlatformWindowSurface ||
+ !cnx->egl.eglCreatePlatformPixmapSurface ||
+ !cnx->egl.eglCreateSync ||
+ !cnx->egl.eglDestroySync ||
+ !cnx->egl.eglClientWaitSync ||
+ !cnx->egl.eglGetSyncAttrib ||
+ !cnx->egl.eglWaitSync) {
+ ALOGE("Driver indicates EGL 1.5 support, but does not have "
+ "a critical API");
+ cnx->minor = 4;
+ }
+ }
+
// the query strings are per-display
mVendorString = sVendorString;
mVersionString.clear();
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index 4da1473..0544ec1 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -415,14 +415,14 @@
Device* device = getDeviceLocked(deviceId);
if (device && device->hasValidFd() && device->keyMap.haveKeyLayout()) {
- Vector<int32_t> scanCodes;
+ std::vector<int32_t> scanCodes;
device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode, &scanCodes);
if (scanCodes.size() != 0) {
uint8_t keyState[sizeof_bit_array(KEY_MAX + 1)];
memset(keyState, 0, sizeof(keyState));
if (ioctl(device->fd, EVIOCGKEY(sizeof(keyState)), keyState) >= 0) {
for (size_t i = 0; i < scanCodes.size(); i++) {
- int32_t sc = scanCodes.itemAt(i);
+ int32_t sc = scanCodes[i];
if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, keyState)) {
return AKEY_STATE_DOWN;
}
@@ -478,7 +478,7 @@
Device* device = getDeviceLocked(deviceId);
if (device && device->keyMap.haveKeyLayout()) {
- Vector<int32_t> scanCodes;
+ std::vector<int32_t> scanCodes;
for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) {
scanCodes.clear();
@@ -609,13 +609,15 @@
}
void EventHub::getVirtualKeyDefinitions(int32_t deviceId,
- Vector<VirtualKeyDefinition>& outVirtualKeys) const {
+ std::vector<VirtualKeyDefinition>& outVirtualKeys) const {
outVirtualKeys.clear();
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
if (device && device->virtualKeyMap) {
- outVirtualKeys.appendVector(device->virtualKeyMap->getVirtualKeys());
+ const std::vector<VirtualKeyDefinition> virtualKeys =
+ device->virtualKeyMap->getVirtualKeys();
+ outVirtualKeys.insert(outVirtualKeys.end(), virtualKeys.begin(), virtualKeys.end());
}
}
@@ -1680,11 +1682,11 @@
return false;
}
- Vector<int32_t> scanCodes;
+ std::vector<int32_t> scanCodes;
device->keyMap.keyLayoutMap->findScanCodesForKey(keycode, &scanCodes);
const size_t N = scanCodes.size();
for (size_t i=0; i<N && i<=KEY_MAX; i++) {
- int32_t sc = scanCodes.itemAt(i);
+ int32_t sc = scanCodes[i];
if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, device->keyBitmask)) {
return true;
}
diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h
index 44f7b37..63a20ef 100644
--- a/services/inputflinger/EventHub.h
+++ b/services/inputflinger/EventHub.h
@@ -228,7 +228,7 @@
virtual void setLedState(int32_t deviceId, int32_t led, bool on) = 0;
virtual void getVirtualKeyDefinitions(int32_t deviceId,
- Vector<VirtualKeyDefinition>& outVirtualKeys) const = 0;
+ std::vector<VirtualKeyDefinition>& outVirtualKeys) const = 0;
virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const = 0;
virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map) = 0;
@@ -304,7 +304,7 @@
virtual void setLedState(int32_t deviceId, int32_t led, bool on);
virtual void getVirtualKeyDefinitions(int32_t deviceId,
- Vector<VirtualKeyDefinition>& outVirtualKeys) const;
+ std::vector<VirtualKeyDefinition>& outVirtualKeys) const;
virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const;
virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map);
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index bcb1ec5..0d5bc15 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -524,10 +524,8 @@
sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId,
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();
- for (size_t i = 0; i < numWindows; i++) {
- sp<InputWindowHandle> windowHandle = windowHandles.itemAt(i);
+ const std::vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
+ for (const sp<InputWindowHandle>& windowHandle : windowHandles) {
const InputWindowInfo* windowInfo = windowHandle->getInfo();
if (windowInfo->displayId == displayId) {
int32_t flags = windowInfo->layoutParamsFlags;
@@ -859,7 +857,7 @@
}
// Identify targets.
- Vector<InputTarget> inputTargets;
+ std::vector<InputTarget> inputTargets;
int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
entry, inputTargets, nextWakeupTime);
if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
@@ -910,7 +908,7 @@
bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
// Identify targets.
- Vector<InputTarget> inputTargets;
+ std::vector<InputTarget> inputTargets;
bool conflictingPointerActions = false;
int32_t injectionResult;
@@ -946,11 +944,11 @@
ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(entry->displayId);
if (stateIndex >= 0) {
const TouchState& state = mTouchStatesByDisplay.valueAt(stateIndex);
- if (!state.portalWindows.isEmpty()) {
+ if (!state.portalWindows.empty()) {
// 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();
+ const InputWindowInfo* windowInfo = state.portalWindows[i]->getInfo();
addMonitoringTargetsLocked(inputTargets, windowInfo->portalToDisplayId,
-windowInfo->frameLeft, -windowInfo->frameTop);
}
@@ -1004,7 +1002,7 @@
}
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
- EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
+ EventEntry* eventEntry, const std::vector<InputTarget>& inputTargets) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("dispatchEventToCurrentInputTargets");
#endif
@@ -1013,9 +1011,7 @@
pokeUserActivityLocked(eventEntry);
- for (size_t i = 0; i < inputTargets.size(); i++) {
- const InputTarget& inputTarget = inputTargets.itemAt(i);
-
+ for (const InputTarget& inputTarget : inputTargets) {
ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
if (connectionIndex >= 0) {
sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
@@ -1181,7 +1177,7 @@
}
int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
- const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {
+ const EventEntry* entry, std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {
int32_t injectionResult;
std::string reason;
@@ -1244,7 +1240,7 @@
}
int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
- const MotionEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
+ const MotionEntry* entry, std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
bool* outConflictingPointerActions) {
enum InjectionPermission {
INJECTION_PERMISSION_UNKNOWN,
@@ -1460,8 +1456,7 @@
// is at least one touched foreground window.
{
bool haveForegroundWindow = false;
- for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
- const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
+ for (const TouchedWindow& touchedWindow : mTempTouchState.windows) {
if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {
haveForegroundWindow = true;
if (! checkInjectionPermission(touchedWindow.windowHandle,
@@ -1491,8 +1486,7 @@
sp<InputWindowHandle> foregroundWindowHandle =
mTempTouchState.getFirstForegroundWindowHandle();
const int32_t foregroundWindowUid = foregroundWindowHandle->getInfo()->ownerUid;
- for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
- const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
+ for (const TouchedWindow& touchedWindow : mTempTouchState.windows) {
if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
sp<InputWindowHandle> inputWindowHandle = touchedWindow.windowHandle;
if (inputWindowHandle->getInfo()->ownerUid != foregroundWindowUid) {
@@ -1504,8 +1498,7 @@
}
// Ensure all touched foreground windows are ready for new input.
- for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
- const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
+ for (const TouchedWindow& touchedWindow : mTempTouchState.windows) {
if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {
// Check whether the window is ready for more input.
std::string reason = checkWindowReadyForMoreInputLocked(currentTime,
@@ -1528,10 +1521,9 @@
sp<InputWindowHandle> foregroundWindowHandle =
mTempTouchState.getFirstForegroundWindowHandle();
if (foregroundWindowHandle->getInfo()->hasWallpaper) {
- 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 std::vector<sp<InputWindowHandle>> windowHandles =
+ getWindowHandlesLocked(displayId);
+ for (const sp<InputWindowHandle>& windowHandle : windowHandles) {
const InputWindowInfo* info = windowHandle->getInfo();
if (info->displayId == displayId
&& windowHandle->getInfo()->layoutParamsType
@@ -1549,8 +1541,7 @@
// Success! Output targets.
injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
- for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
- const TouchedWindow& touchedWindow = mTempTouchState.windows.itemAt(i);
+ for (const TouchedWindow& touchedWindow : mTempTouchState.windows) {
addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags,
touchedWindow.pointerIds, inputTargets);
}
@@ -1613,11 +1604,11 @@
uint32_t pointerId = entry->pointerProperties[pointerIndex].id;
for (size_t i = 0; i < mTempTouchState.windows.size(); ) {
- TouchedWindow& touchedWindow = mTempTouchState.windows.editItemAt(i);
+ TouchedWindow& touchedWindow = mTempTouchState.windows[i];
if (touchedWindow.targetFlags & InputTarget::FLAG_SPLIT) {
touchedWindow.pointerIds.clearBit(pointerId);
if (touchedWindow.pointerIds.isEmpty()) {
- mTempTouchState.windows.removeAt(i);
+ mTempTouchState.windows.erase(mTempTouchState.windows.begin() + i);
continue;
}
}
@@ -1664,17 +1655,15 @@
}
void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
- int32_t targetFlags, BitSet32 pointerIds, Vector<InputTarget>& inputTargets) {
+ int32_t targetFlags, BitSet32 pointerIds, std::vector<InputTarget>& inputTargets) {
sp<InputChannel> inputChannel = getInputChannelLocked(windowHandle->getToken());
if (inputChannel == nullptr) {
ALOGW("Window %s already unregistered input channel", windowHandle->getName().c_str());
return;
}
- inputTargets.push();
-
const InputWindowInfo* windowInfo = windowHandle->getInfo();
- InputTarget& target = inputTargets.editTop();
+ InputTarget target;
target.inputChannel = inputChannel;
target.flags = targetFlags;
target.xOffset = - windowInfo->frameLeft;
@@ -1683,26 +1672,26 @@
target.windowXScale = windowInfo->windowXScale;
target.windowYScale = windowInfo->windowYScale;
target.pointerIds = pointerIds;
+ inputTargets.push_back(target);
}
-void InputDispatcher::addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets,
+void InputDispatcher::addMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets,
int32_t displayId, float xOffset, float yOffset) {
- std::unordered_map<int32_t, Vector<sp<InputChannel>>>::const_iterator it =
+ std::unordered_map<int32_t, std::vector<sp<InputChannel>>>::const_iterator it =
mMonitoringChannelsByDisplay.find(displayId);
if (it != mMonitoringChannelsByDisplay.end()) {
- const Vector<sp<InputChannel>>& monitoringChannels = it->second;
+ const std::vector<sp<InputChannel>>& monitoringChannels = it->second;
const size_t numChannels = monitoringChannels.size();
for (size_t i = 0; i < numChannels; i++) {
- inputTargets.push();
-
- InputTarget& target = inputTargets.editTop();
+ InputTarget target;
target.inputChannel = monitoringChannels[i];
target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
target.xOffset = xOffset;
target.yOffset = yOffset;
target.pointerIds.clear();
target.globalScaleFactor = 1.0f;
+ inputTargets.push_back(target);
}
} else {
// If there is no monitor channel registered or all monitor channel unregistered,
@@ -1735,10 +1724,8 @@
bool InputDispatcher::isWindowObscuredAtPointLocked(
const sp<InputWindowHandle>& windowHandle, int32_t x, int32_t y) const {
int32_t displayId = windowHandle->getInfo()->displayId;
- const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
- size_t numWindows = windowHandles.size();
- for (size_t i = 0; i < numWindows; i++) {
- sp<InputWindowHandle> otherHandle = windowHandles.itemAt(i);
+ const std::vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
+ for (const sp<InputWindowHandle>& otherHandle : windowHandles) {
if (otherHandle == windowHandle) {
break;
}
@@ -1756,11 +1743,9 @@
bool InputDispatcher::isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const {
int32_t displayId = windowHandle->getInfo()->displayId;
- const Vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
+ const std::vector<sp<InputWindowHandle>> windowHandles = getWindowHandlesLocked(displayId);
const InputWindowInfo* windowInfo = windowHandle->getInfo();
- size_t numWindows = windowHandles.size();
- for (size_t i = 0; i < numWindows; i++) {
- sp<InputWindowHandle> otherHandle = windowHandles.itemAt(i);
+ for (const sp<InputWindowHandle>& otherHandle : windowHandles) {
if (otherHandle == windowHandle) {
break;
}
@@ -1973,17 +1958,17 @@
bool wasEmpty = connection->outboundQueue.isEmpty();
// Enqueue dispatch entries for the requested modes.
- enqueueDispatchEntry(connection, eventEntry, inputTarget,
+ enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
- enqueueDispatchEntry(connection, eventEntry, inputTarget,
+ enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
- enqueueDispatchEntry(connection, eventEntry, inputTarget,
+ enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
- enqueueDispatchEntry(connection, eventEntry, inputTarget,
+ enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_IS);
- enqueueDispatchEntry(connection, eventEntry, inputTarget,
+ enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
- enqueueDispatchEntry(connection, eventEntry, inputTarget,
+ enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);
// If the outbound queue was previously empty, start the dispatch cycle going.
@@ -1992,7 +1977,7 @@
}
}
-void InputDispatcher::enqueueDispatchEntry(
+void InputDispatcher::enqueueDispatchEntryLocked(
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
int32_t dispatchMode) {
int32_t inputTargetFlags = inputTarget->flags;
@@ -2069,6 +2054,10 @@
delete dispatchEntry;
return; // skip the inconsistent event
}
+
+ dispatchPointerDownOutsideFocusIfNecessary(motionEntry->source,
+ dispatchEntry->resolvedAction, inputTarget->inputChannel->getToken());
+
break;
}
}
@@ -2081,6 +2070,32 @@
// Enqueue the dispatch entry.
connection->outboundQueue.enqueueAtTail(dispatchEntry);
traceOutboundQueueLength(connection);
+
+}
+
+void InputDispatcher::dispatchPointerDownOutsideFocusIfNecessary(uint32_t source, int32_t action,
+ const sp<IBinder>& newToken) {
+ int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK;
+ if (source != AINPUT_SOURCE_CLASS_POINTER || maskedAction != AMOTION_EVENT_ACTION_DOWN) {
+ return;
+ }
+
+ sp<InputWindowHandle> inputWindowHandle = getWindowHandleLocked(newToken);
+ if (inputWindowHandle == nullptr) {
+ return;
+ }
+
+ int32_t displayId = inputWindowHandle->getInfo()->displayId;
+ sp<InputWindowHandle> focusedWindowHandle =
+ getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
+
+ bool hasFocusChanged = !focusedWindowHandle || focusedWindowHandle->getToken() != newToken;
+
+ if (!hasFocusChanged) {
+ return;
+ }
+
+ // Dispatch onPointerDownOutsideFocus to the policy.
}
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
@@ -2333,7 +2348,7 @@
void InputDispatcher::synthesizeCancelationEventsForMonitorsLocked (
const CancelationOptions& options) {
for (auto& it : mMonitoringChannelsByDisplay) {
- const Vector<sp<InputChannel>>& monitoringChannels = it.second;
+ const std::vector<sp<InputChannel>>& monitoringChannels = it.second;
const size_t numChannels = monitoringChannels.size();
for (size_t i = 0; i < numChannels; i++) {
synthesizeCancelationEventsForInputChannelLocked(monitoringChannels[i], options);
@@ -2358,11 +2373,11 @@
nsecs_t currentTime = now();
- Vector<EventEntry*> cancelationEvents;
+ std::vector<EventEntry*> cancelationEvents;
connection->inputState.synthesizeCancelationEvents(currentTime,
cancelationEvents, options);
- if (!cancelationEvents.isEmpty()) {
+ if (!cancelationEvents.empty()) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
ALOGD("channel '%s' ~ Synthesized %zu cancelation events to bring channel back in sync "
"with reality: %s, mode=%d.",
@@ -2370,7 +2385,7 @@
options.reason, options.mode);
#endif
for (size_t i = 0; i < cancelationEvents.size(); i++) {
- EventEntry* cancelationEventEntry = cancelationEvents.itemAt(i);
+ EventEntry* cancelationEventEntry = cancelationEvents[i];
switch (cancelationEventEntry->type) {
case EventEntry::TYPE_KEY:
logOutboundKeyDetails("cancel - ",
@@ -2400,7 +2415,7 @@
target.inputChannel = connection->inputChannel;
target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
- enqueueDispatchEntry(connection, cancelationEventEntry, // increments ref
+ enqueueDispatchEntryLocked(connection, cancelationEventEntry, // increments ref
&target, InputTarget::FLAG_DISPATCH_AS_IS);
cancelationEventEntry->release();
@@ -3011,24 +3026,23 @@
}
}
-Vector<sp<InputWindowHandle>> InputDispatcher::getWindowHandlesLocked(int32_t displayId) const {
- std::unordered_map<int32_t, Vector<sp<InputWindowHandle>>>::const_iterator it =
+std::vector<sp<InputWindowHandle>> InputDispatcher::getWindowHandlesLocked(
+ int32_t displayId) const {
+ std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>>::const_iterator it =
mWindowHandlesByDisplay.find(displayId);
if(it != mWindowHandlesByDisplay.end()) {
return it->second;
}
// Return an empty one if nothing found.
- return Vector<sp<InputWindowHandle>>();
+ return std::vector<sp<InputWindowHandle>>();
}
sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked(
const sp<IBinder>& windowHandleToken) const {
for (auto& it : mWindowHandlesByDisplay) {
- const Vector<sp<InputWindowHandle>> windowHandles = it.second;
- size_t numWindows = windowHandles.size();
- for (size_t i = 0; i < numWindows; i++) {
- const sp<InputWindowHandle>& windowHandle = windowHandles.itemAt(i);
+ const std::vector<sp<InputWindowHandle>> windowHandles = it.second;
+ for (const sp<InputWindowHandle>& windowHandle : windowHandles) {
if (windowHandle->getToken() == windowHandleToken) {
return windowHandle;
}
@@ -3039,11 +3053,9 @@
bool InputDispatcher::hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const {
for (auto& it : mWindowHandlesByDisplay) {
- const Vector<sp<InputWindowHandle>> windowHandles = it.second;
- size_t numWindows = windowHandles.size();
- for (size_t i = 0; i < numWindows; i++) {
- if (windowHandles.itemAt(i)->getToken()
- == windowHandle->getToken()) {
+ const std::vector<sp<InputWindowHandle>> windowHandles = it.second;
+ for (const sp<InputWindowHandle>& handle : windowHandles) {
+ if (handle->getToken() == windowHandle->getToken()) {
if (windowHandle->getInfo()->displayId != it.first) {
ALOGE("Found window %s in display %" PRId32
", but it should belong to display %" PRId32,
@@ -3072,7 +3084,7 @@
* For focused handle, check if need to change and send a cancel event to previous one.
* For removed handle, check if need to send a cancel event if already in touch.
*/
-void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle>>& inputWindowHandles,
+void InputDispatcher::setInputWindows(const std::vector<sp<InputWindowHandle>>& inputWindowHandles,
int32_t displayId, const sp<ISetInputWindowsListener>& setInputWindowsListener) {
#if DEBUG_FOCUS
ALOGD("setInputWindows displayId=%" PRId32, displayId);
@@ -3081,28 +3093,27 @@
std::scoped_lock _l(mLock);
// Copy old handles for release if they are no longer present.
- const Vector<sp<InputWindowHandle>> oldWindowHandles = getWindowHandlesLocked(displayId);
+ const std::vector<sp<InputWindowHandle>> oldWindowHandles =
+ getWindowHandlesLocked(displayId);
sp<InputWindowHandle> newFocusedWindowHandle = nullptr;
bool foundHoveredWindow = false;
- if (inputWindowHandles.isEmpty()) {
+ if (inputWindowHandles.empty()) {
// Remove all handles on a display if there are no windows left.
mWindowHandlesByDisplay.erase(displayId);
} else {
// Since we compare the pointer of input window handles across window updates, we need
// to make sure the handle object for the same window stays unchanged across updates.
- const Vector<sp<InputWindowHandle>>& oldHandles = mWindowHandlesByDisplay[displayId];
+ const std::vector<sp<InputWindowHandle>>& oldHandles =
+ mWindowHandlesByDisplay[displayId];
std::unordered_map<sp<IBinder>, sp<InputWindowHandle>, IBinderHash> oldHandlesByTokens;
- for (size_t i = 0; i < oldHandles.size(); i++) {
- const sp<InputWindowHandle>& handle = oldHandles.itemAt(i);
+ for (const sp<InputWindowHandle>& handle : oldHandles) {
oldHandlesByTokens[handle->getToken()] = handle;
}
- const size_t numWindows = inputWindowHandles.size();
- Vector<sp<InputWindowHandle>> newHandles;
- for (size_t i = 0; i < numWindows; i++) {
- const sp<InputWindowHandle>& handle = inputWindowHandles.itemAt(i);
+ std::vector<sp<InputWindowHandle>> newHandles;
+ for (const sp<InputWindowHandle>& handle : inputWindowHandles) {
if (!handle->updateInfo() || (getInputChannelLocked(handle->getToken()) == nullptr
&& handle->getInfo()->portalToDisplayId == ADISPLAY_ID_NONE)) {
ALOGE("Window handle %s has no registered input channel",
@@ -3127,8 +3138,7 @@
}
}
- for (size_t i = 0; i < newHandles.size(); i++) {
- const sp<InputWindowHandle>& windowHandle = newHandles.itemAt(i);
+ for (const sp<InputWindowHandle>& windowHandle : newHandles) {
// Set newFocusedWindowHandle to the top most focused window instead of the last one
if (!newFocusedWindowHandle && windowHandle->getInfo()->hasFocus
&& windowHandle->getInfo()->visible) {
@@ -3184,7 +3194,7 @@
if (stateIndex >= 0) {
TouchState& state = mTouchStatesByDisplay.editValueAt(stateIndex);
for (size_t i = 0; i < state.windows.size(); ) {
- TouchedWindow& touchedWindow = state.windows.editItemAt(i);
+ TouchedWindow& touchedWindow = state.windows[i];
if (!hasWindowHandleLocked(touchedWindow.windowHandle)) {
#if DEBUG_FOCUS
ALOGD("Touched window was removed: %s in display %" PRId32,
@@ -3198,7 +3208,7 @@
synthesizeCancelationEventsForInputChannelLocked(
touchedInputChannel, options);
}
- state.windows.removeAt(i);
+ state.windows.erase(state.windows.begin() + i);
} else {
++i;
}
@@ -3209,9 +3219,7 @@
// This ensures that unused input channels are released promptly.
// Otherwise, they might stick around until the window handle is destroyed
// which might not happen until the next GC.
- size_t numWindows = oldWindowHandles.size();
- for (size_t i = 0; i < numWindows; i++) {
- const sp<InputWindowHandle>& oldWindowHandle = oldWindowHandles.itemAt(i);
+ for (const sp<InputWindowHandle>& oldWindowHandle : oldWindowHandles) {
if (!hasWindowHandleLocked(oldWindowHandle)) {
#if DEBUG_FOCUS
ALOGD("Window went away: %s", oldWindowHandle->getName().c_str());
@@ -3243,13 +3251,11 @@
if (oldFocusedApplicationHandle != inputApplicationHandle) {
if (oldFocusedApplicationHandle != nullptr) {
resetANRTimeoutsLocked();
- oldFocusedApplicationHandle->releaseInfo();
}
mFocusedApplicationHandlesByDisplay[displayId] = inputApplicationHandle;
}
} else if (oldFocusedApplicationHandle != nullptr) {
resetANRTimeoutsLocked();
- oldFocusedApplicationHandle->releaseInfo();
oldFocusedApplicationHandle.clear();
mFocusedApplicationHandlesByDisplay.erase(displayId);
}
@@ -3415,7 +3421,7 @@
int32_t oldTargetFlags = touchedWindow.targetFlags;
BitSet32 pointerIds = touchedWindow.pointerIds;
- state.windows.removeAt(i);
+ state.windows.erase(state.windows.begin() + i);
int32_t newTargetFlags = oldTargetFlags
& (InputTarget::FLAG_FOREGROUND
@@ -3531,7 +3537,7 @@
dump += StringPrintf(INDENT2 "%d: down=%s, split=%s, deviceId=%d, source=0x%08x\n",
state.displayId, toString(state.down), toString(state.split),
state.deviceId, state.source);
- if (!state.windows.isEmpty()) {
+ if (!state.windows.empty()) {
dump += INDENT3 "Windows:\n";
for (size_t i = 0; i < state.windows.size(); i++) {
const TouchedWindow& touchedWindow = state.windows[i];
@@ -3543,10 +3549,10 @@
} else {
dump += INDENT3 "Windows: <none>\n";
}
- if (!state.portalWindows.isEmpty()) {
+ if (!state.portalWindows.empty()) {
dump += INDENT3 "Portal windows:\n";
for (size_t i = 0; i < state.portalWindows.size(); i++) {
- const sp<InputWindowHandle> portalWindowHandle = state.portalWindows.itemAt(i);
+ const sp<InputWindowHandle> portalWindowHandle = state.portalWindows[i];
dump += StringPrintf(INDENT4 "%zu: name='%s'\n",
i, portalWindowHandle->getName().c_str());
}
@@ -3558,12 +3564,12 @@
if (!mWindowHandlesByDisplay.empty()) {
for (auto& it : mWindowHandlesByDisplay) {
- const Vector<sp<InputWindowHandle>> windowHandles = it.second;
+ const std::vector<sp<InputWindowHandle>> windowHandles = it.second;
dump += StringPrintf(INDENT "Display: %" PRId32 "\n", it.first);
- if (!windowHandles.isEmpty()) {
+ if (!windowHandles.empty()) {
dump += INDENT2 "Windows:\n";
for (size_t i = 0; i < windowHandles.size(); i++) {
- const sp<InputWindowHandle>& windowHandle = windowHandles.itemAt(i);
+ const sp<InputWindowHandle>& windowHandle = windowHandles[i];
const InputWindowInfo* windowInfo = windowHandle->getInfo();
dump += StringPrintf(INDENT3 "%zu: name='%s', displayId=%d, "
@@ -3600,7 +3606,7 @@
if (!mMonitoringChannelsByDisplay.empty()) {
for (auto& it : mMonitoringChannelsByDisplay) {
- const Vector<sp<InputChannel>>& monitoringChannels = it.second;
+ const std::vector<sp<InputChannel>>& monitoringChannels = it.second;
dump += StringPrintf(INDENT "MonitoringChannels in display %" PRId32 ":\n", it.first);
const size_t numChannels = monitoringChannels.size();
for (size_t i = 0; i < numChannels; i++) {
@@ -3754,9 +3760,9 @@
// Store monitor channel by displayId.
if (monitor) {
- Vector<sp<InputChannel>>& monitoringChannels =
+ std::vector<sp<InputChannel>>& monitoringChannels =
mMonitoringChannelsByDisplay[displayId];
- monitoringChannels.push(inputChannel);
+ monitoringChannels.push_back(inputChannel);
}
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
@@ -3817,11 +3823,11 @@
void InputDispatcher::removeMonitorChannelLocked(const sp<InputChannel>& inputChannel) {
for (auto it = mMonitoringChannelsByDisplay.begin();
it != mMonitoringChannelsByDisplay.end(); ) {
- Vector<sp<InputChannel>>& monitoringChannels = it->second;
+ std::vector<sp<InputChannel>>& monitoringChannels = it->second;
const size_t numChannels = monitoringChannels.size();
for (size_t i = 0; i < numChannels; i++) {
if (monitoringChannels[i] == inputChannel) {
- monitoringChannels.removeAt(i);
+ monitoringChannels.erase(monitoringChannels.begin() + i);
break;
}
}
@@ -4495,13 +4501,12 @@
}
bool InputDispatcher::InputState::isNeutral() const {
- return mKeyMementos.isEmpty() && mMotionMementos.isEmpty();
+ return mKeyMementos.empty() && mMotionMementos.empty();
}
bool InputDispatcher::InputState::isHovering(int32_t deviceId, uint32_t source,
int32_t displayId) const {
- for (size_t i = 0; i < mMotionMementos.size(); i++) {
- const MotionMemento& memento = mMotionMementos.itemAt(i);
+ for (const MotionMemento& memento : mMotionMementos) {
if (memento.deviceId == deviceId
&& memento.source == source
&& memento.displayId == displayId
@@ -4527,7 +4532,7 @@
}
ssize_t index = findKeyMemento(entry);
if (index >= 0) {
- mKeyMementos.removeAt(index);
+ mKeyMementos.erase(mKeyMementos.begin() + index);
return true;
}
/* FIXME: We can't just drop the key up event because that prevents creating
@@ -4552,7 +4557,7 @@
case AKEY_EVENT_ACTION_DOWN: {
ssize_t index = findKeyMemento(entry);
if (index >= 0) {
- mKeyMementos.removeAt(index);
+ mKeyMementos.erase(mKeyMementos.begin() + index);
}
addKeyMemento(entry, flags);
return true;
@@ -4571,7 +4576,7 @@
case AMOTION_EVENT_ACTION_CANCEL: {
ssize_t index = findMotionMemento(entry, false /*hovering*/);
if (index >= 0) {
- mMotionMementos.removeAt(index);
+ mMotionMementos.erase(mMotionMementos.begin() + index);
return true;
}
#if DEBUG_OUTBOUND_EVENT_DETAILS
@@ -4585,7 +4590,7 @@
case AMOTION_EVENT_ACTION_DOWN: {
ssize_t index = findMotionMemento(entry, false /*hovering*/);
if (index >= 0) {
- mMotionMementos.removeAt(index);
+ mMotionMementos.erase(mMotionMementos.begin() + index);
}
addMotionMemento(entry, flags, false /*hovering*/);
return true;
@@ -4610,9 +4615,9 @@
// anything generating fallback events (e.g. DPad keys for joystick movements).
if (index >= 0) {
if (entry->pointerCoords[0].isEmpty()) {
- mMotionMementos.removeAt(index);
+ mMotionMementos.erase(mMotionMementos.begin() + index);
} else {
- MotionMemento& memento = mMotionMementos.editItemAt(index);
+ MotionMemento& memento = mMotionMementos[index];
memento.setPointers(entry);
}
} else if (!entry->pointerCoords[0].isEmpty()) {
@@ -4623,7 +4628,7 @@
return true;
}
if (index >= 0) {
- MotionMemento& memento = mMotionMementos.editItemAt(index);
+ MotionMemento& memento = mMotionMementos[index];
memento.setPointers(entry);
return true;
}
@@ -4638,7 +4643,7 @@
case AMOTION_EVENT_ACTION_HOVER_EXIT: {
ssize_t index = findMotionMemento(entry, true /*hovering*/);
if (index >= 0) {
- mMotionMementos.removeAt(index);
+ mMotionMementos.erase(mMotionMementos.begin() + index);
return true;
}
#if DEBUG_OUTBOUND_EVENT_DETAILS
@@ -4653,7 +4658,7 @@
case AMOTION_EVENT_ACTION_HOVER_MOVE: {
ssize_t index = findMotionMemento(entry, true /*hovering*/);
if (index >= 0) {
- mMotionMementos.removeAt(index);
+ mMotionMementos.erase(mMotionMementos.begin() + index);
}
addMotionMemento(entry, flags, true /*hovering*/);
return true;
@@ -4666,7 +4671,7 @@
ssize_t InputDispatcher::InputState::findKeyMemento(const KeyEntry* entry) const {
for (size_t i = 0; i < mKeyMementos.size(); i++) {
- const KeyMemento& memento = mKeyMementos.itemAt(i);
+ const KeyMemento& memento = mKeyMementos[i];
if (memento.deviceId == entry->deviceId
&& memento.source == entry->source
&& memento.displayId == entry->displayId
@@ -4681,7 +4686,7 @@
ssize_t InputDispatcher::InputState::findMotionMemento(const MotionEntry* entry,
bool hovering) const {
for (size_t i = 0; i < mMotionMementos.size(); i++) {
- const MotionMemento& memento = mMotionMementos.itemAt(i);
+ const MotionMemento& memento = mMotionMementos[i];
if (memento.deviceId == entry->deviceId
&& memento.source == entry->source
&& memento.displayId == entry->displayId
@@ -4693,8 +4698,7 @@
}
void InputDispatcher::InputState::addKeyMemento(const KeyEntry* entry, int32_t flags) {
- mKeyMementos.push();
- KeyMemento& memento = mKeyMementos.editTop();
+ KeyMemento memento;
memento.deviceId = entry->deviceId;
memento.source = entry->source;
memento.displayId = entry->displayId;
@@ -4704,12 +4708,12 @@
memento.flags = flags;
memento.downTime = entry->downTime;
memento.policyFlags = entry->policyFlags;
+ mKeyMementos.push_back(memento);
}
void InputDispatcher::InputState::addMotionMemento(const MotionEntry* entry,
int32_t flags, bool hovering) {
- mMotionMementos.push();
- MotionMemento& memento = mMotionMementos.editTop();
+ MotionMemento memento;
memento.deviceId = entry->deviceId;
memento.source = entry->source;
memento.displayId = entry->displayId;
@@ -4720,6 +4724,7 @@
memento.setPointers(entry);
memento.hovering = hovering;
memento.policyFlags = entry->policyFlags;
+ mMotionMementos.push_back(memento);
}
void InputDispatcher::InputState::MotionMemento::setPointers(const MotionEntry* entry) {
@@ -4731,23 +4736,21 @@
}
void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTime,
- Vector<EventEntry*>& outEvents, const CancelationOptions& options) {
- for (size_t i = 0; i < mKeyMementos.size(); i++) {
- const KeyMemento& memento = mKeyMementos.itemAt(i);
+ std::vector<EventEntry*>& outEvents, const CancelationOptions& options) {
+ for (KeyMemento& memento : mKeyMementos) {
if (shouldCancelKey(memento, options)) {
- outEvents.push(new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime,
+ outEvents.push_back(new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime,
memento.deviceId, memento.source, memento.displayId, memento.policyFlags,
AKEY_EVENT_ACTION_UP, memento.flags | AKEY_EVENT_FLAG_CANCELED,
memento.keyCode, memento.scanCode, memento.metaState, 0, memento.downTime));
}
}
- for (size_t i = 0; i < mMotionMementos.size(); i++) {
- const MotionMemento& memento = mMotionMementos.itemAt(i);
+ for (const MotionMemento& memento : mMotionMementos) {
if (shouldCancelMotion(memento, options)) {
const int32_t action = memento.hovering ?
AMOTION_EVENT_ACTION_HOVER_EXIT : AMOTION_EVENT_ACTION_CANCEL;
- outEvents.push(new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime,
+ outEvents.push_back(new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime,
memento.deviceId, memento.source, memento.displayId, memento.policyFlags,
action, 0 /*actionButton*/, memento.flags, AMETA_NONE, 0 /*buttonState*/,
MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
@@ -4766,19 +4769,19 @@
void InputDispatcher::InputState::copyPointerStateTo(InputState& other) const {
for (size_t i = 0; i < mMotionMementos.size(); i++) {
- const MotionMemento& memento = mMotionMementos.itemAt(i);
+ const MotionMemento& memento = mMotionMementos[i];
if (memento.source & AINPUT_SOURCE_CLASS_POINTER) {
for (size_t j = 0; j < other.mMotionMementos.size(); ) {
- const MotionMemento& otherMemento = other.mMotionMementos.itemAt(j);
+ const MotionMemento& otherMemento = other.mMotionMementos[j];
if (memento.deviceId == otherMemento.deviceId
&& memento.source == otherMemento.source
&& memento.displayId == otherMemento.displayId) {
- other.mMotionMementos.removeAt(j);
+ other.mMotionMementos.erase(other.mMotionMementos.begin() + j);
} else {
j += 1;
}
}
- other.mMotionMementos.push(memento);
+ other.mMotionMementos.push_back(memento);
}
}
}
@@ -4940,7 +4943,7 @@
}
for (size_t i = 0; i < windows.size(); i++) {
- TouchedWindow& touchedWindow = windows.editItemAt(i);
+ TouchedWindow& touchedWindow = windows[i];
if (touchedWindow.windowHandle == windowHandle) {
touchedWindow.targetFlags |= targetFlags;
if (targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) {
@@ -4951,19 +4954,17 @@
}
}
- windows.push();
-
- TouchedWindow& touchedWindow = windows.editTop();
+ TouchedWindow touchedWindow;
touchedWindow.windowHandle = windowHandle;
touchedWindow.targetFlags = targetFlags;
touchedWindow.pointerIds = pointerIds;
+ windows.push_back(touchedWindow);
}
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) {
+ if (portalWindows[i] == windowHandle) {
return;
}
}
@@ -4972,8 +4973,8 @@
void InputDispatcher::TouchState::removeWindow(const sp<InputWindowHandle>& windowHandle) {
for (size_t i = 0; i < windows.size(); i++) {
- if (windows.itemAt(i).windowHandle == windowHandle) {
- windows.removeAt(i);
+ if (windows[i].windowHandle == windowHandle) {
+ windows.erase(windows.begin() + i);
return;
}
}
@@ -4981,8 +4982,8 @@
void InputDispatcher::TouchState::removeWindowByToken(const sp<IBinder>& token) {
for (size_t i = 0; i < windows.size(); i++) {
- if (windows.itemAt(i).windowHandle->getToken() == token) {
- windows.removeAt(i);
+ if (windows[i].windowHandle->getToken() == token) {
+ windows.erase(windows.begin() + i);
return;
}
}
@@ -4990,21 +4991,21 @@
void InputDispatcher::TouchState::filterNonAsIsTouchWindows() {
for (size_t i = 0 ; i < windows.size(); ) {
- TouchedWindow& window = windows.editItemAt(i);
+ TouchedWindow& window = windows[i];
if (window.targetFlags & (InputTarget::FLAG_DISPATCH_AS_IS
| InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER)) {
window.targetFlags &= ~InputTarget::FLAG_DISPATCH_MASK;
window.targetFlags |= InputTarget::FLAG_DISPATCH_AS_IS;
i += 1;
} else {
- windows.removeAt(i);
+ windows.erase(windows.begin() + i);
}
}
}
sp<InputWindowHandle> InputDispatcher::TouchState::getFirstForegroundWindowHandle() const {
for (size_t i = 0; i < windows.size(); i++) {
- const TouchedWindow& window = windows.itemAt(i);
+ const TouchedWindow& window = windows[i];
if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
return window.windowHandle;
}
@@ -5015,8 +5016,7 @@
bool InputDispatcher::TouchState::isSlippery() const {
// Must have exactly one foreground window.
bool haveSlipperyForegroundWindow = false;
- for (size_t i = 0; i < windows.size(); i++) {
- const TouchedWindow& window = windows.itemAt(i);
+ for (const TouchedWindow& window : windows) {
if (window.targetFlags & InputTarget::FLAG_FOREGROUND) {
if (haveSlipperyForegroundWindow
|| !(window.windowHandle->getInfo()->layoutParamsFlags
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 24ae32f..3735a0b 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -23,8 +23,6 @@
#include <input/InputTransport.h>
#include <input/InputWindow.h>
#include <input/ISetInputWindowsListener.h>
-#include <utils/KeyedVector.h>
-#include <utils/Vector.h>
#include <utils/threads.h>
#include <utils/Timers.h>
#include <utils/RefBase.h>
@@ -315,7 +313,7 @@
*
* This method may be called on any thread (usually by the input manager).
*/
- virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles,
+ virtual void setInputWindows(const std::vector<sp<InputWindowHandle> >& inputWindowHandles,
int32_t displayId,
const sp<ISetInputWindowsListener>& setInputWindowsListener = nullptr) = 0;
@@ -407,7 +405,7 @@
int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
uint32_t policyFlags);
- virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles,
+ virtual void setInputWindows(const std::vector<sp<InputWindowHandle> >& inputWindowHandles,
int32_t displayId,
const sp<ISetInputWindowsListener>& setInputWindowsListener = nullptr);
virtual void setFocusedApplication(int32_t displayId,
@@ -762,7 +760,7 @@
// Synthesizes cancelation events for the current state and resets the tracked state.
void synthesizeCancelationEvents(nsecs_t currentTime,
- Vector<EventEntry*>& outEvents, const CancelationOptions& options);
+ std::vector<EventEntry*>& outEvents, const CancelationOptions& options);
// Clears the current state.
void clear();
@@ -815,8 +813,8 @@
void setPointers(const MotionEntry* entry);
};
- Vector<KeyMemento> mKeyMementos;
- Vector<MotionMemento> mMotionMementos;
+ std::vector<KeyMemento> mKeyMementos;
+ std::vector<MotionMemento> mMotionMementos;
KeyedVector<int32_t, int32_t> mFallbackKeys;
ssize_t findKeyMemento(const KeyEntry* entry) const;
@@ -941,7 +939,7 @@
ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel) REQUIRES(mLock);
// Input channels that will receive a copy of all input events sent to the provided display.
- std::unordered_map<int32_t, Vector<sp<InputChannel>>> mMonitoringChannelsByDisplay
+ std::unordered_map<int32_t, std::vector<sp<InputChannel>>> mMonitoringChannelsByDisplay
GUARDED_BY(mLock);
// Event injection and synchronization.
@@ -998,10 +996,11 @@
bool mDispatchFrozen GUARDED_BY(mLock);
bool mInputFilterEnabled GUARDED_BY(mLock);
- std::unordered_map<int32_t, Vector<sp<InputWindowHandle>>> mWindowHandlesByDisplay
+ std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>> mWindowHandlesByDisplay
GUARDED_BY(mLock);
// Get window handles by display, return an empty vector if not found.
- Vector<sp<InputWindowHandle>> getWindowHandlesLocked(int32_t displayId) const REQUIRES(mLock);
+ std::vector<sp<InputWindowHandle>> getWindowHandlesLocked(int32_t displayId) const
+ REQUIRES(mLock);
sp<InputWindowHandle> getWindowHandleLocked(const sp<IBinder>& windowHandleToken) const
REQUIRES(mLock);
sp<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const REQUIRES(mLock);
@@ -1023,12 +1022,12 @@
int32_t deviceId; // id of the device that is currently down, others are rejected
uint32_t source; // source of the device that is current down, others are rejected
int32_t displayId; // id to the display that currently has a touch, others are rejected
- Vector<TouchedWindow> windows;
+ std::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;
+ std::vector<sp<InputWindowHandle>> portalWindows;
TouchState();
~TouchState();
@@ -1069,7 +1068,7 @@
nsecs_t currentTime, MotionEntry* entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) REQUIRES(mLock);
void dispatchEventLocked(nsecs_t currentTime, EventEntry* entry,
- const Vector<InputTarget>& inputTargets) REQUIRES(mLock);
+ const std::vector<InputTarget>& inputTargets) REQUIRES(mLock);
void logOutboundKeyDetails(const char* prefix, const KeyEntry* entry);
void logOutboundMotionDetails(const char* prefix, const MotionEntry* entry);
@@ -1105,15 +1104,15 @@
int32_t getTargetDisplayId(const EventEntry* entry);
int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry,
- Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) REQUIRES(mLock);
+ std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) REQUIRES(mLock);
int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry,
- Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
+ std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
bool* outConflictingPointerActions) REQUIRES(mLock);
void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
- int32_t targetFlags, BitSet32 pointerIds, Vector<InputTarget>& inputTargets)
+ int32_t targetFlags, BitSet32 pointerIds, std::vector<InputTarget>& inputTargets)
REQUIRES(mLock);
- void addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets, int32_t displayId,
+ void addMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, int32_t displayId,
float xOffset = 0, float yOffset = 0) REQUIRES(mLock);
void pokeUserActivityLocked(const EventEntry* eventEntry) REQUIRES(mLock);
@@ -1137,8 +1136,9 @@
EventEntry* eventEntry, const InputTarget* inputTarget) REQUIRES(mLock);
void enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp<Connection>& connection,
EventEntry* eventEntry, const InputTarget* inputTarget) REQUIRES(mLock);
- void enqueueDispatchEntry(const sp<Connection>& connection,
- EventEntry* eventEntry, const InputTarget* inputTarget, int32_t dispatchMode);
+ void enqueueDispatchEntryLocked(const sp<Connection>& connection,
+ EventEntry* eventEntry, const InputTarget* inputTarget, int32_t dispatchMode)
+ REQUIRES(mLock);
void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection)
REQUIRES(mLock);
void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
@@ -1148,6 +1148,9 @@
void drainDispatchQueue(Queue<DispatchEntry>* queue);
void releaseDispatchEntry(DispatchEntry* dispatchEntry);
static int handleReceiveCallback(int fd, int events, void* data);
+ // The action sent should only be of type AMOTION_EVENT_*
+ void dispatchPointerDownOutsideFocusIfNecessary(uint32_t source, int32_t action,
+ const sp<IBinder>& newToken) REQUIRES(mLock);
void synthesizeCancelationEventsForAllConnectionsLocked(
const CancelationOptions& options) REQUIRES(mLock);
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index a403f31..423b69c 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -229,23 +229,23 @@
void QueuedInputListener::notifyConfigurationChanged(
const NotifyConfigurationChangedArgs* args) {
- mArgsQueue.push(new NotifyConfigurationChangedArgs(*args));
+ mArgsQueue.push_back(new NotifyConfigurationChangedArgs(*args));
}
void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
- mArgsQueue.push(new NotifyKeyArgs(*args));
+ mArgsQueue.push_back(new NotifyKeyArgs(*args));
}
void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) {
- mArgsQueue.push(new NotifyMotionArgs(*args));
+ mArgsQueue.push_back(new NotifyMotionArgs(*args));
}
void QueuedInputListener::notifySwitch(const NotifySwitchArgs* args) {
- mArgsQueue.push(new NotifySwitchArgs(*args));
+ mArgsQueue.push_back(new NotifySwitchArgs(*args));
}
void QueuedInputListener::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
- mArgsQueue.push(new NotifyDeviceResetArgs(*args));
+ mArgsQueue.push_back(new NotifyDeviceResetArgs(*args));
}
void QueuedInputListener::flush() {
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index b0157a1..3996cca 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -103,14 +103,14 @@
}
};
-void InputManager::setInputWindows(const Vector<InputWindowInfo>& infos,
+void InputManager::setInputWindows(const std::vector<InputWindowInfo>& infos,
const sp<ISetInputWindowsListener>& setInputWindowsListener) {
- std::unordered_map<int32_t, Vector<sp<InputWindowHandle>>> handlesPerDisplay;
+ std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>> handlesPerDisplay;
- Vector<sp<InputWindowHandle>> handles;
+ std::vector<sp<InputWindowHandle>> handles;
for (const auto& info : infos) {
- handlesPerDisplay.emplace(info.displayId, Vector<sp<InputWindowHandle>>());
- handlesPerDisplay[info.displayId].add(new BinderWindowHandle(info));
+ handlesPerDisplay.emplace(info.displayId, std::vector<sp<InputWindowHandle>>());
+ handlesPerDisplay[info.displayId].push_back(new BinderWindowHandle(info));
}
for (auto const& i : handlesPerDisplay) {
mDispatcher->setInputWindows(i.second, i.first, setInputWindowsListener);
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index ff9a080..e568df5 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -94,7 +94,7 @@
virtual sp<InputClassifierInterface> getClassifier();
virtual sp<InputDispatcherInterface> getDispatcher();
- virtual void setInputWindows(const Vector<InputWindowInfo>& handles,
+ virtual void setInputWindows(const std::vector<InputWindowInfo>& handles,
const sp<ISetInputWindowsListener>& setInputWindowsListener);
virtual void transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken);
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 21ba029..a45b8a5 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -287,7 +287,7 @@
int32_t oldGeneration;
int32_t timeoutMillis;
bool inputDevicesChanged = false;
- Vector<InputDeviceInfo> inputDevices;
+ std::vector<InputDeviceInfo> inputDevices;
{ // acquire lock
AutoMutex _l(mLock);
@@ -590,12 +590,13 @@
refreshConfigurationLocked(InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE);
}
-void InputReader::getExternalStylusDevicesLocked(Vector<InputDeviceInfo>& outDevices) {
+void InputReader::getExternalStylusDevicesLocked(std::vector<InputDeviceInfo>& outDevices) {
for (size_t i = 0; i < mDevices.size(); i++) {
InputDevice* device = mDevices.valueAt(i);
if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS && !device->isIgnored()) {
- outDevices.push();
- device->getDeviceInfo(&outDevices.editTop());
+ InputDeviceInfo info;
+ device->getDeviceInfo(&info);
+ outDevices.push_back(info);
}
}
}
@@ -643,20 +644,21 @@
return ++mGeneration;
}
-void InputReader::getInputDevices(Vector<InputDeviceInfo>& outInputDevices) {
+void InputReader::getInputDevices(std::vector<InputDeviceInfo>& outInputDevices) {
AutoMutex _l(mLock);
getInputDevicesLocked(outInputDevices);
}
-void InputReader::getInputDevicesLocked(Vector<InputDeviceInfo>& outInputDevices) {
+void InputReader::getInputDevicesLocked(std::vector<InputDeviceInfo>& outInputDevices) {
outInputDevices.clear();
size_t numDevices = mDevices.size();
for (size_t i = 0; i < numDevices; i++) {
InputDevice* device = mDevices.valueAt(i);
if (!device->isIgnored()) {
- outInputDevices.push();
- device->getDeviceInfo(&outInputDevices.editTop());
+ InputDeviceInfo info;
+ device->getDeviceInfo(&info);
+ outInputDevices.push_back(info);
}
}
}
@@ -951,7 +953,7 @@
return mReader->bumpGenerationLocked();
}
-void InputReader::ContextImpl::getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices) {
+void InputReader::ContextImpl::getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices) {
// lock is already held by whatever called refreshConfigurationLocked
mReader->getExternalStylusDevicesLocked(outDevices);
}
@@ -1031,11 +1033,11 @@
dump += StringPrintf(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources());
dump += StringPrintf(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType());
- const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
- if (!ranges.isEmpty()) {
+ const std::vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
+ if (!ranges.empty()) {
dump += INDENT2 "Motion Ranges:\n";
for (size_t i = 0; i < ranges.size(); i++) {
- const InputDeviceInfo::MotionRange& range = ranges.itemAt(i);
+ const InputDeviceInfo::MotionRange& range = ranges[i];
const char* label = getAxisLabel(range.axis);
char name[32];
if (label) {
@@ -1059,7 +1061,7 @@
}
void InputDevice::addMapper(InputMapper* mapper) {
- mMappers.add(mapper);
+ mMappers.push_back(mapper);
}
void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) {
@@ -1110,9 +1112,7 @@
}
}
- size_t numMappers = mMappers.size();
- for (size_t i = 0; i < numMappers; i++) {
- InputMapper* mapper = mMappers[i];
+ for (InputMapper* mapper : mMappers) {
mapper->configure(when, config, changes);
mSources |= mapper->getSources();
}
@@ -1120,9 +1120,7 @@
}
void InputDevice::reset(nsecs_t when) {
- size_t numMappers = mMappers.size();
- for (size_t i = 0; i < numMappers; i++) {
- InputMapper* mapper = mMappers[i];
+ for (InputMapper* mapper : mMappers) {
mapper->reset(when);
}
@@ -1137,7 +1135,6 @@
// have side-effects that must be interleaved. For example, joystick movement events and
// gamepad button presses are handled by different mappers but they should be dispatched
// in the order received.
- size_t numMappers = mMappers.size();
for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {
#if DEBUG_RAW_EVENTS
ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%" PRId64,
@@ -1161,8 +1158,7 @@
mDropUntilNextSync = true;
reset(rawEvent->when);
} else {
- for (size_t i = 0; i < numMappers; i++) {
- InputMapper* mapper = mMappers[i];
+ for (InputMapper* mapper : mMappers) {
mapper->process(rawEvent);
}
}
@@ -1171,17 +1167,13 @@
}
void InputDevice::timeoutExpired(nsecs_t when) {
- size_t numMappers = mMappers.size();
- for (size_t i = 0; i < numMappers; i++) {
- InputMapper* mapper = mMappers[i];
+ for (InputMapper* mapper : mMappers) {
mapper->timeoutExpired(when);
}
}
void InputDevice::updateExternalStylusState(const StylusState& state) {
- size_t numMappers = mMappers.size();
- for (size_t i = 0; i < numMappers; i++) {
- InputMapper* mapper = mMappers[i];
+ for (InputMapper* mapper : mMappers) {
mapper->updateExternalStylusState(state);
}
}
@@ -1189,9 +1181,7 @@
void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) {
outDeviceInfo->initialize(mId, mGeneration, mControllerNumber, mIdentifier, mAlias,
mIsExternal, mHasMic);
- size_t numMappers = mMappers.size();
- for (size_t i = 0; i < numMappers; i++) {
- InputMapper* mapper = mMappers[i];
+ for (InputMapper* mapper : mMappers) {
mapper->populateDeviceInfo(outDeviceInfo);
}
}
@@ -1210,9 +1200,7 @@
int32_t InputDevice::getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc) {
int32_t result = AKEY_STATE_UNKNOWN;
- size_t numMappers = mMappers.size();
- for (size_t i = 0; i < numMappers; i++) {
- InputMapper* mapper = mMappers[i];
+ for (InputMapper* mapper : mMappers) {
if (sourcesMatchMask(mapper->getSources(), sourceMask)) {
// If any mapper reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that
// value. Otherwise, return AKEY_STATE_UP as long as one mapper reports it.
@@ -1230,9 +1218,7 @@
bool InputDevice::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
const int32_t* keyCodes, uint8_t* outFlags) {
bool result = false;
- size_t numMappers = mMappers.size();
- for (size_t i = 0; i < numMappers; i++) {
- InputMapper* mapper = mMappers[i];
+ for (InputMapper* mapper : mMappers) {
if (sourcesMatchMask(mapper->getSources(), sourceMask)) {
result |= mapper->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags);
}
@@ -1242,50 +1228,39 @@
void InputDevice::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
int32_t token) {
- size_t numMappers = mMappers.size();
- for (size_t i = 0; i < numMappers; i++) {
- InputMapper* mapper = mMappers[i];
+ for (InputMapper* mapper : mMappers) {
mapper->vibrate(pattern, patternSize, repeat, token);
}
}
void InputDevice::cancelVibrate(int32_t token) {
- size_t numMappers = mMappers.size();
- for (size_t i = 0; i < numMappers; i++) {
- InputMapper* mapper = mMappers[i];
+ for (InputMapper* mapper : mMappers) {
mapper->cancelVibrate(token);
}
}
void InputDevice::cancelTouch(nsecs_t when) {
- size_t numMappers = mMappers.size();
- for (size_t i = 0; i < numMappers; i++) {
- InputMapper* mapper = mMappers[i];
+ for (InputMapper* mapper : mMappers) {
mapper->cancelTouch(when);
}
}
int32_t InputDevice::getMetaState() {
int32_t result = 0;
- size_t numMappers = mMappers.size();
- for (size_t i = 0; i < numMappers; i++) {
- InputMapper* mapper = mMappers[i];
+ for (InputMapper* mapper : mMappers) {
result |= mapper->getMetaState();
}
return result;
}
void InputDevice::updateMetaState(int32_t keyCode) {
- size_t numMappers = mMappers.size();
- for (size_t i = 0; i < numMappers; i++) {
- mMappers[i]->updateMetaState(keyCode);
+ for (InputMapper* mapper : mMappers) {
+ mapper->updateMetaState(keyCode);
}
}
void InputDevice::fadePointer() {
- size_t numMappers = mMappers.size();
- for (size_t i = 0; i < numMappers; i++) {
- InputMapper* mapper = mMappers[i];
+ for (InputMapper* mapper : mMappers) {
mapper->fadePointer();
}
}
@@ -1300,9 +1275,7 @@
}
std::optional<int32_t> InputDevice::getAssociatedDisplay() {
- size_t numMappers = mMappers.size();
- for (size_t i = 0; i < numMappers; i++) {
- InputMapper* mapper = mMappers[i];
+ for (InputMapper* mapper : mMappers) {
std::optional<int32_t> associatedDisplayId = mapper->getAssociatedDisplay();
if (associatedDisplayId) {
return associatedDisplayId;
@@ -2405,7 +2378,7 @@
ssize_t keyDownIndex = findKeyDown(scanCode);
if (keyDownIndex >= 0) {
// key repeat, be sure to use same keycode as before in case of rotation
- keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;
+ keyCode = mKeyDowns[keyDownIndex].keyCode;
} else {
// key down
if ((policyFlags & POLICY_FLAG_VIRTUAL)
@@ -2417,10 +2390,10 @@
mDevice->cancelTouch(when);
}
- mKeyDowns.push();
- KeyDown& keyDown = mKeyDowns.editTop();
+ KeyDown keyDown;
keyDown.keyCode = keyCode;
keyDown.scanCode = scanCode;
+ mKeyDowns.push_back(keyDown);
}
mDownTime = when;
@@ -2429,8 +2402,8 @@
ssize_t keyDownIndex = findKeyDown(scanCode);
if (keyDownIndex >= 0) {
// key up, be sure to use same keycode as before in case of rotation
- keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;
- mKeyDowns.removeAt(size_t(keyDownIndex));
+ keyCode = mKeyDowns[keyDownIndex].keyCode;
+ mKeyDowns.erase(mKeyDowns.begin() + (size_t)keyDownIndex);
} else {
// key was not actually down
ALOGI("Dropping key up from device %s because the key was not down. "
@@ -3316,9 +3289,9 @@
}
void TouchInputMapper::resolveExternalStylusPresence() {
- Vector<InputDeviceInfo> devices;
+ std::vector<InputDeviceInfo> devices;
mContext->getExternalStylusDevices(devices);
- mExternalStylusConnected = !devices.isEmpty();
+ mExternalStylusConnected = !devices.empty();
if (!mExternalStylusConnected) {
resetExternalStylus();
@@ -3967,7 +3940,7 @@
}
void TouchInputMapper::configureVirtualKeys() {
- Vector<VirtualKeyDefinition> virtualKeyDefinitions;
+ std::vector<VirtualKeyDefinition> virtualKeyDefinitions;
getEventHub()->getVirtualKeyDefinitions(getDeviceId(), virtualKeyDefinitions);
mVirtualKeys.clear();
@@ -3976,19 +3949,13 @@
return;
}
- mVirtualKeys.setCapacity(virtualKeyDefinitions.size());
-
int32_t touchScreenLeft = mRawPointerAxes.x.minValue;
int32_t touchScreenTop = mRawPointerAxes.y.minValue;
int32_t touchScreenWidth = mRawPointerAxes.getRawWidth();
int32_t touchScreenHeight = mRawPointerAxes.getRawHeight();
- for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) {
- const VirtualKeyDefinition& virtualKeyDefinition =
- virtualKeyDefinitions[i];
-
- mVirtualKeys.add();
- VirtualKey& virtualKey = mVirtualKeys.editTop();
+ for (const VirtualKeyDefinition& virtualKeyDefinition : virtualKeyDefinitions) {
+ VirtualKey virtualKey;
virtualKey.scanCode = virtualKeyDefinition.scanCode;
int32_t keyCode;
@@ -3998,8 +3965,7 @@
&keyCode, &dummyKeyMetaState, &flags)) {
ALOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring",
virtualKey.scanCode);
- mVirtualKeys.pop(); // drop the key
- continue;
+ continue; // drop the key
}
virtualKey.keyCode = keyCode;
@@ -4017,15 +3983,16 @@
* touchScreenHeight / mSurfaceHeight + touchScreenTop;
virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight)
* touchScreenHeight / mSurfaceHeight + touchScreenTop;
+ mVirtualKeys.push_back(virtualKey);
}
}
void TouchInputMapper::dumpVirtualKeys(std::string& dump) {
- if (!mVirtualKeys.isEmpty()) {
+ if (!mVirtualKeys.empty()) {
dump += INDENT3 "Virtual Keys:\n";
for (size_t i = 0; i < mVirtualKeys.size(); i++) {
- const VirtualKey& virtualKey = mVirtualKeys.itemAt(i);
+ const VirtualKey& virtualKey = mVirtualKeys[i];
dump += StringPrintf(INDENT4 "%zu: scanCode=%d, keyCode=%d, "
"hitLeft=%d, hitRight=%d, hitTop=%d, hitBottom=%d\n",
i, virtualKey.scanCode, virtualKey.keyCode,
@@ -4347,7 +4314,8 @@
nsecs_t timeSinceLastReport = now - mStatistics.lastReportTime;
if (timeSinceLastReport > STATISTICS_REPORT_FREQUENCY) {
android::util::stats_write(android::util::TOUCH_EVENT_REPORTED,
- mStatistics.min, mStatistics.max, mStatistics.mean(), mStatistics.stdev());
+ mStatistics.min, mStatistics.max,
+ mStatistics.mean(), mStatistics.stdev(), mStatistics.count);
mStatistics.reset(now);
}
}
@@ -4364,12 +4332,13 @@
}
void TouchInputMapper::sync(nsecs_t when) {
- const RawState* last = mRawStatesPending.isEmpty() ?
- &mCurrentRawState : &mRawStatesPending.top();
+ const RawState* last = mRawStatesPending.empty() ?
+ &mCurrentRawState : &mRawStatesPending.back();
// Push a new state.
- mRawStatesPending.push();
- RawState* next = &mRawStatesPending.editTop();
+ mRawStatesPending.emplace_back();
+
+ RawState* next = &mRawStatesPending.back();
next->clear();
next->when = when;
@@ -4436,7 +4405,7 @@
cookAndDispatch(mCurrentRawState.when);
}
if (count != 0) {
- mRawStatesPending.removeItemsAt(0, count);
+ mRawStatesPending.erase(mRawStatesPending.begin(), mRawStatesPending.begin() + count);
}
if (mExternalStylusDataPending) {
@@ -6623,12 +6592,9 @@
&& scaledY >= mPhysicalTop && scaledY <= mPhysicalTop + mPhysicalHeight;
}
-const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit(
- int32_t x, int32_t y) {
- size_t numVirtualKeys = mVirtualKeys.size();
- for (size_t i = 0; i < numVirtualKeys; i++) {
- const VirtualKey& virtualKey = mVirtualKeys[i];
+const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit(int32_t x, int32_t y) {
+ for (const VirtualKey& virtualKey: mVirtualKeys) {
#if DEBUG_VIRTUAL_KEYS
ALOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, "
"left=%d, top=%d, right=%d, bottom=%d",
@@ -6838,9 +6804,7 @@
return AKEY_STATE_VIRTUAL;
}
- size_t numVirtualKeys = mVirtualKeys.size();
- for (size_t i = 0; i < numVirtualKeys; i++) {
- const VirtualKey& virtualKey = mVirtualKeys[i];
+ for (const VirtualKey& virtualKey : mVirtualKeys) {
if (virtualKey.keyCode == keyCode) {
return AKEY_STATE_UP;
}
@@ -6854,9 +6818,7 @@
return AKEY_STATE_VIRTUAL;
}
- size_t numVirtualKeys = mVirtualKeys.size();
- for (size_t i = 0; i < numVirtualKeys; i++) {
- const VirtualKey& virtualKey = mVirtualKeys[i];
+ for (const VirtualKey& virtualKey : mVirtualKeys) {
if (virtualKey.scanCode == scanCode) {
return AKEY_STATE_UP;
}
@@ -6867,10 +6829,7 @@
bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
const int32_t* keyCodes, uint8_t* outFlags) {
- size_t numVirtualKeys = mVirtualKeys.size();
- for (size_t i = 0; i < numVirtualKeys; i++) {
- const VirtualKey& virtualKey = mVirtualKeys[i];
-
+ for (const VirtualKey& virtualKey : mVirtualKeys) {
for (size_t i = 0; i < numCodes; i++) {
if (virtualKey.keyCode == keyCodes[i]) {
outFlags[i] = 1;
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index fed55ac..9777779 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -90,7 +90,7 @@
virtual void requestTimeoutAtTime(nsecs_t when) = 0;
virtual int32_t bumpGeneration() = 0;
- virtual void getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices) = 0;
+ virtual void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices) = 0;
virtual void dispatchExternalStylusState(const StylusState& outState) = 0;
virtual InputReaderPolicyInterface* getPolicy() = 0;
@@ -124,7 +124,7 @@
virtual void loopOnce();
- virtual void getInputDevices(Vector<InputDeviceInfo>& outInputDevices);
+ virtual void getInputDevices(std::vector<InputDeviceInfo>& outInputDevices);
virtual bool isInputDeviceEnabled(int32_t deviceId);
@@ -166,7 +166,7 @@
virtual void fadePointer();
virtual void requestTimeoutAtTime(nsecs_t when);
virtual int32_t bumpGeneration();
- virtual void getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices);
+ virtual void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices);
virtual void dispatchExternalStylusState(const StylusState& outState);
virtual InputReaderPolicyInterface* getPolicy();
virtual InputListenerInterface* getListener();
@@ -211,7 +211,7 @@
int32_t getGlobalMetaStateLocked();
void notifyExternalStylusPresenceChanged();
- void getExternalStylusDevicesLocked(Vector<InputDeviceInfo>& outDevices);
+ void getExternalStylusDevicesLocked(std::vector<InputDeviceInfo>& outDevices);
void dispatchExternalStylusState(const StylusState& state);
void fadePointerLocked();
@@ -219,7 +219,7 @@
int32_t mGeneration;
int32_t bumpGenerationLocked();
- void getInputDevicesLocked(Vector<InputDeviceInfo>& outInputDevices);
+ void getInputDevicesLocked(std::vector<InputDeviceInfo>& outInputDevices);
nsecs_t mDisableVirtualKeysTimeout;
void disableVirtualKeysUntilLocked(nsecs_t time);
@@ -266,7 +266,7 @@
inline void setMic(bool hasMic) { mHasMic = hasMic; }
inline bool hasMic() const { return mHasMic; }
- inline bool isIgnored() { return mMappers.isEmpty(); }
+ inline bool isIgnored() { return mMappers.empty(); }
bool isEnabled();
void setEnabled(bool enabled, nsecs_t when);
@@ -331,7 +331,7 @@
std::string mAlias;
uint32_t mClasses;
- Vector<InputMapper*> mMappers;
+ std::vector<InputMapper*> mMappers;
uint32_t mSources;
bool mIsExternal;
@@ -877,7 +877,7 @@
uint32_t mSource;
int32_t mKeyboardType;
- Vector<KeyDown> mKeyDowns; // keys that are down
+ std::vector<KeyDown> mKeyDowns; // keys that are down
int32_t mMetaState;
nsecs_t mDownTime; // time of most recent key down
@@ -1235,7 +1235,7 @@
}
};
- Vector<RawState> mRawStatesPending;
+ std::vector<RawState> mRawStatesPending;
RawState mCurrentRawState;
CookedState mCurrentCookedState;
RawState mLastRawState;
@@ -1262,7 +1262,7 @@
// The pointer controller, or null if the device is not a pointer.
sp<PointerControllerInterface> mPointerController;
- Vector<VirtualKey> mVirtualKeys;
+ std::vector<VirtualKey> mVirtualKeys;
virtual void configureParameters();
virtual void dumpParameters(std::string& dump);
diff --git a/services/inputflinger/TouchVideoDevice.cpp b/services/inputflinger/TouchVideoDevice.cpp
index 76df3a1..19c1313 100644
--- a/services/inputflinger/TouchVideoDevice.cpp
+++ b/services/inputflinger/TouchVideoDevice.cpp
@@ -68,6 +68,7 @@
std::string name = reinterpret_cast<const char*>(cap.card);
struct v4l2_input v4l2_input_struct;
+ v4l2_input_struct.index = 0;
result = ioctl(fd.get(), VIDIOC_ENUMINPUT, &v4l2_input_struct);
if (result == -1) {
ALOGE("VIDIOC_ENUMINPUT failed: %s", strerror(errno));
@@ -91,10 +92,11 @@
const uint32_t width = v4l2_fmt.fmt.pix.width;
ALOGI("Frame dimensions: height = %" PRIu32 " width = %" PRIu32, height, width);
- struct v4l2_requestbuffers req;
+ struct v4l2_requestbuffers req = {};
req.count = NUM_BUFFERS;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
+ // req.reserved is zeroed during initialization, which is required per v4l docs
result = ioctl(fd.get(), VIDIOC_REQBUFS, &req);
if (result == -1) {
ALOGE("VIDIOC_REQBUFS failed: %s", strerror(errno));
@@ -108,6 +110,7 @@
struct v4l2_buffer buf = {};
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
+ // buf.reserved and buf.reserved2 are zeroed during initialization, required per v4l docs
std::array<const int16_t*, NUM_BUFFERS> readLocations;
for (size_t i = 0; i < NUM_BUFFERS; i++) {
buf.index = i;
diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h
index a00b5fb..d8b352c 100644
--- a/services/inputflinger/host/InputFlinger.h
+++ b/services/inputflinger/host/InputFlinger.h
@@ -40,7 +40,8 @@
InputFlinger() ANDROID_API;
virtual status_t dump(int fd, const Vector<String16>& args);
- void setInputWindows(const Vector<InputWindowInfo>&, const sp<ISetInputWindowsListener>&) {}
+ void setInputWindows(const std::vector<InputWindowInfo>&,
+ const sp<ISetInputWindowsListener>&) {}
void transferTouchFocus(const sp<IBinder>&, const sp<IBinder>&) {}
void registerInputChannel(const sp<InputChannel>&) {}
void unregisterInputChannel(const sp<InputChannel>&) {}
diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h
index cd8caf7..b51dcb6 100644
--- a/services/inputflinger/include/InputListener.h
+++ b/services/inputflinger/include/InputListener.h
@@ -221,7 +221,7 @@
private:
sp<InputListenerInterface> mInnerListener;
- Vector<NotifyArgs*> mArgsQueue;
+ std::vector<NotifyArgs*> mArgsQueue;
};
} // namespace android
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index fe1d4d0..8ad5dd0 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -74,7 +74,7 @@
*
* This method may be called on any thread (usually by the input manager).
*/
- virtual void getInputDevices(Vector<InputDeviceInfo>& outInputDevices) = 0;
+ virtual void getInputDevices(std::vector<InputDeviceInfo>& outInputDevices) = 0;
/* Query current input state. */
virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask,
@@ -333,7 +333,7 @@
/* Notifies the input reader policy that some input devices have changed
* and provides information about all current input devices.
*/
- virtual void notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices) = 0;
+ virtual void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) = 0;
/* Gets the keyboard layout for a particular input device. */
virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 3b6fe52..745fac0 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -340,10 +340,7 @@
virtual ~FakeApplicationHandle() {}
virtual bool updateInfo() {
- if (!mInfo) {
- mInfo = new InputApplicationInfo();
- }
- mInfo->dispatchingTimeout = DISPATCHING_TIMEOUT;
+ mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
return true;
}
};
@@ -571,8 +568,8 @@
sp<FakeWindowHandle> window = new FakeWindowHandle(application, mDispatcher, "Fake Window",
ADISPLAY_ID_DEFAULT);
- Vector<sp<InputWindowHandle>> inputWindowHandles;
- inputWindowHandles.add(window);
+ std::vector<sp<InputWindowHandle>> inputWindowHandles;
+ inputWindowHandles.push_back(window);
mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
@@ -591,9 +588,9 @@
sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second",
ADISPLAY_ID_DEFAULT);
- Vector<sp<InputWindowHandle>> inputWindowHandles;
- inputWindowHandles.add(windowTop);
- inputWindowHandles.add(windowSecond);
+ std::vector<sp<InputWindowHandle>> inputWindowHandles;
+ inputWindowHandles.push_back(windowTop);
+ inputWindowHandles.push_back(windowSecond);
mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
@@ -617,9 +614,9 @@
// Expect one focus window exist in display.
windowSecond->setFocus();
- Vector<sp<InputWindowHandle>> inputWindowHandles;
- inputWindowHandles.add(windowTop);
- inputWindowHandles.add(windowSecond);
+ std::vector<sp<InputWindowHandle>> inputWindowHandles;
+ inputWindowHandles.push_back(windowTop);
+ inputWindowHandles.push_back(windowSecond);
mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
@@ -643,9 +640,9 @@
// Display has two focused windows. Add them to inputWindowsHandles in z-order (top most first)
windowTop->setFocus();
windowSecond->setFocus();
- Vector<sp<InputWindowHandle>> inputWindowHandles;
- inputWindowHandles.add(windowTop);
- inputWindowHandles.add(windowSecond);
+ std::vector<sp<InputWindowHandle>> inputWindowHandles;
+ inputWindowHandles.push_back(windowTop);
+ inputWindowHandles.push_back(windowSecond);
mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
@@ -669,9 +666,9 @@
windowTop->setFocus();
windowSecond->setFocus();
- Vector<sp<InputWindowHandle>> inputWindowHandles;
- inputWindowHandles.add(windowTop);
- inputWindowHandles.add(windowSecond);
+ std::vector<sp<InputWindowHandle>> inputWindowHandles;
+ inputWindowHandles.push_back(windowTop);
+ inputWindowHandles.push_back(windowSecond);
// Release channel for window is no longer valid.
windowTop->releaseChannel();
mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
@@ -695,8 +692,8 @@
application1 = new FakeApplicationHandle();
windowInPrimary = new FakeWindowHandle(application1, mDispatcher, "D_1",
ADISPLAY_ID_DEFAULT);
- Vector<sp<InputWindowHandle>> inputWindowHandles;
- inputWindowHandles.push(windowInPrimary);
+ std::vector<sp<InputWindowHandle>> inputWindowHandles;
+ inputWindowHandles.push_back(windowInPrimary);
// Set focus window for primary display, but focused display would be second one.
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application1);
windowInPrimary->setFocus();
@@ -706,8 +703,8 @@
windowInSecondary = new FakeWindowHandle(application2, mDispatcher, "D_2",
SECOND_DISPLAY_ID);
// Set focus to second display window.
- Vector<sp<InputWindowHandle>> inputWindowHandles_Second;
- inputWindowHandles_Second.push(windowInSecondary);
+ std::vector<sp<InputWindowHandle>> inputWindowHandles_Second;
+ inputWindowHandles_Second.push_back(windowInSecondary);
// Set focus display to second one.
mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
// Set focus window for second display.
@@ -762,7 +759,7 @@
windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
// Remove secondary display.
- Vector<sp<InputWindowHandle>> noWindows;
+ std::vector<sp<InputWindowHandle>> noWindows;
mDispatcher->setInputWindows(noWindows, SECOND_DISPLAY_ID);
// Expect old focus should receive a cancel event.
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 80a55f1..d353028 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -158,7 +158,7 @@
class FakeInputReaderPolicy : public InputReaderPolicyInterface {
InputReaderConfiguration mConfig;
KeyedVector<int32_t, sp<FakePointerController> > mPointerControllers;
- Vector<InputDeviceInfo> mInputDevices;
+ std::vector<InputDeviceInfo> mInputDevices;
std::vector<DisplayViewport> mViewports;
TouchAffineTransformation transform;
@@ -226,7 +226,7 @@
return &mConfig;
}
- const Vector<InputDeviceInfo>& getInputDevices() const {
+ const std::vector<InputDeviceInfo>& getInputDevices() const {
return mInputDevices;
}
@@ -280,7 +280,7 @@
return mPointerControllers.valueFor(deviceId);
}
- virtual void notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices) {
+ virtual void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) {
mInputDevices = inputDevices;
}
@@ -314,7 +314,7 @@
KeyedVector<int32_t, KeyInfo> keysByScanCode;
KeyedVector<int32_t, KeyInfo> keysByUsageCode;
KeyedVector<int32_t, bool> leds;
- Vector<VirtualKeyDefinition> virtualKeys;
+ std::vector<VirtualKeyDefinition> virtualKeys;
bool enabled;
status_t enable() {
@@ -482,7 +482,7 @@
void addVirtualKeyDefinition(int32_t deviceId, const VirtualKeyDefinition& definition) {
Device* device = getDevice(deviceId);
- device->virtualKeys.push(definition);
+ device->virtualKeys.push_back(definition);
}
void enqueueEvent(nsecs_t when, int32_t deviceId, int32_t type,
@@ -728,12 +728,12 @@
}
virtual void getVirtualKeyDefinitions(int32_t deviceId,
- Vector<VirtualKeyDefinition>& outVirtualKeys) const {
+ std::vector<VirtualKeyDefinition>& outVirtualKeys) const {
outVirtualKeys.clear();
Device* device = getDevice(deviceId);
if (device) {
- outVirtualKeys.appendVector(device->virtualKeys);
+ outVirtualKeys = device->virtualKeys;
}
}
@@ -842,7 +842,7 @@
return ++mGeneration;
}
- virtual void getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices) {
+ virtual void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices) {
}
@@ -865,7 +865,7 @@
KeyedVector<int32_t, int32_t> mKeyCodeStates;
KeyedVector<int32_t, int32_t> mScanCodeStates;
KeyedVector<int32_t, int32_t> mSwitchStates;
- Vector<int32_t> mSupportedKeyCodes;
+ std::vector<int32_t> mSupportedKeyCodes;
RawEvent mLastEvent;
bool mConfigureWasCalled;
@@ -925,7 +925,7 @@
}
void addSupportedKeyCode(int32_t keyCode) {
- mSupportedKeyCodes.add(keyCode);
+ mSupportedKeyCodes.push_back(keyCode);
}
private:
@@ -1309,7 +1309,7 @@
0, nullptr)); // no classes so device will be ignored
- Vector<InputDeviceInfo> inputDevices;
+ std::vector<InputDeviceInfo> inputDevices;
mReader->getInputDevices(inputDevices);
ASSERT_EQ(1U, inputDevices.size());
@@ -4436,7 +4436,7 @@
ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType);
- // airbrush
+ // air-brush
processKey(mapper, BTN_TOOL_PENCIL, 0);
processKey(mapper, BTN_TOOL_AIRBRUSH, 1);
processSync(mapper);
@@ -5943,7 +5943,7 @@
ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action);
ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType);
- // airbrush
+ // air-brush
processKey(mapper, BTN_TOOL_PENCIL, 0);
processKey(mapper, BTN_TOOL_AIRBRUSH, 1);
processSync(mapper);
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 189ae36..a6ed75f 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -359,7 +359,7 @@
for (const auto & s : mSensorList) {
int32_t handle = s.handle;
const Info& info = mActivationCount.valueFor(handle);
- if (info.batchParams.isEmpty()) continue;
+ if (info.numActiveClients() == 0) continue;
result.appendFormat("0x%08x) active-count = %zu; ", handle, info.batchParams.size());
@@ -730,6 +730,15 @@
return mDisabledClients.indexOf(ident) >= 0;
}
+bool SensorDevice::isSensorActive(int handle) const {
+ Mutex::Autolock _l(mLock);
+ ssize_t activationIndex = mActivationCount.indexOfKey(handle);
+ if (activationIndex < 0) {
+ return false;
+ }
+ return mActivationCount.valueAt(activationIndex).numActiveClients() > 0;
+}
+
void SensorDevice::enableAllSensors() {
if (mSensors == nullptr) return;
Mutex::Autolock _l(mLock);
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 2a69654..71b918f 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -120,6 +120,8 @@
return mReconnecting;
}
+ bool isSensorActive(int handle) const;
+
// Dumpable
virtual std::string dump() const;
private:
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index b66cbcf..c4cfdc6 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -78,7 +78,14 @@
void SensorService::SensorEventConnection::dump(String8& result) {
Mutex::Autolock _l(mConnectionLock);
- result.appendFormat("\tOperating Mode: %s\n",mDataInjectionMode ? "DATA_INJECTION" : "NORMAL");
+ result.appendFormat("\tOperating Mode: ");
+ if (!mService->isWhiteListedPackage(getPackageName())) {
+ result.append("RESTRICTED\n");
+ } else if (mDataInjectionMode) {
+ result.append("DATA_INJECTION\n");
+ } else {
+ result.append("NORMAL\n");
+ }
result.appendFormat("\t %s | WakeLockRefCount %d | uid %d | cache size %d | "
"max cache size %d\n", mPackageName.string(), mWakeLockRefCount, mUid, mCacheSize,
mMaxCacheSize);
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 3fbd61e..e3dfde4 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -441,12 +441,15 @@
}
result.append("Active sensors:\n");
+ SensorDevice& dev = SensorDevice::getInstance();
for (size_t i=0 ; i<mActiveSensors.size() ; i++) {
int handle = mActiveSensors.keyAt(i);
- result.appendFormat("%s (handle=0x%08x, connections=%zu)\n",
- getSensorName(handle).string(),
- handle,
- mActiveSensors.valueAt(i)->getNumConnections());
+ if (dev.isSensorActive(handle)) {
+ result.appendFormat("%s (handle=0x%08x, connections=%zu)\n",
+ getSensorName(handle).string(),
+ handle,
+ mActiveSensors.valueAt(i)->getNumConnections());
+ }
}
result.appendFormat("Socket Buffer size = %zd events\n",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 4751e5f..1b2b180 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -304,7 +304,9 @@
setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::DEVICE);
}
- ui::Dataspace dataspace = isColorSpaceAgnostic() ? targetDataspace : mCurrentDataSpace;
+ ui::Dataspace dataspace = isColorSpaceAgnostic() && targetDataspace != ui::Dataspace::UNKNOWN
+ ? targetDataspace
+ : mCurrentDataSpace;
error = hwcLayer->setDataspace(dataspace);
if (error != HWC2::Error::None) {
ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), dataspace,
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index cc78ece..f2d4c51 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -323,7 +323,8 @@
mCurrentTextureBuffer == nullptr
? nullptr
: mCurrentTextureBuffer->graphicBuffer(),
- mCurrentCrop, mCurrentTransform, mFilteringEnabled);
+ getCurrentCropLocked(), mCurrentTransform,
+ mFilteringEnabled);
}
nsecs_t BufferLayerConsumer::getTimestamp() {
@@ -380,6 +381,10 @@
Rect BufferLayerConsumer::getCurrentCrop() const {
Mutex::Autolock lock(mMutex);
+ return getCurrentCropLocked();
+}
+
+Rect BufferLayerConsumer::getCurrentCropLocked() const {
return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP)
? GLConsumer::scaleDownCrop(mCurrentCrop, mDefaultWidth, mDefaultHeight)
: mCurrentCrop;
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index 32ccfbb..f4ca846 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -253,6 +253,9 @@
// access the current texture buffer.
status_t doFenceWaitLocked() const;
+ // getCurrentCropLocked returns the cropping rectangle of the current buffer.
+ Rect getCurrentCropLocked() const;
+
// The default consumer usage flags that BufferLayerConsumer always sets on its
// BufferQueue instance; these will be OR:d with any additional flags passed
// from the BufferLayerConsumer user. In particular, BufferLayerConsumer will always
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index e4179ee..d3b36fe 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -361,8 +361,12 @@
uint32_t hwcSlot = 0;
sp<GraphicBuffer> hwcBuffer;
+
+ // INVALID_BUFFER_SLOT is used to identify BufferStateLayers. Default to 0
+ // for BufferQueueLayers
+ int slot = (mActiveBufferSlot == BufferQueue::INVALID_BUFFER_SLOT) ? 0 : mActiveBufferSlot;
(*outputLayer->editState().hwc)
- .hwcBufferCache.getHwcBuffer(mActiveBuffer, &hwcSlot, &hwcBuffer);
+ .hwcBufferCache.getHwcBuffer(slot, mActiveBuffer, &hwcSlot, &hwcBuffer);
auto acquireFence = mConsumer->getCurrentFence();
auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 1ca0b02..64dfdc3 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -139,7 +139,6 @@
bool BufferStateLayer::setTransform(uint32_t transform) {
if (mCurrentState.transform == transform) return false;
- mCurrentState.sequence++;
mCurrentState.transform = transform;
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
@@ -170,7 +169,6 @@
}
if (mCurrentState.crop == c) return false;
- mCurrentState.sequence++;
mCurrentState.crop = c;
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
@@ -242,7 +240,6 @@
bool BufferStateLayer::setHdrMetadata(const HdrMetadata& hdrMetadata) {
if (mCurrentState.hdrMetadata == hdrMetadata) return false;
- mCurrentState.sequence++;
mCurrentState.hdrMetadata = hdrMetadata;
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
@@ -250,7 +247,6 @@
}
bool BufferStateLayer::setSurfaceDamageRegion(const Region& surfaceDamage) {
- mCurrentState.sequence++;
mCurrentState.surfaceDamageRegion = surfaceDamage;
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
@@ -259,7 +255,6 @@
bool BufferStateLayer::setApi(int32_t api) {
if (mCurrentState.api == api) return false;
- mCurrentState.sequence++;
mCurrentState.api = api;
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
@@ -268,7 +263,6 @@
bool BufferStateLayer::setSidebandStream(const sp<NativeHandle>& sidebandStream) {
if (mCurrentState.sidebandStream == sidebandStream) return false;
- mCurrentState.sequence++;
mCurrentState.sidebandStream = sidebandStream;
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
@@ -551,6 +545,8 @@
mFlinger->mTimeStats->setAcquireFence(layerID, getFrameNumber(), getCurrentFenceTime());
mFlinger->mTimeStats->setLatchTime(layerID, getFrameNumber(), latchTime);
+ mCurrentStateModified = false;
+
return NO_ERROR;
}
@@ -589,10 +585,10 @@
const State& s(getDrawingState());
- // obtain slot
- uint32_t hwcSlot = 0;
+ uint32_t hwcSlot;
sp<GraphicBuffer> buffer;
- hwcInfo.hwcBufferCache.getHwcBuffer(s.buffer, &hwcSlot, &buffer);
+ hwcInfo.hwcBufferCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, s.buffer, &hwcSlot,
+ &buffer);
auto error = hwcLayer->setBuffer(hwcSlot, buffer, s.acquireFence);
if (error != HWC2::Error::None) {
@@ -600,7 +596,6 @@
s.buffer->handle, to_string(error).c_str(), static_cast<int32_t>(error));
}
- mCurrentStateModified = false;
mFrameNumber++;
}
diff --git a/services/surfaceflinger/BufferStateLayerCache.cpp b/services/surfaceflinger/BufferStateLayerCache.cpp
index cb02d16..51ca45c 100644
--- a/services/surfaceflinger/BufferStateLayerCache.cpp
+++ b/services/surfaceflinger/BufferStateLayerCache.cpp
@@ -23,21 +23,14 @@
#include "BufferStateLayerCache.h"
-#define VALID_CACHE_ID(id) ((id) >= 0 || (id) < (BUFFER_CACHE_MAX_SIZE))
-
namespace android {
ANDROID_SINGLETON_STATIC_INSTANCE(BufferStateLayerCache);
BufferStateLayerCache::BufferStateLayerCache() : mDeathRecipient(new CacheDeathRecipient) {}
-void BufferStateLayerCache::add(sp<IBinder> processToken, int32_t id,
+void BufferStateLayerCache::add(const sp<IBinder>& processToken, uint64_t id,
const sp<GraphicBuffer>& buffer) {
- if (!VALID_CACHE_ID(id)) {
- ALOGE("failed to cache buffer: invalid buffer id");
- return;
- }
-
if (!processToken) {
ALOGE("failed to cache buffer: invalid process token");
return;
@@ -61,15 +54,33 @@
}
auto& processBuffers = mBuffers[processToken];
+
+ if (processBuffers.size() > BUFFER_CACHE_MAX_SIZE) {
+ ALOGE("failed to cache buffer: cache is full");
+ return;
+ }
+
processBuffers[id] = buffer;
}
-sp<GraphicBuffer> BufferStateLayerCache::get(sp<IBinder> processToken, int32_t id) {
- if (!VALID_CACHE_ID(id)) {
- ALOGE("failed to get buffer: invalid buffer id");
- return nullptr;
+void BufferStateLayerCache::erase(const sp<IBinder>& processToken, uint64_t id) {
+ if (!processToken) {
+ ALOGE("failed to uncache buffer: invalid process token");
+ return;
}
+ std::lock_guard lock(mMutex);
+
+ if (mBuffers.find(processToken) == mBuffers.end()) {
+ ALOGE("failed to uncache buffer: process token not found");
+ return;
+ }
+
+ auto& processBuffers = mBuffers[processToken];
+ processBuffers.erase(id);
+}
+
+sp<GraphicBuffer> BufferStateLayerCache::get(const sp<IBinder>& processToken, uint64_t id) {
if (!processToken) {
ALOGE("failed to cache buffer: invalid process token");
return nullptr;
@@ -82,8 +93,8 @@
return nullptr;
}
- if (id >= itr->second.size()) {
- ALOGE("failed to get buffer: id outside the bounds of the cache");
+ if (itr->second.find(id) == itr->second.end()) {
+ ALOGE("failed to get buffer: buffer not found");
return nullptr;
}
diff --git a/services/surfaceflinger/BufferStateLayerCache.h b/services/surfaceflinger/BufferStateLayerCache.h
index ede3feb..415c09c 100644
--- a/services/surfaceflinger/BufferStateLayerCache.h
+++ b/services/surfaceflinger/BufferStateLayerCache.h
@@ -34,14 +34,16 @@
public:
BufferStateLayerCache();
- void add(sp<IBinder> processToken, int32_t id, const sp<GraphicBuffer>& buffer);
- sp<GraphicBuffer> get(sp<IBinder> processToken, int32_t id);
+ void add(const sp<IBinder>& processToken, uint64_t id, const sp<GraphicBuffer>& buffer);
+ void erase(const sp<IBinder>& processToken, uint64_t id);
+
+ sp<GraphicBuffer> get(const sp<IBinder>& processToken, uint64_t id);
void removeProcess(const wp<IBinder>& processToken);
private:
std::mutex mMutex;
- std::map<wp<IBinder> /*caching process*/, std::array<sp<GraphicBuffer>, BUFFER_CACHE_MAX_SIZE>>
+ std::map<wp<IBinder> /*caching process*/, std::map<uint64_t /*Cache id*/, sp<GraphicBuffer>>>
mBuffers GUARDED_BY(mMutex);
class CacheDeathRecipient : public IBinder::DeathRecipient {
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 3364399..fcc2d97 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -114,7 +114,9 @@
setCompositionType(display, Hwc2::IComposerClient::Composition::SOLID_COLOR);
- const ui::Dataspace dataspace = isColorSpaceAgnostic() ? targetDataspace : mCurrentDataSpace;
+ const ui::Dataspace dataspace =
+ isColorSpaceAgnostic() && targetDataspace != ui::Dataspace::UNKNOWN ? targetDataspace
+ : mCurrentDataSpace;
error = hwcLayer->setDataspace(dataspace);
if (error != HWC2::Error::None) {
ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), dataspace,
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
index 02d7890..97bdc8f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
@@ -45,7 +45,7 @@
//
// outBuffer is set to buffer when buffer is not in the HWC cache;
// otherwise, outBuffer is set to nullptr.
- void getHwcBuffer(const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
+ void getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
sp<GraphicBuffer>* outBuffer);
protected:
diff --git a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
index 8613210..a941e09 100644
--- a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
@@ -48,12 +48,20 @@
return std::distance(std::begin(mBuffers), iter);
}
-void HwcBufferCache::getHwcBuffer(const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
+void HwcBufferCache::getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
sp<GraphicBuffer>* outBuffer) {
- bool cached = getSlot(buffer, outSlot);
+ // if this slot corresponds to a BufferStateLayer, generate the slot
+ if (slot == BufferQueue::INVALID_BUFFER_SLOT) {
+ getSlot(buffer, outSlot);
+ } else if (slot < 0 || slot >= BufferQueue::NUM_BUFFER_SLOTS) {
+ *outSlot = 0;
+ } else {
+ *outSlot = slot;
+ }
auto& [currentCounter, currentBuffer] = mBuffers[*outSlot];
- if (cached) {
+ wp<GraphicBuffer> weakCopy(buffer);
+ if (currentBuffer == weakCopy) {
// already cached in HWC, skip sending the buffer
*outBuffer = nullptr;
currentCounter = getCounter();
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 379ad87..5ce72b0 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -282,8 +282,7 @@
* computation so it's enough to just omit it in the composition.
* See comment in BufferLayer::prepareClientLayer with ref to b/36727915 for why.
*/
- transform =
- ui::Transform(invTransform) * displayTransform * layerTransform * bufferTransform;
+ transform = ui::Transform(invTransform) * displayTransform * bufferTransform;
}
// this gives us only the "orientation" component of the transform
diff --git a/services/surfaceflinger/CompositionEngine/tests/FloatRectMatcher.h b/services/surfaceflinger/CompositionEngine/tests/FloatRectMatcher.h
deleted file mode 100644
index 6741cc9..0000000
--- a/services/surfaceflinger/CompositionEngine/tests/FloatRectMatcher.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <string>
-
-#include <android-base/stringprintf.h>
-#include <gmock/gmock.h>
-
-namespace {
-
-using android::base::StringAppendF;
-using FloatRect = android::FloatRect;
-
-void dumpFloatRect(const FloatRect& rect, std::string& result, const char* name) {
- StringAppendF(&result, "%s (%f %f %f %f) ", name, rect.left, rect.top, rect.right, rect.bottom);
-}
-
-// Checks for a region match
-MATCHER_P(FloatRectEq, expected, "") {
- std::string buf;
- buf.append("FloatRects are not equal\n");
- dumpFloatRect(expected, buf, "expected rect");
- dumpFloatRect(arg, buf, "actual rect");
- *result_listener << buf;
-
- const float TOLERANCE = 1e-3f;
- return (std::fabs(expected.left - arg.left) < TOLERANCE) &&
- (std::fabs(expected.top - arg.top) < TOLERANCE) &&
- (std::fabs(expected.right - arg.right) < TOLERANCE) &&
- (std::fabs(expected.bottom - arg.bottom) < TOLERANCE);
-}
-
-} // namespace
diff --git a/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp b/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
index ac04cb3..b261493 100644
--- a/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
@@ -24,9 +24,9 @@
class TestableHwcBufferCache : public impl::HwcBufferCache {
public:
- void getHwcBuffer(const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
+ void getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
sp<GraphicBuffer>* outBuffer) {
- HwcBufferCache::getHwcBuffer(buffer, outSlot, outBuffer);
+ HwcBufferCache::getHwcBuffer(slot, buffer, outSlot, outBuffer);
}
bool getSlot(const sp<GraphicBuffer>& buffer, uint32_t* outSlot) {
return HwcBufferCache::getSlot(buffer, outSlot);
@@ -38,64 +38,88 @@
public:
~HwcBufferCacheTest() override = default;
- TestableHwcBufferCache mCache;
+ void testSlot(const int inSlot, const uint32_t expectedSlot) {
+ uint32_t outSlot;
+ sp<GraphicBuffer> outBuffer;
+
+ // The first time, the output is the same as the input
+ mCache.getHwcBuffer(inSlot, mBuffer1, &outSlot, &outBuffer);
+ EXPECT_EQ(expectedSlot, outSlot);
+ EXPECT_EQ(mBuffer1, outBuffer);
+
+ // The second time with the same buffer, the outBuffer is nullptr.
+ mCache.getHwcBuffer(inSlot, mBuffer1, &outSlot, &outBuffer);
+ EXPECT_EQ(expectedSlot, outSlot);
+ EXPECT_EQ(nullptr, outBuffer.get());
+
+ // With a new buffer, the outBuffer is the input.
+ mCache.getHwcBuffer(inSlot, mBuffer2, &outSlot, &outBuffer);
+ EXPECT_EQ(expectedSlot, outSlot);
+ EXPECT_EQ(mBuffer2, outBuffer);
+
+ // Again, the second request with the same buffer sets outBuffer to nullptr.
+ mCache.getHwcBuffer(inSlot, mBuffer2, &outSlot, &outBuffer);
+ EXPECT_EQ(expectedSlot, outSlot);
+ EXPECT_EQ(nullptr, outBuffer.get());
+
+ // Setting a slot to use nullptr lookslike works, but note that
+ // the output values make it look like no new buffer is being set....
+ mCache.getHwcBuffer(inSlot, sp<GraphicBuffer>(), &outSlot, &outBuffer);
+ EXPECT_EQ(expectedSlot, outSlot);
+ EXPECT_EQ(nullptr, outBuffer.get());
+ }
+
+ impl::HwcBufferCache mCache;
sp<GraphicBuffer> mBuffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
sp<GraphicBuffer> mBuffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
};
-TEST_F(HwcBufferCacheTest, testSlot) {
+TEST_F(HwcBufferCacheTest, cacheWorksForSlotZero) {
+ testSlot(0, 0);
+}
+
+TEST_F(HwcBufferCacheTest, cacheWorksForMaxSlot) {
+ testSlot(BufferQueue::NUM_BUFFER_SLOTS - 1, BufferQueue::NUM_BUFFER_SLOTS - 1);
+}
+
+TEST_F(HwcBufferCacheTest, cacheMapsNegativeSlotToZero) {
+ testSlot(-123, 0);
+}
+
+TEST_F(HwcBufferCacheTest, cacheGeneratesSlotForInvalidBufferSlot) {
uint32_t outSlot;
sp<GraphicBuffer> outBuffer;
- // The first time, the output is the same as the input
- mCache.getHwcBuffer(mBuffer1, &outSlot, &outBuffer);
+ mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer1, &outSlot, &outBuffer);
EXPECT_EQ(0, outSlot);
EXPECT_EQ(mBuffer1, outBuffer);
- // The second time with the same buffer, the outBuffer is nullptr.
- mCache.getHwcBuffer(mBuffer1, &outSlot, &outBuffer);
+ mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer1, &outSlot, &outBuffer);
EXPECT_EQ(0, outSlot);
EXPECT_EQ(nullptr, outBuffer.get());
- // With a new buffer, the outBuffer is the input.
- mCache.getHwcBuffer(mBuffer2, &outSlot, &outBuffer);
+ mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer2, &outSlot, &outBuffer);
EXPECT_EQ(1, outSlot);
EXPECT_EQ(mBuffer2, outBuffer);
- // Again, the second request with the same buffer sets outBuffer to nullptr.
- mCache.getHwcBuffer(mBuffer2, &outSlot, &outBuffer);
+ mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer2, &outSlot, &outBuffer);
EXPECT_EQ(1, outSlot);
EXPECT_EQ(nullptr, outBuffer.get());
- // Setting a slot to use nullptr lookslike works, but note that
- // the output values make it look like no new buffer is being set....
- mCache.getHwcBuffer(sp<GraphicBuffer>(), &outSlot, &outBuffer);
+ mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, sp<GraphicBuffer>(), &outSlot,
+ &outBuffer);
EXPECT_EQ(2, outSlot);
EXPECT_EQ(nullptr, outBuffer.get());
-}
-TEST_F(HwcBufferCacheTest, testGetLeastRecentlyUsedSlot) {
- int slot;
- uint32_t outSlot;
- sp<GraphicBuffer> outBuffer;
-
- // fill up cache
- for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
- sp<GraphicBuffer> buf{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
- mCache.getHwcBuffer(buf, &outSlot, &outBuffer);
- EXPECT_EQ(buf, outBuffer);
- EXPECT_EQ(i, outSlot);
- }
-
- slot = mCache.getLeastRecentlyUsedSlot();
- EXPECT_EQ(0, slot);
-
- mCache.getHwcBuffer(mBuffer1, &outSlot, &outBuffer);
- EXPECT_EQ(0, outSlot);
+ // note that sending mBuffer1 with explicit slot 1 will overwrite mBuffer2
+ // and also cause mBuffer1 to be stored in two places
+ mCache.getHwcBuffer(1, mBuffer1, &outSlot, &outBuffer);
+ EXPECT_EQ(1, outSlot);
EXPECT_EQ(mBuffer1, outBuffer);
- slot = mCache.getLeastRecentlyUsedSlot();
- EXPECT_EQ(1, slot);
+ mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer2, &outSlot, &outBuffer);
+ EXPECT_EQ(3, outSlot);
+ EXPECT_EQ(mBuffer2, outBuffer);
}
} // namespace
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 2504fa6..2060c5a 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -21,7 +21,6 @@
#include <compositionengine/mock/Output.h>
#include <gtest/gtest.h>
-#include "FloatRectMatcher.h"
#include "MockHWC2.h"
#include "MockHWComposer.h"
#include "RectMatcher.h"
@@ -107,114 +106,6 @@
}
/*
- * OutputLayer::calculateOutputSourceCrop()
- */
-
-struct OutputLayerSourceCropTest : public OutputLayerTest {
- OutputLayerSourceCropTest() {
- // Set reasonable default values for a simple case. Each test will
- // set one specific value to something different.
- mLayerState.frontEnd.geomUsesSourceCrop = true;
- mLayerState.frontEnd.geomContentCrop = Rect{0, 0, 1920, 1080};
- mLayerState.frontEnd.geomActiveTransparentRegion = Region{};
- mLayerState.frontEnd.geomLayerBounds = FloatRect{0.f, 0.f, 1920.f, 1080.f};
- mLayerState.frontEnd.geomLayerTransform = ui::Transform{TR_IDENT};
- mLayerState.frontEnd.geomBufferSize = Rect{0, 0, 1920, 1080};
- mLayerState.frontEnd.geomBufferTransform = TR_IDENT;
-
- mOutputState.viewport = Rect{0, 0, 1920, 1080};
- }
-
- FloatRect calculateOutputSourceCrop() {
- mLayerState.frontEnd.geomInverseLayerTransform =
- mLayerState.frontEnd.geomLayerTransform.inverse();
-
- return mOutputLayer.calculateOutputSourceCrop();
- }
-};
-
-TEST_F(OutputLayerSourceCropTest, computesEmptyIfSourceCropNotUsed) {
- mLayerState.frontEnd.geomUsesSourceCrop = false;
-
- const FloatRect expected{};
- EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected));
-}
-
-TEST_F(OutputLayerSourceCropTest, correctForSimpleDefaultCase) {
- const FloatRect expected{0.f, 0.f, 1920.f, 1080.f};
- EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected));
-}
-
-TEST_F(OutputLayerSourceCropTest, handlesBoundsOutsideViewport) {
- mLayerState.frontEnd.geomLayerBounds = FloatRect{-2000.f, -2000.f, 2000.f, 2000.f};
-
- const FloatRect expected{0.f, 0.f, 1920.f, 1080.f};
- EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected));
-}
-
-TEST_F(OutputLayerSourceCropTest, handlesBoundsOutsideViewportRotated) {
- mLayerState.frontEnd.geomLayerBounds = FloatRect{-2000.f, -2000.f, 2000.f, 2000.f};
- mLayerState.frontEnd.geomLayerTransform.set(HAL_TRANSFORM_ROT_90, 1920, 1080);
-
- const FloatRect expected{0.f, 0.f, 1080.f, 1080.f};
- EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected));
-}
-
-TEST_F(OutputLayerSourceCropTest, calculateOutputSourceCropWorksWithATransformedBuffer) {
- struct Entry {
- uint32_t bufferInvDisplay;
- uint32_t buffer;
- uint32_t display;
- FloatRect expected;
- };
- // Not an exhaustive list of cases, but hopefully enough.
- const std::array<Entry, 12> testData = {
- // clang-format off
- // inv buffer display expected
- /* 0 */ Entry{false, TR_IDENT, TR_IDENT, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
- /* 1 */ Entry{false, TR_IDENT, TR_ROT_90, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
- /* 2 */ Entry{false, TR_IDENT, TR_ROT_180, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
- /* 3 */ Entry{false, TR_IDENT, TR_ROT_270, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
-
- /* 4 */ Entry{true, TR_IDENT, TR_IDENT, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
- /* 5 */ Entry{true, TR_IDENT, TR_ROT_90, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
- /* 6 */ Entry{true, TR_IDENT, TR_ROT_180, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
- /* 7 */ Entry{true, TR_IDENT, TR_ROT_270, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
-
- /* 8 */ Entry{false, TR_IDENT, TR_IDENT, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
- /* 9 */ Entry{false, TR_ROT_90, TR_ROT_90, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
- /* 10 */ Entry{false, TR_ROT_180, TR_ROT_180, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
- /* 11 */ Entry{false, TR_ROT_270, TR_ROT_270, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
-
- // clang-format on
- };
-
- for (size_t i = 0; i < testData.size(); i++) {
- const auto& entry = testData[i];
-
- mLayerState.frontEnd.geomBufferUsesDisplayInverseTransform = entry.bufferInvDisplay;
- mLayerState.frontEnd.geomBufferTransform = entry.buffer;
- mOutputState.orientation = entry.display;
-
- EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(entry.expected)) << "entry " << i;
- }
-}
-
-TEST_F(OutputLayerSourceCropTest, geomContentCropAffectsCrop) {
- mLayerState.frontEnd.geomContentCrop = Rect{0, 0, 960, 540};
-
- const FloatRect expected{0.f, 0.f, 960.f, 540.f};
- EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected));
-}
-
-TEST_F(OutputLayerSourceCropTest, viewportAffectsCrop) {
- mOutputState.viewport = Rect{0, 0, 960, 540};
-
- const FloatRect expected{0.f, 0.f, 960.f, 540.f};
- EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected));
-}
-
-/*
* OutputLayer::calculateOutputDisplayFrame()
*/
@@ -272,7 +163,7 @@
EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected));
}
-TEST_F(OutputLayerDisplayFrameTest, geomLayerBoundsAffectsFrame) {
+TEST_F(OutputLayerDisplayFrameTest, geomLayerSnapToBoundsAffectsFrame) {
mLayerState.frontEnd.geomLayerBounds = FloatRect{0.f, 0.f, 960.f, 540.f};
const Rect expected{0, 0, 960, 540};
EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected));
@@ -351,159 +242,6 @@
}
}
-TEST_F(OutputLayerTest,
- calculateOutputRelativeBufferTransformTestWithOfBufferUsesDisplayInverseTransform) {
- mLayerState.frontEnd.geomBufferUsesDisplayInverseTransform = true;
-
- struct Entry {
- uint32_t layer;
- uint32_t buffer;
- uint32_t display;
- uint32_t expected;
- };
- // Not an exhaustive list of cases, but hopefully enough.
- const std::array<Entry, 24> testData = {
- // clang-format off
- // layer buffer display expected
- /* 0 */ Entry{TR_IDENT, TR_IDENT, TR_IDENT, TR_IDENT},
- /* 1 */ Entry{TR_IDENT, TR_IDENT, TR_ROT_90, TR_IDENT},
- /* 2 */ Entry{TR_IDENT, TR_IDENT, TR_ROT_180, TR_IDENT},
- /* 3 */ Entry{TR_IDENT, TR_IDENT, TR_ROT_270, TR_IDENT},
-
- /* 4 */ Entry{TR_IDENT, TR_FLP_H, TR_IDENT, TR_FLP_H},
- /* 5 */ Entry{TR_IDENT, TR_FLP_H, TR_ROT_90, TR_FLP_H},
- /* 6 */ Entry{TR_IDENT, TR_FLP_H, TR_ROT_180, TR_FLP_H},
- /* 7 */ Entry{TR_IDENT, TR_FLP_H, TR_ROT_270, TR_FLP_H},
-
- /* 8 */ Entry{TR_IDENT, TR_FLP_V, TR_IDENT, TR_FLP_V},
- /* 9 */ Entry{TR_IDENT, TR_ROT_90, TR_ROT_90, TR_ROT_90},
- /* 10 */ Entry{TR_IDENT, TR_ROT_180, TR_ROT_180, TR_ROT_180},
- /* 11 */ Entry{TR_IDENT, TR_ROT_270, TR_ROT_270, TR_ROT_270},
-
- /* 12 */ Entry{TR_ROT_90, TR_IDENT, TR_IDENT, TR_IDENT ^ TR_ROT_90},
- /* 13 */ Entry{TR_ROT_90, TR_FLP_H, TR_ROT_90, TR_FLP_H ^ TR_ROT_90},
- /* 14 */ Entry{TR_ROT_90, TR_IDENT, TR_ROT_180, TR_IDENT ^ TR_ROT_90},
- /* 15 */ Entry{TR_ROT_90, TR_FLP_H, TR_ROT_270, TR_FLP_H ^ TR_ROT_90},
-
- /* 16 */ Entry{TR_ROT_180, TR_FLP_H, TR_IDENT, TR_FLP_H ^ TR_ROT_180},
- /* 17 */ Entry{TR_ROT_180, TR_IDENT, TR_ROT_90, TR_IDENT ^ TR_ROT_180},
- /* 18 */ Entry{TR_ROT_180, TR_FLP_H, TR_ROT_180, TR_FLP_H ^ TR_ROT_180},
- /* 19 */ Entry{TR_ROT_180, TR_IDENT, TR_ROT_270, TR_IDENT ^ TR_ROT_180},
-
- /* 20 */ Entry{TR_ROT_270, TR_IDENT, TR_IDENT, TR_IDENT ^ TR_ROT_270},
- /* 21 */ Entry{TR_ROT_270, TR_FLP_H, TR_ROT_90, TR_FLP_H ^ TR_ROT_270},
- /* 22 */ Entry{TR_ROT_270, TR_FLP_H, TR_ROT_180, TR_FLP_H ^ TR_ROT_270},
- /* 23 */ Entry{TR_ROT_270, TR_IDENT, TR_ROT_270, TR_IDENT ^ TR_ROT_270},
- // clang-format on
- };
-
- for (size_t i = 0; i < testData.size(); i++) {
- const auto& entry = testData[i];
-
- mLayerState.frontEnd.geomLayerTransform = ui::Transform{entry.layer};
- mLayerState.frontEnd.geomBufferTransform = entry.buffer;
- mOutputState.orientation = entry.display;
-
- auto actual = mOutputLayer.calculateOutputRelativeBufferTransform();
- EXPECT_EQ(entry.expected, actual) << "entry " << i;
- }
-}
-
-/*
- * OutputLayer::updateCompositionState()
- */
-
-struct OutputLayerPartialMockForUpdateCompositionState : public impl::OutputLayer {
- OutputLayerPartialMockForUpdateCompositionState(const compositionengine::Output& output,
- std::shared_ptr<compositionengine::Layer> layer,
- sp<compositionengine::LayerFE> layerFE)
- : impl::OutputLayer(output, layer, layerFE) {}
- // Mock everything called by updateCompositionState to simplify testing it.
- MOCK_CONST_METHOD0(calculateOutputSourceCrop, FloatRect());
- MOCK_CONST_METHOD0(calculateOutputDisplayFrame, Rect());
- MOCK_CONST_METHOD0(calculateOutputRelativeBufferTransform, uint32_t());
-};
-
-struct OutputLayerUpdateCompositionStateTest : public OutputLayerTest {
-public:
- OutputLayerUpdateCompositionStateTest() {
- EXPECT_CALL(*mLayer, getState()).WillRepeatedly(ReturnRef(mLayerState));
- EXPECT_CALL(mOutput, getState()).WillRepeatedly(ReturnRef(mOutputState));
- }
-
- ~OutputLayerUpdateCompositionStateTest() = default;
-
- void setupGeometryChildCallValues() {
- EXPECT_CALL(mOutputLayer, calculateOutputSourceCrop()).WillOnce(Return(kSourceCrop));
- EXPECT_CALL(mOutputLayer, calculateOutputDisplayFrame()).WillOnce(Return(kDisplayFrame));
- EXPECT_CALL(mOutputLayer, calculateOutputRelativeBufferTransform())
- .WillOnce(Return(mBufferTransform));
- }
-
- void validateComputedGeometryState() {
- const auto& state = mOutputLayer.getState();
- EXPECT_EQ(kSourceCrop, state.sourceCrop);
- EXPECT_EQ(kDisplayFrame, state.displayFrame);
- EXPECT_EQ(static_cast<Hwc2::Transform>(mBufferTransform), state.bufferTransform);
- }
-
- const FloatRect kSourceCrop{1.f, 2.f, 3.f, 4.f};
- const Rect kDisplayFrame{11, 12, 13, 14};
- uint32_t mBufferTransform{21};
-
- using OutputLayer = OutputLayerPartialMockForUpdateCompositionState;
- StrictMock<OutputLayer> mOutputLayer{mOutput, mLayer, mLayerFE};
-};
-
-TEST_F(OutputLayerUpdateCompositionStateTest, setsStateNormally) {
- mLayerState.frontEnd.isSecure = true;
- mOutputState.isSecure = true;
-
- setupGeometryChildCallValues();
-
- mOutputLayer.updateCompositionState(true);
-
- validateComputedGeometryState();
-
- EXPECT_EQ(false, mOutputLayer.getState().forceClientComposition);
-}
-
-TEST_F(OutputLayerUpdateCompositionStateTest,
- alsoSetsForceCompositionIfSecureLayerOnNonsecureOutput) {
- mLayerState.frontEnd.isSecure = true;
- mOutputState.isSecure = false;
-
- setupGeometryChildCallValues();
-
- mOutputLayer.updateCompositionState(true);
-
- validateComputedGeometryState();
-
- EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
-}
-
-TEST_F(OutputLayerUpdateCompositionStateTest,
- alsoSetsForceCompositionIfUnsupportedBufferTransform) {
- mLayerState.frontEnd.isSecure = true;
- mOutputState.isSecure = true;
-
- mBufferTransform = ui::Transform::ROT_INVALID;
-
- setupGeometryChildCallValues();
-
- mOutputLayer.updateCompositionState(true);
-
- validateComputedGeometryState();
-
- EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
-}
-
-TEST_F(OutputLayerUpdateCompositionStateTest, doesNotRecomputeGeometryIfNotRequested) {
- mOutputLayer.updateCompositionState(false);
-
- EXPECT_EQ(false, mOutputLayer.getState().forceClientComposition);
-}
-
/*
* OutputLayer::writeStateToHWC()
*/
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index 7927fa9..ad08a92 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -42,4 +42,32 @@
void ContainerLayer::setPerFrameData(const sp<const DisplayDevice>&, const ui::Transform&,
const Rect&, int32_t, const ui::Dataspace) {}
+Layer::RoundedCornerState ContainerLayer::getRoundedCornerStateInternal(
+ const FloatRect bounds) const {
+ const auto& p = mDrawingParent.promote();
+ if (p != nullptr) {
+ RoundedCornerState parentState = p->getRoundedCornerStateInternal(bounds);
+ if (parentState.radius > 0) {
+ ui::Transform t = getActiveTransform(getDrawingState());
+ t = t.inverse();
+ parentState.cropRect = t.transform(parentState.cropRect);
+ // The rounded corners shader only accepts 1 corner radius for performance reasons,
+ // but a transform matrix can define horizontal and vertical scales.
+ // Let's take the average between both of them and pass into the shader, practically we
+ // never do this type of transformation on windows anyway.
+ parentState.radius *= (t[0][0] + t[1][1]) / 2.0f;
+ return parentState;
+ }
+ }
+ const float radius = getDrawingState().cornerRadius;
+ if (radius > 0) {
+ const Rect crop = getCrop(getDrawingState());
+ if (!crop.isEmpty()) {
+ return RoundedCornerState(bounds.intersect(crop.toFloatRect()), radius);
+ }
+ return RoundedCornerState(bounds, radius);
+ }
+ return RoundedCornerState();
+}
+
} // namespace android
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index 7222a3e..cd8e722 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -40,6 +40,7 @@
bool isCreatedFromMainThread() const override { return true; }
bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
+ Layer::RoundedCornerState getRoundedCornerStateInternal(const FloatRect bounds) const override;
protected:
bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 775fb80..7370b0c 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -111,7 +111,7 @@
BufferItem item;
status_t err = acquireBufferLocked(&item, 0);
if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
- mHwcBufferCache.getHwcBuffer(mCurrentBuffer, &outSlot, &outBuffer);
+ mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer, &outSlot, &outBuffer);
return NO_ERROR;
} else if (err != NO_ERROR) {
ALOGE("error acquiring buffer: %s (%d)", strerror(-err), err);
@@ -137,7 +137,7 @@
mCurrentFence = item.mFence;
outFence = item.mFence;
- mHwcBufferCache.getHwcBuffer(mCurrentBuffer, &outSlot, &outBuffer);
+ mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer, &outSlot, &outBuffer);
outDataspace = static_cast<Dataspace>(item.mDataSpace);
status_t result = mHwc.setClientTarget(mDisplayId, outSlot, outFence, outBuffer, outDataspace);
if (result != NO_ERROR) {
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 613dc77..4e0e4df 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -224,7 +224,7 @@
if (fbBuffer != nullptr) {
uint32_t hwcSlot = 0;
sp<GraphicBuffer> hwcBuffer;
- mHwcBufferCache.getHwcBuffer(fbBuffer, &hwcSlot, &hwcBuffer);
+ mHwcBufferCache.getHwcBuffer(mFbProducerSlot, fbBuffer, &hwcSlot, &hwcBuffer);
// TODO: Correctly propagate the dataspace from GL composition
result = mHwc.setClientTarget(*mDisplayId, hwcSlot, mFbFence, hwcBuffer,
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 16e69b9..73f27e4 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -278,14 +278,12 @@
return reduce(mBounds, activeTransparentRegion);
}
-ui::Transform Layer::getTransformWithScale() const {
+ui::Transform Layer::getBufferScaleTransform() const {
// If the layer is not using NATIVE_WINDOW_SCALING_MODE_FREEZE (e.g.
// it isFixedSize) then there may be additional scaling not accounted
- // for in the transform. We need to mirror this scaling to child surfaces
- // or we will break the contract where WM can treat child surfaces as
- // pixels in the parent surface.
+ // for in the layer transform.
if (!isFixedSize() || !mActiveBuffer) {
- return mEffectiveTransform;
+ return {};
}
// If the layer is a buffer state layer, the active width and height
@@ -293,24 +291,40 @@
const uint32_t activeWidth = getActiveWidth(getDrawingState());
const uint32_t activeHeight = getActiveHeight(getDrawingState());
if (activeWidth >= UINT32_MAX && activeHeight >= UINT32_MAX) {
- return mEffectiveTransform;
+ return {};
}
- int bufferWidth;
- int bufferHeight;
- if ((mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) == 0) {
- bufferWidth = mActiveBuffer->getWidth();
- bufferHeight = mActiveBuffer->getHeight();
- } else {
- bufferHeight = mActiveBuffer->getWidth();
- bufferWidth = mActiveBuffer->getHeight();
+ int bufferWidth = mActiveBuffer->getWidth();
+ int bufferHeight = mActiveBuffer->getHeight();
+
+ if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+ std::swap(bufferWidth, bufferHeight);
}
+
float sx = activeWidth / static_cast<float>(bufferWidth);
float sy = activeHeight / static_cast<float>(bufferHeight);
ui::Transform extraParentScaling;
extraParentScaling.set(sx, 0, 0, sy);
- return mEffectiveTransform * extraParentScaling;
+ return extraParentScaling;
+}
+
+ui::Transform Layer::getTransformWithScale(const ui::Transform& bufferScaleTransform) const {
+ // We need to mirror this scaling to child surfaces or we will break the contract where WM can
+ // treat child surfaces as pixels in the parent surface.
+ if (!isFixedSize() || !mActiveBuffer) {
+ return mEffectiveTransform;
+ }
+ return mEffectiveTransform * bufferScaleTransform;
+}
+
+FloatRect Layer::getBoundsPreScaling(const ui::Transform& bufferScaleTransform) const {
+ // We need the pre scaled layer bounds when computing child bounds to make sure the child is
+ // cropped to its parent layer after any buffer transform scaling is applied.
+ if (!isFixedSize() || !mActiveBuffer) {
+ return mBounds;
+ }
+ return bufferScaleTransform.inverse().transform(mBounds);
}
void Layer::computeBounds(FloatRect parentBounds, ui::Transform parentTransform) {
@@ -322,7 +336,7 @@
// Transform parent bounds to layer space
parentBounds = getActiveTransform(s).inverse().transform(parentBounds);
- // Calculate display frame
+ // Calculate source bounds
mSourceBounds = computeSourceBounds(parentBounds);
// Calculate bounds by croping diplay frame with layer crop and parent bounds
@@ -335,8 +349,12 @@
mBounds = bounds;
mScreenBounds = mEffectiveTransform.transform(mBounds);
+
+ // Add any buffer scaling to the layer's children.
+ ui::Transform bufferScaleTransform = getBufferScaleTransform();
for (const sp<Layer>& child : mDrawingChildren) {
- child->computeBounds(mBounds, getTransformWithScale());
+ child->computeBounds(getBoundsPreScaling(bufferScaleTransform),
+ getTransformWithScale(bufferScaleTransform));
}
}
@@ -1436,7 +1454,9 @@
void Layer::setChildrenDrawingParent(const sp<Layer>& newParent) {
for (const sp<Layer>& child : mDrawingChildren) {
child->mDrawingParent = newParent;
- child->computeBounds(newParent->mBounds, newParent->getTransformWithScale());
+ child->computeBounds(newParent->mBounds,
+ newParent->getTransformWithScale(
+ newParent->getBufferScaleTransform()));
}
}
@@ -1768,9 +1788,13 @@
}
Layer::RoundedCornerState Layer::getRoundedCornerState() const {
+ return getRoundedCornerStateInternal(mSourceBounds);
+}
+
+Layer::RoundedCornerState Layer::getRoundedCornerStateInternal(const FloatRect) const {
const auto& p = mDrawingParent.promote();
if (p != nullptr) {
- RoundedCornerState parentState = p->getRoundedCornerState();
+ RoundedCornerState parentState = p->getRoundedCornerStateInternal(mSourceBounds);
if (parentState.radius > 0) {
ui::Transform t = getActiveTransform(getDrawingState());
t = t.inverse();
@@ -1784,7 +1808,10 @@
}
}
const float radius = getDrawingState().cornerRadius;
- return radius > 0 ? RoundedCornerState(getBounds(), radius) : RoundedCornerState();
+ return radius > 0
+ ? RoundedCornerState(mSourceBounds.intersect(getCrop(getDrawingState()).toFloatRect()),
+ radius)
+ : RoundedCornerState();
}
void Layer::commitChildList() {
@@ -1819,7 +1846,8 @@
setTransactionFlags(eTransactionNeeded);
}
-void Layer::writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet) {
+void Layer::writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet,
+ uint32_t traceFlags) {
const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren;
const State& state = useDrawing ? mDrawingState : mCurrentState;
@@ -1827,114 +1855,129 @@
ui::Transform requestedTransform = state.active_legacy.transform;
ui::Transform transform = getTransform();
- layerInfo->set_id(sequence);
- layerInfo->set_name(getName().c_str());
- layerInfo->set_type(String8(getTypeId()));
+ if (traceFlags & SurfaceTracing::TRACE_CRITICAL) {
+ layerInfo->set_id(sequence);
+ layerInfo->set_name(getName().c_str());
+ layerInfo->set_type(String8(getTypeId()));
- for (const auto& child : children) {
- layerInfo->add_children(child->sequence);
- }
-
- for (const wp<Layer>& weakRelative : state.zOrderRelatives) {
- sp<Layer> strongRelative = weakRelative.promote();
- if (strongRelative != nullptr) {
- layerInfo->add_relatives(strongRelative->sequence);
+ for (const auto& child : children) {
+ layerInfo->add_children(child->sequence);
}
- }
- LayerProtoHelper::writeToProto(state.activeTransparentRegion_legacy,
- [&]() { return layerInfo->mutable_transparent_region(); });
- LayerProtoHelper::writeToProto(visibleRegion,
- [&]() { return layerInfo->mutable_visible_region(); });
- LayerProtoHelper::writeToProto(surfaceDamageRegion,
- [&]() { return layerInfo->mutable_damage_region(); });
-
- layerInfo->set_layer_stack(getLayerStack());
- layerInfo->set_z(state.z);
-
- LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
- [&]() { return layerInfo->mutable_position(); });
-
- LayerProtoHelper::writePositionToProto(requestedTransform.tx(), requestedTransform.ty(), [&]() {
- return layerInfo->mutable_requested_position();
- });
-
- LayerProtoHelper::writeSizeToProto(state.active_legacy.w, state.active_legacy.h,
- [&]() { return layerInfo->mutable_size(); });
-
- LayerProtoHelper::writeToProto(state.crop_legacy, [&]() { return layerInfo->mutable_crop(); });
- layerInfo->set_corner_radius(getRoundedCornerState().radius);
-
- layerInfo->set_is_opaque(isOpaque(state));
- layerInfo->set_invalidate(contentDirty);
-
- // XXX (b/79210409) mCurrentDataSpace is not protected
- layerInfo->set_dataspace(dataspaceDetails(static_cast<android_dataspace>(mCurrentDataSpace)));
-
- layerInfo->set_pixel_format(decodePixelFormat(getPixelFormat()));
- LayerProtoHelper::writeToProto(getColor(), [&]() { return layerInfo->mutable_color(); });
- LayerProtoHelper::writeToProto(state.color,
- [&]() { return layerInfo->mutable_requested_color(); });
- layerInfo->set_flags(state.flags);
-
- LayerProtoHelper::writeToProto(transform, layerInfo->mutable_transform());
- LayerProtoHelper::writeToProto(requestedTransform, layerInfo->mutable_requested_transform());
-
- auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote();
- if (parent != nullptr) {
- layerInfo->set_parent(parent->sequence);
- } else {
- layerInfo->set_parent(-1);
- }
-
- auto zOrderRelativeOf = state.zOrderRelativeOf.promote();
- if (zOrderRelativeOf != nullptr) {
- layerInfo->set_z_order_relative_of(zOrderRelativeOf->sequence);
- } else {
- layerInfo->set_z_order_relative_of(-1);
- }
-
- auto buffer = mActiveBuffer;
- if (buffer != nullptr) {
- LayerProtoHelper::writeToProto(buffer,
- [&]() { return layerInfo->mutable_active_buffer(); });
- LayerProtoHelper::writeToProto(ui::Transform(mCurrentTransform),
- layerInfo->mutable_buffer_transform());
- }
-
- layerInfo->set_queued_frames(getQueuedFrameCount());
- layerInfo->set_refresh_pending(isBufferLatched());
- layerInfo->set_curr_frame(mCurrentFrameNumber);
- layerInfo->set_effective_scaling_mode(getEffectiveScalingMode());
-
- for (const auto& pendingState : mPendingStates) {
- auto barrierLayer = pendingState.barrierLayer_legacy.promote();
- if (barrierLayer != nullptr) {
- BarrierLayerProto* barrierLayerProto = layerInfo->add_barrier_layer();
- barrierLayerProto->set_id(barrierLayer->sequence);
- barrierLayerProto->set_frame_number(pendingState.frameNumber_legacy);
+ for (const wp<Layer>& weakRelative : state.zOrderRelatives) {
+ sp<Layer> strongRelative = weakRelative.promote();
+ if (strongRelative != nullptr) {
+ layerInfo->add_relatives(strongRelative->sequence);
+ }
}
+
+ LayerProtoHelper::writeToProto(state.activeTransparentRegion_legacy,
+ [&]() { return layerInfo->mutable_transparent_region(); });
+ LayerProtoHelper::writeToProto(visibleRegion,
+ [&]() { return layerInfo->mutable_visible_region(); });
+ LayerProtoHelper::writeToProto(surfaceDamageRegion,
+ [&]() { return layerInfo->mutable_damage_region(); });
+
+ layerInfo->set_layer_stack(getLayerStack());
+ layerInfo->set_z(state.z);
+
+ LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
+ [&]() { return layerInfo->mutable_position(); });
+
+ LayerProtoHelper::writePositionToProto(requestedTransform.tx(), requestedTransform.ty(),
+ [&]() {
+ return layerInfo->mutable_requested_position();
+ });
+
+ LayerProtoHelper::writeSizeToProto(state.active_legacy.w, state.active_legacy.h,
+ [&]() { return layerInfo->mutable_size(); });
+
+ LayerProtoHelper::writeToProto(state.crop_legacy,
+ [&]() { return layerInfo->mutable_crop(); });
+ layerInfo->set_corner_radius(getRoundedCornerState().radius);
+
+ layerInfo->set_is_opaque(isOpaque(state));
+ layerInfo->set_invalidate(contentDirty);
+
+ // XXX (b/79210409) mCurrentDataSpace is not protected
+ layerInfo->set_dataspace(
+ dataspaceDetails(static_cast<android_dataspace>(mCurrentDataSpace)));
+
+ layerInfo->set_pixel_format(decodePixelFormat(getPixelFormat()));
+ LayerProtoHelper::writeToProto(getColor(), [&]() { return layerInfo->mutable_color(); });
+ LayerProtoHelper::writeToProto(state.color,
+ [&]() { return layerInfo->mutable_requested_color(); });
+ layerInfo->set_flags(state.flags);
+
+ LayerProtoHelper::writeToProto(transform, layerInfo->mutable_transform());
+ LayerProtoHelper::writeToProto(requestedTransform,
+ layerInfo->mutable_requested_transform());
+
+ auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote();
+ if (parent != nullptr) {
+ layerInfo->set_parent(parent->sequence);
+ } else {
+ layerInfo->set_parent(-1);
+ }
+
+ auto zOrderRelativeOf = state.zOrderRelativeOf.promote();
+ if (zOrderRelativeOf != nullptr) {
+ layerInfo->set_z_order_relative_of(zOrderRelativeOf->sequence);
+ } else {
+ layerInfo->set_z_order_relative_of(-1);
+ }
+
+ auto buffer = mActiveBuffer;
+ if (buffer != nullptr) {
+ LayerProtoHelper::writeToProto(buffer,
+ [&]() { return layerInfo->mutable_active_buffer(); });
+ LayerProtoHelper::writeToProto(ui::Transform(mCurrentTransform),
+ layerInfo->mutable_buffer_transform());
+ }
+
+ layerInfo->set_queued_frames(getQueuedFrameCount());
+ layerInfo->set_refresh_pending(isBufferLatched());
+ layerInfo->set_curr_frame(mCurrentFrameNumber);
+ layerInfo->set_effective_scaling_mode(getEffectiveScalingMode());
+
+ for (const auto& pendingState : mPendingStates) {
+ auto barrierLayer = pendingState.barrierLayer_legacy.promote();
+ if (barrierLayer != nullptr) {
+ BarrierLayerProto* barrierLayerProto = layerInfo->add_barrier_layer();
+ barrierLayerProto->set_id(barrierLayer->sequence);
+ barrierLayerProto->set_frame_number(pendingState.frameNumber_legacy);
+ }
+ }
+ LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); });
}
- auto protoMap = layerInfo->mutable_metadata();
- for (const auto& entry : state.metadata.mMap) {
- (*protoMap)[entry.first] = std::string(entry.second.cbegin(), entry.second.cend());
+ if (traceFlags & SurfaceTracing::TRACE_INPUT) {
+ LayerProtoHelper::writeToProto(state.inputInfo, state.touchableRegionCrop,
+ [&]() { return layerInfo->mutable_input_window_info(); });
}
- LayerProtoHelper::writeToProto(mEffectiveTransform, layerInfo->mutable_effective_transform());
- LayerProtoHelper::writeToProto(mSourceBounds,
- [&]() { return layerInfo->mutable_source_bounds(); });
- LayerProtoHelper::writeToProto(mScreenBounds,
- [&]() { return layerInfo->mutable_screen_bounds(); });
- LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); });
+
+ if (traceFlags & SurfaceTracing::TRACE_EXTRA) {
+ auto protoMap = layerInfo->mutable_metadata();
+ for (const auto& entry : state.metadata.mMap) {
+ (*protoMap)[entry.first] = std::string(entry.second.cbegin(), entry.second.cend());
+ }
+ LayerProtoHelper::writeToProto(mEffectiveTransform,
+ layerInfo->mutable_effective_transform());
+ LayerProtoHelper::writeToProto(mSourceBounds,
+ [&]() { return layerInfo->mutable_source_bounds(); });
+ LayerProtoHelper::writeToProto(mScreenBounds,
+ [&]() { return layerInfo->mutable_screen_bounds(); });
+ }
}
-void Layer::writeToProto(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice) {
+void Layer::writeToProto(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice,
+ uint32_t traceFlags) {
auto outputLayer = findOutputLayerForDisplay(displayDevice);
if (!outputLayer) {
return;
}
- writeToProto(layerInfo, LayerVector::StateSet::Drawing);
+ writeToProto(layerInfo, LayerVector::StateSet::Drawing, traceFlags);
const auto& compositionState = outputLayer->getState();
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index aba3ff2..b9dc7ec 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -361,9 +361,15 @@
// Compute bounds for the layer and cache the results.
void computeBounds(FloatRect parentBounds, ui::Transform parentTransform);
+ // Returns the buffer scale transform if a scaling mode is set.
+ ui::Transform getBufferScaleTransform() const;
+
// Get effective layer transform, taking into account all its parent transform with any
// scaling if the parent scaling more is not NATIVE_WINDOW_SCALING_MODE_FREEZE.
- ui::Transform getTransformWithScale() const;
+ ui::Transform getTransformWithScale(const ui::Transform& bufferScaleTransform) const;
+
+ // Returns the bounds of the layer without any buffer scaling.
+ FloatRect getBoundsPreScaling(const ui::Transform& bufferScaleTransform) const;
int32_t getSequence() const { return sequence; }
@@ -427,10 +433,11 @@
bool isRemovedFromCurrentState() const;
- void writeToProto(LayerProto* layerInfo,
- LayerVector::StateSet stateSet = LayerVector::StateSet::Drawing);
+ void writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet,
+ uint32_t traceFlags = SurfaceTracing::TRACE_ALL);
- void writeToProto(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice);
+ void writeToProto(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice,
+ uint32_t traceFlags = SurfaceTracing::TRACE_ALL);
virtual Geometry getActiveGeometry(const Layer::State& s) const { return s.active_legacy; }
virtual uint32_t getActiveWidth(const Layer::State& s) const { return s.active_legacy.w; }
@@ -445,13 +452,13 @@
virtual void setPostTime(nsecs_t /*postTime*/) {}
virtual void setDesiredPresentTime(nsecs_t /*desiredPresentTime*/) {}
+ virtual RoundedCornerState getRoundedCornerStateInternal(const FloatRect bounds) const;
protected:
virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
bool useIdentityTransform, Region& clearRegion,
const bool supportProtectedContent,
renderengine::LayerSettings& layer);
-
public:
/*
* compositionengine::LayerFE overrides
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index c25c418..c94e439 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -119,5 +119,41 @@
}
}
+void LayerProtoHelper::writeToProto(
+ const InputWindowInfo& inputInfo, const wp<Layer>& touchableRegionBounds,
+ std::function<InputWindowInfoProto*()> getInputWindowInfoProto) {
+ if (inputInfo.token == nullptr) {
+ return;
+ }
+
+ InputWindowInfoProto* proto = getInputWindowInfoProto();
+ proto->set_layout_params_flags(inputInfo.layoutParamsFlags);
+ proto->set_layout_params_type(inputInfo.layoutParamsType);
+
+ LayerProtoHelper::writeToProto({inputInfo.frameLeft, inputInfo.frameTop, inputInfo.frameRight,
+ inputInfo.frameBottom},
+ [&]() { return proto->mutable_frame(); });
+ LayerProtoHelper::writeToProto(inputInfo.touchableRegion,
+ [&]() { return proto->mutable_touchable_region(); });
+
+ proto->set_surface_inset(inputInfo.surfaceInset);
+ proto->set_visible(inputInfo.visible);
+ proto->set_can_receive_keys(inputInfo.canReceiveKeys);
+ proto->set_has_focus(inputInfo.hasFocus);
+ proto->set_has_wallpaper(inputInfo.hasWallpaper);
+
+ proto->set_global_scale_factor(inputInfo.globalScaleFactor);
+ proto->set_window_x_scale(inputInfo.windowXScale);
+ proto->set_window_y_scale(inputInfo.windowYScale);
+ proto->set_replace_touchable_region_with_crop(inputInfo.replaceTouchableRegionWithCrop);
+ auto cropLayer = touchableRegionBounds.promote();
+ if (cropLayer != nullptr) {
+ proto->set_crop_layer_id(cropLayer->sequence);
+ LayerProtoHelper::writeToProto(cropLayer->getScreenBounds(
+ false /* reduceTransparentRegion */),
+ [&]() { return proto->mutable_touchable_region_crop(); });
+ }
+}
+
} // namespace surfaceflinger
} // namespace android
diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h
index dca9a5e..1754a3f 100644
--- a/services/surfaceflinger/LayerProtoHelper.h
+++ b/services/surfaceflinger/LayerProtoHelper.h
@@ -16,6 +16,8 @@
#include <layerproto/LayerProtoHeader.h>
+#include <Layer.h>
+#include <input/InputWindow.h>
#include <math/vec4.h>
#include <ui/GraphicBuffer.h>
#include <ui/Rect.h>
@@ -38,6 +40,9 @@
static void writeToProto(const ui::Transform& transform, TransformProto* transformProto);
static void writeToProto(const sp<GraphicBuffer>& buffer,
std::function<ActiveBufferProto*()> getActiveBufferProto);
+ static void writeToProto(const InputWindowInfo& inputInfo,
+ const wp<Layer>& touchableRegionBounds,
+ std::function<InputWindowInfoProto*()> getInputWindowInfoProto);
};
} // namespace surfaceflinger
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 5296da9..a2a6bd8 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -211,13 +211,14 @@
const nsecs_t numPeriodsSinceReference = baseTime / mPeriod;
const nsecs_t predictedReference = mReferenceTime + numPeriodsSinceReference * mPeriod;
const nsecs_t phaseCorrection = mPhase + listener.mPhase;
- const nsecs_t predictedLastEventTime = predictedReference + phaseCorrection;
- if (predictedLastEventTime >= now) {
- // Make sure that the last event time does not exceed the current time.
- // If it would, then back the last event time by a period.
- listener.mLastEventTime = predictedLastEventTime - mPeriod;
- } else {
- listener.mLastEventTime = predictedLastEventTime;
+ listener.mLastEventTime = predictedReference + phaseCorrection;
+ // If we're very close in time to the predicted last event time,
+ // then we need to back up the last event time so that we can
+ // attempt to fire an event immediately.
+ //
+ // Otherwise, keep the last event time that we predicted.
+ if (isShorterThanPeriod(now - listener.mLastEventTime)) {
+ listener.mLastEventTime -= mPeriod;
}
} else {
listener.mLastEventTime = now + mPhase - mWakeupLatency;
@@ -314,7 +315,7 @@
// Sanity check that the duration is close enough in length to a period without
// falling into double-rate vsyncs.
- bool isCloseToPeriod(nsecs_t duration) {
+ bool isShorterThanPeriod(nsecs_t duration) {
// Ratio of 3/5 is arbitrary, but it must be greater than 1/2.
return duration < (3 * mPeriod) / 5;
}
@@ -330,7 +331,7 @@
nsecs_t t = computeListenerNextEventTimeLocked(eventListener, onePeriodAgo);
if (t < now) {
- if (isCloseToPeriod(now - eventListener.mLastCallbackTime)) {
+ if (isShorterThanPeriod(now - eventListener.mLastCallbackTime)) {
eventListener.mLastEventTime = t;
eventListener.mLastCallbackTime = now;
ALOGV("[%s] [%s] Skipping event due to model error", mName,
@@ -391,7 +392,7 @@
// Check that it's been slightly more than half a period since the last
// event so that we don't accidentally fall into double-rate vsyncs
- if (isCloseToPeriod(t - listener.mLastEventTime)) {
+ if (isShorterThanPeriod(t - listener.mLastEventTime)) {
t += mPeriod;
ALOGV("[%s] Modifying t -> %" PRId64, mName, ns2us(t));
}
@@ -789,31 +790,6 @@
StringAppendF(&result, "current monotonic time: %" PRId64 "\n", now);
}
-// TODO(b/113612090): Figure out how much of this is still relevant.
-// We need to determine the time when a buffer acquired now will be
-// displayed. This can be calculated:
-// time when previous buffer's actual-present fence was signaled
-// + current display refresh rate * HWC latency
-// + a little extra padding
-//
-// Buffer producers are expected to set their desired presentation time
-// based on choreographer time stamps, which (coming from vsync events)
-// will be slightly later then the actual-present timing. If we get a
-// desired-present time that is unintentionally a hair after the next
-// vsync, we'll hold the frame when we really want to display it. We
-// need to take the offset between actual-present and reported-vsync
-// into account.
-//
-// If the system is configured without a DispSync phase offset for the app,
-// we also want to throw in a bit of padding to avoid edge cases where we
-// just barely miss. We want to do it here, not in every app. A major
-// source of trouble is the app's use of the display's ideal refresh time
-// (via Display.getRefreshRate()), which could be off of the actual refresh
-// by a few percent, with the error multiplied by the number of frames
-// between now and when the buffer should be displayed.
-//
-// If the refresh reported to the app has a phase offset, we shouldn't need
-// to tweak anything here.
nsecs_t DispSync::expectedPresentTime() {
// The HWC doesn't currently have a way to report additional latency.
// Assume that whatever we submit now will appear right after the flip.
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index d5e3349..67e6de9 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -135,7 +135,7 @@
public:
using InterceptVSyncsCallback = std::function<void(nsecs_t)>;
- // TODO(b/113612090): Once the Scheduler is complete this constructor will become obsolete.
+ // TODO(b/128863962): Once the Scheduler is complete this constructor will become obsolete.
EventThread(VSyncSource*, InterceptVSyncsCallback, const char* threadName);
EventThread(std::unique_ptr<VSyncSource>, InterceptVSyncsCallback, const char* threadName);
~EventThread();
@@ -169,7 +169,7 @@
using DisplayEventConsumers = std::vector<sp<EventThreadConnection>>;
- // TODO(b/113612090): Once the Scheduler is complete this constructor will become obsolete.
+ // TODO(b/128863962): Once the Scheduler is complete this constructor will become obsolete.
EventThread(VSyncSource* src, std::unique_ptr<VSyncSource> uniqueSrc,
InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName);
@@ -186,10 +186,7 @@
// Implements VSyncSource::Callback
void onVSyncEvent(nsecs_t timestamp) override;
- // Acquires mutex and requests next vsync.
- void requestNextVsyncInternal(const sp<EventThreadConnection>& connection) EXCLUDES(mMutex);
-
- // TODO(b/113612090): Once the Scheduler is complete this pointer will become obsolete.
+ // TODO(b/128863962): Once the Scheduler is complete this pointer will become obsolete.
VSyncSource* mVSyncSource GUARDED_BY(mMutex) = nullptr;
std::unique_ptr<VSyncSource> mVSyncSourceUnique GUARDED_BY(mMutex) = nullptr;
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index 56a00c0..245a8ac 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -85,7 +85,7 @@
virtual ~MessageQueue();
virtual void init(const sp<SurfaceFlinger>& flinger) = 0;
- // TODO(akrulec): Remove this function once everything is migrated to Scheduler.
+ // TODO(b/128863962): Remove this function once everything is migrated to Scheduler.
virtual void setEventThread(EventThread* events, ResyncCallback resyncCallback) = 0;
virtual void setEventConnection(const sp<EventThreadConnection>& connection) = 0;
virtual void waitMessage() = 0;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h
index 6b78cee..ff63faf 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateStats.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h
@@ -153,7 +153,7 @@
// Aggregate refresh rate statistics for telemetry.
std::shared_ptr<TimeStats> mTimeStats;
- int64_t mCurrentConfigMode = 0;
+ int64_t mCurrentConfigMode = SCREEN_OFF_CONFIG_ID;
int32_t mCurrentPowerMode = HWC_POWER_MODE_OFF;
std::unordered_map<int /* power mode */, int64_t /* duration in ms */> mConfigModesTotalTime;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 3c98349..945f6fa 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -157,6 +157,28 @@
return false;
}
+bool isHdrColorMode(const ColorMode colorMode) {
+ switch (colorMode) {
+ case ColorMode::BT2100_PQ:
+ case ColorMode::BT2100_HLG:
+ return true;
+ case ColorMode::DISPLAY_P3:
+ case ColorMode::ADOBE_RGB:
+ case ColorMode::DCI_P3:
+ case ColorMode::BT2020:
+ case ColorMode::DISPLAY_BT2020:
+ case ColorMode::NATIVE:
+ case ColorMode::STANDARD_BT601_625:
+ case ColorMode::STANDARD_BT601_625_UNADJUSTED:
+ case ColorMode::STANDARD_BT601_525:
+ case ColorMode::STANDARD_BT601_525_UNADJUSTED:
+ case ColorMode::STANDARD_BT709:
+ case ColorMode::SRGB:
+ return false;
+ }
+ return false;
+}
+
ui::Transform::orientation_flags fromSurfaceComposerRotation(ISurfaceComposer::Rotation rotation) {
switch (rotation) {
case ISurfaceComposer::eRotateNone:
@@ -717,6 +739,7 @@
mRefreshRateStats =
std::make_unique<scheduler::RefreshRateStats>(mRefreshRateConfigs[*display->getId()],
mTimeStats);
+ mRefreshRateStats->setConfigMode(getHwComposer().getActiveConfigIndex(*display->getId()));
ALOGV("Done initializing");
}
@@ -1224,7 +1247,7 @@
auto resyncCallback =
mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
- // TODO(akrulec): Part of the Injector should be refactored, so that it
+ // TODO(b/128863962): Part of the Injector should be refactored, so that it
// can be passed to Scheduler.
if (enable) {
ALOGV("VSync Injections enabled");
@@ -1844,7 +1867,9 @@
const auto& displayState = display->getState();
layer->setPerFrameData(displayDevice, displayState.transform, displayState.viewport,
- displayDevice->getSupportedPerFrameMetadata(), targetDataspace);
+ displayDevice->getSupportedPerFrameMetadata(),
+ isHdrColorMode(displayState.colorMode) ? Dataspace::UNKNOWN
+ : targetDataspace);
}
}
@@ -2890,13 +2915,13 @@
}
void SurfaceFlinger::updateInputWindowInfo() {
- Vector<InputWindowInfo> inputHandles;
+ std::vector<InputWindowInfo> inputHandles;
mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
if (layer->hasInput()) {
// When calculating the screen bounds we ignore the transparent region since it may
// result in an unwanted offset.
- inputHandles.add(layer->fillInputInfo());
+ inputHandles.push_back(layer->fillInputInfo());
}
});
@@ -3492,13 +3517,15 @@
auto& [applyToken, transactionQueue] = *it;
while (!transactionQueue.empty()) {
- const auto& [states, displays, flags, desiredPresentTime, postTime, privileged] =
- transactionQueue.front();
+ const auto&
+ [states, displays, flags, desiredPresentTime, uncacheBuffer, postTime,
+ privileged] = transactionQueue.front();
if (!transactionIsReadyToBeApplied(desiredPresentTime, states)) {
break;
}
applyTransactionState(states, displays, flags, mPendingInputWindowCommands,
- desiredPresentTime, postTime, privileged);
+ desiredPresentTime, uncacheBuffer, postTime, privileged,
+ /*isMainThread*/ true);
transactionQueue.pop();
}
@@ -3555,7 +3582,8 @@
const Vector<DisplayState>& displays, uint32_t flags,
const sp<IBinder>& applyToken,
const InputWindowCommands& inputWindowCommands,
- int64_t desiredPresentTime) {
+ int64_t desiredPresentTime,
+ const cached_buffer_t& uncacheBuffer) {
ATRACE_CALL();
const int64_t postTime = systemTime();
@@ -3572,20 +3600,22 @@
if (mTransactionQueues.find(applyToken) != mTransactionQueues.end() ||
!transactionIsReadyToBeApplied(desiredPresentTime, states)) {
mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime,
- postTime, privileged);
+ uncacheBuffer, postTime, privileged);
setTransactionFlags(eTransactionNeeded);
return;
}
applyTransactionState(states, displays, flags, inputWindowCommands, desiredPresentTime,
- postTime, privileged);
+ uncacheBuffer, postTime, privileged);
}
void SurfaceFlinger::applyTransactionState(const Vector<ComposerState>& states,
const Vector<DisplayState>& displays, uint32_t flags,
const InputWindowCommands& inputWindowCommands,
- const int64_t desiredPresentTime, const int64_t postTime,
- bool privileged) {
+ const int64_t desiredPresentTime,
+ const cached_buffer_t& uncacheBuffer,
+ const int64_t postTime, bool privileged,
+ bool isMainThread) {
uint32_t transactionFlags = 0;
if (flags & eAnimation) {
@@ -3620,6 +3650,10 @@
transactionFlags |= addInputWindowCommands(inputWindowCommands);
+ if (uncacheBuffer.token) {
+ BufferStateLayerCache::getInstance().erase(uncacheBuffer.token, uncacheBuffer.cacheId);
+ }
+
// If a synchronous transaction is explicitly requested without any changes, force a transaction
// anyway. This can be used as a flush mechanism for previous async transactions.
// Empty animation transaction can be used to simulate back-pressure, so also force a
@@ -3649,7 +3683,12 @@
}
mPendingSyncInputWindows = mPendingInputWindowCommands.syncInputWindows;
- while (mTransactionPending || mPendingSyncInputWindows) {
+
+ // applyTransactionState can be called by either the main SF thread or by
+ // another process through setTransactionState. While a given process may wish
+ // to wait on synchronous transactions, the main SF thread should never
+ // be blocked. Therefore, we only wait if isMainThread is false.
+ while (!isMainThread && (mTransactionPending || mPendingSyncInputWindows)) {
status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
if (CC_UNLIKELY(err != NO_ERROR)) {
// just in case something goes wrong in SF, return to the
@@ -3956,16 +3995,20 @@
callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface));
}
}
-
- if (what & layer_state_t::eBufferChanged) {
- // Add the new buffer to the cache. This should always come before eCachedBufferChanged.
- BufferStateLayerCache::getInstance().add(s.cachedBuffer.token, s.cachedBuffer.bufferId,
+ bool bufferChanged = what & layer_state_t::eBufferChanged;
+ bool cacheIdChanged = what & layer_state_t::eCachedBufferChanged;
+ sp<GraphicBuffer> buffer;
+ if (bufferChanged && cacheIdChanged) {
+ BufferStateLayerCache::getInstance().add(s.cachedBuffer.token, s.cachedBuffer.cacheId,
s.buffer);
+ buffer = s.buffer;
+ } else if (cacheIdChanged) {
+ buffer = BufferStateLayerCache::getInstance().get(s.cachedBuffer.token,
+ s.cachedBuffer.cacheId);
+ } else if (bufferChanged) {
+ buffer = s.buffer;
}
- if (what & layer_state_t::eCachedBufferChanged) {
- sp<GraphicBuffer> buffer =
- BufferStateLayerCache::getInstance().get(s.cachedBuffer.token,
- s.cachedBuffer.bufferId);
+ if (buffer) {
if (layer->setBuffer(buffer)) {
flags |= eTraversalNeeded;
layer->setPostTime(postTime);
@@ -4209,7 +4252,7 @@
d.width = 0;
d.height = 0;
displays.add(d);
- setTransactionState(state, displays, 0, nullptr, mPendingInputWindowCommands, -1);
+ setTransactionState(state, displays, 0, nullptr, mPendingInputWindowCommands, -1, {});
setPowerModeInternal(display, HWC_POWER_MODE_NORMAL);
@@ -4623,13 +4666,14 @@
result.append("\n");
}
-LayersProto SurfaceFlinger::dumpProtoInfo(LayerVector::StateSet stateSet) const {
+LayersProto SurfaceFlinger::dumpProtoInfo(LayerVector::StateSet stateSet,
+ uint32_t traceFlags) const {
LayersProto layersProto;
const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
const State& state = useDrawing ? mDrawingState : mCurrentState;
state.traverseInZOrder([&](Layer* layer) {
LayerProto* layerProto = layersProto.add_layers();
- layer->writeToProto(layerProto, stateSet);
+ layer->writeToProto(layerProto, stateSet, traceFlags);
});
return layersProto;
@@ -4972,9 +5016,9 @@
code == IBinder::SYSPROPS_TRANSACTION) {
return OK;
}
- // Numbers from 1000 to 1032 are currently use for backdoors. The code
+ // Numbers from 1000 to 1033 are currently used for backdoors. The code
// in onTransact verifies that the user is root, and has access to use SF.
- if (code >= 1000 && code <= 1032) {
+ if (code >= 1000 && code <= 1033) {
ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
return OK;
}
@@ -5282,6 +5326,14 @@
mDebugEnableProtectedContent = n;
return NO_ERROR;
}
+ // Set trace flags
+ case 1033: {
+ n = data.readUint32();
+ ALOGD("Updating trace flags to 0x%x", n);
+ mTracing.setTraceFlags(n);
+ reply->writeInt32(NO_ERROR);
+ return NO_ERROR;
+ }
}
}
return err;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 0d39cb5..26d0cd1 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -431,7 +431,8 @@
const Vector<DisplayState>& displays, uint32_t flags,
const sp<IBinder>& applyToken,
const InputWindowCommands& inputWindowCommands,
- int64_t desiredPresentTime) override;
+ int64_t desiredPresentTime,
+ const cached_buffer_t& uncacheBuffer) override;
void bootFinished() override;
bool authenticateSurfaceTexture(
const sp<IGraphicBufferProducer>& bufferProducer) const override;
@@ -577,8 +578,9 @@
void applyTransactionState(const Vector<ComposerState>& state,
const Vector<DisplayState>& displays, uint32_t flags,
const InputWindowCommands& inputWindowCommands,
- const int64_t desiredPresentTime, const int64_t postTime,
- bool privileged) REQUIRES(mStateLock);
+ const int64_t desiredPresentTime,
+ const cached_buffer_t& uncacheBuffer, const int64_t postTime,
+ bool privileged, bool isMainThread = false) REQUIRES(mStateLock);
bool flushTransactionQueues();
uint32_t getTransactionFlags(uint32_t flags);
uint32_t peekTransactionFlags();
@@ -895,7 +897,8 @@
void dumpBufferingStats(std::string& result) const;
void dumpDisplayIdentificationData(std::string& result) const;
void dumpWideColorInfo(std::string& result) const;
- LayersProto dumpProtoInfo(LayerVector::StateSet stateSet) const;
+ LayersProto dumpProtoInfo(LayerVector::StateSet stateSet,
+ uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
void withTracingLock(std::function<void()> operation) REQUIRES(mStateLock);
LayersProto dumpVisibleLayersProtoInfo(const sp<DisplayDevice>& display) const;
@@ -1058,11 +1061,13 @@
struct TransactionState {
TransactionState(const Vector<ComposerState>& composerStates,
const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
- int64_t desiredPresentTime, int64_t postTime, bool privileged)
+ int64_t desiredPresentTime, const cached_buffer_t& uncacheBuffer,
+ int64_t postTime, bool privileged)
: states(composerStates),
displays(displayStates),
flags(transactionFlags),
desiredPresentTime(desiredPresentTime),
+ buffer(uncacheBuffer),
postTime(postTime),
privileged(privileged) {}
@@ -1070,6 +1075,7 @@
Vector<DisplayState> displays;
uint32_t flags;
const int64_t desiredPresentTime;
+ cached_buffer_t buffer;
const int64_t postTime;
bool privileged;
};
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index f1c4347..c4ab066 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -28,46 +28,56 @@
namespace android {
-void SurfaceTracing::mainLoop() {
- bool enabled = true;
- // Upon activation, logs the first frame
- traceLayers("tracing.enable");
- do {
- std::unique_lock<std::mutex> sfLock(mFlinger.mDrawingStateLock);
- mConditionalVariable.wait(sfLock);
- LayersTraceProto entry = traceLayersLocked(mWhere);
- sfLock.unlock();
- {
- std::scoped_lock bufferLock(mTraceLock);
- mBuffer.emplace(std::move(entry));
- if (mWriteToFile) {
- writeProtoFileLocked();
- mWriteToFile = false;
- }
+SurfaceTracing::SurfaceTracing(SurfaceFlinger& flinger)
+ : mFlinger(flinger), mSfLock(flinger.mDrawingStateLock) {}
- enabled = mEnabled;
- }
- } while (enabled);
+void SurfaceTracing::mainLoop() {
+ addFirstEntry();
+ bool enabled = true;
+ while (enabled) {
+ LayersTraceProto entry = traceWhenNotified();
+ enabled = addTraceToBuffer(entry);
+ }
}
-void SurfaceTracing::traceLayers(const char* where) {
- std::unique_lock<std::mutex> sfLock(mFlinger.mDrawingStateLock);
- LayersTraceProto entry = traceLayersLocked(where);
- sfLock.unlock();
- std::scoped_lock bufferLock(mTraceLock);
+void SurfaceTracing::addFirstEntry() {
+ LayersTraceProto entry;
+ {
+ std::scoped_lock lock(mSfLock);
+ entry = traceLayersLocked("tracing.enable");
+ }
+ addTraceToBuffer(entry);
+}
+
+LayersTraceProto SurfaceTracing::traceWhenNotified() {
+ std::unique_lock<std::mutex> lock(mSfLock);
+ mCanStartTrace.wait(lock);
+ android::base::ScopedLockAssertion assumeLock(mSfLock);
+ LayersTraceProto entry = traceLayersLocked(mWhere);
+ lock.unlock();
+ return entry;
+}
+
+bool SurfaceTracing::addTraceToBuffer(LayersTraceProto& entry) {
+ std::scoped_lock lock(mTraceLock);
mBuffer.emplace(std::move(entry));
+ if (mWriteToFile) {
+ writeProtoFileLocked();
+ mWriteToFile = false;
+ }
+ return mEnabled;
}
void SurfaceTracing::notify(const char* where) {
- std::lock_guard<std::mutex> sfLock(mFlinger.mDrawingStateLock);
- mWhere = strdup(where);
- mConditionalVariable.notify_one();
+ std::scoped_lock lock(mSfLock);
+ mWhere = where;
+ mCanStartTrace.notify_one();
}
void SurfaceTracing::writeToFileAsync() {
- std::lock_guard<std::mutex> bufferLock(mTraceLock);
+ std::scoped_lock lock(mTraceLock);
mWriteToFile = true;
- mConditionalVariable.notify_one();
+ mCanStartTrace.notify_one();
}
void SurfaceTracing::LayersTraceBuffer::reset(size_t newSize) {
@@ -102,12 +112,11 @@
}
void SurfaceTracing::enable() {
- std::lock_guard<std::mutex> bufferLock(mTraceLock);
+ std::scoped_lock lock(mTraceLock);
if (mEnabled) {
return;
}
-
mBuffer.reset(mBufferSize);
mEnabled = true;
mThread = std::thread(&SurfaceTracing::mainLoop, this);
@@ -119,7 +128,7 @@
}
bool SurfaceTracing::disable() {
- std::lock_guard<std::mutex> bufferLock(mTraceLock);
+ std::scoped_lock lock(mTraceLock);
if (!mEnabled) {
return false;
@@ -127,28 +136,33 @@
mEnabled = false;
mWriteToFile = true;
- mConditionalVariable.notify_all();
+ mCanStartTrace.notify_all();
return true;
}
bool SurfaceTracing::isEnabled() const {
- std::lock_guard<std::mutex> bufferLock(mTraceLock);
+ std::scoped_lock lock(mTraceLock);
return mEnabled;
}
void SurfaceTracing::setBufferSize(size_t bufferSizeInByte) {
- std::lock_guard<std::mutex> bufferLock(mTraceLock);
+ std::scoped_lock lock(mTraceLock);
mBufferSize = bufferSizeInByte;
mBuffer.setSize(bufferSizeInByte);
}
+void SurfaceTracing::setTraceFlags(uint32_t flags) {
+ std::scoped_lock lock(mSfLock);
+ mTraceFlags = flags;
+}
+
LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where) {
ATRACE_CALL();
LayersTraceProto entry;
entry.set_elapsed_realtime_nanos(elapsedRealtimeNano());
entry.set_where(where);
- LayersProto layers(mFlinger.dumpProtoInfo(LayerVector::StateSet::Drawing));
+ LayersProto layers(mFlinger.dumpProtoInfo(LayerVector::StateSet::Drawing, mTraceFlags));
entry.mutable_layers()->Swap(&layers);
return entry;
@@ -179,8 +193,7 @@
}
void SurfaceTracing::dump(std::string& result) const {
- std::lock_guard<std::mutex> bufferLock(mTraceLock);
-
+ std::scoped_lock lock(mTraceLock);
base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled");
base::StringAppendF(&result, " number of entries: %zu (%.2fMB / %.2fMB)\n",
mBuffer.frameCount(), float(mBuffer.used()) / float(1_MB),
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
index a75ac61..4be2ee9 100644
--- a/services/surfaceflinger/SurfaceTracing.h
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -41,7 +41,7 @@
*/
class SurfaceTracing {
public:
- SurfaceTracing(SurfaceFlinger& flinger) : mFlinger(flinger) {}
+ SurfaceTracing(SurfaceFlinger& flinger);
void enable();
bool disable();
status_t writeToFile();
@@ -52,6 +52,14 @@
void writeToFileAsync();
void dump(std::string& result) const;
+ enum : uint32_t {
+ TRACE_CRITICAL = 1 << 0,
+ TRACE_INPUT = 1 << 1,
+ TRACE_EXTRA = 1 << 2,
+ TRACE_ALL = 0xffffffff
+ };
+ void setTraceFlags(uint32_t flags);
+
private:
static constexpr auto kDefaultBufferCapInByte = 100_MB;
static constexpr auto kDefaultFileName = "/data/misc/wmtrace/layers_trace.pb";
@@ -74,18 +82,24 @@
};
void mainLoop();
- void traceLayers(const char* where);
- LayersTraceProto traceLayersLocked(const char* where);
+ void addFirstEntry();
+ LayersTraceProto traceWhenNotified();
+ LayersTraceProto traceLayersLocked(const char* where) REQUIRES(mSfLock);
+
+ // Returns true if trace is enabled.
+ bool addTraceToBuffer(LayersTraceProto& entry);
void writeProtoFileLocked() REQUIRES(mTraceLock);
const SurfaceFlinger& mFlinger;
-
- char* mWhere;
status_t mLastErr = NO_ERROR;
std::thread mThread;
- std::condition_variable mConditionalVariable;
- mutable std::mutex mTraceLock;
+ std::condition_variable mCanStartTrace;
+ std::mutex& mSfLock;
+ uint32_t mTraceFlags GUARDED_BY(mSfLock) = TRACE_ALL;
+ const char* mWhere GUARDED_BY(mSfLock) = "";
+
+ mutable std::mutex mTraceLock;
LayersTraceBuffer mBuffer GUARDED_BY(mTraceLock);
size_t mBufferSize GUARDED_BY(mTraceLock) = kDefaultBufferCapInByte;
bool mEnabled GUARDED_BY(mTraceLock) = false;
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index fd4695e..b097505 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -96,6 +96,8 @@
FloatRectProto source_bounds = 44;
FloatRectProto bounds = 45;
FloatRectProto screen_bounds = 46;
+
+ InputWindowInfoProto input_window_info = 47;
}
message PositionProto {
@@ -155,3 +157,24 @@
// frame number the barrier is waiting on.
uint64 frame_number = 2;
}
+
+message InputWindowInfoProto {
+ uint32 layout_params_flags = 1;
+ uint32 layout_params_type = 2;
+ RectProto frame = 3;
+ RegionProto touchable_region = 4;
+
+ uint32 surface_inset = 5;
+ bool visible = 6;
+ bool can_receive_keys = 7;
+ bool has_focus = 8;
+ bool has_wallpaper = 9;
+
+ float global_scale_factor = 10;
+ float window_x_scale = 11;
+ float window_y_scale = 12;
+
+ uint32 crop_layer_id = 13;
+ bool replace_touchable_region_with_crop = 14;
+ RectProto touchable_region_crop = 15;
+}
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index bc5642e..d62afa5 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -4307,7 +4307,7 @@
protected:
void SetUp() override {
LayerUpdateTest::SetUp();
- mChild = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888, 0,
+ mChild = createSurface(mClient, "Child surface", 10, 15, PIXEL_FORMAT_RGBA_8888, 0,
mFGSurfaceControl.get());
fillSurfaceRGBA8(mChild, 200, 200, 200);
@@ -4413,6 +4413,32 @@
}
}
+// A child with a scale transform should be cropped by its parent bounds.
+TEST_F(ChildLayerTest, ChildLayerScalingCroppedByParent) {
+ asTransaction([&](Transaction& t) {
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ t.setPosition(mChild, 0, 0);
+ });
+
+ // Find the boundary between the parent and child.
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(9, 9);
+ mCapture->expectFGColor(10, 10);
+ }
+
+ asTransaction([&](Transaction& t) { t.setMatrix(mChild, 10.0, 0, 0, 10.0); });
+
+ // The child should fill its parent bounds and be cropped by it.
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(63, 63);
+ mCapture->expectBGColor(64, 64);
+ }
+}
+
TEST_F(ChildLayerTest, ChildLayerAlpha) {
fillSurfaceRGBA8(mBGSurfaceControl, 0, 0, 254);
fillSurfaceRGBA8(mFGSurfaceControl, 254, 0, 0);
@@ -4649,8 +4675,8 @@
mCapture = screenshot();
// We've positioned the child in the top left.
mCapture->expectChildColor(0, 0);
- // But it's only 10x10.
- mCapture->expectFGColor(10, 10);
+ // But it's only 10x15.
+ mCapture->expectFGColor(10, 15);
}
asTransaction([&](Transaction& t) {
@@ -4664,9 +4690,9 @@
// We've positioned the child in the top left.
mCapture->expectChildColor(0, 0);
mCapture->expectChildColor(10, 10);
- mCapture->expectChildColor(19, 19);
- // And now it should be scaled all the way to 20x20
- mCapture->expectFGColor(20, 20);
+ mCapture->expectChildColor(19, 29);
+ // And now it should be scaled all the way to 20x30
+ mCapture->expectFGColor(20, 30);
}
}
@@ -4682,8 +4708,9 @@
mCapture = screenshot();
// We've positioned the child in the top left.
mCapture->expectChildColor(0, 0);
- // But it's only 10x10.
- mCapture->expectFGColor(10, 10);
+ mCapture->expectChildColor(9, 14);
+ // But it's only 10x15.
+ mCapture->expectFGColor(10, 15);
}
// We set things up as in b/37673612 so that there is a mismatch between the buffer size and
// the WM specified state size.
@@ -4704,6 +4731,115 @@
}
}
+// A child with a buffer transform from its parents should be cropped by its parent bounds.
+TEST_F(ChildLayerTest, ChildCroppedByParentWithBufferTransform) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 0, 0);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ t.setSize(mChild, 100, 100);
+ });
+ fillSurfaceRGBA8(mChild, 200, 200, 200);
+
+ {
+ mCapture = screenshot();
+
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(63, 63);
+ mCapture->expectBGColor(64, 64);
+ }
+
+ asTransaction([&](Transaction& t) { t.setSize(mFGSurfaceControl, 128, 64); });
+ sp<Surface> s = mFGSurfaceControl->getSurface();
+ auto anw = static_cast<ANativeWindow*>(s.get());
+ // Apply a 90 transform on the buffer.
+ native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
+ native_window_set_buffers_dimensions(anw, 64, 128);
+ fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
+ waitForPostedBuffers();
+
+ // The child should be cropped by the new parent bounds.
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(99, 63);
+ mCapture->expectFGColor(100, 63);
+ mCapture->expectBGColor(128, 64);
+ }
+}
+
+// A child with a scale transform from its parents should be cropped by its parent bounds.
+TEST_F(ChildLayerTest, ChildCroppedByParentWithBufferScale) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 0, 0);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ t.setSize(mChild, 200, 200);
+ });
+ fillSurfaceRGBA8(mChild, 200, 200, 200);
+
+ {
+ mCapture = screenshot();
+
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(63, 63);
+ mCapture->expectBGColor(64, 64);
+ }
+
+ asTransaction([&](Transaction& t) {
+ t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ // Set a scaling by 2.
+ t.setSize(mFGSurfaceControl, 128, 128);
+ });
+
+ // Child should inherit its parents scale but should be cropped by its parent bounds.
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(127, 127);
+ mCapture->expectBGColor(128, 128);
+ }
+}
+
+// Regression test for b/127368943
+// Child should ignore the buffer transform but apply parent scale transform.
+TEST_F(ChildLayerTest, ChildrenWithParentBufferTransformAndScale) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 0, 0);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ });
+
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(9, 14);
+ mCapture->expectFGColor(10, 15);
+ }
+
+ // Change the size of the foreground to 128 * 64 so we can test rotation as well.
+ asTransaction([&](Transaction& t) {
+ t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ t.setSize(mFGSurfaceControl, 128, 64);
+ });
+ sp<Surface> s = mFGSurfaceControl->getSurface();
+ auto anw = static_cast<ANativeWindow*>(s.get());
+ // Apply a 90 transform on the buffer and submit a buffer half the expected size so that we
+ // have an effective scale of 2.0 applied to the buffer along with a rotation transform.
+ native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
+ native_window_set_buffers_dimensions(anw, 32, 64);
+ fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
+ waitForPostedBuffers();
+
+ // The child should ignore the buffer transform but apply the 2.0 scale from parent.
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(19, 29);
+ mCapture->expectFGColor(20, 30);
+ }
+}
+
TEST_F(ChildLayerTest, Bug36858924) {
// Destroy the child layer
mChild.clear();
@@ -4857,6 +4993,7 @@
mCapture->checkPixel(10, 10, 255, 255, 255);
}
}
+
class BoundlessLayerTest : public LayerUpdateTest {
protected:
std::unique_ptr<ScreenCapture> mCapture;
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index 4342dc9..10f5af8 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -27,6 +27,7 @@
using namespace std::chrono_literals;
using testing::_;
+using testing::AtLeast;
namespace android {
namespace scheduler {
@@ -75,7 +76,7 @@
init(configs);
// There is one default config, so the refresh rates should have one item.
- ASSERT_EQ(1, mRefreshRateStats->getTotalTimes().size());
+ EXPECT_EQ(1, mRefreshRateStats->getTotalTimes().size());
}
TEST_F(RefreshRateStatsTest, oneConfigTest) {
@@ -88,13 +89,14 @@
init(configs);
- EXPECT_CALL(*mTimeStats, recordRefreshRate(0, _)).Times(4);
- EXPECT_CALL(*mTimeStats, recordRefreshRate(90, _)).Times(2);
+ EXPECT_CALL(*mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1));
+ EXPECT_CALL(*mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1));
std::unordered_map<std::string, int64_t> times = mRefreshRateStats->getTotalTimes();
- ASSERT_EQ(2, times.size());
- ASSERT_EQ(0, times["ScreenOff"]);
- ASSERT_EQ(0, times["90fps"]);
+ EXPECT_EQ(2, times.size());
+ EXPECT_NE(0u, times.count("ScreenOff"));
+ EXPECT_EQ(1u, times.count("90fps"));
+ EXPECT_EQ(0, times["90fps"]);
// Setting up tests on mobile harness can be flaky with time passing, so testing for
// exact time changes can result in flaxy numbers. To avoid that remember old
// numbers to make sure the correct values are increasing in the next test.
@@ -104,31 +106,32 @@
// Screen is off by default.
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
- ASSERT_LT(screenOff, times["ScreenOff"]);
- ASSERT_EQ(0, times["90fps"]);
- screenOff = times["ScreenOff"];
-
- mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL);
- std::this_thread::sleep_for(std::chrono::milliseconds(2));
- times = mRefreshRateStats->getTotalTimes();
- ASSERT_EQ(screenOff, times["ScreenOff"]);
- ASSERT_LT(ninety, times["90fps"]);
- ninety = times["90fps"];
-
- mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE);
- std::this_thread::sleep_for(std::chrono::milliseconds(2));
- times = mRefreshRateStats->getTotalTimes();
- ASSERT_LT(screenOff, times["ScreenOff"]);
- ASSERT_EQ(ninety, times["90fps"]);
- screenOff = times["ScreenOff"];
+ EXPECT_LT(screenOff, times["ScreenOff"]);
+ EXPECT_EQ(0, times["90fps"]);
mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+ mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+ screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
+ times = mRefreshRateStats->getTotalTimes();
+ EXPECT_EQ(screenOff, times["ScreenOff"]);
+ EXPECT_LT(ninety, times["90fps"]);
+
+ mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE);
+ ninety = mRefreshRateStats->getTotalTimes()["90fps"];
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
+ times = mRefreshRateStats->getTotalTimes();
+ EXPECT_LT(screenOff, times["ScreenOff"]);
+ EXPECT_EQ(ninety, times["90fps"]);
+
+ mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+ screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
// Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config
// does not update refresh rates that come from the config.
- ASSERT_LT(screenOff, times["ScreenOff"]);
- ASSERT_EQ(ninety, times["90fps"]);
+ EXPECT_LT(screenOff, times["ScreenOff"]);
+ EXPECT_EQ(ninety, times["90fps"]);
}
TEST_F(RefreshRateStatsTest, twoConfigsTest) {
@@ -145,15 +148,17 @@
init(configs);
- EXPECT_CALL(*mTimeStats, recordRefreshRate(0, _)).Times(6);
- EXPECT_CALL(*mTimeStats, recordRefreshRate(60, _)).Times(4);
- EXPECT_CALL(*mTimeStats, recordRefreshRate(90, _)).Times(4);
+ EXPECT_CALL(*mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1));
+ EXPECT_CALL(*mTimeStats, recordRefreshRate(60, _)).Times(AtLeast(1));
+ EXPECT_CALL(*mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1));
std::unordered_map<std::string, int64_t> times = mRefreshRateStats->getTotalTimes();
- ASSERT_EQ(3, times.size());
- ASSERT_EQ(0, times["ScreenOff"]);
- ASSERT_EQ(0, times["60fps"]);
- ASSERT_EQ(0, times["90fps"]);
+ EXPECT_EQ(3, times.size());
+ EXPECT_NE(0u, times.count("ScreenOff"));
+ EXPECT_EQ(1u, times.count("60fps"));
+ EXPECT_EQ(0, times["60fps"]);
+ EXPECT_EQ(1u, times.count("90fps"));
+ EXPECT_EQ(0, times["90fps"]);
// Setting up tests on mobile harness can be flaky with time passing, so testing for
// exact time changes can result in flaxy numbers. To avoid that remember old
// numbers to make sure the correct values are increasing in the next test.
@@ -164,61 +169,62 @@
// Screen is off by default.
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
- ASSERT_LT(screenOff, times["ScreenOff"]);
- ASSERT_EQ(sixty, times["60fps"]);
- ASSERT_EQ(ninety, times["90fps"]);
- screenOff = times["ScreenOff"];
+ EXPECT_LT(screenOff, times["ScreenOff"]);
+ EXPECT_EQ(sixty, times["60fps"]);
+ EXPECT_EQ(ninety, times["90fps"]);
+ mRefreshRateStats->setConfigMode(CONFIG_ID_90);
mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+ screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
- ASSERT_EQ(screenOff, times["ScreenOff"]);
- ASSERT_EQ(sixty, times["60fps"]);
- ASSERT_LT(ninety, times["90fps"]);
- ninety = times["90fps"];
+ EXPECT_EQ(screenOff, times["ScreenOff"]);
+ EXPECT_EQ(sixty, times["60fps"]);
+ EXPECT_LT(ninety, times["90fps"]);
// When power mode is normal, time for configs updates.
mRefreshRateStats->setConfigMode(CONFIG_ID_60);
+ ninety = mRefreshRateStats->getTotalTimes()["90fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
- ASSERT_EQ(screenOff, times["ScreenOff"]);
- ASSERT_EQ(ninety, times["90fps"]);
- ASSERT_LT(sixty, times["60fps"]);
- sixty = times["60fps"];
+ EXPECT_EQ(screenOff, times["ScreenOff"]);
+ EXPECT_EQ(ninety, times["90fps"]);
+ EXPECT_LT(sixty, times["60fps"]);
mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+ sixty = mRefreshRateStats->getTotalTimes()["60fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
- ASSERT_EQ(screenOff, times["ScreenOff"]);
- ASSERT_LT(ninety, times["90fps"]);
- ASSERT_EQ(sixty, times["60fps"]);
- ninety = times["90fps"];
+ EXPECT_EQ(screenOff, times["ScreenOff"]);
+ EXPECT_LT(ninety, times["90fps"]);
+ EXPECT_EQ(sixty, times["60fps"]);
mRefreshRateStats->setConfigMode(CONFIG_ID_60);
+ ninety = mRefreshRateStats->getTotalTimes()["90fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
- ASSERT_EQ(screenOff, times["ScreenOff"]);
- ASSERT_EQ(ninety, times["90fps"]);
- ASSERT_LT(sixty, times["60fps"]);
- sixty = times["60fps"];
+ EXPECT_EQ(screenOff, times["ScreenOff"]);
+ EXPECT_EQ(ninety, times["90fps"]);
+ EXPECT_LT(sixty, times["60fps"]);
// Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config
// does not update refresh rates that come from the config.
mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE);
mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+ sixty = mRefreshRateStats->getTotalTimes()["60fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
- ASSERT_LT(screenOff, times["ScreenOff"]);
- ASSERT_EQ(ninety, times["90fps"]);
- ASSERT_EQ(sixty, times["60fps"]);
- screenOff = times["ScreenOff"];
+ EXPECT_LT(screenOff, times["ScreenOff"]);
+ EXPECT_EQ(ninety, times["90fps"]);
+ EXPECT_EQ(sixty, times["60fps"]);
mRefreshRateStats->setConfigMode(CONFIG_ID_60);
+ screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
- ASSERT_LT(screenOff, times["ScreenOff"]);
- ASSERT_EQ(ninety, times["90fps"]);
- ASSERT_EQ(sixty, times["60fps"]);
+ EXPECT_LT(screenOff, times["ScreenOff"]);
+ EXPECT_EQ(ninety, times["90fps"]);
+ EXPECT_EQ(sixty, times["60fps"]);
}
} // namespace
} // namespace scheduler