Merge "Changed luma calculation to an approximation method. Test: Manually flashed"
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index 09aee89..be7e3e1 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -66,7 +66,6 @@
name: "dumpstate_aidl",
srcs: [
"binder/android/os/IDumpstateListener.aidl",
- "binder/android/os/IDumpstateToken.aidl",
"binder/android/os/IDumpstate.aidl",
],
path: "binder",
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index f98df99..ccd74db 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -58,8 +58,6 @@
exit(0);
}
-class DumpstateToken : public BnDumpstateToken {};
-
} // namespace
DumpstateService::DumpstateService() : ds_(nullptr) {
@@ -81,38 +79,6 @@
return android::OK;
}
-// Note: this method is part of the old flow and is not expected to be used in combination
-// with startBugreport.
-binder::Status DumpstateService::setListener(const std::string& name,
- const sp<IDumpstateListener>& listener,
- bool getSectionDetails,
- sp<IDumpstateToken>* returned_token) {
- *returned_token = nullptr;
- if (name.empty()) {
- MYLOGE("setListener(): name not set\n");
- return binder::Status::ok();
- }
- if (listener == nullptr) {
- MYLOGE("setListener(): listener not set\n");
- return binder::Status::ok();
- }
- std::lock_guard<std::mutex> lock(lock_);
- if (ds_ == nullptr) {
- ds_ = &(Dumpstate::GetInstance());
- }
- if (ds_->listener_ != nullptr) {
- MYLOGE("setListener(%s): already set (%s)\n", name.c_str(), ds_->listener_name_.c_str());
- return binder::Status::ok();
- }
-
- ds_->listener_name_ = name;
- ds_->listener_ = listener;
- ds_->report_section_ = getSectionDetails;
- *returned_token = new DumpstateToken();
-
- return binder::Status::ok();
-}
-
binder::Status DumpstateService::startBugreport(int32_t calling_uid,
const std::string& calling_package,
const android::base::unique_fd& bugreport_fd,
@@ -121,8 +87,7 @@
const sp<IDumpstateListener>& listener) {
MYLOGI("startBugreport() with mode: %d\n", bugreport_mode);
- // This is the bugreporting API flow, so ensure there is only one bugreport in progress at a
- // time.
+ // Ensure there is only one bugreport in progress at a time.
std::lock_guard<std::mutex> lock(lock_);
if (ds_ != nullptr) {
MYLOGE("Error! There is already a bugreport in progress. Returning.");
@@ -204,19 +169,17 @@
dprintf(fd, "progress:\n");
ds_->progress_->Dump(fd, " ");
dprintf(fd, "args: %s\n", ds_->options_->args.c_str());
- dprintf(fd, "extra_options: %s\n", ds_->options_->extra_options.c_str());
+ dprintf(fd, "bugreport_mode: %s\n", ds_->options_->bugreport_mode.c_str());
dprintf(fd, "version: %s\n", ds_->version_.c_str());
dprintf(fd, "bugreport_dir: %s\n", destination.c_str());
dprintf(fd, "screenshot_path: %s\n", ds_->screenshot_path_.c_str());
dprintf(fd, "log_path: %s\n", ds_->log_path_.c_str());
dprintf(fd, "tmp_path: %s\n", ds_->tmp_path_.c_str());
dprintf(fd, "path: %s\n", ds_->path_.c_str());
- dprintf(fd, "extra_options: %s\n", ds_->options_->extra_options.c_str());
dprintf(fd, "base_name: %s\n", ds_->base_name_.c_str());
dprintf(fd, "name: %s\n", ds_->name_.c_str());
dprintf(fd, "now: %ld\n", ds_->now_);
dprintf(fd, "is_zipping: %s\n", ds_->IsZipping() ? "true" : "false");
- dprintf(fd, "listener: %s\n", ds_->listener_name_.c_str());
dprintf(fd, "notification title: %s\n", ds_->options_->notification_title.c_str());
dprintf(fd, "notification description: %s\n", ds_->options_->notification_description.c_str());
diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h
index 68eda47..27954ad 100644
--- a/cmds/dumpstate/DumpstateService.h
+++ b/cmds/dumpstate/DumpstateService.h
@@ -24,7 +24,6 @@
#include <binder/BinderService.h>
#include "android/os/BnDumpstate.h"
-#include "android/os/BnDumpstateToken.h"
#include "dumpstate.h"
namespace android {
@@ -38,9 +37,6 @@
static char const* getServiceName();
status_t dump(int fd, const Vector<String16>& args) override;
- binder::Status setListener(const std::string& name, const sp<IDumpstateListener>& listener,
- bool getSectionDetails,
- sp<IDumpstateToken>* returned_token) override;
binder::Status startBugreport(int32_t calling_uid, const std::string& calling_package,
const android::base::unique_fd& bugreport_fd,
diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
index cb2d8b8..3f359c8 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
@@ -17,24 +17,12 @@
package android.os;
import android.os.IDumpstateListener;
-import android.os.IDumpstateToken;
/**
* Binder interface for the currently running dumpstate process.
* {@hide}
*/
interface IDumpstate {
- // TODO: remove method once startBugReport is used by Shell.
- /*
- * Sets the listener for this dumpstate progress.
- *
- * Returns a token used to monitor dumpstate death, or `nullptr` if the listener was already
- * set (the listener behaves like a Highlander: There Can be Only One).
- * Set {@code getSectionDetails} to true in order to receive callbacks with per section
- * progress details
- */
- IDumpstateToken setListener(@utf8InCpp String name, IDumpstateListener listener,
- boolean getSectionDetails);
// NOTE: If you add to or change these modes, please also change the corresponding enums
// in system server, in BugreportParams.java.
diff --git a/cmds/dumpstate/binder/android/os/IDumpstateToken.aidl b/cmds/dumpstate/binder/android/os/IDumpstateToken.aidl
deleted file mode 100644
index 7f74ceb..0000000
--- a/cmds/dumpstate/binder/android/os/IDumpstateToken.aidl
+++ /dev/null
@@ -1,24 +0,0 @@
-/**
- * Copyright (c) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os;
-
-/**
- * Token used by the IDumpstateListener to watch for dumpstate death.
- * {@hide}
- */
-interface IDumpstateToken {
-}
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index b87582e..5469d0c 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -231,14 +231,6 @@
return true;
}
-static bool IsFileEmpty(const std::string& file_path) {
- std::ifstream file(file_path, std::ios::binary | std::ios::ate);
- if(file.bad()) {
- MYLOGE("Cannot open file: %s\n", file_path.c_str());
- return true;
- }
- return file.tellg() <= 0;
-}
int64_t GetModuleMetadataVersion() {
auto binder = defaultServiceManager()->getService(android::String16("package_native"));
@@ -288,11 +280,8 @@
};
static const int NUM_OF_DUMPS = arraysize(kDumpstateBoardFiles);
-static constexpr char PROPERTY_EXTRA_OPTIONS[] = "dumpstate.options";
static constexpr char PROPERTY_LAST_ID[] = "dumpstate.last_id";
static constexpr char PROPERTY_VERSION[] = "dumpstate.version";
-static constexpr char PROPERTY_EXTRA_TITLE[] = "dumpstate.options.title";
-static constexpr char PROPERTY_EXTRA_DESCRIPTION[] = "dumpstate.options.description";
static const CommandOptions AS_ROOT_20 = CommandOptions::WithTimeout(20).AsRoot().Build();
@@ -696,8 +685,8 @@
RunCommandToFd(STDOUT_FILENO, "", {"uptime", "-p"},
CommandOptions::WithTimeout(1).Always().Build());
printf("Bugreport format version: %s\n", version_.c_str());
- printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s extra_options=%s\n", id_, pid_,
- PropertiesHelper::IsDryRun(), options_->args.c_str(), options_->extra_options.c_str());
+ printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s bugreport_mode=%s\n", id_, pid_,
+ PropertiesHelper::IsDryRun(), options_->args.c_str(), options_->bugreport_mode.c_str());
printf("\n");
}
@@ -960,6 +949,7 @@
}
RunCommand("LPDUMP", {"lpdump", "--all"});
+ RunCommand("DEVICE-MAPPER", {"gsid", "dump-device-mapper"});
}
static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_dir) {
@@ -1905,7 +1895,7 @@
static void ShowUsage() {
fprintf(stderr,
"usage: dumpstate [-h] [-b soundfile] [-e soundfile] [-d] [-p] "
- "[-z]] [-s] [-S] [-q] [-B] [-P] [-R] [-V version]\n"
+ "[-z]] [-s] [-S] [-q] [-P] [-R] [-V version]\n"
" -h: display this help message\n"
" -b: play sound file instead of vibrate, at beginning of job\n"
" -e: play sound file instead of vibrate, at end of job\n"
@@ -1915,11 +1905,8 @@
" -s: write output to control socket (for init)\n"
" -S: write file location to control socket (for init; requires -z)\n"
" -q: disable vibrate\n"
- " -B: send broadcast when finished\n"
- " -P: send broadcast when started and update system properties on "
- "progress (requires -B)\n"
- " -R: take bugreport in remote mode (requires -z, -d and -B, "
- "shouldn't be used with -P)\n"
+ " -P: send broadcast when started and do progress updates\n"
+ " -R: take bugreport in remote mode (requires -z and -d, shouldn't be used with -P)\n"
" -w: start binder service and make it wait for a call to startBugreport\n"
" -v: prints the dumpstate header and exit\n");
}
@@ -1976,41 +1963,6 @@
return true;
}
-static std::string SHA256_file_hash(const std::string& filepath) {
- android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK
- | O_CLOEXEC | O_NOFOLLOW)));
- if (fd == -1) {
- MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
- return nullptr;
- }
-
- SHA256_CTX ctx;
- SHA256_Init(&ctx);
-
- std::vector<uint8_t> buffer(65536);
- while (1) {
- ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), buffer.size()));
- if (bytes_read == 0) {
- break;
- } else if (bytes_read == -1) {
- MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
- return nullptr;
- }
-
- SHA256_Update(&ctx, buffer.data(), bytes_read);
- }
-
- uint8_t hash[SHA256_DIGEST_LENGTH];
- SHA256_Final(hash, &ctx);
-
- char hash_buffer[SHA256_DIGEST_LENGTH * 2 + 1];
- for(size_t i = 0; i < SHA256_DIGEST_LENGTH; i++) {
- sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
- }
- hash_buffer[sizeof(hash_buffer) - 1] = 0;
- return std::string(hash_buffer);
-}
-
static void SendBroadcast(const std::string& action, const std::vector<std::string>& args) {
// clang-format off
std::vector<std::string> am = {"/system/bin/cmd", "activity", "broadcast", "--user", "0",
@@ -2103,37 +2055,10 @@
}
/*
- * Finalizes writing to the file by renaming or zipping the tmp file to the final location,
+ * Finalizes writing to the file by zipping the tmp file to the final location,
* printing zipped file status, etc.
*/
static void FinalizeFile() {
- /* check if user changed the suffix using system properties */
- std::string name =
- android::base::GetProperty(android::base::StringPrintf("dumpstate.%d.name", ds.pid_), "");
- bool change_suffix = false;
- if (!name.empty()) {
- /* must whitelist which characters are allowed, otherwise it could cross directories */
- std::regex valid_regex("^[-_a-zA-Z0-9]+$");
- if (std::regex_match(name.c_str(), valid_regex)) {
- change_suffix = true;
- } else {
- MYLOGE("invalid suffix provided by user: %s\n", name.c_str());
- }
- }
- if (change_suffix) {
- MYLOGI("changing suffix from %s to %s\n", ds.name_.c_str(), name.c_str());
- ds.name_ = name;
- if (!ds.screenshot_path_.empty()) {
- std::string new_screenshot_path = ds.GetPath(ds.CalledByApi() ? "-tmp.png" : ".png");
- if (rename(ds.screenshot_path_.c_str(), new_screenshot_path.c_str())) {
- MYLOGE("rename(%s, %s): %s\n", ds.screenshot_path_.c_str(),
- new_screenshot_path.c_str(), strerror(errno));
- } else {
- ds.screenshot_path_ = new_screenshot_path;
- }
- }
- }
-
bool do_text_file = true;
if (ds.options_->do_zip_file) {
if (!ds.FinishZipFile()) {
@@ -2141,25 +2066,6 @@
do_text_file = true;
} else {
do_text_file = false;
- // If the user has changed the suffix, we need to change the zip file name.
- std::string new_path = ds.GetPath(ds.CalledByApi() ? "-tmp.zip" : ".zip");
- if (ds.path_ != new_path) {
- MYLOGD("Renaming zip file from %s to %s\n", ds.path_.c_str(), new_path.c_str());
- if (rename(ds.path_.c_str(), new_path.c_str())) {
- MYLOGE("rename(%s, %s): %s\n", ds.path_.c_str(), new_path.c_str(),
- strerror(errno));
- } else {
- ds.path_ = new_path;
- }
- }
- }
- }
- if (do_text_file) {
- ds.path_ = ds.GetPath(".txt");
- MYLOGD("Generating .txt bugreport at %s from %s\n", ds.path_.c_str(), ds.tmp_path_.c_str());
- if (rename(ds.tmp_path_.c_str(), ds.path_.c_str())) {
- MYLOGE("rename(%s, %s): %s\n", ds.tmp_path_.c_str(), ds.path_.c_str(), strerror(errno));
- ds.path_.clear();
}
}
if (ds.options_->use_control_socket) {
@@ -2174,49 +2080,6 @@
}
}
-/* Broadcasts that we are done with the bugreport */
-static void SendBugreportFinishedBroadcast() {
- // TODO(b/111441001): use callback instead of broadcast.
- if (!ds.path_.empty()) {
- MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
- // clang-format off
-
- std::vector<std::string> am_args = {
- "--receiver-permission", "android.permission.DUMP",
- "--ei", "android.intent.extra.ID", std::to_string(ds.id_),
- "--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
- "--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
- "--es", "android.intent.extra.BUGREPORT", ds.path_,
- "--es", "android.intent.extra.DUMPSTATE_LOG", ds.log_path_
- };
- // clang-format on
- if (ds.options_->do_fb && !android::os::IsFileEmpty(ds.screenshot_path_)) {
- am_args.push_back("--es");
- am_args.push_back("android.intent.extra.SCREENSHOT");
- am_args.push_back(ds.screenshot_path_);
- }
- if (!ds.options_->notification_title.empty()) {
- am_args.push_back("--es");
- am_args.push_back("android.intent.extra.TITLE");
- am_args.push_back(ds.options_->notification_title);
- if (!ds.options_->notification_description.empty()) {
- am_args.push_back("--es");
- am_args.push_back("android.intent.extra.DESCRIPTION");
- am_args.push_back(ds.options_->notification_description);
- }
- }
- if (ds.options_->is_remote_mode) {
- am_args.push_back("--es");
- am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
- am_args.push_back(SHA256_file_hash(ds.path_));
- SendBroadcast("com.android.internal.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
- } else {
- SendBroadcast("com.android.internal.intent.action.BUGREPORT_FINISHED", am_args);
- }
- } else {
- MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
- }
-}
static inline const char* ModeToString(Dumpstate::BugreportMode mode) {
switch (mode) {
@@ -2238,10 +2101,9 @@
}
static void SetOptionsFromMode(Dumpstate::BugreportMode mode, Dumpstate::DumpOptions* options) {
- options->extra_options = ModeToString(mode);
+ options->bugreport_mode = ModeToString(mode);
switch (mode) {
case Dumpstate::BugreportMode::BUGREPORT_FULL:
- options->do_broadcast = true;
options->do_fb = true;
break;
case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
@@ -2249,88 +2111,32 @@
options->do_start_service = true;
options->do_progress_updates = true;
options->do_fb = false;
- options->do_broadcast = true;
break;
case Dumpstate::BugreportMode::BUGREPORT_REMOTE:
options->do_vibrate = false;
options->is_remote_mode = true;
options->do_fb = false;
- options->do_broadcast = true;
break;
case Dumpstate::BugreportMode::BUGREPORT_WEAR:
options->do_start_service = true;
options->do_progress_updates = true;
options->do_zip_file = true;
options->do_fb = true;
- options->do_broadcast = true;
break;
case Dumpstate::BugreportMode::BUGREPORT_TELEPHONY:
options->telephony_only = true;
options->do_fb = false;
- options->do_broadcast = true;
break;
case Dumpstate::BugreportMode::BUGREPORT_WIFI:
options->wifi_only = true;
options->do_zip_file = true;
options->do_fb = false;
- options->do_broadcast = true;
break;
case Dumpstate::BugreportMode::BUGREPORT_DEFAULT:
break;
}
}
-static Dumpstate::BugreportMode getBugreportModeFromProperty() {
- // If the system property is not set, it's assumed to be a default bugreport.
- Dumpstate::BugreportMode mode = Dumpstate::BugreportMode::BUGREPORT_DEFAULT;
-
- std::string extra_options = android::base::GetProperty(PROPERTY_EXTRA_OPTIONS, "");
- if (!extra_options.empty()) {
- // Framework uses a system property to override some command-line args.
- // Currently, it contains the type of the requested bugreport.
- if (extra_options == "bugreportplus") {
- mode = Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE;
- } else if (extra_options == "bugreportfull") {
- mode = Dumpstate::BugreportMode::BUGREPORT_FULL;
- } else if (extra_options == "bugreportremote") {
- mode = Dumpstate::BugreportMode::BUGREPORT_REMOTE;
- } else if (extra_options == "bugreportwear") {
- mode = Dumpstate::BugreportMode::BUGREPORT_WEAR;
- } else if (extra_options == "bugreporttelephony") {
- mode = Dumpstate::BugreportMode::BUGREPORT_TELEPHONY;
- } else if (extra_options == "bugreportwifi") {
- mode = Dumpstate::BugreportMode::BUGREPORT_WIFI;
- } else {
- MYLOGE("Unknown extra option: %s\n", extra_options.c_str());
- }
- // Reset the property
- android::base::SetProperty(PROPERTY_EXTRA_OPTIONS, "");
- }
- return mode;
-}
-
-// TODO: Move away from system properties when we have options passed via binder calls.
-/* Sets runtime options from the system properties and then clears those properties. */
-static void SetOptionsFromProperties(Dumpstate::DumpOptions* options) {
- Dumpstate::BugreportMode mode = getBugreportModeFromProperty();
- SetOptionsFromMode(mode, options);
-
- options->notification_title = android::base::GetProperty(PROPERTY_EXTRA_TITLE, "");
- if (!options->notification_title.empty()) {
- // Reset the property
- android::base::SetProperty(PROPERTY_EXTRA_TITLE, "");
-
- options->notification_description =
- android::base::GetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
- if (!options->notification_description.empty()) {
- // Reset the property
- android::base::SetProperty(PROPERTY_EXTRA_DESCRIPTION, "");
- }
- MYLOGD("notification (title: %s, description: %s)\n", options->notification_title.c_str(),
- options->notification_description.c_str());
- }
-}
-
static void LogDumpOptions(const Dumpstate::DumpOptions& options) {
MYLOGI("do_zip_file: %d\n", options.do_zip_file);
MYLOGI("do_add_date: %d\n", options.do_add_date);
@@ -2338,7 +2144,6 @@
MYLOGI("use_socket: %d\n", options.use_socket);
MYLOGI("use_control_socket: %d\n", options.use_control_socket);
MYLOGI("do_fb: %d\n", options.do_fb);
- MYLOGI("do_broadcast: %d\n", options.do_broadcast);
MYLOGI("is_remote_mode: %d\n", options.is_remote_mode);
MYLOGI("show_header_only: %d\n", options.show_header_only);
MYLOGI("do_start_service: %d\n", options.do_start_service);
@@ -2346,10 +2151,8 @@
MYLOGI("wifi_only: %d\n", options.wifi_only);
MYLOGI("do_progress_updates: %d\n", options.do_progress_updates);
MYLOGI("fd: %d\n", options.bugreport_fd.get());
- MYLOGI("extra_options: %s\n", options.extra_options.c_str());
+ MYLOGI("bugreport_mode: %s\n", options.bugreport_mode.c_str());
MYLOGI("args: %s\n", options.args.c_str());
- MYLOGI("notification_title: %s\n", options.notification_title.c_str());
- MYLOGI("notification_description: %s\n", options.notification_description.c_str());
}
void Dumpstate::DumpOptions::Initialize(BugreportMode bugreport_mode,
@@ -2364,7 +2167,6 @@
bugreport_fd.reset(dup(bugreport_fd_in.get()));
screenshot_fd.reset(dup(screenshot_fd_in.get()));
- extra_options = ModeToString(bugreport_mode);
SetOptionsFromMode(bugreport_mode, this);
}
@@ -2383,7 +2185,6 @@
case 'p': do_fb = true; break;
case 'P': do_progress_updates = true; break;
case 'R': is_remote_mode = true; break;
- case 'B': do_broadcast = true; break;
case 'V': break; // compatibility no-op
case 'w':
// This was already processed
@@ -2409,7 +2210,6 @@
// Reset next index used by getopt so this can be called multiple times, for eg, in tests.
optind = 1;
- SetOptionsFromProperties(this);
return status;
}
@@ -2418,7 +2218,7 @@
return false;
}
- if ((do_zip_file || do_add_date || do_progress_updates || do_broadcast) && !OutputToFile()) {
+ if ((do_zip_file || do_add_date || do_progress_updates) && !OutputToFile()) {
return false;
}
@@ -2426,11 +2226,7 @@
return false;
}
- if (do_progress_updates && !do_broadcast) {
- return false;
- }
-
- if (is_remote_mode && (do_progress_updates || !do_broadcast || !do_zip_file || !do_add_date)) {
+ if (is_remote_mode && (do_progress_updates || !do_zip_file || !do_add_date)) {
return false;
}
return true;
@@ -2528,7 +2324,7 @@
MYLOGD("dumpstate calling_uid = %d ; calling package = %s \n",
calling_uid, calling_package.c_str());
- if (options_->bugreport_fd.get() != -1) {
+ if (CalledByApi()) {
// If the output needs to be copied over to the caller's fd, get user consent.
android::String16 package(calling_package.c_str());
CheckUserConsent(calling_uid, package);
@@ -2573,8 +2369,8 @@
MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
}
- MYLOGI("dumpstate info: id=%d, args='%s', extra_options= %s)\n", id_, options_->args.c_str(),
- options_->extra_options.c_str());
+ MYLOGI("dumpstate info: id=%d, args='%s', bugreport_mode= %s)\n", id_, options_->args.c_str(),
+ options_->bugreport_mode.c_str());
MYLOGI("bugreport format version: %s\n", version_.c_str());
@@ -2601,18 +2397,13 @@
PrepareToWriteToFile();
if (options_->do_progress_updates) {
- if (options_->do_broadcast) {
- // clang-format off
- std::vector<std::string> am_args = {
- "--receiver-permission", "android.permission.DUMP",
- "--es", "android.intent.extra.NAME", name_,
- "--ei", "android.intent.extra.ID", std::to_string(id_),
- "--ei", "android.intent.extra.PID", std::to_string(pid_),
- "--ei", "android.intent.extra.MAX", std::to_string(progress_->GetMax()),
- };
- // clang-format on
- SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
- }
+ // clang-format off
+ std::vector<std::string> am_args = {
+ "--receiver-permission", "android.permission.DUMP",
+ };
+ // clang-format on
+ // Send STARTED broadcast for apps that listen to bugreport generation events
+ SendBroadcast("com.android.internal.intent.action.BUGREPORT_STARTED", am_args);
if (options_->use_control_socket) {
dprintf(control_socket_fd_, "BEGIN:%s\n", path_.c_str());
}
@@ -2700,14 +2491,14 @@
TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
}
- // Rename, and/or zip the (now complete) .tmp file within the internal directory.
+ // Zip the (now complete) .tmp file within the internal directory.
if (options_->OutputToFile()) {
FinalizeFile();
}
// Share the final file with the caller if the user has consented or Shell is the caller.
Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
- if (options_->bugreport_fd.get() != -1) {
+ if (CalledByApi()) {
status = CopyBugreportIfUserConsented(calling_uid);
if (status != Dumpstate::RunStatus::OK &&
status != Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT) {
@@ -2748,12 +2539,6 @@
}
}
- /* tell activity manager we're done */
- if (options_->do_broadcast && !CalledByApi()) {
- SendBugreportFinishedBroadcast();
- // Note that listener_ is notified in Run();
- }
-
MYLOGD("Final progress: %d/%d (estimated %d)\n", progress_->Get(), progress_->GetMax(),
progress_->GetInitialMax());
progress_->Save();
@@ -3686,13 +3471,11 @@
if (listener_ != nullptr) {
if (percent % 5 == 0) {
// We don't want to spam logcat, so only log multiples of 5.
- MYLOGD("Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(), progress, max,
- percent);
+ MYLOGD("Setting progress: %d/%d (%d%%)\n", progress, max, percent);
} else {
// stderr is ignored on normal invocations, but useful when calling
// /system/bin/dumpstate directly for debuggging.
- fprintf(stderr, "Setting progress (%s): %d/%d (%d%%)\n", listener_name_.c_str(),
- progress, max, percent);
+ fprintf(stderr, "Setting progress: %d/%d (%d%%)\n", progress, max, percent);
}
listener_->onProgress(percent);
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 430936e..831574d 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -359,7 +359,6 @@
bool use_socket = false;
bool use_control_socket = false;
bool do_fb = false;
- bool do_broadcast = false;
bool is_remote_mode = false;
bool show_header_only = false;
bool do_start_service = false;
@@ -371,16 +370,15 @@
android::base::unique_fd bugreport_fd;
// File descriptor to screenshot file.
android::base::unique_fd screenshot_fd;
- // TODO: rename to MODE.
- // Extra options passed as system property.
- std::string extra_options;
+ // Bugreport mode of the bugreport.
+ std::string bugreport_mode;
// Command-line arguments as string
std::string args;
// Notification title and description
std::string notification_title;
std::string notification_description;
- /* Initializes options from commandline arguments and system properties. */
+ /* Initializes options from commandline arguments. */
RunStatus Initialize(int argc, char* argv[]);
/* Initializes options from the requested mode. */
@@ -456,8 +454,6 @@
// Binder object listening to progress.
android::sp<android::os::IDumpstateListener> listener_;
- std::string listener_name_;
- bool report_section_;
// List of open tombstone dump files.
std::vector<DumpData> tombstone_data_;
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index fbb01f5..f1884f8 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -195,7 +195,6 @@
static Dumpstate& ds;
static std::chrono::milliseconds duration;
static void SetUpTestCase() {
- property_set("dumpstate.options", "bugreportplus");
// clang-format off
char* argv[] = {
(char*)"dumpstate",
@@ -206,8 +205,6 @@
// clang-format on
sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout)), sections));
ds.listener_ = listener;
- ds.listener_name_ = "Smokey";
- ds.report_section_ = true;
auto start = std::chrono::steady_clock::now();
ds.ParseCommandlineAndRun(ARRAY_SIZE(argv), argv);
auto end = std::chrono::steady_clock::now();
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index cff1d43..1ae073c 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -37,6 +37,7 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <cutils/properties.h>
+#include <android-base/unique_fd.h>
namespace android {
namespace os {
@@ -148,10 +149,9 @@
options_ = Dumpstate::DumpOptions();
}
void TearDown() {
- // Reset the property
- property_set("dumpstate.options", "");
}
Dumpstate::DumpOptions options_;
+ android::base::unique_fd fd;
};
TEST_F(DumpOptionsTest, InitializeNone) {
@@ -174,7 +174,6 @@
EXPECT_FALSE(options_.do_fb);
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
- EXPECT_FALSE(options_.do_broadcast);
}
TEST_F(DumpOptionsTest, InitializeAdbBugreport) {
@@ -200,7 +199,6 @@
EXPECT_FALSE(options_.do_fb);
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
- EXPECT_FALSE(options_.do_broadcast);
EXPECT_FALSE(options_.use_socket);
}
@@ -226,28 +224,13 @@
EXPECT_FALSE(options_.do_fb);
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
- EXPECT_FALSE(options_.do_broadcast);
}
TEST_F(DumpOptionsTest, InitializeFullBugReport) {
- // clang-format off
- char* argv[] = {
- const_cast<char*>("bugreport"),
- const_cast<char*>("-d"),
- const_cast<char*>("-p"),
- const_cast<char*>("-B"),
- const_cast<char*>("-z"),
- };
- // clang-format on
- property_set("dumpstate.options", "bugreportfull");
-
- Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
-
- EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+ options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_FULL, fd, fd);
EXPECT_TRUE(options_.do_add_date);
EXPECT_TRUE(options_.do_fb);
EXPECT_TRUE(options_.do_zip_file);
- EXPECT_TRUE(options_.do_broadcast);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -260,23 +243,8 @@
}
TEST_F(DumpOptionsTest, InitializeInteractiveBugReport) {
- // clang-format off
- char* argv[] = {
- const_cast<char*>("bugreport"),
- const_cast<char*>("-d"),
- const_cast<char*>("-p"),
- const_cast<char*>("-B"),
- const_cast<char*>("-z"),
- };
- // clang-format on
-
- property_set("dumpstate.options", "bugreportplus");
-
- Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
-
- EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+ options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE, fd, fd);
EXPECT_TRUE(options_.do_add_date);
- EXPECT_TRUE(options_.do_broadcast);
EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.do_progress_updates);
EXPECT_TRUE(options_.do_start_service);
@@ -291,23 +259,8 @@
}
TEST_F(DumpOptionsTest, InitializeRemoteBugReport) {
- // clang-format off
- char* argv[] = {
- const_cast<char*>("bugreport"),
- const_cast<char*>("-d"),
- const_cast<char*>("-p"),
- const_cast<char*>("-B"),
- const_cast<char*>("-z"),
- };
- // clang-format on
-
- property_set("dumpstate.options", "bugreportremote");
-
- Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
-
- EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+ options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_REMOTE, fd, fd);
EXPECT_TRUE(options_.do_add_date);
- EXPECT_TRUE(options_.do_broadcast);
EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.is_remote_mode);
EXPECT_FALSE(options_.do_vibrate);
@@ -321,24 +274,9 @@
}
TEST_F(DumpOptionsTest, InitializeWearBugReport) {
- // clang-format off
- char* argv[] = {
- const_cast<char*>("bugreport"),
- const_cast<char*>("-d"),
- const_cast<char*>("-p"),
- const_cast<char*>("-B"),
- const_cast<char*>("-z"),
- };
- // clang-format on
-
- property_set("dumpstate.options", "bugreportwear");
-
- Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
-
- EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+ options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WEAR, fd, fd);
EXPECT_TRUE(options_.do_add_date);
EXPECT_TRUE(options_.do_fb);
- EXPECT_TRUE(options_.do_broadcast);
EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.do_progress_updates);
EXPECT_TRUE(options_.do_start_service);
@@ -352,24 +290,9 @@
}
TEST_F(DumpOptionsTest, InitializeTelephonyBugReport) {
- // clang-format off
- char* argv[] = {
- const_cast<char*>("bugreport"),
- const_cast<char*>("-d"),
- const_cast<char*>("-p"),
- const_cast<char*>("-B"),
- const_cast<char*>("-z"),
- };
- // clang-format on
-
- property_set("dumpstate.options", "bugreporttelephony");
-
- Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
-
- EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+ options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_TELEPHONY, fd, fd);
EXPECT_TRUE(options_.do_add_date);
EXPECT_FALSE(options_.do_fb);
- EXPECT_TRUE(options_.do_broadcast);
EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.telephony_only);
@@ -383,24 +306,9 @@
}
TEST_F(DumpOptionsTest, InitializeWifiBugReport) {
- // clang-format off
- char* argv[] = {
- const_cast<char*>("bugreport"),
- const_cast<char*>("-d"),
- const_cast<char*>("-p"),
- const_cast<char*>("-B"),
- const_cast<char*>("-z"),
- };
- // clang-format on
-
- property_set("dumpstate.options", "bugreportwifi");
-
- Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
-
- EXPECT_EQ(status, Dumpstate::RunStatus::OK);
+ options_.Initialize(Dumpstate::BugreportMode::BUGREPORT_WIFI, fd, fd);
EXPECT_TRUE(options_.do_add_date);
EXPECT_FALSE(options_.do_fb);
- EXPECT_TRUE(options_.do_broadcast);
EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.wifi_only);
@@ -420,20 +328,15 @@
const_cast<char*>("bugreport"),
const_cast<char*>("-d"),
const_cast<char*>("-p"),
- const_cast<char*>("-B"),
const_cast<char*>("-z"),
};
// clang-format on
-
- property_set("dumpstate.options", "");
-
Dumpstate::RunStatus status = options_.Initialize(ARRAY_SIZE(argv), argv);
EXPECT_EQ(status, Dumpstate::RunStatus::OK);
EXPECT_TRUE(options_.do_add_date);
EXPECT_TRUE(options_.do_fb);
EXPECT_TRUE(options_.do_zip_file);
- EXPECT_TRUE(options_.do_broadcast);
// Other options retain default values
EXPECT_TRUE(options_.do_vibrate);
@@ -472,7 +375,6 @@
EXPECT_FALSE(options_.do_fb);
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
- EXPECT_FALSE(options_.do_broadcast);
}
TEST_F(DumpOptionsTest, InitializePartial2) {
@@ -484,7 +386,6 @@
const_cast<char*>("-p"),
const_cast<char*>("-P"),
const_cast<char*>("-R"),
- const_cast<char*>("-B"),
};
// clang-format on
@@ -496,7 +397,6 @@
EXPECT_TRUE(options_.do_fb);
EXPECT_TRUE(options_.do_progress_updates);
EXPECT_TRUE(options_.is_remote_mode);
- EXPECT_TRUE(options_.do_broadcast);
// Other options retain default values
EXPECT_FALSE(options_.do_add_date);
@@ -544,7 +444,7 @@
}
TEST_F(DumpOptionsTest, ValidateOptionsNeedOutfile2) {
- options_.do_broadcast = true;
+ options_.do_progress_updates = true;
// Writing to socket = !writing to file.
options_.use_socket = true;
EXPECT_FALSE(options_.ValidateOptions());
@@ -561,19 +461,10 @@
EXPECT_TRUE(options_.ValidateOptions());
}
-TEST_F(DumpOptionsTest, ValidateOptionsUpdateProgressNeedsBroadcast) {
- options_.do_progress_updates = true;
- EXPECT_FALSE(options_.ValidateOptions());
-
- options_.do_broadcast = true;
- EXPECT_TRUE(options_.ValidateOptions());
-}
-
TEST_F(DumpOptionsTest, ValidateOptionsRemoteMode) {
options_.is_remote_mode = true;
EXPECT_FALSE(options_.ValidateOptions());
- options_.do_broadcast = true;
options_.do_zip_file = true;
options_.do_add_date = true;
EXPECT_TRUE(options_.ValidateOptions());
@@ -616,8 +507,8 @@
ds.progress_.reset(new Progress(initial_max, progress, 1.2));
}
- std::string GetProgressMessage(const std::string& listener_name, int progress, int max,
- int old_max = 0, bool update_progress = true) {
+ std::string GetProgressMessage(int progress, int max,
+ int old_max = 0, bool update_progress = true) {
EXPECT_EQ(progress, ds.progress_->Get()) << "invalid progress";
EXPECT_EQ(max, ds.progress_->GetMax()) << "invalid max";
@@ -630,9 +521,8 @@
}
if (update_progress) {
- message += android::base::StringPrintf("Setting progress (%s): %d/%d (%d%%)\n",
- listener_name.c_str(), progress, max,
- (100 * progress / max));
+ message += android::base::StringPrintf("Setting progress: %d/%d (%d%%)\n",
+ progress, max, (100 * progress / max));
}
return message;
@@ -787,18 +677,17 @@
TEST_F(DumpstateTest, RunCommandProgress) {
sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
ds.listener_ = listener;
- ds.listener_name_ = "FoxMulder";
SetProgress(0, 30);
EXPECT_CALL(*listener, onProgress(66)); // 20/30 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(20).Build()));
- std::string progress_message = GetProgressMessage(ds.listener_name_, 20, 30);
+ std::string progress_message = GetProgressMessage(20, 30);
EXPECT_THAT(out, StrEq("stdout\n"));
EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
EXPECT_CALL(*listener, onProgress(80)); // 24/30 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(4).Build()));
- progress_message = GetProgressMessage(ds.listener_name_, 24, 30);
+ progress_message = GetProgressMessage(24, 30);
EXPECT_THAT(out, StrEq("stdout\n"));
EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
@@ -806,20 +695,20 @@
SetDryRun(true);
EXPECT_CALL(*listener, onProgress(90)); // 27/30 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(3).Build()));
- progress_message = GetProgressMessage(ds.listener_name_, 27, 30);
+ progress_message = GetProgressMessage(27, 30);
EXPECT_THAT(out, IsEmpty());
EXPECT_THAT(err, StrEq(progress_message));
SetDryRun(false);
EXPECT_CALL(*listener, onProgress(96)); // 29/30 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(2).Build()));
- progress_message = GetProgressMessage(ds.listener_name_, 29, 30);
+ progress_message = GetProgressMessage(29, 30);
EXPECT_THAT(out, StrEq("stdout\n"));
EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
EXPECT_CALL(*listener, onProgress(100)); // 30/30 %
EXPECT_EQ(0, RunCommand("", {kSimpleCommand}, CommandOptions::WithTimeout(1).Build()));
- progress_message = GetProgressMessage(ds.listener_name_, 30, 30);
+ progress_message = GetProgressMessage(30, 30);
EXPECT_THAT(out, StrEq("stdout\n"));
EXPECT_THAT(err, StrEq("stderr\n" + progress_message));
@@ -1044,14 +933,12 @@
TEST_F(DumpstateTest, DumpFileUpdateProgress) {
sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
ds.listener_ = listener;
- ds.listener_name_ = "FoxMulder";
SetProgress(0, 30);
EXPECT_CALL(*listener, onProgress(16)); // 5/30 %
EXPECT_EQ(0, DumpFile("", kTestDataPath + "single-line.txt"));
- std::string progress_message =
- GetProgressMessage(ds.listener_name_, 5, 30); // TODO: unhardcode WEIGHT_FILE (5)?
+ std::string progress_message = GetProgressMessage(5, 30); // TODO: unhardcode WEIGHT_FILE (5)?
EXPECT_THAT(err, StrEq(progress_message));
EXPECT_THAT(out, StrEq("I AM LINE1\n")); // dumpstate adds missing newline
@@ -1063,48 +950,6 @@
DumpstateService dss;
};
-TEST_F(DumpstateServiceTest, SetListenerNoName) {
- sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
- sp<IDumpstateToken> token;
- EXPECT_TRUE(dss.setListener("", listener, /* getSectionDetails = */ false, &token).isOk());
- ASSERT_THAT(token, IsNull());
-}
-
-TEST_F(DumpstateServiceTest, SetListenerNoPointer) {
- sp<IDumpstateToken> token;
- EXPECT_TRUE(
- dss.setListener("whatever", nullptr, /* getSectionDetails = */ false, &token).isOk());
- ASSERT_THAT(token, IsNull());
-}
-
-TEST_F(DumpstateServiceTest, SetListenerTwice) {
- sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
- sp<IDumpstateToken> token;
- EXPECT_TRUE(
- dss.setListener("whatever", listener, /* getSectionDetails = */ false, &token).isOk());
- ASSERT_THAT(token, NotNull());
- EXPECT_THAT(Dumpstate::GetInstance().listener_name_, StrEq("whatever"));
- EXPECT_FALSE(Dumpstate::GetInstance().report_section_);
-
- token.clear();
- EXPECT_TRUE(
- dss.setListener("whatsoever", listener, /* getSectionDetails = */ false, &token).isOk());
- ASSERT_THAT(token, IsNull());
- EXPECT_THAT(Dumpstate::GetInstance().listener_name_, StrEq("whatever"));
- EXPECT_FALSE(Dumpstate::GetInstance().report_section_);
-}
-
-TEST_F(DumpstateServiceTest, SetListenerWithSectionDetails) {
- sp<DumpstateListenerMock> listener(new DumpstateListenerMock());
- sp<IDumpstateToken> token;
- Dumpstate::GetInstance().listener_ = nullptr;
- EXPECT_TRUE(
- dss.setListener("whatever", listener, /* getSectionDetails = */ true, &token).isOk());
- ASSERT_THAT(token, NotNull());
- EXPECT_THAT(Dumpstate::GetInstance().listener_name_, StrEq("whatever"));
- EXPECT_TRUE(Dumpstate::GetInstance().report_section_);
-}
-
class ProgressTest : public DumpstateBaseTest {
public:
Progress GetInstance(int32_t max, double growth_factor, const std::string& path = "") {
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index cf4e0b5..b9395ba 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -54,6 +54,7 @@
MOCK_METHOD4(addService, status_t(const String16&, const sp<IBinder>&, bool, int));
MOCK_METHOD1(listServices, Vector<String16>(int));
MOCK_METHOD1(waitForService, sp<IBinder>(const String16&));
+ MOCK_METHOD1(isDeclared, bool(const String16&));
protected:
MOCK_METHOD0(onAsBinder, IBinder*());
};
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 9344368..91e89ae 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -34,11 +34,7 @@
namespace android {
#ifndef VENDORSERVICEMANAGER
-static bool meetsDeclarationRequirements(const sp<IBinder>& binder, const std::string& name) {
- if (!Stability::requiresVintfDeclaration(binder)) {
- return true;
- }
-
+static bool isVintfDeclared(const std::string& name) {
size_t firstSlash = name.find('/');
size_t lastDot = name.rfind('.', firstSlash);
if (firstSlash == std::string::npos || lastDot == std::string::npos) {
@@ -62,6 +58,14 @@
<< " in the VINTF manifest.";
return false;
}
+
+static bool meetsDeclarationRequirements(const sp<IBinder>& binder, const std::string& name) {
+ if (!Stability::requiresVintfDeclaration(binder)) {
+ return true;
+ }
+
+ return isVintfDeclared(name);
+}
#endif // !VENDORSERVICEMANAGER
ServiceManager::ServiceManager(std::unique_ptr<Access>&& access) : mAccess(std::move(access)) {}
@@ -165,7 +169,7 @@
#endif // !VENDORSERVICEMANAGER
// implicitly unlinked when the binder is removed
- if (OK != binder->linkToDeath(this)) {
+ if (binder->remoteBinder() != nullptr && binder->linkToDeath(this) != OK) {
LOG(ERROR) << "Could not linkToDeath when adding " << name;
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
@@ -270,6 +274,21 @@
return Status::ok();
}
+Status ServiceManager::isDeclared(const std::string& name, bool* outReturn) {
+ auto ctx = mAccess->getCallingContext();
+
+ if (!mAccess->canFind(ctx, name)) {
+ return Status::fromExceptionCode(Status::EX_SECURITY);
+ }
+
+ *outReturn = false;
+
+#ifndef VENDORSERVICEMANAGER
+ *outReturn = isVintfDeclared(name);
+#endif
+ return Status::ok();
+}
+
void ServiceManager::removeCallback(const wp<IBinder>& who,
CallbackMap::iterator* it,
bool* found) {
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index 006e519..7dcdaa4 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -40,6 +40,7 @@
const sp<IServiceCallback>& callback) override;
binder::Status unregisterForNotifications(const std::string& name,
const sp<IServiceCallback>& callback) override;
+ binder::Status isDeclared(const std::string& name, bool* outReturn) override;
void binderDied(const wp<IBinder>& who) override;
diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp
index 11d43a6..4b12fc6 100644
--- a/cmds/servicemanager/main.cpp
+++ b/cmds/servicemanager/main.cpp
@@ -23,11 +23,12 @@
#include "Access.h"
#include "ServiceManager.h"
-using ::android::sp;
-using ::android::ProcessState;
-using ::android::IPCThreadState;
-using ::android::ServiceManager;
using ::android::Access;
+using ::android::IPCThreadState;
+using ::android::ProcessState;
+using ::android::ServiceManager;
+using ::android::os::IServiceManager;
+using ::android::sp;
int main(int argc, char** argv) {
if (argc > 2) {
@@ -41,6 +42,10 @@
ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);
sp<ServiceManager> manager = new ServiceManager(std::make_unique<Access>());
+ if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) {
+ LOG(ERROR) << "Could not self register servicemanager";
+ }
+
IPCThreadState::self()->setTheContextObject(manager);
ps->becomeContextManager(nullptr, nullptr);
diff --git a/headers/media_plugin/media/cas/CasAPI.h b/headers/media_plugin/media/cas/CasAPI.h
index c87ee56..8cc9d36 100644
--- a/headers/media_plugin/media/cas/CasAPI.h
+++ b/headers/media_plugin/media/cas/CasAPI.h
@@ -56,6 +56,11 @@
size_t size,
const CasSessionId *sessionId);
+typedef void (*CasPluginStatusCallback)(
+ void *appData,
+ int32_t event,
+ int32_t arg);
+
struct CasFactory {
CasFactory() {}
virtual ~CasFactory() {}
@@ -91,6 +96,10 @@
CasPlugin() {}
virtual ~CasPlugin() {}
+ // Provide a callback to report plugin status
+ virtual status_t setStatusCallback(
+ CasPluginStatusCallback callback) = 0;
+
// Provide the CA private data from a CA_descriptor in the conditional
// access table to a CasPlugin.
virtual status_t setPrivateData(
@@ -100,6 +109,11 @@
// streams.
virtual status_t openSession(CasSessionId *sessionId) = 0;
+ // Open a session with intend and mode for descrambling a program, or one
+ // or more elementary streams.
+ virtual status_t openSession(uint32_t intent, uint32_t mode,
+ CasSessionId *sessionId) = 0;
+
// Close a previously opened session.
virtual status_t closeSession(const CasSessionId &sessionId) = 0;
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index c056c97..1822e4a 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -60,14 +60,14 @@
* in StructLayout_test should be made.
*/
struct InputMessage {
- enum {
- TYPE_KEY = 1,
- TYPE_MOTION = 2,
- TYPE_FINISHED = 3,
+ enum class Type : uint32_t {
+ KEY,
+ MOTION,
+ FINISHED,
};
struct Header {
- uint32_t type;
+ Type type; // 4 bytes
// We don't need this field in order to align the body below but we
// leave it here because InputMessage::size() and other functions
// compute the size of this structure as sizeof(Header) + sizeof(Body).
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 643a956..7ee4882 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -73,6 +73,7 @@
// or dessert updates. Instead, apex users should use libbinder_ndk.
apex_available: [
"//apex_available:platform",
+ "com.android.vndk.current",
// TODO(b/139016109) remove these three
"com.android.media.swcodec",
"test_com.android.media.swcodec",
@@ -164,3 +165,16 @@
],
path: "aidl",
}
+
+aidl_interface {
+ name: "libbinder_aidl_test_stub",
+ local_include_dir: "aidl",
+ srcs: [":libbinder_aidl"],
+ visibility: [":__subpackages__"],
+ vendor_available: true,
+ backend: {
+ java: {
+ enabled: false,
+ },
+ },
+}
diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp
index 9da9c13..60f047f 100644
--- a/libs/binder/AppOpsManager.cpp
+++ b/libs/binder/AppOpsManager.cpp
@@ -115,18 +115,23 @@
}
int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage) {
- return noteOp(op, uid, callingPackage, String16("noteOp from native code"));
+ return noteOp(op, uid, callingPackage, String16(), String16());
}
int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage,
- const String16& message) {
+ const String16& featureId, const String16& message) {
sp<IAppOpsService> service = getService();
int32_t mode = service != nullptr
? service->noteOperation(op, uid, callingPackage)
: APP_OPS_MANAGER_UNAVAILABLE_MODE;
if (mode == AppOpsManager::MODE_ALLOWED) {
- markAppOpNoted(uid, callingPackage, op, message);
+ if (message.size() == 0) {
+ markAppOpNoted(uid, callingPackage, op, featureId,
+ String16("noteOp from native code"));
+ } else {
+ markAppOpNoted(uid, callingPackage, op, featureId, message);
+ }
}
return mode;
@@ -134,19 +139,23 @@
int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
bool startIfModeDefault) {
- return startOpNoThrow(op, uid, callingPackage, startIfModeDefault,
- String16("startOpNoThrow from native code"));
+ return startOpNoThrow(op, uid, callingPackage, startIfModeDefault, String16(), String16());
}
int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
- bool startIfModeDefault, const String16& message) {
+ bool startIfModeDefault, const String16& featureId, const String16& message) {
sp<IAppOpsService> service = getService();
int32_t mode = service != nullptr
? service->startOperation(getToken(service), op, uid, callingPackage,
startIfModeDefault) : APP_OPS_MANAGER_UNAVAILABLE_MODE;
if (mode == AppOpsManager::MODE_ALLOWED) {
- markAppOpNoted(uid, callingPackage, op, message);
+ if (message.size() == 0) {
+ markAppOpNoted(uid, callingPackage, op, featureId,
+ String16("startOp from native code"));
+ } else {
+ markAppOpNoted(uid, callingPackage, op, featureId, message);
+ }
}
return mode;
@@ -198,7 +207,7 @@
}
void AppOpsManager::markAppOpNoted(int32_t uid, const String16& packageName, int32_t opCode,
- const String16& message) {
+ const String16& featureId, const String16& message) {
// check it the appops needs to be collected and cache result
if (appOpsToNote[opCode] == 0) {
if (shouldCollectNotes(opCode)) {
@@ -212,14 +221,16 @@
return;
}
- noteAsyncOp(String16(), uid, packageName, opCode, message);
+ noteAsyncOp(String16(), uid, packageName, opCode, featureId, message);
}
void AppOpsManager::noteAsyncOp(const String16& callingPackageName, int32_t uid,
- const String16& packageName, int32_t opCode, const String16& message) {
+ const String16& packageName, int32_t opCode, const String16& featureId,
+ const String16& message) {
sp<IAppOpsService> service = getService();
if (service != nullptr) {
- return service->noteAsyncOp(callingPackageName, uid, packageName, opCode, message);
+ return service->noteAsyncOp(callingPackageName, uid, packageName, opCode, featureId,
+ message);
}
}
diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp
index 6c16c2d..9760e13 100644
--- a/libs/binder/IAppOpsService.cpp
+++ b/libs/binder/IAppOpsService.cpp
@@ -145,7 +145,8 @@
}
virtual void noteAsyncOp(const String16& callingPackageName, int32_t uid,
- const String16& packageName, int32_t opCode, const String16& message) {
+ const String16& packageName, int32_t opCode, const String16& featureId,
+ const String16& message) {
Parcel data, reply;
data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
@@ -166,6 +167,14 @@
}
data.writeInt32(opCode);
+
+ // Convert empty featureId into null string
+ if (featureId.size() != 0) {
+ data.writeString16(featureId);
+ } else {
+ data.writeString16(nullptr, 0);
+ }
+
data.writeString16(message);
remote()->transact(NOTE_ASYNC_OP_TRANSACTION, data, &reply);
}
@@ -291,8 +300,9 @@
int32_t uid = data.readInt32();
String16 packageName = data.readString16();
int32_t opCode = data.readInt32();
+ String16 featureId = data.readString16();
String16 message = data.readString16();
- noteAsyncOp(callingPackageName, uid, packageName, opCode, message);
+ noteAsyncOp(callingPackageName, uid, packageName, opCode, featureId, message);
reply->writeNoException();
return NO_ERROR;
} break;
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index a30df14..4f47db1 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -72,6 +72,7 @@
bool allowIsolated, int dumpsysPriority) override;
Vector<String16> listServices(int dumpsysPriority) override;
sp<IBinder> waitForService(const String16& name16) override;
+ bool isDeclared(const String16& name) override;
// for legacy ABI
const String16& getInterfaceDescriptor() const override {
@@ -321,4 +322,12 @@
}
}
+bool ServiceManagerShim::isDeclared(const String16& name) {
+ bool declared;
+ if (!mTheRealServiceManager->isDeclared(String8(name).c_str(), &declared).isOk()) {
+ return false;
+ }
+ return declared;
+}
+
} // namespace android
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index b70e57d..7219b47 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -505,7 +505,7 @@
}
}
-#if defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#if defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__))
constexpr int32_t kHeader = B_PACK_CHARS('V', 'N', 'D', 'R');
#else
constexpr int32_t kHeader = B_PACK_CHARS('S', 'Y', 'S', 'T');
@@ -2562,11 +2562,13 @@
if (objectsSize == 0) {
free(mObjects);
mObjects = nullptr;
+ mObjectsCapacity = 0;
} else {
binder_size_t* objects =
(binder_size_t*)realloc(mObjects, objectsSize*sizeof(binder_size_t));
if (objects) {
mObjects = objects;
+ mObjectsCapacity = objectsSize;
}
}
mObjectsSize = objectsSize;
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 6971c72..3f47f3b 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -188,6 +188,30 @@
return count;
}
+// Queries the driver for the current strong reference count of the node
+// that the handle points to. Can only be used by the servicemanager.
+//
+// Returns -1 in case of failure, otherwise the strong reference count.
+ssize_t ProcessState::getStrongRefCountForNodeByHandle(int32_t handle) {
+ binder_node_info_for_ref info;
+ memset(&info, 0, sizeof(binder_node_info_for_ref));
+
+ info.handle = handle;
+
+ status_t result = ioctl(mDriverFD, BINDER_GET_NODE_INFO_FOR_REF, &info);
+
+ if (result != OK) {
+ static bool logged = false;
+ if (!logged) {
+ ALOGW("Kernel does not support BINDER_GET_NODE_INFO_FOR_REF.");
+ logged = true;
+ }
+ return -1;
+ }
+
+ return info.strong_count;
+}
+
void ProcessState::setCallRestriction(CallRestriction restriction) {
LOG_ALWAYS_FATAL_IF(IPCThreadState::selfOrNull() != nullptr,
"Call restrictions must be set before the threadpool is started.");
diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl
index 60c2cce..8c7ebba 100644
--- a/libs/binder/aidl/android/os/IServiceManager.aidl
+++ b/libs/binder/aidl/android/os/IServiceManager.aidl
@@ -31,22 +31,22 @@
* Must update values in IServiceManager.h
*/
/* Allows services to dump sections according to priorities. */
- const int DUMP_FLAG_PRIORITY_CRITICAL = 1; // 1 << 0
- const int DUMP_FLAG_PRIORITY_HIGH = 2; // 1 << 1
- const int DUMP_FLAG_PRIORITY_NORMAL = 4; // 1 << 2
+ const int DUMP_FLAG_PRIORITY_CRITICAL = 1 << 0;
+ const int DUMP_FLAG_PRIORITY_HIGH = 1 << 1;
+ const int DUMP_FLAG_PRIORITY_NORMAL = 1 << 2;
/**
* Services are by default registered with a DEFAULT dump priority. DEFAULT priority has the
* same priority as NORMAL priority but the services are not called with dump priority
* arguments.
*/
- const int DUMP_FLAG_PRIORITY_DEFAULT = 8; // 1 << 3
+ const int DUMP_FLAG_PRIORITY_DEFAULT = 1 << 3;
const int DUMP_FLAG_PRIORITY_ALL = 15;
// DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_HIGH
// | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PRIORITY_DEFAULT;
/* Allows services to dump sections in protobuf format. */
- const int DUMP_FLAG_PROTO = 16; // 1 << 4
+ const int DUMP_FLAG_PROTO = 1 << 4;
/**
* Retrieve an existing service called @a name from the
@@ -89,4 +89,11 @@
* Unregisters all requests for notifications for a specific callback.
*/
void unregisterForNotifications(@utf8InCpp String name, IServiceCallback callback);
+
+ /**
+ * Returns whether a given interface is declared on the device, even if it
+ * is not started yet. For instance, this could be a service declared in the VINTF
+ * manifest.
+ */
+ boolean isDeclared(@utf8InCpp String name);
}
diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h
index 0ab40b8..2744ce1 100644
--- a/libs/binder/include/binder/AppOpsManager.h
+++ b/libs/binder/include/binder/AppOpsManager.h
@@ -130,16 +130,17 @@
int32_t checkOp(int32_t op, int32_t uid, const String16& callingPackage);
int32_t checkAudioOpNoThrow(int32_t op, int32_t usage, int32_t uid,
const String16& callingPackage);
- // @Deprecated, use noteOp(int32_t, int32_t uid, const String16&, const String16&) instead
+ // @Deprecated, use noteOp(int32_t, int32_t uid, const String16&, const String16&,
+ // const String16&) instead
int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage);
int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage,
- const String16& message);
- // @Deprecated, use startOpNoThrow(int32_t, int32_t, const String16&, bool, const String16&)
- // instead
+ const String16& featureId, const String16& message);
+ // @Deprecated, use startOpNoThrow(int32_t, int32_t, const String16&, bool, const String16&,
+ // const String16&) instead
int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
bool startIfModeDefault);
int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
- bool startIfModeDefault, const String16& message);
+ bool startIfModeDefault, const String16& featureId, const String16& message);
void finishOp(int32_t op, int32_t uid, const String16& callingPackage);
void startWatchingMode(int32_t op, const String16& packageName,
const sp<IAppOpsCallback>& callback);
@@ -147,7 +148,7 @@
int32_t permissionToOpCode(const String16& permission);
void setCameraAudioRestriction(int32_t mode);
void noteAsyncOp(const String16& callingPackageName, int32_t uid, const String16& packageName,
- int32_t opCode, const String16& message);
+ int32_t opCode, const String16& featureId, const String16& message);
private:
Mutex mLock;
@@ -155,7 +156,7 @@
sp<IAppOpsService> getService();
void markAppOpNoted(int32_t uid, const String16& packageName, int32_t opCode,
- const String16& message);
+ const String16& featureId, const String16& message);
bool shouldCollectNotes(int32_t opCode);
};
diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h
index 8b8a3c2..ad34bc5 100644
--- a/libs/binder/include/binder/IAppOpsService.h
+++ b/libs/binder/include/binder/IAppOpsService.h
@@ -49,7 +49,8 @@
const String16& packageName) = 0;
virtual void setCameraAudioRestriction(int32_t mode) = 0;
virtual void noteAsyncOp(const String16& callingPackageName, int32_t uid,
- const String16& packageName, int32_t opCode, const String16& message) = 0;
+ const String16& packageName, int32_t opCode, const String16& featureId,
+ const String16& message) = 0;
virtual bool shouldCollectNotes(int32_t opCode) = 0;
enum {
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index a675513..4a44c5a 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -88,6 +88,14 @@
* Returns nullptr only for permission problem or fatal error.
*/
virtual sp<IBinder> waitForService(const String16& name) = 0;
+
+ /**
+ * Check if a service is declared (e.g. VINTF manifest).
+ *
+ * If this returns true, waitForService should always be able to return the
+ * service.
+ */
+ virtual bool isDeclared(const String16& name) = 0;
};
sp<IServiceManager> defaultServiceManager();
@@ -99,6 +107,13 @@
}
template<typename INTERFACE>
+sp<INTERFACE> waitForDeclaredService(const String16& name) {
+ const sp<IServiceManager> sm = defaultServiceManager();
+ if (!sm->isDeclared(name)) return nullptr;
+ return interface_cast<INTERFACE>(sm->waitForService(name));
+}
+
+template<typename INTERFACE>
status_t getService(const String16& name, sp<INTERFACE>* outService)
{
const sp<IServiceManager> sm = defaultServiceManager();
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index f7c38f4..e57ff1c 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -69,6 +69,14 @@
ssize_t getKernelReferences(size_t count, uintptr_t* buf);
+ // Only usable by the context manager.
+ // This refcount includes:
+ // 1. Strong references to the node by this and other processes
+ // 2. Temporary strong references held by the kernel during a
+ // transaction on the node.
+ // It does NOT include local strong references to the node
+ ssize_t getStrongRefCountForNodeByHandle(int32_t handle);
+
enum class CallRestriction {
// all calls okay
NONE,
diff --git a/libs/binder/include/binder/Stability.h b/libs/binder/include/binder/Stability.h
index 2894482..b2f51d3 100644
--- a/libs/binder/include/binder/Stability.h
+++ b/libs/binder/include/binder/Stability.h
@@ -81,7 +81,7 @@
VINTF = 0b111111,
};
-#if defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#if defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__))
static constexpr Level kLocalStability = Level::VENDOR;
#else
static constexpr Level kLocalStability = Level::SYSTEM;
diff --git a/libs/binder/ndk/include_platform/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h
index e1a8cfd..2a4ded8 100644
--- a/libs/binder/ndk/include_platform/android/binder_stability.h
+++ b/libs/binder/ndk/include_platform/android/binder_stability.h
@@ -30,7 +30,8 @@
FLAG_PRIVATE_VENDOR = 0x10000000,
};
-#if (defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__))
+#if defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || \
+ (defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__))
enum {
FLAG_PRIVATE_LOCAL = FLAG_PRIVATE_VENDOR,
@@ -45,7 +46,8 @@
AIBinder_markVendorStability(binder);
}
-#else // defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#else // defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) &&
+ // !defined(__ANDROID_APEX__))
enum {
FLAG_PRIVATE_LOCAL = 0,
@@ -60,7 +62,8 @@
AIBinder_markSystemStability(binder);
}
-#endif // defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
+#endif // defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) &&
+ // !defined(__ANDROID_APEX__))
/**
* This interface has system<->vendor stability
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp
index 1c5dba3..ebd08b2 100644
--- a/libs/binder/ndk/test/Android.bp
+++ b/libs/binder/ndk/test/Android.bp
@@ -77,6 +77,7 @@
static_libs: [
"IBinderVendorDoubleLoadTest-cpp",
"IBinderVendorDoubleLoadTest-ndk_platform",
+ "libbinder_aidl_test_stub-ndk_platform",
],
shared_libs: [
"libbase",
diff --git a/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp b/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp
index f72dc36..d3ccdc2 100644
--- a/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp
+++ b/libs/binder/ndk/test/binderVendorDoubleLoadTest.cpp
@@ -16,6 +16,7 @@
#include <BnBinderVendorDoubleLoadTest.h>
#include <aidl/BnBinderVendorDoubleLoadTest.h>
+#include <aidl/android/os/IServiceManager.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
@@ -109,6 +110,24 @@
}
}
+TEST(DoubleBinder, CallIntoSystemStabilityNdk) {
+ // picking an arbitrary system service
+ SpAIBinder binder = SpAIBinder(AServiceManager_checkService("manager"));
+ ASSERT_NE(nullptr, binder.get());
+
+ // can make stable transaction to system server
+ EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
+
+ using aidl::android::os::IServiceManager;
+ std::shared_ptr<IServiceManager> manager = IServiceManager::fromBinder(binder);
+ ASSERT_NE(nullptr, manager.get());
+
+ std::vector<std::string> services;
+ ASSERT_EQ(
+ STATUS_BAD_TYPE,
+ manager->listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL, &services).getStatus());
+}
+
void initDrivers() {
// Explicitly instantiated with the same driver that system would use.
// __ANDROID_VNDK__ right now uses /dev/vndbinder by default.
diff --git a/libs/binder/tests/binderStabilityTest.cpp b/libs/binder/tests/binderStabilityTest.cpp
index 0bee56c..1f2779a 100644
--- a/libs/binder/tests/binderStabilityTest.cpp
+++ b/libs/binder/tests/binderStabilityTest.cpp
@@ -134,18 +134,15 @@
TEST(BinderStability, VintfStabilityServerMustBeDeclaredInManifest) {
sp<IBinder> vintfServer = BadStableBinder::vintf();
- EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
- android::defaultServiceManager()->addService(String16("."), vintfServer));
- EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
- android::defaultServiceManager()->addService(String16("/"), vintfServer));
- EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
- android::defaultServiceManager()->addService(String16("/."), vintfServer));
- EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
- android::defaultServiceManager()->addService(String16("a.d.IFoo"), vintfServer));
- EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
- android::defaultServiceManager()->addService(String16("foo"), vintfServer));
- EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
- android::defaultServiceManager()->addService(String16("a.d.IFoo/foo"), vintfServer));
+ for (const char* instance8 : {
+ ".", "/", "/.", "a.d.IFoo", "foo", "a.d.IFoo/foo"
+ }) {
+ String16 instance (instance8);
+
+ EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+ android::defaultServiceManager()->addService(String16("."), vintfServer)) << instance8;
+ EXPECT_FALSE(android::defaultServiceManager()->isDeclared(instance)) << instance8;
+ }
}
TEST(BinderStability, CantCallVendorBinderInSystemContext) {
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index e6d442d..b360a26 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -17,8 +17,16 @@
export_include_dirs: ["include"],
// we must build this module to get the required header as that is generated
- export_shared_lib_headers: [ "android.hidl.token@1.0-utils" ],
- shared_libs: [ "android.hidl.token@1.0-utils" ],
+ export_shared_lib_headers: [
+ "android.hidl.token@1.0-utils",
+ "android.hardware.graphics.bufferqueue@1.0",
+ "android.hardware.graphics.bufferqueue@2.0",
+ ],
+ shared_libs: [
+ "android.hidl.token@1.0-utils",
+ "android.hardware.graphics.bufferqueue@1.0",
+ "android.hardware.graphics.bufferqueue@2.0",
+ ],
}
cc_library_shared {
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 5fb3f0b..c1d92a2 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -43,6 +43,27 @@
}
}
+void BufferQueue::ProxyConsumerListener::onFrameDequeued(const uint64_t bufferId) {
+ sp<ConsumerListener> listener(mConsumerListener.promote());
+ if (listener != nullptr) {
+ listener->onFrameDequeued(bufferId);
+ }
+}
+
+void BufferQueue::ProxyConsumerListener::onFrameCancelled(const uint64_t bufferId) {
+ sp<ConsumerListener> listener(mConsumerListener.promote());
+ if (listener != nullptr) {
+ listener->onFrameCancelled(bufferId);
+ }
+}
+
+void BufferQueue::ProxyConsumerListener::onFrameDetached(const uint64_t bufferId) {
+ sp<ConsumerListener> listener(mConsumerListener.promote());
+ if (listener != nullptr) {
+ listener->onFrameDetached(bufferId);
+ }
+}
+
void BufferQueue::ProxyConsumerListener::onFrameAvailable(
const BufferItem& item) {
sp<ConsumerListener> listener(mConsumerListener.promote());
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 5674674..09c74de 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -580,6 +580,11 @@
}
addAndGetFrameTimestamps(nullptr, outTimestamps);
+ { // Autolock scope
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
+ mCore->mConsumerListener->onFrameDequeued(mSlots[*outSlot].mGraphicBuffer->getId());
+ }
+
return returnFlags;
}
@@ -621,13 +626,16 @@
return BAD_VALUE;
}
+ listener = mCore->mConsumerListener;
+ if (listener != nullptr) {
+ listener->onFrameDetached(mSlots[slot].mGraphicBuffer->getId());
+ }
mSlots[slot].mBufferState.detachProducer();
mCore->mActiveBuffers.erase(slot);
mCore->mFreeSlots.insert(slot);
mCore->clearBufferSlotLocked(slot);
mCore->mDequeueCondition.notify_all();
VALIDATE_CONSISTENCY();
- listener = mCore->mConsumerListener;
}
if (listener != nullptr) {
@@ -1083,6 +1091,9 @@
mCore->mFreeBuffers.push_back(slot);
}
+ if (mCore->mConsumerListener != nullptr) {
+ mCore->mConsumerListener->onFrameCancelled(mSlots[slot].mGraphicBuffer->getId());
+ }
mSlots[slot].mFence = fence;
mCore->mDequeueCondition.notify_all();
VALIDATE_CONSISTENCY();
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index abd9921..9f91d9d 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -101,6 +101,48 @@
mSlots[slotIndex].mFrameNumber = 0;
}
+void ConsumerBase::onFrameDequeued(const uint64_t bufferId) {
+ CB_LOGV("onFrameDequeued");
+
+ sp<FrameAvailableListener> listener;
+ {
+ Mutex::Autolock lock(mFrameAvailableMutex);
+ listener = mFrameAvailableListener.promote();
+ }
+
+ if (listener != nullptr) {
+ listener->onFrameDequeued(bufferId);
+ }
+}
+
+void ConsumerBase::onFrameCancelled(const uint64_t bufferId) {
+ CB_LOGV("onFrameCancelled");
+
+ sp<FrameAvailableListener> listener;
+ {
+ Mutex::Autolock lock(mFrameAvailableMutex);
+ listener = mFrameAvailableListener.promote();
+ }
+
+ if (listener != nullptr) {
+ listener->onFrameCancelled(bufferId);
+ }
+}
+
+void ConsumerBase::onFrameDetached(const uint64_t bufferId) {
+ CB_LOGV("onFrameDetached");
+
+ sp<FrameAvailableListener> listener;
+ {
+ Mutex::Autolock lock(mFrameAvailableMutex);
+ listener = mFrameAvailableListener.promote();
+ }
+
+ if (listener != nullptr) {
+ listener->onFrameDetached(bufferId);
+ }
+}
+
void ConsumerBase::onFrameAvailable(const BufferItem& item) {
CB_LOGV("onFrameAvailable");
diff --git a/libs/gui/IConsumerListener.cpp b/libs/gui/IConsumerListener.cpp
index 85ac304..48cb4b9 100644
--- a/libs/gui/IConsumerListener.cpp
+++ b/libs/gui/IConsumerListener.cpp
@@ -28,7 +28,10 @@
ON_FRAME_REPLACED,
ON_BUFFERS_RELEASED,
ON_SIDEBAND_STREAM_CHANGED,
- LAST = ON_SIDEBAND_STREAM_CHANGED,
+ ON_FRAME_DEQUEUED,
+ ON_FRAME_CANCELLED,
+ ON_FRAME_DETACHED,
+ LAST = ON_FRAME_DETACHED,
};
} // Anonymous namespace
@@ -44,6 +47,21 @@
callRemoteAsync<decltype(&IConsumerListener::onDisconnect)>(Tag::ON_DISCONNECT);
}
+ void onFrameDequeued(const uint64_t bufferId) override {
+ callRemoteAsync<decltype(&IConsumerListener::onFrameDequeued)>(Tag::ON_FRAME_DEQUEUED,
+ bufferId);
+ }
+
+ void onFrameDetached(const uint64_t bufferId) override {
+ callRemoteAsync<decltype(&IConsumerListener::onFrameDetached)>(Tag::ON_FRAME_DETACHED,
+ bufferId);
+ }
+
+ void onFrameCancelled(const uint64_t bufferId) override {
+ callRemoteAsync<decltype(&IConsumerListener::onFrameCancelled)>(Tag::ON_FRAME_CANCELLED,
+ bufferId);
+ }
+
void onFrameAvailable(const BufferItem& item) override {
callRemoteAsync<decltype(&IConsumerListener::onFrameAvailable)>(Tag::ON_FRAME_AVAILABLE,
item);
@@ -93,6 +111,12 @@
return callLocalAsync(data, reply, &IConsumerListener::onBuffersReleased);
case Tag::ON_SIDEBAND_STREAM_CHANGED:
return callLocalAsync(data, reply, &IConsumerListener::onSidebandStreamChanged);
+ case Tag::ON_FRAME_DEQUEUED:
+ return callLocalAsync(data, reply, &IConsumerListener::onFrameDequeued);
+ case Tag::ON_FRAME_CANCELLED:
+ return callLocalAsync(data, reply, &IConsumerListener::onFrameCancelled);
+ case Tag::ON_FRAME_DETACHED:
+ return callLocalAsync(data, reply, &IConsumerListener::onFrameDetached);
}
}
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index acda600..e5e25aa 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -48,6 +48,7 @@
} else {
err = output->writeBool(false);
}
+ err = output->writeUint32(transformHint);
return err;
}
@@ -72,7 +73,8 @@
return err;
}
}
- return NO_ERROR;
+ err = input->readUint32(&transformHint);
+ return err;
}
status_t TransactionStats::writeToParcel(Parcel* output) const {
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 7b256f5..e9079ef 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -222,7 +222,8 @@
for (const auto& surfaceStats : transactionStats.surfaceStats) {
surfaceControlStats.emplace_back(surfaceControls[surfaceStats.surfaceControl],
surfaceStats.acquireTime,
- surfaceStats.previousReleaseFence);
+ surfaceStats.previousReleaseFence,
+ surfaceStats.transformHint);
}
callbackFunction(transactionStats.latchTime, transactionStats.presentFence,
diff --git a/libs/gui/include/gui/BufferQueue.h b/libs/gui/include/gui/BufferQueue.h
index da95274..91f80d2 100644
--- a/libs/gui/include/gui/BufferQueue.h
+++ b/libs/gui/include/gui/BufferQueue.h
@@ -63,6 +63,9 @@
void onFrameReplaced(const BufferItem& item) override;
void onBuffersReleased() override;
void onSidebandStreamChanged() override;
+ void onFrameDequeued(const uint64_t bufferId) override;
+ void onFrameCancelled(const uint64_t bufferId) override;
+ void onFrameDetached(const uint64_t bufferID) override;
void addAndGetFrameTimestamps(
const NewFrameEventsEntry* newTimestamps,
FrameEventHistoryDelta* outDelta) override;
diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h
index 366ced3..8ff0cd0 100644
--- a/libs/gui/include/gui/ConsumerBase.h
+++ b/libs/gui/include/gui/ConsumerBase.h
@@ -45,6 +45,9 @@
// See IConsumerListener::onFrame{Available,Replaced}
virtual void onFrameAvailable(const BufferItem& item) = 0;
virtual void onFrameReplaced(const BufferItem& /* item */) {}
+ virtual void onFrameDequeued(const uint64_t){};
+ virtual void onFrameCancelled(const uint64_t){};
+ virtual void onFrameDetached(const uint64_t){};
};
~ConsumerBase() override;
@@ -141,6 +144,9 @@
// classes if they want the notification.
virtual void onFrameAvailable(const BufferItem& item) override;
virtual void onFrameReplaced(const BufferItem& item) override;
+ virtual void onFrameDequeued(const uint64_t bufferId) override;
+ virtual void onFrameCancelled(const uint64_t bufferId) override;
+ virtual void onFrameDetached(const uint64_t bufferId) override;
virtual void onBuffersReleased() override;
virtual void onSidebandStreamChanged() override;
diff --git a/libs/gui/include/gui/IConsumerListener.h b/libs/gui/include/gui/IConsumerListener.h
index c082882..046f6e1 100644
--- a/libs/gui/include/gui/IConsumerListener.h
+++ b/libs/gui/include/gui/IConsumerListener.h
@@ -43,6 +43,17 @@
// onDisconnect is called when a producer disconnects from the BufferQueue.
virtual void onDisconnect() {} /* Asynchronous */
+ // onFrameDequeued is called when a call to the BufferQueueProducer::dequeueBuffer successfully
+ // returns a slot from the BufferQueue.
+ virtual void onFrameDequeued(const uint64_t) {}
+
+ // onFrameCancelled is called when the client calls cancelBuffer, thereby releasing the slot
+ // back to the BufferQueue.
+ virtual void onFrameCancelled(const uint64_t) {}
+
+ // onFrameDetached is called after a successful detachBuffer() call while in asynchronous mode.
+ virtual void onFrameDetached(const uint64_t) {}
+
// onFrameAvailable is called from queueBuffer each time an additional frame becomes available
// for consumption. This means that frames that are queued while in asynchronous mode only
// trigger the callback if no previous frames are pending. Frames queued while in synchronous
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index 178ca2d..9c15225 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -41,12 +41,17 @@
status_t readFromParcel(const Parcel* input) override;
SurfaceStats() = default;
- SurfaceStats(const sp<IBinder>& sc, nsecs_t time, const sp<Fence>& prevReleaseFence)
- : surfaceControl(sc), acquireTime(time), previousReleaseFence(prevReleaseFence) {}
+ SurfaceStats(const sp<IBinder>& sc, nsecs_t time, const sp<Fence>& prevReleaseFence,
+ uint32_t hint)
+ : surfaceControl(sc),
+ acquireTime(time),
+ previousReleaseFence(prevReleaseFence),
+ transformHint(hint) {}
sp<IBinder> surfaceControl;
nsecs_t acquireTime = -1;
sp<Fence> previousReleaseFence;
+ uint32_t transformHint = 0;
};
class TransactionStats : public Parcelable {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 6676be4..08f4e9e 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -58,12 +58,16 @@
struct SurfaceControlStats {
SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t time,
- const sp<Fence>& prevReleaseFence)
- : surfaceControl(sc), acquireTime(time), previousReleaseFence(prevReleaseFence) {}
+ const sp<Fence>& prevReleaseFence, uint32_t hint)
+ : surfaceControl(sc),
+ acquireTime(time),
+ previousReleaseFence(prevReleaseFence),
+ transformHint(hint) {}
sp<SurfaceControl> surfaceControl;
nsecs_t acquireTime = -1;
sp<Fence> previousReleaseFence;
+ uint32_t transformHint = 0;
};
using TransactionCompletedCallbackTakesContext =
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 366c93c..c4f7fe0 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -93,13 +93,12 @@
bool InputMessage::isValid(size_t actualSize) const {
if (size() == actualSize) {
switch (header.type) {
- case TYPE_KEY:
- return true;
- case TYPE_MOTION:
- return body.motion.pointerCount > 0
- && body.motion.pointerCount <= MAX_POINTERS;
- case TYPE_FINISHED:
- return true;
+ case Type::KEY:
+ return true;
+ case Type::MOTION:
+ return body.motion.pointerCount > 0 && body.motion.pointerCount <= MAX_POINTERS;
+ case Type::FINISHED:
+ return true;
}
}
return false;
@@ -107,12 +106,12 @@
size_t InputMessage::size() const {
switch (header.type) {
- case TYPE_KEY:
- return sizeof(Header) + body.key.size();
- case TYPE_MOTION:
- return sizeof(Header) + body.motion.size();
- case TYPE_FINISHED:
- return sizeof(Header) + body.finished.size();
+ case Type::KEY:
+ return sizeof(Header) + body.key.size();
+ case Type::MOTION:
+ return sizeof(Header) + body.motion.size();
+ case Type::FINISHED:
+ return sizeof(Header) + body.finished.size();
}
return sizeof(Header);
}
@@ -129,7 +128,7 @@
// Write the body
switch(header.type) {
- case InputMessage::TYPE_KEY: {
+ case InputMessage::Type::KEY: {
// uint32_t seq
msg->body.key.seq = body.key.seq;
// nsecs_t eventTime
@@ -156,7 +155,7 @@
msg->body.key.downTime = body.key.downTime;
break;
}
- case InputMessage::TYPE_MOTION: {
+ case InputMessage::Type::MOTION: {
// uint32_t seq
msg->body.motion.seq = body.motion.seq;
// nsecs_t eventTime
@@ -212,7 +211,7 @@
}
break;
}
- case InputMessage::TYPE_FINISHED: {
+ case InputMessage::Type::FINISHED: {
msg->body.finished.seq = body.finished.seq;
msg->body.finished.handled = body.finished.handled;
break;
@@ -457,7 +456,7 @@
}
InputMessage msg;
- msg.header.type = InputMessage::TYPE_KEY;
+ msg.header.type = InputMessage::Type::KEY;
msg.body.key.seq = seq;
msg.body.key.deviceId = deviceId;
msg.body.key.source = source;
@@ -511,7 +510,7 @@
}
InputMessage msg;
- msg.header.type = InputMessage::TYPE_MOTION;
+ msg.header.type = InputMessage::Type::MOTION;
msg.body.motion.seq = seq;
msg.body.motion.deviceId = deviceId;
msg.body.motion.source = source;
@@ -553,7 +552,7 @@
*outHandled = false;
return result;
}
- if (msg.header.type != InputMessage::TYPE_FINISHED) {
+ if (msg.header.type != InputMessage::Type::FINISHED) {
ALOGE("channel '%s' publisher ~ Received unexpected message of type %d from consumer",
mChannel->getName().c_str(), msg.header.type);
return UNKNOWN_ERROR;
@@ -614,59 +613,59 @@
}
switch (mMsg.header.type) {
- case InputMessage::TYPE_KEY: {
- KeyEvent* keyEvent = factory->createKeyEvent();
- if (!keyEvent) return NO_MEMORY;
+ case InputMessage::Type::KEY: {
+ KeyEvent* keyEvent = factory->createKeyEvent();
+ if (!keyEvent) return NO_MEMORY;
- initializeKeyEvent(keyEvent, &mMsg);
- *outSeq = mMsg.body.key.seq;
- *outEvent = keyEvent;
+ initializeKeyEvent(keyEvent, &mMsg);
+ *outSeq = mMsg.body.key.seq;
+ *outEvent = keyEvent;
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' consumer ~ consumed key event, seq=%u",
mChannel->getName().c_str(), *outSeq);
#endif
break;
- }
+ }
- case InputMessage::TYPE_MOTION: {
- ssize_t batchIndex = findBatch(mMsg.body.motion.deviceId, mMsg.body.motion.source);
- if (batchIndex >= 0) {
- Batch& batch = mBatches.editItemAt(batchIndex);
- if (canAddSample(batch, &mMsg)) {
- batch.samples.push(mMsg);
+ case InputMessage::Type::MOTION: {
+ ssize_t batchIndex = findBatch(mMsg.body.motion.deviceId, mMsg.body.motion.source);
+ if (batchIndex >= 0) {
+ Batch& batch = mBatches.editItemAt(batchIndex);
+ if (canAddSample(batch, &mMsg)) {
+ batch.samples.push(mMsg);
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' consumer ~ appended to batch event",
mChannel->getName().c_str());
#endif
break;
- } else if (isPointerEvent(mMsg.body.motion.source) &&
- mMsg.body.motion.action == AMOTION_EVENT_ACTION_CANCEL) {
- // No need to process events that we are going to cancel anyways
- const size_t count = batch.samples.size();
- for (size_t i = 0; i < count; i++) {
- const InputMessage& msg = batch.samples.itemAt(i);
- sendFinishedSignal(msg.body.motion.seq, false);
- }
- batch.samples.removeItemsAt(0, count);
- mBatches.removeAt(batchIndex);
- } else {
- // We cannot append to the batch in progress, so we need to consume
- // the previous batch right now and defer the new message until later.
- mMsgDeferred = true;
- status_t result = consumeSamples(factory,
- batch, batch.samples.size(), outSeq, outEvent);
- mBatches.removeAt(batchIndex);
- if (result) {
- return result;
- }
+ } else if (isPointerEvent(mMsg.body.motion.source) &&
+ mMsg.body.motion.action == AMOTION_EVENT_ACTION_CANCEL) {
+ // No need to process events that we are going to cancel anyways
+ const size_t count = batch.samples.size();
+ for (size_t i = 0; i < count; i++) {
+ const InputMessage& msg = batch.samples.itemAt(i);
+ sendFinishedSignal(msg.body.motion.seq, false);
+ }
+ batch.samples.removeItemsAt(0, count);
+ mBatches.removeAt(batchIndex);
+ } else {
+ // We cannot append to the batch in progress, so we need to consume
+ // the previous batch right now and defer the new message until later.
+ mMsgDeferred = true;
+ status_t result = consumeSamples(factory, batch, batch.samples.size(),
+ outSeq, outEvent);
+ mBatches.removeAt(batchIndex);
+ if (result) {
+ return result;
+ }
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' consumer ~ consumed batch event and "
"deferred current event, seq=%u",
mChannel->getName().c_str(), *outSeq);
#endif
break;
+ }
}
- }
// Start a new batch if needed.
if (mMsg.body.motion.action == AMOTION_EVENT_ACTION_MOVE
@@ -694,7 +693,7 @@
mChannel->getName().c_str(), *outSeq);
#endif
break;
- }
+ }
default:
ALOGE("channel '%s' consumer ~ Received unexpected message of type %d",
@@ -1074,7 +1073,7 @@
status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {
InputMessage msg;
- msg.header.type = InputMessage::TYPE_FINISHED;
+ msg.header.type = InputMessage::Type::FINISHED;
msg.body.finished.seq = seq;
msg.body.finished.handled = handled;
return mChannel->sendMessage(&msg);
diff --git a/libs/input/tests/InputChannel_test.cpp b/libs/input/tests/InputChannel_test.cpp
index af74edd..7c331e1 100644
--- a/libs/input/tests/InputChannel_test.cpp
+++ b/libs/input/tests/InputChannel_test.cpp
@@ -86,7 +86,7 @@
// Server->Client communication
InputMessage serverMsg;
memset(&serverMsg, 0, sizeof(InputMessage));
- serverMsg.header.type = InputMessage::TYPE_KEY;
+ serverMsg.header.type = InputMessage::Type::KEY;
serverMsg.body.key.action = AKEY_EVENT_ACTION_DOWN;
EXPECT_EQ(OK, serverChannel->sendMessage(&serverMsg))
<< "server channel should be able to send message to client channel";
@@ -102,7 +102,7 @@
// Client->Server communication
InputMessage clientReply;
memset(&clientReply, 0, sizeof(InputMessage));
- clientReply.header.type = InputMessage::TYPE_FINISHED;
+ clientReply.header.type = InputMessage::Type::FINISHED;
clientReply.body.finished.seq = 0x11223344;
clientReply.body.finished.handled = true;
EXPECT_EQ(OK, clientChannel->sendMessage(&clientReply))
@@ -161,7 +161,7 @@
serverChannel.clear(); // close server channel
InputMessage msg;
- msg.header.type = InputMessage::TYPE_KEY;
+ msg.header.type = InputMessage::Type::KEY;
EXPECT_EQ(DEAD_OBJECT, clientChannel->sendMessage(&msg))
<< "sendMessage should have returned DEAD_OBJECT";
}
@@ -180,7 +180,7 @@
};
InputMessage serverMsg = {}, clientMsg;
- serverMsg.header.type = InputMessage::TYPE_MOTION;
+ serverMsg.header.type = InputMessage::Type::MOTION;
serverMsg.body.motion.seq = 1;
serverMsg.body.motion.pointerCount = 1;
diff --git a/libs/math/include/math/quat.h b/libs/math/include/math/quat.h
index 1936a2b..07573c5 100644
--- a/libs/math/include/math/quat.h
+++ b/libs/math/include/math/quat.h
@@ -109,7 +109,7 @@
// initialize from 4 values to w + xi + yj + zk
template<typename A, typename B, typename C, typename D>
- constexpr TQuaternion(A w, B x, C y, D z) : x(x), y(y), z(z), w(w) { }
+ constexpr TQuaternion(A w, B x, C y, D z) : x(static_cast<T>(x)), y(static_cast<T>(y)), z(static_cast<T>(z)), w(static_cast<T>(w)) { }
// initialize from a vec3 + a value to : v.xi + v.yj + v.zk + w
template<typename A, typename B>
diff --git a/libs/math/include/math/vec2.h b/libs/math/include/math/vec2.h
index a347633..e0adb7f 100644
--- a/libs/math/include/math/vec2.h
+++ b/libs/math/include/math/vec2.h
@@ -89,7 +89,7 @@
constexpr TVec2(A v) : x(v), y(v) { }
template<typename A, typename B>
- constexpr TVec2(A x, B y) : x(x), y(y) { }
+ constexpr TVec2(A x, B y) : x(static_cast<T>(x)), y(static_cast<T>(y)) { }
template<typename A>
explicit
diff --git a/libs/math/include/math/vec3.h b/libs/math/include/math/vec3.h
index 009fd84..21fb684 100644
--- a/libs/math/include/math/vec3.h
+++ b/libs/math/include/math/vec3.h
@@ -86,13 +86,13 @@
// handles implicit conversion to a tvec4. must not be explicit.
template<typename A, typename = typename std::enable_if<std::is_arithmetic<A>::value >::type>
- constexpr TVec3(A v) : x(v), y(v), z(v) { }
+ constexpr TVec3(A v) : x(static_cast<T>(v)), y(static_cast<T>(v)), z(static_cast<T>(v)) { }
template<typename A, typename B, typename C>
- constexpr TVec3(A x, B y, C z) : x(x), y(y), z(z) { }
+ constexpr TVec3(A x, B y, C z) : x(static_cast<T>(x)), y(static_cast<T>(y)), z(static_cast<T>(z)) { }
template<typename A, typename B>
- constexpr TVec3(const TVec2<A>& v, B z) : x(v.x), y(v.y), z(z) { }
+ constexpr TVec3(const TVec2<A>& v, B z) : x(v.x), y(v.y), z(static_cast<T>(z)) { }
template<typename A>
explicit
diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp
index 166c267..0fdf093 100644
--- a/libs/renderengine/RenderEngine.cpp
+++ b/libs/renderengine/RenderEngine.cpp
@@ -24,23 +24,22 @@
namespace android {
namespace renderengine {
-std::unique_ptr<impl::RenderEngine> RenderEngine::create(int hwcFormat, uint32_t featureFlags,
- uint32_t imageCacheSize) {
+std::unique_ptr<impl::RenderEngine> RenderEngine::create(const RenderEngineCreationArgs& args) {
char prop[PROPERTY_VALUE_MAX];
property_get(PROPERTY_DEBUG_RENDERENGINE_BACKEND, prop, "gles");
if (strcmp(prop, "gles") == 0) {
ALOGD("RenderEngine GLES Backend");
- return renderengine::gl::GLESRenderEngine::create(hwcFormat, featureFlags, imageCacheSize);
+ return renderengine::gl::GLESRenderEngine::create(args);
}
ALOGE("UNKNOWN BackendType: %s, create GLES RenderEngine.", prop);
- return renderengine::gl::GLESRenderEngine::create(hwcFormat, featureFlags, imageCacheSize);
+ return renderengine::gl::GLESRenderEngine::create(args);
}
RenderEngine::~RenderEngine() = default;
namespace impl {
-RenderEngine::RenderEngine(uint32_t featureFlags) : mFeatureFlags(featureFlags) {}
+RenderEngine::RenderEngine(const RenderEngineCreationArgs& args) : mArgs(args) {}
RenderEngine::~RenderEngine() = default;
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index b8cf0ea..15d025b 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -227,8 +227,7 @@
return err;
}
-std::unique_ptr<GLESRenderEngine> GLESRenderEngine::create(int hwcFormat, uint32_t featureFlags,
- uint32_t imageCacheSize) {
+std::unique_ptr<GLESRenderEngine> GLESRenderEngine::create(const RenderEngineCreationArgs& args) {
// initialize EGL for the default display
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (!eglInitialize(display, nullptr, nullptr)) {
@@ -243,14 +242,13 @@
// supported.
EGLConfig config = EGL_NO_CONFIG;
if (!extensions.hasNoConfigContext()) {
- config = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
+ config = chooseEglConfig(display, args.pixelFormat, /*logConfig*/ true);
}
- bool useContextPriority = extensions.hasContextPriority() &&
- (featureFlags & RenderEngine::USE_HIGH_PRIORITY_CONTEXT);
+ bool useContextPriority =
+ extensions.hasContextPriority() && args.contextPriority == ContextPriority::HIGH;
EGLContext protectedContext = EGL_NO_CONTEXT;
- if ((featureFlags & RenderEngine::ENABLE_PROTECTED_CONTEXT) &&
- extensions.hasProtectedContent()) {
+ if (args.enableProtectedContext && extensions.hasProtectedContent()) {
protectedContext = createEglContext(display, config, nullptr, useContextPriority,
Protection::PROTECTED);
ALOGE_IF(protectedContext == EGL_NO_CONTEXT, "Can't create protected context");
@@ -264,7 +262,8 @@
EGLSurface dummy = EGL_NO_SURFACE;
if (!extensions.hasSurfacelessContext()) {
- dummy = createDummyEglPbufferSurface(display, config, hwcFormat, Protection::UNPROTECTED);
+ dummy = createDummyEglPbufferSurface(display, config, args.pixelFormat,
+ Protection::UNPROTECTED);
LOG_ALWAYS_FATAL_IF(dummy == EGL_NO_SURFACE, "can't create dummy pbuffer");
}
EGLBoolean success = eglMakeCurrent(display, dummy, dummy, ctxt);
@@ -274,8 +273,8 @@
EGLSurface protectedDummy = EGL_NO_SURFACE;
if (protectedContext != EGL_NO_CONTEXT && !extensions.hasSurfacelessContext()) {
- protectedDummy =
- createDummyEglPbufferSurface(display, config, hwcFormat, Protection::PROTECTED);
+ protectedDummy = createDummyEglPbufferSurface(display, config, args.pixelFormat,
+ Protection::PROTECTED);
ALOGE_IF(protectedDummy == EGL_NO_SURFACE, "can't create protected dummy pbuffer");
}
@@ -291,9 +290,8 @@
break;
case GLES_VERSION_2_0:
case GLES_VERSION_3_0:
- engine = std::make_unique<GLESRenderEngine>(featureFlags, display, config, ctxt, dummy,
- protectedContext, protectedDummy,
- imageCacheSize);
+ engine = std::make_unique<GLESRenderEngine>(args, display, config, ctxt, dummy,
+ protectedContext, protectedDummy);
break;
}
@@ -347,10 +345,10 @@
return config;
}
-GLESRenderEngine::GLESRenderEngine(uint32_t featureFlags, EGLDisplay display, EGLConfig config,
- EGLContext ctxt, EGLSurface dummy, EGLContext protectedContext,
- EGLSurface protectedDummy, uint32_t imageCacheSize)
- : renderengine::impl::RenderEngine(featureFlags),
+GLESRenderEngine::GLESRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display,
+ EGLConfig config, EGLContext ctxt, EGLSurface dummy,
+ EGLContext protectedContext, EGLSurface protectedDummy)
+ : renderengine::impl::RenderEngine(args),
mEGLDisplay(display),
mEGLConfig(config),
mEGLContext(ctxt),
@@ -359,8 +357,8 @@
mProtectedDummySurface(protectedDummy),
mVpWidth(0),
mVpHeight(0),
- mFramebufferImageCacheSize(imageCacheSize),
- mUseColorManagement(featureFlags & USE_COLOR_MANAGEMENT) {
+ mFramebufferImageCacheSize(args.imageCacheSize),
+ mUseColorManagement(args.useColorManagement) {
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
@@ -457,10 +455,9 @@
}
void GLESRenderEngine::primeCache() const {
- ProgramCache::getInstance().primeCache(
- mInProtectedContext ? mProtectedEGLContext : mEGLContext,
- mFeatureFlags & USE_COLOR_MANAGEMENT,
- mFeatureFlags & PRECACHE_TONE_MAPPER_SHADER_ONLY);
+ ProgramCache::getInstance().primeCache(mInProtectedContext ? mProtectedEGLContext : mEGLContext,
+ mArgs.useColorManagement,
+ mArgs.precacheToneMapperShaderOnly);
}
base::unique_fd GLESRenderEngine::flush() {
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 501b044..397bc16 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -49,13 +49,11 @@
class GLESRenderEngine : public impl::RenderEngine {
public:
- static std::unique_ptr<GLESRenderEngine> create(int hwcFormat, uint32_t featureFlags,
- uint32_t imageCacheSize);
+ static std::unique_ptr<GLESRenderEngine> create(const RenderEngineCreationArgs& args);
- GLESRenderEngine(uint32_t featureFlags, // See RenderEngine::FeatureFlag
- EGLDisplay display, EGLConfig config, EGLContext ctxt, EGLSurface dummy,
- EGLContext protectedContext, EGLSurface protectedDummy,
- uint32_t imageCacheSize);
+ GLESRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, EGLConfig config,
+ EGLContext ctxt, EGLSurface dummy, EGLContext protectedContext,
+ EGLSurface protectedDummy);
~GLESRenderEngine() override EXCLUDES(mRenderingMutex);
void primeCache() const override;
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 9dcd510..4db5c57 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -48,6 +48,7 @@
class Image;
class Mesh;
class Texture;
+struct RenderEngineCreationArgs;
namespace impl {
class RenderEngine;
@@ -60,19 +61,13 @@
class RenderEngine {
public:
- enum FeatureFlag {
- USE_COLOR_MANAGEMENT = 1 << 0, // Device manages color
- USE_HIGH_PRIORITY_CONTEXT = 1 << 1, // Use high priority context
-
- // Create a protected context when if possible
- ENABLE_PROTECTED_CONTEXT = 1 << 2,
-
- // Only precache HDR to SDR tone-mapping shaders
- PRECACHE_TONE_MAPPER_SHADER_ONLY = 1 << 3,
+ enum class ContextPriority {
+ LOW = 1,
+ MEDIUM = 2,
+ HIGH = 3,
};
- static std::unique_ptr<impl::RenderEngine> create(int hwcFormat, uint32_t featureFlags,
- uint32_t imageCacheSize);
+ static std::unique_ptr<impl::RenderEngine> create(const RenderEngineCreationArgs& args);
virtual ~RenderEngine() = 0;
@@ -173,6 +168,76 @@
friend class BindNativeBufferAsFramebuffer;
};
+struct RenderEngineCreationArgs {
+ int pixelFormat;
+ uint32_t imageCacheSize;
+ bool useColorManagement;
+ bool enableProtectedContext;
+ bool precacheToneMapperShaderOnly;
+ RenderEngine::ContextPriority contextPriority;
+
+ struct Builder;
+
+private:
+ // must be created by Builder via constructor with full argument list
+ RenderEngineCreationArgs(
+ int _pixelFormat,
+ uint32_t _imageCacheSize,
+ bool _useColorManagement,
+ bool _enableProtectedContext,
+ bool _precacheToneMapperShaderOnly,
+ RenderEngine::ContextPriority _contextPriority)
+ : pixelFormat(_pixelFormat)
+ , imageCacheSize(_imageCacheSize)
+ , useColorManagement(_useColorManagement)
+ , enableProtectedContext(_enableProtectedContext)
+ , precacheToneMapperShaderOnly(_precacheToneMapperShaderOnly)
+ , contextPriority(_contextPriority) {}
+ RenderEngineCreationArgs() = delete;
+};
+
+struct RenderEngineCreationArgs::Builder {
+ Builder() {}
+
+ Builder& setPixelFormat(int pixelFormat) {
+ this->pixelFormat = pixelFormat;
+ return *this;
+ }
+ Builder& setImageCacheSize(uint32_t imageCacheSize) {
+ this->imageCacheSize = imageCacheSize;
+ return *this;
+ }
+ Builder& setUseColorManagerment(bool useColorManagement) {
+ this->useColorManagement = useColorManagement;
+ return *this;
+ }
+ Builder& setEnableProtectedContext(bool enableProtectedContext) {
+ this->enableProtectedContext = enableProtectedContext;
+ return *this;
+ }
+ Builder& setPrecacheToneMapperShaderOnly(bool precacheToneMapperShaderOnly) {
+ this->precacheToneMapperShaderOnly = precacheToneMapperShaderOnly;
+ return *this;
+ }
+ Builder& setContextPriority(RenderEngine::ContextPriority contextPriority) {
+ this->contextPriority = contextPriority;
+ return *this;
+ }
+ RenderEngineCreationArgs build() const {
+ return RenderEngineCreationArgs(pixelFormat, imageCacheSize, useColorManagement,
+ enableProtectedContext, precacheToneMapperShaderOnly, contextPriority);
+ }
+
+private:
+ // 1 means RGBA_8888
+ int pixelFormat = 1;
+ uint32_t imageCacheSize = 0;
+ bool useColorManagement = true;
+ bool enableProtectedContext = false;
+ bool precacheToneMapperShaderOnly = false;
+ RenderEngine::ContextPriority contextPriority = RenderEngine::ContextPriority::MEDIUM;
+};
+
class BindNativeBufferAsFramebuffer {
public:
BindNativeBufferAsFramebuffer(RenderEngine& engine, ANativeWindowBuffer* buffer,
@@ -206,8 +271,8 @@
bool useWaitSync() const override;
protected:
- RenderEngine(uint32_t featureFlags);
- const uint32_t mFeatureFlags;
+ RenderEngine(const RenderEngineCreationArgs& args);
+ const RenderEngineCreationArgs mArgs;
};
} // namespace impl
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index f47c7fd..d01c740 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -31,9 +31,15 @@
struct RenderEngineTest : public ::testing::Test {
static void SetUpTestSuite() {
- sRE = renderengine::gl::GLESRenderEngine::create(static_cast<int32_t>(
- ui::PixelFormat::RGBA_8888),
- 0, 1);
+ sRE = renderengine::gl::GLESRenderEngine::create(
+ renderengine::RenderEngineCreationArgs::Builder()
+ .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
+ .setImageCacheSize(1)
+ .setUseColorManagerment(false)
+ .setEnableProtectedContext(false)
+ .setPrecacheToneMapperShaderOnly(false)
+ .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
+ .build());
}
static void TearDownTestSuite() {
diff --git a/libs/ui/ColorSpace.cpp b/libs/ui/ColorSpace.cpp
index 7a14af1..df390e2 100644
--- a/libs/ui/ColorSpace.cpp
+++ b/libs/ui/ColorSpace.cpp
@@ -364,7 +364,11 @@
for (uint32_t z = 0; z < size; z++) {
for (int32_t y = int32_t(size - 1); y >= 0; y--) {
for (uint32_t x = 0; x < size; x++) {
- *data++ = connector.transform({x * m, y * m, z * m});
+ *data++ = connector.transform({
+ static_cast<float>(x) * m,
+ static_cast<float>(y) * m,
+ static_cast<float>(z) * m,
+ });
}
}
}
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index eb787a2..fcc2547 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -89,7 +89,7 @@
if (rec.size) {
StringAppendF(&result,
"%10p: %7.2f KiB | %4u (%4u) x %4u | %4u | %8X | 0x%" PRIx64 " | %s\n",
- list.keyAt(i), rec.size / 1024.0, rec.width, rec.stride, rec.height,
+ list.keyAt(i), static_cast<double>(rec.size) / 1024.0, rec.width, rec.stride, rec.height,
rec.layerCount, rec.format, rec.usage, rec.requestorName.c_str());
} else {
StringAppendF(&result,
@@ -99,7 +99,7 @@
}
total += rec.size;
}
- StringAppendF(&result, "Total allocated (estimate): %.2f KB\n", total / 1024.0);
+ StringAppendF(&result, "Total allocated (estimate): %.2f KB\n", static_cast<double>(total) / 1024.0);
result.append(mAllocator->dumpDebugInfo());
}
@@ -140,6 +140,17 @@
status_t error =
mAllocator->allocate(width, height, format, layerCount, usage, 1, stride, handle);
+ size_t bufSize;
+
+ // if stride has no meaning or is too large,
+ // approximate size with the input width instead
+ if ((*stride) != 0 &&
+ std::numeric_limits<size_t>::max() / height / (*stride) < static_cast<size_t>(bpp)) {
+ bufSize = static_cast<size_t>(width) * height * bpp;
+ } else {
+ bufSize = static_cast<size_t>((*stride)) * height * bpp;
+ }
+
if (error == NO_ERROR) {
Mutex::Autolock _l(sLock);
KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
@@ -150,7 +161,7 @@
rec.format = format;
rec.layerCount = layerCount;
rec.usage = usage;
- rec.size = static_cast<size_t>(height * (*stride) * bpp);
+ rec.size = bufSize;
rec.requestorName = std::move(requestorName);
list.add(*handle, rec);
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index 55e3b99..1222cd6 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -339,10 +339,10 @@
size_t count = mStorage.size();
Rect* rects = mStorage.editArray();
while (count) {
- rects->left = static_cast<int32_t>(rects->left * sx + 0.5f);
- rects->right = static_cast<int32_t>(rects->right * sx + 0.5f);
- rects->top = static_cast<int32_t>(rects->top * sy + 0.5f);
- rects->bottom = static_cast<int32_t>(rects->bottom * sy + 0.5f);
+ rects->left = static_cast<int32_t>(static_cast<float>(rects->left) * sx + 0.5f);
+ rects->right = static_cast<int32_t>(static_cast<float>(rects->right) * sx + 0.5f);
+ rects->top = static_cast<int32_t>(static_cast<float>(rects->top) * sy + 0.5f);
+ rects->bottom = static_cast<int32_t>(static_cast<float>(rects->bottom) * sy + 0.5f);
rects++;
count--;
}
diff --git a/libs/ui/include/ui/GraphicBufferAllocator.h b/libs/ui/include/ui/GraphicBufferAllocator.h
index 25d4512..324d9e1 100644
--- a/libs/ui/include/ui/GraphicBufferAllocator.h
+++ b/libs/ui/include/ui/GraphicBufferAllocator.h
@@ -54,7 +54,7 @@
void dump(std::string& res) const;
static void dumpToSystemLog();
-private:
+protected:
struct alloc_rec_t {
uint32_t width;
uint32_t height;
diff --git a/libs/ui/include/ui/Size.h b/libs/ui/include/ui/Size.h
index c39d8af..d9b713d 100644
--- a/libs/ui/include/ui/Size.h
+++ b/libs/ui/include/ui/Size.h
@@ -132,7 +132,7 @@
// Otherwise we leverage implicit conversion to safely compare values of
// different types, to ensure we return a value clamped to the range of
// ToType.
- return v < toLowest ? toLowest : (v > toHighest ? toHighest : static_cast<ToType>(v));
+ return v < toLowest ? toLowest : (static_cast<ToType>(v) > toHighest ? toHighest : static_cast<ToType>(v));
}
};
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 0452f84..d2ad242 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -29,6 +29,26 @@
}
cc_test {
+ name: "GraphicBufferAllocator_test",
+ header_libs: [
+ "libdvr_headers",
+ "libnativewindow_headers",
+ ],
+ static_libs: [
+ "libgmock",
+ ],
+ shared_libs: [
+ "liblog",
+ "libui",
+ ],
+ srcs: [
+ "GraphicBufferAllocator_test.cpp",
+ "mock/MockGrallocAllocator.cpp",
+ ],
+ cflags: ["-Wall", "-Werror"],
+}
+
+cc_test {
name: "GraphicBuffer_test",
header_libs: [
"libdvr_headers",
diff --git a/libs/ui/tests/GraphicBufferAllocator_test.cpp b/libs/ui/tests/GraphicBufferAllocator_test.cpp
new file mode 100644
index 0000000..efca083
--- /dev/null
+++ b/libs/ui/tests/GraphicBufferAllocator_test.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "GraphicBufferAllocatorTest"
+
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicBufferAllocator.h>
+#include <ui/PixelFormat.h>
+
+#include <gtest/gtest.h>
+
+#include "mock/MockGrallocAllocator.h"
+
+#include <algorithm>
+#include <limits>
+
+namespace android {
+
+namespace {
+
+constexpr uint32_t kTestWidth = 1024;
+constexpr uint32_t kTestHeight = 1;
+constexpr uint32_t kTestLayerCount = 1;
+constexpr uint64_t kTestUsage = GraphicBuffer::USAGE_SW_WRITE_OFTEN;
+
+} // namespace
+
+using ::testing::DoAll;
+using ::testing::Return;
+using ::testing::SetArgPointee;
+
+class TestableGraphicBufferAllocator : public GraphicBufferAllocator {
+public:
+ TestableGraphicBufferAllocator() {
+ mAllocator = std::make_unique<const mock::MockGrallocAllocator>();
+ }
+ void setUpAllocateExpectations(status_t err, uint32_t stride) {
+ std::cout << "Setting expected stride to " << stride << std::endl;
+ EXPECT_CALL(*(reinterpret_cast<const mock::MockGrallocAllocator*>(mAllocator.get())),
+ allocate)
+ .WillOnce(DoAll(SetArgPointee<6>(stride), Return(err)));
+ }
+ std::unique_ptr<const GrallocAllocator>& getAllocator() { return mAllocator; }
+};
+
+class GraphicBufferAllocatorTest : public testing::Test {
+public:
+ GraphicBufferAllocatorTest() : mAllocator() {}
+ const TestableGraphicBufferAllocator& getAllocator() { return mAllocator; }
+
+protected:
+ TestableGraphicBufferAllocator mAllocator;
+};
+
+TEST_F(GraphicBufferAllocatorTest, AllocateNoError) {
+ mAllocator.setUpAllocateExpectations(NO_ERROR, kTestWidth);
+ android::PixelFormat format = PIXEL_FORMAT_RGBA_8888;
+ uint32_t stride = 0;
+ buffer_handle_t handle;
+ status_t err = mAllocator.allocate(kTestWidth, kTestHeight, format, kTestLayerCount, kTestUsage,
+ &handle, &stride, 0, "GraphicBufferAllocatorTest");
+ ASSERT_EQ(NO_ERROR, err);
+ ASSERT_EQ(kTestWidth, stride);
+}
+
+TEST_F(GraphicBufferAllocatorTest, AllocateZeroStride) {
+ android::PixelFormat format = PIXEL_FORMAT_RGBA_8888;
+ uint32_t expectedStride = 0;
+
+ mAllocator.setUpAllocateExpectations(NO_ERROR, expectedStride);
+ uint32_t stride = 0;
+ buffer_handle_t handle;
+ // a divide by zero would cause a crash
+ status_t err = mAllocator.allocate(kTestWidth, kTestHeight, format, kTestLayerCount, kTestUsage,
+ &handle, &stride, 0, "GraphicBufferAllocatorTest");
+ ASSERT_EQ(NO_ERROR, err);
+ ASSERT_EQ(expectedStride, stride);
+}
+
+TEST_F(GraphicBufferAllocatorTest, AllocateLargeStride) {
+ uint32_t height = std::numeric_limits<uint32_t>::max();
+ uint32_t bpp = 4;
+ android::PixelFormat format = PIXEL_FORMAT_RGBA_8888;
+
+ if (std::numeric_limits<size_t>::max() / height / bpp >= std::numeric_limits<uint32_t>::max()) {
+ std::cout << "stride cannot cause overflow" << std::endl;
+ GTEST_SUCCEED() << "stride cannot cause overflow";
+ return;
+ }
+ uint32_t width = std::numeric_limits<size_t>::max() / height / bpp;
+
+ uint32_t expectedStride = std::numeric_limits<uint32_t>::max();
+
+ mAllocator.setUpAllocateExpectations(NO_ERROR, expectedStride);
+ uint32_t stride = 0;
+ buffer_handle_t handle;
+ // an overflow would cause a crash
+ status_t err = mAllocator.allocate(width, height, format, kTestLayerCount, kTestUsage, &handle,
+ &stride, 0, "GraphicBufferAllocatorTest");
+ ASSERT_EQ(NO_ERROR, err);
+ ASSERT_EQ(expectedStride, stride);
+}
+} // namespace android
diff --git a/libs/ui/tests/mock/MockGrallocAllocator.cpp b/libs/ui/tests/mock/MockGrallocAllocator.cpp
new file mode 100644
index 0000000..d71e25f
--- /dev/null
+++ b/libs/ui/tests/mock/MockGrallocAllocator.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MockGrallocAllocator.h"
+
+namespace android {
+
+namespace mock {
+
+MockGrallocAllocator::MockGrallocAllocator() = default;
+MockGrallocAllocator::~MockGrallocAllocator() = default;
+
+} // namespace mock
+} // namespace android
diff --git a/libs/ui/tests/mock/MockGrallocAllocator.h b/libs/ui/tests/mock/MockGrallocAllocator.h
new file mode 100644
index 0000000..22c80a4
--- /dev/null
+++ b/libs/ui/tests/mock/MockGrallocAllocator.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include <ui/Gralloc.h>
+
+namespace android {
+
+class GraphicBuffer;
+
+namespace mock {
+
+class MockGrallocAllocator : public GrallocAllocator {
+public:
+ MockGrallocAllocator();
+ ~MockGrallocAllocator() override;
+
+ MOCK_METHOD(bool, isLoaded, (), (const, override));
+ MOCK_METHOD(std::string, dumpDebugInfo, (), (const, override));
+ MOCK_METHOD(status_t, allocate,
+ (uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount,
+ uint64_t usage, uint32_t bufferCount, uint32_t* outStride,
+ buffer_handle_t* outBufferHandles),
+ (const, override));
+};
+
+} // namespace mock
+} // namespace android
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index ee8c344..90cc5c6 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -17,7 +17,7 @@
#define LOG_TAG "InputDispatcher"
#define ATRACE_TAG ATRACE_TAG_INPUT
-#define LOG_NDEBUG 0
+#define LOG_NDEBUG 1
// Log detailed debug messages about each inbound event notification to the dispatcher.
#define DEBUG_INBOUND_EVENT_DETAILS 0
@@ -245,7 +245,7 @@
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy)
: mPolicy(policy),
mPendingEvent(nullptr),
- mLastDropReason(DROP_REASON_NOT_DROPPED),
+ mLastDropReason(DropReason::NOT_DROPPED),
mAppSwitchSawKeyDown(false),
mAppSwitchDueTime(LONG_LONG_MAX),
mNextUnblockedEvent(nullptr),
@@ -374,11 +374,11 @@
// All events are eventually dequeued and processed this way, even if we intend to drop them.
ALOG_ASSERT(mPendingEvent != nullptr);
bool done = false;
- DropReason dropReason = DROP_REASON_NOT_DROPPED;
+ DropReason dropReason = DropReason::NOT_DROPPED;
if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) {
- dropReason = DROP_REASON_POLICY;
+ dropReason = DropReason::POLICY;
} else if (!mDispatchEnabled) {
- dropReason = DROP_REASON_DISABLED;
+ dropReason = DropReason::DISABLED;
}
if (mNextUnblockedEvent == mPendingEvent) {
@@ -390,14 +390,14 @@
ConfigurationChangedEntry* typedEntry =
static_cast<ConfigurationChangedEntry*>(mPendingEvent);
done = dispatchConfigurationChangedLocked(currentTime, typedEntry);
- dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped
+ dropReason = DropReason::NOT_DROPPED; // configuration changes are never dropped
break;
}
case EventEntry::TYPE_DEVICE_RESET: {
DeviceResetEntry* typedEntry = static_cast<DeviceResetEntry*>(mPendingEvent);
done = dispatchDeviceResetLocked(currentTime, typedEntry);
- dropReason = DROP_REASON_NOT_DROPPED; // device resets are never dropped
+ dropReason = DropReason::NOT_DROPPED; // device resets are never dropped
break;
}
@@ -407,15 +407,15 @@
if (isAppSwitchKeyEvent(typedEntry)) {
resetPendingAppSwitchLocked(true);
isAppSwitchDue = false;
- } else if (dropReason == DROP_REASON_NOT_DROPPED) {
- dropReason = DROP_REASON_APP_SWITCH;
+ } else if (dropReason == DropReason::NOT_DROPPED) {
+ dropReason = DropReason::APP_SWITCH;
}
}
- if (dropReason == DROP_REASON_NOT_DROPPED && isStaleEvent(currentTime, typedEntry)) {
- dropReason = DROP_REASON_STALE;
+ if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, typedEntry)) {
+ dropReason = DropReason::STALE;
}
- if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
- dropReason = DROP_REASON_BLOCKED;
+ if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) {
+ dropReason = DropReason::BLOCKED;
}
done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
break;
@@ -423,14 +423,14 @@
case EventEntry::TYPE_MOTION: {
MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
- if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {
- dropReason = DROP_REASON_APP_SWITCH;
+ if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) {
+ dropReason = DropReason::APP_SWITCH;
}
- if (dropReason == DROP_REASON_NOT_DROPPED && isStaleEvent(currentTime, typedEntry)) {
- dropReason = DROP_REASON_STALE;
+ if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, typedEntry)) {
+ dropReason = DropReason::STALE;
}
- if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
- dropReason = DROP_REASON_BLOCKED;
+ if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) {
+ dropReason = DropReason::BLOCKED;
}
done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
break;
@@ -442,7 +442,7 @@
}
if (done) {
- if (dropReason != DROP_REASON_NOT_DROPPED) {
+ if (dropReason != DropReason::NOT_DROPPED) {
dropInboundEventLocked(mPendingEvent, dropReason);
}
mLastDropReason = dropReason;
@@ -594,35 +594,36 @@
void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropReason) {
const char* reason;
switch (dropReason) {
- case DROP_REASON_POLICY:
+ case DropReason::POLICY:
#if DEBUG_INBOUND_EVENT_DETAILS
ALOGD("Dropped event because policy consumed it.");
#endif
reason = "inbound event was dropped because the policy consumed it";
break;
- case DROP_REASON_DISABLED:
- if (mLastDropReason != DROP_REASON_DISABLED) {
+ case DropReason::DISABLED:
+ if (mLastDropReason != DropReason::DISABLED) {
ALOGI("Dropped event because input dispatch is disabled.");
}
reason = "inbound event was dropped because input dispatch is disabled";
break;
- case DROP_REASON_APP_SWITCH:
+ case DropReason::APP_SWITCH:
ALOGI("Dropped event because of pending overdue app switch.");
reason = "inbound event was dropped because of pending overdue app switch";
break;
- case DROP_REASON_BLOCKED:
+ case DropReason::BLOCKED:
ALOGI("Dropped event because the current application is not responding and the user "
"has started interacting with a different application.");
reason = "inbound event was dropped because the current application is not responding "
"and the user has started interacting with a different application";
break;
- case DROP_REASON_STALE:
+ case DropReason::STALE:
ALOGI("Dropped event because it is stale.");
reason = "inbound event was dropped because it is stale";
break;
- default:
- ALOG_ASSERT(false);
+ case DropReason::NOT_DROPPED: {
+ LOG_ALWAYS_FATAL("Should not be dropping a NOT_DROPPED event");
return;
+ }
}
switch (entry->type) {
@@ -869,15 +870,15 @@
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
}
} else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) {
- if (*dropReason == DROP_REASON_NOT_DROPPED) {
- *dropReason = DROP_REASON_POLICY;
+ if (*dropReason == DropReason::NOT_DROPPED) {
+ *dropReason = DropReason::POLICY;
}
}
// Clean up if dropping the event.
- if (*dropReason != DROP_REASON_NOT_DROPPED) {
+ if (*dropReason != DropReason::NOT_DROPPED) {
setInjectionResult(entry,
- *dropReason == DROP_REASON_POLICY ? INPUT_EVENT_INJECTION_SUCCEEDED
+ *dropReason == DropReason::POLICY ? INPUT_EVENT_INJECTION_SUCCEEDED
: INPUT_EVENT_INJECTION_FAILED);
mReporter->reportDroppedKey(entry->sequenceNum);
return true;
@@ -926,9 +927,9 @@
}
// Clean up if dropping the event.
- if (*dropReason != DROP_REASON_NOT_DROPPED) {
+ if (*dropReason != DropReason::NOT_DROPPED) {
setInjectionResult(entry,
- *dropReason == DROP_REASON_POLICY ? INPUT_EVENT_INJECTION_SUCCEEDED
+ *dropReason == DropReason::POLICY ? INPUT_EVENT_INJECTION_SUCCEEDED
: INPUT_EVENT_INJECTION_FAILED);
return true;
}
@@ -3221,7 +3222,7 @@
!(info->layoutParamsFlags & InputWindowInfo::FLAG_NOT_TOUCHABLE) ||
!(info->layoutParamsFlags & InputWindowInfo::FLAG_NOT_FOCUSABLE);
if (canReceiveInput && !noInputChannel) {
- ALOGE("Window handle %s has no registered input channel",
+ ALOGV("Window handle %s has no registered input channel",
handle->getName().c_str());
}
continue;
@@ -3954,7 +3955,7 @@
return BAD_VALUE;
}
- const bool removed = removeByValue(mConnectionsByFd, connection);
+ [[maybe_unused]] const bool removed = removeByValue(mConnectionsByFd, connection);
ALOG_ASSERT(removed);
mInputChannelsByToken.erase(inputChannel->getToken());
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 1f906e4..9d22e2c 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -113,14 +113,13 @@
virtual status_t pilferPointers(const sp<IBinder>& token) override;
private:
-
- enum DropReason {
- DROP_REASON_NOT_DROPPED = 0,
- DROP_REASON_POLICY = 1,
- DROP_REASON_APP_SWITCH = 2,
- DROP_REASON_DISABLED = 3,
- DROP_REASON_BLOCKED = 4,
- DROP_REASON_STALE = 5,
+ enum class DropReason {
+ NOT_DROPPED,
+ POLICY,
+ APP_SWITCH,
+ DISABLED,
+ BLOCKED,
+ STALE,
};
sp<InputDispatcherPolicyInterface> mPolicy;
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 34603b9..c80a2dc 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -668,7 +668,7 @@
naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft;
naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop;
naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft;
- naturalPhysicalLeft = mViewport.deviceHeight - mViewport.physicalBottom;
+ naturalPhysicalLeft = mViewport.deviceHeight - naturalPhysicalWidth;
naturalPhysicalTop = mViewport.physicalLeft;
naturalDeviceWidth = mViewport.deviceHeight;
naturalDeviceHeight = mViewport.deviceWidth;
@@ -689,7 +689,7 @@
naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop;
naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft;
naturalPhysicalLeft = mViewport.physicalTop;
- naturalPhysicalTop = mViewport.deviceWidth - mViewport.physicalRight;
+ naturalPhysicalTop = mViewport.deviceWidth - naturalPhysicalHeight;
naturalDeviceWidth = mViewport.deviceHeight;
naturalDeviceHeight = mViewport.deviceWidth;
break;
@@ -2173,6 +2173,7 @@
// TODO: Adjust coverage coords?
float xTransformed = in.x, yTransformed = in.y;
mAffineTransform.applyTo(xTransformed, yTransformed);
+ rotateAndScale(xTransformed, yTransformed);
// Adjust X, Y, and coverage coords for surface orientation.
float x, y;
@@ -2180,8 +2181,8 @@
switch (mSurfaceOrientation) {
case DISPLAY_ORIENTATION_90:
- x = float(yTransformed - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
- y = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale + mXTranslate;
+ x = yTransformed + mYTranslate;
+ y = xTransformed + mXTranslate;
left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
right = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate;
@@ -2194,8 +2195,8 @@
}
break;
case DISPLAY_ORIENTATION_180:
- x = float(mRawPointerAxes.x.maxValue - xTransformed) * mXScale;
- y = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale + mYTranslate;
+ x = xTransformed + mXTranslate;
+ y = yTransformed + mYTranslate;
left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale;
right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale;
bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate;
@@ -2208,8 +2209,8 @@
}
break;
case DISPLAY_ORIENTATION_270:
- x = float(mRawPointerAxes.y.maxValue - yTransformed) * mYScale;
- y = float(xTransformed - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
+ x = yTransformed + mYTranslate;
+ y = xTransformed + mXTranslate;
left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale;
right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale;
bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
@@ -2222,8 +2223,8 @@
}
break;
default:
- x = float(xTransformed - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
- y = float(yTransformed - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
+ x = xTransformed + mXTranslate;
+ y = yTransformed + mYTranslate;
left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate;
bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate;
@@ -3617,13 +3618,34 @@
abortTouches(when, 0 /* policyFlags*/);
}
+void TouchInputMapper::rotateAndScale(float& x, float& y) {
+ switch (mSurfaceOrientation) {
+ case DISPLAY_ORIENTATION_90:
+ x = float(mRawPointerAxes.x.maxValue - x) * mXScale;
+ y = float(y - mRawPointerAxes.y.minValue) * mYScale;
+ break;
+ case DISPLAY_ORIENTATION_180:
+ x = float(mRawPointerAxes.x.maxValue - x) * mXScale;
+ y = float(mRawPointerAxes.y.maxValue - y) * mYScale;
+ break;
+ case DISPLAY_ORIENTATION_270:
+ x = float(x - mRawPointerAxes.x.minValue) * mXScale;
+ y = float(mRawPointerAxes.y.maxValue - y) * mYScale;
+ break;
+ default:
+ x = float(x - mRawPointerAxes.x.minValue) * mXScale;
+ y = float(y - mRawPointerAxes.y.minValue) * mYScale;
+ break;
+ }
+}
+
bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) {
- const float scaledX = x * mXScale;
- const float scaledY = y * mYScale;
+ float xTransformed = x, yTransformed = y;
+ rotateAndScale(xTransformed, yTransformed);
return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue &&
- scaledX >= mSurfaceLeft && scaledX <= mSurfaceLeft + mSurfaceWidth &&
+ xTransformed >= mSurfaceLeft && xTransformed <= mSurfaceLeft + mSurfaceWidth &&
y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue &&
- scaledY >= mSurfaceTop && scaledY <= mSurfaceTop + mSurfaceHeight;
+ yTransformed >= mSurfaceTop && yTransformed <= mSurfaceTop + mSurfaceHeight;
}
const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit(int32_t x, int32_t y) {
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index 89c017d..4b1c0cb 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -758,6 +758,7 @@
static void assignPointerIds(const RawState* last, RawState* current);
const char* modeToString(DeviceMode deviceMode);
+ void rotateAndScale(float& x, float& y);
};
} // namespace android
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index c4f8626..ada2266 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -15,6 +15,7 @@
"-Werror",
"-Wextra",
"-Wno-unused-parameter",
+ "-Wthread-safety",
],
shared_libs: [
"android.hardware.input.classifier@1.0",
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 31b1652..c1c9122 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -25,13 +25,18 @@
#include <TestInputListener.h>
#include <TouchInputMapper.h>
+#include <android-base/thread_annotations.h>
#include <gtest/gtest.h>
#include <inttypes.h>
#include <math.h>
-
namespace android {
+using std::chrono_literals::operator""ms;
+
+// Timeout for waiting for an expected event
+static constexpr std::chrono::duration WAIT_TIMEOUT = 100ms;
+
// An arbitrary time value.
static const nsecs_t ARBITRARY_TIME = 1234;
@@ -164,9 +169,13 @@
// --- FakeInputReaderPolicy ---
class FakeInputReaderPolicy : public InputReaderPolicyInterface {
+ std::mutex mLock;
+ std::condition_variable mDevicesChangedCondition;
+
InputReaderConfiguration mConfig;
KeyedVector<int32_t, sp<FakePointerController> > mPointerControllers;
- std::vector<InputDeviceInfo> mInputDevices;
+ std::vector<InputDeviceInfo> mInputDevices GUARDED_BY(mLock);
+ bool mInputDevicesChanged GUARDED_BY(mLock){false};
std::vector<DisplayViewport> mViewports;
TouchAffineTransformation transform;
@@ -177,6 +186,20 @@
FakeInputReaderPolicy() {
}
+ void assertInputDevicesChanged() {
+ std::unique_lock<std::mutex> lock(mLock);
+ base::ScopedLockAssertion assumeLocked(mLock);
+
+ const bool devicesChanged =
+ mDevicesChangedCondition.wait_for(lock, WAIT_TIMEOUT, [this]() REQUIRES(mLock) {
+ return mInputDevicesChanged;
+ });
+ if (!devicesChanged) {
+ FAIL() << "Timed out waiting for notifyInputDevicesChanged() to be called.";
+ }
+ mInputDevicesChanged = false;
+ }
+
virtual void clearViewports() {
mViewports.clear();
mConfig.setDisplayViewports(mViewports);
@@ -291,7 +314,10 @@
}
virtual void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) {
+ std::scoped_lock<std::mutex> lock(mLock);
mInputDevices = inputDevices;
+ mInputDevicesChanged = true;
+ mDevicesChangedCondition.notify_all();
}
virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const InputDeviceIdentifier&) {
@@ -342,9 +368,12 @@
}
};
+ std::mutex mLock;
+ std::condition_variable mEventsCondition;
+
KeyedVector<int32_t, Device*> mDevices;
std::vector<std::string> mExcludedDevices;
- List<RawEvent> mEvents;
+ List<RawEvent> mEvents GUARDED_BY(mLock);
std::unordered_map<int32_t /*deviceId*/, std::vector<TouchVideoFrame>> mVideoFrames;
public:
@@ -496,6 +525,7 @@
void enqueueEvent(nsecs_t when, int32_t deviceId, int32_t type,
int32_t code, int32_t value) {
+ std::scoped_lock<std::mutex> lock(mLock);
RawEvent event;
event.when = when;
event.deviceId = deviceId;
@@ -515,8 +545,14 @@
}
void assertQueueIsEmpty() {
- ASSERT_EQ(size_t(0), mEvents.size())
- << "Expected the event queue to be empty (fully consumed).";
+ std::unique_lock<std::mutex> lock(mLock);
+ base::ScopedLockAssertion assumeLocked(mLock);
+ const bool queueIsEmpty =
+ mEventsCondition.wait_for(lock, WAIT_TIMEOUT,
+ [this]() REQUIRES(mLock) { return mEvents.size() == 0; });
+ if (!queueIsEmpty) {
+ FAIL() << "Timed out waiting for EventHub queue to be emptied.";
+ }
}
private:
@@ -619,12 +655,14 @@
}
virtual size_t getEvents(int, RawEvent* buffer, size_t) {
+ std::scoped_lock<std::mutex> lock(mLock);
if (mEvents.empty()) {
return 0;
}
*buffer = *mEvents.begin();
mEvents.erase(mEvents.begin());
+ mEventsCondition.notify_all();
return 1;
}
@@ -877,11 +915,13 @@
KeyedVector<int32_t, int32_t> mScanCodeStates;
KeyedVector<int32_t, int32_t> mSwitchStates;
std::vector<int32_t> mSupportedKeyCodes;
- RawEvent mLastEvent;
- bool mConfigureWasCalled;
- bool mResetWasCalled;
- bool mProcessWasCalled;
+ std::mutex mLock;
+ std::condition_variable mStateChangedCondition;
+ bool mConfigureWasCalled GUARDED_BY(mLock);
+ bool mResetWasCalled GUARDED_BY(mLock);
+ bool mProcessWasCalled GUARDED_BY(mLock);
+ RawEvent mLastEvent GUARDED_BY(mLock);
std::optional<DisplayViewport> mViewport;
public:
@@ -903,20 +943,41 @@
}
void assertConfigureWasCalled() {
- ASSERT_TRUE(mConfigureWasCalled)
- << "Expected configure() to have been called.";
+ std::unique_lock<std::mutex> lock(mLock);
+ base::ScopedLockAssertion assumeLocked(mLock);
+ const bool configureCalled =
+ mStateChangedCondition.wait_for(lock, WAIT_TIMEOUT, [this]() REQUIRES(mLock) {
+ return mConfigureWasCalled;
+ });
+ if (!configureCalled) {
+ FAIL() << "Expected configure() to have been called.";
+ }
mConfigureWasCalled = false;
}
void assertResetWasCalled() {
- ASSERT_TRUE(mResetWasCalled)
- << "Expected reset() to have been called.";
+ std::unique_lock<std::mutex> lock(mLock);
+ base::ScopedLockAssertion assumeLocked(mLock);
+ const bool resetCalled =
+ mStateChangedCondition.wait_for(lock, WAIT_TIMEOUT, [this]() REQUIRES(mLock) {
+ return mResetWasCalled;
+ });
+ if (!resetCalled) {
+ FAIL() << "Expected reset() to have been called.";
+ }
mResetWasCalled = false;
}
void assertProcessWasCalled(RawEvent* outLastEvent = nullptr) {
- ASSERT_TRUE(mProcessWasCalled)
- << "Expected process() to have been called.";
+ std::unique_lock<std::mutex> lock(mLock);
+ base::ScopedLockAssertion assumeLocked(mLock);
+ const bool processCalled =
+ mStateChangedCondition.wait_for(lock, WAIT_TIMEOUT, [this]() REQUIRES(mLock) {
+ return mProcessWasCalled;
+ });
+ if (!processCalled) {
+ FAIL() << "Expected process() to have been called.";
+ }
if (outLastEvent) {
*outLastEvent = mLastEvent;
}
@@ -953,6 +1014,7 @@
}
virtual void configure(nsecs_t, const InputReaderConfiguration* config, uint32_t changes) {
+ std::scoped_lock<std::mutex> lock(mLock);
mConfigureWasCalled = true;
// Find the associated viewport if exist.
@@ -960,15 +1022,21 @@
if (displayPort && (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
mViewport = config->getDisplayViewportByPort(*displayPort);
}
+
+ mStateChangedCondition.notify_all();
}
virtual void reset(nsecs_t) {
+ std::scoped_lock<std::mutex> lock(mLock);
mResetWasCalled = true;
+ mStateChangedCondition.notify_all();
}
virtual void process(const RawEvent* rawEvent) {
+ std::scoped_lock<std::mutex> lock(mLock);
mLastEvent = *rawEvent;
mProcessWasCalled = true;
+ mStateChangedCondition.notify_all();
}
virtual int32_t getKeyCodeState(uint32_t, int32_t keyCode) {
@@ -1033,23 +1101,22 @@
}
}
- void setNextDevice(InputDevice* device) {
- mNextDevice = device;
- }
+ void setNextDevice(InputDevice* device) { mNextDevice = device; }
InputDevice* newDevice(int32_t deviceId, int32_t controllerNumber, const std::string& name,
- uint32_t classes, const std::string& location = "") {
+ uint32_t classes, const std::string& location = "") {
InputDeviceIdentifier identifier;
identifier.name = name;
identifier.location = location;
int32_t generation = deviceId + 1;
return new InputDevice(&mContext, deviceId, generation, controllerNumber, identifier,
- classes);
+ classes);
}
protected:
virtual InputDevice* createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
- const InputDeviceIdentifier& identifier, uint32_t classes) {
+ const InputDeviceIdentifier& identifier,
+ uint32_t classes) {
if (mNextDevice) {
InputDevice* device = mNextDevice;
mNextDevice = nullptr;
@@ -1281,7 +1348,8 @@
mFakeEventHub->finishDeviceScan();
mReader->loopOnce();
mReader->loopOnce();
- mFakeEventHub->assertQueueIsEmpty();
+ ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged());
+ ASSERT_NO_FATAL_FAILURE(mFakeEventHub->assertQueueIsEmpty());
}
void disableDevice(int32_t deviceId, InputDevice* device) {
@@ -1316,10 +1384,8 @@
ASSERT_NO_FATAL_FAILURE(addDevice(2, "ignored",
0, nullptr)); // no classes so device will be ignored
-
std::vector<InputDeviceInfo> inputDevices;
mReader->getInputDevices(inputDevices);
-
ASSERT_EQ(1U, inputDevices.size());
ASSERT_EQ(1, inputDevices[0].getId());
ASSERT_STREQ("keyboard", inputDevices[0].getIdentifier().name.c_str());
@@ -1345,7 +1411,7 @@
FakeInputMapper* mapper = new FakeInputMapper(device, AINPUT_SOURCE_KEYBOARD);
device->addMapper(mapper);
mReader->setNextDevice(device);
- addDevice(deviceId, "fake", deviceClass, nullptr);
+ ASSERT_NO_FATAL_FAILURE(addDevice(deviceId, "fake", deviceClass, nullptr));
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyConfigurationChangedWasCalled(nullptr));
@@ -1358,20 +1424,20 @@
disableDevice(deviceId, device);
mReader->loopOnce();
- mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime);
ASSERT_EQ(deviceId, resetArgs.deviceId);
ASSERT_EQ(device->isEnabled(), false);
disableDevice(deviceId, device);
mReader->loopOnce();
- mFakeListener->assertNotifyDeviceResetWasNotCalled();
- mFakeListener->assertNotifyConfigurationChangedWasNotCalled();
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasNotCalled());
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyConfigurationChangedWasNotCalled());
ASSERT_EQ(device->isEnabled(), false);
enableDevice(deviceId, device);
mReader->loopOnce();
- mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime);
ASSERT_EQ(deviceId, resetArgs.deviceId);
ASSERT_EQ(device->isEnabled(), true);
@@ -1529,7 +1595,7 @@
FakeInputMapper* mapper = new FakeInputMapper(device, AINPUT_SOURCE_KEYBOARD);
device->addMapper(mapper);
mReader->setNextDevice(device);
- addDevice(deviceId, "fake", deviceClass, nullptr);
+ ASSERT_NO_FATAL_FAILURE(addDevice(deviceId, "fake", deviceClass, nullptr));
NotifyDeviceResetArgs resetArgs;
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
@@ -1537,19 +1603,19 @@
disableDevice(deviceId, device);
mReader->loopOnce();
- mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
ASSERT_TRUE(prevSequenceNum < resetArgs.sequenceNum);
prevSequenceNum = resetArgs.sequenceNum;
enableDevice(deviceId, device);
mReader->loopOnce();
- mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
ASSERT_TRUE(prevSequenceNum < resetArgs.sequenceNum);
prevSequenceNum = resetArgs.sequenceNum;
disableDevice(deviceId, device);
mReader->loopOnce();
- mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
ASSERT_TRUE(prevSequenceNum < resetArgs.sequenceNum);
prevSequenceNum = resetArgs.sequenceNum;
}
@@ -1577,6 +1643,7 @@
DISPLAY_ORIENTATION_0, "local:1", hdmi1, ViewportType::VIEWPORT_EXTERNAL);
mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
mReader->loopOnce();
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyConfigurationChangedWasCalled());
// Device should only dispatch to the specified display.
ASSERT_EQ(deviceId, device->getId());
@@ -6614,20 +6681,41 @@
MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
addConfigurationProperty("touch.deviceType", "touchScreen");
prepareDisplay(DISPLAY_ORIENTATION_0);
- // Let surface be different from physical display.
- std::optional<DisplayViewport> internalViewport =
- mFakePolicy->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL);
- internalViewport->logicalLeft = internalViewport->physicalTop + 20;
- internalViewport->logicalTop = internalViewport->physicalRight + 20;
- internalViewport->logicalRight = internalViewport->physicalRight - 20;
- internalViewport->logicalBottom = internalViewport->physicalBottom - 20;
- mFakePolicy->updateViewport(internalViewport.value());
-
prepareAxes(POSITION);
addMapperAndConfigure(mapper);
- int32_t rawX = 10;
- int32_t rawY = 10;
+ // Touch on left-top area should work.
+ int32_t rawX = DISPLAY_WIDTH / 2 - 1;
+ int32_t rawY = DISPLAY_HEIGHT / 2 - 1;
+ processPosition(mapper, rawX, rawY);
+ processSync(mapper);
+
+ NotifyMotionArgs args;
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+
+ // Reset.
+ mapper->reset(ARBITRARY_TIME);
+
+ // Let logical display be different to physical display and rotate 90-degrees.
+ std::optional<DisplayViewport> internalViewport =
+ mFakePolicy->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL);
+ internalViewport->orientation = DISPLAY_ORIENTATION_90;
+ internalViewport->logicalLeft = 0;
+ internalViewport->logicalTop = 0;
+ internalViewport->logicalRight = DISPLAY_HEIGHT;
+ internalViewport->logicalBottom = DISPLAY_WIDTH / 2;
+
+ internalViewport->physicalLeft = DISPLAY_HEIGHT;
+ internalViewport->physicalTop = DISPLAY_WIDTH / 2;
+ internalViewport->physicalRight = DISPLAY_HEIGHT;
+ internalViewport->physicalBottom = DISPLAY_WIDTH;
+
+ internalViewport->deviceWidth = DISPLAY_HEIGHT;
+ internalViewport->deviceHeight = DISPLAY_WIDTH;
+ mFakePolicy->updateViewport(internalViewport.value());
+ configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+
+ // Display align to right-top after rotate 90-degrees, touch on left-top area should not work.
processPosition(mapper, rawX, rawY);
processSync(mapper);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
diff --git a/services/inputflinger/tests/TestInputListener.cpp b/services/inputflinger/tests/TestInputListener.cpp
index 3ee33f1..06b05ac 100644
--- a/services/inputflinger/tests/TestInputListener.cpp
+++ b/services/inputflinger/tests/TestInputListener.cpp
@@ -19,6 +19,15 @@
#include "TestInputListener.h"
+namespace {
+
+using std::chrono_literals::operator""ms;
+
+// Timeout for waiting for an expected event
+static constexpr std::chrono::duration WAIT_TIMEOUT = 5ms;
+
+} // namespace
+
namespace android {
// --- TestInputListener ---
@@ -29,87 +38,117 @@
void TestInputListener::assertNotifyConfigurationChangedWasCalled(
NotifyConfigurationChangedArgs* outEventArgs) {
- ASSERT_FALSE(mNotifyConfigurationChangedArgsQueue.empty())
- << "Expected notifyConfigurationChanged() to have been called.";
- if (outEventArgs) {
- *outEventArgs = *mNotifyConfigurationChangedArgsQueue.begin();
- }
- mNotifyConfigurationChangedArgsQueue.erase(mNotifyConfigurationChangedArgsQueue.begin());
+ ASSERT_NO_FATAL_FAILURE(
+ assertCalled<NotifyConfigurationChangedArgs>(outEventArgs,
+ "Expected notifyConfigurationChanged() "
+ "to have been called."));
}
void TestInputListener::assertNotifyConfigurationChangedWasNotCalled() {
- ASSERT_TRUE(mNotifyConfigurationChangedArgsQueue.empty())
- << "Expected notifyConfigurationChanged() to not have been called.";
+ ASSERT_NO_FATAL_FAILURE(assertNotCalled<NotifyConfigurationChangedArgs>(
+ "notifyConfigurationChanged() should not be called."));
}
void TestInputListener::assertNotifyDeviceResetWasCalled(
NotifyDeviceResetArgs* outEventArgs) {
- ASSERT_FALSE(mNotifyDeviceResetArgsQueue.empty())
- << "Expected notifyDeviceReset() to have been called.";
- if (outEventArgs) {
- *outEventArgs = *mNotifyDeviceResetArgsQueue.begin();
- }
- mNotifyDeviceResetArgsQueue.erase(mNotifyDeviceResetArgsQueue.begin());
+ ASSERT_NO_FATAL_FAILURE(
+ assertCalled<
+ NotifyDeviceResetArgs>(outEventArgs,
+ "Expected notifyDeviceReset() to have been called."));
}
void TestInputListener::assertNotifyDeviceResetWasNotCalled() {
- ASSERT_TRUE(mNotifyDeviceResetArgsQueue.empty())
- << "Expected notifyDeviceReset() to not have been called.";
+ ASSERT_NO_FATAL_FAILURE(
+ assertNotCalled<NotifyDeviceResetArgs>("notifyDeviceReset() should not be called."));
}
void TestInputListener::assertNotifyKeyWasCalled(NotifyKeyArgs* outEventArgs) {
- ASSERT_FALSE(mNotifyKeyArgsQueue.empty()) << "Expected notifyKey() to have been called.";
- if (outEventArgs) {
- *outEventArgs = *mNotifyKeyArgsQueue.begin();
- }
- mNotifyKeyArgsQueue.erase(mNotifyKeyArgsQueue.begin());
+ ASSERT_NO_FATAL_FAILURE(
+ assertCalled<NotifyKeyArgs>(outEventArgs, "Expected notifyKey() to have been called."));
}
void TestInputListener::assertNotifyKeyWasNotCalled() {
- ASSERT_TRUE(mNotifyKeyArgsQueue.empty()) << "Expected notifyKey() to not have been called.";
+ ASSERT_NO_FATAL_FAILURE(assertNotCalled<NotifyKeyArgs>("notifyKey() should not be called."));
}
void TestInputListener::assertNotifyMotionWasCalled(NotifyMotionArgs* outEventArgs) {
- ASSERT_FALSE(mNotifyMotionArgsQueue.empty()) << "Expected notifyMotion() to have been called.";
- if (outEventArgs) {
- *outEventArgs = *mNotifyMotionArgsQueue.begin();
- }
- mNotifyMotionArgsQueue.erase(mNotifyMotionArgsQueue.begin());
+ ASSERT_NO_FATAL_FAILURE(
+ assertCalled<NotifyMotionArgs>(outEventArgs,
+ "Expected notifyMotion() to have been called."));
}
void TestInputListener::assertNotifyMotionWasNotCalled() {
- ASSERT_TRUE(mNotifyMotionArgsQueue.empty())
- << "Expected notifyMotion() to not have been called.";
+ ASSERT_NO_FATAL_FAILURE(
+ assertNotCalled<NotifySwitchArgs>("notifySwitch() should not be called."));
}
void TestInputListener::assertNotifySwitchWasCalled(NotifySwitchArgs* outEventArgs) {
- ASSERT_FALSE(mNotifySwitchArgsQueue.empty())
- << "Expected notifySwitch() to have been called.";
- if (outEventArgs) {
- *outEventArgs = *mNotifySwitchArgsQueue.begin();
+ ASSERT_NO_FATAL_FAILURE(
+ assertCalled<NotifySwitchArgs>(outEventArgs,
+ "Expected notifySwitch() to have been called."));
+}
+
+template <class NotifyArgsType>
+void TestInputListener::assertCalled(NotifyArgsType* outEventArgs, std::string message) {
+ std::unique_lock<std::mutex> lock(mLock);
+ base::ScopedLockAssertion assumeLocked(mLock);
+
+ std::vector<NotifyArgsType>& queue = std::get<std::vector<NotifyArgsType>>(mQueues);
+ if (queue.empty()) {
+ const bool eventReceived =
+ mCondition.wait_for(lock, WAIT_TIMEOUT,
+ [&queue]() REQUIRES(mLock) { return !queue.empty(); });
+ if (!eventReceived) {
+ FAIL() << "Timed out waiting for event: " << message.c_str();
+ }
}
- mNotifySwitchArgsQueue.erase(mNotifySwitchArgsQueue.begin());
+ if (outEventArgs) {
+ *outEventArgs = *queue.begin();
+ }
+ queue.erase(queue.begin());
+}
+
+template <class NotifyArgsType>
+void TestInputListener::assertNotCalled(std::string message) {
+ std::unique_lock<std::mutex> lock(mLock);
+ base::ScopedLockAssertion assumeLocked(mLock);
+
+ std::vector<NotifyArgsType>& queue = std::get<std::vector<NotifyArgsType>>(mQueues);
+ const bool eventReceived = mCondition.wait_for(lock, WAIT_TIMEOUT, [&queue]() REQUIRES(mLock) {
+ return !queue.empty();
+ });
+ if (eventReceived) {
+ FAIL() << "Unexpected event: " << message.c_str();
+ }
+}
+
+template <class NotifyArgsType>
+void TestInputListener::notify(const NotifyArgsType* args) {
+ std::scoped_lock<std::mutex> lock(mLock);
+
+ std::vector<NotifyArgsType>& queue = std::get<std::vector<NotifyArgsType>>(mQueues);
+ queue.push_back(*args);
+ mCondition.notify_all();
}
void TestInputListener::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) {
- mNotifyConfigurationChangedArgsQueue.push_back(*args);
+ notify<NotifyConfigurationChangedArgs>(args);
}
void TestInputListener::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
- mNotifyDeviceResetArgsQueue.push_back(*args);
+ notify<NotifyDeviceResetArgs>(args);
}
void TestInputListener::notifyKey(const NotifyKeyArgs* args) {
- mNotifyKeyArgsQueue.push_back(*args);
+ notify<NotifyKeyArgs>(args);
}
void TestInputListener::notifyMotion(const NotifyMotionArgs* args) {
- mNotifyMotionArgsQueue.push_back(*args);
+ notify<NotifyMotionArgs>(args);
}
void TestInputListener::notifySwitch(const NotifySwitchArgs* args) {
- mNotifySwitchArgsQueue.push_back(*args);
- }
-
+ notify<NotifySwitchArgs>(args);
+}
} // namespace android
diff --git a/services/inputflinger/tests/TestInputListener.h b/services/inputflinger/tests/TestInputListener.h
index 085d343..945e2ea 100644
--- a/services/inputflinger/tests/TestInputListener.h
+++ b/services/inputflinger/tests/TestInputListener.h
@@ -17,6 +17,7 @@
#ifndef _UI_TEST_INPUT_LISTENER_H
#define _UI_TEST_INPUT_LISTENER_H
+#include <android-base/thread_annotations.h>
#include <gtest/gtest.h>
#include "InputListener.h"
@@ -25,13 +26,6 @@
// --- TestInputListener ---
class TestInputListener : public InputListenerInterface {
-private:
- std::vector<NotifyConfigurationChangedArgs> mNotifyConfigurationChangedArgsQueue;
- std::vector<NotifyDeviceResetArgs> mNotifyDeviceResetArgsQueue;
- std::vector<NotifyKeyArgs> mNotifyKeyArgsQueue;
- std::vector<NotifyMotionArgs> mNotifyMotionArgsQueue;
- std::vector<NotifySwitchArgs> mNotifySwitchArgsQueue;
-
protected:
virtual ~TestInputListener();
@@ -58,15 +52,34 @@
void assertNotifySwitchWasCalled(NotifySwitchArgs* outEventArgs = nullptr);
private:
- virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);
+ template <class NotifyArgsType>
+ void assertCalled(NotifyArgsType* outEventArgs, std::string message);
- virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);
+ template <class NotifyArgsType>
+ void assertNotCalled(std::string message);
- virtual void notifyKey(const NotifyKeyArgs* args);
+ template <class NotifyArgsType>
+ void notify(const NotifyArgsType* args);
- virtual void notifyMotion(const NotifyMotionArgs* args);
+ virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
- virtual void notifySwitch(const NotifySwitchArgs* args);
+ virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
+
+ virtual void notifyKey(const NotifyKeyArgs* args) override;
+
+ virtual void notifyMotion(const NotifyMotionArgs* args) override;
+
+ virtual void notifySwitch(const NotifySwitchArgs* args) override;
+
+ std::mutex mLock;
+ std::condition_variable mCondition;
+
+ std::tuple<std::vector<NotifyConfigurationChangedArgs>, //
+ std::vector<NotifyDeviceResetArgs>, //
+ std::vector<NotifyKeyArgs>, //
+ std::vector<NotifyMotionArgs>, //
+ std::vector<NotifySwitchArgs>> //
+ mQueues GUARDED_BY(mLock);
};
} // namespace android
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index b500ad3..a25709c 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -61,7 +61,7 @@
mTextureName(args.textureName),
mCompositionLayer{mFlinger->getCompositionEngine().createLayer(
compositionengine::LayerCreationArgs{this})} {
- ALOGV("Creating Layer %s", args.name.string());
+ ALOGV("Creating Layer %s", getDebugName());
mPremultipliedAlpha = !(args.flags & ISurfaceComposerClient::eNonPremultiplied);
@@ -107,11 +107,8 @@
}
bool BufferLayer::isVisible() const {
- bool visible = !(isHiddenByPolicy()) && getAlpha() > 0.0f &&
+ return !isHiddenByPolicy() && getAlpha() > 0.0f &&
(mBufferInfo.mBuffer != nullptr || mSidebandStream != nullptr);
- mFlinger->mScheduler->setLayerVisibility(mSchedulerLayerHandle, visible);
-
- return visible;
}
bool BufferLayer::isFixedSize() const {
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index d80a70e..c24cdaa 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -62,7 +62,7 @@
std::vector<OccupancyTracker::Segment> history;
status_t result = mConsumer->getOccupancyHistory(forceFlush, &history);
if (result != NO_ERROR) {
- ALOGW("[%s] Failed to obtain occupancy history (%d)", mName.string(), result);
+ ALOGW("[%s] Failed to obtain occupancy history (%d)", getDebugName(), result);
return {};
}
return history;
@@ -110,7 +110,7 @@
ALOGW_IF(!isPlausible,
"[%s] Timestamp %" PRId64 " seems implausible "
"relative to expectedPresent %" PRId64,
- mName.string(), addedTime, expectedPresentTime);
+ getDebugName(), addedTime, expectedPresentTime);
const bool isDue = addedTime < expectedPresentTime;
return isDue || !isPlausible;
@@ -225,7 +225,7 @@
bool queuedBuffer = false;
const int32_t layerID = getSequence();
LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
- getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode,
+ getProducerStickyTransform() != 0, mName, mOverrideScalingMode,
getTransformToDisplayInverse());
if (isRemovedFromCurrentState()) {
@@ -372,19 +372,25 @@
// Interface implementation for BufferLayerConsumer::ContentsChangedListener
// -----------------------------------------------------------------------
+void BufferQueueLayer::onFrameDequeued(const uint64_t bufferId) {
+ const int32_t layerID = getSequence();
+ mFlinger->mFrameTracer->traceTimestamp(layerID, bufferId, FrameTracer::UNSPECIFIED_FRAME_NUMBER,
+ systemTime(), FrameTracer::FrameEvent::DEQUEUE, 3000);
+}
+
void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
const int32_t layerID = getSequence();
mFlinger->mFrameTracer->traceNewLayer(layerID, getName().c_str());
mFlinger->mFrameTracer->traceTimestamp(layerID, item.mGraphicBuffer->getId(), item.mFrameNumber,
- systemTime(), FrameTracer::FrameEvent::POST);
+ systemTime(), FrameTracer::FrameEvent::QUEUE);
ATRACE_CALL();
// Add this buffer from our internal queue tracker
{ // Autolock scope
if (mFlinger->mUseSmart90ForVideo) {
const nsecs_t presentTime = item.mIsAutoTimestamp ? 0 : item.mTimestamp;
- mFlinger->mScheduler->addLayerPresentTimeAndHDR(mSchedulerLayerHandle, presentTime,
- item.mHdrMetadata.validTypes != 0);
+ mFlinger->mScheduler->recordLayerHistory(this, presentTime,
+ item.mHdrMetadata.validTypes != 0);
}
Mutex::Autolock lock(mQueueItemLock);
@@ -398,7 +404,7 @@
while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500));
if (result != NO_ERROR) {
- ALOGE("[%s] Timed out waiting on callback", mName.string());
+ ALOGE("[%s] Timed out waiting on callback", getDebugName());
}
}
@@ -426,7 +432,7 @@
while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500));
if (result != NO_ERROR) {
- ALOGE("[%s] Timed out waiting on callback", mName.string());
+ ALOGE("[%s] Timed out waiting on callback", getDebugName());
}
}
@@ -459,12 +465,14 @@
// Creates a custom BufferQueue for SurfaceFlingerConsumer to use
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer, true);
- mProducer = new MonitoredProducer(producer, mFlinger, this);
- mConsumer = new BufferLayerConsumer(consumer, mFlinger->getRenderEngine(), mTextureName, this);
+ mFlinger->getFactory().createBufferQueue(&producer, &consumer, true);
+ mProducer = mFlinger->getFactory().createMonitoredProducer(producer, mFlinger, this);
+ mConsumer =
+ mFlinger->getFactory().createBufferLayerConsumer(consumer, mFlinger->getRenderEngine(),
+ mTextureName, this);
mConsumer->setConsumerUsageBits(getEffectiveUsage(0));
mConsumer->setContentsChangedListener(this);
- mConsumer->setName(mName);
+ mConsumer->setName(String8(mName.data(), mName.size()));
// BufferQueueCore::mMaxDequeuedBufferCount is default to 1
if (!mFlinger->isLayerTripleBufferingDisabled()) {
@@ -527,9 +535,7 @@
}
sp<Layer> BufferQueueLayer::createClone() {
- const String8 name = mName + " (Mirror)";
- LayerCreationArgs args =
- LayerCreationArgs(mFlinger.get(), nullptr, name, 0, 0, 0, LayerMetadata());
+ LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0, LayerMetadata());
args.textureName = mTextureName;
sp<BufferQueueLayer> layer = mFlinger->getFactory().createBufferQueueLayer(args);
layer->setInitialValuesForClone(this);
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index f3e8a19..95e0b10 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -93,6 +93,7 @@
void onFrameAvailable(const BufferItem& item) override;
void onFrameReplaced(const BufferItem& item) override;
void onSidebandStreamChanged() override;
+ void onFrameDequeued(const uint64_t bufferId) override;
// -----------------------------------------------------------------------
public:
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 75fc0e9..5768edd 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -103,12 +103,15 @@
}
}
-void BufferStateLayer::setTransformHint(uint32_t /*orientation*/) const {
- // TODO(marissaw): send the transform hint to buffer owner
- return;
+void BufferStateLayer::setTransformHint(uint32_t orientation) const {
+ mTransformHint = orientation;
}
void BufferStateLayer::releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) {
+ for (const auto& handle : mDrawingState.callbackHandles) {
+ handle->transformHint = mTransformHint;
+ }
+
mFlinger->getTransactionCompletedThread().finalizePendingCallbackHandles(
mDrawingState.callbackHandles);
@@ -136,7 +139,7 @@
return;
}
mPendingStates.push_back(mCurrentState);
- ATRACE_INT(mTransactionName.string(), mPendingStates.size());
+ ATRACE_INT(mTransactionName.c_str(), mPendingStates.size());
}
bool BufferStateLayer::applyPendingStates(Layer::State* stateToCommit) {
@@ -246,8 +249,8 @@
if (mFlinger->mUseSmart90ForVideo) {
const nsecs_t presentTime = (desiredPresentTime == -1) ? 0 : desiredPresentTime;
- mFlinger->mScheduler->addLayerPresentTimeAndHDR(mSchedulerLayerHandle, presentTime,
- mCurrentState.hdrMetadata.validTypes != 0);
+ mFlinger->mScheduler->recordLayerHistory(this, presentTime,
+ mCurrentState.hdrMetadata.validTypes != 0);
}
return true;
@@ -479,7 +482,7 @@
(s.active.w != bufferWidth || s.active.h != bufferHeight)) {
ALOGE("[%s] rejecting buffer: "
"bufferWidth=%d, bufferHeight=%d, front.active.{w=%d, h=%d}",
- mName.string(), bufferWidth, bufferHeight, s.active.w, s.active.h);
+ getDebugName(), bufferWidth, bufferHeight, s.active.w, s.active.h);
mFlinger->mTimeStats->removeTimeRecord(layerID, mFrameNumber);
return BAD_VALUE;
}
@@ -669,9 +672,7 @@
}
sp<Layer> BufferStateLayer::createClone() {
- const String8 name = mName + " (Mirror)";
- LayerCreationArgs args =
- LayerCreationArgs(mFlinger.get(), nullptr, name, 0, 0, 0, LayerMetadata());
+ LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0, LayerMetadata());
args.textureName = mTextureName;
sp<BufferStateLayer> layer = mFlinger->getFactory().createBufferStateLayer(args);
layer->mHwcSlotGenerator = mHwcSlotGenerator;
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 3dfe76c..289bb17 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -149,6 +149,8 @@
bool mReleasePreviousBuffer = false;
nsecs_t mCallbackHandleAcquireTime = -1;
+ mutable uint32_t mTransformHint = 0;
+
// TODO(marissaw): support sticky transform for LEGACY camera mode
class HwcSlotGenerator : public ClientCache::ErasedRecipient {
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 172d445..8bfa569 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -108,13 +108,11 @@
}
sp<Layer> ColorLayer::createClone() {
- String8 name = mName + " (Mirror)";
sp<ColorLayer> layer = mFlinger->getFactory().createColorLayer(
- LayerCreationArgs(mFlinger.get(), nullptr, name, 0, 0, 0, LayerMetadata()));
+ LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0,
+ LayerMetadata()));
layer->setInitialValuesForClone(this);
return layer;
}
-// ---------------------------------------------------------------------------
-
-}; // namespace android
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 721e953..ce0222c 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -326,6 +326,9 @@
writeOutputIndependentPerFrameStateToHWC(hwcLayer.get(), outputIndependentState);
writeCompositionTypeToHWC(hwcLayer.get(), requestedCompositionType);
+
+ // Always set the layer color after setting the composition type.
+ writeSolidColorStateToHWC(hwcLayer.get(), outputIndependentState);
}
void OutputLayer::writeOutputDependentGeometryStateToHWC(
@@ -435,7 +438,7 @@
// Content-specific per-frame state
switch (outputIndependentState.compositionType) {
case Hwc2::IComposerClient::Composition::SOLID_COLOR:
- writeSolidColorStateToHWC(hwcLayer, outputIndependentState);
+ // For compatibility, should be written AFTER the composition type.
break;
case Hwc2::IComposerClient::Composition::SIDEBAND:
writeSidebandStateToHWC(hwcLayer, outputIndependentState);
@@ -453,6 +456,10 @@
void OutputLayer::writeSolidColorStateToHWC(HWC2::Layer* hwcLayer,
const LayerFECompositionState& outputIndependentState) {
+ if (outputIndependentState.compositionType != Hwc2::IComposerClient::Composition::SOLID_COLOR) {
+ return;
+ }
+
hwc_color_t color = {static_cast<uint8_t>(std::round(255.0f * outputIndependentState.color.r)),
static_cast<uint8_t>(std::round(255.0f * outputIndependentState.color.g)),
static_cast<uint8_t>(std::round(255.0f * outputIndependentState.color.b)),
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index a338784..88acd04 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -33,6 +33,7 @@
namespace {
using testing::_;
+using testing::InSequence;
using testing::Return;
using testing::ReturnRef;
using testing::StrictMock;
@@ -769,8 +770,13 @@
mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
expectPerFrameCommonCalls();
- expectSetColorCall();
+
+ // Setting the composition type should happen before setting the color. We
+ // check this in this test only by setting up an testing::InSeqeuence
+ // instance before setting up the two expectations.
+ InSequence s;
expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::SOLID_COLOR);
+ expectSetColorCall();
mOutputLayer.writeStateToHWC(false);
}
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index e58e6f4..ab664be 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -31,10 +31,11 @@
}
sp<Layer> ContainerLayer::createClone() {
- String8 name = mName + " (Mirror)";
sp<ContainerLayer> layer = mFlinger->getFactory().createContainerLayer(
- LayerCreationArgs(mFlinger.get(), nullptr, name, 0, 0, 0, LayerMetadata()));
+ LayerCreationArgs(mFlinger.get(), nullptr, mName + " (Mirror)", 0, 0, 0,
+ LayerMetadata()));
layer->setInitialValuesForClone(this);
return layer;
}
+
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index acddc42..aef1c75 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -95,6 +95,7 @@
// assume NO_RESOURCES when Status::isOk returns false
constexpr Error kDefaultError = Error::NO_RESOURCES;
+constexpr V2_4::Error kDefaultError_2_4 = V2_4::Error::NO_RESOURCES;
template<typename T, typename U>
T unwrapRet(Return<T>& ret, const U& default_val)
@@ -177,7 +178,7 @@
if (sp<IComposer> composer_2_4 = IComposer::castFrom(mComposer)) {
composer_2_4->createClient_2_4([&](const auto& tmpError, const auto& tmpClient) {
- if (tmpError == Error::NONE) {
+ if (tmpError == V2_4::Error::NONE) {
mClient = tmpClient;
mClient_2_2 = tmpClient;
mClient_2_3 = tmpClient;
@@ -1172,12 +1173,12 @@
return Error::UNSUPPORTED;
}
- Error error = kDefaultError;
+ V2_4::Error error = kDefaultError_2_4;
if (mClient_2_4) {
mClient_2_4->getDisplayCapabilities_2_4(display,
[&](const auto& tmpError, const auto& tmpCaps) {
error = tmpError;
- if (error != Error::NONE) {
+ if (error != V2_4::Error::NONE) {
return;
}
*outCapabilities = tmpCaps;
@@ -1185,8 +1186,8 @@
} else {
mClient_2_3
->getDisplayCapabilities(display, [&](const auto& tmpError, const auto& tmpCaps) {
- error = tmpError;
- if (error != Error::NONE) {
+ error = static_cast<V2_4::Error>(tmpError);
+ if (error != V2_4::Error::NONE) {
return;
}
@@ -1196,7 +1197,7 @@
});
}
- return error;
+ return static_cast<Error>(error);
}
Error Composer::getDisplayConnectionType(Display display,
@@ -1205,17 +1206,17 @@
return Error::UNSUPPORTED;
}
- Error error = kDefaultError;
+ V2_4::Error error = kDefaultError_2_4;
mClient_2_4->getDisplayConnectionType(display, [&](const auto& tmpError, const auto& tmpType) {
error = tmpError;
- if (error != Error::NONE) {
+ if (error != V2_4::Error::NONE) {
return;
}
*outType = tmpType;
});
- return error;
+ return static_cast<V2_1::Error>(error);
}
CommandReader::~CommandReader()
diff --git a/services/surfaceflinger/EventLog/EventLog.cpp b/services/surfaceflinger/EventLog/EventLog.cpp
index 365a0bd..a532fc1 100644
--- a/services/surfaceflinger/EventLog/EventLog.cpp
+++ b/services/surfaceflinger/EventLog/EventLog.cpp
@@ -17,13 +17,10 @@
#include <stdio.h>
#include <stdlib.h>
#include <log/log.h>
-#include <utils/String8.h>
#include "EventLog.h"
-// ---------------------------------------------------------------------------
namespace android {
-// ---------------------------------------------------------------------------
ANDROID_SINGLETON_STATIC_INSTANCE(EventLog)
@@ -31,11 +28,11 @@
EventLog::EventLog() {
}
-void EventLog::doLogFrameDurations(const String8& window,
- const int32_t* durations, size_t numDurations) {
+void EventLog::doLogFrameDurations(const std::string_view& name, const int32_t* durations,
+ size_t numDurations) {
EventLog::TagBuffer buffer(LOGTAG_SF_FRAME_DUR);
buffer.startList(1 + numDurations);
- buffer.writeString8(window);
+ buffer.writeString(name);
for (size_t i = 0; i < numDurations; i++) {
buffer.writeInt32(durations[i]);
}
@@ -43,10 +40,9 @@
buffer.log();
}
-void EventLog::logFrameDurations(const String8& window,
- const int32_t* durations, size_t numDurations) {
- EventLog::getInstance().doLogFrameDurations(window, durations,
- numDurations);
+void EventLog::logFrameDurations(const std::string_view& name, const int32_t* durations,
+ size_t numDurations) {
+ EventLog::getInstance().doLogFrameDurations(name, durations, numDurations);
}
// ---------------------------------------------------------------------------
@@ -113,9 +109,9 @@
mPos += needed;
}
-void EventLog::TagBuffer::writeString8(const String8& value) {
+void EventLog::TagBuffer::writeString(const std::string_view& value) {
if (mOverflow) return;
- const int32_t stringLen = value.length();
+ const size_t stringLen = value.length();
const size_t needed = 1 + sizeof(int32_t) + stringLen;
if (mPos + needed > STORAGE_MAX_SIZE) {
mOverflow = true;
@@ -123,11 +119,8 @@
}
mStorage[mPos + 0] = EVENT_TYPE_STRING;
memcpy(&mStorage[mPos + 1], &stringLen, sizeof(int32_t));
- memcpy(&mStorage[mPos + 5], value.string(), stringLen);
+ memcpy(&mStorage[mPos + 5], value.data(), stringLen);
mPos += needed;
}
-// ---------------------------------------------------------------------------
-}// namespace android
-
-// ---------------------------------------------------------------------------
+} // namespace android
diff --git a/services/surfaceflinger/EventLog/EventLog.h b/services/surfaceflinger/EventLog/EventLog.h
index efc5d70..ee3587e 100644
--- a/services/surfaceflinger/EventLog/EventLog.h
+++ b/services/surfaceflinger/EventLog/EventLog.h
@@ -14,24 +14,21 @@
* limitations under the License.
*/
-#include <stdint.h>
+#pragma once
+
#include <utils/Errors.h>
#include <utils/Singleton.h>
-#ifndef ANDROID_SF_EVENTLOG_H
-#define ANDROID_SF_EVENTLOG_H
+#include <cstdint>
+#include <string_view>
-// ---------------------------------------------------------------------------
namespace android {
-// ---------------------------------------------------------------------------
-
-class String8;
class EventLog : public Singleton<EventLog> {
public:
- static void logFrameDurations(const String8& window,
- const int32_t* durations, size_t numDurations);
+ static void logFrameDurations(const std::string_view& name, const int32_t* durations,
+ size_t numDurations);
protected:
EventLog();
@@ -54,18 +51,13 @@
public:
explicit TagBuffer(int32_t tag);
- // starts list of items
void startList(int8_t count);
- // terminates the list
void endList();
- // write a 32-bit integer
- void writeInt32(int32_t value);
- // write a 64-bit integer
- void writeInt64(int64_t value);
- // write a C string
- void writeString8(const String8& value);
- // outputs the the buffer to the log
+ void writeInt32(int32_t);
+ void writeInt64(int64_t);
+ void writeString(const std::string_view&);
+
void log();
};
@@ -74,12 +66,8 @@
EventLog& operator =(const EventLog&);
enum { LOGTAG_SF_FRAME_DUR = 60100 };
- void doLogFrameDurations(const String8& window, const int32_t* durations,
- size_t numDurations);
+ void doLogFrameDurations(const std::string_view& name, const int32_t* durations,
+ size_t numDurations);
};
-// ---------------------------------------------------------------------------
-}// namespace android
-// ---------------------------------------------------------------------------
-
-#endif /* ANDROID_SF_EVENTLOG_H */
+} // namespace android
diff --git a/services/surfaceflinger/FrameTracer/FrameTracer.cpp b/services/surfaceflinger/FrameTracer/FrameTracer.cpp
index 006dbfe..3a0408e 100644
--- a/services/surfaceflinger/FrameTracer/FrameTracer.cpp
+++ b/services/surfaceflinger/FrameTracer/FrameTracer.cpp
@@ -133,7 +133,9 @@
packet->set_timestamp(timestamp);
auto* event = packet->set_graphics_frame_event()->set_buffer_event();
event->set_buffer_id(static_cast<uint32_t>(bufferID));
- event->set_frame_number(frameNumber);
+ if (frameNumber != UNSPECIFIED_FRAME_NUMBER) {
+ event->set_frame_number(frameNumber);
+ }
event->set_type(type);
if (mTraceTracker.find(layerID) != mTraceTracker.end() &&
diff --git a/services/surfaceflinger/FrameTracer/FrameTracer.h b/services/surfaceflinger/FrameTracer/FrameTracer.h
index d4dfab9..e91a750 100644
--- a/services/surfaceflinger/FrameTracer/FrameTracer.h
+++ b/services/surfaceflinger/FrameTracer/FrameTracer.h
@@ -33,6 +33,8 @@
virtual void OnStop(const StopArgs&) override{};
};
+ static const uint64_t UNSPECIFIED_FRAME_NUMBER = std::numeric_limits<uint64_t>::max();
+
using FrameEvent = perfetto::protos::pbzero::GraphicsFrameEvent;
~FrameTracer() = default;
diff --git a/services/surfaceflinger/FrameTracker.cpp b/services/surfaceflinger/FrameTracker.cpp
index f4cc49b..a6e511e 100644
--- a/services/surfaceflinger/FrameTracker.cpp
+++ b/services/surfaceflinger/FrameTracker.cpp
@@ -21,7 +21,6 @@
#include <android-base/stringprintf.h>
#include <android/log.h>
-#include <utils/String8.h>
#include <ui/FrameStats.h>
@@ -139,7 +138,7 @@
}
}
-void FrameTracker::logAndResetStats(const String8& name) {
+void FrameTracker::logAndResetStats(const std::string_view& name) {
Mutex::Autolock lock(mMutex);
logStatsLocked(name);
resetFrameCountersLocked();
@@ -217,7 +216,7 @@
}
}
-void FrameTracker::logStatsLocked(const String8& name) const {
+void FrameTracker::logStatsLocked(const std::string_view& name) const {
for (int i = 0; i < NUM_FRAME_BUCKETS; i++) {
if (mNumFrames[i] > 0) {
EventLog::logFrameDurations(name, mNumFrames, NUM_FRAME_BUCKETS);
diff --git a/services/surfaceflinger/FrameTracker.h b/services/surfaceflinger/FrameTracker.h
index 555dcc1..35382be 100644
--- a/services/surfaceflinger/FrameTracker.h
+++ b/services/surfaceflinger/FrameTracker.h
@@ -14,21 +14,18 @@
* limitations under the License.
*/
-#ifndef ANDROID_FRAMETRACKER_H
-#define ANDROID_FRAMETRACKER_H
+#pragma once
#include <ui/FenceTime.h>
-
-#include <stddef.h>
-
#include <utils/Mutex.h>
-#include <utils/Timers.h>
#include <utils/RefBase.h>
+#include <utils/Timers.h>
+
+#include <cstddef>
+#include <string_view>
namespace android {
-class String8;
-
// FrameTracker tracks information about the most recently rendered frames. It
// uses a circular buffer of frame records, and is *NOT* thread-safe -
// mutexing must be done at a higher level if multi-threaded access is
@@ -87,7 +84,7 @@
// logAndResetStats dumps the current statistics to the binary event log
// and then resets the accumulated statistics to their initial values.
- void logAndResetStats(const String8& name);
+ void logAndResetStats(const std::string_view& name);
// dumpStats dump appends the current frame display time history to the result string.
void dumpStats(std::string& result) const;
@@ -123,7 +120,7 @@
void resetFrameCountersLocked();
// logStatsLocked dumps the current statistics to the binary event log.
- void logStatsLocked(const String8& name) const;
+ void logStatsLocked(const std::string_view& name) const;
// isFrameValidLocked returns true if the data for the given frame index is
// valid and has all arrived (i.e. there are no oustanding fences).
@@ -160,6 +157,4 @@
mutable Mutex mMutex;
};
-}
-
-#endif // ANDROID_FRAMETRACKER_H
+} // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 7065460..e19b79b 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -83,8 +83,6 @@
if (args.flags & ISurfaceComposerClient::eOpaque) layerFlags |= layer_state_t::eLayerOpaque;
if (args.flags & ISurfaceComposerClient::eSecure) layerFlags |= layer_state_t::eLayerSecure;
- mTransactionName = String8("TX - ") + mName;
-
mCurrentState.active_legacy.w = args.w;
mCurrentState.active_legacy.h = args.h;
mCurrentState.flags = layerFlags;
@@ -120,10 +118,9 @@
mFrameEventHistory.initializeCompositorTiming(compositorTiming);
mFrameTracker.setDisplayRefreshPeriod(compositorTiming.interval);
- mSchedulerLayerHandle = mFlinger->mScheduler->registerLayer(mName.c_str(), mWindowType);
mCallingPid = args.callingPid;
mCallingUid = args.callingUid;
- mFlinger->onLayerCreated();
+ mFlinger->onLayerCreated(this);
}
Layer::~Layer() {
@@ -137,11 +134,11 @@
}
LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, const sp<Client>& client,
- const String8& name, uint32_t w, uint32_t h, uint32_t flags,
+ std::string name, uint32_t w, uint32_t h, uint32_t flags,
LayerMetadata metadata)
: flinger(flinger),
client(client),
- name(name),
+ name(std::move(name)),
w(w),
h(h),
flags(flags),
@@ -235,10 +232,6 @@
// set-up
// ---------------------------------------------------------------------------
-const String8& Layer::getName() const {
- return mName;
-}
-
bool Layer::getPremultipledAlpha() const {
return mPremultipliedAlpha;
}
@@ -523,7 +516,7 @@
}
const char* Layer::getDebugName() const {
- return mName.string();
+ return mName.c_str();
}
// ---------------------------------------------------------------------------
@@ -614,7 +607,7 @@
if (mCurrentState.barrierLayer_legacy != nullptr && !isRemovedFromCurrentState()) {
sp<Layer> barrierLayer = mCurrentState.barrierLayer_legacy.promote();
if (barrierLayer == nullptr) {
- ALOGE("[%s] Unable to promote barrier Layer.", mName.string());
+ ALOGE("[%s] Unable to promote barrier Layer.", getDebugName());
// If we can't promote the layer we are intended to wait on,
// then it is expired or otherwise invalid. Allow this transaction
// to be applied as per normal (no synchronization).
@@ -638,7 +631,7 @@
mFlinger->setTransactionFlags(eTraversalNeeded);
}
mPendingStates.push_back(mCurrentState);
- ATRACE_INT(mTransactionName.string(), mPendingStates.size());
+ ATRACE_INT(mTransactionName.c_str(), mPendingStates.size());
}
void Layer::popPendingState(State* stateToCommit) {
@@ -646,7 +639,7 @@
*stateToCommit = mPendingStates[0];
mPendingStates.removeAt(0);
- ATRACE_INT(mTransactionName.string(), mPendingStates.size());
+ ATRACE_INT(mTransactionName.c_str(), mPendingStates.size());
}
bool Layer::applyPendingStates(State* stateToCommit) {
@@ -657,7 +650,7 @@
// If we don't have a sync point for this, apply it anyway. It
// will be visually wrong, but it should keep us from getting
// into too much trouble.
- ALOGE("[%s] No local sync point found", mName.string());
+ ALOGE("[%s] No local sync point found", getDebugName());
popPendingState(stateToCommit);
stateUpdateAvailable = true;
continue;
@@ -665,7 +658,7 @@
if (mRemoteSyncPoints.front()->getFrameNumber() !=
mPendingStates[0].frameNumber_legacy) {
- ALOGE("[%s] Unexpected sync point frame number found", mName.string());
+ ALOGE("[%s] Unexpected sync point frame number found", getDebugName());
// Signal our end of the sync point and then dispose of it
mRemoteSyncPoints.front()->setTransactionApplied();
@@ -717,7 +710,7 @@
" requested={ wh={%4u,%4u} }}\n"
" drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
" requested={ wh={%4u,%4u} }}\n",
- this, getName().string(), getBufferTransform(), getEffectiveScalingMode(),
+ this, getName().c_str(), getBufferTransform(), getEffectiveScalingMode(),
stateToCommit->active_legacy.w, stateToCommit->active_legacy.h,
stateToCommit->crop_legacy.left, stateToCommit->crop_legacy.top,
stateToCommit->crop_legacy.right, stateToCommit->crop_legacy.bottom,
@@ -999,9 +992,10 @@
if (!mCurrentState.bgColorLayer && alpha != 0) {
// create background color layer if one does not yet exist
uint32_t flags = ISurfaceComposerClient::eFXSurfaceColor;
- const String8& name = mName + "BackgroundColorLayer";
+ std::string name = mName + "BackgroundColorLayer";
mCurrentState.bgColorLayer = mFlinger->getFactory().createColorLayer(
- LayerCreationArgs(mFlinger.get(), nullptr, name, 0, 0, flags, LayerMetadata()));
+ LayerCreationArgs(mFlinger.get(), nullptr, std::move(name), 0, 0, flags,
+ LayerMetadata()));
// add to child list
addChild(mCurrentState.bgColorLayer);
@@ -1196,11 +1190,13 @@
// TODO(marissaw): add new layer state info to layer debugging
LayerDebugInfo Layer::getLayerDebugInfo() const {
+ using namespace std::string_literals;
+
LayerDebugInfo info;
const State& ds = getDrawingState();
info.mName = getName();
sp<Layer> parent = getParent();
- info.mParentName = (parent == nullptr ? std::string("none") : parent->getName().string());
+ info.mParentName = parent ? parent->getName() : "none"s;
info.mType = getType();
info.mTransparentRegion = ds.activeTransparentRegion_legacy;
@@ -1267,12 +1263,12 @@
std::string name;
if (mName.length() > 77) {
std::string shortened;
- shortened.append(mName.string(), 36);
+ shortened.append(mName, 0, 36);
shortened.append("[...]");
- shortened.append(mName.string() + (mName.length() - 36), 36);
- name = shortened;
+ shortened.append(mName, mName.length() - 36);
+ name = std::move(shortened);
} else {
- name = std::string(mName.string(), mName.size());
+ name = mName;
}
StringAppendF(&result, " %s\n", name.c_str());
@@ -1319,14 +1315,14 @@
}
void Layer::dumpFrameEvents(std::string& result) {
- StringAppendF(&result, "- Layer %s (%s, %p)\n", getName().string(), getType(), this);
+ StringAppendF(&result, "- Layer %s (%s, %p)\n", getName().c_str(), getType(), this);
Mutex::Autolock lock(mFrameEventHistoryMutex);
mFrameEventHistory.checkFencesForCompletion();
mFrameEventHistory.dump(result);
}
void Layer::dumpCallingUidPid(std::string& result) const {
- StringAppendF(&result, "Layer %s (%s) pid:%d uid:%d\n", getName().string(), getType(),
+ StringAppendF(&result, "Layer %s (%s) pid:%d uid:%d\n", getName().c_str(), getType(),
mCallingPid, mCallingUid);
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 3023cf5..fdac98f 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -34,7 +34,6 @@
#include <ui/Region.h>
#include <ui/Transform.h>
#include <utils/RefBase.h>
-#include <utils/String8.h>
#include <utils/Timers.h>
#include <cstdint>
@@ -79,12 +78,12 @@
// ---------------------------------------------------------------------------
struct LayerCreationArgs {
- LayerCreationArgs(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name,
+ LayerCreationArgs(SurfaceFlinger* flinger, const sp<Client>& client, std::string name,
uint32_t w, uint32_t h, uint32_t flags, LayerMetadata metadata);
SurfaceFlinger* flinger;
const sp<Client>& client;
- const String8& name;
+ std::string name;
uint32_t w;
uint32_t h;
uint32_t flags;
@@ -222,6 +221,8 @@
explicit Layer(const LayerCreationArgs& args);
virtual ~Layer();
+ int getWindowType() const { return mWindowType; }
+
void setPrimaryDisplayOnly() { mPrimaryDisplayOnly = true; }
bool getPrimaryDisplayOnly() const { return mPrimaryDisplayOnly; }
@@ -804,7 +805,7 @@
// Creates a new handle each time, so we only expect
// this to be called once.
sp<IBinder> getHandle();
- const String8& getName() const;
+ const std::string& getName() const { return mName; }
virtual void notifyAvailableFrames(nsecs_t /*expectedPresentTime*/) {}
virtual PixelFormat getPixelFormat() const { return PIXEL_FORMAT_NONE; }
bool getPremultipledAlpha() const;
@@ -820,8 +821,8 @@
bool usingRelativeZ(LayerVector::StateSet stateSet) const;
bool mPremultipliedAlpha{true};
- String8 mName;
- String8 mTransactionName; // A cached version of "TX - " + mName for systraces
+ const std::string mName;
+ const std::string mTransactionName{"TX - " + mName};
bool mPrimaryDisplayOnly = false;
@@ -887,9 +888,6 @@
// Window types from WindowManager.LayoutParams
const int mWindowType;
- // This is populated if the layer is registered with Scheduler for tracking purposes.
- std::unique_ptr<scheduler::LayerHistory::LayerHandle> mSchedulerLayerHandle;
-
private:
/**
* Returns an unsorted vector of all layers that are part of this tree.
diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp
index 8a22183..1a60f1e 100644
--- a/services/surfaceflinger/LayerRejecter.cpp
+++ b/services/surfaceflinger/LayerRejecter.cpp
@@ -24,7 +24,7 @@
namespace android {
LayerRejecter::LayerRejecter(Layer::State& front, Layer::State& current,
- bool& recomputeVisibleRegions, bool stickySet, const char* name,
+ bool& recomputeVisibleRegions, bool stickySet, const std::string& name,
int32_t overrideScalingMode, bool transformToDisplayInverse)
: mFront(front),
mCurrent(current),
@@ -90,7 +90,7 @@
"(%4d,%4d) "
"}\n"
" requested_legacy={ wh={%4u,%4u} }}\n",
- mName, bufWidth, bufHeight, item.mTransform, item.mScalingMode,
+ mName.c_str(), bufWidth, bufHeight, item.mTransform, item.mScalingMode,
mFront.active_legacy.w, mFront.active_legacy.h, mFront.crop_legacy.left,
mFront.crop_legacy.top, mFront.crop_legacy.right, mFront.crop_legacy.bottom,
mFront.crop_legacy.getWidth(), mFront.crop_legacy.getHeight(),
@@ -102,7 +102,8 @@
// reject this buffer
ALOGE("[%s] rejecting buffer: "
"bufWidth=%d, bufHeight=%d, front.active_legacy.{w=%d, h=%d}",
- mName, bufWidth, bufHeight, mFront.active_legacy.w, mFront.active_legacy.h);
+ mName.c_str(), bufWidth, bufHeight, mFront.active_legacy.w,
+ mFront.active_legacy.h);
return true;
}
}
diff --git a/services/surfaceflinger/LayerRejecter.h b/services/surfaceflinger/LayerRejecter.h
index 1bd0c26..fb5c750 100644
--- a/services/surfaceflinger/LayerRejecter.h
+++ b/services/surfaceflinger/LayerRejecter.h
@@ -14,30 +14,29 @@
* limitations under the License.
*/
-#ifndef ANDROID_LAYER_REJECTER_H
-#define ANDROID_LAYER_REJECTER_H
+#pragma once
#include "Layer.h"
#include "BufferLayerConsumer.h"
namespace android {
- class LayerRejecter : public BufferLayerConsumer::BufferRejecter {
- public:
- LayerRejecter(Layer::State &front, Layer::State ¤t, bool &recomputeVisibleRegions,
- bool stickySet, const char *name, int32_t overrideScalingMode,
- bool transformToDisplayInverse);
- virtual bool reject(const sp<GraphicBuffer> &buf, const BufferItem &item);
+class LayerRejecter : public BufferLayerConsumer::BufferRejecter {
+public:
+ LayerRejecter(Layer::State& front, Layer::State& current, bool& recomputeVisibleRegions,
+ bool stickySet, const std::string& name, int32_t overrideScalingMode,
+ bool transformToDisplayInverse);
- private:
- Layer::State &mFront;
- Layer::State &mCurrent;
- bool &mRecomputeVisibleRegions;
- bool mStickyTransformSet;
- const char *mName;
- int32_t mOverrideScalingMode;
- bool mTransformToDisplayInverse;
- };
-} // namespace android
+ virtual bool reject(const sp<GraphicBuffer>&, const BufferItem&);
-#endif // ANDROID_LAYER_REJECTER_H
+private:
+ Layer::State& mFront;
+ Layer::State& mCurrent;
+ bool& mRecomputeVisibleRegions;
+ const bool mStickyTransformSet;
+ const std::string& mName;
+ const int32_t mOverrideScalingMode;
+ const bool mTransformToDisplayInverse;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index b7e772d..a484373 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -419,7 +419,7 @@
}
if (!intersectsAnyArea) return;
- ALOGV("Traversing [%s] [%d, %d, %d, %d]", layer->getName().string(), bounds.left,
+ ALOGV("Traversing [%s] [%d, %d, %d, %d]", layer->getDebugName(), bounds.left,
bounds.top, bounds.right, bounds.bottom);
visitor(layer);
};
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 5473db6..8b71728 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -14,183 +14,150 @@
* limitations under the License.
*/
+#undef LOG_TAG
+#define LOG_TAG "LayerHistory"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include "LayerHistory.h"
-#include <cinttypes>
-#include <cstdint>
-#include <limits>
-#include <numeric>
-#include <string>
-#include <unordered_map>
-
#include <cutils/properties.h>
#include <utils/Log.h>
#include <utils/Timers.h>
#include <utils/Trace.h>
+#include <algorithm>
+#include <cmath>
+#include <string>
+#include <utility>
+
+#include "../Layer.h"
+#include "LayerInfo.h"
#include "SchedulerUtils.h"
-namespace android {
-namespace scheduler {
+namespace android::scheduler {
-std::atomic<int64_t> LayerHistory::sNextId = 0;
+namespace {
-LayerHistory::LayerHistory() {
+bool isLayerActive(const Layer& layer, const LayerInfo& info, nsecs_t threshold) {
+ return layer.isVisible() && (info.isHDR() || info.getLastUpdatedTime() >= threshold);
+}
+
+bool traceEnabled() {
char value[PROPERTY_VALUE_MAX];
property_get("debug.sf.layer_history_trace", value, "0");
- mTraceEnabled = static_cast<bool>(atoi(value));
+ return atoi(value);
}
+void trace(const wp<Layer>& weak, int fps) {
+ const auto layer = weak.promote();
+ if (!layer) return;
+
+ const auto& name = layer->getName();
+ const auto tag = "LFPS " + name;
+ ATRACE_INT(tag.c_str(), fps);
+ ALOGD("%s: %s @ %d Hz", __FUNCTION__, name.c_str(), fps);
+}
+
+} // namespace
+
+LayerHistory::LayerHistory() : mTraceEnabled(traceEnabled()) {}
LayerHistory::~LayerHistory() = default;
-std::unique_ptr<LayerHistory::LayerHandle> LayerHistory::createLayer(const std::string name,
- float minRefreshRate,
- float maxRefreshRate) {
- const int64_t id = sNextId++;
-
+void LayerHistory::registerLayer(Layer* layer, float lowRefreshRate, float highRefreshRate) {
+ auto info = std::make_unique<LayerInfo>(lowRefreshRate, highRefreshRate);
std::lock_guard lock(mLock);
- mInactiveLayerInfos.emplace(id,
- std::make_shared<LayerInfo>(name, minRefreshRate, maxRefreshRate));
- return std::make_unique<LayerHistory::LayerHandle>(*this, id);
+ mLayerInfos.emplace_back(layer, std::move(info));
}
-void LayerHistory::destroyLayer(const int64_t id) {
+void LayerHistory::record(Layer* layer, nsecs_t presentTime, bool isHDR, nsecs_t now) {
std::lock_guard lock(mLock);
- auto it = mActiveLayerInfos.find(id);
- if (it != mActiveLayerInfos.end()) {
- mActiveLayerInfos.erase(it);
- }
- it = mInactiveLayerInfos.find(id);
- if (it != mInactiveLayerInfos.end()) {
- mInactiveLayerInfos.erase(it);
+ const auto it = std::find_if(mLayerInfos.begin(), mLayerInfos.end(),
+ [layer](const auto& pair) { return pair.first == layer; });
+ LOG_FATAL_IF(it == mLayerInfos.end(), "%s: unknown layer %p", __FUNCTION__, layer);
+
+ const auto& info = it->second;
+ info->setLastPresentTime(presentTime, now);
+ info->setIsHDR(isHDR);
+
+ // Activate layer if inactive.
+ if (const auto end = activeLayers().end(); it >= end) {
+ std::iter_swap(it, end);
+ mActiveLayersEnd++;
}
}
-void LayerHistory::insert(const std::unique_ptr<LayerHandle>& layerHandle, nsecs_t presentTime,
- bool isHdr) {
- std::shared_ptr<LayerInfo> layerInfo;
- {
- std::lock_guard lock(mLock);
- auto layerInfoIterator = mInactiveLayerInfos.find(layerHandle->mId);
- if (layerInfoIterator != mInactiveLayerInfos.end()) {
- layerInfo = layerInfoIterator->second;
- mInactiveLayerInfos.erase(layerInfoIterator);
- mActiveLayerInfos.insert({layerHandle->mId, layerInfo});
- } else {
- layerInfoIterator = mActiveLayerInfos.find(layerHandle->mId);
- if (layerInfoIterator != mActiveLayerInfos.end()) {
- layerInfo = layerInfoIterator->second;
- } else {
- ALOGW("Inserting information about layer that is not registered: %" PRId64,
- layerHandle->mId);
- return;
- }
- }
- }
- layerInfo->setLastPresentTime(presentTime);
- layerInfo->setHDRContent(isHdr);
-}
-
-void LayerHistory::setVisibility(const std::unique_ptr<LayerHandle>& layerHandle, bool visible) {
- std::shared_ptr<LayerInfo> layerInfo;
- {
- std::lock_guard lock(mLock);
- auto layerInfoIterator = mInactiveLayerInfos.find(layerHandle->mId);
- if (layerInfoIterator != mInactiveLayerInfos.end()) {
- layerInfo = layerInfoIterator->second;
- if (visible) {
- mInactiveLayerInfos.erase(layerInfoIterator);
- mActiveLayerInfos.insert({layerHandle->mId, layerInfo});
- }
- } else {
- layerInfoIterator = mActiveLayerInfos.find(layerHandle->mId);
- if (layerInfoIterator != mActiveLayerInfos.end()) {
- layerInfo = layerInfoIterator->second;
- } else {
- ALOGW("Inserting information about layer that is not registered: %" PRId64,
- layerHandle->mId);
- return;
- }
- }
- }
- layerInfo->setVisibility(visible);
-}
-
-std::pair<float, bool> LayerHistory::getDesiredRefreshRateAndHDR() {
+LayerHistory::Summary LayerHistory::summarize(nsecs_t now) {
+ float maxRefreshRate = 0;
bool isHDR = false;
- float newRefreshRate = 0.f;
+
std::lock_guard lock(mLock);
- removeIrrelevantLayers();
+ partitionLayers(now);
- // Iterate through all layers that have been recently updated, and find the max refresh rate.
- for (const auto& [layerId, layerInfo] : mActiveLayerInfos) {
- const bool recent = layerInfo->isRecentlyActive();
+ // Find the maximum refresh rate among recently active layers.
+ for (const auto& [layer, info] : activeLayers()) {
+ const bool recent = info->isRecentlyActive(now);
if (recent || CC_UNLIKELY(mTraceEnabled)) {
- const float refreshRate = layerInfo->getDesiredRefreshRate();
- if (recent && refreshRate > newRefreshRate) {
- newRefreshRate = refreshRate;
+ const float refreshRate = info->getRefreshRate(now);
+ if (recent && refreshRate > maxRefreshRate) {
+ maxRefreshRate = refreshRate;
}
if (CC_UNLIKELY(mTraceEnabled)) {
- std::string name = "LFPS " + layerInfo->getName();
- const float rate = std::round(refreshRate);
- ATRACE_INT(name.c_str(), rate);
- ALOGD("%s: %f", name.c_str(), rate);
+ trace(layer, std::round(refreshRate));
}
}
- isHDR |= layerInfo->getHDRContent();
+ isHDR |= info->isHDR();
}
if (CC_UNLIKELY(mTraceEnabled)) {
- ALOGD("LayerHistory DesiredRefreshRate: %.2f", newRefreshRate);
+ ALOGD("%s: maxRefreshRate=%.2f, isHDR=%d", __FUNCTION__, maxRefreshRate, isHDR);
}
- return {newRefreshRate, isHDR};
+ return {maxRefreshRate, isHDR};
}
-void LayerHistory::removeIrrelevantLayers() {
- const int64_t obsoleteEpsilon = systemTime() - scheduler::OBSOLETE_TIME_EPSILON_NS.count();
- // Iterator pointing to first element in map
- auto it = mActiveLayerInfos.begin();
- while (it != mActiveLayerInfos.end()) {
- // If last updated was before the obsolete time, remove it.
- // Keep HDR layer around as long as they are visible.
- if (!it->second->isVisible() ||
- (!it->second->getHDRContent() && it->second->getLastUpdatedTime() < obsoleteEpsilon)) {
- // erase() function returns the iterator of the next
- // to last deleted element.
- if (CC_UNLIKELY(mTraceEnabled)) {
- ALOGD("Layer %s obsolete", it->second->getName().c_str());
- // Make sure to update systrace to indicate that the layer was erased.
- std::string layerName = "LFPS " + it->second->getName();
- ATRACE_INT(layerName.c_str(), 0);
- }
- auto id = it->first;
- auto layerInfo = it->second;
- layerInfo->clearHistory();
- mInactiveLayerInfos.insert({id, layerInfo});
- it = mActiveLayerInfos.erase(it);
+void LayerHistory::partitionLayers(nsecs_t now) {
+ const nsecs_t threshold = getActiveLayerThreshold(now);
+
+ // Collect expired and inactive layers after active layers.
+ size_t i = 0;
+ while (i < mActiveLayersEnd) {
+ auto& [weak, info] = mLayerInfos[i];
+ if (const auto layer = weak.promote(); layer && isLayerActive(*layer, *info, threshold)) {
+ i++;
+ continue;
+ }
+
+ if (CC_UNLIKELY(mTraceEnabled)) {
+ trace(weak, 0);
+ }
+
+ info->clearHistory();
+ std::swap(mLayerInfos[i], mLayerInfos[--mActiveLayersEnd]);
+ }
+
+ // Collect expired layers after inactive layers.
+ size_t end = mLayerInfos.size();
+ while (i < end) {
+ if (mLayerInfos[i].first.promote()) {
+ i++;
} else {
- ++it;
+ std::swap(mLayerInfos[i], mLayerInfos[--end]);
}
}
+
+ mLayerInfos.erase(mLayerInfos.begin() + end, mLayerInfos.end());
}
-void LayerHistory::clearHistory() {
+void LayerHistory::clear() {
std::lock_guard lock(mLock);
- auto it = mActiveLayerInfos.begin();
- while (it != mActiveLayerInfos.end()) {
- auto id = it->first;
- auto layerInfo = it->second;
- layerInfo->clearHistory();
- mInactiveLayerInfos.insert({id, layerInfo});
- it = mActiveLayerInfos.erase(it);
+ for (const auto& [layer, info] : activeLayers()) {
+ info->clearHistory();
}
+
+ mActiveLayersEnd = 0;
}
-} // namespace scheduler
-} // namespace android
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index 5598cc1..15ac8ca 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -16,76 +16,78 @@
#pragma once
-#include <array>
-#include <cinttypes>
-#include <cstdint>
-#include <numeric>
-#include <string>
-#include <unordered_map>
-
+#include <android-base/thread_annotations.h>
+#include <utils/RefBase.h>
#include <utils/Timers.h>
-#include "LayerInfo.h"
-#include "SchedulerUtils.h"
+#include <memory>
+#include <mutex>
+#include <utility>
+#include <vector>
namespace android {
+
+class Layer;
+
namespace scheduler {
-/*
- * This class represents information about layers that are considered current. We keep an
- * unordered map between layer name and LayerInfo.
- */
+class LayerInfo;
+
+// Records per-layer history of scheduling-related information (primarily present time),
+// heuristically categorizes layers as active or inactive, and summarizes stats about
+// active layers (primarily maximum refresh rate). See go/content-fps-detection-in-scheduler.
class LayerHistory {
public:
- // Handle for each layer we keep track of.
- class LayerHandle {
- public:
- LayerHandle(LayerHistory& lh, int64_t id) : mId(id), mLayerHistory(lh) {}
- ~LayerHandle() { mLayerHistory.destroyLayer(mId); }
-
- const int64_t mId;
-
- private:
- LayerHistory& mLayerHistory;
- };
-
LayerHistory();
~LayerHistory();
- // When the layer is first created, register it.
- std::unique_ptr<LayerHandle> createLayer(const std::string name, float minRefreshRate,
- float maxRefreshRate);
+ // Layers are unregistered when the weak reference expires.
+ void registerLayer(Layer*, float lowRefreshRate, float highRefreshRate);
- // Method for inserting layers and their requested present time into the unordered map.
- void insert(const std::unique_ptr<LayerHandle>& layerHandle, nsecs_t presentTime, bool isHdr);
- // Method for setting layer visibility
- void setVisibility(const std::unique_ptr<LayerHandle>& layerHandle, bool visible);
+ // Marks the layer as active, and records the given state to its history.
+ void record(Layer*, nsecs_t presentTime, bool isHDR, nsecs_t now);
- // Returns the desired refresh rate, which is a max refresh rate of all the current
- // layers. See go/content-fps-detection-in-scheduler for more information.
- std::pair<float, bool> getDesiredRefreshRateAndHDR();
+ struct Summary {
+ float maxRefreshRate; // Maximum refresh rate among recently active layers.
+ bool isHDR; // True if any recently active layer has HDR content.
+ };
- // Clears all layer history.
- void clearHistory();
+ // Rebuilds sets of active/inactive layers, and accumulates stats for active layers.
+ Summary summarize(nsecs_t now);
- // Removes the handle and the object from the map.
- void destroyLayer(const int64_t id);
+ void clear();
private:
- // Removes the layers that have been idle for a given amount of time from mLayerInfos.
- void removeIrrelevantLayers() REQUIRES(mLock);
+ friend class LayerHistoryTest;
- // Information about currently active layers.
- std::mutex mLock;
- std::unordered_map<int64_t, std::shared_ptr<LayerInfo>> mActiveLayerInfos GUARDED_BY(mLock);
- std::unordered_map<int64_t, std::shared_ptr<LayerInfo>> mInactiveLayerInfos GUARDED_BY(mLock);
+ using LayerPair = std::pair<wp<Layer>, std::unique_ptr<LayerInfo>>;
+ using LayerInfos = std::vector<LayerPair>;
- // Each layer has it's own ID. This variable keeps track of the count.
- static std::atomic<int64_t> sNextId;
+ struct ActiveLayers {
+ LayerInfos& infos;
+ const size_t index;
- // Flag whether to log layer FPS in systrace
- bool mTraceEnabled = false;
+ auto begin() { return infos.begin(); }
+ auto end() { return begin() + index; }
+ };
+
+ ActiveLayers activeLayers() REQUIRES(mLock) { return {mLayerInfos, mActiveLayersEnd}; }
+
+ // Iterates over layers in a single pass, swapping pairs such that active layers precede
+ // inactive layers, and inactive layers precede expired layers. Removes expired layers by
+ // truncating after inactive layers.
+ void partitionLayers(nsecs_t now) REQUIRES(mLock);
+
+ mutable std::mutex mLock;
+
+ // Partitioned such that active layers precede inactive layers. For fast lookup, the few active
+ // layers are at the front, and weak pointers are stored in contiguous memory to hit the cache.
+ LayerInfos mLayerInfos GUARDED_BY(mLock);
+ size_t mActiveLayersEnd GUARDED_BY(mLock) = 0;
+
+ // Whether to emit systrace output and debug logs.
+ const bool mTraceEnabled;
};
} // namespace scheduler
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index 723d71f..f3b0d56 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -16,27 +16,17 @@
#include "LayerInfo.h"
-#include <cinttypes>
-#include <cstdint>
-#include <numeric>
-#include <string>
+#include <algorithm>
+#include <utility>
-namespace android {
-namespace scheduler {
+namespace android::scheduler {
-LayerInfo::LayerInfo(const std::string name, float minRefreshRate, float maxRefreshRate)
- : mName(name),
- mMinRefreshDuration(1e9f / maxRefreshRate),
- mLowActivityRefreshDuration(1e9f / minRefreshRate),
- mRefreshRateHistory(mMinRefreshDuration) {}
+LayerInfo::LayerInfo(float lowRefreshRate, float highRefreshRate)
+ : mLowRefreshRate(lowRefreshRate), mHighRefreshRate(highRefreshRate) {}
-LayerInfo::~LayerInfo() = default;
-
-void LayerInfo::setLastPresentTime(nsecs_t lastPresentTime) {
- std::lock_guard lock(mLock);
-
+void LayerInfo::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now) {
// Buffers can come with a present time far in the future. That keeps them relevant.
- mLastUpdatedTime = std::max(lastPresentTime, systemTime());
+ mLastUpdatedTime = std::max(lastPresentTime, now);
mPresentTimeHistory.insertPresentTime(mLastUpdatedTime);
if (mLastPresentTime == 0) {
@@ -45,14 +35,13 @@
return;
}
- const nsecs_t timeDiff = lastPresentTime - mLastPresentTime;
+ const nsecs_t period = lastPresentTime - mLastPresentTime;
mLastPresentTime = lastPresentTime;
// Ignore time diff that are too high - those are stale values
- if (timeDiff > OBSOLETE_TIME_EPSILON_NS.count()) return;
- const nsecs_t refreshDuration = std::max(timeDiff, mMinRefreshDuration);
- const int fps = 1e9f / refreshDuration;
+ if (period > MAX_ACTIVE_LAYER_PERIOD_NS.count()) return;
+
+ const float fps = std::min(1e9f / period, mHighRefreshRate);
mRefreshRateHistory.insertRefreshRate(fps);
}
-} // namespace scheduler
-} // namespace android
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
index 17afdda..b86709f 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.h
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -16,27 +16,37 @@
#pragma once
-#include <cinttypes>
-#include <cstdint>
-#include <deque>
-#include <mutex>
-#include <numeric>
-#include <string>
-
-#include <log/log.h>
-
-#include <utils/Mutex.h>
#include <utils/Timers.h>
+#include <chrono>
+#include <deque>
+
#include "SchedulerUtils.h"
namespace android {
+
+class Layer;
+
namespace scheduler {
-/*
- * This class represents information about individial layers.
- */
+using namespace std::chrono_literals;
+
+// Maximum period between presents for a layer to be considered active.
+constexpr std::chrono::nanoseconds MAX_ACTIVE_LAYER_PERIOD_NS = 1200ms;
+
+// Earliest present time for a layer to be considered active.
+constexpr nsecs_t getActiveLayerThreshold(nsecs_t now) {
+ return now - MAX_ACTIVE_LAYER_PERIOD_NS.count();
+}
+
+// Stores history of present times and refresh rates for a layer.
class LayerInfo {
+ // Layer is considered frequent if the earliest value in the window of most recent present times
+ // is within a threshold. If a layer is infrequent, its average refresh rate is disregarded in
+ // favor of a low refresh rate.
+ static constexpr size_t FREQUENT_LAYER_WINDOW_SIZE = 3;
+ static constexpr std::chrono::nanoseconds MAX_FREQUENT_LAYER_PERIOD_NS = 250ms;
+
/**
* Struct that keeps the information about the refresh rate for last
* HISTORY_SIZE frames. This is used to better determine the refresh rate
@@ -44,9 +54,9 @@
*/
class RefreshRateHistory {
public:
- explicit RefreshRateHistory(nsecs_t minRefreshDuration)
- : mMinRefreshDuration(minRefreshDuration) {}
- void insertRefreshRate(int refreshRate) {
+ explicit RefreshRateHistory(float highRefreshRate) : mHighRefreshRate(highRefreshRate) {}
+
+ void insertRefreshRate(float refreshRate) {
mElements.push_back(refreshRate);
if (mElements.size() > HISTORY_SIZE) {
mElements.pop_front();
@@ -54,19 +64,16 @@
}
float getRefreshRateAvg() const {
- if (mElements.empty()) {
- return 1e9f / mMinRefreshDuration;
- }
-
- return scheduler::calculate_mean(mElements);
+ return mElements.empty() ? mHighRefreshRate : calculate_mean(mElements);
}
void clearHistory() { mElements.clear(); }
private:
- std::deque<nsecs_t> mElements;
+ const float mHighRefreshRate;
+
static constexpr size_t HISTORY_SIZE = 30;
- const nsecs_t mMinRefreshDuration;
+ std::deque<float> mElements;
};
/**
@@ -76,6 +83,8 @@
*/
class PresentTimeHistory {
public:
+ static constexpr size_t HISTORY_SIZE = 90;
+
void insertPresentTime(nsecs_t presentTime) {
mElements.push_back(presentTime);
if (mElements.size() > HISTORY_SIZE) {
@@ -83,60 +92,45 @@
}
}
- // Checks whether the present time that was inserted HISTORY_SIZE ago is within a
- // certain threshold: TIME_EPSILON_NS.
- bool isRelevant() const {
+ // Returns whether the earliest present time is within the active threshold.
+ bool isRecentlyActive(nsecs_t now) const {
if (mElements.size() < 2) {
return false;
}
// The layer had to publish at least HISTORY_SIZE or HISTORY_TIME of updates
- if (mElements.size() != HISTORY_SIZE &&
- mElements.at(mElements.size() - 1) - mElements.at(0) < HISTORY_TIME.count()) {
+ if (mElements.size() < HISTORY_SIZE &&
+ mElements.back() - mElements.front() < HISTORY_TIME.count()) {
return false;
}
- // The last update should not be older than OBSOLETE_TIME_EPSILON_NS nanoseconds.
- const int64_t obsoleteEpsilon =
- systemTime() - scheduler::OBSOLETE_TIME_EPSILON_NS.count();
- if (mElements.at(mElements.size() - 1) < obsoleteEpsilon) {
- return false;
- }
-
- return true;
+ return mElements.back() >= getActiveLayerThreshold(now);
}
- bool isLowActivityLayer() const {
- // We want to make sure that we received more than two frames from the layer
- // in order to check low activity.
- if (mElements.size() < scheduler::LOW_ACTIVITY_BUFFERS + 1) {
+ bool isFrequent(nsecs_t now) const {
+ // Assume layer is infrequent if too few present times have been recorded.
+ if (mElements.size() < FREQUENT_LAYER_WINDOW_SIZE) {
return false;
}
- const int64_t obsoleteEpsilon =
- systemTime() - scheduler::LOW_ACTIVITY_EPSILON_NS.count();
- // Check the frame before last to determine whether there is low activity.
- // If that frame is older than LOW_ACTIVITY_EPSILON_NS, the layer is sending
- // infrequent updates.
- if (mElements.at(mElements.size() - (scheduler::LOW_ACTIVITY_BUFFERS + 1)) <
- obsoleteEpsilon) {
- return true;
- }
-
- return false;
+ // Layer is frequent if the earliest value in the window of most recent present times is
+ // within threshold.
+ const auto it = mElements.end() - FREQUENT_LAYER_WINDOW_SIZE;
+ const nsecs_t threshold = now - MAX_FREQUENT_LAYER_PERIOD_NS.count();
+ return *it >= threshold;
}
void clearHistory() { mElements.clear(); }
private:
std::deque<nsecs_t> mElements;
- static constexpr size_t HISTORY_SIZE = 90;
static constexpr std::chrono::nanoseconds HISTORY_TIME = 1s;
};
+ friend class LayerHistoryTest;
+
public:
- LayerInfo(const std::string name, float minRefreshRate, float maxRefreshRate);
- ~LayerInfo();
+ LayerInfo(float lowRefreshRate, float highRefreshRate);
LayerInfo(const LayerInfo&) = delete;
LayerInfo& operator=(const LayerInfo&) = delete;
@@ -144,71 +138,37 @@
// Records the last requested oresent time. It also stores information about when
// the layer was last updated. If the present time is farther in the future than the
// updated time, the updated time is the present time.
- void setLastPresentTime(nsecs_t lastPresentTime);
+ void setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now);
- void setHDRContent(bool isHdr) {
- std::lock_guard lock(mLock);
- mIsHDR = isHdr;
- }
+ bool isHDR() const { return mIsHDR; }
+ void setIsHDR(bool isHDR) { mIsHDR = isHDR; }
- void setVisibility(bool visible) {
- std::lock_guard lock(mLock);
- mIsVisible = visible;
- }
+ bool isRecentlyActive(nsecs_t now) const { return mPresentTimeHistory.isRecentlyActive(now); }
+ bool isFrequent(nsecs_t now) const { return mPresentTimeHistory.isFrequent(now); }
- // Checks the present time history to see whether the layer is relevant.
- bool isRecentlyActive() const {
- std::lock_guard lock(mLock);
- return mPresentTimeHistory.isRelevant();
- }
-
- // Calculate the average refresh rate.
- float getDesiredRefreshRate() const {
- std::lock_guard lock(mLock);
-
- if (mPresentTimeHistory.isLowActivityLayer()) {
- return 1e9f / mLowActivityRefreshDuration;
- }
- return mRefreshRateHistory.getRefreshRateAvg();
- }
-
- bool getHDRContent() {
- std::lock_guard lock(mLock);
- return mIsHDR;
- }
-
- bool isVisible() {
- std::lock_guard lock(mLock);
- return mIsVisible;
+ float getRefreshRate(nsecs_t now) const {
+ return isFrequent(now) ? mRefreshRateHistory.getRefreshRateAvg() : mLowRefreshRate;
}
// Return the last updated time. If the present time is farther in the future than the
// updated time, the updated time is the present time.
- nsecs_t getLastUpdatedTime() {
- std::lock_guard lock(mLock);
- return mLastUpdatedTime;
- }
-
- std::string getName() const { return mName; }
+ nsecs_t getLastUpdatedTime() const { return mLastUpdatedTime; }
void clearHistory() {
- std::lock_guard lock(mLock);
mRefreshRateHistory.clearHistory();
mPresentTimeHistory.clearHistory();
}
private:
- const std::string mName;
- const nsecs_t mMinRefreshDuration;
- const nsecs_t mLowActivityRefreshDuration;
- mutable std::mutex mLock;
- nsecs_t mLastUpdatedTime GUARDED_BY(mLock) = 0;
- nsecs_t mLastPresentTime GUARDED_BY(mLock) = 0;
- RefreshRateHistory mRefreshRateHistory GUARDED_BY(mLock);
- PresentTimeHistory mPresentTimeHistory GUARDED_BY(mLock);
- bool mIsHDR GUARDED_BY(mLock) = false;
- bool mIsVisible GUARDED_BY(mLock) = false;
+ const float mLowRefreshRate;
+ const float mHighRefreshRate;
+
+ nsecs_t mLastUpdatedTime = 0;
+ nsecs_t mLastPresentTime = 0;
+ RefreshRateHistory mRefreshRateHistory{mHighRefreshRate};
+ PresentTimeHistory mPresentTimeHistory;
+ bool mIsHDR = false;
};
} // namespace scheduler
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index d60e101..71b3500 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -20,13 +20,6 @@
#include "Scheduler.h"
-#include <algorithm>
-#include <cinttypes>
-#include <cstdint>
-#include <functional>
-#include <memory>
-#include <numeric>
-
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
#include <configstore/Utils.h>
@@ -37,6 +30,14 @@
#include <utils/Timers.h>
#include <utils/Trace.h>
+#include <algorithm>
+#include <cinttypes>
+#include <cstdint>
+#include <functional>
+#include <memory>
+#include <numeric>
+
+#include "../Layer.h"
#include "DispSync.h"
#include "DispSyncSource.h"
#include "EventControlThread.h"
@@ -325,37 +326,27 @@
return mPrimaryDispSync->expectedPresentTime();
}
-std::unique_ptr<scheduler::LayerHistory::LayerHandle> Scheduler::registerLayer(
- std::string const& name, int windowType) {
+void Scheduler::registerLayer(Layer* layer) {
uint32_t defaultFps, performanceFps;
if (mRefreshRateConfigs.refreshRateSwitchingSupported()) {
defaultFps = mRefreshRateConfigs.getRefreshRateFromType(RefreshRateType::DEFAULT).fps;
- performanceFps =
- mRefreshRateConfigs
- .getRefreshRateFromType((windowType == InputWindowInfo::TYPE_WALLPAPER)
- ? RefreshRateType::DEFAULT
- : RefreshRateType::PERFORMANCE)
- .fps;
+ const auto type = layer->getWindowType() == InputWindowInfo::TYPE_WALLPAPER
+ ? RefreshRateType::DEFAULT
+ : RefreshRateType::PERFORMANCE;
+ performanceFps = mRefreshRateConfigs.getRefreshRateFromType(type).fps;
} else {
defaultFps = mRefreshRateConfigs.getCurrentRefreshRate().second.fps;
performanceFps = defaultFps;
}
- return mLayerHistory.createLayer(name, defaultFps, performanceFps);
+ mLayerHistory.registerLayer(layer, defaultFps, performanceFps);
}
-void Scheduler::addLayerPresentTimeAndHDR(
- const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle,
- nsecs_t presentTime, bool isHDR) {
- mLayerHistory.insert(layerHandle, presentTime, isHDR);
-}
-
-void Scheduler::setLayerVisibility(
- const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle, bool visible) {
- mLayerHistory.setVisibility(layerHandle, visible);
+void Scheduler::recordLayerHistory(Layer* layer, nsecs_t presentTime, bool isHDR) {
+ mLayerHistory.record(layer, presentTime, isHDR, systemTime());
}
void Scheduler::updateFpsBasedOnContent() {
- auto [refreshRate, isHDR] = mLayerHistory.getDesiredRefreshRateAndHDR();
+ auto [refreshRate, isHDR] = mLayerHistory.summarize(systemTime());
const uint32_t refreshRateRound = std::round(refreshRate);
RefreshRateType newRefreshRateType;
{
@@ -402,7 +393,7 @@
// Touch event will boost the refresh rate to performance.
// Clear Layer History to get fresh FPS detection
- mLayerHistory.clearHistory();
+ mLayerHistory.clear();
}
void Scheduler::setDisplayPowerState(bool normal) {
@@ -417,7 +408,7 @@
// Display Power event will boost the refresh rate to performance.
// Clear Layer History to get fresh FPS detection
- mLayerHistory.clearHistory();
+ mLayerHistory.clear();
}
void Scheduler::kernelIdleTimerCallback(TimerState state) {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index a5971fe..c983475 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -100,17 +100,11 @@
void addPresentFence(const std::shared_ptr<FenceTime>&);
void setIgnorePresentFences(bool ignore);
nsecs_t getDispSyncExpectedPresentTime();
- // Registers the layer in the scheduler, and returns the handle for future references.
- std::unique_ptr<scheduler::LayerHistory::LayerHandle> registerLayer(std::string const& name,
- int windowType);
- // Stores present time for a layer.
- void addLayerPresentTimeAndHDR(
- const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle,
- nsecs_t presentTime, bool isHDR);
- // Stores visibility for a layer.
- void setLayerVisibility(
- const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle, bool visible);
+ // Layers are registered on creation, and unregistered when the weak reference expires.
+ void registerLayer(Layer*);
+ void recordLayerHistory(Layer*, nsecs_t presentTime, bool isHDR);
+
// Updates FPS based on the most content presented.
void updateFpsBasedOnContent();
diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.h b/services/surfaceflinger/Scheduler/SchedulerUtils.h
index 3b7567c..d301b99 100644
--- a/services/surfaceflinger/Scheduler/SchedulerUtils.h
+++ b/services/surfaceflinger/Scheduler/SchedulerUtils.h
@@ -16,7 +16,6 @@
#pragma once
-#include <chrono>
#include <cinttypes>
#include <numeric>
#include <unordered_map>
@@ -38,21 +37,6 @@
return lhs.id == rhs.id;
}
-using namespace std::chrono_literals;
-
-// This number is used when we try to determine how long do we keep layer information around
-// before we remove it. It is also used to determine how long the layer stays relevant.
-// This time period captures infrequent updates when playing YouTube video with static image,
-// or waiting idle in messaging app, when cursor is blinking.
-static constexpr std::chrono::nanoseconds OBSOLETE_TIME_EPSILON_NS = 1200ms;
-
-// Layer is considered low activity if the LOW_ACTIVITY_BUFFERS buffers come more than
-// LOW_ACTIVITY_EPSILON_NS apart.
-// This is helping SF to vote for lower refresh rates when there is not activity
-// in screen.
-static constexpr int LOW_ACTIVITY_BUFFERS = 2;
-static constexpr std::chrono::nanoseconds LOW_ACTIVITY_EPSILON_NS = 250ms;
-
// Calculates the statistical mean (average) in the data structure (array, vector). The
// function does not modify the contents of the array.
template <typename T>
diff --git a/services/surfaceflinger/Scheduler/StrongTyping.h b/services/surfaceflinger/Scheduler/StrongTyping.h
new file mode 100644
index 0000000..02db022
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/StrongTyping.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+namespace android {
+
+template <typename T, template <typename> class AbilityType>
+struct Ability {
+ T& base() { return static_cast<T&>(*this); }
+ T const& base() const { return static_cast<T const&>(*this); }
+};
+
+template <typename T>
+struct Add : Ability<T, Add> {
+ inline T operator+(T const& other) const { return T(this->base().value() + other.value()); }
+ inline T& operator++() {
+ ++this->base().value();
+ return this->base();
+ };
+ inline T operator++(int) {
+ T tmp(this->base());
+ operator++();
+ return tmp;
+ };
+ inline T& operator+=(T const& other) {
+ this->base().value() += other.value();
+ return this->base();
+ };
+};
+
+template <typename T>
+struct Compare : Ability<T, Compare> {
+ inline bool operator==(T const& other) const { return this->base().value() == other.value(); };
+ inline bool operator<(T const& other) const { return this->base().value() < other.value(); }
+ inline bool operator<=(T const& other) const { return (*this < other) || (*this == other); }
+ inline bool operator!=(T const& other) const { return !(*this == other); }
+ inline bool operator>=(T const& other) const { return !(*this < other); }
+ inline bool operator>(T const& other) const { return !(*this < other || *this == other); }
+};
+
+template <typename T, typename W, template <typename> class... Ability>
+struct StrongTyping : Ability<StrongTyping<T, W, Ability...>>... {
+ StrongTyping() : mValue(0) {}
+ explicit StrongTyping(T const& value) : mValue(value) {}
+ StrongTyping(StrongTyping const&) = default;
+ StrongTyping& operator=(StrongTyping const&) = default;
+ inline operator T() const { return mValue; }
+ T const& value() const { return mValue; }
+ T& value() { return mValue; }
+
+private:
+ T mValue;
+};
+} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 54e2065..1acb2da 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -122,6 +122,8 @@
namespace android {
+using namespace std::string_literals;
+
using namespace android::hardware::configstore;
using namespace android::hardware::configstore::V1_0;
using namespace android::sysprop;
@@ -599,20 +601,19 @@
Mutex::Autolock _l(mStateLock);
// Get a RenderEngine for the given display / config (can't fail)
- int32_t renderEngineFeature = 0;
- renderEngineFeature |= (useColorManagement ?
- renderengine::RenderEngine::USE_COLOR_MANAGEMENT : 0);
- renderEngineFeature |= (useContextPriority ?
- renderengine::RenderEngine::USE_HIGH_PRIORITY_CONTEXT : 0);
- renderEngineFeature |=
- (enable_protected_contents(false) ? renderengine::RenderEngine::ENABLE_PROTECTED_CONTEXT
- : 0);
-
// TODO(b/77156734): We need to stop casting and use HAL types when possible.
// Sending maxFrameBufferAcquiredBuffers as the cache size is tightly tuned to single-display.
- mCompositionEngine->setRenderEngine(
- renderengine::RenderEngine::create(static_cast<int32_t>(defaultCompositionPixelFormat),
- renderEngineFeature, maxFrameBufferAcquiredBuffers));
+ mCompositionEngine->setRenderEngine(renderengine::RenderEngine::create(
+ renderengine::RenderEngineCreationArgs::Builder()
+ .setPixelFormat(static_cast<int32_t>(defaultCompositionPixelFormat))
+ .setImageCacheSize(maxFrameBufferAcquiredBuffers)
+ .setUseColorManagerment(useColorManagement)
+ .setEnableProtectedContext(enable_protected_contents(false))
+ .setPrecacheToneMapperShaderOnly(false)
+ .setContextPriority(useContextPriority
+ ? renderengine::RenderEngine::ContextPriority::HIGH
+ : renderengine::RenderEngine::ContextPriority::MEDIUM)
+ .build()));
LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
"Starting with vr flinger active is not currently supported.");
@@ -1911,8 +1912,7 @@
layer->onPostComposition(displayDevice->getId(), glCompositionDoneFenceTime,
presentFenceTime, compositorTiming);
if (frameLatched) {
- recordBufferingStats(layer->getName().string(),
- layer->getOccupancyHistory(false));
+ recordBufferingStats(layer->getName(), layer->getOccupancyHistory(false));
}
});
@@ -2574,7 +2574,7 @@
if (!mLayersPendingRemoval.isEmpty()) {
// Notify removed layers now that they can't be drawn from
for (const auto& l : mLayersPendingRemoval) {
- recordBufferingStats(l->getName().string(), l->getOccupancyHistory(true));
+ recordBufferingStats(l->getName(), l->getOccupancyHistory(true));
// Ensure any buffers set to display on any children are released.
if (l->isRemovedFromCurrentState()) {
@@ -3244,11 +3244,12 @@
// everything else inherits layer stack from its parent.
if (layer->hasParent()) {
ALOGE("Attempt to set layer stack on layer with parent (%s) is invalid",
- layer->getName().string());
+ layer->getDebugName());
} else if (idx < 0) {
ALOGE("Attempt to set layer stack on layer without parent (%s) that "
- "that also does not appear in the top level layer list. Something"
- " has gone wrong.", layer->getName().string());
+ "that also does not appear in the top level layer list. Something"
+ " has gone wrong.",
+ layer->getDebugName());
} else if (layer->setLayerStack(s.layerStack)) {
mCurrentState.layersSortedByZ.removeAt(idx);
mCurrentState.layersSortedByZ.add(layer);
@@ -3406,7 +3407,7 @@
sp<Layer> mirrorLayer;
sp<Layer> mirrorFrom;
- String8 uniqueName = getUniqueLayerName(String8("MirrorRoot"));
+ std::string uniqueName = getUniqueLayerName("MirrorRoot");
{
Mutex::Autolock _l(mStateLock);
@@ -3415,8 +3416,8 @@
return NAME_NOT_FOUND;
}
- status_t result = createContainerLayer(client, uniqueName, -1, -1, 0, LayerMetadata(),
- outHandle, &mirrorLayer);
+ status_t result = createContainerLayer(client, std::move(uniqueName), -1, -1, 0,
+ LayerMetadata(), outHandle, &mirrorLayer);
if (result != NO_ERROR) {
return result;
}
@@ -3447,7 +3448,7 @@
sp<Layer> layer;
- String8 uniqueName = getUniqueLayerName(name);
+ std::string uniqueName = getUniqueLayerName(name.string());
bool primaryDisplayOnly = false;
@@ -3463,13 +3464,13 @@
switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
case ISurfaceComposerClient::eFXSurfaceBufferQueue:
- result = createBufferQueueLayer(client, uniqueName, w, h, flags, std::move(metadata),
- format, handle, gbp, &layer);
+ result = createBufferQueueLayer(client, std::move(uniqueName), w, h, flags,
+ std::move(metadata), format, handle, gbp, &layer);
break;
case ISurfaceComposerClient::eFXSurfaceBufferState:
- result = createBufferStateLayer(client, uniqueName, w, h, flags, std::move(metadata),
- handle, &layer);
+ result = createBufferStateLayer(client, std::move(uniqueName), w, h, flags,
+ std::move(metadata), handle, &layer);
break;
case ISurfaceComposerClient::eFXSurfaceColor:
// check if buffer size is set for color layer.
@@ -3479,8 +3480,8 @@
return BAD_VALUE;
}
- result = createColorLayer(client, uniqueName, w, h, flags, std::move(metadata), handle,
- &layer);
+ result = createColorLayer(client, std::move(uniqueName), w, h, flags,
+ std::move(metadata), handle, &layer);
break;
case ISurfaceComposerClient::eFXSurfaceContainer:
// check if buffer size is set for container layer.
@@ -3489,8 +3490,8 @@
int(w), int(h));
return BAD_VALUE;
}
- result = createContainerLayer(client, uniqueName, w, h, flags, std::move(metadata),
- handle, &layer);
+ result = createContainerLayer(client, std::move(uniqueName), w, h, flags,
+ std::move(metadata), handle, &layer);
break;
default:
result = BAD_VALUE;
@@ -3517,35 +3518,32 @@
return result;
}
-String8 SurfaceFlinger::getUniqueLayerName(const String8& name)
-{
- bool matchFound = true;
- uint32_t dupeCounter = 0;
+std::string SurfaceFlinger::getUniqueLayerName(const char* name) {
+ unsigned dupeCounter = 0;
// Tack on our counter whether there is a hit or not, so everyone gets a tag
- String8 uniqueName = name + "#" + String8(std::to_string(dupeCounter).c_str());
+ std::string uniqueName = base::StringPrintf("%s#%u", name, dupeCounter);
// Grab the state lock since we're accessing mCurrentState
Mutex::Autolock lock(mStateLock);
// Loop over layers until we're sure there is no matching name
+ bool matchFound = true;
while (matchFound) {
matchFound = false;
mCurrentState.traverseInZOrder([&](Layer* layer) {
if (layer->getName() == uniqueName) {
matchFound = true;
- uniqueName = name + "#" + String8(std::to_string(++dupeCounter).c_str());
+ uniqueName = base::StringPrintf("%s#%u", name, ++dupeCounter);
}
});
}
- ALOGV_IF(dupeCounter > 0, "duplicate layer name: changing %s to %s", name.c_str(),
- uniqueName.c_str());
-
+ ALOGV_IF(dupeCounter > 0, "duplicate layer name: changing %s to %s", name, uniqueName.c_str());
return uniqueName;
}
-status_t SurfaceFlinger::createBufferQueueLayer(const sp<Client>& client, const String8& name,
+status_t SurfaceFlinger::createBufferQueueLayer(const sp<Client>& client, std::string name,
uint32_t w, uint32_t h, uint32_t flags,
LayerMetadata metadata, PixelFormat& format,
sp<IBinder>* handle,
@@ -3563,8 +3561,7 @@
}
sp<BufferQueueLayer> layer;
- LayerCreationArgs args =
- LayerCreationArgs(this, client, name, w, h, flags, std::move(metadata));
+ LayerCreationArgs args(this, client, std::move(name), w, h, flags, std::move(metadata));
args.textureName = getNewTexture();
{
// Grab the SF state lock during this since it's the only safe way to access
@@ -3585,12 +3582,11 @@
return err;
}
-status_t SurfaceFlinger::createBufferStateLayer(const sp<Client>& client, const String8& name,
+status_t SurfaceFlinger::createBufferStateLayer(const sp<Client>& client, std::string name,
uint32_t w, uint32_t h, uint32_t flags,
LayerMetadata metadata, sp<IBinder>* handle,
sp<Layer>* outLayer) {
- LayerCreationArgs args =
- LayerCreationArgs(this, client, name, w, h, flags, std::move(metadata));
+ LayerCreationArgs args(this, client, std::move(name), w, h, flags, std::move(metadata));
args.displayDevice = getDefaultDisplayDevice();
args.textureName = getNewTexture();
sp<BufferStateLayer> layer = getFactory().createBufferStateLayer(args);
@@ -3600,26 +3596,25 @@
return NO_ERROR;
}
-status_t SurfaceFlinger::createColorLayer(const sp<Client>& client, const String8& name, uint32_t w,
+status_t SurfaceFlinger::createColorLayer(const sp<Client>& client, std::string name, uint32_t w,
uint32_t h, uint32_t flags, LayerMetadata metadata,
sp<IBinder>* handle, sp<Layer>* outLayer) {
*outLayer = getFactory().createColorLayer(
- LayerCreationArgs(this, client, name, w, h, flags, std::move(metadata)));
+ {this, client, std::move(name), w, h, flags, std::move(metadata)});
*handle = (*outLayer)->getHandle();
return NO_ERROR;
}
-status_t SurfaceFlinger::createContainerLayer(const sp<Client>& client, const String8& name,
+status_t SurfaceFlinger::createContainerLayer(const sp<Client>& client, std::string name,
uint32_t w, uint32_t h, uint32_t flags,
LayerMetadata metadata, sp<IBinder>* handle,
sp<Layer>* outLayer) {
*outLayer = getFactory().createContainerLayer(
- LayerCreationArgs(this, client, name, w, h, flags, std::move(metadata)));
+ {this, client, std::move(name), w, h, flags, std::move(metadata)});
*handle = (*outLayer)->getHandle();
return NO_ERROR;
}
-
void SurfaceFlinger::markLayerPendingRemovalLocked(const sp<Layer>& layer) {
mLayersPendingRemoval.add(layer);
mLayersRemoved = true;
@@ -3828,8 +3823,6 @@
strerror(-err), err);
}
- using namespace std::string_literals;
-
static const std::unordered_map<std::string, Dumper> dumpers = {
{"--display-id"s, dumper(&SurfaceFlinger::dumpDisplayIdentificationData)},
{"--dispsync"s,
@@ -3885,7 +3878,7 @@
void SurfaceFlinger::listLayersLocked(std::string& result) const {
mCurrentState.traverseInZOrder(
- [&](Layer* layer) { StringAppendF(&result, "%s\n", layer->getName().string()); });
+ [&](Layer* layer) { StringAppendF(&result, "%s\n", layer->getDebugName()); });
}
void SurfaceFlinger::dumpStatsLocked(const DumpArgs& args, std::string& result) const {
@@ -3894,7 +3887,7 @@
if (args.size() > 1) {
const auto name = String8(args[1]);
mCurrentState.traverseInZOrder([&](Layer* layer) {
- if (name == layer->getName()) {
+ if (layer->getName() == name.string()) {
layer->dumpFrameStats(result);
}
});
@@ -3904,8 +3897,11 @@
}
void SurfaceFlinger::clearStatsLocked(const DumpArgs& args, std::string&) {
+ const bool clearAll = args.size() < 2;
+ const auto name = clearAll ? String8() : String8(args[1]);
+
mCurrentState.traverseInZOrder([&](Layer* layer) {
- if (args.size() < 2 || String8(args[1]) == layer->getName()) {
+ if (clearAll || layer->getName() == name.string()) {
layer->clearFrameStats();
}
});
@@ -3924,7 +3920,7 @@
layer->logFrameStats();
});
- mAnimFrameTracker.logAndResetStats(String8("<win-anim>"));
+ mAnimFrameTracker.logAndResetStats("<win-anim>");
}
void SurfaceFlinger::appendSfConfigString(std::string& result) const {
@@ -3982,8 +3978,8 @@
bucketTimeSec, percent);
}
-void SurfaceFlinger::recordBufferingStats(const char* layerName,
- std::vector<OccupancyTracker::Segment>&& history) {
+void SurfaceFlinger::recordBufferingStats(const std::string& layerName,
+ std::vector<OccupancyTracker::Segment>&& history) {
Mutex::Autolock lock(getBE().mBufferingStatsMutex);
auto& stats = getBE().mBufferingStats[layerName];
for (const auto& segment : history) {
@@ -5031,13 +5027,14 @@
drawLayers();
} else {
Rect bounds = getBounds();
+ uint32_t w = static_cast<uint32_t>(bounds.getWidth());
+ uint32_t h = static_cast<uint32_t>(bounds.getHeight());
// In the "childrenOnly" case we reparent the children to a screenshot
// layer which has no properties set and which does not draw.
sp<ContainerLayer> screenshotParentLayer =
- mFlinger->getFactory().createContainerLayer(
- LayerCreationArgs(mFlinger, nullptr, String8("Screenshot Parent"),
- bounds.getWidth(), bounds.getHeight(), 0,
- LayerMetadata()));
+ mFlinger->getFactory().createContainerLayer({mFlinger, nullptr,
+ "Screenshot Parent"s, w, h, 0,
+ LayerMetadata()});
ReparentForDrawing reparent(mLayer, screenshotParentLayer, sourceCrop);
drawLayers();
@@ -5454,7 +5451,7 @@
return NO_ERROR;
}
- postMessageSync(new LambdaMessage([&]() NO_THREAD_SAFETY_ANALYSIS {
+ postMessageSync(new LambdaMessage([&]() {
const auto display = getDisplayDeviceLocked(displayToken);
if (!display) {
ALOGE("Attempt to set allowed display configs for invalid display token %p",
@@ -5462,6 +5459,7 @@
} else if (display->isVirtual()) {
ALOGW("Attempt to set allowed display configs for virtual display");
} else {
+ Mutex::Autolock lock(mStateLock);
setAllowedDisplayConfigsInternal(display, allowedConfigs);
}
}));
@@ -5507,6 +5505,16 @@
return nullptr;
}
+void SurfaceFlinger::onLayerCreated(Layer* layer) {
+ mNumLayers++;
+ mScheduler->registerLayer(layer);
+}
+
+void SurfaceFlinger::onLayerDestroyed(Layer* layer) {
+ mNumLayers--;
+ mOffscreenLayers.erase(layer);
+}
+
void SurfaceFlinger::bufferErased(const client_cache_t& clientCacheId) {
getRenderEngine().unbindExternalTextureBuffer(clientCacheId.id);
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 9f3a914..abb8b82 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -310,11 +310,8 @@
bool authenticateSurfaceTextureLocked(
const sp<IGraphicBufferProducer>& bufferProducer) const;
- inline void onLayerCreated() { mNumLayers++; }
- inline void onLayerDestroyed(Layer* layer) {
- mNumLayers--;
- mOffscreenLayers.erase(layer);
- }
+ void onLayerCreated(Layer*);
+ void onLayerDestroyed(Layer*);
TransactionCompletedThread& getTransactionCompletedThread() {
return mTransactionCompletedThread;
@@ -607,27 +604,27 @@
sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp,
const sp<IBinder>& parentHandle, const sp<Layer>& parentLayer = nullptr);
- status_t createBufferQueueLayer(const sp<Client>& client, const String8& name, uint32_t w,
+ status_t createBufferQueueLayer(const sp<Client>& client, std::string name, uint32_t w,
uint32_t h, uint32_t flags, LayerMetadata metadata,
PixelFormat& format, sp<IBinder>* outHandle,
sp<IGraphicBufferProducer>* outGbp, sp<Layer>* outLayer);
- status_t createBufferStateLayer(const sp<Client>& client, const String8& name, uint32_t w,
+ status_t createBufferStateLayer(const sp<Client>& client, std::string name, uint32_t w,
uint32_t h, uint32_t flags, LayerMetadata metadata,
sp<IBinder>* outHandle, sp<Layer>* outLayer);
- status_t createColorLayer(const sp<Client>& client, const String8& name, uint32_t w, uint32_t h,
+ status_t createColorLayer(const sp<Client>& client, std::string name, uint32_t w, uint32_t h,
uint32_t flags, LayerMetadata metadata, sp<IBinder>* outHandle,
sp<Layer>* outLayer);
- status_t createContainerLayer(const sp<Client>& client, const String8& name, uint32_t w,
+ status_t createContainerLayer(const sp<Client>& client, std::string name, uint32_t w,
uint32_t h, uint32_t flags, LayerMetadata metadata,
sp<IBinder>* outHandle, sp<Layer>* outLayer);
status_t mirrorLayer(const sp<Client>& client, const sp<IBinder>& mirrorFromHandle,
sp<IBinder>* outHandle);
- String8 getUniqueLayerName(const String8& name);
+ std::string getUniqueLayerName(const char* name);
// called when all clients have released all their references to
// this layer meaning it is entirely safe to destroy all
@@ -866,8 +863,8 @@
// Not const because each Layer needs to query Fences and cache timestamps.
void dumpFrameEventsLocked(std::string& result);
- void recordBufferingStats(const char* layerName,
- std::vector<OccupancyTracker::Segment>&& history);
+ void recordBufferingStats(const std::string& layerName,
+ std::vector<OccupancyTracker::Segment>&& history);
void dumpBufferingStats(std::string& result) const;
void dumpDisplayIdentificationData(std::string& result) const;
void dumpRawDisplayIdentificationData(const DumpArgs&, std::string& result) const;
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index f0457e3..4f439da 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -17,12 +17,14 @@
#include <compositionengine/impl/CompositionEngine.h>
#include <ui/GraphicBuffer.h>
+#include "BufferLayerConsumer.h"
#include "BufferQueueLayer.h"
#include "BufferStateLayer.h"
#include "ColorLayer.h"
#include "ContainerLayer.h"
#include "DisplayDevice.h"
#include "Layer.h"
+#include "MonitoredProducer.h"
#include "NativeWindowSurface.h"
#include "StartPropertySetThread.h"
#include "SurfaceFlingerDefaultFactory.h"
@@ -92,6 +94,18 @@
BufferQueue::createBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger);
}
+sp<IGraphicBufferProducer> DefaultFactory::createMonitoredProducer(
+ const sp<IGraphicBufferProducer>& producer, const sp<SurfaceFlinger>& flinger,
+ const wp<Layer>& layer) {
+ return new MonitoredProducer(producer, flinger, layer);
+}
+
+sp<BufferLayerConsumer> DefaultFactory::createBufferLayerConsumer(
+ const sp<IGraphicBufferConsumer>& consumer, renderengine::RenderEngine& renderEngine,
+ uint32_t textureName, Layer* layer) {
+ return new BufferLayerConsumer(consumer, renderEngine, textureName, layer);
+}
+
std::unique_ptr<surfaceflinger::NativeWindowSurface> DefaultFactory::createNativeWindowSurface(
const sp<IGraphicBufferProducer>& producer) {
return surfaceflinger::impl::createNativeWindowSurface(producer);
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index 89e0679..42bb177 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -42,6 +42,12 @@
void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer,
bool consumerIsSurfaceFlinger) override;
+ sp<IGraphicBufferProducer> createMonitoredProducer(const sp<IGraphicBufferProducer>&,
+ const sp<SurfaceFlinger>&,
+ const wp<Layer>&) override;
+ sp<BufferLayerConsumer> createBufferLayerConsumer(const sp<IGraphicBufferConsumer>&,
+ renderengine::RenderEngine&, uint32_t tex,
+ Layer*) override;
std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
const sp<IGraphicBufferProducer>&) override;
std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() override;
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index 3fd4de8..20784d2 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -30,6 +30,7 @@
class BufferQueueLayer;
class BufferStateLayer;
+class BufferLayerConsumer;
class ColorLayer;
class ContainerLayer;
class DisplayDevice;
@@ -39,6 +40,7 @@
class HWComposer;
class IGraphicBufferConsumer;
class IGraphicBufferProducer;
+class Layer;
class MessageQueue;
class Scheduler;
class StartPropertySetThread;
@@ -85,6 +87,13 @@
virtual void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer,
bool consumerIsSurfaceFlinger) = 0;
+ virtual sp<IGraphicBufferProducer> createMonitoredProducer(const sp<IGraphicBufferProducer>&,
+ const sp<SurfaceFlinger>&,
+ const wp<Layer>&) = 0;
+ virtual sp<BufferLayerConsumer> createBufferLayerConsumer(const sp<IGraphicBufferConsumer>&,
+ renderengine::RenderEngine&,
+ uint32_t tex, Layer*) = 0;
+
virtual std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
const sp<IGraphicBufferProducer>&) = 0;
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index a02d14c..7e6c472 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -165,10 +165,6 @@
return layer;
}
-const std::string SurfaceInterceptor::getLayerName(const sp<const Layer>& layer) const {
- return layer->getName().string();
-}
-
int32_t SurfaceInterceptor::getLayerId(const sp<const Layer>& layer) const {
return layer->sequence;
}
@@ -490,7 +486,7 @@
{
SurfaceCreation* creation(increment->mutable_surface_creation());
creation->set_id(getLayerId(layer));
- creation->set_name(getLayerName(layer));
+ creation->set_name(layer->getName());
creation->set_w(layer->mCurrentState.active_legacy.w);
creation->set_h(layer->mCurrentState.active_legacy.h);
}
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index 6858c4d..72b734b 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -123,7 +123,6 @@
status_t writeProtoFileLocked();
const sp<const Layer> getLayer(const wp<const IBinder>& weakHandle) const;
- const std::string getLayerName(const sp<const Layer>& layer) const;
int32_t getLayerId(const sp<const Layer>& layer) const;
int32_t getLayerIdFromWeakRef(const wp<const Layer>& layer) const;
int32_t getLayerIdFromHandle(const sp<const IBinder>& weakHandle) const;
diff --git a/services/surfaceflinger/TimeStats/OWNERS b/services/surfaceflinger/TimeStats/OWNERS
index ac02d12..1441f91 100644
--- a/services/surfaceflinger/TimeStats/OWNERS
+++ b/services/surfaceflinger/TimeStats/OWNERS
@@ -1 +1,2 @@
-zzyiwei@google.com
\ No newline at end of file
+alecmouri@google.com
+zzyiwei@google.com
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
index 92e59d7..8db03db 100644
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -234,7 +234,8 @@
sp<IBinder> surfaceControl = handle->surfaceControl.promote();
if (surfaceControl) {
transactionStats->surfaceStats.emplace_back(surfaceControl, handle->acquireTime,
- handle->previousReleaseFence);
+ handle->previousReleaseFence,
+ handle->transformHint);
}
return NO_ERROR;
}
diff --git a/services/surfaceflinger/TransactionCompletedThread.h b/services/surfaceflinger/TransactionCompletedThread.h
index a85ad1e..12ea8fe 100644
--- a/services/surfaceflinger/TransactionCompletedThread.h
+++ b/services/surfaceflinger/TransactionCompletedThread.h
@@ -44,6 +44,7 @@
sp<Fence> previousReleaseFence;
nsecs_t acquireTime = -1;
nsecs_t latchTime = -1;
+ uint32_t transformHint = 0;
};
class TransactionCompletedThread {
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 2183d34..f85da20 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -53,6 +53,7 @@
"TimeStatsTest.cpp",
"FrameTracerTest.cpp",
"TransactionApplicationTest.cpp",
+ "StrongTypingTest.cpp",
"mock/DisplayHardware/MockComposer.cpp",
"mock/DisplayHardware/MockDisplay.cpp",
"mock/DisplayHardware/MockPowerAdvisor.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 8aff096..60da70f 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -839,7 +839,7 @@
static FlingerLayerType createLayer(CompositionTest* test) {
FlingerLayerType layer = Base::template createLayerWithFactory<ColorLayer>(test, [test]() {
return new ColorLayer(LayerCreationArgs(test->mFlinger.mFlinger.get(), sp<Client>(),
- String8("test-layer"), LayerProperties::WIDTH,
+ "test-layer", LayerProperties::WIDTH,
LayerProperties::HEIGHT,
LayerProperties::LAYER_FLAGS, LayerMetadata()));
});
@@ -879,11 +879,9 @@
FlingerLayerType layer =
Base::template createLayerWithFactory<BufferQueueLayer>(test, [test]() {
sp<Client> client;
- String8 name("test-layer");
- LayerCreationArgs args =
- LayerCreationArgs(test->mFlinger.mFlinger.get(), client, name,
- LayerProperties::WIDTH, LayerProperties::HEIGHT,
- LayerProperties::LAYER_FLAGS, LayerMetadata());
+ LayerCreationArgs args(test->mFlinger.mFlinger.get(), client, "test-layer",
+ LayerProperties::WIDTH, LayerProperties::HEIGHT,
+ LayerProperties::LAYER_FLAGS, LayerMetadata());
args.textureName = test->mFlinger.mutableTexturePool().back();
return new BufferQueueLayer(args);
});
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index 8e7440c..9a962bc 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -1,140 +1,243 @@
#undef LOG_TAG
-#define LOG_TAG "LayerHistoryUnittests"
+#define LOG_TAG "LayerHistoryTest"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-
#include <log/log.h>
-#include <mutex>
-#include <thread>
-
#include "Scheduler/LayerHistory.h"
+#include "Scheduler/LayerInfo.h"
+#include "TestableScheduler.h"
+#include "TestableSurfaceFlinger.h"
+#include "mock/MockLayer.h"
using testing::_;
using testing::Return;
-namespace android {
-namespace scheduler {
+namespace android::scheduler {
class LayerHistoryTest : public testing::Test {
-public:
- LayerHistoryTest();
- ~LayerHistoryTest() override;
-
protected:
- std::unique_ptr<LayerHistory> mLayerHistory;
+ static constexpr auto PRESENT_TIME_HISTORY_SIZE = LayerInfo::PresentTimeHistory::HISTORY_SIZE;
+ static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = LayerInfo::MAX_FREQUENT_LAYER_PERIOD_NS;
- static constexpr float MIN_REFRESH_RATE = 30.f;
- static constexpr float MAX_REFRESH_RATE = 90.f;
- static constexpr auto RELEVANT_FRAME_THRESHOLD = 90u;
- static constexpr uint64_t THIRTY_FPS_INTERVAL = 33'333'333;
+ static constexpr float LO_FPS = 30.f;
+ static constexpr nsecs_t LO_FPS_PERIOD = 33'333'333;
- void forceRelevancy(const std::unique_ptr<LayerHistory::LayerHandle>& testLayer) {
- mLayerHistory->setVisibility(testLayer, true);
- for (auto i = 0u; i < RELEVANT_FRAME_THRESHOLD; i++) {
- mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
- }
- };
-};
+ static constexpr float HI_FPS = 90.f;
+ static constexpr nsecs_t HI_FPS_PERIOD = 11'111'111;
-LayerHistoryTest::LayerHistoryTest() {
- mLayerHistory = std::make_unique<LayerHistory>();
-}
-LayerHistoryTest::~LayerHistoryTest() {}
+ LayerHistoryTest() { mFlinger.resetScheduler(mScheduler); }
-namespace {
-TEST_F(LayerHistoryTest, oneLayer) {
- std::unique_ptr<LayerHistory::LayerHandle> testLayer =
- mLayerHistory->createLayer("TestLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
- mLayerHistory->setVisibility(testLayer, true);
- for (auto i = 0u; i < RELEVANT_FRAME_THRESHOLD; i++) {
- EXPECT_FLOAT_EQ(0.f, mLayerHistory->getDesiredRefreshRateAndHDR().first);
- mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
+ LayerHistory& history() { return mScheduler->mutableLayerHistory(); }
+ const LayerHistory& history() const { return mScheduler->mutableLayerHistory(); }
+
+ size_t layerCount() const NO_THREAD_SAFETY_ANALYSIS { return history().mLayerInfos.size(); }
+ size_t activeLayerCount() const NO_THREAD_SAFETY_ANALYSIS { return history().mActiveLayersEnd; }
+
+ size_t frequentLayerCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS {
+ const auto& infos = history().mLayerInfos;
+ return std::count_if(infos.begin(), infos.begin() + history().mActiveLayersEnd,
+ [now](const auto& pair) { return pair.second->isFrequent(now); });
}
- // Add a few more. This time we should get MAX refresh rate as the layer
- // becomes relevant
- static constexpr auto A_FEW = 10;
- for (auto i = 0u; i < A_FEW; i++) {
- EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first);
- mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
+ auto createLayer() { return sp<mock::MockLayer>(new mock::MockLayer(mFlinger.flinger())); }
+
+ RefreshRateConfigs mConfigs{true,
+ {RefreshRateConfigs::InputConfig{0, LO_FPS_PERIOD},
+ RefreshRateConfigs::InputConfig{1, HI_FPS_PERIOD}},
+ 0};
+ TestableScheduler* const mScheduler{new TestableScheduler(mConfigs)};
+ TestableSurfaceFlinger mFlinger;
+
+ const nsecs_t mTime = systemTime();
+};
+
+namespace {
+
+TEST_F(LayerHistoryTest, oneLayer) {
+ const auto layer = createLayer();
+ constexpr bool isHDR = false;
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+
+ // 0 FPS is returned if no layers are active.
+ EXPECT_FLOAT_EQ(0, history().summarize(mTime).maxRefreshRate);
+ EXPECT_EQ(0, activeLayerCount());
+
+ // 0 FPS is returned if active layers have insufficient history.
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
+ history().record(layer.get(), 0, isHDR, mTime);
+ EXPECT_FLOAT_EQ(0, history().summarize(mTime).maxRefreshRate);
+ EXPECT_EQ(1, activeLayerCount());
+ }
+
+ // High FPS is returned once enough history has been recorded.
+ for (int i = 0; i < 10; i++) {
+ history().record(layer.get(), 0, isHDR, mTime);
+ EXPECT_FLOAT_EQ(HI_FPS, history().summarize(mTime).maxRefreshRate);
+ EXPECT_EQ(1, activeLayerCount());
}
}
TEST_F(LayerHistoryTest, oneHDRLayer) {
- std::unique_ptr<LayerHistory::LayerHandle> testLayer =
- mLayerHistory->createLayer("TestHDRLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
- mLayerHistory->setVisibility(testLayer, true);
+ const auto layer = createLayer();
+ constexpr bool isHDR = true;
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- mLayerHistory->insert(testLayer, 0, true /*isHDR*/);
- EXPECT_FLOAT_EQ(0.0f, mLayerHistory->getDesiredRefreshRateAndHDR().first);
- EXPECT_EQ(true, mLayerHistory->getDesiredRefreshRateAndHDR().second);
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
- mLayerHistory->setVisibility(testLayer, false);
- EXPECT_FLOAT_EQ(0.0f, mLayerHistory->getDesiredRefreshRateAndHDR().first);
- EXPECT_EQ(false, mLayerHistory->getDesiredRefreshRateAndHDR().second);
+ history().record(layer.get(), 0, isHDR, mTime);
+ auto summary = history().summarize(mTime);
+ EXPECT_FLOAT_EQ(0, summary.maxRefreshRate);
+ EXPECT_TRUE(summary.isHDR);
+ EXPECT_EQ(1, activeLayerCount());
+
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(false));
+
+ summary = history().summarize(mTime);
+ EXPECT_FLOAT_EQ(0, summary.maxRefreshRate);
+ EXPECT_FALSE(summary.isHDR);
+ EXPECT_EQ(0, activeLayerCount());
}
TEST_F(LayerHistoryTest, explicitTimestamp) {
- std::unique_ptr<LayerHistory::LayerHandle> test30FpsLayer =
- mLayerHistory->createLayer("30FpsLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
- mLayerHistory->setVisibility(test30FpsLayer, true);
+ const auto layer = createLayer();
+ constexpr bool isHDR = false;
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- nsecs_t startTime = systemTime();
- for (int i = 0; i < RELEVANT_FRAME_THRESHOLD; i++) {
- mLayerHistory->insert(test30FpsLayer, startTime + (i * THIRTY_FPS_INTERVAL),
- false /*isHDR*/);
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+
+ nsecs_t time = mTime;
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer.get(), time, isHDR, time);
+ time += LO_FPS_PERIOD;
}
- EXPECT_FLOAT_EQ(30.f, mLayerHistory->getDesiredRefreshRateAndHDR().first);
+ EXPECT_FLOAT_EQ(LO_FPS, history().summarize(mTime).maxRefreshRate);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
}
TEST_F(LayerHistoryTest, multipleLayers) {
- std::unique_ptr<LayerHistory::LayerHandle> testLayer =
- mLayerHistory->createLayer("TestLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
- mLayerHistory->setVisibility(testLayer, true);
- std::unique_ptr<LayerHistory::LayerHandle> test30FpsLayer =
- mLayerHistory->createLayer("30FpsLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
- mLayerHistory->setVisibility(test30FpsLayer, true);
- std::unique_ptr<LayerHistory::LayerHandle> testLayer2 =
- mLayerHistory->createLayer("TestLayer2", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
- mLayerHistory->setVisibility(testLayer2, true);
+ auto layer1 = createLayer();
+ auto layer2 = createLayer();
+ auto layer3 = createLayer();
+ constexpr bool isHDR = false;
- nsecs_t startTime = systemTime();
- for (int i = 0; i < RELEVANT_FRAME_THRESHOLD; i++) {
- mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
+ EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer2, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer3, isVisible()).WillRepeatedly(Return(true));
+
+ nsecs_t time = mTime;
+
+ EXPECT_EQ(3, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+
+ // layer1 is active but infrequent.
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer1.get(), time, isHDR, time);
+ time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
}
- EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first);
- startTime = systemTime();
- for (int i = 0; i < RELEVANT_FRAME_THRESHOLD; i++) {
- mLayerHistory->insert(test30FpsLayer, startTime + (i * THIRTY_FPS_INTERVAL),
- false /*isHDR*/);
+ EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time).maxRefreshRate);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+
+ // layer2 is frequent and has high refresh rate.
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer2.get(), time, isHDR, time);
+ time += HI_FPS_PERIOD;
}
- EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first);
- for (int i = 10; i < RELEVANT_FRAME_THRESHOLD; i++) {
- mLayerHistory->insert(test30FpsLayer, startTime + (i * THIRTY_FPS_INTERVAL),
- false /*isHDR*/);
+ // layer1 is still active but infrequent.
+ history().record(layer1.get(), time, isHDR, time);
+
+ EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time).maxRefreshRate);
+ EXPECT_EQ(2, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer1 is no longer active.
+ // layer2 is frequent and has low refresh rate.
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer2.get(), time, isHDR, time);
+ time += LO_FPS_PERIOD;
}
- EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first);
- // This frame is only around for 9 occurrences, so it doesn't throw
- // anything off.
- for (int i = 0; i < 9; i++) {
- mLayerHistory->insert(testLayer2, 0, false /*isHDR*/);
+ EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time).maxRefreshRate);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer2 still has low refresh rate.
+ // layer3 has high refresh rate but not enough history.
+ constexpr int RATIO = LO_FPS_PERIOD / HI_FPS_PERIOD;
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
+ if (i % RATIO == 0) {
+ history().record(layer2.get(), time, isHDR, time);
+ }
+
+ history().record(layer3.get(), time, isHDR, time);
+ time += HI_FPS_PERIOD;
}
- EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first);
- // After 1200 ms frames become obsolete.
- std::this_thread::sleep_for(std::chrono::milliseconds(1500));
- mLayerHistory->insert(test30FpsLayer,
- startTime + (RELEVANT_FRAME_THRESHOLD * THIRTY_FPS_INTERVAL),
- false /*isHDR*/);
- EXPECT_FLOAT_EQ(30.f, mLayerHistory->getDesiredRefreshRateAndHDR().first);
+ EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time).maxRefreshRate);
+ EXPECT_EQ(2, activeLayerCount());
+ EXPECT_EQ(2, frequentLayerCount(time));
+
+ // layer3 becomes recently active.
+ history().record(layer3.get(), time, isHDR, time);
+ EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time).maxRefreshRate);
+ EXPECT_EQ(2, activeLayerCount());
+ EXPECT_EQ(2, frequentLayerCount(time));
+
+ // layer1 expires.
+ layer1.clear();
+ EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time).maxRefreshRate);
+ EXPECT_EQ(2, layerCount());
+ EXPECT_EQ(2, activeLayerCount());
+ EXPECT_EQ(2, frequentLayerCount(time));
+
+ // layer2 still has low refresh rate.
+ // layer3 becomes inactive.
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer2.get(), time, isHDR, time);
+ time += LO_FPS_PERIOD;
+ }
+
+ EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time).maxRefreshRate);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer2 expires.
+ layer2.clear();
+ EXPECT_FLOAT_EQ(0, history().summarize(time).maxRefreshRate);
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+
+ // layer3 becomes active and has high refresh rate.
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer3.get(), time, isHDR, time);
+ time += HI_FPS_PERIOD;
+ }
+
+ EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time).maxRefreshRate);
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer3 expires.
+ layer3.clear();
+ EXPECT_FLOAT_EQ(0, history().summarize(time).maxRefreshRate);
+ EXPECT_EQ(0, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
}
} // namespace
-} // namespace scheduler
-} // namespace android
\ No newline at end of file
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/StrongTypingTest.cpp b/services/surfaceflinger/tests/unittests/StrongTypingTest.cpp
new file mode 100644
index 0000000..b9ddcd7
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/StrongTypingTest.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include "Scheduler/StrongTyping.h"
+
+using namespace testing;
+
+namespace android {
+
+TEST(StrongTypeTest, comparison) {
+ using SpunkyType = StrongTyping<int, struct SpunkyTypeTag, Compare>;
+ SpunkyType f2(22);
+ SpunkyType f1(10);
+
+ EXPECT_TRUE(f1 == f1);
+ EXPECT_TRUE(SpunkyType(10) != SpunkyType(11));
+ EXPECT_FALSE(SpunkyType(31) != SpunkyType(31));
+
+ EXPECT_TRUE(SpunkyType(10) < SpunkyType(11));
+ EXPECT_TRUE(SpunkyType(-1) < SpunkyType(0));
+ EXPECT_FALSE(SpunkyType(-10) < SpunkyType(-20));
+
+ EXPECT_TRUE(SpunkyType(10) <= SpunkyType(11));
+ EXPECT_TRUE(SpunkyType(10) <= SpunkyType(10));
+ EXPECT_TRUE(SpunkyType(-10) <= SpunkyType(1));
+ EXPECT_FALSE(SpunkyType(10) <= SpunkyType(9));
+
+ EXPECT_TRUE(SpunkyType(11) >= SpunkyType(11));
+ EXPECT_TRUE(SpunkyType(12) >= SpunkyType(11));
+ EXPECT_FALSE(SpunkyType(11) >= SpunkyType(12));
+
+ EXPECT_FALSE(SpunkyType(11) > SpunkyType(12));
+ EXPECT_TRUE(SpunkyType(-11) < SpunkyType(7));
+}
+
+TEST(StrongTypeTest, addition) {
+ using FunkyType = StrongTyping<int, struct FunkyTypeTag, Compare, Add>;
+ FunkyType f2(22);
+ FunkyType f1(10);
+
+ EXPECT_THAT(f1 + f2, Eq(FunkyType(32)));
+ EXPECT_THAT(f2 + f1, Eq(FunkyType(32)));
+
+ EXPECT_THAT(++f1, Eq(11));
+ EXPECT_THAT(f1, Eq(11));
+ EXPECT_THAT(f1++, Eq(11));
+ EXPECT_THAT(f1++, Eq(12));
+ EXPECT_THAT(f1, Eq(13));
+
+ auto f3 = f1;
+ EXPECT_THAT(f1, Eq(f3));
+ EXPECT_THAT(f1, Lt(f2));
+
+ f3 += f1;
+ EXPECT_THAT(f1, Eq(13));
+ EXPECT_THAT(f3, Eq(26));
+}
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index ae72467..ae6aa89 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -48,6 +48,7 @@
auto& mutableEventControlThread() { return mEventControlThread; }
auto& mutablePrimaryDispSync() { return mPrimaryDispSync; }
auto& mutableHWVsyncAvailable() { return mHWVsyncAvailable; }
+ auto& mutableLayerHistory() { return mLayerHistory; }
~TestableScheduler() {
// All these pointer and container clears help ensure that GMock does
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index b85c1b6..94fc5f7 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -22,6 +22,7 @@
#include <compositionengine/OutputLayer.h>
#include <compositionengine/impl/CompositionEngine.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
+#include <compositionengine/mock/DisplaySurface.h>
#include "BufferQueueLayer.h"
#include "BufferStateLayer.h"
@@ -62,23 +63,19 @@
~Factory() = default;
std::unique_ptr<DispSync> createDispSync(const char*, bool) override {
- // TODO: Use test-fixture controlled factory
return nullptr;
}
std::unique_ptr<EventControlThread> createEventControlThread(
std::function<void(bool)>) override {
- // TODO: Use test-fixture controlled factory
return nullptr;
}
std::unique_ptr<HWComposer> createHWComposer(const std::string&) override {
- // TODO: Use test-fixture controlled factory
return nullptr;
}
std::unique_ptr<MessageQueue> createMessageQueue() override {
- // TODO: Use test-fixture controlled factory
return std::make_unique<android::impl::MessageQueue>();
}
@@ -88,39 +85,49 @@
std::unique_ptr<Scheduler> createScheduler(std::function<void(bool)>,
const scheduler::RefreshRateConfigs&) override {
- // TODO: Use test-fixture controlled factory
return nullptr;
}
std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger* flinger) override {
- // TODO: Use test-fixture controlled factory
return std::make_unique<android::impl::SurfaceInterceptor>(flinger);
}
sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override {
- // TODO: Use test-fixture controlled factory
return new StartPropertySetThread(timestampPropertyValue);
}
sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&& creationArgs) override {
- // TODO: Use test-fixture controlled factory
return new DisplayDevice(std::move(creationArgs));
}
sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format,
uint32_t layerCount, uint64_t usage,
std::string requestorName) override {
- // TODO: Use test-fixture controlled factory
return new GraphicBuffer(width, height, format, layerCount, usage, requestorName);
}
void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer,
bool consumerIsSurfaceFlinger) override {
- if (!mCreateBufferQueue) return;
+ if (!mCreateBufferQueue) {
+ BufferQueue::createBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger);
+ return;
+ }
mCreateBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger);
}
+ sp<IGraphicBufferProducer> createMonitoredProducer(const sp<IGraphicBufferProducer>& producer,
+ const sp<SurfaceFlinger>& flinger,
+ const wp<Layer>& layer) override {
+ return new MonitoredProducer(producer, flinger, layer);
+ }
+
+ sp<BufferLayerConsumer> createBufferLayerConsumer(const sp<IGraphicBufferConsumer>& consumer,
+ renderengine::RenderEngine& renderEngine,
+ uint32_t textureName, Layer* layer) override {
+ return new BufferLayerConsumer(consumer, renderEngine, textureName, layer);
+ }
+
std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
const sp<IGraphicBufferProducer>& producer) override {
if (!mCreateNativeWindowSurface) return nullptr;
@@ -132,22 +139,18 @@
}
sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs&) override {
- // TODO: Use test-fixture controlled factory
return nullptr;
}
sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs&) override {
- // TODO: Use test-fixture controlled factory
return nullptr;
}
sp<ColorLayer> createColorLayer(const LayerCreationArgs&) override {
- // TODO: Use test-fixture controlled factory
return nullptr;
}
sp<ContainerLayer> createContainerLayer(const LayerCreationArgs&) override {
- // TODO: Use test-fixture controlled factory
return nullptr;
}
@@ -171,6 +174,7 @@
class TestableSurfaceFlinger {
public:
+ SurfaceFlinger* flinger() { return mFlinger.get(); }
TestableScheduler* scheduler() { return mScheduler; }
// Extend this as needed for accessing SurfaceFlinger private (and public)
@@ -205,13 +209,15 @@
mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread));
mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread));
+ resetScheduler(mScheduler);
- mFlinger->mScheduler.reset(mScheduler);
mFlinger->mVSyncModulator.emplace(*mScheduler, mFlinger->mAppConnectionHandle,
mFlinger->mSfConnectionHandle,
mFlinger->mPhaseOffsets->getCurrentOffsets());
}
+ void resetScheduler(Scheduler* scheduler) { mFlinger->mScheduler.reset(scheduler); }
+
using CreateBufferQueueFunction = surfaceflinger::test::Factory::CreateBufferQueueFunction;
void setCreateBufferQueueFunction(CreateBufferQueueFunction f) {
mFactory.mCreateBufferQueue = f;
diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
new file mode 100644
index 0000000..f375e23
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "Layer.h"
+
+namespace android::mock {
+
+class MockLayer : public Layer {
+public:
+ explicit MockLayer(SurfaceFlinger* flinger)
+ : Layer(LayerCreationArgs(flinger, nullptr, "TestLayer", 800, 600, 0, {})) {}
+
+ MOCK_CONST_METHOD0(getType, const char*());
+ MOCK_CONST_METHOD0(isVisible, bool());
+ MOCK_METHOD0(createClone, sp<Layer>());
+};
+
+} // namespace android::mock
diff --git a/services/surfaceflinger/tests/utils/CallbackUtils.h b/services/surfaceflinger/tests/utils/CallbackUtils.h
index 51ae8c4..4e2b7c3 100644
--- a/services/surfaceflinger/tests/utils/CallbackUtils.h
+++ b/services/surfaceflinger/tests/utils/CallbackUtils.h
@@ -121,7 +121,8 @@
void verifySurfaceControlStats(const SurfaceControlStats& surfaceControlStats,
nsecs_t latchTime) const {
- const auto& [surfaceControl, acquireTime, previousReleaseFence] = surfaceControlStats;
+ const auto& [surfaceControl, acquireTime, previousReleaseFence, transformHint] =
+ surfaceControlStats;
ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED)
<< "bad acquire time";
diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp
index 48f26e7..24039b1 100644
--- a/vulkan/libvulkan/api.cpp
+++ b/vulkan/libvulkan/api.cpp
@@ -519,7 +519,11 @@
get_device_proc_addr_(nullptr),
driver_extensions_(nullptr),
driver_extension_count_(0) {
- enabled_extensions_.set(driver::ProcHook::EXTENSION_CORE);
+ // advertise the loader supported core Vulkan API version at vulkan::api
+ for (uint32_t i = driver::ProcHook::EXTENSION_CORE_1_0;
+ i != driver::ProcHook::EXTENSION_COUNT; ++i) {
+ enabled_extensions_.set(i);
+ }
}
LayerChain::~LayerChain() {
@@ -1275,7 +1279,7 @@
return *pPropertyCount < count ? VK_INCOMPLETE : VK_SUCCESS;
}
- // TODO how about extensions from implicitly enabled layers?
+ // TODO(b/143293104): expose extensions from implicitly enabled layers
return vulkan::driver::EnumerateInstanceExtensionProperties(
nullptr, pPropertyCount, pProperties);
}
@@ -1329,7 +1333,7 @@
return *pPropertyCount < count ? VK_INCOMPLETE : VK_SUCCESS;
}
- // TODO how about extensions from implicitly enabled layers?
+ // TODO(b/143293104): expose extensions from implicitly enabled layers
const InstanceData& data = GetData(physicalDevice);
return data.dispatch.EnumerateDeviceExtensionProperties(
physicalDevice, nullptr, pPropertyCount, pProperties);
diff --git a/vulkan/libvulkan/debug_report.h b/vulkan/libvulkan/debug_report.h
index 3d8bd50..e5b1587 100644
--- a/vulkan/libvulkan/debug_report.h
+++ b/vulkan/libvulkan/debug_report.h
@@ -78,7 +78,7 @@
VkDebugReportCallbackEXT driver_handle;
};
- // TODO(jessehall): replace with std::shared_mutex when available in libc++
+ // TODO(b/143295577): use std::shared_mutex when available in libc++
mutable std::shared_timed_mutex rwmutex_;
Node head_;
};
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index b413ac9..d92f35a 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -37,7 +37,10 @@
#include <algorithm>
#include <array>
+#include <climits>
#include <new>
+#include <string_view>
+#include <sstream>
#include <vector>
#include "stubhal.h"
@@ -99,6 +102,7 @@
VkResult Validate();
void DowngradeApiVersion();
+ void UpgradeDeviceCoreApiVersion(uint32_t api_version);
const std::bitset<ProcHook::EXTENSION_COUNT>& GetHookExtensions() const;
const std::bitset<ProcHook::EXTENSION_COUNT>& GetHalExtensions() const;
@@ -147,15 +151,12 @@
Hal Hal::hal_;
void* LoadLibrary(const android_dlextinfo& dlextinfo,
- const char* subname,
- int subname_len) {
+ const std::string_view subname) {
ATRACE_CALL();
- const char kLibFormat[] = "vulkan.%*s.so";
- char* name = static_cast<char*>(
- alloca(sizeof(kLibFormat) + static_cast<size_t>(subname_len)));
- sprintf(name, kLibFormat, subname_len, subname);
- return android_dlopen_ext(name, RTLD_LOCAL | RTLD_NOW, &dlextinfo);
+ std::stringstream ss;
+ ss << "vulkan." << subname << ".so";
+ return android_dlopen_ext(ss.str().c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo);
}
const std::array<const char*, 2> HAL_SUBNAME_KEY_PROPERTIES = {{
@@ -175,8 +176,9 @@
char prop[PROPERTY_VALUE_MAX];
for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
int prop_len = property_get(key, prop, nullptr);
- if (prop_len > 0) {
- so = LoadLibrary(dlextinfo, prop, prop_len);
+ if (prop_len > 0 && prop_len <= UINT_MAX) {
+ std::string_view lib_name(prop, static_cast<unsigned int>(prop_len));
+ so = LoadLibrary(dlextinfo, lib_name);
if (so)
break;
}
@@ -328,8 +330,12 @@
physical_dev_(VK_NULL_HANDLE),
instance_info_(create_info),
extension_filter_() {
- hook_extensions_.set(ProcHook::EXTENSION_CORE);
- hal_extensions_.set(ProcHook::EXTENSION_CORE);
+ // instance core versions need to match the loader api version
+ for (uint32_t i = ProcHook::EXTENSION_CORE_1_0;
+ i != ProcHook::EXTENSION_COUNT; ++i) {
+ hook_extensions_.set(i);
+ hal_extensions_.set(i);
+ }
}
CreateInfoWrapper::CreateInfoWrapper(VkPhysicalDevice physical_dev,
@@ -340,8 +346,9 @@
physical_dev_(physical_dev),
dev_info_(create_info),
extension_filter_() {
- hook_extensions_.set(ProcHook::EXTENSION_CORE);
- hal_extensions_.set(ProcHook::EXTENSION_CORE);
+ // initialize with baseline core API version
+ hook_extensions_.set(ProcHook::EXTENSION_CORE_1_0);
+ hal_extensions_.set(ProcHook::EXTENSION_CORE_1_0);
}
CreateInfoWrapper::~CreateInfoWrapper() {
@@ -540,7 +547,8 @@
case ProcHook::ANDROID_external_memory_android_hardware_buffer:
case ProcHook::ANDROID_native_buffer:
case ProcHook::GOOGLE_display_timing:
- case ProcHook::EXTENSION_CORE:
+ case ProcHook::EXTENSION_CORE_1_0:
+ case ProcHook::EXTENSION_CORE_1_1:
case ProcHook::EXTENSION_COUNT:
// Device and meta extensions. If we ever get here it's a bug in
// our code. But enumerating them lets us avoid having a default
@@ -588,7 +596,8 @@
case ProcHook::EXT_debug_report:
case ProcHook::EXT_swapchain_colorspace:
case ProcHook::ANDROID_native_buffer:
- case ProcHook::EXTENSION_CORE:
+ case ProcHook::EXTENSION_CORE_1_0:
+ case ProcHook::EXTENSION_CORE_1_1:
case ProcHook::EXTENSION_COUNT:
// Instance and meta extensions. If we ever get here it's a bug
// in our code. But enumerating them lets us avoid having a
@@ -636,6 +645,31 @@
}
}
+void CreateInfoWrapper::UpgradeDeviceCoreApiVersion(uint32_t api_version) {
+ ALOG_ASSERT(!is_instance_, "Device only API called by instance wrapper.");
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wold-style-cast"
+ api_version ^= VK_VERSION_PATCH(api_version);
+#pragma clang diagnostic pop
+
+ // cap the API version to the loader supported highest version
+ if (api_version > VK_API_VERSION_1_1)
+ api_version = VK_API_VERSION_1_1;
+
+ switch (api_version) {
+ case VK_API_VERSION_1_1:
+ hook_extensions_.set(ProcHook::EXTENSION_CORE_1_1);
+ hal_extensions_.set(ProcHook::EXTENSION_CORE_1_1);
+ [[clang::fallthrough]];
+ case VK_API_VERSION_1_0:
+ break;
+ default:
+ ALOGD("Unknown upgrade API version[%u]", api_version);
+ break;
+ }
+}
+
VKAPI_ATTR void* DefaultAllocate(void*,
size_t size,
size_t alignment,
@@ -659,7 +693,7 @@
return nullptr;
}
- // TODO(jessehall): Right now we never shrink allocations; if the new
+ // TODO(b/143295633): Right now we never shrink allocations; if the new
// request is smaller than the existing chunk, we just continue using it.
// Right now the loader never reallocs, so this doesn't matter. If that
// changes, or if this code is copied into some other project, this should
@@ -771,7 +805,7 @@
: nullptr;
break;
case ProcHook::DEVICE:
- proc = (hook->extension == ProcHook::EXTENSION_CORE)
+ proc = (hook->extension == ProcHook::EXTENSION_CORE_1_0)
? hook->proc
: hook->checked_proc;
break;
@@ -1117,6 +1151,13 @@
if (!data)
return VK_ERROR_OUT_OF_HOST_MEMORY;
+ VkPhysicalDeviceProperties properties;
+ ATRACE_BEGIN("driver.GetPhysicalDeviceProperties");
+ instance_data.driver.GetPhysicalDeviceProperties(physicalDevice,
+ &properties);
+ ATRACE_END();
+
+ wrapper.UpgradeDeviceCoreApiVersion(properties.apiVersion);
data->hook_extensions |= wrapper.GetHookExtensions();
// call into the driver
@@ -1161,12 +1202,6 @@
return VK_ERROR_INCOMPATIBLE_DRIVER;
}
- VkPhysicalDeviceProperties properties;
- ATRACE_BEGIN("driver.GetPhysicalDeviceProperties");
- instance_data.driver.GetPhysicalDeviceProperties(physicalDevice,
- &properties);
- ATRACE_END();
-
if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) {
// Log that the app is hitting software Vulkan implementation
android::GraphicsEnv::getInstance().setTargetStats(
@@ -1174,7 +1209,6 @@
}
data->driver_device = dev;
- data->driver_version = properties.driverVersion;
*pDevice = dev;
diff --git a/vulkan/libvulkan/driver.h b/vulkan/libvulkan/driver.h
index f058c47..7edadea 100644
--- a/vulkan/libvulkan/driver.h
+++ b/vulkan/libvulkan/driver.h
@@ -67,9 +67,7 @@
: opaque_api_data(),
allocator(alloc),
driver(),
- get_device_proc_addr(nullptr) {
- hook_extensions.set(ProcHook::EXTENSION_CORE);
- }
+ get_device_proc_addr(nullptr) {}
api::InstanceData opaque_api_data;
@@ -89,9 +87,7 @@
: opaque_api_data(),
allocator(alloc),
debug_report_callbacks(debug_report_callbacks_),
- driver() {
- hook_extensions.set(ProcHook::EXTENSION_CORE);
- }
+ driver() {}
api::DeviceData opaque_api_data;
@@ -102,7 +98,6 @@
VkDevice driver_device;
DeviceDriverTable driver;
- uint32_t driver_version;
};
bool Debuggable();
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
index f676573..52205e9 100644
--- a/vulkan/libvulkan/driver_gen.cpp
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -74,6 +74,15 @@
}
}
+VKAPI_ATTR VkResult checkedBindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos) {
+ if (GetData(device).hook_extensions[ProcHook::EXTENSION_CORE_1_1]) {
+ return BindImageMemory2(device, bindInfoCount, pBindInfos);
+ } else {
+ Logger(device).Err(device, "VK_VERSION_1_1 not enabled. vkBindImageMemory2 not executed.");
+ return VK_SUCCESS;
+ }
+}
+
VKAPI_ATTR VkResult checkedBindImageMemory2KHR(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos) {
if (GetData(device).hook_extensions[ProcHook::KHR_bind_memory2]) {
return BindImageMemory2KHR(device, bindInfoCount, pBindInfos);
@@ -145,6 +154,14 @@
}
}
+VKAPI_ATTR void checkedGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue) {
+ if (GetData(device).hook_extensions[ProcHook::EXTENSION_CORE_1_1]) {
+ GetDeviceQueue2(device, pQueueInfo, pQueue);
+ } else {
+ Logger(device).Err(device, "VK_VERSION_1_1 not enabled. vkGetDeviceQueue2 not executed.");
+ }
+}
+
// clang-format on
const ProcHook g_proc_hooks[] = {
@@ -173,16 +190,16 @@
{
"vkAllocateCommandBuffers",
ProcHook::DEVICE,
- ProcHook::EXTENSION_CORE,
+ ProcHook::EXTENSION_CORE_1_0,
reinterpret_cast<PFN_vkVoidFunction>(AllocateCommandBuffers),
nullptr,
},
{
"vkBindImageMemory2",
ProcHook::DEVICE,
- ProcHook::EXTENSION_CORE,
+ ProcHook::EXTENSION_CORE_1_1,
reinterpret_cast<PFN_vkVoidFunction>(BindImageMemory2),
- nullptr,
+ reinterpret_cast<PFN_vkVoidFunction>(checkedBindImageMemory2),
},
{
"vkBindImageMemory2KHR",
@@ -208,14 +225,14 @@
{
"vkCreateDevice",
ProcHook::INSTANCE,
- ProcHook::EXTENSION_CORE,
+ ProcHook::EXTENSION_CORE_1_0,
reinterpret_cast<PFN_vkVoidFunction>(CreateDevice),
nullptr,
},
{
"vkCreateInstance",
ProcHook::GLOBAL,
- ProcHook::EXTENSION_CORE,
+ ProcHook::EXTENSION_CORE_1_0,
reinterpret_cast<PFN_vkVoidFunction>(CreateInstance),
nullptr,
},
@@ -243,14 +260,14 @@
{
"vkDestroyDevice",
ProcHook::DEVICE,
- ProcHook::EXTENSION_CORE,
+ ProcHook::EXTENSION_CORE_1_0,
reinterpret_cast<PFN_vkVoidFunction>(DestroyDevice),
nullptr,
},
{
"vkDestroyInstance",
ProcHook::INSTANCE,
- ProcHook::EXTENSION_CORE,
+ ProcHook::EXTENSION_CORE_1_0,
reinterpret_cast<PFN_vkVoidFunction>(DestroyInstance),
nullptr,
},
@@ -271,28 +288,28 @@
{
"vkEnumerateDeviceExtensionProperties",
ProcHook::INSTANCE,
- ProcHook::EXTENSION_CORE,
+ ProcHook::EXTENSION_CORE_1_0,
reinterpret_cast<PFN_vkVoidFunction>(EnumerateDeviceExtensionProperties),
nullptr,
},
{
"vkEnumerateInstanceExtensionProperties",
ProcHook::GLOBAL,
- ProcHook::EXTENSION_CORE,
+ ProcHook::EXTENSION_CORE_1_0,
reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceExtensionProperties),
nullptr,
},
{
"vkEnumeratePhysicalDeviceGroups",
ProcHook::INSTANCE,
- ProcHook::EXTENSION_CORE,
+ ProcHook::EXTENSION_CORE_1_1,
reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDeviceGroups),
nullptr,
},
{
"vkEnumeratePhysicalDevices",
ProcHook::INSTANCE,
- ProcHook::EXTENSION_CORE,
+ ProcHook::EXTENSION_CORE_1_0,
reinterpret_cast<PFN_vkVoidFunction>(EnumeratePhysicalDevices),
nullptr,
},
@@ -313,28 +330,28 @@
{
"vkGetDeviceProcAddr",
ProcHook::DEVICE,
- ProcHook::EXTENSION_CORE,
+ ProcHook::EXTENSION_CORE_1_0,
reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr),
nullptr,
},
{
"vkGetDeviceQueue",
ProcHook::DEVICE,
- ProcHook::EXTENSION_CORE,
+ ProcHook::EXTENSION_CORE_1_0,
reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue),
nullptr,
},
{
"vkGetDeviceQueue2",
ProcHook::DEVICE,
- ProcHook::EXTENSION_CORE,
+ ProcHook::EXTENSION_CORE_1_1,
reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue2),
- nullptr,
+ reinterpret_cast<PFN_vkVoidFunction>(checkedGetDeviceQueue2),
},
{
"vkGetInstanceProcAddr",
ProcHook::INSTANCE,
- ProcHook::EXTENSION_CORE,
+ ProcHook::EXTENSION_CORE_1_0,
reinterpret_cast<PFN_vkVoidFunction>(GetInstanceProcAddr),
nullptr,
},
@@ -446,7 +463,7 @@
{
"vkQueueSubmit",
ProcHook::DEVICE,
- ProcHook::EXTENSION_CORE,
+ ProcHook::EXTENSION_CORE_1_0,
reinterpret_cast<PFN_vkVoidFunction>(QueueSubmit),
nullptr,
},
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index cd7d8f8..43c4d14 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -49,7 +49,8 @@
KHR_bind_memory2,
KHR_get_physical_device_properties2,
- EXTENSION_CORE, // valid bit
+ EXTENSION_CORE_1_0,
+ EXTENSION_CORE_1_1,
EXTENSION_COUNT,
EXTENSION_UNKNOWN,
};
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index 5679412..22f92d6 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -38,13 +38,7 @@
#include <utils/Trace.h>
#include <ziparchive/zip_archive.h>
-// TODO(jessehall): The whole way we deal with extensions is pretty hokey, and
-// not a good long-term solution. Having a hard-coded enum of extensions is
-// bad, of course. Representing sets of extensions (requested, supported, etc.)
-// as a bitset isn't necessarily bad, if the mapping from extension to bit were
-// dynamic. Need to rethink this completely when there's a little more time.
-
-// TODO(jessehall): This file currently builds up global data structures as it
+// TODO(b/143296676): This file currently builds up global data structures as it
// loads, and never cleans them up. This means we're doing heap allocations
// without going through an app-provided allocator, but worse, we'll leak those
// allocations if the loader is unloaded.
@@ -101,9 +95,7 @@
bool EnumerateLayers(size_t library_idx,
std::vector<Layer>& instance_layers) const;
- void* GetGPA(const Layer& layer,
- const char* gpa_name,
- size_t gpa_name_len) const;
+ void* GetGPA(const Layer& layer, const std::string_view gpa_name) const;
const std::string GetFilename() { return filename_; }
@@ -226,9 +218,8 @@
}
// get layer properties
- VkLayerProperties* properties = static_cast<VkLayerProperties*>(alloca(
- (num_instance_layers + num_device_layers) * sizeof(VkLayerProperties)));
- result = enumerate_instance_layers(&num_instance_layers, properties);
+ std::vector<VkLayerProperties> properties(num_instance_layers + num_device_layers);
+ result = enumerate_instance_layers(&num_instance_layers, properties.data());
if (result != VK_SUCCESS) {
ALOGE("vkEnumerateInstanceLayerProperties failed for library '%s': %d",
path_.c_str(), result);
@@ -236,7 +227,7 @@
}
if (num_device_layers > 0) {
result = enumerate_device_layers(VK_NULL_HANDLE, &num_device_layers,
- properties + num_instance_layers);
+ &properties[num_instance_layers]);
if (result != VK_SUCCESS) {
ALOGE(
"vkEnumerateDeviceLayerProperties failed for library '%s': %d",
@@ -321,21 +312,11 @@
return true;
}
-void* LayerLibrary::GetGPA(const Layer& layer,
- const char* gpa_name,
- size_t gpa_name_len) const {
- void* gpa;
- size_t layer_name_len =
- std::max(size_t{2}, strlen(layer.properties.layerName));
- char* name = static_cast<char*>(alloca(layer_name_len + gpa_name_len + 1));
- strcpy(name, layer.properties.layerName);
- strcpy(name + layer_name_len, gpa_name);
- if (!(gpa = GetTrampoline(name))) {
- strcpy(name, "vk");
- strcpy(name + 2, gpa_name);
- gpa = GetTrampoline(name);
- }
- return gpa;
+void* LayerLibrary::GetGPA(const Layer& layer, const std::string_view gpa_name) const {
+ std::string layer_name { layer.properties.layerName };
+ if (void* gpa = GetTrampoline((layer_name.append(gpa_name).c_str())))
+ return gpa;
+ return GetTrampoline((std::string {"vk"}.append(gpa_name)).c_str());
}
// ----------------------------------------------------------------------------
@@ -470,10 +451,9 @@
}
void* GetLayerGetProcAddr(const Layer& layer,
- const char* gpa_name,
- size_t gpa_name_len) {
+ const std::string_view gpa_name) {
const LayerLibrary& library = g_layer_libraries[layer.library_idx];
- return library.GetGPA(layer, gpa_name, gpa_name_len);
+ return library.GetGPA(layer, gpa_name);
}
} // anonymous namespace
@@ -556,13 +536,13 @@
PFN_vkGetInstanceProcAddr LayerRef::GetGetInstanceProcAddr() const {
return layer_ ? reinterpret_cast<PFN_vkGetInstanceProcAddr>(
- GetLayerGetProcAddr(*layer_, "GetInstanceProcAddr", 19))
+ GetLayerGetProcAddr(*layer_, "GetInstanceProcAddr"))
: nullptr;
}
PFN_vkGetDeviceProcAddr LayerRef::GetGetDeviceProcAddr() const {
return layer_ ? reinterpret_cast<PFN_vkGetDeviceProcAddr>(
- GetLayerGetProcAddr(*layer_, "GetDeviceProcAddr", 17))
+ GetLayerGetProcAddr(*layer_, "GetDeviceProcAddr"))
: nullptr;
}
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index d60eaa7..8f4667e 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -694,8 +694,8 @@
const InstanceData& instance_data = GetData(pdev);
- // TODO(jessehall): Fill out the set of supported formats. Longer term, add
- // a new gralloc method to query whether a (format, usage) pair is
+ // TODO(b/143296550): Fill out the set of supported formats. Longer term,
+ // add a new gralloc method to query whether a (format, usage) pair is
// supported, and check that for each gralloc format that corresponds to a
// Vulkan format. Shorter term, just add a few more formats to the ones
// hardcoded below.
@@ -704,8 +704,6 @@
{VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
{VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
{VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
- {VK_FORMAT_A2B10G10R10_UNORM_PACK32, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
- {VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
};
const uint32_t kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
uint32_t total_num_formats = kNumFormats;
@@ -953,7 +951,7 @@
strerror(-err), err);
}
- // TODO: Return something better than "whole window"
+ // TODO(b/143294545): Return something better than "whole window"
pRects[0].offset.x = 0;
pRects[0].offset.y = 0;
pRects[0].extent = VkExtent2D{static_cast<uint32_t>(width),
@@ -1291,6 +1289,7 @@
VkImageCreateInfo image_create = {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.pNext = &image_native_buffer,
+ .flags = createProtectedSwapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u,
.imageType = VK_IMAGE_TYPE_2D,
.format = create_info->imageFormat,
.extent = {0, 0, 1},
@@ -1299,7 +1298,6 @@
.samples = VK_SAMPLE_COUNT_1_BIT,
.tiling = VK_IMAGE_TILING_OPTIMAL,
.usage = create_info->imageUsage,
- .flags = createProtectedSwapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u,
.sharingMode = create_info->imageSharingMode,
.queueFamilyIndexCount = create_info->queueFamilyIndexCount,
.pQueueFamilyIndices = create_info->pQueueFamilyIndices,
@@ -1812,7 +1810,7 @@
return VK_ERROR_OUT_OF_DATE_KHR;
}
- // TODO(chrisforbes): Implement this function properly
+ // TODO(b/143296009): Implement this function properly
return result;
}
diff --git a/vulkan/scripts/driver_generator.py b/vulkan/scripts/driver_generator.py
index 0be0491..a64a702 100644
--- a/vulkan/scripts/driver_generator.py
+++ b/vulkan/scripts/driver_generator.py
@@ -177,8 +177,12 @@
for ext in _KNOWN_EXTENSIONS:
f.write(gencom.indent(2) + gencom.base_ext_name(ext) + ',\n')
- f.write("""
- EXTENSION_CORE, // valid bit
+ f.write('\n')
+ for version in gencom.version_code_list:
+ f.write(gencom.indent(2) + 'EXTENSION_CORE_' + version + ',\n')
+
+ # EXTENSION_COUNT must be the next enum after the highest API version.
+ f.write("""\
EXTENSION_COUNT,
EXTENSION_UNKNOWN,
};
@@ -249,6 +253,18 @@
return False
+def _get_proc_hook_enum(cmd):
+ """Returns the ProcHook enumeration for the corresponding core function.
+
+ Args:
+ cmd: Vulkan function name.
+ """
+ assert cmd in gencom.version_dict
+ for version in gencom.version_code_list:
+ if gencom.version_dict[cmd] == 'VK_VERSION_' + version:
+ return 'ProcHook::EXTENSION_CORE_' + version
+
+
def _need_proc_hook_stub(cmd):
"""Returns true if a function needs a ProcHook stub.
@@ -259,6 +275,8 @@
if cmd in gencom.extension_dict:
if not gencom.is_extension_internal(gencom.extension_dict[cmd]):
return True
+ elif gencom.version_dict[cmd] != 'VK_VERSION_1_0':
+ return True
return False
@@ -271,8 +289,16 @@
"""
if _need_proc_hook_stub(cmd):
return_type = gencom.return_type_dict[cmd]
- ext_name = gencom.extension_dict[cmd]
- ext_hook = 'ProcHook::' + ext_name[3:]
+
+ ext_name = ''
+ ext_hook = ''
+ if cmd in gencom.extension_dict:
+ ext_name = gencom.extension_dict[cmd]
+ ext_hook = 'ProcHook::' + gencom.base_ext_name(ext_name)
+ else:
+ ext_name = gencom.version_dict[cmd]
+ ext_hook = _get_proc_hook_enum(cmd)
+
handle = gencom.param_dict[cmd][0][1]
param_types = ', '.join([''.join(i) for i in gencom.param_dict[cmd]])
param_names = ', '.join([''.join(i[1]) for i in gencom.param_dict[cmd]])
@@ -306,12 +332,12 @@
f.write(gencom.indent(1) + '{\n')
f.write(gencom.indent(2) + '\"' + cmd + '\",\n')
- f.write("""\
- ProcHook::GLOBAL,
- ProcHook::EXTENSION_CORE,
- reinterpret_cast<PFN_vkVoidFunction>(""" + gencom.base_name(cmd) + """),
- nullptr,
- },\n""")
+ f.write(gencom.indent(2) + 'ProcHook::GLOBAL,\n')
+ f.write(gencom.indent(2) + _get_proc_hook_enum(cmd) + ',\n')
+ f.write(gencom.indent(2) + 'reinterpret_cast<PFN_vkVoidFunction>(' +
+ gencom.base_name(cmd) + '),\n')
+ f.write(gencom.indent(2) + 'nullptr,\n')
+ f.write(gencom.indent(1) + '},\n')
def _define_instance_proc_hook(cmd, f):
@@ -327,7 +353,8 @@
if cmd in gencom.extension_dict:
ext_name = gencom.extension_dict[cmd]
- f.write(gencom.indent(2) + 'ProcHook::' + ext_name[3:] + ',\n')
+ f.write(gencom.indent(2) + 'ProcHook::' +
+ gencom.base_ext_name(ext_name) + ',\n')
if gencom.is_extension_internal(ext_name):
f.write("""\
@@ -338,8 +365,8 @@
reinterpret_cast<PFN_vkVoidFunction>(""" + gencom.base_name(cmd) + """),
nullptr,\n""")
else:
+ f.write(gencom.indent(2) + _get_proc_hook_enum(cmd) + ',\n')
f.write("""\
- ProcHook::EXTENSION_CORE,
reinterpret_cast<PFN_vkVoidFunction>(""" + gencom.base_name(cmd) + """),
nullptr,\n""")
@@ -357,9 +384,17 @@
f.write(gencom.indent(2) + '\"' + cmd + '\",\n')
f.write(gencom.indent(2) + 'ProcHook::DEVICE,\n')
- if cmd in gencom.extension_dict:
- ext_name = gencom.extension_dict[cmd]
- f.write(gencom.indent(2) + 'ProcHook::' + ext_name[3:] + ',\n')
+ if (cmd in gencom.extension_dict or
+ gencom.version_dict[cmd] != 'VK_VERSION_1_0'):
+ ext_name = ''
+ ext_hook = ''
+ if cmd in gencom.extension_dict:
+ ext_name = gencom.extension_dict[cmd]
+ ext_hook = 'ProcHook::' + gencom.base_ext_name(ext_name)
+ else:
+ ext_name = gencom.version_dict[cmd]
+ ext_hook = _get_proc_hook_enum(cmd)
+ f.write(gencom.indent(2) + ext_hook + ',\n')
if gencom.is_extension_internal(ext_name):
f.write("""\
@@ -372,8 +407,8 @@
gencom.base_name(cmd) + '),\n')
else:
+ f.write(gencom.indent(2) + _get_proc_hook_enum(cmd) + ',\n')
f.write("""\
- ProcHook::EXTENSION_CORE,
reinterpret_cast<PFN_vkVoidFunction>(""" + gencom.base_name(cmd) + """),
nullptr,\n""")
diff --git a/vulkan/scripts/generator_common.py b/vulkan/scripts/generator_common.py
index 5bfa9ec..cf370fa 100644
--- a/vulkan/scripts/generator_common.py
+++ b/vulkan/scripts/generator_common.py
@@ -91,6 +91,9 @@
# Dict for mapping a function to its return type.
return_type_dict = {}
+# List of the sorted Vulkan version codes. e.g. '1_0', '1_1'.
+version_code_list = []
+
# Dict for mapping a function to the core Vulkan API version.
version_dict = {}
@@ -171,6 +174,15 @@
return ext[3:]
+def version_code(version):
+ """Returns the version code from a version string.
+
+ Args:
+ version: Vulkan version string.
+ """
+ return version[11:]
+
+
def is_function_supported(cmd):
"""Returns true if a function is core or from a supportable extension.
@@ -286,7 +298,7 @@
"""
f.write(indent(1))
if name in extension_dict:
- f.write('INIT_PROC_EXT(' + extension_dict[name][3:] + ', ')
+ f.write('INIT_PROC_EXT(' + base_ext_name(extension_dict[name]) + ', ')
else:
f.write('INIT_PROC(')
@@ -313,6 +325,7 @@
extension_dict
param_dict
return_type_dict
+ version_code_list
version_dict
"""
registry = os.path.join(os.path.dirname(__file__), '..', '..', '..', '..',
@@ -385,3 +398,9 @@
cmd_name = command.get('name')
if cmd_name in command_list:
version_dict[cmd_name] = apiversion
+
+ version_code_set = set()
+ for version in version_dict.values():
+ version_code_set.add(version_code(version))
+ for code in sorted(version_code_set):
+ version_code_list.append(code)