Merge "Revert "Creates an Android.bp with prebuilt_etc for permission XMLs.""
diff --git a/cmds/cmd/Android.bp b/cmds/cmd/Android.bp
index c900a24..c3d2601 100644
--- a/cmds/cmd/Android.bp
+++ b/cmds/cmd/Android.bp
@@ -49,6 +49,7 @@
"liblog",
"libselinux",
"libbinder",
+ "packagemanager_aidl-cpp",
],
cflags: [
diff --git a/cmds/cmd/fuzzer/Android.bp b/cmds/cmd/fuzzer/Android.bp
index 8262bc2..a65f6de 100644
--- a/cmds/cmd/fuzzer/Android.bp
+++ b/cmds/cmd/fuzzer/Android.bp
@@ -30,12 +30,12 @@
],
static_libs: [
"libcmd",
- "libutils",
"liblog",
"libselinux",
],
shared_libs: [
"libbinder",
+ "libutils",
],
fuzz_config: {
cc: [
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index aff32c3..74dbf4b 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -100,6 +100,7 @@
"liblog",
"libutils",
"libbinderdebug",
+ "packagemanager_aidl-cpp",
],
srcs: [
"DumpstateService.cpp",
@@ -173,7 +174,6 @@
test_suites: ["device-tests"],
}
-
// =======================#
// dumpstate_test_fixture #
// =======================#
diff --git a/cmds/dumpsys/Android.bp b/cmds/dumpsys/Android.bp
index 6ab6b7f..ceb16cb 100644
--- a/cmds/dumpsys/Android.bp
+++ b/cmds/dumpsys/Android.bp
@@ -64,6 +64,10 @@
srcs: [
"main.cpp",
],
+
+ shared_libs: [
+ "packagemanager_aidl-cpp",
+ ],
}
cc_binary {
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 74be7ce..5082eb0 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -307,6 +307,8 @@
}
}
+ out << "is_dexopt_blocked:" << android::installd::is_dexopt_blocked() << endl;
+
out << endl;
out.flush();
@@ -2401,7 +2403,8 @@
const std::optional<std::string>& seInfo, bool downgrade, int32_t targetSdkVersion,
const std::optional<std::string>& profileName,
const std::optional<std::string>& dexMetadataPath,
- const std::optional<std::string>& compilationReason) {
+ const std::optional<std::string>& compilationReason,
+ bool* aidl_return) {
ENFORCE_UID(AID_SYSTEM);
CHECK_ARGUMENT_UUID(uuid);
CHECK_ARGUMENT_PATH(apkPath);
@@ -2429,12 +2432,20 @@
const char* dm_path = getCStr(dexMetadataPath);
const char* compilation_reason = getCStr(compilationReason);
std::string error_msg;
+ bool completed = false; // not necessary but for compiler
int res = android::installd::dexopt(apk_path, uid, pkgname, instruction_set, dexoptNeeded,
oat_dir, dexFlags, compiler_filter, volume_uuid, class_loader_context, se_info,
- downgrade, targetSdkVersion, profile_name, dm_path, compilation_reason, &error_msg);
+ downgrade, targetSdkVersion, profile_name, dm_path, compilation_reason, &error_msg,
+ &completed);
+ *aidl_return = completed;
return res ? error(res, error_msg) : ok();
}
+binder::Status InstalldNativeService::controlDexOptBlocking(bool block) {
+ android::installd::control_dexopt_blocking(block);
+ return ok();
+}
+
binder::Status InstalldNativeService::compileLayouts(const std::string& apkPath,
const std::string& packageName,
const std ::string& outDexFile, int uid,
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index ea0c945..ae257df 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -117,7 +117,10 @@
const std::optional<std::string>& seInfo, bool downgrade,
int32_t targetSdkVersion, const std::optional<std::string>& profileName,
const std::optional<std::string>& dexMetadataPath,
- const std::optional<std::string>& compilationReason);
+ const std::optional<std::string>& compilationReason,
+ bool* aidl_return);
+
+ binder::Status controlDexOptBlocking(bool block);
binder::Status compileLayouts(const std::string& apkPath, const std::string& packageName,
const std::string& outDexFile, int uid, bool* _aidl_return);
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 3d32f61..637a9f2 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -55,7 +55,8 @@
@utf8InCpp String packageName, int appId,
@utf8InCpp String seInfo, int targetSdkVersion, @utf8InCpp String fromCodePath);
- void dexopt(@utf8InCpp String apkPath, int uid, @nullable @utf8InCpp String packageName,
+ // Returns false if it is cancelled. Returns true if it is completed or have other errors.
+ boolean dexopt(@utf8InCpp String apkPath, int uid, @nullable @utf8InCpp String packageName,
@utf8InCpp String instructionSet, int dexoptNeeded,
@nullable @utf8InCpp String outputPath, int dexFlags,
@utf8InCpp String compilerFilter, @nullable @utf8InCpp String uuid,
@@ -64,6 +65,9 @@
@nullable @utf8InCpp String profileName,
@nullable @utf8InCpp String dexMetadataPath,
@nullable @utf8InCpp String compilationReason);
+ // Blocks (when block is true) or unblock (when block is false) dexopt.
+ // Blocking also invloves cancelling the currently running dexopt.
+ void controlDexOptBlocking(boolean block);
boolean compileLayouts(@utf8InCpp String apkPath, @utf8InCpp String packageName,
@utf8InCpp String outDexFile, int uid);
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index d678281..f3ec63f 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -15,8 +15,8 @@
*/
#define LOG_TAG "installd"
-#include <array>
#include <fcntl.h>
+#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/capability.h>
@@ -28,10 +28,14 @@
#include <sys/wait.h>
#include <unistd.h>
+#include <array>
#include <iomanip>
+#include <mutex>
+#include <unordered_set>
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/no_destructor.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
@@ -47,6 +51,7 @@
#include <selinux/android.h>
#include <server_configurable_flags/get_flags.h>
#include <system/thread_defs.h>
+#include <utils/Mutex.h>
#include "dexopt.h"
#include "dexopt_return_codes.h"
@@ -69,6 +74,76 @@
using android::base::WriteFully;
using android::base::unique_fd;
+namespace {
+
+class DexOptStatus {
+ public:
+ // Check if dexopt is cancelled and fork if it is not cancelled.
+ // cancelled is set to true if cancelled. Otherwise it will be set to false.
+ // If it is not cancelled, it will return the return value of fork() call.
+ // If cancelled, fork will not happen and it will return -1.
+ pid_t check_cancellation_and_fork(/* out */ bool *cancelled) {
+ std::lock_guard<std::mutex> lock(dexopt_lock_);
+ if (dexopt_blocked_) {
+ *cancelled = true;
+ return -1;
+ }
+ pid_t pid = fork();
+ *cancelled = false;
+ if (pid > 0) { // parent
+ dexopt_pids_.insert(pid);
+ }
+ return pid;
+ }
+
+ // Returns true if pid was killed (is in killed list). It could have finished if killing
+ // happened after the process is finished.
+ bool check_if_killed_and_remove_dexopt_pid(pid_t pid) {
+ std::lock_guard<std::mutex> lock(dexopt_lock_);
+ dexopt_pids_.erase(pid);
+ if (dexopt_killed_pids_.erase(pid) == 1) {
+ return true;
+ }
+ return false;
+ }
+
+ // Tells whether dexopt is blocked or not.
+ bool is_dexopt_blocked() {
+ std::lock_guard<std::mutex> lock(dexopt_lock_);
+ return dexopt_blocked_;
+ }
+
+ // Enable or disable dexopt blocking.
+ void control_dexopt_blocking(bool block) {
+ std::lock_guard<std::mutex> lock(dexopt_lock_);
+ dexopt_blocked_ = block;
+ if (!block) {
+ return;
+ }
+ // Blocked, also kill currently running tasks
+ for (auto pid : dexopt_pids_) {
+ LOG(INFO) << "control_dexopt_blocking kill pid:" << pid;
+ kill(pid, SIGKILL);
+ dexopt_killed_pids_.insert(pid);
+ }
+ dexopt_pids_.clear();
+ }
+
+ private:
+ std::mutex dexopt_lock_;
+ // when true, dexopt is blocked and will not run.
+ bool dexopt_blocked_ GUARDED_BY(dexopt_lock_) = false;
+ // PIDs of child process while runinng dexopt.
+ // If the child process is finished, it should be removed.
+ std::unordered_set<pid_t> dexopt_pids_ GUARDED_BY(dexopt_lock_);
+ // PIDs of child processes killed by cancellation.
+ std::unordered_set<pid_t> dexopt_killed_pids_ GUARDED_BY(dexopt_lock_);
+};
+
+android::base::NoDestructor<DexOptStatus> dexopt_status_;
+
+} // namespace
+
namespace android {
namespace installd {
@@ -1525,23 +1600,46 @@
return ss.str();
}
+void control_dexopt_blocking(bool block) {
+ dexopt_status_->control_dexopt_blocking(block);
+}
+
+bool is_dexopt_blocked() {
+ return dexopt_status_->is_dexopt_blocked();
+}
+
+enum SecondaryDexOptProcessResult {
+ kSecondaryDexOptProcessOk = 0,
+ kSecondaryDexOptProcessCancelled = 1,
+ kSecondaryDexOptProcessError = 2
+};
+
// 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.
-// When returning true, the output parameters will be:
+// be compiled.
+// Returns: kSecondaryDexOptProcessError for errors (logged).
+// kSecondaryDexOptProcessOk if the secondary dex path was process successfully.
+// kSecondaryDexOptProcessCancelled if the processing was cancelled.
+//
+// When returning kSecondaryDexOptProcessOk, the output parameters will be:
// - is_public_out: whether or not the oat file should not be made public
// - dexopt_needed_out: valid OatFileAsssitant::DexOptNeeded
// - oat_dir_out: the oat dir path where the oat file should be stored
-static bool process_secondary_dex_dexopt(const std::string& dex_path, const char* pkgname,
- 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,
- const std::vector<std::string>& context_dex_paths, /* out */ std::string* error_msg) {
+static SecondaryDexOptProcessResult process_secondary_dex_dexopt(const std::string& dex_path,
+ const char* pkgname, 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, const std::vector<std::string>& context_dex_paths,
+ /* out */ std::string* error_msg) {
LOG(DEBUG) << "Processing secondary dex path " << dex_path;
+
+ if (dexopt_status_->is_dexopt_blocked()) {
+ return kSecondaryDexOptProcessCancelled;
+ }
+
int storage_flag;
if (!validate_dexopt_storage_flags(dexopt_flags, &storage_flag, error_msg)) {
LOG(ERROR) << *error_msg;
- return false;
+ return kSecondaryDexOptProcessError;
}
// Compute the oat dir as it's not easy to extract it from the child computation.
char oat_path[PKG_PATH_MAX];
@@ -1550,11 +1648,15 @@
if (!create_secondary_dex_oat_layout(
dex_path, instruction_set, oat_dir, oat_isa_dir, oat_path, error_msg)) {
LOG(ERROR) << "Could not create secondary odex layout: " << *error_msg;
- return false;
+ return kSecondaryDexOptProcessError;
}
oat_dir_out->assign(oat_dir);
- pid_t pid = fork();
+ bool cancelled = false;
+ pid_t pid = dexopt_status_->check_cancellation_and_fork(&cancelled);
+ if (cancelled) {
+ return kSecondaryDexOptProcessCancelled;
+ }
if (pid == 0) {
// child -- drop privileges before continuing.
drop_capabilities(uid);
@@ -1623,12 +1725,17 @@
/* parent */
int result = wait_child(pid);
+ cancelled = dexopt_status_->check_if_killed_and_remove_dexopt_pid(pid);
if (!WIFEXITED(result)) {
+ if ((WTERMSIG(result) == SIGKILL) && cancelled) {
+ LOG(INFO) << "dexoptanalyzer cancelled for path:" << dex_path;
+ return kSecondaryDexOptProcessCancelled;
+ }
*error_msg = StringPrintf("dexoptanalyzer failed for path %s: 0x%04x",
dex_path.c_str(),
result);
LOG(ERROR) << *error_msg;
- return false;
+ return kSecondaryDexOptProcessError;
}
result = WEXITSTATUS(result);
// Check that we successfully executed dexoptanalyzer.
@@ -1656,7 +1763,7 @@
// It is ok to check this flag outside in the parent process.
*is_public_out = ((dexopt_flags & DEXOPT_PUBLIC) != 0) && is_file_public(dex_path);
- return success;
+ return success ? kSecondaryDexOptProcessOk : kSecondaryDexOptProcessError;
}
static std::string format_dexopt_error(int status, const char* dex_path) {
@@ -1670,17 +1777,29 @@
return StringPrintf("Dex2oat invocation for %s failed with 0x%04x", dex_path, status);
}
+
int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* instruction_set,
int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
const char* volume_uuid, const char* class_loader_context, const char* se_info,
bool downgrade, int target_sdk_version, const char* profile_name,
- const char* dex_metadata_path, const char* compilation_reason, std::string* error_msg) {
+ const char* dex_metadata_path, const char* compilation_reason, std::string* error_msg,
+ /* out */ bool* completed) {
CHECK(pkgname != nullptr);
CHECK(pkgname[0] != 0);
CHECK(error_msg != nullptr);
CHECK_EQ(dexopt_flags & ~DEXOPT_MASK, 0)
<< "dexopt flags contains unknown fields: " << dexopt_flags;
+ bool local_completed; // local placeholder for nullptr case
+ if (completed == nullptr) {
+ completed = &local_completed;
+ }
+ *completed = true;
+ if (dexopt_status_->is_dexopt_blocked()) {
+ *completed = false;
+ return 0;
+ }
+
if (!validate_dex_path_size(dex_path)) {
*error_msg = StringPrintf("Failed to validate %s", dex_path);
return -1;
@@ -1712,14 +1831,19 @@
*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, context_dex_paths, error_msg)) {
+ SecondaryDexOptProcessResult sec_dex_result = 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,
+ context_dex_paths, error_msg);
+ if (sec_dex_result == kSecondaryDexOptProcessOk) {
oat_dir = oat_dir_str.c_str();
if (dexopt_needed == NO_DEXOPT_NEEDED) {
return 0; // Nothing to do, report success.
}
+ } else if (sec_dex_result == kSecondaryDexOptProcessCancelled) {
+ // cancelled, not an error.
+ *completed = false;
+ return 0;
} else {
if (error_msg->empty()) { // TODO: Make this a CHECK.
*error_msg = "Failed processing secondary.";
@@ -1849,7 +1973,11 @@
use_jitzygote_image,
compilation_reason);
- pid_t pid = fork();
+ bool cancelled = false;
+ pid_t pid = dexopt_status_->check_cancellation_and_fork(&cancelled);
+ if (cancelled) {
+ return 0;
+ }
if (pid == 0) {
// Need to set schedpolicy before dropping privileges
// for cgroup migration. See details at b/175178520.
@@ -1867,9 +1995,16 @@
runner.Exec(DexoptReturnCodes::kDex2oatExec);
} else {
int res = wait_child(pid);
+ bool cancelled = dexopt_status_->check_if_killed_and_remove_dexopt_pid(pid);
if (res == 0) {
LOG(VERBOSE) << "DexInv: --- END '" << dex_path << "' (success) ---";
} else {
+ if ((WTERMSIG(res) == SIGKILL) && cancelled) {
+ LOG(VERBOSE) << "DexInv: --- END '" << dex_path << "' --- cancelled";
+ // cancelled, not an error
+ *completed = false;
+ return 0;
+ }
LOG(VERBOSE) << "DexInv: --- END '" << dex_path << "' --- status=0x"
<< std::hex << std::setw(4) << res << ", process failed";
*error_msg = format_dexopt_error(res, dex_path);
@@ -1877,12 +2012,14 @@
}
}
+ // TODO(b/156537504) Implement SWAP of completed files
// We've been successful, don't delete output.
out_oat.DisableCleanup();
out_vdex.DisableCleanup();
out_image.DisableCleanup();
reference_profile.DisableCleanup();
+ *completed = true;
return 0;
}
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 5a637b1..12579b0 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -121,11 +121,18 @@
const std::string& pkgname, int uid, const std::optional<std::string>& volume_uuid,
int storage_flag, std::vector<uint8_t>* out_secondary_dex_hash);
+// completed pass false if it is canceled. Otherwise it will be true even if there is other
+// error.
int dexopt(const char *apk_path, uid_t uid, const char *pkgName, const char *instruction_set,
int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
const char* volume_uuid, const char* class_loader_context, const char* se_info,
bool downgrade, int target_sdk_version, const char* profile_name,
- const char* dexMetadataPath, const char* compilation_reason, std::string* error_msg);
+ const char* dexMetadataPath, const char* compilation_reason, std::string* error_msg,
+ /* out */ bool* completed = nullptr);
+
+bool is_dexopt_blocked();
+
+void control_dexopt_blocking(bool block);
bool calculate_oat_file_path_default(char path[PKG_PATH_MAX], const char *oat_dir,
const char *apk_path, const char *instruction_set);
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 7e7e513..ea26955 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -232,6 +232,7 @@
virtual void TearDown() {
if (!kDebug) {
+ service_->controlDexOptBlocking(false);
service_->destroyAppData(
volume_uuid_, package_name_, kTestUserId, kAppDataFlags, ce_data_inode_);
run_cmd("rm -rf " + app_apk_dir_);
@@ -347,7 +348,7 @@
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,
- const char* class_loader_context = nullptr) {
+ const char* class_loader_context = nullptr, bool expect_completed = true) {
if (uid == -1) {
uid = kTestAppUid;
}
@@ -364,6 +365,7 @@
std::optional<std::string> dm_path;
std::optional<std::string> compilation_reason;
+ bool completed = false;
binder::Status result = service_->dexopt(path,
uid,
package_name_,
@@ -379,8 +381,10 @@
target_sdk_version,
profile_name,
dm_path,
- compilation_reason);
+ compilation_reason,
+ &completed);
ASSERT_EQ(should_binder_call_succeed, result.isOk()) << result.toString8().c_str();
+ ASSERT_EQ(expect_completed, completed);
int expected_access = should_dex_be_compiled ? 0 : -1;
std::string odex = GetSecondaryDexArtifact(path, "odex");
std::string vdex = GetSecondaryDexArtifact(path, "vdex");
@@ -431,6 +435,11 @@
ASSERT_EQ(mode, st.st_mode);
}
+ void AssertNoFile(const std::string& file) {
+ struct stat st;
+ ASSERT_EQ(-1, stat(file.c_str(), &st));
+ }
+
void CompilePrimaryDexOk(std::string compiler_filter,
int32_t dex_flags,
const char* oat_dir,
@@ -447,6 +456,7 @@
dm_path,
downgrade,
true,
+ true,
binder_result);
}
@@ -466,6 +476,27 @@
dm_path,
downgrade,
false,
+ true,
+ binder_result);
+ }
+
+ void CompilePrimaryDexCancelled(std::string compiler_filter,
+ int32_t dex_flags,
+ const char* oat_dir,
+ int32_t uid,
+ int32_t dexopt_needed,
+ binder::Status* binder_result = nullptr,
+ const char* dm_path = nullptr,
+ bool downgrade = false) {
+ CompilePrimaryDex(compiler_filter,
+ dex_flags,
+ oat_dir,
+ uid,
+ dexopt_needed,
+ dm_path,
+ downgrade,
+ true, // should_binder_call_succeed
+ false, // expect_completed
binder_result);
}
@@ -477,6 +508,7 @@
const char* dm_path,
bool downgrade,
bool should_binder_call_succeed,
+ bool expect_completed,
/*out */ binder::Status* binder_result) {
std::optional<std::string> out_path = oat_dir ? std::make_optional<std::string>(oat_dir) : std::nullopt;
std::string class_loader_context = "PCL[]";
@@ -491,6 +523,7 @@
dm_path_opt, &prof_result));
ASSERT_TRUE(prof_result);
+ bool completed = false;
binder::Status result = service_->dexopt(apk_path_,
uid,
package_name_,
@@ -506,8 +539,10 @@
target_sdk_version,
profile_name,
dm_path_opt,
- compilation_reason);
+ compilation_reason,
+ &completed);
ASSERT_EQ(should_binder_call_succeed, result.isOk()) << result.toString8().c_str();
+ ASSERT_EQ(expect_completed, completed);
if (!should_binder_call_succeed) {
if (binder_result != nullptr) {
@@ -525,11 +560,20 @@
bool is_public = (dex_flags & DEXOPT_PUBLIC) != 0;
mode_t mode = S_IFREG | (is_public ? 0644 : 0640);
- CheckFileAccess(odex, kSystemUid, uid, mode);
- CheckFileAccess(vdex, kSystemUid, uid, mode);
+ if (expect_completed) {
+ CheckFileAccess(odex, kSystemUid, uid, mode);
+ CheckFileAccess(vdex, kSystemUid, uid, mode);
+ } else {
+ AssertNoFile(odex);
+ AssertNoFile(vdex);
+ }
if (compiler_filter == "speed-profile") {
- CheckFileAccess(art, kSystemUid, uid, mode);
+ if (expect_completed) {
+ CheckFileAccess(art, kSystemUid, uid, mode);
+ } else {
+ AssertNoFile(art);
+ }
}
if (binder_result != nullptr) {
*binder_result = result;
@@ -750,6 +794,28 @@
empty_dm_file_.c_str());
}
+TEST_F(DexoptTest, DexoptBlockPrimary) {
+ LOG(INFO) << "DexoptPrimaryPublic";
+ service_->controlDexOptBlocking(true);
+ CompilePrimaryDexCancelled("verify",
+ DEXOPT_BOOTCOMPLETE | DEXOPT_PUBLIC,
+ app_oat_dir_.c_str(),
+ kTestAppGid,
+ DEX2OAT_FROM_SCRATCH, nullptr, nullptr);
+ service_->controlDexOptBlocking(false);
+}
+
+TEST_F(DexoptTest, DexoptUnblockPrimary) {
+ LOG(INFO) << "DexoptPrimaryPublic";
+ service_->controlDexOptBlocking(true);
+ service_->controlDexOptBlocking(false);
+ CompilePrimaryDexOk("verify",
+ DEXOPT_BOOTCOMPLETE | DEXOPT_PUBLIC,
+ app_oat_dir_.c_str(),
+ kTestAppGid,
+ DEX2OAT_FROM_SCRATCH, nullptr, nullptr);
+}
+
TEST_F(DexoptTest, DeleteDexoptArtifactsData) {
LOG(INFO) << "DeleteDexoptArtifactsData";
TestDeleteOdex(/*in_dalvik_cache=*/ false);
diff --git a/include/input/Input.h b/include/input/Input.h
index 2e42409..d2d9fd4 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -1025,6 +1025,25 @@
std::queue<std::unique_ptr<TouchModeEvent>> mTouchModeEventPool;
};
+/*
+ * Describes a unique request to enable or disable Pointer Capture.
+ */
+struct PointerCaptureRequest {
+public:
+ inline PointerCaptureRequest() : enable(false), seq(0) {}
+ inline PointerCaptureRequest(bool enable, uint32_t seq) : enable(enable), seq(seq) {}
+ inline bool operator==(const PointerCaptureRequest& other) const {
+ return enable == other.enable && seq == other.seq;
+ }
+ explicit inline operator bool() const { return enable; }
+
+ // True iff this is a request to enable Pointer Capture.
+ bool enable;
+
+ // The sequence number for the request.
+ uint32_t seq;
+};
+
} // namespace android
#endif // _LIBINPUT_INPUT_H
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 2f42da5..9592562 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -64,9 +64,6 @@
"PermissionCache.cpp",
"PermissionController.cpp",
]
-libbinder_no_vendor_interface_sources = [
- ":packagemanager_aidl",
-]
cc_library {
name: "libbinder",
@@ -128,7 +125,7 @@
"TextOutput.cpp",
"Utils.cpp",
":libbinder_aidl",
- ] + libbinder_no_vendor_interface_sources,
+ ],
target: {
android: {
@@ -140,7 +137,7 @@
},
},
vendor: {
- exclude_srcs: libbinder_device_interface_sources + libbinder_no_vendor_interface_sources,
+ exclude_srcs: libbinder_device_interface_sources,
},
darwin: {
enabled: false,
@@ -289,8 +286,11 @@
path: "aidl",
}
-filegroup {
+aidl_interface {
name: "packagemanager_aidl",
+ unstable: true,
+ local_include_dir: "aidl",
+ host_supported: true,
srcs: [
"aidl/android/content/pm/IPackageChangeObserver.aidl",
"aidl/android/content/pm/IPackageManagerNative.aidl",
@@ -299,7 +299,6 @@
"aidl/android/content/pm/ApexStagedEvent.aidl",
"aidl/android/content/pm/StagedApexInfo.aidl",
],
- path: "aidl",
}
aidl_interface {
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 52a6cf1..8ab0e88 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -18,6 +18,7 @@
#include <binder/ProcessState.h>
+#include <android-base/result.h>
#include <binder/BpBinder.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
@@ -384,68 +385,73 @@
return mDriverName;
}
-static int open_driver(const char *driver)
-{
+static base::Result<int> open_driver(const char* driver) {
int fd = open(driver, O_RDWR | O_CLOEXEC);
- if (fd >= 0) {
- int vers = 0;
- status_t result = ioctl(fd, BINDER_VERSION, &vers);
- if (result == -1) {
- ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
- close(fd);
- fd = -1;
- }
- if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
- ALOGE("Binder driver protocol(%d) does not match user space protocol(%d)! ioctl() return value: %d",
- vers, BINDER_CURRENT_PROTOCOL_VERSION, result);
- close(fd);
- fd = -1;
- }
- size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
- result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
- if (result == -1) {
- ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
- }
- uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION;
- result = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable);
- if (result == -1) {
- ALOGV("Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
- }
- } else {
- ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));
+ if (fd < 0) {
+ return base::ErrnoError() << "Opening '" << driver << "' failed";
+ }
+ int vers = 0;
+ status_t result = ioctl(fd, BINDER_VERSION, &vers);
+ if (result == -1) {
+ close(fd);
+ return base::ErrnoError() << "Binder ioctl to obtain version failed";
+ }
+ if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
+ close(fd);
+ return base::Error() << "Binder driver protocol(" << vers
+ << ") does not match user space protocol("
+ << BINDER_CURRENT_PROTOCOL_VERSION
+ << ")! ioctl() return value: " << result;
+ }
+ size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
+ result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
+ if (result == -1) {
+ ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
+ }
+ uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION;
+ result = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable);
+ if (result == -1) {
+ ALOGV("Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
}
return fd;
}
-ProcessState::ProcessState(const char *driver)
- : mDriverName(String8(driver))
- , mDriverFD(open_driver(driver))
- , mVMStart(MAP_FAILED)
- , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
- , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
- , mExecutingThreadsCount(0)
- , mWaitingForThreads(0)
- , mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
- , mStarvationStartTimeMs(0)
- , mThreadPoolStarted(false)
- , mThreadPoolSeq(1)
- , mCallRestriction(CallRestriction::NONE)
-{
- if (mDriverFD >= 0) {
+ProcessState::ProcessState(const char* driver)
+ : mDriverName(String8(driver)),
+ mDriverFD(-1),
+ mVMStart(MAP_FAILED),
+ mThreadCountLock(PTHREAD_MUTEX_INITIALIZER),
+ mThreadCountDecrement(PTHREAD_COND_INITIALIZER),
+ mExecutingThreadsCount(0),
+ mWaitingForThreads(0),
+ mMaxThreads(DEFAULT_MAX_BINDER_THREADS),
+ mStarvationStartTimeMs(0),
+ mThreadPoolStarted(false),
+ mThreadPoolSeq(1),
+ mCallRestriction(CallRestriction::NONE) {
+ base::Result<int> opened = open_driver(driver);
+
+ if (opened.ok()) {
// mmap the binder, providing a chunk of virtual address space to receive transactions.
- mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
+ mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE,
+ opened.value(), 0);
if (mVMStart == MAP_FAILED) {
+ close(opened.value());
// *sigh*
- ALOGE("Using %s failed: unable to mmap transaction memory.\n", mDriverName.c_str());
- close(mDriverFD);
- mDriverFD = -1;
+ opened = base::Error()
+ << "Using " << driver << " failed: unable to mmap transaction memory.";
mDriverName.clear();
}
}
#ifdef __ANDROID__
- LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver '%s' could not be opened. Terminating.", driver);
+ LOG_ALWAYS_FATAL_IF(!opened.ok(), "Binder driver '%s' could not be opened. Terminating: %s",
+ driver, opened.error().message().c_str());
#endif
+
+ if (opened.ok()) {
+ mDriverFD = opened.value();
+ }
}
ProcessState::~ProcessState()
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index a20445b..ad9ba96 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -39,8 +39,7 @@
using base::ScopeGuard;
using base::unique_fd;
-RpcServer::RpcServer(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory)
- : mRpcTransportCtxFactory(std::move(rpcTransportCtxFactory)) {}
+RpcServer::RpcServer(std::unique_ptr<RpcTransportCtx> ctx) : mCtx(std::move(ctx)) {}
RpcServer::~RpcServer() {
(void)shutdown();
}
@@ -49,7 +48,9 @@
// Default is without TLS.
if (rpcTransportCtxFactory == nullptr)
rpcTransportCtxFactory = RpcTransportCtxFactoryRaw::make();
- return sp<RpcServer>::make(std::move(rpcTransportCtxFactory));
+ auto ctx = rpcTransportCtxFactory->newServerCtx();
+ if (ctx == nullptr) return nullptr;
+ return sp<RpcServer>::make(std::move(ctx));
}
void RpcServer::iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction() {
@@ -138,6 +139,20 @@
return ret;
}
+std::string RpcServer::getCertificate(CertificateFormat format) {
+ std::lock_guard<std::mutex> _l(mLock);
+ return mCtx->getCertificate(format);
+}
+
+status_t RpcServer::addTrustedPeerCertificate(CertificateFormat format, std::string_view cert) {
+ std::lock_guard<std::mutex> _l(mLock);
+ // Ensure that join thread is not running or shutdown trigger is not set up. In either case,
+ // it means there are child threads running. It is invalid to add trusted peer certificates
+ // after join thread and/or child threads are running to avoid race condition.
+ if (mJoinThreadRunning || mShutdownTrigger != nullptr) return INVALID_OPERATION;
+ return mCtx->addTrustedPeerCertificate(format, cert);
+}
+
static void joinRpcServer(sp<RpcServer>&& thiz) {
thiz->join();
}
@@ -159,10 +174,6 @@
mJoinThreadRunning = true;
mShutdownTrigger = FdTrigger::make();
LOG_ALWAYS_FATAL_IF(mShutdownTrigger == nullptr, "Cannot create join signaler");
-
- mCtx = mRpcTransportCtxFactory->newServerCtx();
- LOG_ALWAYS_FATAL_IF(mCtx == nullptr, "Unable to create RpcTransportCtx with %s sockets",
- mRpcTransportCtxFactory->toCString());
}
status_t status;
@@ -229,7 +240,6 @@
LOG_RPC_DETAIL("Finished waiting on shutdown.");
mShutdownTrigger = nullptr;
- mCtx = nullptr;
return true;
}
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 3e9e5a8..c57b749 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -49,8 +49,7 @@
using base::unique_fd;
-RpcSession::RpcSession(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory)
- : mRpcTransportCtxFactory(std::move(rpcTransportCtxFactory)) {
+RpcSession::RpcSession(std::unique_ptr<RpcTransportCtx> ctx) : mCtx(std::move(ctx)) {
LOG_RPC_DETAIL("RpcSession created %p", this);
mState = std::make_unique<RpcState>();
@@ -63,11 +62,26 @@
"Should not be able to destroy a session with servers in use.");
}
-sp<RpcSession> RpcSession::make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory) {
+sp<RpcSession> RpcSession::make() {
// Default is without TLS.
- if (rpcTransportCtxFactory == nullptr)
- rpcTransportCtxFactory = RpcTransportCtxFactoryRaw::make();
- return sp<RpcSession>::make(std::move(rpcTransportCtxFactory));
+ return make(RpcTransportCtxFactoryRaw::make(), std::nullopt, std::nullopt);
+}
+
+sp<RpcSession> RpcSession::make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory,
+ std::optional<CertificateFormat> serverCertificateFormat,
+ std::optional<std::string> serverCertificate) {
+ auto ctx = rpcTransportCtxFactory->newClientCtx();
+ if (ctx == nullptr) return nullptr;
+ LOG_ALWAYS_FATAL_IF(serverCertificateFormat.has_value() != serverCertificate.has_value());
+ if (serverCertificateFormat.has_value() && serverCertificate.has_value()) {
+ status_t status =
+ ctx->addTrustedPeerCertificate(*serverCertificateFormat, *serverCertificate);
+ if (status != OK) {
+ ALOGE("Cannot add trusted server certificate: %s", statusToString(status).c_str());
+ return nullptr;
+ }
+ }
+ return sp<RpcSession>::make(std::move(ctx));
}
void RpcSession::setMaxThreads(size_t threads) {
@@ -155,12 +169,7 @@
return -savedErrno;
}
- auto ctx = mRpcTransportCtxFactory->newClientCtx();
- if (ctx == nullptr) {
- ALOGE("Unable to create RpcTransportCtx for null debugging client");
- return NO_MEMORY;
- }
- auto server = ctx->newTransport(std::move(serverFd), mShutdownTrigger.get());
+ auto server = mCtx->newTransport(std::move(serverFd), mShutdownTrigger.get());
if (server == nullptr) {
ALOGE("Unable to set up RpcTransport");
return UNKNOWN_ERROR;
@@ -531,15 +540,9 @@
status_t RpcSession::initAndAddConnection(unique_fd fd, const RpcAddress& sessionId,
bool incoming) {
LOG_ALWAYS_FATAL_IF(mShutdownTrigger == nullptr);
- auto ctx = mRpcTransportCtxFactory->newClientCtx();
- if (ctx == nullptr) {
- ALOGE("Unable to create client RpcTransportCtx with %s sockets",
- mRpcTransportCtxFactory->toCString());
- return NO_MEMORY;
- }
- auto server = ctx->newTransport(std::move(fd), mShutdownTrigger.get());
+ auto server = mCtx->newTransport(std::move(fd), mShutdownTrigger.get());
if (server == nullptr) {
- ALOGE("Unable to set up RpcTransport in %s context", mRpcTransportCtxFactory->toCString());
+ ALOGE("%s: Unable to set up RpcTransport", __PRETTY_FUNCTION__);
return UNKNOWN_ERROR;
}
@@ -694,6 +697,10 @@
return false;
}
+std::string RpcSession::getCertificate(CertificateFormat format) {
+ return mCtx->getCertificate(format);
+}
+
status_t RpcSession::ExclusiveConnection::find(const sp<RpcSession>& session, ConnectionUse use,
ExclusiveConnection* connection) {
connection->mSession = session;
diff --git a/libs/binder/RpcWireFormat.h b/libs/binder/RpcWireFormat.h
index 0f8efd2..067c4ad 100644
--- a/libs/binder/RpcWireFormat.h
+++ b/libs/binder/RpcWireFormat.h
@@ -31,6 +31,7 @@
uint64_t options;
uint8_t address[32];
};
+static_assert(sizeof(RpcWireAddress) == 40);
/**
* This is sent to an RpcServer in order to request a new connection is created,
@@ -43,6 +44,7 @@
uint8_t options;
uint8_t reserved1[7];
};
+static_assert(sizeof(RpcConnectionHeader) == 56);
/**
* In response to an RpcConnectionHeader which corresponds to a new session,
@@ -52,6 +54,7 @@
uint32_t version; // maximum supported by callee <= maximum supported by caller
uint8_t reserved[4];
};
+static_assert(sizeof(RpcNewSessionResponse) == 8);
#define RPC_CONNECTION_INIT_OKAY "cci"
@@ -64,6 +67,7 @@
char msg[4];
uint8_t reserved[4];
};
+static_assert(sizeof(RpcOutgoingConnectionInit) == 8);
enum : uint32_t {
/**
@@ -105,6 +109,7 @@
uint32_t reserved[2];
};
+static_assert(sizeof(RpcWireHeader) == 16);
struct RpcWireTransaction {
RpcWireAddress address;
@@ -115,13 +120,15 @@
uint32_t reserved[4];
- uint8_t data[0];
+ uint8_t data[];
};
+static_assert(sizeof(RpcWireTransaction) == 72);
struct RpcWireReply {
int32_t status; // transact return
- uint8_t data[0];
+ uint8_t data[];
};
+static_assert(sizeof(RpcWireReply) == 4);
#pragma clang diagnostic pop
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index bf3e7e0..d0e4e27 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -134,6 +134,17 @@
sp<IBinder> getRootObject();
/**
+ * See RpcTransportCtx::getCertificate
+ */
+ std::string getCertificate(CertificateFormat);
+
+ /**
+ * See RpcTransportCtx::addTrustedPeerCertificate.
+ * Thread-safe. This is only possible before the server is join()-ing.
+ */
+ status_t addTrustedPeerCertificate(CertificateFormat, std::string_view cert);
+
+ /**
* Runs join() in a background thread. Immediately returns.
*/
void start();
@@ -170,7 +181,7 @@
private:
friend sp<RpcServer>;
- explicit RpcServer(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory);
+ explicit RpcServer(std::unique_ptr<RpcTransportCtx> ctx);
void onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) override;
void onSessionIncomingThreadEnded() override;
@@ -178,7 +189,7 @@
static void establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd);
status_t setupSocketServer(const RpcSocketAddress& address);
- const std::unique_ptr<RpcTransportCtxFactory> mRpcTransportCtxFactory;
+ const std::unique_ptr<RpcTransportCtx> mCtx;
bool mAgreedExperimental = false;
size_t mMaxThreads = 1;
std::optional<uint32_t> mProtocolVersion;
@@ -193,7 +204,6 @@
std::map<RpcAddress, sp<RpcSession>> mSessions;
std::unique_ptr<FdTrigger> mShutdownTrigger;
std::condition_variable mShutdownCv;
- std::unique_ptr<RpcTransportCtx> mCtx;
};
} // namespace android
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index 6e6eb74..d92af0a 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -51,8 +51,15 @@
*/
class RpcSession final : public virtual RefBase {
public:
- static sp<RpcSession> make(
- std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory = nullptr);
+ // Create an RpcSession with default configuration (raw sockets).
+ static sp<RpcSession> make();
+
+ // Create an RpcSession with the given configuration. |serverCertificateFormat| and
+ // |serverCertificate| must have values or be nullopt simultaneously. If they have values, set
+ // server certificate.
+ static sp<RpcSession> make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory,
+ std::optional<CertificateFormat> serverCertificateFormat,
+ std::optional<std::string> serverCertificate);
/**
* Set the maximum number of threads allowed to be made (for things like callbacks).
@@ -125,6 +132,11 @@
status_t getRemoteMaxThreads(size_t* maxThreads);
/**
+ * See RpcTransportCtx::getCertificate
+ */
+ std::string getCertificate(CertificateFormat);
+
+ /**
* Shuts down the service.
*
* For client sessions, wait can be true or false. For server sessions,
@@ -159,7 +171,7 @@
friend sp<RpcSession>;
friend RpcServer;
friend RpcState;
- explicit RpcSession(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory);
+ explicit RpcSession(std::unique_ptr<RpcTransportCtx> ctx);
class EventListener : public virtual RefBase {
public:
@@ -259,7 +271,7 @@
bool mReentrant = false;
};
- const std::unique_ptr<RpcTransportCtxFactory> mRpcTransportCtxFactory;
+ const std::unique_ptr<RpcTransportCtx> mCtx;
// On the other side of a session, for each of mOutgoingConnections here, there should
// be one of mIncomingConnections on the other side (and vice versa).
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 717beec..f88896f 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -172,7 +172,7 @@
status_t ABBinder::onTransact(transaction_code_t code, const Parcel& data, Parcel* reply,
binder_flags_t flags) {
if (isUserCommand(code)) {
- if (!data.checkInterface(this)) {
+ if (getClass()->writeHeader && !data.checkInterface(this)) {
return STATUS_BAD_TYPE;
}
@@ -354,6 +354,12 @@
clazz->onDump = onDump;
}
+void AIBinder_Class_disableInterfaceTokenHeader(AIBinder_Class* clazz) {
+ CHECK(clazz != nullptr) << "disableInterfaceTokenHeader requires non-null clazz";
+
+ clazz->writeHeader = false;
+}
+
void AIBinder_Class_setHandleShellCommand(AIBinder_Class* clazz,
AIBinder_handleShellCommand handleShellCommand) {
CHECK(clazz != nullptr) << "setHandleShellCommand requires non-null clazz";
@@ -606,7 +612,10 @@
*in = new AParcel(binder);
(*in)->get()->markForBinder(binder->getBinder());
- status_t status = (*in)->get()->writeInterfaceToken(clazz->getInterfaceDescriptor());
+ status_t status = android::OK;
+ if (clazz->writeHeader) {
+ status = (*in)->get()->writeInterfaceToken(clazz->getInterfaceDescriptor());
+ }
binder_status_t ret = PruneStatusT(status);
if (ret != STATUS_OK) {
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index 3b515ab..3cb95ea 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -116,6 +116,9 @@
const ::android::String16& getInterfaceDescriptor() const { return mWideInterfaceDescriptor; }
const char* getInterfaceDescriptorUtf8() const { return mInterfaceDescriptor.c_str(); }
+ // whether a transaction header should be written
+ bool writeHeader = true;
+
// required to be non-null, implemented for every class
const AIBinder_Class_onCreate onCreate = nullptr;
const AIBinder_Class_onDestroy onDestroy = nullptr;
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index 78f2d3a..c82df83 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -219,6 +219,21 @@
void AIBinder_Class_setOnDump(AIBinder_Class* clazz, AIBinder_onDump onDump) __INTRODUCED_IN(29);
/**
+ * This tells users of this class not to use a transaction header. By default, libbinder_ndk users
+ * read/write transaction headers implicitly (in the SDK, this must be manually written by
+ * android.os.Parcel#writeInterfaceToken, and it is read/checked with
+ * android.os.Parcel#enforceInterface). This method is provided in order to talk to legacy code
+ * which does not write an interface token. When this is disabled, type safety is reduced, so you
+ * must have a separate way of determining the binder you are talking to is the right type. Must
+ * be called before any instance of the class is created.
+ *
+ * Available since API level 32.
+ *
+ * \param clazz class to disable interface header on.
+ */
+void AIBinder_Class_disableInterfaceTokenHeader(AIBinder_Class* clazz) __INTRODUCED_IN(32);
+
+/**
* Creates a new binder object of the appropriate class.
*
* Ownership of args is passed to this object. The lifecycle is implemented with AIBinder_incStrong
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 685ebb5..1975bdc 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -141,6 +141,11 @@
AParcel_reset;
};
+LIBBINDER_NDK32 { # introduced=32
+ global:
+ AIBinder_Class_disableInterfaceTokenHeader;
+};
+
LIBBINDER_NDK_PLATFORM {
global:
AParcel_getAllowFds;
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index 8d27eed..fe2da18 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -135,3 +135,23 @@
"libbinder_ndk_sys",
],
}
+
+rust_test {
+ name: "libbinder_ndk_bindgen_test",
+ srcs: [":libbinder_ndk_bindgen"],
+ crate_name: "binder_ndk_bindgen",
+ test_suites: ["general-tests"],
+ auto_gen_config: true,
+ clippy_lints: "none",
+ lints: "none",
+}
+
+rust_test {
+ name: "libbinder_rpc_unstable_bindgen_test",
+ srcs: [":libbinder_rpc_unstable_bindgen"],
+ crate_name: "binder_rpc_unstable_bindgen",
+ test_suites: ["general-tests"],
+ auto_gen_config: true,
+ clippy_lints: "none",
+ lints: "none",
+}
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 35db444..7c405d3 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -522,7 +522,8 @@
status_t status;
for (size_t i = 0; i < options.numSessions; i++) {
- sp<RpcSession> session = RpcSession::make(newFactory(rpcSecurity));
+ sp<RpcSession> session =
+ RpcSession::make(newFactory(rpcSecurity), std::nullopt, std::nullopt);
session->setMaxThreads(options.numIncomingConnections);
switch (socketType) {
@@ -1207,7 +1208,8 @@
}
server->start();
- sp<RpcSession> session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
+ sp<RpcSession> session =
+ RpcSession::make(RpcTransportCtxFactoryRaw::make(), std::nullopt, std::nullopt);
status_t status = session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort);
while (!server->shutdown()) usleep(10000);
ALOGE("Detected vsock loopback supported: %s", statusToString(status).c_str());
diff --git a/libs/binder/tests/binderRpcWireProtocolTest.cpp b/libs/binder/tests/binderRpcWireProtocolTest.cpp
index 46e9630..a807afa 100644
--- a/libs/binder/tests/binderRpcWireProtocolTest.cpp
+++ b/libs/binder/tests/binderRpcWireProtocolTest.cpp
@@ -21,6 +21,7 @@
#include <android-base/strings.h>
#include <binder/Parcel.h>
#include <binder/RpcSession.h>
+#include <binder/Status.h>
#include <gtest/gtest.h>
#include "../Debug.h"
@@ -154,6 +155,9 @@
[](Parcel* p) { ASSERT_EQ(OK, p->writeVectorSize(std::optional<std::vector<int32_t>>(std::nullopt))); },
[](Parcel* p) { ASSERT_EQ(OK, p->writeVectorSize(std::optional<std::vector<int32_t>>({0, 1, 17}))); },
[](Parcel* p) { ASSERT_EQ(OK, p->writeNoException()); },
+ [](Parcel* p) { ASSERT_EQ(OK, binder::Status::ok().writeToParcel(p)); },
+ [](Parcel* p) { ASSERT_EQ(OK, binder::Status::fromExceptionCode(7, ":D").writeToParcel(p)); },
+ [](Parcel* p) { ASSERT_EQ(OK, binder::Status::fromServiceSpecificError(8, ":/").writeToParcel(p)); },
};
// clang-format on
@@ -226,7 +230,8 @@
"020000000000000001000000|020000000000000001000000|ffffffff|"
"0200000000000000000000000100000000000000|0200000000000000000000000100000000000000|"
"ffffffff|010000000100000025000000|010000000100000025000000|00000000|0100000025000000|"
- "0100000025000000|03000000|00000000|ffffffff|03000000|00000000";
+ "0100000025000000|03000000|00000000|ffffffff|03000000|00000000|00000000|"
+ "07000000020000003a0044000000000000000000|f8ffffff020000003a002f00000000000000000008000000";
TEST(RpcWire, CurrentVersion) {
checkRepr(kCurrentRepr, RPC_WIRE_PROTOCOL_VERSION);
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
index 8bf04cc..7fd9f6b 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
@@ -36,7 +36,8 @@
void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider) {
if (provider.ConsumeBool()) {
- auto session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
+ auto session =
+ RpcSession::make(RpcTransportCtxFactoryRaw::make(), std::nullopt, std::nullopt);
CHECK_EQ(OK, session->addNullDebuggingClient());
p->markForRpc(session);
fillRandomParcelData(p, std::move(provider));
diff --git a/libs/binder/tests/rpc_fuzzer/Android.bp b/libs/binder/tests/rpc_fuzzer/Android.bp
index 1c75306..9323bd5 100644
--- a/libs/binder/tests/rpc_fuzzer/Android.bp
+++ b/libs/binder/tests/rpc_fuzzer/Android.bp
@@ -22,18 +22,19 @@
"libbase",
"libcutils",
"liblog",
- "libutils",
],
target: {
android: {
shared_libs: [
"libbinder",
+ "libutils",
],
},
host: {
static_libs: [
"libbinder",
+ "libutils",
],
},
},
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 70f2ae7..982dd63 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -118,12 +118,12 @@
}
void BLASTBufferItemConsumer::setBlastBufferQueue(BLASTBufferQueue* blastbufferqueue) {
- Mutex::Autolock lock(mMutex);
+ std::scoped_lock lock(mBufferQueueMutex);
mBLASTBufferQueue = blastbufferqueue;
}
void BLASTBufferItemConsumer::onSidebandStreamChanged() {
- Mutex::Autolock lock(mMutex);
+ std::scoped_lock lock(mBufferQueueMutex);
if (mBLASTBufferQueue != nullptr) {
sp<NativeHandle> stream = getSidebandStream();
mBLASTBufferQueue->setSidebandStream(stream);
@@ -630,7 +630,10 @@
class BBQSurface : public Surface {
private:
+ std::mutex mMutex;
sp<BLASTBufferQueue> mBbq;
+ bool mDestroyed = false;
+
public:
BBQSurface(const sp<IGraphicBufferProducer>& igbp, bool controlledByApp,
const sp<IBinder>& scHandle, const sp<BLASTBufferQueue>& bbq)
@@ -650,6 +653,10 @@
status_t setFrameRate(float frameRate, int8_t compatibility,
int8_t changeFrameRateStrategy) override {
+ std::unique_lock _lock{mMutex};
+ if (mDestroyed) {
+ return DEAD_OBJECT;
+ }
if (!ValidateFrameRate(frameRate, compatibility, changeFrameRateStrategy,
"BBQSurface::setFrameRate")) {
return BAD_VALUE;
@@ -658,8 +665,20 @@
}
status_t setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) override {
+ std::unique_lock _lock{mMutex};
+ if (mDestroyed) {
+ return DEAD_OBJECT;
+ }
return mBbq->setFrameTimelineInfo(frameTimelineInfo);
}
+
+ void destroy() override {
+ Surface::destroy();
+
+ std::unique_lock _lock{mMutex};
+ mDestroyed = true;
+ mBbq = nullptr;
+ }
};
// TODO: Can we coalesce this with frame updates? Need to confirm
@@ -837,4 +856,9 @@
}
}
+uint64_t BLASTBufferQueue::getLastAcquiredFrameNum() {
+ std::unique_lock _lock{mMutex};
+ return mLastAcquiredFrameNumber;
+}
+
} // namespace android
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 2edb4e4..353a91d 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -2622,4 +2622,14 @@
return composerService()->setFrameTimelineInfo(mGraphicBufferProducer, frameTimelineInfo);
}
+sp<IBinder> Surface::getSurfaceControlHandle() const {
+ Mutex::Autolock lock(mMutex);
+ return mSurfaceControlHandle;
+}
+
+void Surface::destroy() {
+ Mutex::Autolock lock(mMutex);
+ mSurfaceControlHandle = nullptr;
+}
+
}; // namespace android
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index ea9b1c6..be46180 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -62,11 +62,12 @@
uint64_t mCurrentFrameNumber = 0;
Mutex mMutex;
+ std::mutex mBufferQueueMutex;
ConsumerFrameEventHistory mFrameEventHistory GUARDED_BY(mMutex);
std::queue<uint64_t> mDisconnectEvents GUARDED_BY(mMutex);
bool mCurrentlyConnected GUARDED_BY(mMutex);
bool mPreviouslyConnected GUARDED_BY(mMutex);
- BLASTBufferQueue* mBLASTBufferQueue GUARDED_BY(mMutex);
+ BLASTBufferQueue* mBLASTBufferQueue GUARDED_BY(mBufferQueueMutex);
};
class BLASTBufferQueue
@@ -106,6 +107,7 @@
void setSidebandStream(const sp<NativeHandle>& stream);
uint32_t getLastTransformHint() const;
+ uint64_t getLastAcquiredFrameNum();
virtual ~BLASTBufferQueue();
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 7e4143b..e540351 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -99,7 +99,7 @@
*/
sp<IGraphicBufferProducer> getIGraphicBufferProducer() const;
- sp<IBinder> getSurfaceControlHandle() const { return mSurfaceControlHandle; }
+ sp<IBinder> getSurfaceControlHandle() const;
/* convenience function to check that the given surface is non NULL as
* well as its IGraphicBufferProducer */
@@ -333,6 +333,7 @@
virtual int connect(
int api, bool reportBufferRemoval,
const sp<SurfaceListener>& sListener);
+ virtual void destroy();
// When client connects to Surface with reportBufferRemoval set to true, any buffers removed
// from this Surface will be collected and returned here. Once this method returns, these
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index b3b726d..694bda6 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -424,13 +424,11 @@
ASSERT_TRUE(result.valid());
auto [status, fence] = result.get();
- int fd = fence.release();
- if (fd >= 0) {
- sync_wait(fd, -1);
- close(fd);
+ ASSERT_EQ(NO_ERROR, status);
+ if (fence.ok()) {
+ sync_wait(fence.get(), -1);
}
- ASSERT_EQ(NO_ERROR, status);
if (layers.size() > 0 && mGLESRE != nullptr) {
ASSERT_TRUE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getBuffer()->getId()));
}
@@ -1317,31 +1315,9 @@
mRE->drawLayers(settings, layers, nullptr, true, base::unique_fd());
ASSERT_TRUE(result.valid());
- auto [status, _] = result.get();
+ auto [status, fence] = result.get();
ASSERT_EQ(BAD_VALUE, status);
-}
-
-TEST_P(RenderEngineTest, drawLayers_nullOutputFence) {
- initializeRenderEngine();
-
- renderengine::DisplaySettings settings;
- settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
- settings.physicalDisplay = fullscreenRect();
- settings.clip = fullscreenRect();
-
- std::vector<const renderengine::LayerSettings*> layers;
- renderengine::LayerSettings layer;
- layer.geometry.boundaries = fullscreenRect().toFloatRect();
- BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
- layer.alpha = 1.0;
- layers.push_back(&layer);
-
- std::future<renderengine::RenderEngineResult> result =
- mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd());
- ASSERT_TRUE(result.valid());
- auto [status, _] = result.get();
- ASSERT_EQ(NO_ERROR, status);
- expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
+ ASSERT_FALSE(fence.ok());
}
TEST_P(RenderEngineTest, drawLayers_doesNotCacheFramebuffer) {
@@ -1369,8 +1345,13 @@
std::future<renderengine::RenderEngineResult> result =
mRE->drawLayers(settings, layers, mBuffer, false, base::unique_fd());
ASSERT_TRUE(result.valid());
- auto [status, _] = result.get();
+ auto [status, fence] = result.get();
+
ASSERT_EQ(NO_ERROR, status);
+ if (fence.ok()) {
+ sync_wait(fence.get(), -1);
+ }
+
ASSERT_FALSE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getBuffer()->getId()));
expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
}
@@ -1780,11 +1761,10 @@
ASSERT_TRUE(resultTwo.valid());
auto [statusTwo, fenceTwo] = resultTwo.get();
ASSERT_EQ(NO_ERROR, statusTwo);
-
- const int fd = fenceTwo.get();
- if (fd >= 0) {
- sync_wait(fd, -1);
+ if (fenceTwo.ok()) {
+ sync_wait(fenceTwo.get(), -1);
}
+
// Only cleanup the first time.
EXPECT_FALSE(mRE->canSkipPostRenderCleanup());
mRE->cleanupPostRender();
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index 33b3e1e..71b0f5f 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -287,16 +287,16 @@
// --- NotifyPointerCaptureChangedArgs ---
-NotifyPointerCaptureChangedArgs::NotifyPointerCaptureChangedArgs(int32_t id, nsecs_t eventTime,
- bool enabled)
- : NotifyArgs(id, eventTime), enabled(enabled) {}
+NotifyPointerCaptureChangedArgs::NotifyPointerCaptureChangedArgs(
+ int32_t id, nsecs_t eventTime, const PointerCaptureRequest& request)
+ : NotifyArgs(id, eventTime), request(request) {}
NotifyPointerCaptureChangedArgs::NotifyPointerCaptureChangedArgs(
const NotifyPointerCaptureChangedArgs& other)
- : NotifyArgs(other.id, other.eventTime), enabled(other.enabled) {}
+ : NotifyArgs(other.id, other.eventTime), request(other.request) {}
bool NotifyPointerCaptureChangedArgs::operator==(const NotifyPointerCaptureChangedArgs& rhs) const {
- return id == rhs.id && eventTime == rhs.eventTime && enabled == rhs.enabled;
+ return id == rhs.id && eventTime == rhs.eventTime && request == rhs.request;
}
void NotifyPointerCaptureChangedArgs::notify(const sp<InputListenerInterface>& listener) const {
diff --git a/services/inputflinger/InputReaderBase.cpp b/services/inputflinger/InputReaderBase.cpp
index f26a9a9..05ef489 100644
--- a/services/inputflinger/InputReaderBase.cpp
+++ b/services/inputflinger/InputReaderBase.cpp
@@ -67,6 +67,9 @@
if (changes & CHANGE_EXTERNAL_STYLUS_PRESENCE) {
result += "EXTERNAL_STYLUS_PRESENCE | ";
}
+ if (changes & CHANGE_POINTER_CAPTURE) {
+ result += "POINTER_CAPTURE | ";
+ }
if (changes & CHANGE_ENABLED_STATE) {
result += "ENABLED_STATE | ";
}
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index 5e9facf..6ce0313 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -116,7 +116,7 @@
void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override {}
- void setPointerCapture(bool enabled) override {}
+ void setPointerCapture(const PointerCaptureRequest&) override {}
void notifyDropWindow(const sp<IBinder>&, float x, float y) override {}
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index 288068f..9744920 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -119,15 +119,15 @@
// PointerCaptureChanged notifications always go to apps, so set the flag POLICY_FLAG_PASS_TO_USER
// for all entries.
PointerCaptureChangedEntry::PointerCaptureChangedEntry(int32_t id, nsecs_t eventTime,
- bool hasPointerCapture)
+ const PointerCaptureRequest& request)
: EventEntry(id, Type::POINTER_CAPTURE_CHANGED, eventTime, POLICY_FLAG_PASS_TO_USER),
- pointerCaptureEnabled(hasPointerCapture) {}
+ pointerCaptureRequest(request) {}
PointerCaptureChangedEntry::~PointerCaptureChangedEntry() {}
std::string PointerCaptureChangedEntry::getDescription() const {
return StringPrintf("PointerCaptureChangedEvent(pointerCaptureEnabled=%s)",
- pointerCaptureEnabled ? "true" : "false");
+ pointerCaptureRequest.enable ? "true" : "false");
}
// --- DragEntry ---
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index 8feb982..44c35c1 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -104,9 +104,9 @@
};
struct PointerCaptureChangedEntry : EventEntry {
- bool pointerCaptureEnabled;
+ const PointerCaptureRequest pointerCaptureRequest;
- PointerCaptureChangedEntry(int32_t id, nsecs_t eventTime, bool hasPointerCapture);
+ PointerCaptureChangedEntry(int32_t id, nsecs_t eventTime, const PointerCaptureRequest&);
std::string getDescription() const override;
~PointerCaptureChangedEntry() override;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 59cb419..e097773 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -559,7 +559,6 @@
mInTouchMode(true),
mMaximumObscuringOpacityForTouch(1.0f),
mFocusedDisplayId(ADISPLAY_ID_DEFAULT),
- mFocusedWindowRequestedPointerCapture(false),
mWindowTokenWithPointerCapture(nullptr),
mLatencyAggregator(),
mLatencyTracker(&mLatencyAggregator),
@@ -1331,36 +1330,51 @@
void InputDispatcher::dispatchPointerCaptureChangedLocked(
nsecs_t currentTime, const std::shared_ptr<PointerCaptureChangedEntry>& entry,
DropReason& dropReason) {
+ dropReason = DropReason::NOT_DROPPED;
+
const bool haveWindowWithPointerCapture = mWindowTokenWithPointerCapture != nullptr;
- if (entry->pointerCaptureEnabled && haveWindowWithPointerCapture) {
- LOG_ALWAYS_FATAL("Pointer Capture has already been enabled for the window.");
- }
- if (!entry->pointerCaptureEnabled && !haveWindowWithPointerCapture) {
- // Pointer capture was already forcefully disabled because of focus change.
- dropReason = DropReason::NOT_DROPPED;
- return;
- }
-
- // Set drop reason for early returns
- dropReason = DropReason::NO_POINTER_CAPTURE;
-
sp<IBinder> token;
- if (entry->pointerCaptureEnabled) {
- // Enable Pointer Capture
- if (!mFocusedWindowRequestedPointerCapture) {
+
+ if (entry->pointerCaptureRequest.enable) {
+ // Enable Pointer Capture.
+ if (haveWindowWithPointerCapture &&
+ (entry->pointerCaptureRequest == mCurrentPointerCaptureRequest)) {
+ LOG_ALWAYS_FATAL("This request to enable Pointer Capture has already been dispatched "
+ "to the window.");
+ }
+ if (!mCurrentPointerCaptureRequest.enable) {
// This can happen if a window requests capture and immediately releases capture.
ALOGW("No window requested Pointer Capture.");
+ dropReason = DropReason::NO_POINTER_CAPTURE;
return;
}
+ if (entry->pointerCaptureRequest.seq != mCurrentPointerCaptureRequest.seq) {
+ ALOGI("Skipping dispatch of Pointer Capture being enabled: sequence number mismatch.");
+ return;
+ }
+
token = mFocusResolver.getFocusedWindowToken(mFocusedDisplayId);
LOG_ALWAYS_FATAL_IF(!token, "Cannot find focused window for Pointer Capture.");
mWindowTokenWithPointerCapture = token;
} else {
- // Disable Pointer Capture
+ // Disable Pointer Capture.
+ // We do not check if the sequence number matches for requests to disable Pointer Capture
+ // for two reasons:
+ // 1. Pointer Capture can be disabled by a focus change, which means we can get two entries
+ // to disable capture with the same sequence number: one generated by
+ // disablePointerCaptureForcedLocked() and another as an acknowledgement of Pointer
+ // Capture being disabled in InputReader.
+ // 2. We respect any request to disable Pointer Capture generated by InputReader, since the
+ // actual Pointer Capture state that affects events being generated by input devices is
+ // in InputReader.
+ if (!haveWindowWithPointerCapture) {
+ // Pointer capture was already forcefully disabled because of focus change.
+ dropReason = DropReason::NOT_DROPPED;
+ return;
+ }
token = mWindowTokenWithPointerCapture;
mWindowTokenWithPointerCapture = nullptr;
- if (mFocusedWindowRequestedPointerCapture) {
- mFocusedWindowRequestedPointerCapture = false;
+ if (mCurrentPointerCaptureRequest.enable) {
setPointerCaptureLocked(false);
}
}
@@ -1369,8 +1383,7 @@
if (channel == nullptr) {
// Window has gone away, clean up Pointer Capture state.
mWindowTokenWithPointerCapture = nullptr;
- if (mFocusedWindowRequestedPointerCapture) {
- mFocusedWindowRequestedPointerCapture = false;
+ if (mCurrentPointerCaptureRequest.enable) {
setPointerCaptureLocked(false);
}
return;
@@ -3183,7 +3196,7 @@
static_cast<const PointerCaptureChangedEntry&>(eventEntry);
status = connection->inputPublisher
.publishCaptureEvent(dispatchEntry->seq, captureEntry.id,
- captureEntry.pointerCaptureEnabled);
+ captureEntry.pointerCaptureRequest.enable);
break;
}
@@ -3999,14 +4012,14 @@
void InputDispatcher::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) {
if (DEBUG_INBOUND_EVENT_DETAILS) {
ALOGD("notifyPointerCaptureChanged - eventTime=%" PRId64 ", enabled=%s", args->eventTime,
- args->enabled ? "true" : "false");
+ args->request.enable ? "true" : "false");
}
bool needWake;
{ // acquire lock
std::scoped_lock _l(mLock);
auto entry = std::make_unique<PointerCaptureChangedEntry>(args->id, args->eventTime,
- args->enabled);
+ args->request);
needWake = enqueueInboundEventLocked(std::move(entry));
} // release lock
@@ -4944,8 +4957,8 @@
std::string InputDispatcher::dumpPointerCaptureStateLocked() {
std::string dump;
- dump += StringPrintf(INDENT "FocusedWindowRequestedPointerCapture: %s\n",
- toString(mFocusedWindowRequestedPointerCapture));
+ dump += StringPrintf(INDENT "Pointer Capture Requested: %s\n",
+ toString(mCurrentPointerCaptureRequest.enable));
std::string windowName = "None";
if (mWindowTokenWithPointerCapture) {
@@ -4954,7 +4967,7 @@
windowName = captureWindowHandle ? captureWindowHandle->getName().c_str()
: "token has capture without window";
}
- dump += StringPrintf(INDENT "CurrentWindowWithPointerCapture: %s\n", windowName.c_str());
+ dump += StringPrintf(INDENT "Current Window with Pointer Capture: %s\n", windowName.c_str());
return dump;
}
@@ -5420,14 +5433,13 @@
return;
}
- if (enabled == mFocusedWindowRequestedPointerCapture) {
+ if (enabled == mCurrentPointerCaptureRequest.enable) {
ALOGW("Ignoring request to %s Pointer Capture: "
"window has %s requested pointer capture.",
enabled ? "enable" : "disable", enabled ? "already" : "not");
return;
}
- mFocusedWindowRequestedPointerCapture = enabled;
setPointerCaptureLocked(enabled);
} // release lock
@@ -6048,14 +6060,13 @@
}
void InputDispatcher::disablePointerCaptureForcedLocked() {
- if (!mFocusedWindowRequestedPointerCapture && !mWindowTokenWithPointerCapture) {
+ if (!mCurrentPointerCaptureRequest.enable && !mWindowTokenWithPointerCapture) {
return;
}
ALOGD_IF(DEBUG_FOCUS, "Disabling Pointer Capture because the window lost focus.");
- if (mFocusedWindowRequestedPointerCapture) {
- mFocusedWindowRequestedPointerCapture = false;
+ if (mCurrentPointerCaptureRequest.enable) {
setPointerCaptureLocked(false);
}
@@ -6072,14 +6083,16 @@
}
auto entry = std::make_unique<PointerCaptureChangedEntry>(mIdGenerator.nextId(), now(),
- false /* hasCapture */);
+ mCurrentPointerCaptureRequest);
mInboundQueue.push_front(std::move(entry));
}
-void InputDispatcher::setPointerCaptureLocked(bool enabled) {
- auto command = [this, enabled]() REQUIRES(mLock) {
+void InputDispatcher::setPointerCaptureLocked(bool enable) {
+ mCurrentPointerCaptureRequest.enable = enable;
+ mCurrentPointerCaptureRequest.seq++;
+ auto command = [this, request = mCurrentPointerCaptureRequest]() REQUIRES(mLock) {
scoped_unlock unlock(mLock);
- mPolicy->setPointerCapture(enabled);
+ mPolicy->setPointerCapture(request);
};
postCommandLocked(std::move(command));
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 6df333a..d0d58a4 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -383,10 +383,12 @@
// Keeps track of the focused window per display and determines focus changes.
FocusResolver mFocusResolver GUARDED_BY(mLock);
- // Whether the focused window on the focused display has requested Pointer Capture.
- // The state of this variable should always be in sync with the state of Pointer Capture in the
- // policy, which is updated through setPointerCaptureLocked(enabled).
- bool mFocusedWindowRequestedPointerCapture GUARDED_BY(mLock);
+
+ // The enabled state of this request is true iff the focused window on the focused display has
+ // requested Pointer Capture. This request also contains the sequence number associated with the
+ // current request. The state of this variable should always be in sync with the state of
+ // Pointer Capture in the policy, and is only updated through setPointerCaptureLocked(request).
+ PointerCaptureRequest mCurrentPointerCaptureRequest GUARDED_BY(mLock);
// The window token that has Pointer Capture.
// This should be in sync with PointerCaptureChangedEvents dispatched to the input channel.
@@ -396,7 +398,7 @@
void disablePointerCaptureForcedLocked() REQUIRES(mLock);
// Set the Pointer Capture state in the Policy.
- void setPointerCaptureLocked(bool enabled) REQUIRES(mLock);
+ void setPointerCaptureLocked(bool enable) REQUIRES(mLock);
// Dispatcher state at time of last ANR.
std::string mLastAnrState GUARDED_BY(mLock);
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
index ebfcbe1..3c1e637 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -156,7 +156,7 @@
*
* InputDispatcher is solely responsible for updating the Pointer Capture state.
*/
- virtual void setPointerCapture(bool enabled) = 0;
+ virtual void setPointerCapture(const PointerCaptureRequest&) = 0;
/* Notifies the policy that the drag window has moved over to another window */
virtual void notifyDropWindow(const sp<IBinder>& token, float x, float y) = 0;
diff --git a/services/inputflinger/docs/pointer_capture.md b/services/inputflinger/docs/pointer_capture.md
index 8da699d..0b44187 100644
--- a/services/inputflinger/docs/pointer_capture.md
+++ b/services/inputflinger/docs/pointer_capture.md
@@ -17,6 +17,8 @@
`InputDispatcher` is responsible for controlling the state of Pointer Capture. Since the feature requires changes to how events are generated, Pointer Capture is configured in `InputReader`.
+We use a sequence number to synchronize different requests to enable Pointer Capture between InputReader and InputDispatcher.
+
### Enabling Pointer Capture
There are four key steps that take place when Pointer Capture is enabled:
@@ -40,5 +42,5 @@
`InputDispatcher` tracks two pieces of state information regarding Pointer Capture:
-- `mFocusedWindowRequestedPointerCapture`: Whether or not the focused window has requested Pointer Capture. This is updated whenever the Dispatcher receives requests from `InputManagerService`.
+- `mCurrentPointerCaptureRequest`: The sequence number of the current Pointer Capture request. This request is enabled iff the focused window has requested Pointer Capture. This is updated whenever the Dispatcher receives requests from `InputManagerService`.
- `mWindowTokenWithPointerCapture`: The Binder token of the `InputWindow` that currently has Pointer Capture. This is only updated during the dispatch cycle. If it is not `nullptr`, it signifies that the window was notified that it has Pointer Capture.
diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h
index 4b7d26d..fe74214 100644
--- a/services/inputflinger/include/InputListener.h
+++ b/services/inputflinger/include/InputListener.h
@@ -211,11 +211,12 @@
/* Describes a change in the state of Pointer Capture. */
struct NotifyPointerCaptureChangedArgs : public NotifyArgs {
- bool enabled;
+ // The sequence number of the Pointer Capture request, if enabled.
+ PointerCaptureRequest request;
inline NotifyPointerCaptureChangedArgs() {}
- NotifyPointerCaptureChangedArgs(int32_t id, nsecs_t eventTime, bool enabled);
+ NotifyPointerCaptureChangedArgs(int32_t id, nsecs_t eventTime, const PointerCaptureRequest&);
NotifyPointerCaptureChangedArgs(const NotifyPointerCaptureChangedArgs& other);
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index 7fdbbfd..3c8ac1c 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -279,29 +279,30 @@
// True to show the location of touches on the touch screen as spots.
bool showTouches;
- // True if pointer capture is enabled.
- bool pointerCapture;
+ // The latest request to enable or disable Pointer Capture.
+ PointerCaptureRequest pointerCaptureRequest;
// The set of currently disabled input devices.
std::set<int32_t> disabledDevices;
- InputReaderConfiguration() :
- virtualKeyQuietTime(0),
+ InputReaderConfiguration()
+ : virtualKeyQuietTime(0),
pointerVelocityControlParameters(1.0f, 500.0f, 3000.0f, 3.0f),
wheelVelocityControlParameters(1.0f, 15.0f, 50.0f, 4.0f),
pointerGesturesEnabled(true),
- pointerGestureQuietInterval(100 * 1000000LL), // 100 ms
- pointerGestureDragMinSwitchSpeed(50), // 50 pixels per second
- pointerGestureTapInterval(150 * 1000000LL), // 150 ms
- pointerGestureTapDragInterval(150 * 1000000LL), // 150 ms
- pointerGestureTapSlop(10.0f), // 10 pixels
+ pointerGestureQuietInterval(100 * 1000000LL), // 100 ms
+ pointerGestureDragMinSwitchSpeed(50), // 50 pixels per second
+ pointerGestureTapInterval(150 * 1000000LL), // 150 ms
+ pointerGestureTapDragInterval(150 * 1000000LL), // 150 ms
+ pointerGestureTapSlop(10.0f), // 10 pixels
pointerGestureMultitouchSettleInterval(100 * 1000000LL), // 100 ms
- pointerGestureMultitouchMinDistance(15), // 15 pixels
- pointerGestureSwipeTransitionAngleCosine(0.2588f), // cosine of 75 degrees
+ pointerGestureMultitouchMinDistance(15), // 15 pixels
+ pointerGestureSwipeTransitionAngleCosine(0.2588f), // cosine of 75 degrees
pointerGestureSwipeMaxWidthRatio(0.25f),
pointerGestureMovementSpeedRatio(0.8f),
pointerGestureZoomSpeedRatio(0.3f),
- showTouches(false), pointerCapture(false) { }
+ showTouches(false),
+ pointerCaptureRequest() {}
static std::string changesToString(uint32_t changes);
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index e71a9e9..86d4c26 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -367,9 +367,15 @@
}
if (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE) {
- const NotifyPointerCaptureChangedArgs args(mContext.getNextId(), now,
- mConfig.pointerCapture);
- mQueuedListener->notifyPointerCaptureChanged(&args);
+ if (mCurrentPointerCaptureRequest == mConfig.pointerCaptureRequest) {
+ ALOGV("Skipping notifying pointer capture changes: "
+ "There was no change in the pointer capture state.");
+ } else {
+ mCurrentPointerCaptureRequest = mConfig.pointerCaptureRequest;
+ const NotifyPointerCaptureChangedArgs args(mContext.getNextId(), now,
+ mCurrentPointerCaptureRequest);
+ mQueuedListener->notifyPointerCaptureChanged(&args);
+ }
}
}
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index a00c5af..e44aa0f 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -230,6 +230,8 @@
uint32_t mConfigurationChangesToRefresh GUARDED_BY(mLock);
void refreshConfigurationLocked(uint32_t changes) REQUIRES(mLock);
+ PointerCaptureRequest mCurrentPointerCaptureRequest GUARDED_BY(mLock);
+
// state queries
typedef int32_t (InputDevice::*GetStateFunc)(uint32_t sourceMask, int32_t code);
int32_t getStateLocked(int32_t deviceId, uint32_t sourceMask, int32_t code,
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index 437902a..2ac41b1 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -154,9 +154,9 @@
mHWheelScale = 1.0f;
}
- if ((!changes && config->pointerCapture) ||
+ if ((!changes && config->pointerCaptureRequest.enable) ||
(changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE)) {
- if (config->pointerCapture) {
+ if (config->pointerCaptureRequest.enable) {
if (mParameters.mode == Parameters::MODE_POINTER) {
mParameters.mode = Parameters::MODE_POINTER_RELATIVE;
mSource = AINPUT_SOURCE_MOUSE_RELATIVE;
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index a9f0247..ac5f6b6 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -470,6 +470,23 @@
getDeviceContext().getConfiguration().tryGetProperty(String8("touch.orientationAware"),
mParameters.orientationAware);
+ mParameters.orientation = Parameters::Orientation::ORIENTATION_0;
+ String8 orientationString;
+ if (getDeviceContext().getConfiguration().tryGetProperty(String8("touch.orientation"),
+ orientationString)) {
+ if (mParameters.deviceType != Parameters::DeviceType::TOUCH_SCREEN) {
+ ALOGW("The configuration 'touch.orientation' is only supported for touchscreens.");
+ } else if (orientationString == "ORIENTATION_90") {
+ mParameters.orientation = Parameters::Orientation::ORIENTATION_90;
+ } else if (orientationString == "ORIENTATION_180") {
+ mParameters.orientation = Parameters::Orientation::ORIENTATION_180;
+ } else if (orientationString == "ORIENTATION_270") {
+ mParameters.orientation = Parameters::Orientation::ORIENTATION_270;
+ } else if (orientationString != "ORIENTATION_0") {
+ ALOGW("Invalid value for touch.orientation: '%s'", orientationString.string());
+ }
+ }
+
mParameters.hasAssociatedDisplay = false;
mParameters.associatedDisplayIsExternal = false;
if (mParameters.orientationAware ||
@@ -508,6 +525,7 @@
toString(mParameters.associatedDisplayIsExternal),
mParameters.uniqueDisplayId.c_str());
dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware));
+ dump += INDENT4 "Orientation: " + NamedEnum::string(mParameters.orientation) + "\n";
}
void TouchInputMapper::configureRawPointerAxes() {
@@ -603,7 +621,7 @@
// Determine device mode.
if (mParameters.deviceType == Parameters::DeviceType::POINTER &&
- mConfig.pointerGesturesEnabled && !mConfig.pointerCapture) {
+ mConfig.pointerGesturesEnabled && !mConfig.pointerCaptureRequest.enable) {
mSource = AINPUT_SOURCE_MOUSE;
mDeviceMode = DeviceMode::POINTER;
if (hasStylus()) {
@@ -669,7 +687,13 @@
int32_t naturalPhysicalWidth, naturalPhysicalHeight;
int32_t naturalPhysicalLeft, naturalPhysicalTop;
int32_t naturalDeviceWidth, naturalDeviceHeight;
- switch (mViewport.orientation) {
+
+ // Apply the inverse of the input device orientation so that the surface is configured
+ // in the same orientation as the device. The input device orientation will be
+ // re-applied to mSurfaceOrientation.
+ const int32_t naturalSurfaceOrientation =
+ (mViewport.orientation - static_cast<int32_t>(mParameters.orientation) + 4) % 4;
+ switch (naturalSurfaceOrientation) {
case DISPLAY_ORIENTATION_90:
naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop;
naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft;
@@ -752,6 +776,10 @@
mSurfaceOrientation = mParameters.orientationAware ? mViewport.orientation
: DISPLAY_ORIENTATION_0;
}
+
+ // Apply the input device orientation for the device.
+ mSurfaceOrientation =
+ (mSurfaceOrientation + static_cast<int32_t>(mParameters.orientation)) % 4;
} else {
mPhysicalWidth = rawWidth;
mPhysicalHeight = rawHeight;
@@ -776,11 +804,12 @@
// preserve the cursor position.
if (mDeviceMode == DeviceMode::POINTER ||
(mDeviceMode == DeviceMode::DIRECT && mConfig.showTouches) ||
- (mParameters.deviceType == Parameters::DeviceType::POINTER && mConfig.pointerCapture)) {
+ (mParameters.deviceType == Parameters::DeviceType::POINTER &&
+ mConfig.pointerCaptureRequest.enable)) {
if (mPointerController == nullptr) {
mPointerController = getContext()->getPointerController(getDeviceId());
}
- if (mConfig.pointerCapture) {
+ if (mConfig.pointerCaptureRequest.enable) {
mPointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
}
} else {
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index 920f842..e104220 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -204,6 +204,15 @@
bool hasAssociatedDisplay;
bool associatedDisplayIsExternal;
bool orientationAware;
+
+ enum class Orientation : int32_t {
+ ORIENTATION_0 = DISPLAY_ORIENTATION_0,
+ ORIENTATION_90 = DISPLAY_ORIENTATION_90,
+ ORIENTATION_180 = DISPLAY_ORIENTATION_180,
+ ORIENTATION_270 = DISPLAY_ORIENTATION_270,
+ };
+ Orientation orientation;
+
bool hasButtonUnderPad;
std::string uniqueDisplayId;
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 0fc4708..f997cb7 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -243,19 +243,22 @@
mConfig.keyRepeatDelay = delay;
}
- void waitForSetPointerCapture(bool enabled) {
+ PointerCaptureRequest assertSetPointerCaptureCalled(bool enabled) {
std::unique_lock lock(mLock);
base::ScopedLockAssertion assumeLocked(mLock);
if (!mPointerCaptureChangedCondition.wait_for(lock, 100ms,
[this, enabled]() REQUIRES(mLock) {
- return mPointerCaptureEnabled &&
- *mPointerCaptureEnabled ==
+ return mPointerCaptureRequest->enable ==
enabled;
})) {
- FAIL() << "Timed out waiting for setPointerCapture(" << enabled << ") to be called.";
+ ADD_FAILURE() << "Timed out waiting for setPointerCapture(" << enabled
+ << ") to be called.";
+ return {};
}
- mPointerCaptureEnabled.reset();
+ auto request = *mPointerCaptureRequest;
+ mPointerCaptureRequest.reset();
+ return request;
}
void assertSetPointerCaptureNotCalled() {
@@ -263,11 +266,11 @@
base::ScopedLockAssertion assumeLocked(mLock);
if (mPointerCaptureChangedCondition.wait_for(lock, 100ms) != std::cv_status::timeout) {
- FAIL() << "Expected setPointerCapture(enabled) to not be called, but was called. "
+ FAIL() << "Expected setPointerCapture(request) to not be called, but was called. "
"enabled = "
- << *mPointerCaptureEnabled;
+ << std::to_string(mPointerCaptureRequest->enable);
}
- mPointerCaptureEnabled.reset();
+ mPointerCaptureRequest.reset();
}
void assertDropTargetEquals(const sp<IBinder>& targetToken) {
@@ -285,7 +288,8 @@
std::optional<NotifySwitchArgs> mLastNotifySwitch GUARDED_BY(mLock);
std::condition_variable mPointerCaptureChangedCondition;
- std::optional<bool> mPointerCaptureEnabled GUARDED_BY(mLock);
+
+ std::optional<PointerCaptureRequest> mPointerCaptureRequest GUARDED_BY(mLock);
// ANR handling
std::queue<std::shared_ptr<InputApplicationHandle>> mAnrApplications GUARDED_BY(mLock);
@@ -402,9 +406,9 @@
mOnPointerDownToken = newToken;
}
- void setPointerCapture(bool enabled) override {
+ void setPointerCapture(const PointerCaptureRequest& request) override {
std::scoped_lock lock(mLock);
- mPointerCaptureEnabled = {enabled};
+ mPointerCaptureRequest = {request};
mPointerCaptureChangedCondition.notify_all();
}
@@ -1385,8 +1389,9 @@
return generateMotionArgs(action, source, displayId, {PointF{100, 200}});
}
-static NotifyPointerCaptureChangedArgs generatePointerCaptureChangedArgs(bool enabled) {
- return NotifyPointerCaptureChangedArgs(/* id */ 0, systemTime(SYSTEM_TIME_MONOTONIC), enabled);
+static NotifyPointerCaptureChangedArgs generatePointerCaptureChangedArgs(
+ const PointerCaptureRequest& request) {
+ return NotifyPointerCaptureChangedArgs(/* id */ 0, systemTime(SYSTEM_TIME_MONOTONIC), request);
}
TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) {
@@ -4596,16 +4601,18 @@
mWindow->consumeFocusEvent(true);
}
- void notifyPointerCaptureChanged(bool enabled) {
- const NotifyPointerCaptureChangedArgs args = generatePointerCaptureChangedArgs(enabled);
+ void notifyPointerCaptureChanged(const PointerCaptureRequest& request) {
+ const NotifyPointerCaptureChangedArgs args = generatePointerCaptureChangedArgs(request);
mDispatcher->notifyPointerCaptureChanged(&args);
}
- void requestAndVerifyPointerCapture(const sp<FakeWindowHandle>& window, bool enabled) {
+ PointerCaptureRequest requestAndVerifyPointerCapture(const sp<FakeWindowHandle>& window,
+ bool enabled) {
mDispatcher->requestPointerCapture(window->getToken(), enabled);
- mFakePolicy->waitForSetPointerCapture(enabled);
- notifyPointerCaptureChanged(enabled);
+ auto request = mFakePolicy->assertSetPointerCaptureCalled(enabled);
+ notifyPointerCaptureChanged(request);
window->consumeCaptureEvent(enabled);
+ return request;
}
};
@@ -4627,7 +4634,7 @@
}
TEST_F(InputDispatcherPointerCaptureTests, DisablesPointerCaptureAfterWindowLosesFocus) {
- requestAndVerifyPointerCapture(mWindow, true);
+ auto request = requestAndVerifyPointerCapture(mWindow, true);
setFocusedWindow(mSecondWindow);
@@ -4635,26 +4642,26 @@
mWindow->consumeCaptureEvent(false);
mWindow->consumeFocusEvent(false);
mSecondWindow->consumeFocusEvent(true);
- mFakePolicy->waitForSetPointerCapture(false);
+ mFakePolicy->assertSetPointerCaptureCalled(false);
// Ensure that additional state changes from InputReader are not sent to the window.
- notifyPointerCaptureChanged(false);
- notifyPointerCaptureChanged(true);
- notifyPointerCaptureChanged(false);
+ notifyPointerCaptureChanged({});
+ notifyPointerCaptureChanged(request);
+ notifyPointerCaptureChanged({});
mWindow->assertNoEvents();
mSecondWindow->assertNoEvents();
mFakePolicy->assertSetPointerCaptureNotCalled();
}
TEST_F(InputDispatcherPointerCaptureTests, UnexpectedStateChangeDisablesPointerCapture) {
- requestAndVerifyPointerCapture(mWindow, true);
+ auto request = requestAndVerifyPointerCapture(mWindow, true);
// InputReader unexpectedly disables and enables pointer capture.
- notifyPointerCaptureChanged(false);
- notifyPointerCaptureChanged(true);
+ notifyPointerCaptureChanged({});
+ notifyPointerCaptureChanged(request);
// Ensure that Pointer Capture is disabled.
- mFakePolicy->waitForSetPointerCapture(false);
+ mFakePolicy->assertSetPointerCaptureCalled(false);
mWindow->consumeCaptureEvent(false);
mWindow->assertNoEvents();
}
@@ -4664,24 +4671,43 @@
// The first window loses focus.
setFocusedWindow(mSecondWindow);
- mFakePolicy->waitForSetPointerCapture(false);
+ mFakePolicy->assertSetPointerCaptureCalled(false);
mWindow->consumeCaptureEvent(false);
// Request Pointer Capture from the second window before the notification from InputReader
// arrives.
mDispatcher->requestPointerCapture(mSecondWindow->getToken(), true);
- mFakePolicy->waitForSetPointerCapture(true);
+ auto request = mFakePolicy->assertSetPointerCaptureCalled(true);
// InputReader notifies Pointer Capture was disabled (because of the focus change).
- notifyPointerCaptureChanged(false);
+ notifyPointerCaptureChanged({});
// InputReader notifies Pointer Capture was enabled (because of mSecondWindow's request).
- notifyPointerCaptureChanged(true);
+ notifyPointerCaptureChanged(request);
mSecondWindow->consumeFocusEvent(true);
mSecondWindow->consumeCaptureEvent(true);
}
+TEST_F(InputDispatcherPointerCaptureTests, EnableRequestFollowsSequenceNumbers) {
+ // App repeatedly enables and disables capture.
+ mDispatcher->requestPointerCapture(mWindow->getToken(), true);
+ auto firstRequest = mFakePolicy->assertSetPointerCaptureCalled(true);
+ mDispatcher->requestPointerCapture(mWindow->getToken(), false);
+ mFakePolicy->assertSetPointerCaptureCalled(false);
+ mDispatcher->requestPointerCapture(mWindow->getToken(), true);
+ auto secondRequest = mFakePolicy->assertSetPointerCaptureCalled(true);
+
+ // InputReader notifies that PointerCapture has been enabled for the first request. Since the
+ // first request is now stale, this should do nothing.
+ notifyPointerCaptureChanged(firstRequest);
+ mWindow->assertNoEvents();
+
+ // InputReader notifies that the second request was enabled.
+ notifyPointerCaptureChanged(secondRequest);
+ mWindow->consumeCaptureEvent(true);
+}
+
class InputDispatcherUntrustedTouchesTest : public InputDispatcherTest {
protected:
constexpr static const float MAXIMUM_OBSCURING_OPACITY = 0.8;
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index c76ed38..5c430f5 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -312,8 +312,9 @@
transform = t;
}
- void setPointerCapture(bool enabled) {
- mConfig.pointerCapture = enabled;
+ PointerCaptureRequest setPointerCapture(bool enabled) {
+ mConfig.pointerCaptureRequest = {enabled, mNextPointerCaptureSequenceNumber++};
+ return mConfig.pointerCaptureRequest;
}
void setShowTouches(bool enabled) {
@@ -327,6 +328,8 @@
float getPointerGestureMovementSpeedRatio() { return mConfig.pointerGestureMovementSpeedRatio; }
private:
+ uint32_t mNextPointerCaptureSequenceNumber = 0;
+
DisplayViewport createDisplayViewport(int32_t displayId, int32_t width, int32_t height,
int32_t orientation, bool isActive,
const std::string& uniqueId,
@@ -1993,24 +1996,24 @@
TEST_F(InputReaderTest, ChangingPointerCaptureNotifiesInputListener) {
NotifyPointerCaptureChangedArgs args;
- mFakePolicy->setPointerCapture(true);
+ auto request = mFakePolicy->setPointerCapture(true);
mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
mReader->loopOnce();
mFakeListener->assertNotifyCaptureWasCalled(&args);
- ASSERT_TRUE(args.enabled) << "Pointer Capture should be enabled.";
+ ASSERT_TRUE(args.request.enable) << "Pointer Capture should be enabled.";
+ ASSERT_EQ(args.request, request) << "Pointer Capture sequence number should match.";
mFakePolicy->setPointerCapture(false);
mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
mReader->loopOnce();
mFakeListener->assertNotifyCaptureWasCalled(&args);
- ASSERT_FALSE(args.enabled) << "Pointer Capture should be disabled.";
+ ASSERT_FALSE(args.request.enable) << "Pointer Capture should be disabled.";
- // Verify that the Pointer Capture state is re-configured correctly when the configuration value
+ // Verify that the Pointer Capture state is not updated when the configuration value
// does not change.
mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
mReader->loopOnce();
- mFakeListener->assertNotifyCaptureWasCalled(&args);
- ASSERT_FALSE(args.enabled) << "Pointer Capture should be disabled.";
+ mFakeListener->assertNotifyCaptureWasNotCalled();
}
class FakeVibratorInputMapper : public FakeInputMapper {
@@ -4701,6 +4704,8 @@
void prepareLocationCalibration();
int32_t toRawX(float displayX);
int32_t toRawY(float displayY);
+ int32_t toRotatedRawX(float displayX);
+ int32_t toRotatedRawY(float displayY);
float toCookedX(float rawX, float rawY);
float toCookedY(float rawX, float rawY);
float toDisplayX(int32_t rawX);
@@ -4783,6 +4788,14 @@
return int32_t(displayY * (RAW_Y_MAX - RAW_Y_MIN + 1) / DISPLAY_HEIGHT + RAW_Y_MIN);
}
+int32_t TouchInputMapperTest::toRotatedRawX(float displayX) {
+ return int32_t(displayX * (RAW_X_MAX - RAW_X_MIN + 1) / DISPLAY_HEIGHT + RAW_X_MIN);
+}
+
+int32_t TouchInputMapperTest::toRotatedRawY(float displayY) {
+ return int32_t(displayY * (RAW_Y_MAX - RAW_Y_MIN + 1) / DISPLAY_WIDTH + RAW_Y_MIN);
+}
+
float TouchInputMapperTest::toCookedX(float rawX, float rawY) {
AFFINE_TRANSFORM.applyTo(rawX, rawY);
return rawX;
@@ -5529,6 +5542,172 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
}
+TEST_F(SingleTouchInputMapperTest, Process_WhenOrientation0_RotatesMotions) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareButtons();
+ prepareAxes(POSITION);
+ addConfigurationProperty("touch.orientationAware", "1");
+ addConfigurationProperty("touch.orientation", "ORIENTATION_0");
+ clearViewports();
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ auto& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
+ NotifyMotionArgs args;
+
+ // Orientation 0.
+ processDown(mapper, toRawX(50), toRawY(75));
+ processSync(mapper);
+
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
+ EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
+
+ processUp(mapper);
+ processSync(mapper);
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
+}
+
+TEST_F(SingleTouchInputMapperTest, Process_WhenOrientation90_RotatesMotions) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareButtons();
+ prepareAxes(POSITION);
+ addConfigurationProperty("touch.orientationAware", "1");
+ addConfigurationProperty("touch.orientation", "ORIENTATION_90");
+ clearViewports();
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ auto& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
+ NotifyMotionArgs args;
+
+ // Orientation 90.
+ processDown(mapper, RAW_X_MAX - toRotatedRawX(75) + RAW_X_MIN, toRotatedRawY(50));
+ processSync(mapper);
+
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
+ EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
+
+ processUp(mapper);
+ processSync(mapper);
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
+}
+
+TEST_F(SingleTouchInputMapperTest, Process_WhenOrientation180_RotatesMotions) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareButtons();
+ prepareAxes(POSITION);
+ addConfigurationProperty("touch.orientationAware", "1");
+ addConfigurationProperty("touch.orientation", "ORIENTATION_180");
+ clearViewports();
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ auto& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
+ NotifyMotionArgs args;
+
+ // Orientation 180.
+ processDown(mapper, RAW_X_MAX - toRawX(50) + RAW_X_MIN, RAW_Y_MAX - toRawY(75) + RAW_Y_MIN);
+ processSync(mapper);
+
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
+ EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
+
+ processUp(mapper);
+ processSync(mapper);
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
+}
+
+TEST_F(SingleTouchInputMapperTest, Process_WhenOrientation270_RotatesMotions) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareButtons();
+ prepareAxes(POSITION);
+ addConfigurationProperty("touch.orientationAware", "1");
+ addConfigurationProperty("touch.orientation", "ORIENTATION_270");
+ clearViewports();
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ auto& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
+ NotifyMotionArgs args;
+
+ // Orientation 270.
+ processDown(mapper, toRotatedRawX(75), RAW_Y_MAX - toRotatedRawY(50) + RAW_Y_MIN);
+ processSync(mapper);
+
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
+ EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
+
+ processUp(mapper);
+ processSync(mapper);
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
+}
+
+TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationSpecified_RotatesMotionWithDisplay) {
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareButtons();
+ prepareAxes(POSITION);
+ // Since InputReader works in the un-rotated coordinate space, only devices that are not
+ // orientation-aware are affected by display rotation.
+ addConfigurationProperty("touch.orientationAware", "0");
+ addConfigurationProperty("touch.orientation", "ORIENTATION_90");
+ auto& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
+
+ NotifyMotionArgs args;
+
+ // Orientation 90, Rotation 0.
+ clearViewports();
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ processDown(mapper, RAW_X_MAX - toRotatedRawX(75) + RAW_X_MIN, toRotatedRawY(50));
+ processSync(mapper);
+
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
+ EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
+
+ processUp(mapper);
+ processSync(mapper);
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
+
+ // Orientation 90, Rotation 90.
+ clearViewports();
+ prepareDisplay(DISPLAY_ORIENTATION_90);
+ processDown(mapper, toRotatedRawX(50), toRotatedRawY(75));
+ processSync(mapper);
+
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
+ EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
+
+ processUp(mapper);
+ processSync(mapper);
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
+
+ // Orientation 90, Rotation 180.
+ clearViewports();
+ prepareDisplay(DISPLAY_ORIENTATION_180);
+ processDown(mapper, toRotatedRawX(75), RAW_Y_MAX - toRotatedRawY(50) + RAW_Y_MIN);
+ processSync(mapper);
+
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
+ EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
+
+ processUp(mapper);
+ processSync(mapper);
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
+
+ // Orientation 90, Rotation 270.
+ clearViewports();
+ prepareDisplay(DISPLAY_ORIENTATION_270);
+ processDown(mapper, RAW_X_MAX - toRotatedRawX(50) + RAW_X_MIN,
+ RAW_Y_MAX - toRotatedRawY(75) + RAW_Y_MIN);
+ processSync(mapper);
+
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ EXPECT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1);
+ EXPECT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1);
+
+ processUp(mapper);
+ processSync(mapper);
+ EXPECT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled());
+}
+
TEST_F(SingleTouchInputMapperTest, Process_AllAxes_DefaultCalibration) {
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
diff --git a/services/inputflinger/tests/TestInputListener.cpp b/services/inputflinger/tests/TestInputListener.cpp
index fb7de97..6a26c63 100644
--- a/services/inputflinger/tests/TestInputListener.cpp
+++ b/services/inputflinger/tests/TestInputListener.cpp
@@ -100,6 +100,11 @@
"to have been called."));
}
+void TestInputListener::assertNotifyCaptureWasNotCalled() {
+ ASSERT_NO_FATAL_FAILURE(assertNotCalled<NotifyPointerCaptureChangedArgs>(
+ "notifyPointerCaptureChanged() should not be called."));
+}
+
template <class NotifyArgsType>
void TestInputListener::assertCalled(NotifyArgsType* outEventArgs, std::string message) {
std::unique_lock<std::mutex> lock(mLock);
diff --git a/services/inputflinger/tests/TestInputListener.h b/services/inputflinger/tests/TestInputListener.h
index 0ffcaaa..0a1dc4b 100644
--- a/services/inputflinger/tests/TestInputListener.h
+++ b/services/inputflinger/tests/TestInputListener.h
@@ -55,6 +55,7 @@
void assertNotifySwitchWasCalled(NotifySwitchArgs* outEventArgs = nullptr);
void assertNotifyCaptureWasCalled(NotifyPointerCaptureChangedArgs* outEventArgs = nullptr);
+ void assertNotifyCaptureWasNotCalled();
void assertNotifySensorWasCalled(NotifySensorArgs* outEventArgs = nullptr);
void assertNotifyVibratorStateWasCalled(NotifyVibratorStateArgs* outEventArgs = nullptr);
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index 4151b45..bba6e22 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -36,7 +36,7 @@
"-Wall",
"-Werror",
"-Wextra",
- "-fvisibility=hidden"
+ "-fvisibility=hidden",
],
header_libs: [
@@ -60,6 +60,7 @@
"libbase",
"libhidlbase",
"libfmq",
+ "packagemanager_aidl-cpp",
"android.hardware.sensors@1.0",
"android.hardware.sensors@2.0",
"android.hardware.sensors@2.1",
@@ -76,6 +77,7 @@
"libsensor",
"libsensorprivacy",
"libpermission",
+ "packagemanager_aidl-cpp",
],
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 534efee..c64ccd1 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -395,6 +395,14 @@
return;
}
+ // If the mode is not the current mode, this means that a
+ // mode change is in progress. In that case we shouldn't dispatch an event
+ // as it will be dispatched when the current mode changes.
+ if (std::scoped_lock lock(mRefreshRateConfigsLock);
+ mRefreshRateConfigs->getCurrentRefreshRate().getMode() != mFeatures.mode) {
+ return;
+ }
+
// If there is no change from cached mode, there is no need to dispatch an event
if (mFeatures.mode == mFeatures.cachedModeChangedParams->mode) {
return;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 38b8ef1..f79c861 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2422,23 +2422,28 @@
}
}
-FloatRect SurfaceFlinger::getLayerClipBoundsForDisplay(const DisplayDevice& displayDevice) const {
- return displayDevice.getLayerStackSpaceRect().toFloatRect();
-}
-
void SurfaceFlinger::computeLayerBounds() {
+ // Find the largest width and height among all the displays.
+ int32_t maxDisplayWidth = 0;
+ int32_t maxDisplayHeight = 0;
for (const auto& pair : ON_MAIN_THREAD(mDisplays)) {
const auto& displayDevice = pair.second;
- const auto display = displayDevice->getCompositionDisplay();
- for (const auto& layer : mDrawingState.layersSortedByZ) {
- // Only consider the layers on this display.
- if (!display->includesLayer(layer->getOutputFilter())) {
- continue;
- }
-
- layer->computeBounds(getLayerClipBoundsForDisplay(*displayDevice), ui::Transform(),
- 0.f /* shadowRadius */);
+ int32_t width = displayDevice->getWidth();
+ int32_t height = displayDevice->getHeight();
+ if (width > maxDisplayWidth) {
+ maxDisplayWidth = width;
}
+ if (height > maxDisplayHeight) {
+ maxDisplayHeight = height;
+ }
+ }
+
+ // Ignore display bounds for now since they will be computed later. Use a large Rect bound
+ // to ensure it's bigger than an actual display will be.
+ FloatRect maxBounds(-maxDisplayWidth * 10, -maxDisplayHeight * 10, maxDisplayWidth * 10,
+ maxDisplayHeight * 10);
+ for (const auto& layer : mDrawingState.layersSortedByZ) {
+ layer->computeBounds(maxBounds, ui::Transform(), 0.f /* shadowRadius */);
}
}
@@ -2864,8 +2869,8 @@
(currentState.orientedDisplaySpaceRect != drawingState.orientedDisplaySpaceRect)) {
display->setProjection(currentState.orientation, currentState.layerStackSpaceRect,
currentState.orientedDisplaySpaceRect);
- if (display->isPrimary()) {
- mDefaultDisplayTransformHint = display->getTransformHint();
+ if (isDisplayActiveLocked(display)) {
+ mActiveDisplayTransformHint = display->getTransformHint();
}
}
if (currentState.width != drawingState.width ||
@@ -3344,9 +3349,9 @@
composerState.state.surface = handle;
states.add(composerState);
- lbc->updateTransformHint(mDefaultDisplayTransformHint);
+ lbc->updateTransformHint(mActiveDisplayTransformHint);
if (outTransformHint) {
- *outTransformHint = mDefaultDisplayTransformHint;
+ *outTransformHint = mActiveDisplayTransformHint;
}
// attach this layer to the client
client->attachLayer(handle, lbc);
@@ -4457,7 +4462,7 @@
const nsecs_t vsyncPeriod =
display->refreshRateConfigs().getCurrentRefreshRate().getVsyncPeriod();
mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod);
- mDefaultDisplayTransformHint = display->getTransformHint();
+ mActiveDisplayTransformHint = display->getTransformHint();
// Use phase of 0 since phase is not known.
// Use latency of 0, which will snap to the ideal latency.
DisplayStatInfo stats{0 /* vsyncTime */, vsyncPeriod};
@@ -5674,6 +5679,7 @@
return nullptr;
}();
+ mDebugDisplayModeSetByBackdoor = false;
const status_t result = setActiveMode(display, modeId);
mDebugDisplayModeSetByBackdoor = result == NO_ERROR;
return result;
@@ -6876,7 +6882,7 @@
parent->addChild(layer);
}
- layer->updateTransformHint(mDefaultDisplayTransformHint);
+ layer->updateTransformHint(mActiveDisplayTransformHint);
if (state->initialProducer != nullptr) {
mGraphicBufferProducerList.insert(state->initialProducer);
@@ -6923,12 +6929,12 @@
return;
}
mActiveDisplayToken = activeDisplay->getDisplayToken();
-
activeDisplay->getCompositionDisplay()->setLayerCachingTexturePoolEnabled(true);
updateInternalDisplayVsyncLocked(activeDisplay);
mScheduler->setModeChangePending(false);
mScheduler->setRefreshRateConfigs(activeDisplay->holdRefreshRateConfigs());
onActiveDisplaySizeChanged(activeDisplay);
+ mActiveDisplayTransformHint = activeDisplay->getTransformHint();
}
status_t SurfaceFlinger::addWindowInfosListener(
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 46dad50..9dedfa7 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -354,13 +354,6 @@
std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& listenerCallbacks)
REQUIRES(mStateLock);
- // Used internally by computeLayerBounds() to gets the clip rectangle to use for the
- // root layers on a particular display in layer-coordinate space. The
- // layers (and effectively their children) will be clipped against this
- // rectangle. The base behavior is to clip to the visible region of the
- // display.
- virtual FloatRect getLayerClipBoundsForDisplay(const DisplayDevice&) const;
-
virtual void processDisplayAdded(const wp<IBinder>& displayToken, const DisplayDeviceState&)
REQUIRES(mStateLock);
@@ -1507,7 +1500,7 @@
auto getLayerCreatedState(const sp<IBinder>& handle);
sp<Layer> handleLayerCreatedLocked(const sp<IBinder>& handle) REQUIRES(mStateLock);
- std::atomic<ui::Transform::RotationFlags> mDefaultDisplayTransformHint;
+ std::atomic<ui::Transform::RotationFlags> mActiveDisplayTransformHint;
void scheduleRegionSamplingThread();
void notifyRegionSamplingThread();
diff --git a/services/surfaceflinger/tests/EffectLayer_test.cpp b/services/surfaceflinger/tests/EffectLayer_test.cpp
index 1361ded..9fa0452 100644
--- a/services/surfaceflinger/tests/EffectLayer_test.cpp
+++ b/services/surfaceflinger/tests/EffectLayer_test.cpp
@@ -176,6 +176,15 @@
}
}
+TEST_F(EffectLayerTest, EffectLayerWithColorNoCrop) {
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ ui::DisplayMode mode;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
+ const ui::Size& resolution = mode.resolution;
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, resolution.getWidth(), resolution.getHeight()), Color::RED);
+}
+
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 2715587..3ed3eba 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -1231,6 +1231,12 @@
return VK_ERROR_SURFACE_LOST_KHR;
}
+ // In shared mode the num_images must be one regardless of how many
+ // buffers were allocated for the buffer queue.
+ if (swapchain_image_usage & VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID) {
+ num_images = 1;
+ }
+
int32_t legacy_usage = 0;
if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
uint64_t consumer_usage, producer_usage;