Merge "Make the connection between implementation and llndk_library explicit"
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index ead491e..80d14ac 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -105,6 +105,8 @@
name: "dumpstate",
defaults: ["dumpstate_defaults"],
srcs: [
+ "DumpPool.cpp",
+ "TaskQueue.cpp",
"dumpstate.cpp",
"main.cpp",
],
@@ -132,6 +134,8 @@
name: "dumpstate_test",
defaults: ["dumpstate_defaults"],
srcs: [
+ "DumpPool.cpp",
+ "TaskQueue.cpp",
"dumpstate.cpp",
"tests/dumpstate_test.cpp",
],
@@ -148,10 +152,14 @@
name: "dumpstate_smoke_test",
defaults: ["dumpstate_defaults"],
srcs: [
+ "DumpPool.cpp",
+ "TaskQueue.cpp",
"dumpstate.cpp",
"tests/dumpstate_smoke_test.cpp",
],
static_libs: ["libgmock"],
+ test_config: "dumpstate_smoke_test.xml",
+ test_suites: ["device-tests"],
}
diff --git a/cmds/dumpstate/DumpPool.cpp b/cmds/dumpstate/DumpPool.cpp
new file mode 100644
index 0000000..e15ac3f
--- /dev/null
+++ b/cmds/dumpstate/DumpPool.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2020 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 "dumpstate"
+
+#include "DumpPool.h"
+
+#include <array>
+#include <thread>
+
+#include <log/log.h>
+
+#include "dumpstate.h"
+#include "DumpstateInternal.h"
+#include "DumpstateUtil.h"
+
+namespace android {
+namespace os {
+namespace dumpstate {
+
+const std::string DumpPool::PREFIX_TMPFILE_NAME = "dump-tmp.";
+
+DumpPool::DumpPool(const std::string& tmp_root) : tmp_root_(tmp_root), shutdown_(false),
+ log_duration_(true) {
+ assert(!tmp_root.empty());
+ deleteTempFiles(tmp_root_);
+}
+
+DumpPool::~DumpPool() {
+ shutdown();
+}
+
+void DumpPool::start(int thread_counts) {
+ assert(thread_counts > 0);
+ assert(threads_.empty());
+ if (thread_counts > MAX_THREAD_COUNT) {
+ thread_counts = MAX_THREAD_COUNT;
+ }
+ MYLOGI("Start thread pool:%d", thread_counts);
+ shutdown_ = false;
+ for (int i = 0; i < thread_counts; i++) {
+ threads_.emplace_back(std::thread([=]() {
+ setThreadName(pthread_self(), i + 1);
+ loop();
+ }));
+ }
+}
+
+void DumpPool::shutdown() {
+ std::unique_lock lock(lock_);
+ if (shutdown_ || threads_.empty()) {
+ return;
+ }
+ while (!tasks_.empty()) tasks_.pop();
+ futures_map_.clear();
+
+ shutdown_ = true;
+ condition_variable_.notify_all();
+ lock.unlock();
+
+ for (auto& thread : threads_) {
+ thread.join();
+ }
+ threads_.clear();
+ deleteTempFiles(tmp_root_);
+ MYLOGI("shutdown thread pool");
+}
+
+void DumpPool::waitForTask(const std::string& task_name, const std::string& title,
+ int out_fd) {
+ DurationReporter duration_reporter("Wait for " + task_name, true);
+ auto iterator = futures_map_.find(task_name);
+ if (iterator == futures_map_.end()) {
+ MYLOGW("Task %s does not exist", task_name.c_str());
+ return;
+ }
+ Future future = iterator->second;
+ futures_map_.erase(iterator);
+
+ std::string result = future.get();
+ if (result.empty()) {
+ return;
+ }
+ DumpFileToFd(out_fd, title, result);
+ if (unlink(result.c_str())) {
+ MYLOGE("Failed to unlink (%s): %s\n", result.c_str(), strerror(errno));
+ }
+}
+
+void DumpPool::deleteTempFiles() {
+ deleteTempFiles(tmp_root_);
+}
+
+void DumpPool::setLogDuration(bool log_duration) {
+ log_duration_ = log_duration;
+}
+
+template <>
+void DumpPool::invokeTask<std::function<void()>>(std::function<void()> dump_func,
+ const std::string& duration_title, int out_fd) {
+ DurationReporter duration_reporter(duration_title, /*logcat_only =*/!log_duration_,
+ /*verbose =*/false, out_fd);
+ std::invoke(dump_func);
+}
+
+template <>
+void DumpPool::invokeTask<std::function<void(int)>>(std::function<void(int)> dump_func,
+ const std::string& duration_title, int out_fd) {
+ DurationReporter duration_reporter(duration_title, /*logcat_only =*/!log_duration_,
+ /*verbose =*/false, out_fd);
+ std::invoke(dump_func, out_fd);
+}
+
+std::unique_ptr<DumpPool::TmpFile> DumpPool::createTempFile() {
+ auto tmp_file_ptr = std::make_unique<TmpFile>();
+ std::string file_name_format = "%s/" + PREFIX_TMPFILE_NAME + "XXXXXX";
+ snprintf(tmp_file_ptr->path, sizeof(tmp_file_ptr->path), file_name_format.c_str(),
+ tmp_root_.c_str());
+ tmp_file_ptr->fd.reset(TEMP_FAILURE_RETRY(
+ mkostemp(tmp_file_ptr->path, O_CLOEXEC)));
+ if (tmp_file_ptr->fd.get() == -1) {
+ MYLOGE("open(%s, %s)\n", tmp_file_ptr->path, strerror(errno));
+ tmp_file_ptr = nullptr;
+ return tmp_file_ptr;
+ }
+ return tmp_file_ptr;
+}
+
+void DumpPool::deleteTempFiles(const std::string& folder) {
+ std::unique_ptr<DIR, decltype(&closedir)> dir_ptr(opendir(folder.c_str()),
+ &closedir);
+ if (!dir_ptr) {
+ MYLOGE("Failed to opendir (%s): %s\n", folder.c_str(), strerror(errno));
+ return;
+ }
+ int dir_fd = dirfd(dir_ptr.get());
+ if (dir_fd < 0) {
+ MYLOGE("Failed to get fd of dir (%s): %s\n", folder.c_str(),
+ strerror(errno));
+ return;
+ }
+
+ struct dirent* de;
+ while ((de = readdir(dir_ptr.get()))) {
+ if (de->d_type != DT_REG) {
+ continue;
+ }
+ std::string file_name(de->d_name);
+ if (file_name.find(PREFIX_TMPFILE_NAME) != 0) {
+ continue;
+ }
+ if (unlinkat(dir_fd, file_name.c_str(), 0)) {
+ MYLOGE("Failed to unlink (%s): %s\n", file_name.c_str(),
+ strerror(errno));
+ }
+ }
+}
+
+void DumpPool::setThreadName(const pthread_t thread, int id) {
+ std::array<char, 15> name;
+ snprintf(name.data(), name.size(), "dumpstate_%d", id);
+ pthread_setname_np(thread, name.data());
+}
+
+void DumpPool::loop() {
+ std::unique_lock lock(lock_);
+ while (!shutdown_) {
+ if (tasks_.empty()) {
+ condition_variable_.wait(lock);
+ continue;
+ } else {
+ std::packaged_task<std::string()> task = std::move(tasks_.front());
+ tasks_.pop();
+ lock.unlock();
+ std::invoke(task);
+ lock.lock();
+ }
+ }
+}
+
+} // namespace dumpstate
+} // namespace os
+} // namespace android
diff --git a/cmds/dumpstate/DumpPool.h b/cmds/dumpstate/DumpPool.h
new file mode 100644
index 0000000..0c3c2cc
--- /dev/null
+++ b/cmds/dumpstate/DumpPool.h
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FRAMEWORK_NATIVE_CMD_DUMPPOOL_H_
+#define FRAMEWORK_NATIVE_CMD_DUMPPOOL_H_
+
+#include <future>
+#include <map>
+#include <queue>
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/macros.h>
+
+namespace android {
+namespace os {
+namespace dumpstate {
+
+class DumpPoolTest;
+
+/*
+ * A thread pool with the fixed number of threads to execute multiple dump tasks
+ * simultaneously for the dumpstate. The dump task is a callable function. It
+ * could include a file descriptor as a parameter to redirect dump results, if
+ * it needs to output results to the bugreport. This can avoid messing up
+ * bugreport's results when multiple dump tasks are running at the same time.
+ * Takes an example below for the usage of the DumpPool:
+ *
+ * void DumpFoo(int out_fd) {
+ * dprintf(out_fd, "Dump result to out_fd ...");
+ * }
+ * ...
+ * DumpPool pool(tmp_root);
+ * pool.enqueueTaskWithFd("TaskName", &DumpFoo, std::placeholders::_1);
+ * ...
+ * pool.waitForTask("TaskName");
+ *
+ * DumpFoo is a callable function included a out_fd parameter. Using the
+ * enqueueTaskWithFd method in DumpPool to enqueue the task to the pool. The
+ * std::placeholders::_1 is a placeholder for DumpPool to pass a fd argument.
+ */
+class DumpPool {
+ friend class android::os::dumpstate::DumpPoolTest;
+
+ public:
+ /*
+ * Creates a thread pool.
+ *
+ * |tmp_root| A path to a temporary folder for threads to create temporary
+ * files.
+ */
+ explicit DumpPool(const std::string& tmp_root);
+ ~DumpPool();
+
+ /*
+ * Starts the threads in the pool.
+ *
+ * |thread_counts| the number of threads to start.
+ */
+ void start(int thread_counts = MAX_THREAD_COUNT);
+
+ /*
+ * Requests to shutdown the pool and waits until all threads exit the loop.
+ */
+ void shutdown();
+
+ /*
+ * Adds a task into the queue of the thread pool.
+ *
+ * |task_name| The name of the task. It's also the title of the
+ * DurationReporter log.
+ * |f| Callable function to execute the task.
+ * |args| A list of arguments.
+ *
+ * TODO(b/164369078): remove this api to have just one enqueueTask for consistency.
+ */
+ template<class F, class... Args> void enqueueTask(const std::string& task_name, F&& f,
+ Args&&... args) {
+ std::function<void(void)> func = std::bind(std::forward<F>(f),
+ std::forward<Args>(args)...);
+ futures_map_[task_name] = post(task_name, func);
+ if (threads_.empty()) {
+ start();
+ }
+ }
+
+ /*
+ * Adds a task into the queue of the thread pool. The task takes a file
+ * descriptor as a parameter to redirect dump results to a temporary file.
+ *
+ * |task_name| The name of the task. It's also the title of the
+ * DurationReporter log.
+ * |f| Callable function to execute the task.
+ * |args| A list of arguments. A placeholder std::placeholders::_1 as a fd
+ * argument needs to be included here.
+ */
+ template<class F, class... Args> void enqueueTaskWithFd(const std::string& task_name, F&& f,
+ Args&&... args) {
+ std::function<void(int)> func = std::bind(std::forward<F>(f),
+ std::forward<Args>(args)...);
+ futures_map_[task_name] = post(task_name, func);
+ if (threads_.empty()) {
+ start();
+ }
+ }
+
+ /*
+ * Waits until the task is finished. Dumps the task results to the STDOUT_FILENO.
+ */
+ void waitForTask(const std::string& task_name) {
+ waitForTask(task_name, "", STDOUT_FILENO);
+ }
+
+ /*
+ * Waits until the task is finished. Dumps the task results to the specified
+ * out_fd.
+ *
+ * |task_name| The name of the task.
+ * |title| Dump title string to the out_fd, an empty string for nothing.
+ * |out_fd| The target file to dump the result from the task.
+ */
+ void waitForTask(const std::string& task_name, const std::string& title, int out_fd);
+
+ /*
+ * Deletes temporary files created by DumpPool.
+ */
+ void deleteTempFiles();
+
+ static const std::string PREFIX_TMPFILE_NAME;
+
+ private:
+ using Task = std::packaged_task<std::string()>;
+ using Future = std::shared_future<std::string>;
+
+ template<class T> void invokeTask(T dump_func, const std::string& duration_title, int out_fd);
+
+ template<class T> Future post(const std::string& task_name, T dump_func) {
+ Task packaged_task([=]() {
+ std::unique_ptr<TmpFile> tmp_file_ptr = createTempFile();
+ if (!tmp_file_ptr) {
+ return std::string("");
+ }
+ invokeTask(dump_func, task_name, tmp_file_ptr->fd.get());
+ fsync(tmp_file_ptr->fd.get());
+ return std::string(tmp_file_ptr->path);
+ });
+ std::unique_lock lock(lock_);
+ auto future = packaged_task.get_future().share();
+ tasks_.push(std::move(packaged_task));
+ condition_variable_.notify_one();
+ return future;
+ }
+
+ typedef struct {
+ android::base::unique_fd fd;
+ char path[1024];
+ } TmpFile;
+
+ std::unique_ptr<TmpFile> createTempFile();
+ void deleteTempFiles(const std::string& folder);
+ void setThreadName(const pthread_t thread, int id);
+ void loop();
+
+ /*
+ * For test purpose only. Enables or disables logging duration of the task.
+ *
+ * |log_duration| if true, DurationReporter is initiated to log duration of
+ * the task.
+ */
+ void setLogDuration(bool log_duration);
+
+ private:
+ static const int MAX_THREAD_COUNT = 4;
+
+ /* A path to a temporary folder for threads to create temporary files. */
+ std::string tmp_root_;
+ bool shutdown_;
+ bool log_duration_; // For test purpose only, the default value is true.
+ std::mutex lock_; // A lock for the tasks_.
+ std::condition_variable condition_variable_;
+
+ std::vector<std::thread> threads_;
+ std::queue<Task> tasks_;
+ std::map<std::string, Future> futures_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(DumpPool);
+};
+
+} // namespace dumpstate
+} // namespace os
+} // namespace android
+
+#endif //FRAMEWORK_NATIVE_CMD_DUMPPOOL_H_
diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp
index 4b69607..eeaa5a3 100644
--- a/cmds/dumpstate/DumpstateUtil.cpp
+++ b/cmds/dumpstate/DumpstateUtil.cpp
@@ -180,6 +180,7 @@
std::string PropertiesHelper::build_type_ = "";
int PropertiesHelper::dry_run_ = -1;
int PropertiesHelper::unroot_ = -1;
+int PropertiesHelper::parallel_run_ = -1;
bool PropertiesHelper::IsUserBuild() {
if (build_type_.empty()) {
@@ -202,6 +203,14 @@
return unroot_ == 1;
}
+bool PropertiesHelper::IsParallelRun() {
+ if (parallel_run_ == -1) {
+ parallel_run_ = android::base::GetBoolProperty("dumpstate.parallel_run",
+ /* default_value = */true) ? 1 : 0;
+ }
+ return parallel_run_ == 1;
+}
+
int DumpFileToFd(int out_fd, const std::string& title, const std::string& path) {
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
if (fd.get() < 0) {
diff --git a/cmds/dumpstate/DumpstateUtil.h b/cmds/dumpstate/DumpstateUtil.h
index b7ac25c..b099443 100644
--- a/cmds/dumpstate/DumpstateUtil.h
+++ b/cmds/dumpstate/DumpstateUtil.h
@@ -176,10 +176,18 @@
*/
static bool IsUnroot();
+ /*
+ * Whether or not the parallel run is enabled. Setting the system property
+ * 'dumpstate.parallel_run' to false to disable it, otherwise it returns
+ * true by default.
+ */
+ static bool IsParallelRun();
+
private:
static std::string build_type_;
static int dry_run_;
static int unroot_;
+ static int parallel_run_;
};
/*
diff --git a/cmds/dumpstate/TEST_MAPPING b/cmds/dumpstate/TEST_MAPPING
index 083944f..839a2c3 100644
--- a/cmds/dumpstate/TEST_MAPPING
+++ b/cmds/dumpstate/TEST_MAPPING
@@ -1,7 +1,28 @@
{
"presubmit": [
{
+ "name": "BugreportManagerTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.LargeTest"
+ }
+ ]
+ },
+ {
+ "name": "dumpstate_smoke_test"
+ },
+ {
"name": "dumpstate_test"
}
+ ],
+ "postsubmit": [
+ {
+ "name": "BugreportManagerTestCases"
+ }
+ ],
+ "imports": [
+ {
+ "path": "frameworks/base/packages/Shell"
+ }
]
-}
\ No newline at end of file
+}
diff --git a/cmds/dumpstate/TaskQueue.cpp b/cmds/dumpstate/TaskQueue.cpp
new file mode 100644
index 0000000..8550aec
--- /dev/null
+++ b/cmds/dumpstate/TaskQueue.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 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 "TaskQueue.h"
+
+namespace android {
+namespace os {
+namespace dumpstate {
+
+TaskQueue::~TaskQueue() {
+ run(/* do_cancel = */true);
+}
+
+void TaskQueue::run(bool do_cancel) {
+ std::unique_lock lock(lock_);
+ while (!tasks_.empty()) {
+ auto task = tasks_.front();
+ tasks_.pop();
+ lock.unlock();
+ std::invoke(task, do_cancel);
+ lock.lock();
+ }
+}
+
+} // namespace dumpstate
+} // namespace os
+} // namespace android
diff --git a/cmds/dumpstate/TaskQueue.h b/cmds/dumpstate/TaskQueue.h
new file mode 100644
index 0000000..b7e72f1
--- /dev/null
+++ b/cmds/dumpstate/TaskQueue.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FRAMEWORK_NATIVE_CMD_TASKQUEUE_H_
+#define FRAMEWORK_NATIVE_CMD_TASKQUEUE_H_
+
+#include <mutex>
+#include <queue>
+
+#include <android-base/macros.h>
+
+namespace android {
+namespace os {
+namespace dumpstate {
+
+/*
+ * A task queue for dumpstate to collect tasks such as adding file to the zip
+ * which are needed to run in a single thread. The task is a callable function
+ * included a cancel task boolean parameter. The TaskQueue could
+ * cancel the task in the destructor if the task has never been called.
+ */
+class TaskQueue {
+ public:
+ TaskQueue() = default;
+ ~TaskQueue();
+
+ /*
+ * Adds a task into the queue.
+ *
+ * |f| Callable function to execute the task. The function must include a
+ * boolean parameter for TaskQueue to notify whether the task is
+ * cancelled or not.
+ * |args| A list of arguments.
+ */
+ template<class F, class... Args> void add(F&& f, Args&&... args) {
+ auto func = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
+ std::unique_lock lock(lock_);
+ tasks_.emplace([=](bool cancelled) {
+ std::invoke(func, cancelled);
+ });
+ }
+
+ /*
+ * Invokes all tasks in the task queue.
+ *
+ * |do_cancel| true to cancel all tasks in the queue.
+ */
+ void run(bool do_cancel);
+
+ private:
+ using Task = std::function<void(bool)>;
+
+ std::mutex lock_;
+ std::queue<Task> tasks_;
+
+ DISALLOW_COPY_AND_ASSIGN(TaskQueue);
+};
+
+} // namespace dumpstate
+} // namespace os
+} // namespace android
+
+#endif //FRAMEWORK_NATIVE_CMD_TASKQUEUE_H_
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 84de9f3..eefc84f 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -95,6 +95,7 @@
using ::android::hardware::dumpstate::V1_1::toString;
using ::std::literals::chrono_literals::operator""ms;
using ::std::literals::chrono_literals::operator""s;
+using ::std::placeholders::_1;
// TODO: remove once moved to namespace
using android::defaultServiceManager;
@@ -113,7 +114,9 @@
using android::os::IDumpstateListener;
using android::os::dumpstate::CommandOptions;
using android::os::dumpstate::DumpFileToFd;
+using android::os::dumpstate::DumpPool;
using android::os::dumpstate::PropertiesHelper;
+using android::os::dumpstate::TaskQueue;
// Keep in sync with
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -126,8 +129,8 @@
static Dumpstate& ds = Dumpstate::GetInstance();
static int RunCommand(const std::string& title, const std::vector<std::string>& full_command,
const CommandOptions& options = CommandOptions::DEFAULT,
- bool verbose_duration = false) {
- return ds.RunCommand(title, full_command, options, verbose_duration);
+ bool verbose_duration = false, int out_fd = STDOUT_FILENO) {
+ return ds.RunCommand(title, full_command, options, verbose_duration, out_fd);
}
// Reasonable value for max stats.
@@ -196,8 +199,36 @@
func_ptr(__VA_ARGS__); \
RETURN_IF_USER_DENIED_CONSENT();
+// Runs func_ptr, and logs a duration report after it's finished.
+#define RUN_SLOW_FUNCTION_AND_LOG(log_title, func_ptr, ...) \
+ { \
+ DurationReporter duration_reporter_in_macro(log_title); \
+ func_ptr(__VA_ARGS__); \
+ }
+
+// Similar with RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK, an additional duration report
+// is output after a slow function is finished.
+#define RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(log_title, func_ptr, ...) \
+ RETURN_IF_USER_DENIED_CONSENT(); \
+ RUN_SLOW_FUNCTION_AND_LOG(log_title, func_ptr, __VA_ARGS__); \
+ RETURN_IF_USER_DENIED_CONSENT();
+
+#define WAIT_TASK_WITH_CONSENT_CHECK(task_name, pool_ptr) \
+ RETURN_IF_USER_DENIED_CONSENT(); \
+ pool_ptr->waitForTask(task_name); \
+ RETURN_IF_USER_DENIED_CONSENT();
+
static const char* WAKE_LOCK_NAME = "dumpstate_wakelock";
+// Names of parallel tasks, they are used for the DumpPool to identify the dump
+// task and the log title of the duration report.
+static const std::string DUMP_TRACES_TASK = "DUMP TRACES";
+static const std::string DUMP_INCIDENT_REPORT_TASK = "INCIDENT REPORT";
+static const std::string DUMP_HALS_TASK = "DUMP HALS";
+static const std::string DUMP_BOARD_TASK = "dumpstate_board()";
+static const std::string DUMP_CHECKINS_TASK = "DUMP CHECKINS";
+static const std::string DUMP_APP_INFOS_TASK = "DUMP APP INFOS";
+
namespace android {
namespace os {
namespace {
@@ -306,8 +337,12 @@
static void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs,
const CommandOptions& options = Dumpstate::DEFAULT_DUMPSYS,
- long dumpsysTimeoutMs = 0) {
- return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeoutMs);
+ long dumpsysTimeoutMs = 0, int out_fd = STDOUT_FILENO) {
+ return ds.RunDumpsys(title, dumpsysArgs, options, dumpsysTimeoutMs, out_fd);
+}
+static void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsysArgs,
+ int out_fd) {
+ return ds.RunDumpsys(title, dumpsysArgs, Dumpstate::DEFAULT_DUMPSYS, 0, out_fd);
}
static int DumpFile(const std::string& title, const std::string& path) {
return ds.DumpFile(title, path);
@@ -762,8 +797,9 @@
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 bugreport_mode=%s\n", id_, pid_,
- PropertiesHelper::IsDryRun(), options_->args.c_str(), options_->bugreport_mode.c_str());
+ printf("Dumpstate info: id=%d pid=%d dry_run=%d parallel_run=%d args=%s bugreport_mode=%s\n",
+ id_, pid_, PropertiesHelper::IsDryRun(), PropertiesHelper::IsParallelRun(),
+ options_->args.c_str(), options_->bugreport_mode.c_str());
printf("\n");
}
@@ -993,7 +1029,6 @@
MYLOGD("Not dumping incident report because it's not a zipped bugreport\n");
return;
}
- DurationReporter duration_reporter("INCIDENT REPORT");
const std::string path = ds.bugreport_internal_dir_ + "/tmp_incident_report";
auto fd = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(),
O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
@@ -1008,9 +1043,11 @@
// Use a different name from "incident.proto"
// /proto/incident.proto is reserved for incident service dump
// i.e. metadata for debugging.
- ds.AddZipEntry(kProtoPath + "incident_report" + kProtoExt, path);
+ ds.EnqueueAddZipEntryAndCleanupIfNeeded(kProtoPath + "incident_report" + kProtoExt,
+ path);
+ } else {
+ unlink(path.c_str());
}
- unlink(path.c_str());
}
static void DumpVisibleWindowViews() {
@@ -1305,15 +1342,20 @@
/* timeout= */ 90s, /* service_timeout= */ 10s);
}
-static void DumpHals() {
+/*
+ * |out_fd| A fd to support the DumpPool to output results to a temporary file.
+ * Dumpstate can pick up later and output to the bugreport. Using STDOUT_FILENO
+ * if it's not running in the parallel task.
+ */
+static void DumpHals(int out_fd = STDOUT_FILENO) {
if (!ds.IsZipping()) {
RunCommand("HARDWARE HALS", {"lshal", "--all", "--types=all", "--debug"},
CommandOptions::WithTimeout(60).AsRootIfAvailable().Build());
return;
}
- DurationReporter duration_reporter("DUMP HALS");
RunCommand("HARDWARE HALS", {"lshal", "--all", "--types=all"},
- CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
+ CommandOptions::WithTimeout(10).AsRootIfAvailable().Build(),
+ false, out_fd);
using android::hidl::manager::V1_0::IServiceManager;
using android::hardware::defaultServiceManager;
@@ -1335,6 +1377,7 @@
}, '_');
const std::string path = ds.bugreport_internal_dir_ + "/lshal_debug_" + cleanName;
+ bool empty = false;
{
auto fd = android::base::unique_fd(
TEMP_FAILURE_RETRY(open(path.c_str(),
@@ -1349,13 +1392,14 @@
{"lshal", "debug", "-E", interface},
CommandOptions::WithTimeout(2).AsRootIfAvailable().Build());
- bool empty = 0 == lseek(fd, 0, SEEK_END);
- if (!empty) {
- ds.AddZipEntry("lshal-debug/" + cleanName + ".txt", path);
- }
+ empty = 0 == lseek(fd, 0, SEEK_END);
}
-
- unlink(path.c_str());
+ if (!empty) {
+ ds.EnqueueAddZipEntryAndCleanupIfNeeded("lshal-debug/" + cleanName + ".txt",
+ path);
+ } else {
+ unlink(path.c_str());
+ }
}
});
@@ -1443,6 +1487,73 @@
printf("========================================================\n");
}
+/*
+ * |out_fd| A fd to support the DumpPool to output results to a temporary file.
+ * Dumpstate can pick up later and output to the bugreport. Using STDOUT_FILENO
+ * if it's not running in the parallel task.
+ */
+static void DumpCheckins(int out_fd = STDOUT_FILENO) {
+ dprintf(out_fd, "========================================================\n");
+ dprintf(out_fd, "== Checkins\n");
+ dprintf(out_fd, "========================================================\n");
+
+ RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"}, out_fd);
+ RunDumpsys("CHECKIN MEMINFO", {"meminfo", "--checkin"}, out_fd);
+ RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"}, out_fd);
+ RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"}, out_fd);
+ RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"}, out_fd);
+ RunDumpsys("CHECKIN PACKAGE", {"package", "--checkin"}, out_fd);
+}
+
+/*
+ * Runs dumpsys on activity service to dump all application activities, services
+ * and providers in the device.
+ *
+ * |out_fd| A fd to support the DumpPool to output results to a temporary file.
+ * Dumpstate can pick up later and output to the bugreport. Using STDOUT_FILENO
+ * if it's not running in the parallel task.
+ */
+static void DumpAppInfos(int out_fd = STDOUT_FILENO) {
+ dprintf(out_fd, "========================================================\n");
+ dprintf(out_fd, "== Running Application Activities\n");
+ dprintf(out_fd, "========================================================\n");
+
+ // The following dumpsys internally collects output from running apps, so it can take a long
+ // time. So let's extend the timeout.
+
+ const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
+
+ RunDumpsys("APP ACTIVITIES", {"activity", "-v", "all"}, DUMPSYS_COMPONENTS_OPTIONS, 0, out_fd);
+
+ dprintf(out_fd, "========================================================\n");
+ dprintf(out_fd, "== Running Application Services (platform)\n");
+ dprintf(out_fd, "========================================================\n");
+
+ RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform-non-critical"},
+ DUMPSYS_COMPONENTS_OPTIONS, 0, out_fd);
+
+ dprintf(out_fd, "========================================================\n");
+ dprintf(out_fd, "== Running Application Services (non-platform)\n");
+ dprintf(out_fd, "========================================================\n");
+
+ RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
+ DUMPSYS_COMPONENTS_OPTIONS, 0, out_fd);
+
+ dprintf(out_fd, "========================================================\n");
+ dprintf(out_fd, "== Running Application Providers (platform)\n");
+ dprintf(out_fd, "========================================================\n");
+
+ RunDumpsys("APP PROVIDERS PLATFORM", {"activity", "provider", "all-platform"},
+ DUMPSYS_COMPONENTS_OPTIONS, out_fd);
+
+ dprintf(out_fd, "========================================================\n");
+ dprintf(out_fd, "== Running Application Providers (non-platform)\n");
+ dprintf(out_fd, "========================================================\n");
+
+ RunDumpsys("APP PROVIDERS NON-PLATFORM", {"activity", "provider", "all-non-platform"},
+ DUMPSYS_COMPONENTS_OPTIONS, 0, out_fd);
+}
+
// Dumps various things. Returns early with status USER_CONSENT_DENIED if user denies consent
// via the consent they are shown. Ignores other errors that occur while running various
// commands. The consent checking is currently done around long running tasks, which happen to
@@ -1450,6 +1561,19 @@
static Dumpstate::RunStatus dumpstate() {
DurationReporter duration_reporter("DUMPSTATE");
+ // Enqueue slow functions into the thread pool, if the parallel run is enabled.
+ if (ds.dump_pool_) {
+ // Pool was shutdown in DumpstateDefaultAfterCritical method in order to
+ // drop root user. Restarts it with two threads for the parallel run.
+ ds.dump_pool_->start(/* thread_counts = */2);
+
+ ds.dump_pool_->enqueueTaskWithFd(DUMP_HALS_TASK, &DumpHals, _1);
+ ds.dump_pool_->enqueueTask(DUMP_INCIDENT_REPORT_TASK, &DumpIncidentReport);
+ ds.dump_pool_->enqueueTaskWithFd(DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1);
+ ds.dump_pool_->enqueueTaskWithFd(DUMP_CHECKINS_TASK, &DumpCheckins, _1);
+ ds.dump_pool_->enqueueTaskWithFd(DUMP_APP_INFOS_TASK, &DumpAppInfos, _1);
+ }
+
// Dump various things. Note that anything that takes "long" (i.e. several seconds) should
// check intermittently (if it's intrerruptable like a foreach on pids) and/or should be wrapped
// in a consent check (via RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK).
@@ -1481,7 +1605,11 @@
RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "LIBRANK", {"librank"},
CommandOptions::AS_ROOT);
- DumpHals();
+ if (ds.dump_pool_) {
+ WAIT_TASK_WITH_CONSENT_CHECK(DUMP_HALS_TASK, ds.dump_pool_);
+ } else {
+ RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_HALS_TASK, DumpHals);
+ }
RunCommand("PRINTENV", {"printenv"});
RunCommand("NETSTAT", {"netstat", "-nW"});
@@ -1564,7 +1692,11 @@
ds.AddDir(SNAPSHOTCTL_LOG_DIR, false);
- RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpstateBoard);
+ if (ds.dump_pool_) {
+ WAIT_TASK_WITH_CONSENT_CHECK(DUMP_BOARD_TASK, ds.dump_pool_);
+ } else {
+ RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_BOARD_TASK, ds.DumpstateBoard);
+ }
/* Migrate the ril_dumpstate to a device specific dumpstate? */
int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0);
@@ -1586,57 +1718,17 @@
RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysNormal);
- printf("========================================================\n");
- printf("== Checkins\n");
- printf("========================================================\n");
+ if (ds.dump_pool_) {
+ WAIT_TASK_WITH_CONSENT_CHECK(DUMP_CHECKINS_TASK, ds.dump_pool_);
+ } else {
+ RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_CHECKINS_TASK, DumpCheckins);
+ }
- RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});
-
- RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsys, "CHECKIN MEMINFO", {"meminfo", "--checkin"});
-
- RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"});
- RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"});
- RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"});
- RunDumpsys("CHECKIN PACKAGE", {"package", "--checkin"});
-
- printf("========================================================\n");
- printf("== Running Application Activities\n");
- printf("========================================================\n");
-
- // The following dumpsys internally collects output from running apps, so it can take a long
- // time. So let's extend the timeout.
-
- const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();
-
- RunDumpsys("APP ACTIVITIES", {"activity", "-v", "all"}, DUMPSYS_COMPONENTS_OPTIONS);
-
- printf("========================================================\n");
- printf("== Running Application Services (platform)\n");
- printf("========================================================\n");
-
- RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform-non-critical"},
- DUMPSYS_COMPONENTS_OPTIONS);
-
- printf("========================================================\n");
- printf("== Running Application Services (non-platform)\n");
- printf("========================================================\n");
-
- RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
- DUMPSYS_COMPONENTS_OPTIONS);
-
- printf("========================================================\n");
- printf("== Running Application Providers (platform)\n");
- printf("========================================================\n");
-
- RunDumpsys("APP PROVIDERS PLATFORM", {"activity", "provider", "all-platform"},
- DUMPSYS_COMPONENTS_OPTIONS);
-
- printf("========================================================\n");
- printf("== Running Application Providers (non-platform)\n");
- printf("========================================================\n");
-
- RunDumpsys("APP PROVIDERS NON-PLATFORM", {"activity", "provider", "all-non-platform"},
- DUMPSYS_COMPONENTS_OPTIONS);
+ if (ds.dump_pool_) {
+ WAIT_TASK_WITH_CONSENT_CHECK(DUMP_APP_INFOS_TASK, ds.dump_pool_);
+ } else {
+ RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_APP_INFOS_TASK, DumpAppInfos);
+ }
printf("========================================================\n");
printf("== Dropbox crashes\n");
@@ -1661,7 +1753,12 @@
// Add linker configuration directory
ds.AddDir(LINKERCONFIG_DIR, true);
- RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpIncidentReport);
+ if (ds.dump_pool_) {
+ WAIT_TASK_WITH_CONSENT_CHECK(DUMP_INCIDENT_REPORT_TASK, ds.dump_pool_);
+ } else {
+ RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_INCIDENT_REPORT_TASK,
+ DumpIncidentReport);
+ }
return Dumpstate::RunStatus::OK;
}
@@ -1682,7 +1779,18 @@
time_t logcat_ts = time(nullptr);
/* collect stack traces from Dalvik and native processes (needs root) */
- RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpTraces, &dump_traces_path);
+ if (dump_pool_) {
+ RETURN_IF_USER_DENIED_CONSENT();
+ // One thread is enough since we only need to enqueue DumpTraces here.
+ dump_pool_->start(/* thread_counts = */1);
+
+ // DumpTraces takes long time, post it to the another thread in the
+ // pool, if pool is available
+ dump_pool_->enqueueTask(DUMP_TRACES_TASK, &Dumpstate::DumpTraces, &ds, &dump_traces_path);
+ } else {
+ RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_TRACES_TASK, ds.DumpTraces,
+ &dump_traces_path);
+ }
/* Run some operations that require root. */
ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
@@ -1725,6 +1833,15 @@
DumpFile("PSI memory", "/proc/pressure/memory");
DumpFile("PSI io", "/proc/pressure/io");
+ if (dump_pool_) {
+ RETURN_IF_USER_DENIED_CONSENT();
+ dump_pool_->waitForTask(DUMP_TRACES_TASK);
+
+ // Current running thread in the pool is the root user also. Shutdown
+ // the pool and restart later to ensure all threads in the pool could
+ // drop the root user.
+ dump_pool_->shutdown();
+ }
if (!DropRootUser()) {
return Dumpstate::RunStatus::ERROR;
}
@@ -1736,31 +1853,39 @@
return status;
}
+// Common states for telephony and wifi which are needed to be collected before
+// dumpstate drop the root user.
+static void DumpstateRadioAsRoot() {
+ DumpIpTablesAsRoot();
+ ds.AddDir(LOGPERSIST_DATA_DIR, false);
+}
+
// This method collects common dumpsys for telephony and wifi. Typically, wifi
// reports are fine to include all information, but telephony reports on user
// builds need to strip some content (see DumpstateTelephonyOnly).
static void DumpstateRadioCommon(bool include_sensitive_info = true) {
- DumpIpTablesAsRoot();
-
- ds.AddDir(LOGPERSIST_DATA_DIR, false);
-
- if (!DropRootUser()) {
- return;
- }
-
// We need to be picky about some stuff for telephony reports on user builds.
if (!include_sensitive_info) {
// Only dump the radio log buffer (other buffers and dumps contain too much unrelated info).
DoRadioLogcat();
} else {
+ // DumpHals takes long time, post it to the another thread in the pool,
+ // if pool is available.
+ if (ds.dump_pool_) {
+ ds.dump_pool_->enqueueTaskWithFd(DUMP_HALS_TASK, &DumpHals, _1);
+ }
// Contains various system properties and process startup info.
do_dmesg();
// Logs other than the radio buffer may contain package/component names and potential PII.
DoLogcat();
// Too broad for connectivity problems.
DoKmsg();
- // Contains unrelated hardware info (camera, NFC, biometrics, ...).
- DumpHals();
+ // DumpHals contains unrelated hardware info (camera, NFC, biometrics, ...).
+ if (ds.dump_pool_) {
+ ds.dump_pool_->waitForTask(DUMP_HALS_TASK);
+ } else {
+ RUN_SLOW_FUNCTION_AND_LOG(DUMP_HALS_TASK, DumpHals);
+ }
}
DumpPacketStats();
@@ -1784,6 +1909,21 @@
const bool include_sensitive_info = !PropertiesHelper::IsUserBuild();
+ DumpstateRadioAsRoot();
+ if (!DropRootUser()) {
+ return;
+ }
+
+ // Starts thread pool after the root user is dropped, and two additional threads
+ // are created for DumpHals in the DumpstateRadioCommon and DumpstateBoard.
+ if (ds.dump_pool_) {
+ ds.dump_pool_->start(/*thread_counts =*/2);
+
+ // DumpstateBoard takes long time, post it to the another thread in the pool,
+ // if pool is available.
+ ds.dump_pool_->enqueueTaskWithFd(DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1);
+ }
+
DumpstateRadioCommon(include_sensitive_info);
if (include_sensitive_info) {
@@ -1860,12 +2000,29 @@
printf("========================================================\n");
printf("== dumpstate: done (id %d)\n", ds.id_);
printf("========================================================\n");
+
+ if (ds.dump_pool_) {
+ ds.dump_pool_->waitForTask(DUMP_BOARD_TASK);
+ } else {
+ RUN_SLOW_FUNCTION_AND_LOG(DUMP_BOARD_TASK, ds.DumpstateBoard);
+ }
}
// This method collects dumpsys for wifi debugging only
static void DumpstateWifiOnly() {
DurationReporter duration_reporter("DUMPSTATE");
+ DumpstateRadioAsRoot();
+ if (!DropRootUser()) {
+ return;
+ }
+
+ // Starts thread pool after the root user is dropped. Only one additional
+ // thread is needed for DumpHals in the DumpstateRadioCommon.
+ if (ds.dump_pool_) {
+ ds.dump_pool_->start(/*thread_counts =*/1);
+ }
+
DumpstateRadioCommon();
printf("========================================================\n");
@@ -1883,8 +2040,6 @@
}
Dumpstate::RunStatus Dumpstate::DumpTraces(const char** path) {
- DurationReporter duration_reporter("DUMP TRACES");
-
const std::string temp_file_pattern = "/data/anr/dumptrace_XXXXXX";
const size_t buf_size = temp_file_pattern.length() + 1;
std::unique_ptr<char[]> file_name_buf(new char[buf_size]);
@@ -1992,11 +2147,10 @@
return RunStatus::OK;
}
-void Dumpstate::DumpstateBoard() {
- DurationReporter duration_reporter("dumpstate_board()");
- printf("========================================================\n");
- printf("== Board\n");
- printf("========================================================\n");
+void Dumpstate::DumpstateBoard(int out_fd) {
+ dprintf(out_fd, "========================================================\n");
+ dprintf(out_fd, "== Board\n");
+ dprintf(out_fd, "========================================================\n");
if (!IsZipping()) {
MYLOGD("Not dumping board info because it's not a zipped bugreport\n");
@@ -2122,8 +2276,9 @@
MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str());
continue;
}
- AddZipEntry(kDumpstateBoardFiles[i], paths[i]);
- printf("*** See %s entry ***\n", kDumpstateBoardFiles[i].c_str());
+ remover[i].Disable();
+ EnqueueAddZipEntryAndCleanupIfNeeded(kDumpstateBoardFiles[i], paths[i]);
+ dprintf(out_fd, "*** See %s entry ***\n", kDumpstateBoardFiles[i].c_str());
}
}
@@ -2153,6 +2308,11 @@
}
bool Dumpstate::FinishZipFile() {
+ // Runs all enqueued adding zip entry and cleanup tasks before finishing the zip file.
+ if (zip_entry_tasks_) {
+ zip_entry_tasks_->run(/* do_cancel = */false);
+ }
+
std::string entry_name = base_name_ + "-" + name_ + ".txt";
MYLOGD("Adding main entry (%s) from %s to .zip bugreport\n", entry_name.c_str(),
tmp_path_.c_str());
@@ -2356,7 +2516,6 @@
break;
case Dumpstate::BugreportMode::BUGREPORT_INTERACTIVE:
// Currently, the dumpstate binder is only used by Shell to update progress.
- options->do_start_service = true;
options->do_progress_updates = true;
options->do_screenshot = is_screenshot_requested;
options->dumpstate_hal_mode = DumpstateMode::INTERACTIVE;
@@ -2368,7 +2527,6 @@
options->dumpstate_hal_mode = DumpstateMode::REMOTE;
break;
case Dumpstate::BugreportMode::BUGREPORT_WEAR:
- options->do_start_service = true;
options->do_progress_updates = true;
options->do_zip_file = true;
options->do_screenshot = is_screenshot_requested;
@@ -2395,12 +2553,12 @@
static void LogDumpOptions(const Dumpstate::DumpOptions& options) {
MYLOGI(
"do_zip_file: %d do_vibrate: %d use_socket: %d use_control_socket: %d do_screenshot: %d "
- "is_remote_mode: %d show_header_only: %d do_start_service: %d telephony_only: %d "
+ "is_remote_mode: %d show_header_only: %d telephony_only: %d "
"wifi_only: %d do_progress_updates: %d fd: %d bugreport_mode: %s dumpstate_hal_mode: %s "
"limited_only: %d args: %s\n",
options.do_zip_file, options.do_vibrate, options.use_socket, options.use_control_socket,
options.do_screenshot, options.is_remote_mode, options.show_header_only,
- options.do_start_service, options.telephony_only, options.wifi_only,
+ options.telephony_only, options.wifi_only,
options.do_progress_updates, options.bugreport_fd.get(), options.bugreport_mode.c_str(),
toString(options.dumpstate_hal_mode).c_str(), options.limited_only, options.args.c_str());
}
@@ -2531,6 +2689,15 @@
}
tombstone_data_.clear();
anr_data_.clear();
+
+ // Instead of shutdown the pool, we delete temporary files directly since
+ // shutdown blocking the call.
+ if (dump_pool_) {
+ dump_pool_->deleteTempFiles();
+ }
+ if (zip_entry_tasks_) {
+ zip_entry_tasks_->run(/*do_cancel =*/ true);
+ }
}
/*
@@ -2556,6 +2723,7 @@
*/
Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
const std::string& calling_package) {
+ DurationReporter duration_reporter("RUN INTERNAL", /* logcat_only = */true);
LogDumpOptions(*options_);
if (!options_->ValidateOptions()) {
MYLOGE("Invalid options specified\n");
@@ -2615,15 +2783,6 @@
register_sig_handler();
- // TODO(b/111441001): maybe skip if already started?
- if (options_->do_start_service) {
- MYLOGI("Starting 'dumpstate' service\n");
- android::status_t ret;
- if ((ret = android::os::DumpstateService::Start()) != android::OK) {
- MYLOGE("Unable to start DumpstateService: %d\n", ret);
- }
- }
-
if (PropertiesHelper::IsDryRun()) {
MYLOGI("Running on dry-run mode (to disable it, call 'setprop dumpstate.dry_run false')\n");
}
@@ -2717,6 +2876,13 @@
// Don't buffer stdout
setvbuf(stdout, nullptr, _IONBF, 0);
+ // Enable the parallel run if the client requests to output to a file.
+ EnableParallelRunIfNeeded();
+ // Using scope guard to make sure the dump pool can be shut down correctly.
+ auto scope_guard_to_shutdown_pool = android::base::make_scope_guard([=]() {
+ ShutdownDumpPool();
+ });
+
// NOTE: there should be no stdout output until now, otherwise it would break the header.
// In particular, DurationReport objects should be created passing 'title, NULL', so their
// duration is logged into MYLOG instead.
@@ -2728,7 +2894,6 @@
onUiIntensiveBugreportDumpsFinished(calling_uid, calling_package);
MaybeCheckUserConsent(calling_uid, calling_package);
DumpstateTelephonyOnly(calling_package);
- DumpstateBoard();
} else if (options_->wifi_only) {
MaybeTakeEarlyScreenshot();
onUiIntensiveBugreportDumpsFinished(calling_uid, calling_package);
@@ -2883,6 +3048,45 @@
android::os::UnlinkAndLogOnError(path_);
}
+void Dumpstate::EnableParallelRunIfNeeded() {
+ // The thread pool needs to create temporary files to receive dump results.
+ // That's why we only enable it when the bugreport client chooses to output
+ // to a file.
+ if (!PropertiesHelper::IsParallelRun() || !options_->OutputToFile()) {
+ return;
+ }
+ dump_pool_ = std::make_unique<DumpPool>(bugreport_internal_dir_);
+ zip_entry_tasks_ = std::make_unique<TaskQueue>();
+}
+
+void Dumpstate::ShutdownDumpPool() {
+ if (dump_pool_) {
+ dump_pool_->shutdown();
+ dump_pool_ = nullptr;
+ }
+ if (zip_entry_tasks_) {
+ zip_entry_tasks_->run(/* do_cancel = */true);
+ zip_entry_tasks_ = nullptr;
+ }
+}
+
+void Dumpstate::EnqueueAddZipEntryAndCleanupIfNeeded(const std::string& entry_name,
+ const std::string& entry_path) {
+ auto func_add_zip_entry_and_cleanup = [=](bool task_cancelled) {
+ if (!task_cancelled) {
+ AddZipEntry(entry_name, entry_path);
+ }
+ android::os::UnlinkAndLogOnError(entry_path);
+ };
+ if (zip_entry_tasks_) {
+ // Enqueues AddZipEntryAndCleanup function if the parallel run is enabled.
+ zip_entry_tasks_->add(func_add_zip_entry_and_cleanup, _1);
+ } else {
+ // Invokes AddZipEntryAndCleanup immediately
+ std::invoke(func_add_zip_entry_and_cleanup, /* task_cancelled = */false);
+ }
+}
+
Dumpstate::RunStatus Dumpstate::HandleUserConsentDenied() {
MYLOGD("User denied consent; deleting files and returning\n");
CleanupTmpFiles();
@@ -3001,8 +3205,9 @@
return singleton_;
}
-DurationReporter::DurationReporter(const std::string& title, bool logcat_only, bool verbose)
- : title_(title), logcat_only_(logcat_only), verbose_(verbose) {
+DurationReporter::DurationReporter(const std::string& title, bool logcat_only, bool verbose,
+ int duration_fd) : title_(title), logcat_only_(logcat_only), verbose_(verbose),
+ duration_fd_(duration_fd) {
if (!title_.empty()) {
started_ = Nanotime();
}
@@ -3016,7 +3221,8 @@
}
if (!logcat_only_) {
// Use "Yoda grammar" to make it easier to grep|sort sections.
- printf("------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str());
+ dprintf(duration_fd_, "------ %.3fs was the duration of '%s' ------\n",
+ elapsed, title_.c_str());
}
}
}
@@ -3602,10 +3808,11 @@
}
int Dumpstate::RunCommand(const std::string& title, const std::vector<std::string>& full_command,
- const CommandOptions& options, bool verbose_duration) {
- DurationReporter duration_reporter(title, false /* logcat_only */, verbose_duration);
+ const CommandOptions& options, bool verbose_duration, int out_fd) {
+ DurationReporter duration_reporter(title, false /* logcat_only */,
+ verbose_duration, out_fd);
- int status = RunCommandToFd(STDOUT_FILENO, title, full_command, options);
+ int status = RunCommandToFd(out_fd, title, full_command, options);
/* TODO: for now we're simplifying the progress calculation by using the
* timeout as the weight. It's a good approximation for most cases, except when calling dumpsys,
@@ -3617,11 +3824,11 @@
}
void Dumpstate::RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args,
- const CommandOptions& options, long dumpsysTimeoutMs) {
+ const CommandOptions& options, long dumpsysTimeoutMs, int out_fd) {
long timeout_ms = dumpsysTimeoutMs > 0 ? dumpsysTimeoutMs : options.TimeoutInMs();
std::vector<std::string> dumpsys = {"/system/bin/dumpsys", "-T", std::to_string(timeout_ms)};
dumpsys.insert(dumpsys.end(), dumpsys_args.begin(), dumpsys_args.end());
- RunCommand(title, dumpsys, options);
+ RunCommand(title, dumpsys, options, false, out_fd);
}
int open_socket(const char *service) {
@@ -3744,12 +3951,16 @@
fclose(fp);
}
-// TODO: make this function thread safe if sections are generated in parallel.
void Dumpstate::UpdateProgress(int32_t delta_sec) {
if (progress_ == nullptr) {
MYLOGE("UpdateProgress: progress_ not set\n");
return;
}
+ // This function updates progress related members of the dumpstate and reports
+ // progress percentage to the bugreport client. Since it could be called by
+ // different dump tasks at the same time if the parallel run is enabled, a
+ // mutex lock is necessary here to synchronize the call.
+ std::lock_guard<std::recursive_mutex> lock(mutex_);
// Always update progess so stats can be tuned...
progress_->Inc(delta_sec);
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 0d25d30..9582c9d 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -35,6 +35,8 @@
#include <ziparchive/zip_writer.h>
#include "DumpstateUtil.h"
+#include "DumpPool.h"
+#include "TaskQueue.h"
// Workaround for const char *args[MAX_ARGS_ARRAY_SIZE] variables until they're converted to
// std::vector<std::string>
@@ -75,7 +77,7 @@
class DurationReporter {
public:
explicit DurationReporter(const std::string& title, bool logcat_only = false,
- bool verbose = false);
+ bool verbose = false, int duration_fd = STDOUT_FILENO);
~DurationReporter();
@@ -84,6 +86,7 @@
bool logcat_only_;
bool verbose_;
uint64_t started_;
+ int duration_fd_;
DISALLOW_COPY_AND_ASSIGN(DurationReporter);
};
@@ -193,7 +196,7 @@
* that are spread accross utils.cpp and dumpstate.cpp will be moved to it.
*/
class Dumpstate {
- friend class DumpstateTest;
+ friend class android::os::dumpstate::DumpstateTest;
public:
enum RunStatus { OK, HELP, INVALID_INPUT, ERROR, USER_CONSENT_DENIED, USER_CONSENT_TIMED_OUT };
@@ -227,11 +230,13 @@
* |full_command| array containing the command (first entry) and its arguments.
* Must contain at least one element.
* |options| optional argument defining the command's behavior.
+ * |out_fd| A fd to support the DumpPool to output results to a temporary
+ * file. Using STDOUT_FILENO if it's not running in the parallel task.
*/
int RunCommand(const std::string& title, const std::vector<std::string>& fullCommand,
const android::os::dumpstate::CommandOptions& options =
android::os::dumpstate::CommandOptions::DEFAULT,
- bool verbose_duration = false);
+ bool verbose_duration = false, int out_fd = STDOUT_FILENO);
/*
* Runs `dumpsys` with the given arguments, automatically setting its timeout
@@ -244,10 +249,12 @@
* |options| optional argument defining the command's behavior.
* |dumpsys_timeout| when > 0, defines the value passed to `dumpsys -T` (otherwise it uses the
* timeout from `options`)
+ * |out_fd| A fd to support the DumpPool to output results to a temporary
+ * file. Using STDOUT_FILENO if it's not running in the parallel task.
*/
void RunDumpsys(const std::string& title, const std::vector<std::string>& dumpsys_args,
const android::os::dumpstate::CommandOptions& options = DEFAULT_DUMPSYS,
- long dumpsys_timeout_ms = 0);
+ long dumpsys_timeout_ms = 0, int out_fd = STDOUT_FILENO);
/*
* Prints the contents of a file.
@@ -304,7 +311,12 @@
// Returns OK in all other cases.
RunStatus DumpTraces(const char** path);
- void DumpstateBoard();
+ /*
+ * |out_fd| A fd to support the DumpPool to output results to a temporary file.
+ * Dumpstate can pick up later and output to the bugreport. Using STDOUT_FILENO
+ * if it's not running in the parallel task.
+ */
+ void DumpstateBoard(int out_fd = STDOUT_FILENO);
/*
* Updates the overall progress of the bugreport generation by the given weight increment.
@@ -361,6 +373,18 @@
bool CalledByApi() const;
/*
+ * Enqueues a task to the dumpstate's TaskQueue if the parallel run is enabled,
+ * otherwise invokes it immediately. The task adds file at path entry_path
+ * as a zip file entry with name entry_name. Unlinks entry_path when done.
+ *
+ * All enqueued tasks will be executed in the dumpstate's FinishZipFile method
+ * before the zip file is finished. Tasks will be cancelled in dumpstate's
+ * ShutdownDumpPool method if they have never been called.
+ */
+ void EnqueueAddZipEntryAndCleanupIfNeeded(const std::string& entry_name,
+ const std::string& entry_path);
+
+ /*
* Structure to hold options that determine the behavior of dumpstate.
*/
struct DumpOptions {
@@ -374,7 +398,6 @@
bool is_screenshot_copied = false;
bool is_remote_mode = false;
bool show_header_only = false;
- bool do_start_service = false;
bool telephony_only = false;
bool wifi_only = false;
// Trimmed-down version of dumpstate to only include whitelisted logs.
@@ -490,6 +513,13 @@
// List of open ANR dump files.
std::vector<DumpData> anr_data_;
+ // A thread pool to execute dump tasks simultaneously if the parallel run is enabled.
+ std::unique_ptr<android::os::dumpstate::DumpPool> dump_pool_;
+
+ // A task queue to collect adding zip entry tasks inside dump tasks if the
+ // parallel run is enabled.
+ std::unique_ptr<android::os::dumpstate::TaskQueue> zip_entry_tasks_;
+
// A callback to IncidentCompanion service, which checks user consent for sharing the
// bugreport with the calling app. If the user has not responded yet to the dialog it will
// be neither confirmed nor denied.
@@ -528,6 +558,10 @@
// but leaves the log file alone.
void CleanupTmpFiles();
+ // Create the thread pool to enable the parallel run function.
+ void EnableParallelRunIfNeeded();
+ void ShutdownDumpPool();
+
RunStatus HandleUserConsentDenied();
// Copies bugreport artifacts over to the caller's directories provided there is user consent or
@@ -539,6 +573,8 @@
android::sp<ConsentCallback> consent_callback_;
+ std::recursive_mutex mutex_;
+
DISALLOW_COPY_AND_ASSIGN(Dumpstate);
};
diff --git a/cmds/dumpstate/dumpstate_smoke_test.xml b/cmds/dumpstate/dumpstate_smoke_test.xml
new file mode 100644
index 0000000..0aff200
--- /dev/null
+++ b/cmds/dumpstate/dumpstate_smoke_test.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+<configuration description="Config for dumpstate_smoke_test">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="dumpstate_smoke_test->/data/local/tmp/dumpstate_smoke_test" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="dumpstate_smoke_test" />
+ <option name="native-test-timeout" value="600000" />
+ </test>
+</configuration>
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index 6f2d754..2c800c6 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -209,13 +209,12 @@
static std::shared_ptr<std::vector<SectionInfo>> sections;
static Dumpstate& ds;
static std::chrono::milliseconds duration;
- static void SetUpTestCase() {
+ static void GenerateBugreport() {
// clang-format off
char* argv[] = {
(char*)"dumpstate",
(char*)"-d",
- (char*)"-z",
- (char*)"-B"
+ (char*)"-z"
};
// clang-format on
sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout)), sections));
@@ -236,20 +235,20 @@
std::chrono::milliseconds ZippedBugreportGenerationTest::duration = 0s;
TEST_F(ZippedBugreportGenerationTest, IsGeneratedWithoutErrors) {
+ GenerateBugreport();
EXPECT_EQ(access(getZipFilePath().c_str(), F_OK), 0);
}
-TEST_F(ZippedBugreportGenerationTest, Is3MBto30MBinSize) {
+TEST_F(ZippedBugreportGenerationTest, Is1MBMBinSize) {
struct stat st;
EXPECT_EQ(stat(getZipFilePath().c_str(), &st), 0);
- EXPECT_GE(st.st_size, 3000000 /* 3MB */);
- EXPECT_LE(st.st_size, 30000000 /* 30MB */);
+ EXPECT_GE(st.st_size, 1000000 /* 1MB */);
}
-TEST_F(ZippedBugreportGenerationTest, TakesBetween30And150Seconds) {
+TEST_F(ZippedBugreportGenerationTest, TakesBetween30And300Seconds) {
EXPECT_GE(duration, 30s) << "Expected completion in more than 30s. Actual time "
<< duration.count() << " s.";
- EXPECT_LE(duration, 150s) << "Expected completion in less than 150s. Actual time "
+ EXPECT_LE(duration, 300s) << "Expected completion in less than 300s. Actual time "
<< duration.count() << " s.";
}
@@ -266,7 +265,8 @@
CloseArchive(handle);
}
- void FileExists(const char* filename, uint32_t minsize, uint32_t maxsize) {
+ void FileExists(const char* filename, uint32_t minsize,
+ uint32_t maxsize = std::numeric_limits<uint32_t>::max()) {
ZipEntry entry;
GetEntry(handle, filename, &entry);
EXPECT_GT(entry.uncompressed_length, minsize);
@@ -285,7 +285,7 @@
main_entry.uncompressed_length);
// contains main entry file
- FileExists(bugreport_txt_name.c_str(), 1000000U, 50000000U);
+ FileExists(bugreport_txt_name.c_str(), 1000000U);
}
TEST_F(ZippedBugReportContentsTest, ContainsVersion) {
@@ -301,8 +301,9 @@
}
TEST_F(ZippedBugReportContentsTest, ContainsBoardSpecificFiles) {
- FileExists("dumpstate_board.bin", 1000000U, 80000000U);
- FileExists("dumpstate_board.txt", 100000U, 1000000U);
+ // TODO(b/160109027): cf_x86_phone-userdebug does not dump them.
+ // FileExists("dumpstate_board.bin", 1000000U, 80000000U);
+ // FileExists("dumpstate_board.txt", 100000U, 1000000U);
}
TEST_F(ZippedBugReportContentsTest, ContainsProtoFile) {
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index c7df1bb..6b93692 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -21,6 +21,7 @@
#include "DumpstateService.h"
#include "android/os/BnDumpstate.h"
#include "dumpstate.h"
+#include "DumpPool.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -46,6 +47,7 @@
using ::android::hardware::dumpstate::V1_1::DumpstateMode;
using ::testing::EndsWith;
+using ::testing::Eq;
using ::testing::HasSubstr;
using ::testing::IsEmpty;
using ::testing::IsNull;
@@ -95,6 +97,10 @@
PropertiesHelper::unroot_ = unroot;
}
+ void SetParallelRun(bool parallel_run) const {
+ PropertiesHelper::parallel_run_ = parallel_run;
+ }
+
bool IsStandalone() const {
return calls_ == 1;
}
@@ -252,7 +258,6 @@
EXPECT_FALSE(options_.do_progress_updates);
EXPECT_FALSE(options_.is_remote_mode);
EXPECT_FALSE(options_.use_socket);
- EXPECT_FALSE(options_.do_start_service);
EXPECT_FALSE(options_.limited_only);
}
@@ -261,7 +266,6 @@
EXPECT_TRUE(options_.do_add_date);
EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.do_progress_updates);
- EXPECT_TRUE(options_.do_start_service);
EXPECT_TRUE(options_.do_screenshot);
EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::INTERACTIVE);
@@ -297,7 +301,6 @@
EXPECT_TRUE(options_.do_screenshot);
EXPECT_TRUE(options_.do_zip_file);
EXPECT_TRUE(options_.do_progress_updates);
- EXPECT_TRUE(options_.do_start_service);
EXPECT_EQ(options_.dumpstate_hal_mode, DumpstateMode::WEAR);
// Other options retain default values
@@ -542,6 +545,10 @@
ds.options_.reset(new Dumpstate::DumpOptions());
}
+ void TearDown() {
+ ds.ShutdownDumpPool();
+ }
+
// Runs a command and capture `stdout` and `stderr`.
int RunCommand(const std::string& title, const std::vector<std::string>& full_command,
const CommandOptions& options = CommandOptions::DEFAULT) {
@@ -569,6 +576,10 @@
ds.progress_.reset(new Progress(initial_max, progress, 1.2));
}
+ void EnableParallelRunIfNeeded() {
+ ds.EnableParallelRunIfNeeded();
+ }
+
std::string GetProgressMessage(int progress, int max,
int old_max = 0, bool update_progress = true) {
EXPECT_EQ(progress, ds.progress_->Get()) << "invalid progress";
@@ -1007,6 +1018,30 @@
ds.listener_.clear();
}
+TEST_F(DumpstateTest, DumpPool_withOutputToFileAndParallelRunEnabled_notNull) {
+ ds.options_->use_socket = false;
+ SetParallelRun(true);
+ EnableParallelRunIfNeeded();
+ EXPECT_TRUE(ds.options_->OutputToFile());
+ EXPECT_TRUE(ds.zip_entry_tasks_);
+ EXPECT_TRUE(ds.dump_pool_);
+}
+
+TEST_F(DumpstateTest, DumpPool_withNotOutputToFile_isNull) {
+ ds.options_->use_socket = true;
+ EnableParallelRunIfNeeded();
+ EXPECT_FALSE(ds.options_->OutputToFile());
+ EXPECT_FALSE(ds.zip_entry_tasks_);
+ EXPECT_FALSE(ds.dump_pool_);
+}
+
+TEST_F(DumpstateTest, DumpPool_withParallelRunDisabled_isNull) {
+ SetParallelRun(false);
+ EnableParallelRunIfNeeded();
+ EXPECT_FALSE(ds.zip_entry_tasks_);
+ EXPECT_FALSE(ds.dump_pool_);
+}
+
class DumpstateServiceTest : public DumpstateBaseTest {
public:
DumpstateService dss;
@@ -1618,6 +1653,154 @@
EXPECT_THAT(out, EndsWith("skipped on dry run\n"));
}
+class DumpPoolTest : public DumpstateBaseTest {
+ public:
+ void SetUp() {
+ dump_pool_ = std::make_unique<DumpPool>(kTestDataPath);
+ DumpstateBaseTest::SetUp();
+ CreateOutputFile();
+ }
+
+ void CreateOutputFile() {
+ out_path_ = kTestDataPath + "out.txt";
+ out_fd_.reset(TEMP_FAILURE_RETRY(open(out_path_.c_str(),
+ O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
+ ASSERT_GE(out_fd_.get(), 0) << "could not create FD for path "
+ << out_path_;
+ }
+
+ int getTempFileCounts(const std::string& folder) {
+ int count = 0;
+ std::unique_ptr<DIR, decltype(&closedir)> dir_ptr(opendir(folder.c_str()),
+ &closedir);
+ if (!dir_ptr) {
+ return -1;
+ }
+ int dir_fd = dirfd(dir_ptr.get());
+ if (dir_fd < 0) {
+ return -1;
+ }
+
+ struct dirent* de;
+ while ((de = readdir(dir_ptr.get()))) {
+ if (de->d_type != DT_REG) {
+ continue;
+ }
+ std::string file_name(de->d_name);
+ if (file_name.find(DumpPool::PREFIX_TMPFILE_NAME) != 0) {
+ continue;
+ }
+ count++;
+ }
+ return count;
+ }
+
+ void setLogDuration(bool log_duration) {
+ dump_pool_->setLogDuration(log_duration);
+ }
+
+ std::unique_ptr<DumpPool> dump_pool_;
+ android::base::unique_fd out_fd_;
+ std::string out_path_;
+};
+
+TEST_F(DumpPoolTest, EnqueueTaskWithFd) {
+ auto dump_func_1 = [](int out_fd) {
+ dprintf(out_fd, "A");
+ };
+ auto dump_func_2 = [](int out_fd) {
+ dprintf(out_fd, "B");
+ sleep(1);
+ };
+ auto dump_func_3 = [](int out_fd) {
+ dprintf(out_fd, "C");
+ };
+ setLogDuration(/* log_duration = */false);
+ dump_pool_->enqueueTaskWithFd(/* task_name = */"1", dump_func_1, std::placeholders::_1);
+ dump_pool_->enqueueTaskWithFd(/* task_name = */"2", dump_func_2, std::placeholders::_1);
+ dump_pool_->enqueueTaskWithFd(/* task_name = */"3", dump_func_3, std::placeholders::_1);
+
+ dump_pool_->waitForTask("1", "", out_fd_.get());
+ dump_pool_->waitForTask("2", "", out_fd_.get());
+ dump_pool_->waitForTask("3", "", out_fd_.get());
+ dump_pool_->shutdown();
+
+ std::string result;
+ ReadFileToString(out_path_, &result);
+ EXPECT_THAT(result, StrEq("A\nB\nC\n"));
+ EXPECT_THAT(getTempFileCounts(kTestDataPath), Eq(0));
+}
+
+TEST_F(DumpPoolTest, EnqueueTask_withDurationLog) {
+ bool run_1 = false;
+ auto dump_func_1 = [&]() {
+ run_1 = true;
+ };
+
+ dump_pool_->enqueueTask(/* task_name = */"1", dump_func_1);
+ dump_pool_->waitForTask("1", "", out_fd_.get());
+ dump_pool_->shutdown();
+
+ std::string result;
+ ReadFileToString(out_path_, &result);
+ EXPECT_TRUE(run_1);
+ EXPECT_THAT(result, StrEq("------ 0.000s was the duration of '1' ------\n"));
+ EXPECT_THAT(getTempFileCounts(kTestDataPath), Eq(0));
+}
+
+class TaskQueueTest : public DumpstateBaseTest {
+public:
+ void SetUp() {
+ DumpstateBaseTest::SetUp();
+ }
+
+ TaskQueue task_queue_;
+};
+
+TEST_F(TaskQueueTest, runTask) {
+ bool is_task1_run = false;
+ bool is_task2_run = false;
+ auto task_1 = [&](bool task_cancelled) {
+ if (task_cancelled) {
+ return;
+ }
+ is_task1_run = true;
+ };
+ auto task_2 = [&](bool task_cancelled) {
+ if (task_cancelled) {
+ return;
+ }
+ is_task2_run = true;
+ };
+ task_queue_.add(task_1, std::placeholders::_1);
+ task_queue_.add(task_2, std::placeholders::_1);
+
+ task_queue_.run(/* do_cancel = */false);
+
+ EXPECT_TRUE(is_task1_run);
+ EXPECT_TRUE(is_task2_run);
+}
+
+TEST_F(TaskQueueTest, runTask_withCancelled) {
+ bool is_task1_cancelled = false;
+ bool is_task2_cancelled = false;
+ auto task_1 = [&](bool task_cancelled) {
+ is_task1_cancelled = task_cancelled;
+ };
+ auto task_2 = [&](bool task_cancelled) {
+ is_task2_cancelled = task_cancelled;
+ };
+ task_queue_.add(task_1, std::placeholders::_1);
+ task_queue_.add(task_2, std::placeholders::_1);
+
+ task_queue_.run(/* do_cancel = */true);
+
+ EXPECT_TRUE(is_task1_cancelled);
+ EXPECT_TRUE(is_task2_cancelled);
+}
+
+
} // namespace dumpstate
} // namespace os
} // namespace android
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index bd45005..7c9e3b2 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -41,6 +41,21 @@
"liblogwrap",
],
test_config: "installd_cache_test.xml",
+
+ product_variables: {
+ arc: {
+ exclude_srcs: [
+ "QuotaUtils.cpp",
+ ],
+ static_libs: [
+ "libarcdiskquota",
+ "arc_services_aidl",
+ ],
+ cflags: [
+ "-DUSE_ARC",
+ ],
+ },
+ },
}
cc_test {
@@ -66,6 +81,21 @@
"liblogwrap",
],
test_config: "installd_service_test.xml",
+
+ product_variables: {
+ arc: {
+ exclude_srcs: [
+ "QuotaUtils.cpp",
+ ],
+ static_libs: [
+ "libarcdiskquota",
+ "arc_services_aidl",
+ ],
+ cflags: [
+ "-DUSE_ARC",
+ ],
+ },
+ },
}
cc_test {
@@ -93,6 +123,21 @@
"libz",
],
test_config: "installd_dexopt_test.xml",
+
+ product_variables: {
+ arc: {
+ exclude_srcs: [
+ "QuotaUtils.cpp",
+ ],
+ static_libs: [
+ "libarcdiskquota",
+ "arc_services_aidl",
+ ],
+ cflags: [
+ "-DUSE_ARC",
+ ],
+ },
+ },
}
cc_test {
diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp
index 9964888..ba6cdf1 100644
--- a/cmds/lshal/test.cpp
+++ b/cmds/lshal/test.cpp
@@ -479,8 +479,7 @@
}
TEST_F(ListTest, DumpVintf) {
- const std::string expected = "<manifest version=\"2.0\" type=\"device\">\n"
- " <hal format=\"hidl\">\n"
+ const std::string expected = " <hal format=\"hidl\">\n"
" <name>a.h.foo1</name>\n"
" <transport>hwbinder</transport>\n"
" <fqname>@1.0::IFoo/1</fqname>\n"
@@ -499,8 +498,7 @@
" <name>a.h.foo4</name>\n"
" <transport arch=\"32\">passthrough</transport>\n"
" <fqname>@4.0::IFoo/4</fqname>\n"
- " </hal>\n"
- "</manifest>";
+ " </hal>\n";
optind = 1; // mimic Lshal::parseArg()
EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--init-vintf"})));
diff --git a/libs/binder/ParcelableHolder.cpp b/libs/binder/ParcelableHolder.cpp
index e9df279..b2b8671 100644
--- a/libs/binder/ParcelableHolder.cpp
+++ b/libs/binder/ParcelableHolder.cpp
@@ -27,7 +27,6 @@
namespace android {
namespace os {
status_t ParcelableHolder::writeToParcel(Parcel* p) const {
- std::lock_guard<std::mutex> l(mMutex);
RETURN_ON_FAILURE(p->writeInt32(static_cast<int32_t>(this->getStability())));
if (this->mParcelPtr) {
RETURN_ON_FAILURE(p->writeInt32(this->mParcelPtr->dataSize()));
@@ -53,7 +52,6 @@
}
status_t ParcelableHolder::readFromParcel(const Parcel* p) {
- std::lock_guard<std::mutex> l(mMutex);
this->mStability = static_cast<Stability>(p->readInt32());
this->mParcelable = nullptr;
this->mParcelableName = std::nullopt;
diff --git a/libs/binder/include/binder/ParcelableHolder.h b/libs/binder/include/binder/ParcelableHolder.h
index 5da2515..4ea3dd3 100644
--- a/libs/binder/include/binder/ParcelableHolder.h
+++ b/libs/binder/include/binder/ParcelableHolder.h
@@ -59,7 +59,6 @@
template <typename T>
bool setParcelable(std::shared_ptr<T> p) {
- std::lock_guard<std::mutex> l(mMutex);
static_assert(std::is_base_of<Parcelable, T>::value, "T must be derived from Parcelable");
if (p && this->getStability() > p->getStability()) {
return false;
@@ -73,7 +72,6 @@
template <typename T>
std::shared_ptr<T> getParcelable() const {
static_assert(std::is_base_of<Parcelable, T>::value, "T must be derived from Parcelable");
- std::lock_guard<std::mutex> l(mMutex);
const std::string& parcelableDesc = T::getParcelableDescriptor();
if (!this->mParcelPtr) {
if (!this->mParcelable || !this->mParcelableName) {
@@ -135,7 +133,6 @@
mutable std::optional<std::string> mParcelableName;
mutable std::unique_ptr<Parcel> mParcelPtr;
Stability mStability;
- mutable std::mutex mMutex;
};
} // namespace os
} // namespace android
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
index 6701518..dfcf4dc 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
@@ -25,6 +25,8 @@
*/
#pragma once
+#include <android/binder_parcel_utils.h>
+#include <optional>
namespace ndk {
// Also see Parcelable.h in libbinder.
@@ -33,6 +35,89 @@
STABILITY_LOCAL,
STABILITY_VINTF, // corresponds to @VintfStability
};
+#define RETURN_ON_FAILURE(expr) \
+ do { \
+ binder_status_t _status = (expr); \
+ if (_status != STATUS_OK) return _status; \
+ } while (false)
+
+class AParcelableHolder {
+ public:
+ AParcelableHolder() = delete;
+ explicit AParcelableHolder(parcelable_stability_t stability)
+ : mParcel(AParcel_create()), mStability(stability) {}
+
+ virtual ~AParcelableHolder() = default;
+
+ binder_status_t writeToParcel(AParcel* parcel) const {
+ RETURN_ON_FAILURE(AParcel_writeInt32(parcel, static_cast<int32_t>(this->mStability)));
+ RETURN_ON_FAILURE(AParcel_writeInt32(parcel, AParcel_getDataSize(this->mParcel.get())));
+ RETURN_ON_FAILURE(AParcel_appendFrom(this->mParcel.get(), parcel, 0,
+ AParcel_getDataSize(this->mParcel.get())));
+ return STATUS_OK;
+ }
+
+ binder_status_t readFromParcel(const AParcel* parcel) {
+ AParcel_reset(mParcel.get());
+
+ RETURN_ON_FAILURE(AParcel_readInt32(parcel, &this->mStability));
+ int32_t dataSize;
+ binder_status_t status = AParcel_readInt32(parcel, &dataSize);
+
+ if (status != STATUS_OK || dataSize < 0) {
+ return status != STATUS_OK ? status : STATUS_BAD_VALUE;
+ }
+
+ int32_t dataStartPos = AParcel_getDataPosition(parcel);
+
+ if (dataStartPos > INT32_MAX - dataSize) {
+ return STATUS_BAD_VALUE;
+ }
+
+ status = AParcel_appendFrom(parcel, mParcel.get(), dataStartPos, dataSize);
+ if (status != STATUS_OK) {
+ return status;
+ }
+ return AParcel_setDataPosition(parcel, dataStartPos + dataSize);
+ }
+
+ template <typename T>
+ bool setParcelable(T* p) {
+ if (p && this->mStability > T::_aidl_stability) {
+ return false;
+ }
+ AParcel_reset(mParcel.get());
+ AParcel_writeString(mParcel.get(), T::descriptor, strlen(T::descriptor));
+ p->writeToParcel(mParcel.get());
+ return true;
+ }
+
+ template <typename T>
+ std::unique_ptr<T> getParcelable() const {
+ const std::string parcelableDesc(T::descriptor);
+ AParcel_setDataPosition(mParcel.get(), 0);
+ if (AParcel_getDataSize(mParcel.get()) == 0) {
+ return nullptr;
+ }
+ std::string parcelableDescInParcel;
+ binder_status_t status = AParcel_readString(mParcel.get(), &parcelableDescInParcel);
+ if (status != STATUS_OK || parcelableDesc != parcelableDescInParcel) {
+ return nullptr;
+ }
+ std::unique_ptr<T> ret = std::make_unique<T>();
+ status = ret->readFromParcel(this->mParcel.get());
+ if (status != STATUS_OK) {
+ return nullptr;
+ }
+ return std::move(ret);
+ }
+
+ private:
+ mutable ndk::ScopedAParcel mParcel;
+ parcelable_stability_t mStability;
+};
+
+#undef RETURN_ON_FAILURE
} // namespace ndk
/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index a031e29..93c3f32 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -1120,6 +1120,53 @@
// @END-PRIMITIVE-READ-WRITE
#endif //__ANDROID_API__ >= 29
+#if __ANDROID_API__ >= 31
+/**
+ * Reset the parcel to the initial status.
+ *
+ * Available since API level 31.
+ *
+ * \param parcel The parcel of which to be reset.
+ *
+ * \return STATUS_OK on success.
+ */
+binder_status_t AParcel_reset(AParcel* parcel) __INTRODUCED_IN(31);
+
+/**
+ * Gets the size of the parcel.
+ *
+ * Available since API level 31.
+ *
+ * \param parcel The parcel of which to get the size.
+ *
+ * \return The size of the parcel.
+ */
+int32_t AParcel_getDataSize(const AParcel* parcel) __INTRODUCED_IN(31);
+
+/**
+ * Copy the data of a parcel to other parcel.
+ *
+ * Available since API level 31.
+ *
+ * \param from The source
+ * \param to The detination
+ * \param start The position where the copied data starts.
+ * \param size The amount of data which will be copied.
+ *
+ * \return STATUS_OK on success.
+ */
+binder_status_t AParcel_appendFrom(const AParcel* from, AParcel* to, int32_t start, int32_t size)
+ __INTRODUCED_IN(31);
+
+/**
+ * Creates a parcel.
+ *
+ * Available since API level 31.
+ *
+ * \return A parcel which is not related to any IBinder objects.
+ */
+AParcel* AParcel_create() __INTRODUCED_IN(31);
+#endif //__ANDROID_API__ >= 31
__END_DECLS
/** @} */
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 1701fb5..947cc98 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -120,6 +120,11 @@
AServiceManager_isDeclared; # apex llndk
AServiceManager_registerLazyService; # llndk
AServiceManager_waitForService; # apex llndk
+
+ AParcel_reset;
+ AParcel_getDataSize;
+ AParcel_appendFrom;
+ AParcel_create;
};
LIBBINDER_NDK_PLATFORM {
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index 722ae23..2f95318 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -647,4 +647,22 @@
return parcel->get()->allowFds();
}
+binder_status_t AParcel_reset(AParcel* parcel) {
+ parcel->get()->freeData();
+ return STATUS_OK;
+}
+
+int32_t AParcel_getDataSize(const AParcel* parcel) {
+ return parcel->get()->dataSize();
+}
+
+binder_status_t AParcel_appendFrom(const AParcel* from, AParcel* to, int32_t start, int32_t size) {
+ status_t status = to->get()->appendFrom(from->get(), start, size);
+ return PruneStatusT(status);
+}
+
+AParcel* AParcel_create() {
+ return new AParcel(nullptr);
+}
+
// @END
diff --git a/libs/binder/parcel_fuzzer/Android.bp b/libs/binder/parcel_fuzzer/Android.bp
index 1a67898..c5b3d80 100644
--- a/libs/binder/parcel_fuzzer/Android.bp
+++ b/libs/binder/parcel_fuzzer/Android.bp
@@ -18,6 +18,7 @@
],
static_libs: [
"libbase",
+ "libbinder_random_parcel",
"libcgrouprc",
"libcgrouprc_format",
"libcutils",
@@ -47,3 +48,20 @@
// produced, you may find uncommenting the below line very useful.
// cflags: ["-DENABLE_LOG_FUZZ"],
}
+
+cc_library_static {
+ name: "libbinder_random_parcel",
+ host_supported: true,
+ srcs: [
+ "random_fd.cpp",
+ "random_parcel.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ ],
+ local_include_dirs: ["include_random_parcel"],
+ export_include_dirs: ["include_random_parcel"],
+}
diff --git a/libs/binder/parcel_fuzzer/random_fd.h b/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
similarity index 100%
rename from libs/binder/parcel_fuzzer/random_fd.h
rename to libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
diff --git a/libs/binder/parcel_fuzzer/random_parcel.h b/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
similarity index 88%
rename from libs/binder/parcel_fuzzer/random_parcel.h
rename to libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
index 2923c47..b92a6a9 100644
--- a/libs/binder/parcel_fuzzer/random_parcel.h
+++ b/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
@@ -16,12 +16,9 @@
#pragma once
-#include "binder_ndk.h"
-
#include <binder/Parcel.h>
#include <fuzzer/FuzzedDataProvider.h>
namespace android {
void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider);
-void fillRandomParcel(NdkParcelAdapter* p, FuzzedDataProvider&& provider);
} // namespace android
diff --git a/libs/binder/parcel_fuzzer/main.cpp b/libs/binder/parcel_fuzzer/main.cpp
index 46bf417..386c70b 100644
--- a/libs/binder/parcel_fuzzer/main.cpp
+++ b/libs/binder/parcel_fuzzer/main.cpp
@@ -18,10 +18,10 @@
#include "binder.h"
#include "binder_ndk.h"
#include "hwbinder.h"
-#include "random_parcel.h"
#include "util.h"
#include <android-base/logging.h>
+#include <fuzzbinder/random_parcel.h>
#include <fuzzer/FuzzedDataProvider.h>
#include <cstdlib>
@@ -30,9 +30,14 @@
using android::fillRandomParcel;
void fillRandomParcel(::android::hardware::Parcel* p, FuzzedDataProvider&& provider) {
+ // TODO: functionality to create random parcels for libhwbinder parcels
std::vector<uint8_t> input = provider.ConsumeRemainingBytes<uint8_t>();
p->setData(input.data(), input.size());
}
+static void fillRandomParcel(NdkParcelAdapter* p, FuzzedDataProvider&& provider) {
+ // fill underlying parcel using functions to fill random libbinder parcel
+ fillRandomParcel(p->parcel(), std::move(provider));
+}
template <typename P>
void doFuzz(const char* backend, const std::vector<ParcelRead<P>>& reads,
diff --git a/libs/binder/parcel_fuzzer/random_fd.cpp b/libs/binder/parcel_fuzzer/random_fd.cpp
index eb80ece..cef6adb 100644
--- a/libs/binder/parcel_fuzzer/random_fd.cpp
+++ b/libs/binder/parcel_fuzzer/random_fd.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "random_fd.h"
+#include <fuzzbinder/random_fd.h>
#include <fcntl.h>
diff --git a/libs/binder/parcel_fuzzer/random_parcel.cpp b/libs/binder/parcel_fuzzer/random_parcel.cpp
index 3dae904..9ca4c8a 100644
--- a/libs/binder/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/parcel_fuzzer/random_parcel.cpp
@@ -14,20 +14,15 @@
* limitations under the License.
*/
-#include "random_parcel.h"
-
-#include "random_fd.h"
+#include <fuzzbinder/random_parcel.h>
#include <android-base/logging.h>
#include <binder/IServiceManager.h>
+#include <fuzzbinder/random_fd.h>
#include <utils/String16.h>
namespace android {
-void fillRandomParcel(NdkParcelAdapter* p, FuzzedDataProvider&& provider) {
- fillRandomParcel(p->parcel(), std::move(provider));
-}
-
class NamedBinder : public BBinder {
public:
NamedBinder(const String16& descriptor) : mDescriptor(descriptor) {}
diff --git a/libs/gralloc/types/Android.bp b/libs/gralloc/types/Android.bp
index 66fb295..cc31cd5 100644
--- a/libs/gralloc/types/Android.bp
+++ b/libs/gralloc/types/Android.bp
@@ -38,14 +38,14 @@
],
shared_libs: [
- "android.hardware.graphics.common-ndk_platform",
+ "android.hardware.graphics.common-unstable-ndk_platform",
"android.hardware.graphics.mapper@4.0",
"libhidlbase",
"liblog",
],
export_shared_lib_headers: [
- "android.hardware.graphics.common-ndk_platform",
+ "android.hardware.graphics.common-unstable-ndk_platform",
"android.hardware.graphics.mapper@4.0",
"libhidlbase",
],
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index c3323fe..d6f9e63 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -732,6 +732,8 @@
mSharedBufferHasBeenQueued = false;
}
+ mDequeuedSlots.insert(buf);
+
return OK;
}
@@ -760,6 +762,8 @@
mSharedBufferHasBeenQueued = true;
}
+ mDequeuedSlots.erase(i);
+
return OK;
}
@@ -895,6 +899,8 @@
ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err);
}
+ mDequeuedSlots.erase(i);
+
if (mEnableFrameTimestamps) {
mFrameEventHistory->applyDelta(output.frameTimestamps);
// Update timestamps with the local acquire fence.
@@ -1660,6 +1666,7 @@
mRemovedBuffers.push_back(mSlots[attachedSlot].buffer);
}
mSlots[attachedSlot].buffer = graphicBuffer;
+ mDequeuedSlots.insert(attachedSlot);
return NO_ERROR;
}
@@ -1926,6 +1933,10 @@
}
void Surface::freeAllBuffers() {
+ if (!mDequeuedSlots.empty()) {
+ ALOGE("%s: %zu buffers were freed while being dequeued!",
+ __FUNCTION__, mDequeuedSlots.size());
+ }
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
mSlots[i].buffer = nullptr;
}
@@ -1947,6 +1958,10 @@
ALOGW("%s: Discarded slot %d doesn't contain buffer!", __FUNCTION__, i);
continue;
}
+ // Don't flush currently dequeued buffers
+ if (mDequeuedSlots.count(i) > 0) {
+ continue;
+ }
outBuffers->push_back(mSlots[i].buffer);
mSlots[i].buffer = nullptr;
}
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 49c83da..55b4101 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -30,6 +30,7 @@
#include <utils/RefBase.h>
#include <shared_mutex>
+#include <unordered_set>
namespace android {
@@ -543,8 +544,15 @@
int mMaxBufferCount;
sp<IProducerListener> mListenerProxy;
+
+ // Get and flush the buffers of given slots, if the buffer in the slot
+ // is currently dequeued then it won't be flushed and won't be returned
+ // in outBuffers.
status_t getAndFlushBuffersFromSlots(const std::vector<int32_t>& slots,
std::vector<sp<GraphicBuffer>>* outBuffers);
+
+ // Buffers that are successfully dequeued/attached and handed to clients
+ std::unordered_set<int> mDequeuedSlots;
};
} // namespace android
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 1ee8c71..47eb59f 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -72,7 +72,7 @@
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.allocator@4.0",
- "android.hardware.graphics.common-ndk_platform",
+ "android.hardware.graphics.common-unstable-ndk_platform",
"android.hardware.graphics.common@1.2",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.1",
@@ -89,7 +89,7 @@
export_shared_lib_headers: [
"android.hardware.graphics.common@1.2",
- "android.hardware.graphics.common-ndk_platform",
+ "android.hardware.graphics.common-unstable-ndk_platform",
"android.hardware.graphics.mapper@4.0",
"libgralloctypes",
],
diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java
index 9c80212..59ef3c8 100644
--- a/opengl/tools/glgen/src/JniCodeEmitter.java
+++ b/opengl/tools/glgen/src/JniCodeEmitter.java
@@ -15,6 +15,7 @@
*/
import java.io.PrintStream;
+import java.util.Arrays;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
@@ -201,6 +202,33 @@
out.println(iii + ");");
}
+ // Function to automatically generate properly formatted function calls that
+ // comply with clang format rules
+ public static String formatFunctionCall(String indent, String functionCall) {
+ final int MAXLEN = 100;
+ String tokens[] = functionCall.split("\\(|\\)", 2);
+ String params[] = tokens[1].split(",\\s*");
+ String formatted = indent + tokens[0] + "(";
+ char[] chars = new char[indent.length() + tokens[0].length() + 1];
+ Arrays.fill(chars, ' ');
+ String multiIndent = new String(chars);
+ ArrayList<String> lines = new ArrayList<String>();
+ for(int i = 0; i < params.length; i++) {
+ String terminator = ((i == params.length - 1) ? "" : ",");
+ if(indent.length() + formatted.length() + params[i].length() > MAXLEN) {
+ lines.add(formatted);
+ if (!indent.equals(multiIndent)) {
+ indent = multiIndent;
+ }
+ formatted = indent + params[i] + terminator;
+ } else {
+ formatted += (i == 0 ? "" : " ") + params[i] + terminator;
+ }
+ }
+ lines.add(formatted);
+ return String.join("\n", lines);
+ }
+
void printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck,
String iii) {
printIfcheckPostamble(out, isBuffer, emitExceptionCheck,
@@ -1538,14 +1566,19 @@
"_exception ? JNI_ABORT : 0" : "0")) +
");");
} else {
- out.println(indent + indent +
+ String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" :
+ "_" + cfunc.getArgName(cIndex) + "BufferOffset";
+ String typeCast = "(char *)" + cfunc.getArgName(cIndex);
+ String withOffset = "(void *)(" + typeCast + " - " + bufferOffset + ")";
+ String releasePointerCall = (
"releasePointer(_env, " + array + ", " +
- cfunc.getArgName(cIndex) +
+ withOffset +
", " +
(cfunc.getArgType(cIndex).isConst() ?
"JNI_FALSE" : (emitExceptionCheck ?
"_exception ? JNI_FALSE : JNI_TRUE" : "JNI_TRUE")) +
");");
+ out.println(formatFunctionCall(indent + indent, releasePointerCall));
}
out.println(indent + "}");
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index fe016af..2517060 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -482,6 +482,33 @@
}
/**
+ * Raise ANR if there is no focused window.
+ * Before the ANR is raised, do a final state check:
+ * 1. The currently focused application must be the same one we are waiting for.
+ * 2. Ensure we still don't have a focused window.
+ */
+void InputDispatcher::processNoFocusedWindowAnrLocked() {
+ // Check if the application that we are waiting for is still focused.
+ sp<InputApplicationHandle> focusedApplication =
+ getValueByKey(mFocusedApplicationHandlesByDisplay, mAwaitedApplicationDisplayId);
+ if (focusedApplication == nullptr ||
+ focusedApplication->getApplicationToken() !=
+ mAwaitedFocusedApplication->getApplicationToken()) {
+ // Unexpected because we should have reset the ANR timer when focused application changed
+ ALOGE("Waited for a focused window, but focused application has already changed to %s",
+ focusedApplication->getName().c_str());
+ return; // The focused application has changed.
+ }
+
+ const sp<InputWindowHandle>& focusedWindowHandle =
+ getFocusedWindowHandleLocked(mAwaitedApplicationDisplayId);
+ if (focusedWindowHandle != nullptr) {
+ return; // We now have a focused window. No need for ANR.
+ }
+ onAnrLocked(mAwaitedFocusedApplication);
+}
+
+/**
* Check if any of the connections' wait queues have events that are too old.
* If we waited for events to be ack'ed for more than the window timeout, raise an ANR.
* Return the time at which we should wake up next.
@@ -492,8 +519,9 @@
// Check if we are waiting for a focused window to appear. Raise ANR if waited too long
if (mNoFocusedWindowTimeoutTime.has_value() && mAwaitedFocusedApplication != nullptr) {
if (currentTime >= *mNoFocusedWindowTimeoutTime) {
- onAnrLocked(mAwaitedFocusedApplication);
+ processNoFocusedWindowAnrLocked();
mAwaitedFocusedApplication.clear();
+ mNoFocusedWindowTimeoutTime = std::nullopt;
return LONG_LONG_MIN;
} else {
// Keep waiting
@@ -518,7 +546,7 @@
connection->responsive = false;
// Stop waking up for this unresponsive connection
mAnrTracker.eraseToken(connection->inputChannel->getConnectionToken());
- onAnrLocked(connection);
+ onAnrLocked(*connection);
return LONG_LONG_MIN;
}
@@ -1477,6 +1505,7 @@
DEFAULT_INPUT_DISPATCHING_TIMEOUT.count());
mNoFocusedWindowTimeoutTime = currentTime + timeout;
mAwaitedFocusedApplication = focusedApplicationHandle;
+ mAwaitedApplicationDisplayId = displayId;
ALOGW("Waiting because no window has focus but %s may eventually add a "
"window when it finishes starting up. Will wait for %" PRId64 "ms",
mAwaitedFocusedApplication->getName().c_str(), ns2ms(timeout));
@@ -3567,6 +3596,10 @@
return getValueByKey(mWindowHandlesByDisplay, displayId);
}
+sp<InputWindowHandle> InputDispatcher::getFocusedWindowHandleLocked(int displayId) const {
+ return getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
+}
+
sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked(
const sp<IBinder>& windowHandleToken) const {
if (windowHandleToken == nullptr) {
@@ -4542,12 +4575,12 @@
postCommandLocked(std::move(commandEntry));
}
-void InputDispatcher::onAnrLocked(const sp<Connection>& connection) {
+void InputDispatcher::onAnrLocked(const Connection& connection) {
// Since we are allowing the policy to extend the timeout, maybe the waitQueue
// is already healthy again. Don't raise ANR in this situation
- if (connection->waitQueue.empty()) {
+ if (connection.waitQueue.empty()) {
ALOGI("Not raising ANR because the connection %s has recovered",
- connection->inputChannel->getName().c_str());
+ connection.inputChannel->getName().c_str());
return;
}
/**
@@ -4558,21 +4591,21 @@
* processes the events linearly. So providing information about the oldest entry seems to be
* most useful.
*/
- DispatchEntry* oldestEntry = *connection->waitQueue.begin();
+ DispatchEntry* oldestEntry = *connection.waitQueue.begin();
const nsecs_t currentWait = now() - oldestEntry->deliveryTime;
std::string reason =
android::base::StringPrintf("%s is not responding. Waited %" PRId64 "ms for %s",
- connection->inputChannel->getName().c_str(),
+ connection.inputChannel->getName().c_str(),
ns2ms(currentWait),
oldestEntry->eventEntry->getDescription().c_str());
- updateLastAnrStateLocked(getWindowHandleLocked(connection->inputChannel->getConnectionToken()),
+ updateLastAnrStateLocked(getWindowHandleLocked(connection.inputChannel->getConnectionToken()),
reason);
std::unique_ptr<CommandEntry> commandEntry =
std::make_unique<CommandEntry>(&InputDispatcher::doNotifyAnrLockedInterruptible);
commandEntry->inputApplicationHandle = nullptr;
- commandEntry->inputChannel = connection->inputChannel;
+ commandEntry->inputChannel = connection.inputChannel;
commandEntry->reason = std::move(reason);
postCommandLocked(std::move(commandEntry));
}
@@ -4672,15 +4705,15 @@
void InputDispatcher::extendAnrTimeoutsLocked(const sp<InputApplicationHandle>& application,
const sp<IBinder>& connectionToken,
nsecs_t timeoutExtension) {
+ if (connectionToken == nullptr && application != nullptr) {
+ // The ANR happened because there's no focused window
+ mNoFocusedWindowTimeoutTime = now() + timeoutExtension;
+ mAwaitedFocusedApplication = application;
+ }
+
sp<Connection> connection = getConnectionLocked(connectionToken);
if (connection == nullptr) {
- if (mNoFocusedWindowTimeoutTime.has_value() && application != nullptr) {
- // Maybe ANR happened because there's no focused window?
- mNoFocusedWindowTimeoutTime = now() + timeoutExtension;
- mAwaitedFocusedApplication = application;
- } else {
- // It's also possible that the connection already disappeared. No action necessary.
- }
+ // It's possible that the connection already disappeared. No action necessary.
return;
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index e679c6b..31fad1f 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -300,6 +300,7 @@
REQUIRES(mLock);
sp<InputWindowHandle> getWindowHandleLocked(const sp<IBinder>& windowHandleToken) const
REQUIRES(mLock);
+ sp<InputWindowHandle> getFocusedWindowHandleLocked(int displayId) const REQUIRES(mLock);
sp<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const REQUIRES(mLock);
bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const REQUIRES(mLock);
@@ -366,6 +367,11 @@
* Used to raise an ANR when we have no focused window.
*/
sp<InputApplicationHandle> mAwaitedFocusedApplication GUARDED_BY(mLock);
+ /**
+ * The displayId that the focused application is associated with.
+ */
+ int32_t mAwaitedApplicationDisplayId GUARDED_BY(mLock);
+ void processNoFocusedWindowAnrLocked() REQUIRES(mLock);
// Optimization: AnrTracker is used to quickly find which connection is due for a timeout next.
// AnrTracker must be kept in-sync with all responsive connection.waitQueues.
@@ -489,7 +495,7 @@
REQUIRES(mLock);
void onFocusChangedLocked(const sp<InputWindowHandle>& oldFocus,
const sp<InputWindowHandle>& newFocus) REQUIRES(mLock);
- void onAnrLocked(const sp<Connection>& connection) REQUIRES(mLock);
+ void onAnrLocked(const Connection& connection) REQUIRES(mLock);
void onAnrLocked(const sp<InputApplicationHandle>& application) REQUIRES(mLock);
void updateLastAnrStateLocked(const sp<InputWindowHandle>& window, const std::string& reason)
REQUIRES(mLock);
diff --git a/services/inputflinger/reader/include/TouchVideoDevice.h b/services/inputflinger/reader/include/TouchVideoDevice.h
index 5a32443..7de9b83 100644
--- a/services/inputflinger/reader/include/TouchVideoDevice.h
+++ b/services/inputflinger/reader/include/TouchVideoDevice.h
@@ -102,7 +102,7 @@
* How many buffers to keep for the internal queue. When the internal buffer
* exceeds this capacity, oldest frames will be dropped.
*/
- static constexpr size_t MAX_QUEUE_SIZE = 10;
+ static constexpr size_t MAX_QUEUE_SIZE = 20;
std::vector<TouchVideoFrame> mFrames;
/**
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 1a133dc..668a7ab 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -150,6 +150,7 @@
const std::chrono::duration waited = std::chrono::steady_clock::now() - start;
if (mAnrApplications.empty() || mAnrWindowTokens.empty()) {
ADD_FAILURE() << "Did not receive ANR callback";
+ return {};
}
// Ensure that the ANR didn't get raised too early. We can't be too strict here because
// the dispatcher started counting before this function was called
@@ -3031,4 +3032,64 @@
mFocusedWindow->assertNoEvents();
}
+/**
+ * If we have no focused window, and a key comes in, we start the ANR timer.
+ * The focused application should add a focused window before the timer runs out to prevent ANR.
+ *
+ * If the user touches another application during this time, the key should be dropped.
+ * Next, if a new focused window comes in, without toggling the focused application,
+ * then no ANR should occur.
+ *
+ * Normally, we would expect the new focused window to be accompanied by 'setFocusedApplication',
+ * but in some cases the policy may not update the focused application.
+ */
+TEST_F(InputDispatcherMultiWindowAnr, FocusedWindowWithoutSetFocusedApplication_NoAnr) {
+ sp<FakeApplicationHandle> focusedApplication = new FakeApplicationHandle();
+ focusedApplication->setDispatchingTimeout(60ms);
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, focusedApplication);
+ // The application that owns 'mFocusedWindow' and 'mUnfocusedWindow' is not focused.
+ mFocusedWindow->setFocus(false);
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mFocusedWindow, mUnfocusedWindow}}});
+ mFocusedWindow->consumeFocusEvent(false);
+
+ // Send a key. The ANR timer should start because there is no focused window.
+ // 'focusedApplication' will get blamed if this timer completes.
+ // Key will not be sent anywhere because we have no focused window. It will remain pending.
+ int32_t result =
+ injectKey(mDispatcher, AKEY_EVENT_ACTION_DOWN, 0 /*repeatCount*/, ADISPLAY_ID_DEFAULT,
+ INPUT_EVENT_INJECTION_SYNC_NONE, 10ms /*injectionTimeout*/);
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, result);
+
+ // Wait until dispatcher starts the "no focused window" timer. If we don't wait here,
+ // then the injected touches won't cause the focused event to get dropped.
+ // The dispatcher only checks for whether the queue should be pruned upon queueing.
+ // If we inject the touch right away and the ANR timer hasn't started, the touch event would
+ // simply be added to the queue without 'shouldPruneInboundQueueLocked' returning 'true'.
+ // For this test, it means that the key would get delivered to the window once it becomes
+ // focused.
+ std::this_thread::sleep_for(10ms);
+
+ // Touch unfocused window. This should force the pending key to get dropped.
+ NotifyMotionArgs motionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {UNFOCUSED_WINDOW_LOCATION});
+ mDispatcher->notifyMotion(&motionArgs);
+
+ // We do not consume the motion right away, because that would require dispatcher to first
+ // process (== drop) the key event, and by that time, ANR will be raised.
+ // Set the focused window first.
+ mFocusedWindow->setFocus(true);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mFocusedWindow, mUnfocusedWindow}}});
+ mFocusedWindow->consumeFocusEvent(true);
+ // We do not call "setFocusedApplication" here, even though the newly focused window belongs
+ // to another application. This could be a bug / behaviour in the policy.
+
+ mUnfocusedWindow->consumeMotionDown();
+
+ ASSERT_TRUE(mDispatcher->waitForIdle());
+ // Should not ANR because we actually have a focused window. It was just added too slowly.
+ ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyAnrWasNotCalled());
+}
+
} // namespace android::inputdispatcher
diff --git a/services/surfaceflinger/Scheduler/TimeKeeper.h b/services/surfaceflinger/Scheduler/TimeKeeper.h
index da2195c..40dd841 100644
--- a/services/surfaceflinger/Scheduler/TimeKeeper.h
+++ b/services/surfaceflinger/Scheduler/TimeKeeper.h
@@ -43,10 +43,10 @@
virtual ~TimeKeeper();
/*
- * Arms callback to fired in time nanoseconds.
+ * Arms callback to fired when time is current based on CLOCK_MONOTONIC
* There is only one timer, and subsequent calls will reset the callback function and the time.
*/
- virtual void alarmIn(std::function<void()> const& callback, nsecs_t time) = 0;
+ virtual void alarmAt(std::function<void()> const& callback, nsecs_t time) = 0;
/*
* Cancels an existing pending callback
diff --git a/services/surfaceflinger/Scheduler/Timer.cpp b/services/surfaceflinger/Scheduler/Timer.cpp
index 7c5058e..59c336a 100644
--- a/services/surfaceflinger/Scheduler/Timer.cpp
+++ b/services/surfaceflinger/Scheduler/Timer.cpp
@@ -88,7 +88,7 @@
return systemTime(SYSTEM_TIME_MONOTONIC);
}
-void Timer::alarmIn(std::function<void()> const& cb, nsecs_t fireIn) {
+void Timer::alarmAt(std::function<void()> const& cb, nsecs_t time) {
std::lock_guard<decltype(mMutex)> lk(mMutex);
using namespace std::literals;
static constexpr int ns_per_s =
@@ -99,11 +99,11 @@
struct itimerspec old_timer;
struct itimerspec new_timer {
.it_interval = {.tv_sec = 0, .tv_nsec = 0},
- .it_value = {.tv_sec = static_cast<long>(fireIn / ns_per_s),
- .tv_nsec = static_cast<long>(fireIn % ns_per_s)},
+ .it_value = {.tv_sec = static_cast<long>(time / ns_per_s),
+ .tv_nsec = static_cast<long>(time % ns_per_s)},
};
- if (timerfd_settime(mTimerFd, 0, &new_timer, &old_timer)) {
+ if (timerfd_settime(mTimerFd, TFD_TIMER_ABSTIME, &new_timer, &old_timer)) {
ALOGW("Failed to set timerfd %s (%i)", strerror(errno), errno);
}
}
diff --git a/services/surfaceflinger/Scheduler/Timer.h b/services/surfaceflinger/Scheduler/Timer.h
index a8e2d5a..69ce079 100644
--- a/services/surfaceflinger/Scheduler/Timer.h
+++ b/services/surfaceflinger/Scheduler/Timer.h
@@ -30,9 +30,9 @@
~Timer();
nsecs_t now() const final;
- // NB: alarmIn and alarmCancel are threadsafe; with the last-returning function being effectual
+ // NB: alarmAt and alarmCancel are threadsafe; with the last-returning function being effectual
// Most users will want to serialize thes calls so as to be aware of the timer state.
- void alarmIn(std::function<void()> const& cb, nsecs_t fireIn) final;
+ void alarmAt(std::function<void()> const& cb, nsecs_t time) final;
void alarmCancel() final;
void dump(std::string& result) const final;
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
index a596bce..ef92680 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp
@@ -180,10 +180,10 @@
mTimeKeeper->alarmCancel();
}
-void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t now) {
+void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t /*now*/) {
mIntendedWakeupTime = targetTime;
- mTimeKeeper->alarmIn(std::bind(&VSyncDispatchTimerQueue::timerCallback, this),
- targetTime - now);
+ mTimeKeeper->alarmAt(std::bind(&VSyncDispatchTimerQueue::timerCallback, this),
+ mIntendedWakeupTime);
mLastTimerSchedule = mTimeKeeper->now();
}
@@ -243,7 +243,8 @@
std::vector<Invocation> invocations;
{
std::lock_guard<decltype(mMutex)> lk(mMutex);
- mLastTimerCallback = mTimeKeeper->now();
+ auto const now = mTimeKeeper->now();
+ mLastTimerCallback = now;
for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
auto& callback = it->second;
auto const wakeupTime = callback->wakeupTime();
@@ -251,7 +252,8 @@
continue;
}
- if (*wakeupTime < mIntendedWakeupTime + mTimerSlack) {
+ auto const lagAllowance = std::max(now - mIntendedWakeupTime, static_cast<nsecs_t>(0));
+ if (*wakeupTime < mIntendedWakeupTime + mTimerSlack + lagAllowance) {
callback->executing();
invocations.emplace_back(
Invocation{callback, *callback->lastExecutedVsyncTarget(), *wakeupTime});
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 1342cfc..9d65f2f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2122,7 +2122,8 @@
mTimeStats->incrementCompositionStrategyChanges();
}
- mVSyncModulator->onRefreshed(mHadClientComposition);
+ // TODO: b/160583065 Enable skip validation when SF caches all client composition layers
+ mVSyncModulator->onRefreshed(mHadClientComposition || mReusedClientComposition);
mLayersWithQueuedFrames.clear();
if (mVisibleRegionsDirty) {
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index fe2af80..1532855 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -44,7 +44,7 @@
"libtrace_proto",
],
shared_libs: [
- "android.hardware.graphics.common-ndk_platform",
+ "android.hardware.graphics.common-unstable-ndk_platform",
"android.hardware.graphics.common@1.2",
"android.hardware.graphics.composer@2.1",
"libandroid",
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 3c4a791..1bbc3f8 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -58,6 +58,7 @@
"RegionSamplingTest.cpp",
"TimeStatsTest.cpp",
"FrameTracerTest.cpp",
+ "TimerTest.cpp",
"TransactionApplicationTest.cpp",
"StrongTypingTest.cpp",
"VSyncDispatchTimerQueueTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/TimerTest.cpp b/services/surfaceflinger/tests/unittests/TimerTest.cpp
new file mode 100644
index 0000000..cda6bbf
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/TimerTest.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2020 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 "AsyncCallRecorder.h"
+#include "Scheduler/TimeKeeper.h"
+#include "Scheduler/Timer.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using namespace testing;
+using namespace std::literals;
+
+namespace android::scheduler {
+
+struct TimerTest : testing::Test {
+ static constexpr int mIterations = 20;
+
+ AsyncCallRecorder<void (*)()> mCallbackRecorder;
+ Timer mTimer;
+
+ void timerCallback() { mCallbackRecorder.recordCall(); }
+};
+
+TEST_F(TimerTest, callsCallbackIfScheduledInPast) {
+ for (int i = 0; i < mIterations; i++) {
+ mTimer.alarmAt(std::bind(&TimerTest::timerCallback, this), systemTime() - 10'000'00);
+ EXPECT_TRUE(mCallbackRecorder.waitForCall().has_value());
+ EXPECT_FALSE(mCallbackRecorder.waitForUnexpectedCall().has_value());
+ }
+}
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
index d940dc5..fa5cc32 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -63,19 +63,19 @@
class ControllableClock : public TimeKeeper {
public:
ControllableClock() {
- ON_CALL(*this, alarmIn(_, _))
- .WillByDefault(Invoke(this, &ControllableClock::alarmInDefaultBehavior));
+ ON_CALL(*this, alarmAt(_, _))
+ .WillByDefault(Invoke(this, &ControllableClock::alarmAtDefaultBehavior));
ON_CALL(*this, now()).WillByDefault(Invoke(this, &ControllableClock::fakeTime));
}
MOCK_CONST_METHOD0(now, nsecs_t());
- MOCK_METHOD2(alarmIn, void(std::function<void()> const&, nsecs_t time));
+ MOCK_METHOD2(alarmAt, void(std::function<void()> const&, nsecs_t time));
MOCK_METHOD0(alarmCancel, void());
MOCK_CONST_METHOD1(dump, void(std::string&));
- void alarmInDefaultBehavior(std::function<void()> const& callback, nsecs_t time) {
+ void alarmAtDefaultBehavior(std::function<void()> const& callback, nsecs_t time) {
mCallback = callback;
- mNextCallbackTime = time + mCurrentTime;
+ mNextCallbackTime = time;
}
nsecs_t fakeTime() const { return mCurrentTime; }
@@ -115,11 +115,15 @@
operator VSyncDispatch::CallbackToken() const { return mToken; }
- void counter(nsecs_t time, nsecs_t) { mCalls.push_back(time); }
+ void counter(nsecs_t time, nsecs_t wakeup_time) {
+ mCalls.push_back(time);
+ mWakeupTime.push_back(wakeup_time);
+ }
VSyncDispatch& mDispatch;
VSyncDispatch::CallbackToken mToken;
std::vector<nsecs_t> mCalls;
+ std::vector<nsecs_t> mWakeupTime;
};
class PausingCallback {
@@ -187,8 +191,8 @@
class TimeKeeperWrapper : public TimeKeeper {
public:
TimeKeeperWrapper(TimeKeeper& control) : mControllableClock(control) {}
- void alarmIn(std::function<void()> const& callback, nsecs_t time) final {
- mControllableClock.alarmIn(callback, time);
+ void alarmAt(std::function<void()> const& callback, nsecs_t time) final {
+ mControllableClock.alarmAt(callback, time);
}
void alarmCancel() final { mControllableClock.alarmCancel(); }
nsecs_t now() const final { return mControllableClock.now(); }
@@ -217,7 +221,7 @@
};
TEST_F(VSyncDispatchTimerQueueTest, unregistersSetAlarmOnDestruction) {
- EXPECT_CALL(mMockClock, alarmIn(_, 900));
+ EXPECT_CALL(mMockClock, alarmAt(_, 900));
EXPECT_CALL(mMockClock, alarmCancel());
{
VSyncDispatchTimerQueue mDispatch{createTimeKeeper(), mStubTracker, mDispatchGroupThreshold,
@@ -229,7 +233,7 @@
TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingFuture) {
auto intended = mPeriod - 230;
- EXPECT_CALL(mMockClock, alarmIn(_, 900));
+ EXPECT_CALL(mMockClock, alarmAt(_, 900));
CountingCallback cb(mDispatch);
EXPECT_EQ(mDispatch.schedule(cb, 100, intended), ScheduleResult::Scheduled);
@@ -241,7 +245,7 @@
TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingFutureWithAdjustmentToTrueVsync) {
EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000)).WillOnce(Return(1150));
- EXPECT_CALL(mMockClock, alarmIn(_, 1050));
+ EXPECT_CALL(mMockClock, alarmAt(_, 1050));
CountingCallback cb(mDispatch);
mDispatch.schedule(cb, 100, mPeriod);
@@ -257,14 +261,14 @@
auto const workDuration = 10 * mPeriod;
EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(now + workDuration))
.WillOnce(Return(mPeriod * 11));
- EXPECT_CALL(mMockClock, alarmIn(_, mPeriod - now));
+ EXPECT_CALL(mMockClock, alarmAt(_, mPeriod));
CountingCallback cb(mDispatch);
EXPECT_EQ(mDispatch.schedule(cb, workDuration, mPeriod), ScheduleResult::Scheduled);
}
TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancel) {
- EXPECT_CALL(mMockClock, alarmIn(_, 900));
+ EXPECT_CALL(mMockClock, alarmAt(_, 900));
EXPECT_CALL(mMockClock, alarmCancel());
CountingCallback cb(mDispatch);
@@ -273,7 +277,7 @@
}
TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancelTooLate) {
- EXPECT_CALL(mMockClock, alarmIn(_, 900));
+ EXPECT_CALL(mMockClock, alarmAt(_, 900));
EXPECT_CALL(mMockClock, alarmCancel());
CountingCallback cb(mDispatch);
@@ -283,7 +287,7 @@
}
TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancelTooLateWhenRunning) {
- EXPECT_CALL(mMockClock, alarmIn(_, 900));
+ EXPECT_CALL(mMockClock, alarmAt(_, 900));
EXPECT_CALL(mMockClock, alarmCancel());
PausingCallback cb(mDispatch, std::chrono::duration_cast<std::chrono::milliseconds>(1s));
@@ -297,7 +301,7 @@
}
TEST_F(VSyncDispatchTimerQueueTest, unregisterSynchronizes) {
- EXPECT_CALL(mMockClock, alarmIn(_, 900));
+ EXPECT_CALL(mMockClock, alarmAt(_, 900));
EXPECT_CALL(mMockClock, alarmCancel());
auto resource = std::make_shared<int>(110);
@@ -327,9 +331,9 @@
.WillOnce(Return(1075));
Sequence seq;
- EXPECT_CALL(mMockClock, alarmIn(_, 955)).InSequence(seq);
- EXPECT_CALL(mMockClock, alarmIn(_, 813)).InSequence(seq);
- EXPECT_CALL(mMockClock, alarmIn(_, 162)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 955)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 813)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 975)).InSequence(seq);
CountingCallback cb0(mDispatch);
CountingCallback cb1(mDispatch);
@@ -355,9 +359,9 @@
.WillOnce(Return(10000));
Sequence seq;
- EXPECT_CALL(mMockClock, alarmIn(_, 9900)).InSequence(seq);
- EXPECT_CALL(mMockClock, alarmIn(_, 750)).InSequence(seq);
- EXPECT_CALL(mMockClock, alarmIn(_, 9900)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 9900)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 750)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 9900)).InSequence(seq);
CountingCallback cb0(mDispatch);
CountingCallback cb1(mDispatch);
@@ -369,8 +373,8 @@
TEST_F(VSyncDispatchTimerQueueTest, noUnnecessaryRearmsWhenRescheduling) {
Sequence seq;
- EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
- EXPECT_CALL(mMockClock, alarmIn(_, 100)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 700)).InSequence(seq);
CountingCallback cb0(mDispatch);
CountingCallback cb1(mDispatch);
@@ -383,9 +387,9 @@
TEST_F(VSyncDispatchTimerQueueTest, necessaryRearmsWhenModifying) {
Sequence seq;
- EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
- EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
- EXPECT_CALL(mMockClock, alarmIn(_, 100)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 500)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
CountingCallback cb0(mDispatch);
CountingCallback cb1(mDispatch);
@@ -398,10 +402,10 @@
TEST_F(VSyncDispatchTimerQueueTest, modifyIntoGroup) {
Sequence seq;
- EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
- EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
- EXPECT_CALL(mMockClock, alarmIn(_, 990)).InSequence(seq);
- EXPECT_CALL(mMockClock, alarmIn(_, 10)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 1600)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 1590)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 1600)).InSequence(seq);
auto offset = 400;
auto closeOffset = offset + mDispatchGroupThreshold - 1;
@@ -432,9 +436,10 @@
}
TEST_F(VSyncDispatchTimerQueueTest, rearmsWhenEndingAndDoesntCancel) {
- EXPECT_CALL(mMockClock, alarmIn(_, 900));
- EXPECT_CALL(mMockClock, alarmIn(_, 800));
- EXPECT_CALL(mMockClock, alarmIn(_, 100));
+ Sequence seq;
+ EXPECT_CALL(mMockClock, alarmAt(_, 900)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 800)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 900)).InSequence(seq);
EXPECT_CALL(mMockClock, alarmCancel());
CountingCallback cb0(mDispatch);
@@ -472,8 +477,8 @@
TEST_F(VSyncDispatchTimerQueueTest, callbackReentrancy) {
Sequence seq;
- EXPECT_CALL(mMockClock, alarmIn(_, 900)).InSequence(seq);
- EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 900)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 1900)).InSequence(seq);
VSyncDispatch::CallbackToken tmp;
tmp = mDispatch.registerCallback([&](auto, auto) { mDispatch.schedule(tmp, 100, 2000); },
@@ -507,10 +512,10 @@
TEST_F(VSyncDispatchTimerQueueTest, modificationsAroundVsyncTime) {
Sequence seq;
- EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
- EXPECT_CALL(mMockClock, alarmIn(_, 200)).InSequence(seq);
- EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
- EXPECT_CALL(mMockClock, alarmIn(_, 150)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 1000)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 950)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 1950)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 1900)).InSequence(seq);
CountingCallback cb(mDispatch);
mDispatch.schedule(cb, 0, 1000);
@@ -527,10 +532,10 @@
TEST_F(VSyncDispatchTimerQueueTest, lateModifications) {
Sequence seq;
- EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
- EXPECT_CALL(mMockClock, alarmIn(_, 400)).InSequence(seq);
- EXPECT_CALL(mMockClock, alarmIn(_, 350)).InSequence(seq);
- EXPECT_CALL(mMockClock, alarmIn(_, 950)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 500)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 900)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 850)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 1800)).InSequence(seq);
CountingCallback cb0(mDispatch);
CountingCallback cb1(mDispatch);
@@ -548,7 +553,7 @@
TEST_F(VSyncDispatchTimerQueueTest, doesntCancelPriorValidTimerForFutureMod) {
Sequence seq;
- EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 500)).InSequence(seq);
CountingCallback cb0(mDispatch);
CountingCallback cb1(mDispatch);
@@ -558,9 +563,9 @@
TEST_F(VSyncDispatchTimerQueueTest, setsTimerAfterCancellation) {
Sequence seq;
- EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 500)).InSequence(seq);
EXPECT_CALL(mMockClock, alarmCancel()).InSequence(seq);
- EXPECT_CALL(mMockClock, alarmIn(_, 900)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 900)).InSequence(seq);
CountingCallback cb0(mDispatch);
mDispatch.schedule(cb0, 500, 1000);
@@ -582,7 +587,7 @@
// b/1450138150
TEST_F(VSyncDispatchTimerQueueTest, doesNotMoveCallbackBackwardsAndSkipAScheduledTargetVSync) {
- EXPECT_CALL(mMockClock, alarmIn(_, 500));
+ EXPECT_CALL(mMockClock, alarmAt(_, 500));
CountingCallback cb(mDispatch);
EXPECT_EQ(mDispatch.schedule(cb, 500, 1000), ScheduleResult::Scheduled);
mMockClock.advanceBy(400);
@@ -612,8 +617,8 @@
TEST_F(VSyncDispatchTimerQueueTest, canScheduleLargeNegativeOffset) {
Sequence seq;
- EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
- EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 500)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 1100)).InSequence(seq);
CountingCallback cb0(mDispatch);
EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled);
advanceToNextCallback();
@@ -621,7 +626,7 @@
}
TEST_F(VSyncDispatchTimerQueueTest, scheduleUpdatesDoesNotAffectSchedulingState) {
- EXPECT_CALL(mMockClock, alarmIn(_, 600));
+ EXPECT_CALL(mMockClock, alarmAt(_, 600));
CountingCallback cb(mDispatch);
EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled);
@@ -632,7 +637,7 @@
}
TEST_F(VSyncDispatchTimerQueueTest, helperMove) {
- EXPECT_CALL(mMockClock, alarmIn(_, 500)).Times(1);
+ EXPECT_CALL(mMockClock, alarmAt(_, 500)).Times(1);
EXPECT_CALL(mMockClock, alarmCancel()).Times(1);
VSyncCallbackRegistration cb(
@@ -646,7 +651,7 @@
}
TEST_F(VSyncDispatchTimerQueueTest, helperMoveAssign) {
- EXPECT_CALL(mMockClock, alarmIn(_, 500)).Times(1);
+ EXPECT_CALL(mMockClock, alarmAt(_, 500)).Times(1);
EXPECT_CALL(mMockClock, alarmCancel()).Times(1);
VSyncCallbackRegistration cb(
@@ -664,8 +669,8 @@
// b/154303580
TEST_F(VSyncDispatchTimerQueueTest, skipsSchedulingIfTimerReschedulingIsImminent) {
Sequence seq;
- EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
- EXPECT_CALL(mMockClock, alarmIn(_, 1200)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 1900)).InSequence(seq);
CountingCallback cb1(mDispatch);
CountingCallback cb2(mDispatch);
@@ -686,8 +691,8 @@
// update later, as opposed to blocking the calling thread.
TEST_F(VSyncDispatchTimerQueueTest, skipsSchedulingIfTimerReschedulingIsImminentSameCallback) {
Sequence seq;
- EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
- EXPECT_CALL(mMockClock, alarmIn(_, 930)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 1630)).InSequence(seq);
CountingCallback cb(mDispatch);
EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled);
@@ -704,7 +709,7 @@
// b/154303580.
TEST_F(VSyncDispatchTimerQueueTest, skipsRearmingWhenNotNextScheduled) {
Sequence seq;
- EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
EXPECT_CALL(mMockClock, alarmCancel()).InSequence(seq);
CountingCallback cb1(mDispatch);
CountingCallback cb2(mDispatch);
@@ -725,8 +730,8 @@
TEST_F(VSyncDispatchTimerQueueTest, rearmsWhenCancelledAndIsNextScheduled) {
Sequence seq;
- EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
- EXPECT_CALL(mMockClock, alarmIn(_, 1280)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmAt(_, 1900)).InSequence(seq);
EXPECT_CALL(mMockClock, alarmCancel()).InSequence(seq);
CountingCallback cb1(mDispatch);
CountingCallback cb2(mDispatch);
@@ -747,6 +752,31 @@
EXPECT_THAT(cb2.mCalls.size(), Eq(1));
}
+TEST_F(VSyncDispatchTimerQueueTest, laggedTimerGroupsCallbacksWithinLag) {
+ CountingCallback cb1(mDispatch);
+ CountingCallback cb2(mDispatch);
+
+ Sequence seq;
+ EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000))
+ .InSequence(seq)
+ .WillOnce(Return(1000));
+ EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
+ EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000))
+ .InSequence(seq)
+ .WillOnce(Return(1000));
+
+ EXPECT_EQ(mDispatch.schedule(cb1, 400, 1000), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb2, 390, 1000), ScheduleResult::Scheduled);
+
+ mMockClock.setLag(100);
+ mMockClock.advanceBy(700);
+
+ ASSERT_THAT(cb1.mWakeupTime.size(), Eq(1));
+ EXPECT_THAT(cb1.mWakeupTime[0], Eq(600));
+ ASSERT_THAT(cb2.mWakeupTime.size(), Eq(1));
+ EXPECT_THAT(cb2.mWakeupTime[0], Eq(610));
+}
+
class VSyncDispatchTimerQueueEntryTest : public testing::Test {
protected:
nsecs_t const mPeriod = 1000;
diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp
index d9a9427..26052fb 100644
--- a/vulkan/libvulkan/api_gen.cpp
+++ b/vulkan/libvulkan/api_gen.cpp
@@ -226,6 +226,7 @@
INIT_PROC(true, dev, CreateQueryPool);
INIT_PROC(true, dev, DestroyQueryPool);
INIT_PROC(true, dev, GetQueryPoolResults);
+ INIT_PROC(false, dev, ResetQueryPool);
INIT_PROC(true, dev, CreateBuffer);
INIT_PROC(true, dev, DestroyBuffer);
INIT_PROC(true, dev, CreateBufferView);
@@ -337,8 +338,20 @@
INIT_PROC(false, dev, DestroySamplerYcbcrConversion);
INIT_PROC(false, dev, GetDeviceQueue2);
INIT_PROC(false, dev, GetDescriptorSetLayoutSupport);
+ INIT_PROC(false, dev, CreateRenderPass2);
+ INIT_PROC(false, dev, CmdBeginRenderPass2);
+ INIT_PROC(false, dev, CmdNextSubpass2);
+ INIT_PROC(false, dev, CmdEndRenderPass2);
+ INIT_PROC(false, dev, GetSemaphoreCounterValue);
+ INIT_PROC(false, dev, WaitSemaphores);
+ INIT_PROC(false, dev, SignalSemaphore);
INIT_PROC_EXT(ANDROID_external_memory_android_hardware_buffer, true, dev, GetAndroidHardwareBufferPropertiesANDROID);
INIT_PROC_EXT(ANDROID_external_memory_android_hardware_buffer, true, dev, GetMemoryAndroidHardwareBufferANDROID);
+ INIT_PROC(false, dev, CmdDrawIndirectCount);
+ INIT_PROC(false, dev, CmdDrawIndexedIndirectCount);
+ INIT_PROC(false, dev, GetBufferOpaqueCaptureAddress);
+ INIT_PROC(false, dev, GetBufferDeviceAddress);
+ INIT_PROC(false, dev, GetDeviceMemoryOpaqueCaptureAddress);
// clang-format on
return success;
@@ -391,6 +404,7 @@
VKAPI_ATTR VkResult CreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool);
VKAPI_ATTR void DestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator);
VKAPI_ATTR VkResult GetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags);
+VKAPI_ATTR void ResetQueryPool(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount);
VKAPI_ATTR VkResult CreateBuffer(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer);
VKAPI_ATTR void DestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator);
VKAPI_ATTR VkResult CreateBufferView(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView);
@@ -520,8 +534,20 @@
VKAPI_ATTR void DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator);
VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue);
VKAPI_ATTR void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport);
+VKAPI_ATTR VkResult CreateRenderPass2(VkDevice device, const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass);
+VKAPI_ATTR void CmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfo* pSubpassBeginInfo);
+VKAPI_ATTR void CmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo* pSubpassBeginInfo, const VkSubpassEndInfo* pSubpassEndInfo);
+VKAPI_ATTR void CmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpassEndInfo* pSubpassEndInfo);
+VKAPI_ATTR VkResult GetSemaphoreCounterValue(VkDevice device, VkSemaphore semaphore, uint64_t* pValue);
+VKAPI_ATTR VkResult WaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout);
+VKAPI_ATTR VkResult SignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo);
VKAPI_ATTR VkResult GetAndroidHardwareBufferPropertiesANDROID(VkDevice device, const struct AHardwareBuffer* buffer, VkAndroidHardwareBufferPropertiesANDROID* pProperties);
VKAPI_ATTR VkResult GetMemoryAndroidHardwareBufferANDROID(VkDevice device, const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo, struct AHardwareBuffer** pBuffer);
+VKAPI_ATTR void CmdDrawIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);
+VKAPI_ATTR void CmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);
+VKAPI_ATTR uint64_t GetBufferOpaqueCaptureAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo);
+VKAPI_ATTR VkDeviceAddress GetBufferDeviceAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo);
+VKAPI_ATTR uint64_t GetDeviceMemoryOpaqueCaptureAddress(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo);
VKAPI_ATTR VkResult EnumeratePhysicalDevices(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices) {
return GetData(instance).dispatch.EnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices);
@@ -551,6 +577,7 @@
"vkEnumerateInstanceVersion",
"vkEnumeratePhysicalDeviceGroups",
"vkEnumeratePhysicalDeviceGroupsKHR",
+ "vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR",
"vkEnumeratePhysicalDevices",
"vkGetDisplayModeProperties2KHR",
"vkGetDisplayPlaneCapabilities2KHR",
@@ -571,7 +598,7 @@
"vkGetPhysicalDeviceFormatProperties",
"vkGetPhysicalDeviceFormatProperties2",
"vkGetPhysicalDeviceFormatProperties2KHR",
- "vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX",
+ "vkGetPhysicalDeviceFragmentShadingRatesKHR",
"vkGetPhysicalDeviceImageFormatProperties",
"vkGetPhysicalDeviceImageFormatProperties2",
"vkGetPhysicalDeviceImageFormatProperties2KHR",
@@ -583,6 +610,7 @@
"vkGetPhysicalDeviceProperties",
"vkGetPhysicalDeviceProperties2",
"vkGetPhysicalDeviceProperties2KHR",
+ "vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR",
"vkGetPhysicalDeviceQueueFamilyProperties",
"vkGetPhysicalDeviceQueueFamilyProperties2",
"vkGetPhysicalDeviceQueueFamilyProperties2KHR",
@@ -595,6 +623,7 @@
"vkGetPhysicalDeviceSurfaceFormatsKHR",
"vkGetPhysicalDeviceSurfacePresentModesKHR",
"vkGetPhysicalDeviceSurfaceSupportKHR",
+ "vkGetPhysicalDeviceToolPropertiesEXT",
"vkSubmitDebugUtilsMessageEXT",
};
// clang-format on
@@ -646,6 +675,7 @@
{ "vkBindImageMemory2", reinterpret_cast<PFN_vkVoidFunction>(BindImageMemory2) },
{ "vkCmdBeginQuery", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginQuery) },
{ "vkCmdBeginRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginRenderPass) },
+ { "vkCmdBeginRenderPass2", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginRenderPass2) },
{ "vkCmdBindDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(CmdBindDescriptorSets) },
{ "vkCmdBindIndexBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdBindIndexBuffer) },
{ "vkCmdBindPipeline", reinterpret_cast<PFN_vkVoidFunction>(CmdBindPipeline) },
@@ -665,12 +695,16 @@
{ "vkCmdDraw", reinterpret_cast<PFN_vkVoidFunction>(CmdDraw) },
{ "vkCmdDrawIndexed", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexed) },
{ "vkCmdDrawIndexedIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexedIndirect) },
+ { "vkCmdDrawIndexedIndirectCount", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexedIndirectCount) },
{ "vkCmdDrawIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndirect) },
+ { "vkCmdDrawIndirectCount", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndirectCount) },
{ "vkCmdEndQuery", reinterpret_cast<PFN_vkVoidFunction>(CmdEndQuery) },
{ "vkCmdEndRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CmdEndRenderPass) },
+ { "vkCmdEndRenderPass2", reinterpret_cast<PFN_vkVoidFunction>(CmdEndRenderPass2) },
{ "vkCmdExecuteCommands", reinterpret_cast<PFN_vkVoidFunction>(CmdExecuteCommands) },
{ "vkCmdFillBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdFillBuffer) },
{ "vkCmdNextSubpass", reinterpret_cast<PFN_vkVoidFunction>(CmdNextSubpass) },
+ { "vkCmdNextSubpass2", reinterpret_cast<PFN_vkVoidFunction>(CmdNextSubpass2) },
{ "vkCmdPipelineBarrier", reinterpret_cast<PFN_vkVoidFunction>(CmdPipelineBarrier) },
{ "vkCmdPushConstants", reinterpret_cast<PFN_vkVoidFunction>(CmdPushConstants) },
{ "vkCmdResetEvent", reinterpret_cast<PFN_vkVoidFunction>(CmdResetEvent) },
@@ -709,6 +743,7 @@
{ "vkCreatePipelineLayout", reinterpret_cast<PFN_vkVoidFunction>(CreatePipelineLayout) },
{ "vkCreateQueryPool", reinterpret_cast<PFN_vkVoidFunction>(CreateQueryPool) },
{ "vkCreateRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CreateRenderPass) },
+ { "vkCreateRenderPass2", reinterpret_cast<PFN_vkVoidFunction>(CreateRenderPass2) },
{ "vkCreateSampler", reinterpret_cast<PFN_vkVoidFunction>(CreateSampler) },
{ "vkCreateSamplerYcbcrConversion", reinterpret_cast<PFN_vkVoidFunction>(CreateSamplerYcbcrConversion) },
{ "vkCreateSemaphore", reinterpret_cast<PFN_vkVoidFunction>(CreateSemaphore) },
@@ -749,13 +784,16 @@
{ "vkFreeDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(FreeDescriptorSets) },
{ "vkFreeMemory", reinterpret_cast<PFN_vkVoidFunction>(FreeMemory) },
{ "vkGetAndroidHardwareBufferPropertiesANDROID", reinterpret_cast<PFN_vkVoidFunction>(GetAndroidHardwareBufferPropertiesANDROID) },
+ { "vkGetBufferDeviceAddress", reinterpret_cast<PFN_vkVoidFunction>(GetBufferDeviceAddress) },
{ "vkGetBufferMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(GetBufferMemoryRequirements) },
{ "vkGetBufferMemoryRequirements2", reinterpret_cast<PFN_vkVoidFunction>(GetBufferMemoryRequirements2) },
+ { "vkGetBufferOpaqueCaptureAddress", reinterpret_cast<PFN_vkVoidFunction>(GetBufferOpaqueCaptureAddress) },
{ "vkGetDescriptorSetLayoutSupport", reinterpret_cast<PFN_vkVoidFunction>(GetDescriptorSetLayoutSupport) },
{ "vkGetDeviceGroupPeerMemoryFeatures", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceGroupPeerMemoryFeatures) },
{ "vkGetDeviceGroupPresentCapabilitiesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceGroupPresentCapabilitiesKHR) },
{ "vkGetDeviceGroupSurfacePresentModesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceGroupSurfacePresentModesKHR) },
{ "vkGetDeviceMemoryCommitment", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceMemoryCommitment) },
+ { "vkGetDeviceMemoryOpaqueCaptureAddress", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceMemoryOpaqueCaptureAddress) },
{ "vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr) },
{ "vkGetDeviceQueue", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue) },
{ "vkGetDeviceQueue2", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue2) },
@@ -771,6 +809,7 @@
{ "vkGetPipelineCacheData", reinterpret_cast<PFN_vkVoidFunction>(GetPipelineCacheData) },
{ "vkGetQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(GetQueryPoolResults) },
{ "vkGetRenderAreaGranularity", reinterpret_cast<PFN_vkVoidFunction>(GetRenderAreaGranularity) },
+ { "vkGetSemaphoreCounterValue", reinterpret_cast<PFN_vkVoidFunction>(GetSemaphoreCounterValue) },
{ "vkGetSwapchainImagesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetSwapchainImagesKHR) },
{ "vkInvalidateMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(InvalidateMappedMemoryRanges) },
{ "vkMapMemory", reinterpret_cast<PFN_vkVoidFunction>(MapMemory) },
@@ -784,12 +823,15 @@
{ "vkResetDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(ResetDescriptorPool) },
{ "vkResetEvent", reinterpret_cast<PFN_vkVoidFunction>(ResetEvent) },
{ "vkResetFences", reinterpret_cast<PFN_vkVoidFunction>(ResetFences) },
+ { "vkResetQueryPool", reinterpret_cast<PFN_vkVoidFunction>(ResetQueryPool) },
{ "vkSetEvent", reinterpret_cast<PFN_vkVoidFunction>(SetEvent) },
+ { "vkSignalSemaphore", reinterpret_cast<PFN_vkVoidFunction>(SignalSemaphore) },
{ "vkTrimCommandPool", reinterpret_cast<PFN_vkVoidFunction>(TrimCommandPool) },
{ "vkUnmapMemory", reinterpret_cast<PFN_vkVoidFunction>(UnmapMemory) },
{ "vkUpdateDescriptorSetWithTemplate", reinterpret_cast<PFN_vkVoidFunction>(UpdateDescriptorSetWithTemplate) },
{ "vkUpdateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(UpdateDescriptorSets) },
{ "vkWaitForFences", reinterpret_cast<PFN_vkVoidFunction>(WaitForFences) },
+ { "vkWaitSemaphores", reinterpret_cast<PFN_vkVoidFunction>(WaitSemaphores) },
};
// clang-format on
constexpr size_t count = sizeof(hooks) / sizeof(hooks[0]);
@@ -965,6 +1007,10 @@
return GetData(device).dispatch.GetQueryPoolResults(device, queryPool, firstQuery, queryCount, dataSize, pData, stride, flags);
}
+VKAPI_ATTR void ResetQueryPool(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) {
+ GetData(device).dispatch.ResetQueryPool(device, queryPool, firstQuery, queryCount);
+}
+
VKAPI_ATTR VkResult CreateBuffer(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer) {
return GetData(device).dispatch.CreateBuffer(device, pCreateInfo, pAllocator, pBuffer);
}
@@ -1481,6 +1527,34 @@
GetData(device).dispatch.GetDescriptorSetLayoutSupport(device, pCreateInfo, pSupport);
}
+VKAPI_ATTR VkResult CreateRenderPass2(VkDevice device, const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass) {
+ return GetData(device).dispatch.CreateRenderPass2(device, pCreateInfo, pAllocator, pRenderPass);
+}
+
+VKAPI_ATTR void CmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfo* pSubpassBeginInfo) {
+ GetData(commandBuffer).dispatch.CmdBeginRenderPass2(commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
+}
+
+VKAPI_ATTR void CmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo* pSubpassBeginInfo, const VkSubpassEndInfo* pSubpassEndInfo) {
+ GetData(commandBuffer).dispatch.CmdNextSubpass2(commandBuffer, pSubpassBeginInfo, pSubpassEndInfo);
+}
+
+VKAPI_ATTR void CmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpassEndInfo* pSubpassEndInfo) {
+ GetData(commandBuffer).dispatch.CmdEndRenderPass2(commandBuffer, pSubpassEndInfo);
+}
+
+VKAPI_ATTR VkResult GetSemaphoreCounterValue(VkDevice device, VkSemaphore semaphore, uint64_t* pValue) {
+ return GetData(device).dispatch.GetSemaphoreCounterValue(device, semaphore, pValue);
+}
+
+VKAPI_ATTR VkResult WaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout) {
+ return GetData(device).dispatch.WaitSemaphores(device, pWaitInfo, timeout);
+}
+
+VKAPI_ATTR VkResult SignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo) {
+ return GetData(device).dispatch.SignalSemaphore(device, pSignalInfo);
+}
+
VKAPI_ATTR VkResult GetAndroidHardwareBufferPropertiesANDROID(VkDevice device, const struct AHardwareBuffer* buffer, VkAndroidHardwareBufferPropertiesANDROID* pProperties) {
return GetData(device).dispatch.GetAndroidHardwareBufferPropertiesANDROID(device, buffer, pProperties);
}
@@ -1489,6 +1563,26 @@
return GetData(device).dispatch.GetMemoryAndroidHardwareBufferANDROID(device, pInfo, pBuffer);
}
+VKAPI_ATTR void CmdDrawIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) {
+ GetData(commandBuffer).dispatch.CmdDrawIndirectCount(commandBuffer, buffer, offset, countBuffer, countBufferOffset, maxDrawCount, stride);
+}
+
+VKAPI_ATTR void CmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) {
+ GetData(commandBuffer).dispatch.CmdDrawIndexedIndirectCount(commandBuffer, buffer, offset, countBuffer, countBufferOffset, maxDrawCount, stride);
+}
+
+VKAPI_ATTR uint64_t GetBufferOpaqueCaptureAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo) {
+ return GetData(device).dispatch.GetBufferOpaqueCaptureAddress(device, pInfo);
+}
+
+VKAPI_ATTR VkDeviceAddress GetBufferDeviceAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo) {
+ return GetData(device).dispatch.GetBufferDeviceAddress(device, pInfo);
+}
+
+VKAPI_ATTR uint64_t GetDeviceMemoryOpaqueCaptureAddress(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo) {
+ return GetData(device).dispatch.GetDeviceMemoryOpaqueCaptureAddress(device, pInfo);
+}
+
} // anonymous namespace
@@ -1755,6 +1849,11 @@
}
__attribute__((visibility("default")))
+VKAPI_ATTR void vkResetQueryPool(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) {
+ vulkan::api::ResetQueryPool(device, queryPool, firstQuery, queryCount);
+}
+
+__attribute__((visibility("default")))
VKAPI_ATTR VkResult vkCreateBuffer(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer) {
return vulkan::api::CreateBuffer(device, pCreateInfo, pAllocator, pBuffer);
}
@@ -2400,6 +2499,41 @@
}
__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkCreateRenderPass2(VkDevice device, const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass) {
+ return vulkan::api::CreateRenderPass2(device, pCreateInfo, pAllocator, pRenderPass);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkCmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfo* pSubpassBeginInfo) {
+ vulkan::api::CmdBeginRenderPass2(commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkCmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo* pSubpassBeginInfo, const VkSubpassEndInfo* pSubpassEndInfo) {
+ vulkan::api::CmdNextSubpass2(commandBuffer, pSubpassBeginInfo, pSubpassEndInfo);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkCmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpassEndInfo* pSubpassEndInfo) {
+ vulkan::api::CmdEndRenderPass2(commandBuffer, pSubpassEndInfo);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkGetSemaphoreCounterValue(VkDevice device, VkSemaphore semaphore, uint64_t* pValue) {
+ return vulkan::api::GetSemaphoreCounterValue(device, semaphore, pValue);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkWaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout) {
+ return vulkan::api::WaitSemaphores(device, pWaitInfo, timeout);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkSignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo) {
+ return vulkan::api::SignalSemaphore(device, pSignalInfo);
+}
+
+__attribute__((visibility("default")))
VKAPI_ATTR VkResult vkGetAndroidHardwareBufferPropertiesANDROID(VkDevice device, const struct AHardwareBuffer* buffer, VkAndroidHardwareBufferPropertiesANDROID* pProperties) {
return vulkan::api::GetAndroidHardwareBufferPropertiesANDROID(device, buffer, pProperties);
}
@@ -2409,4 +2543,29 @@
return vulkan::api::GetMemoryAndroidHardwareBufferANDROID(device, pInfo, pBuffer);
}
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkCmdDrawIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) {
+ vulkan::api::CmdDrawIndirectCount(commandBuffer, buffer, offset, countBuffer, countBufferOffset, maxDrawCount, stride);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkCmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) {
+ vulkan::api::CmdDrawIndexedIndirectCount(commandBuffer, buffer, offset, countBuffer, countBufferOffset, maxDrawCount, stride);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR uint64_t vkGetBufferOpaqueCaptureAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo) {
+ return vulkan::api::GetBufferOpaqueCaptureAddress(device, pInfo);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkDeviceAddress vkGetBufferDeviceAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo) {
+ return vulkan::api::GetBufferDeviceAddress(device, pInfo);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR uint64_t vkGetDeviceMemoryOpaqueCaptureAddress(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo) {
+ return vulkan::api::GetDeviceMemoryOpaqueCaptureAddress(device, pInfo);
+}
+
// clang-format on
diff --git a/vulkan/libvulkan/api_gen.h b/vulkan/libvulkan/api_gen.h
index 2195845..ad5cc34 100644
--- a/vulkan/libvulkan/api_gen.h
+++ b/vulkan/libvulkan/api_gen.h
@@ -99,6 +99,7 @@
PFN_vkCreateQueryPool CreateQueryPool;
PFN_vkDestroyQueryPool DestroyQueryPool;
PFN_vkGetQueryPoolResults GetQueryPoolResults;
+ PFN_vkResetQueryPool ResetQueryPool;
PFN_vkCreateBuffer CreateBuffer;
PFN_vkDestroyBuffer DestroyBuffer;
PFN_vkCreateBufferView CreateBufferView;
@@ -210,8 +211,20 @@
PFN_vkDestroySamplerYcbcrConversion DestroySamplerYcbcrConversion;
PFN_vkGetDeviceQueue2 GetDeviceQueue2;
PFN_vkGetDescriptorSetLayoutSupport GetDescriptorSetLayoutSupport;
+ PFN_vkCreateRenderPass2 CreateRenderPass2;
+ PFN_vkCmdBeginRenderPass2 CmdBeginRenderPass2;
+ PFN_vkCmdNextSubpass2 CmdNextSubpass2;
+ PFN_vkCmdEndRenderPass2 CmdEndRenderPass2;
+ PFN_vkGetSemaphoreCounterValue GetSemaphoreCounterValue;
+ PFN_vkWaitSemaphores WaitSemaphores;
+ PFN_vkSignalSemaphore SignalSemaphore;
PFN_vkGetAndroidHardwareBufferPropertiesANDROID GetAndroidHardwareBufferPropertiesANDROID;
PFN_vkGetMemoryAndroidHardwareBufferANDROID GetMemoryAndroidHardwareBufferANDROID;
+ PFN_vkCmdDrawIndirectCount CmdDrawIndirectCount;
+ PFN_vkCmdDrawIndexedIndirectCount CmdDrawIndexedIndirectCount;
+ PFN_vkGetBufferOpaqueCaptureAddress GetBufferOpaqueCaptureAddress;
+ PFN_vkGetBufferDeviceAddress GetBufferDeviceAddress;
+ PFN_vkGetDeviceMemoryOpaqueCaptureAddress GetDeviceMemoryOpaqueCaptureAddress;
// clang-format on
};
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 01cbf39..c63fdf5 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -549,6 +549,7 @@
case ProcHook::GOOGLE_display_timing:
case ProcHook::EXTENSION_CORE_1_0:
case ProcHook::EXTENSION_CORE_1_1:
+ case ProcHook::EXTENSION_CORE_1_2:
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
@@ -598,6 +599,7 @@
case ProcHook::ANDROID_native_buffer:
case ProcHook::EXTENSION_CORE_1_0:
case ProcHook::EXTENSION_CORE_1_1:
+ case ProcHook::EXTENSION_CORE_1_2:
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
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index 43c4d14..62538c1 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -51,6 +51,7 @@
EXTENSION_CORE_1_0,
EXTENSION_CORE_1_1,
+ EXTENSION_CORE_1_2,
EXTENSION_COUNT,
EXTENSION_UNKNOWN,
};
diff --git a/vulkan/libvulkan/libvulkan.map.txt b/vulkan/libvulkan/libvulkan.map.txt
index 0be66c9..df97d7f 100644
--- a/vulkan/libvulkan/libvulkan.map.txt
+++ b/vulkan/libvulkan/libvulkan.map.txt
@@ -12,6 +12,7 @@
vkBindImageMemory2; # introduced=28
vkCmdBeginQuery;
vkCmdBeginRenderPass;
+ vkCmdBeginRenderPass2; # introduced=31
vkCmdBindDescriptorSets;
vkCmdBindIndexBuffer;
vkCmdBindPipeline;
@@ -31,12 +32,16 @@
vkCmdDraw;
vkCmdDrawIndexed;
vkCmdDrawIndexedIndirect;
+ vkCmdDrawIndexedIndirectCount; # introduced=31
vkCmdDrawIndirect;
+ vkCmdDrawIndirectCount; # introduced=31
vkCmdEndQuery;
vkCmdEndRenderPass;
+ vkCmdEndRenderPass2; # introduced=31
vkCmdExecuteCommands;
vkCmdFillBuffer;
vkCmdNextSubpass;
+ vkCmdNextSubpass2; # introduced=31
vkCmdPipelineBarrier;
vkCmdPushConstants;
vkCmdResetEvent;
@@ -76,6 +81,7 @@
vkCreatePipelineLayout;
vkCreateQueryPool;
vkCreateRenderPass;
+ vkCreateRenderPass2; # introduced=31
vkCreateSampler;
vkCreateSamplerYcbcrConversion; # introduced=28
vkCreateSemaphore;
@@ -119,13 +125,16 @@
vkFreeDescriptorSets;
vkFreeMemory;
vkGetAndroidHardwareBufferPropertiesANDROID; # introduced=28
+ vkGetBufferDeviceAddress; # introduced=31
vkGetBufferMemoryRequirements;
vkGetBufferMemoryRequirements2; # introduced=28
+ vkGetBufferOpaqueCaptureAddress; # introduced=31
vkGetDescriptorSetLayoutSupport; # introduced=28
vkGetDeviceGroupPeerMemoryFeatures; # introduced=28
vkGetDeviceGroupPresentCapabilitiesKHR; # introduced=28
vkGetDeviceGroupSurfacePresentModesKHR; # introduced=28
vkGetDeviceMemoryCommitment;
+ vkGetDeviceMemoryOpaqueCaptureAddress; # introduced=31
vkGetDeviceProcAddr;
vkGetDeviceQueue;
vkGetDeviceQueue2; # introduced=28
@@ -163,6 +172,7 @@
vkGetPipelineCacheData;
vkGetQueryPoolResults;
vkGetRenderAreaGranularity;
+ vkGetSemaphoreCounterValue; # introduced=31
vkGetSwapchainImagesKHR;
vkInvalidateMappedMemoryRanges;
vkMapMemory;
@@ -176,12 +186,15 @@
vkResetDescriptorPool;
vkResetEvent;
vkResetFences;
+ vkResetQueryPool; # introduced=31
vkSetEvent;
+ vkSignalSemaphore; # introduced=31
vkTrimCommandPool; # introduced=28
vkUnmapMemory;
vkUpdateDescriptorSets;
vkUpdateDescriptorSetWithTemplate; # introduced=28
vkWaitForFences;
+ vkWaitSemaphores; # introduced=31
local:
*;
};
diff --git a/vulkan/nulldrv/null_driver.cpp b/vulkan/nulldrv/null_driver.cpp
index 4647a80..b94233b 100644
--- a/vulkan/nulldrv/null_driver.cpp
+++ b/vulkan/nulldrv/null_driver.cpp
@@ -1123,6 +1123,14 @@
return VK_SUCCESS;
}
+VkResult CreateRenderPass2(VkDevice device,
+ const VkRenderPassCreateInfo2*,
+ const VkAllocationCallbacks* /*allocator*/,
+ VkRenderPass* pRenderPass) {
+ *pRenderPass = AllocHandle<VkRenderPass>(device, HandleType::kRenderPass);
+ return VK_SUCCESS;
+}
+
// -----------------------------------------------------------------------------
// No-op entrypoints
@@ -1568,6 +1576,55 @@
void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport) {
}
+void ResetQueryPool(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) {
+ ALOGV("TODO: vk%s", __FUNCTION__);
+}
+
+void CmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfo* pSubpassBeginInfo) {
+}
+
+void CmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo* pSubpassBeginInfo, const VkSubpassEndInfo* pSubpassEndInfo) {
+}
+
+void CmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpassEndInfo* pSubpassEndInfo) {
+}
+
+VkResult GetSemaphoreCounterValue(VkDevice device, VkSemaphore semaphore, uint64_t* pValue) {
+ ALOGV("TODO: vk%s", __FUNCTION__);
+ return VK_SUCCESS;
+}
+
+VkResult WaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout) {
+ ALOGV("TODO: vk%s", __FUNCTION__);
+ return VK_SUCCESS;
+}
+
+VkResult SignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo) {
+ ALOGV("TODO: vk%s", __FUNCTION__);
+ return VK_SUCCESS;
+}
+
+void CmdDrawIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) {
+}
+
+void CmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) {
+}
+
+uint64_t GetBufferOpaqueCaptureAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo) {
+ ALOGV("TODO: vk%s", __FUNCTION__);
+ return 0;
+}
+
+VkDeviceAddress GetBufferDeviceAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo) {
+ ALOGV("TODO: vk%s", __FUNCTION__);
+ return (VkDeviceAddress)0;
+}
+
+uint64_t GetDeviceMemoryOpaqueCaptureAddress(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo) {
+ ALOGV("TODO: vk%s", __FUNCTION__);
+ return 0;
+}
+
#pragma clang diagnostic pop
// clang-format on
diff --git a/vulkan/nulldrv/null_driver_gen.cpp b/vulkan/nulldrv/null_driver_gen.cpp
index b8d7d2b..edda12c 100644
--- a/vulkan/nulldrv/null_driver_gen.cpp
+++ b/vulkan/nulldrv/null_driver_gen.cpp
@@ -67,6 +67,7 @@
{"vkBindImageMemory2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkBindImageMemory2>(BindImageMemory2))},
{"vkCmdBeginQuery", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBeginQuery>(CmdBeginQuery))},
{"vkCmdBeginRenderPass", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBeginRenderPass>(CmdBeginRenderPass))},
+ {"vkCmdBeginRenderPass2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBeginRenderPass2>(CmdBeginRenderPass2))},
{"vkCmdBindDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBindDescriptorSets>(CmdBindDescriptorSets))},
{"vkCmdBindIndexBuffer", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBindIndexBuffer>(CmdBindIndexBuffer))},
{"vkCmdBindPipeline", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBindPipeline>(CmdBindPipeline))},
@@ -86,12 +87,16 @@
{"vkCmdDraw", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDraw>(CmdDraw))},
{"vkCmdDrawIndexed", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDrawIndexed>(CmdDrawIndexed))},
{"vkCmdDrawIndexedIndirect", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDrawIndexedIndirect>(CmdDrawIndexedIndirect))},
+ {"vkCmdDrawIndexedIndirectCount", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDrawIndexedIndirectCount>(CmdDrawIndexedIndirectCount))},
{"vkCmdDrawIndirect", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDrawIndirect>(CmdDrawIndirect))},
+ {"vkCmdDrawIndirectCount", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDrawIndirectCount>(CmdDrawIndirectCount))},
{"vkCmdEndQuery", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdEndQuery>(CmdEndQuery))},
{"vkCmdEndRenderPass", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdEndRenderPass>(CmdEndRenderPass))},
+ {"vkCmdEndRenderPass2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdEndRenderPass2>(CmdEndRenderPass2))},
{"vkCmdExecuteCommands", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdExecuteCommands>(CmdExecuteCommands))},
{"vkCmdFillBuffer", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdFillBuffer>(CmdFillBuffer))},
{"vkCmdNextSubpass", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdNextSubpass>(CmdNextSubpass))},
+ {"vkCmdNextSubpass2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdNextSubpass2>(CmdNextSubpass2))},
{"vkCmdPipelineBarrier", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdPipelineBarrier>(CmdPipelineBarrier))},
{"vkCmdPushConstants", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdPushConstants>(CmdPushConstants))},
{"vkCmdResetEvent", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdResetEvent>(CmdResetEvent))},
@@ -131,6 +136,7 @@
{"vkCreatePipelineLayout", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreatePipelineLayout>(CreatePipelineLayout))},
{"vkCreateQueryPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateQueryPool>(CreateQueryPool))},
{"vkCreateRenderPass", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateRenderPass>(CreateRenderPass))},
+ {"vkCreateRenderPass2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateRenderPass2>(CreateRenderPass2))},
{"vkCreateSampler", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateSampler>(CreateSampler))},
{"vkCreateSamplerYcbcrConversion", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateSamplerYcbcrConversion>(CreateSamplerYcbcrConversion))},
{"vkCreateSemaphore", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateSemaphore>(CreateSemaphore))},
@@ -172,11 +178,14 @@
{"vkFreeCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkFreeCommandBuffers>(FreeCommandBuffers))},
{"vkFreeDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkFreeDescriptorSets>(FreeDescriptorSets))},
{"vkFreeMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkFreeMemory>(FreeMemory))},
+ {"vkGetBufferDeviceAddress", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetBufferDeviceAddress>(GetBufferDeviceAddress))},
{"vkGetBufferMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetBufferMemoryRequirements>(GetBufferMemoryRequirements))},
{"vkGetBufferMemoryRequirements2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetBufferMemoryRequirements2>(GetBufferMemoryRequirements2))},
+ {"vkGetBufferOpaqueCaptureAddress", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetBufferOpaqueCaptureAddress>(GetBufferOpaqueCaptureAddress))},
{"vkGetDescriptorSetLayoutSupport", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDescriptorSetLayoutSupport>(GetDescriptorSetLayoutSupport))},
{"vkGetDeviceGroupPeerMemoryFeatures", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceGroupPeerMemoryFeatures>(GetDeviceGroupPeerMemoryFeatures))},
{"vkGetDeviceMemoryCommitment", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceMemoryCommitment>(GetDeviceMemoryCommitment))},
+ {"vkGetDeviceMemoryOpaqueCaptureAddress", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceMemoryOpaqueCaptureAddress>(GetDeviceMemoryOpaqueCaptureAddress))},
{"vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceProcAddr>(GetDeviceProcAddr))},
{"vkGetDeviceQueue", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceQueue>(GetDeviceQueue))},
{"vkGetDeviceQueue2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceQueue2>(GetDeviceQueue2))},
@@ -215,6 +224,7 @@
{"vkGetPipelineCacheData", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPipelineCacheData>(GetPipelineCacheData))},
{"vkGetQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetQueryPoolResults>(GetQueryPoolResults))},
{"vkGetRenderAreaGranularity", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetRenderAreaGranularity>(GetRenderAreaGranularity))},
+ {"vkGetSemaphoreCounterValue", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSemaphoreCounterValue>(GetSemaphoreCounterValue))},
{"vkGetSwapchainGrallocUsage2ANDROID", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSwapchainGrallocUsage2ANDROID>(GetSwapchainGrallocUsage2ANDROID))},
{"vkGetSwapchainGrallocUsageANDROID", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSwapchainGrallocUsageANDROID>(GetSwapchainGrallocUsageANDROID))},
{"vkInvalidateMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkInvalidateMappedMemoryRanges>(InvalidateMappedMemoryRanges))},
@@ -229,12 +239,15 @@
{"vkResetDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkResetDescriptorPool>(ResetDescriptorPool))},
{"vkResetEvent", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkResetEvent>(ResetEvent))},
{"vkResetFences", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkResetFences>(ResetFences))},
+ {"vkResetQueryPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkResetQueryPool>(ResetQueryPool))},
{"vkSetEvent", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkSetEvent>(SetEvent))},
+ {"vkSignalSemaphore", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkSignalSemaphore>(SignalSemaphore))},
{"vkTrimCommandPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkTrimCommandPool>(TrimCommandPool))},
{"vkUnmapMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkUnmapMemory>(UnmapMemory))},
{"vkUpdateDescriptorSetWithTemplate", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkUpdateDescriptorSetWithTemplate>(UpdateDescriptorSetWithTemplate))},
{"vkUpdateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkUpdateDescriptorSets>(UpdateDescriptorSets))},
{"vkWaitForFences", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkWaitForFences>(WaitForFences))},
+ {"vkWaitSemaphores", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkWaitSemaphores>(WaitSemaphores))},
// clang-format on
};
diff --git a/vulkan/nulldrv/null_driver_gen.h b/vulkan/nulldrv/null_driver_gen.h
index 0d3f688..e59cae9 100644
--- a/vulkan/nulldrv/null_driver_gen.h
+++ b/vulkan/nulldrv/null_driver_gen.h
@@ -79,6 +79,7 @@
VKAPI_ATTR VkResult CreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool);
VKAPI_ATTR void DestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator);
VKAPI_ATTR VkResult GetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags);
+VKAPI_ATTR void ResetQueryPool(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount);
VKAPI_ATTR VkResult CreateBuffer(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer);
VKAPI_ATTR void DestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator);
VKAPI_ATTR VkResult CreateBufferView(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView);
@@ -207,6 +208,18 @@
VKAPI_ATTR VkResult GetSwapchainGrallocUsage2ANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, VkSwapchainImageUsageFlagsANDROID swapchainImageUsage, uint64_t* grallocConsumerUsage, uint64_t* grallocProducerUsage);
VKAPI_ATTR VkResult AcquireImageANDROID(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence);
VKAPI_ATTR VkResult QueueSignalReleaseImageANDROID(VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd);
+VKAPI_ATTR VkResult CreateRenderPass2(VkDevice device, const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass);
+VKAPI_ATTR void CmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfo* pSubpassBeginInfo);
+VKAPI_ATTR void CmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo* pSubpassBeginInfo, const VkSubpassEndInfo* pSubpassEndInfo);
+VKAPI_ATTR void CmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpassEndInfo* pSubpassEndInfo);
+VKAPI_ATTR VkResult GetSemaphoreCounterValue(VkDevice device, VkSemaphore semaphore, uint64_t* pValue);
+VKAPI_ATTR VkResult WaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout);
+VKAPI_ATTR VkResult SignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo);
+VKAPI_ATTR void CmdDrawIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);
+VKAPI_ATTR void CmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);
+VKAPI_ATTR uint64_t GetBufferOpaqueCaptureAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo);
+VKAPI_ATTR VkDeviceAddress GetBufferDeviceAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo);
+VKAPI_ATTR uint64_t GetDeviceMemoryOpaqueCaptureAddress(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo);
// clang-format on
} // namespace null_driver
diff --git a/vulkan/scripts/generator_common.py b/vulkan/scripts/generator_common.py
index ef0719d..e9a96f3 100644
--- a/vulkan/scripts/generator_common.py
+++ b/vulkan/scripts/generator_common.py
@@ -25,6 +25,7 @@
_BLOCKED_EXTENSIONS = [
'VK_EXT_acquire_xlib_display',
'VK_EXT_direct_mode_display',
+ 'VK_EXT_directfb_surface',
'VK_EXT_display_control',
'VK_EXT_display_surface_counter',
'VK_EXT_full_screen_exclusive',
@@ -302,12 +303,12 @@
else:
f.write('INIT_PROC(')
- if name in version_dict and version_dict[name] == 'VK_VERSION_1_1':
+ if name in _OPTIONAL_COMMANDS:
f.write('false, ')
- elif name in _OPTIONAL_COMMANDS:
- f.write('false, ')
- else:
+ elif version_dict[name] == 'VK_VERSION_1_0':
f.write('true, ')
+ else:
+ f.write('false, ')
if is_instance_dispatched(name):
f.write('instance, ')
@@ -376,7 +377,7 @@
for exts in root.iter('extensions'):
for extension in exts:
- apiversion = ''
+ apiversion = 'VK_VERSION_1_0'
if extension.tag == 'extension':
extname = extension.get('name')
for req in extension:
@@ -387,8 +388,7 @@
cmd_name = commands.get('name')
if cmd_name not in extension_dict:
extension_dict[cmd_name] = extname
- if apiversion:
- version_dict[cmd_name] = apiversion
+ version_dict[cmd_name] = apiversion
for feature in root.iter('feature'):
apiversion = feature.get('name')
diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc
index b0b466c..bfc240e 100644
--- a/vulkan/vkjson/vkjson.cc
+++ b/vulkan/vkjson/vkjson.cc
@@ -57,9 +57,17 @@
template <typename T> struct EnumTraits;
template <> struct EnumTraits<VkPhysicalDeviceType> {
- static uint32_t min() { return VK_PHYSICAL_DEVICE_TYPE_BEGIN_RANGE; }
- static uint32_t max() { return VK_PHYSICAL_DEVICE_TYPE_END_RANGE; }
- static bool exist(uint32_t e) { return e >= min() && e <= max(); }
+ static bool exist(uint32_t e) {
+ switch (e) {
+ case VK_PHYSICAL_DEVICE_TYPE_OTHER:
+ case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
+ case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
+ case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
+ case VK_PHYSICAL_DEVICE_TYPE_CPU:
+ return true;
+ }
+ return false;
+ }
};
template <> struct EnumTraits<VkFormat> {
@@ -250,6 +258,40 @@
case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
+ case VK_FORMAT_G8B8G8R8_422_UNORM:
+ case VK_FORMAT_B8G8R8G8_422_UNORM:
+ case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
+ case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
+ case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
+ case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
+ case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
+ case VK_FORMAT_R10X6_UNORM_PACK16:
+ case VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
+ case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
+ case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
+ case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
+ case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
+ case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
+ case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
+ case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
+ case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
+ case VK_FORMAT_R12X4_UNORM_PACK16:
+ case VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
+ case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
+ case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
+ case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
+ case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
+ case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
+ case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
+ case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
+ case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
+ case VK_FORMAT_G16B16G16R16_422_UNORM:
+ case VK_FORMAT_B16G16R16G16_422_UNORM:
+ case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
+ case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
+ case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
+ case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
+ case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG:
case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG:
case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG:
@@ -258,40 +300,22 @@
case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG:
case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG:
case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG:
- case VK_FORMAT_G8B8G8R8_422_UNORM_KHR:
- case VK_FORMAT_B8G8R8G8_422_UNORM_KHR:
- case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR:
- case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR:
- case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR:
- case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR:
- case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR:
- case VK_FORMAT_R10X6_UNORM_PACK16_KHR:
- case VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR:
- case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR:
- case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR:
- case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR:
- case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR:
- case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR:
- case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR:
- case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR:
- case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR:
- case VK_FORMAT_R12X4_UNORM_PACK16_KHR:
- case VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR:
- case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR:
- case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR:
- case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR:
- case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR:
- case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR:
- case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR:
- case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR:
- case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR:
- case VK_FORMAT_G16B16G16R16_422_UNORM_KHR:
- case VK_FORMAT_B16G16R16G16_422_UNORM_KHR:
- case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR:
- case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR:
- case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR:
- case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR:
- case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR:
+ case VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT:
+ case VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT:
+ case VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT:
+ case VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT:
+ case VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT:
+ case VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT:
+ case VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT:
+ case VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT:
+ case VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT:
+ case VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT:
+ case VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT:
+ case VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT:
+ case VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT:
+ case VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT:
+ case VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT:
+ case VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT:
return true;
}
return false;
@@ -300,9 +324,14 @@
template <>
struct EnumTraits<VkPointClippingBehavior> {
- static uint32_t min() { return VK_POINT_CLIPPING_BEHAVIOR_BEGIN_RANGE; }
- static uint32_t max() { return VK_POINT_CLIPPING_BEHAVIOR_END_RANGE; }
- static bool exist(uint32_t e) { return e >= min() && e <= max(); }
+ static bool exist(uint32_t e) {
+ switch (e) {
+ case VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES:
+ case VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY:
+ return true;
+ }
+ return false;
+ }
};
template <>
@@ -336,9 +365,26 @@
template <>
struct EnumTraits<VkDriverIdKHR> {
- static uint32_t min() { return VK_DRIVER_ID_BEGIN_RANGE_KHR; }
- static uint32_t max() { return VK_DRIVER_ID_END_RANGE_KHR; }
- static bool exist(uint32_t e) { return e >= min() && e <= max(); }
+ static bool exist(uint32_t e) {
+ switch (e) {
+ case VK_DRIVER_ID_AMD_PROPRIETARY:
+ case VK_DRIVER_ID_AMD_OPEN_SOURCE:
+ case VK_DRIVER_ID_MESA_RADV:
+ case VK_DRIVER_ID_NVIDIA_PROPRIETARY:
+ case VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS:
+ case VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA:
+ case VK_DRIVER_ID_IMAGINATION_PROPRIETARY:
+ case VK_DRIVER_ID_QUALCOMM_PROPRIETARY:
+ case VK_DRIVER_ID_ARM_PROPRIETARY:
+ case VK_DRIVER_ID_GOOGLE_SWIFTSHADER:
+ case VK_DRIVER_ID_GGP_PROPRIETARY:
+ case VK_DRIVER_ID_BROADCOM_PROPRIETARY:
+ case VK_DRIVER_ID_MESA_LLVMPIPE:
+ case VK_DRIVER_ID_MOLTENVK:
+ return true;
+ }
+ return false;
+ }
};
// VkSparseImageFormatProperties
diff --git a/vulkan/vkjson/vkjson_instance.cc b/vulkan/vkjson/vkjson_instance.cc
index 84cfe5e..73586d4 100644
--- a/vulkan/vkjson/vkjson_instance.cc
+++ b/vulkan/vkjson/vkjson_instance.cc
@@ -165,7 +165,9 @@
VkFormatProperties format_properties = {};
for (VkFormat format = VK_FORMAT_R4G4_UNORM_PACK8;
- format <= VK_FORMAT_END_RANGE;
+ // TODO(http://b/171403054): avoid hard-coding last value in the
+ // contiguous range
+ format <= VK_FORMAT_ASTC_12x12_SRGB_BLOCK;
format = static_cast<VkFormat>(format + 1)) {
vkGetPhysicalDeviceFormatProperties(physical_device, format,
&format_properties);
@@ -178,6 +180,8 @@
if (device.properties.apiVersion >= VK_API_VERSION_1_1) {
for (VkFormat format = VK_FORMAT_G8B8G8R8_422_UNORM;
+ // TODO(http://b/171403054): avoid hard-coding last value in the
+ // contiguous range
format <= VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM;
format = static_cast<VkFormat>(format + 1)) {
vkGetPhysicalDeviceFormatProperties(physical_device, format,