Merge "libgui: Check slot received from IGBP in Surface" into lmp-dev am: 98e3c06010 am: 970bb51580 am: 78976cea8f am: 2fe15aa6f0 am: cce83f15e5 am: 9a44ee0742 am: 787aa48f41 am: f69675e5c2 am: d65a388e1b am: b829d2abe9 am: 79a34dd24b
am: a1b1e635cc
Change-Id: Idfd63642dda3ae741056b75c9c9ddccd63feb76f
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..cd05b21
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,15 @@
+ndk_headers {
+ name: "libandroid_headers",
+ from: "include/android",
+ to: "android",
+ srcs: ["include/android/**/*.h"],
+ license: "NOTICE",
+}
+
+subdirs = [
+ "cmds/*",
+ "libs/*",
+ "opengl",
+ "services/*",
+ "vulkan",
+]
diff --git a/cmds/atrace/Android.bp b/cmds/atrace/Android.bp
new file mode 100644
index 0000000..a2560e3
--- /dev/null
+++ b/cmds/atrace/Android.bp
@@ -0,0 +1,19 @@
+// Copyright 2012 The Android Open Source Project
+
+cc_binary {
+ name: "atrace",
+ srcs: ["atrace.cpp"],
+
+ shared_libs: [
+ "libbinder",
+ "libhwbinder",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libutils",
+ "libz",
+ "libbase",
+ ],
+
+ init_rc: ["atrace.rc"],
+}
diff --git a/cmds/atrace/Android.mk b/cmds/atrace/Android.mk
deleted file mode 100644
index a787e95..0000000
--- a/cmds/atrace/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright 2012 The Android Open Source Project
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= atrace.cpp
-
-LOCAL_C_INCLUDES += external/zlib
-
-LOCAL_MODULE:= atrace
-
-LOCAL_MODULE_TAGS:= optional
-
-LOCAL_SHARED_LIBRARIES := \
- libbinder \
- libcutils \
- libutils \
- libz \
-
-LOCAL_INIT_RC := atrace.rc
-
-include $(BUILD_EXECUTABLE)
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 5885738..add5285 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
- #define LOG_TAG "atrace"
+#define LOG_TAG "atrace"
#include <errno.h>
#include <fcntl.h>
@@ -26,25 +26,31 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/sendfile.h>
#include <time.h>
#include <unistd.h>
#include <zlib.h>
+#include <memory>
+
#include <binder/IBinder.h>
#include <binder/IServiceManager.h>
#include <binder/Parcel.h>
-#include <cutils/properties.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <hidl/ServiceManagement.h>
#include <utils/String8.h>
#include <utils/Timers.h>
#include <utils/Tokenizer.h>
#include <utils/Trace.h>
+#include <android-base/file.h>
+#include <android-base/macros.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
using namespace android;
-#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
+using std::string;
#define MAX_SYS_FILES 10
#define MAX_PACKAGES 16
@@ -103,72 +109,84 @@
{ "ss", "System Server", ATRACE_TAG_SYSTEM_SERVER, { } },
{ "database", "Database", ATRACE_TAG_DATABASE, { } },
{ "network", "Network", ATRACE_TAG_NETWORK, { } },
+ { "adb", "ADB", ATRACE_TAG_ADB, { } },
{ k_coreServiceCategory, "Core services", 0, { } },
{ "sched", "CPU Scheduling", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/sched/sched_switch/enable" },
- { REQ, "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/sched/sched_blocked_reason/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug/enable" },
+ { REQ, "events/sched/sched_switch/enable" },
+ { REQ, "events/sched/sched_wakeup/enable" },
+ { OPT, "events/sched/sched_blocked_reason/enable" },
+ { OPT, "events/sched/sched_cpu_hotplug/enable" },
} },
{ "irq", "IRQ Events", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/irq/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/ipi/enable" },
+ { REQ, "events/irq/enable" },
+ { OPT, "events/ipi/enable" },
+ } },
+ { "i2c", "I2C Events", 0, {
+ { REQ, "events/i2c/enable" },
+ { REQ, "events/i2c/i2c_read/enable" },
+ { REQ, "events/i2c/i2c_write/enable" },
+ { REQ, "events/i2c/i2c_result/enable" },
+ { REQ, "events/i2c/i2c_reply/enable" },
+ { OPT, "events/i2c/smbus_read/enable" },
+ { OPT, "events/i2c/smbus_write/enable" },
+ { OPT, "events/i2c/smbus_result/enable" },
+ { OPT, "events/i2c/smbus_reply/enable" },
} },
{ "freq", "CPU Frequency", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/power/cpu_frequency_limits/enable" },
+ { REQ, "events/power/cpu_frequency/enable" },
+ { OPT, "events/power/clock_set_rate/enable" },
+ { OPT, "events/power/cpu_frequency_limits/enable" },
} },
{ "membus", "Memory Bus Utilization", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/memory_bus/enable" },
+ { REQ, "events/memory_bus/enable" },
} },
{ "idle", "CPU Idle", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/power/cpu_idle/enable" },
+ { REQ, "events/power/cpu_idle/enable" },
} },
{ "disk", "Disk I/O", 0, {
- { OPT, "/sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_enter/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_exit/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/f2fs/f2fs_write_begin/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/f2fs/f2fs_write_end/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/ext4/ext4_da_write_end/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable" },
- { OPT, "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable" },
- { REQ, "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable" },
- { REQ, "/sys/kernel/debug/tracing/events/block/block_rq_complete/enable" },
+ { OPT, "events/f2fs/f2fs_sync_file_enter/enable" },
+ { OPT, "events/f2fs/f2fs_sync_file_exit/enable" },
+ { OPT, "events/f2fs/f2fs_write_begin/enable" },
+ { OPT, "events/f2fs/f2fs_write_end/enable" },
+ { OPT, "events/ext4/ext4_da_write_begin/enable" },
+ { OPT, "events/ext4/ext4_da_write_end/enable" },
+ { OPT, "events/ext4/ext4_sync_file_enter/enable" },
+ { OPT, "events/ext4/ext4_sync_file_exit/enable" },
+ { REQ, "events/block/block_rq_issue/enable" },
+ { REQ, "events/block/block_rq_complete/enable" },
} },
{ "mmc", "eMMC commands", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/mmc/enable" },
+ { REQ, "events/mmc/enable" },
} },
{ "load", "CPU Load", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/cpufreq_interactive/enable" },
+ { REQ, "events/cpufreq_interactive/enable" },
} },
{ "sync", "Synchronization", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/sync/enable" },
+ { REQ, "events/sync/enable" },
} },
{ "workq", "Kernel Workqueues", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/workqueue/enable" },
+ { REQ, "events/workqueue/enable" },
} },
{ "memreclaim", "Kernel Memory Reclaim", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable" },
- { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable" },
- { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable" },
- { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable" },
+ { REQ, "events/vmscan/mm_vmscan_direct_reclaim_begin/enable" },
+ { REQ, "events/vmscan/mm_vmscan_direct_reclaim_end/enable" },
+ { REQ, "events/vmscan/mm_vmscan_kswapd_wake/enable" },
+ { REQ, "events/vmscan/mm_vmscan_kswapd_sleep/enable" },
} },
{ "regulators", "Voltage and Current Regulators", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/regulator/enable" },
+ { REQ, "events/regulator/enable" },
} },
{ "binder_driver", "Binder Kernel driver", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/binder/binder_transaction/enable" },
- { REQ, "/sys/kernel/debug/tracing/events/binder/binder_transaction_received/enable" },
+ { REQ, "events/binder/binder_transaction/enable" },
+ { REQ, "events/binder/binder_transaction_received/enable" },
} },
{ "binder_lock", "Binder global lock trace", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/binder/binder_lock/enable" },
- { REQ, "/sys/kernel/debug/tracing/events/binder/binder_locked/enable" },
- { REQ, "/sys/kernel/debug/tracing/events/binder/binder_unlock/enable" },
+ { REQ, "events/binder/binder_lock/enable" },
+ { REQ, "events/binder/binder_locked/enable" },
+ { REQ, "events/binder/binder_unlock/enable" },
} },
{ "pagecache", "Page cache", 0, {
- { REQ, "/sys/kernel/debug/tracing/events/filemap/enable" },
+ { REQ, "events/filemap/enable" },
} },
};
@@ -186,62 +204,63 @@
/* Global state */
static bool g_traceAborted = false;
-static bool g_categoryEnables[NELEM(k_categories)] = {};
+static bool g_categoryEnables[arraysize(k_categories)] = {};
+static std::string g_traceFolder;
/* Sys file paths */
static const char* k_traceClockPath =
- "/sys/kernel/debug/tracing/trace_clock";
+ "trace_clock";
static const char* k_traceBufferSizePath =
- "/sys/kernel/debug/tracing/buffer_size_kb";
+ "buffer_size_kb";
static const char* k_tracingOverwriteEnablePath =
- "/sys/kernel/debug/tracing/options/overwrite";
+ "options/overwrite";
static const char* k_currentTracerPath =
- "/sys/kernel/debug/tracing/current_tracer";
+ "current_tracer";
static const char* k_printTgidPath =
- "/sys/kernel/debug/tracing/options/print-tgid";
+ "options/print-tgid";
static const char* k_funcgraphAbsTimePath =
- "/sys/kernel/debug/tracing/options/funcgraph-abstime";
+ "options/funcgraph-abstime";
static const char* k_funcgraphCpuPath =
- "/sys/kernel/debug/tracing/options/funcgraph-cpu";
+ "options/funcgraph-cpu";
static const char* k_funcgraphProcPath =
- "/sys/kernel/debug/tracing/options/funcgraph-proc";
+ "options/funcgraph-proc";
static const char* k_funcgraphFlatPath =
- "/sys/kernel/debug/tracing/options/funcgraph-flat";
+ "options/funcgraph-flat";
static const char* k_funcgraphDurationPath =
- "/sys/kernel/debug/tracing/options/funcgraph-duration";
+ "options/funcgraph-duration";
static const char* k_ftraceFilterPath =
- "/sys/kernel/debug/tracing/set_ftrace_filter";
+ "set_ftrace_filter";
static const char* k_tracingOnPath =
- "/sys/kernel/debug/tracing/tracing_on";
+ "tracing_on";
static const char* k_tracePath =
- "/sys/kernel/debug/tracing/trace";
+ "trace";
static const char* k_traceStreamPath =
- "/sys/kernel/debug/tracing/trace_pipe";
+ "trace_pipe";
static const char* k_traceMarkerPath =
- "/sys/kernel/debug/tracing/trace_marker";
+ "trace_marker";
// Check whether a file exists.
static bool fileExists(const char* filename) {
- return access(filename, F_OK) != -1;
+ return access((g_traceFolder + filename).c_str(), F_OK) != -1;
}
// Check whether a file is writable.
static bool fileIsWritable(const char* filename) {
- return access(filename, W_OK) != -1;
+ return access((g_traceFolder + filename).c_str(), W_OK) != -1;
}
// Truncate a file.
@@ -250,9 +269,9 @@
// This uses creat rather than truncate because some of the debug kernel
// device nodes (e.g. k_ftraceFilterPath) currently aren't changed by
// calls to truncate, but they are cleared by calls to creat.
- int traceFD = creat(path, 0);
+ int traceFD = creat((g_traceFolder + path).c_str(), 0);
if (traceFD == -1) {
- fprintf(stderr, "error truncating %s: %s (%d)\n", path,
+ fprintf(stderr, "error truncating %s: %s (%d)\n", (g_traceFolder + path).c_str(),
strerror(errno), errno);
return false;
}
@@ -264,9 +283,10 @@
static bool _writeStr(const char* filename, const char* str, int flags)
{
- int fd = open(filename, flags);
+ std::string fullFilename = g_traceFolder + filename;
+ int fd = open(fullFilename.c_str(), flags);
if (fd == -1) {
- fprintf(stderr, "error opening %s: %s (%d)\n", filename,
+ fprintf(stderr, "error opening %s: %s (%d)\n", fullFilename.c_str(),
strerror(errno), errno);
return false;
}
@@ -274,7 +294,7 @@
bool ok = true;
ssize_t len = strlen(str);
if (write(fd, str, len) != len) {
- fprintf(stderr, "error writing to %s: %s (%d)\n", filename,
+ fprintf(stderr, "error writing to %s: %s (%d)\n", fullFilename.c_str(),
strerror(errno), errno);
ok = false;
}
@@ -300,7 +320,7 @@
{
char buffer[128];
int len = 0;
- int fd = open(k_traceMarkerPath, O_WRONLY);
+ int fd = open((g_traceFolder + k_traceMarkerPath).c_str(), O_WRONLY);
if (fd == -1) {
fprintf(stderr, "error opening %s: %s (%d)\n", k_traceMarkerPath,
strerror(errno), errno);
@@ -336,9 +356,7 @@
static bool isCategorySupported(const TracingCategory& category)
{
if (strcmp(category.name, k_coreServiceCategory) == 0) {
- char value[PROPERTY_VALUE_MAX];
- property_get(k_coreServicesProp, value, "");
- return strlen(value) != 0;
+ return !android::base::GetProperty(k_coreServicesProp, "").empty();
}
bool ok = category.tags != 0;
@@ -421,7 +439,7 @@
// local [global] counter uptime perf
static bool isTraceClock(const char *mode)
{
- int fd = open(k_traceClockPath, O_RDONLY);
+ int fd = open((g_traceFolder + k_traceClockPath).c_str(), O_RDONLY);
if (fd == -1) {
fprintf(stderr, "error opening %s: %s (%d)\n", k_traceClockPath,
strerror(errno), errno);
@@ -503,13 +521,54 @@
return true;
}
+// Poke all the HAL processes in the system to get them to re-read
+// their system properties.
+static void pokeHalServices()
+{
+ using ::android::hidl::base::V1_0::IBase;
+ using ::android::hidl::manager::V1_0::IServiceManager;
+ using ::android::hardware::hidl_string;
+ using ::android::hardware::Return;
+
+ sp<IServiceManager> sm = ::android::hardware::defaultServiceManager();
+
+ if (sm == nullptr) {
+ fprintf(stderr, "failed to get IServiceManager to poke hal services\n");
+ return;
+ }
+
+ auto listRet = sm->list([&](const auto &interfaces) {
+ for (size_t i = 0; i < interfaces.size(); i++) {
+ string fqInstanceName = interfaces[i];
+ string::size_type n = fqInstanceName.find("/");
+ if (n == std::string::npos || interfaces[i].size() == n+1)
+ continue;
+ hidl_string fqInterfaceName = fqInstanceName.substr(0, n);
+ hidl_string instanceName = fqInstanceName.substr(n+1, std::string::npos);
+ Return<sp<IBase>> interfaceRet = sm->get(fqInterfaceName, instanceName);
+ if (!interfaceRet.isOk()) {
+ // ignore
+ continue;
+ }
+ sp<IBase> interface = interfaceRet;
+ auto notifyRet = interface->notifySyspropsChanged();
+ if (!notifyRet.isOk()) {
+ // ignore
+ }
+ }
+ });
+ if (!listRet.isOk()) {
+ // TODO(b/34242478) fix this when we determine the correct ACL
+ //fprintf(stderr, "failed to list services: %s\n", listRet.description().c_str());
+ }
+}
+
// Set the trace tags that userland tracing uses, and poke the running
// processes to pick up the new value.
static bool setTagsProperty(uint64_t tags)
{
- char buf[PROPERTY_VALUE_MAX];
- snprintf(buf, sizeof(buf), "%#" PRIx64, tags);
- if (property_set(k_traceTagsProperty, buf) < 0) {
+ std::string value = android::base::StringPrintf("%#" PRIx64, tags);
+ if (!android::base::SetProperty(k_traceTagsProperty, value)) {
fprintf(stderr, "error setting trace tags system property\n");
return false;
}
@@ -518,14 +577,13 @@
static void clearAppProperties()
{
- char buf[PROPERTY_KEY_MAX];
for (int i = 0; i < MAX_PACKAGES; i++) {
- snprintf(buf, sizeof(buf), k_traceAppsPropertyTemplate, i);
- if (property_set(buf, "") < 0) {
- fprintf(stderr, "failed to clear system property: %s\n", buf);
+ std::string key = android::base::StringPrintf(k_traceAppsPropertyTemplate, i);
+ if (!android::base::SetProperty(key, "")) {
+ fprintf(stderr, "failed to clear system property: %s\n", key.c_str());
}
}
- if (property_set(k_traceAppsNumberProperty, "") < 0) {
+ if (!android::base::SetProperty(k_traceAppsNumberProperty, "")) {
fprintf(stderr, "failed to clear system property: %s",
k_traceAppsNumberProperty);
}
@@ -533,11 +591,10 @@
// Set the system property that indicates which apps should perform
// application-level tracing.
-static bool setAppCmdlineProperty(const char* cmdline)
+static bool setAppCmdlineProperty(char* cmdline)
{
- char buf[PROPERTY_KEY_MAX];
int i = 0;
- const char* start = cmdline;
+ char* start = cmdline;
while (start != NULL) {
if (i == MAX_PACKAGES) {
fprintf(stderr, "error: only 16 packages could be traced at once\n");
@@ -549,9 +606,9 @@
*end = '\0';
end++;
}
- snprintf(buf, sizeof(buf), k_traceAppsPropertyTemplate, i);
- if (property_set(buf, start) < 0) {
- fprintf(stderr, "error setting trace app %d property to %s\n", i, buf);
+ std::string key = android::base::StringPrintf(k_traceAppsPropertyTemplate, i);
+ if (!android::base::SetProperty(key, start)) {
+ fprintf(stderr, "error setting trace app %d property to %s\n", i, key.c_str());
clearAppProperties();
return false;
}
@@ -559,9 +616,9 @@
i++;
}
- snprintf(buf, sizeof(buf), "%d", i);
- if (property_set(k_traceAppsNumberProperty, buf) < 0) {
- fprintf(stderr, "error setting trace app number property to %s\n", buf);
+ std::string value = android::base::StringPrintf("%d", i);
+ if (!android::base::SetProperty(k_traceAppsNumberProperty, value)) {
+ fprintf(stderr, "error setting trace app number property to %s\n", value.c_str());
clearAppProperties();
return false;
}
@@ -571,7 +628,7 @@
// Disable all /sys/ enable files.
static bool disableKernelTraceEvents() {
bool ok = true;
- for (int i = 0; i < NELEM(k_categories); i++) {
+ for (size_t i = 0; i < arraysize(k_categories); i++) {
const TracingCategory &c = k_categories[i];
for (int j = 0; j < MAX_SYS_FILES; j++) {
const char* path = c.sysfiles[j].path;
@@ -587,24 +644,14 @@
// kernel.
static bool verifyKernelTraceFuncs(const char* funcs)
{
- int fd = open(k_ftraceFilterPath, O_RDONLY);
- if (fd == -1) {
- fprintf(stderr, "error opening %s: %s (%d)\n", k_ftraceFilterPath,
+ std::string buf;
+ if (!android::base::ReadFileToString(g_traceFolder + k_ftraceFilterPath, &buf)) {
+ fprintf(stderr, "error opening %s: %s (%d)\n", k_ftraceFilterPath,
strerror(errno), errno);
- return false;
+ return false;
}
- char buf[4097];
- ssize_t n = read(fd, buf, 4096);
- close(fd);
- if (n == -1) {
- fprintf(stderr, "error reading %s: %s (%d)\n", k_ftraceFilterPath,
- strerror(errno), errno);
- return false;
- }
-
- buf[n] = '\0';
- String8 funcList = String8::format("\n%s", buf);
+ String8 funcList = String8::format("\n%s",buf.c_str());
// Make sure that every function listed in funcs is in the list we just
// read from the kernel, except for wildcard inputs.
@@ -624,7 +671,6 @@
func = strtok(NULL, ",");
}
free(myFuncs);
-
return ok;
}
@@ -670,7 +716,7 @@
static bool setCategoryEnable(const char* name, bool enable)
{
- for (int i = 0; i < NELEM(k_categories); i++) {
+ for (size_t i = 0; i < arraysize(k_categories); i++) {
const TracingCategory& c = k_categories[i];
if (strcmp(name, c.name) == 0) {
if (isCategorySupported(c)) {
@@ -730,7 +776,7 @@
// Set up the tags property.
uint64_t tags = 0;
- for (int i = 0; i < NELEM(k_categories); i++) {
+ for (size_t i = 0; i < arraysize(k_categories); i++) {
if (g_categoryEnables[i]) {
const TracingCategory &c = k_categories[i];
tags |= c.tags;
@@ -739,7 +785,7 @@
ok &= setTagsProperty(tags);
bool coreServicesTagEnabled = false;
- for (int i = 0; i < NELEM(k_categories); i++) {
+ for (size_t i = 0; i < arraysize(k_categories); i++) {
if (strcmp(k_categories[i].name, k_coreServiceCategory) == 0) {
coreServicesTagEnabled = g_categoryEnables[i];
}
@@ -747,22 +793,21 @@
std::string packageList(g_debugAppCmdLine);
if (coreServicesTagEnabled) {
- char value[PROPERTY_VALUE_MAX];
- property_get(k_coreServicesProp, value, "");
if (!packageList.empty()) {
packageList += ",";
}
- packageList += value;
+ packageList += android::base::GetProperty(k_coreServicesProp, "");
}
- ok &= setAppCmdlineProperty(packageList.data());
+ ok &= setAppCmdlineProperty(&packageList[0]);
ok &= pokeBinderServices();
+ pokeHalServices();
// Disable all the sysfs enables. This is done as a separate loop from
// the enables to allow the same enable to exist in multiple categories.
ok &= disableKernelTraceEvents();
// Enable all the sysfs enables that are in an enabled category.
- for (int i = 0; i < NELEM(k_categories); i++) {
+ for (size_t i = 0; i < arraysize(k_categories); i++) {
if (g_categoryEnables[i]) {
const TracingCategory &c = k_categories[i];
for (int j = 0; j < MAX_SYS_FILES; j++) {
@@ -819,7 +864,7 @@
static void streamTrace()
{
char trace_data[4096];
- int traceFD = open(k_traceStreamPath, O_RDWR);
+ int traceFD = open((g_traceFolder + k_traceStreamPath).c_str(), O_RDWR);
if (traceFD == -1) {
fprintf(stderr, "error opening %s: %s (%d)\n", k_traceStreamPath,
strerror(errno), errno);
@@ -844,7 +889,7 @@
static void dumpTrace(int outFd)
{
ALOGI("Dumping trace");
- int traceFD = open(k_tracePath, O_RDWR);
+ int traceFD = open((g_traceFolder + k_tracePath).c_str(), O_RDWR);
if (traceFD == -1) {
fprintf(stderr, "error opening %s: %s (%d)\n", k_tracePath,
strerror(errno), errno);
@@ -853,30 +898,34 @@
if (g_compress) {
z_stream zs;
- uint8_t *in, *out;
- int result, flush;
-
memset(&zs, 0, sizeof(zs));
- result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
+
+ int result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
if (result != Z_OK) {
fprintf(stderr, "error initializing zlib: %d\n", result);
close(traceFD);
return;
}
- const size_t bufSize = 64*1024;
- in = (uint8_t*)malloc(bufSize);
- out = (uint8_t*)malloc(bufSize);
- flush = Z_NO_FLUSH;
+ constexpr size_t bufSize = 64*1024;
+ std::unique_ptr<uint8_t> in(new uint8_t[bufSize]);
+ std::unique_ptr<uint8_t> out(new uint8_t[bufSize]);
+ if (!in || !out) {
+ fprintf(stderr, "couldn't allocate buffers\n");
+ close(traceFD);
+ return;
+ }
- zs.next_out = out;
+ int flush = Z_NO_FLUSH;
+
+ zs.next_out = reinterpret_cast<Bytef*>(out.get());
zs.avail_out = bufSize;
do {
if (zs.avail_in == 0) {
// More input is needed.
- result = read(traceFD, in, bufSize);
+ result = read(traceFD, in.get(), bufSize);
if (result < 0) {
fprintf(stderr, "error reading trace: %s (%d)\n",
strerror(errno), errno);
@@ -885,14 +934,14 @@
} else if (result == 0) {
flush = Z_FINISH;
} else {
- zs.next_in = in;
+ zs.next_in = reinterpret_cast<Bytef*>(in.get());
zs.avail_in = result;
}
}
if (zs.avail_out == 0) {
// Need to write the output.
- result = write(outFd, out, bufSize);
+ result = write(outFd, out.get(), bufSize);
if ((size_t)result < bufSize) {
fprintf(stderr, "error writing deflated trace: %s (%d)\n",
strerror(errno), errno);
@@ -900,7 +949,7 @@
zs.avail_out = bufSize; // skip the final write
break;
}
- zs.next_out = out;
+ zs.next_out = reinterpret_cast<Bytef*>(out.get());
zs.avail_out = bufSize;
}
@@ -912,7 +961,7 @@
if (zs.avail_out < bufSize) {
size_t bytes = bufSize - zs.avail_out;
- result = write(outFd, out, bytes);
+ result = write(outFd, out.get(), bytes);
if ((size_t)result < bytes) {
fprintf(stderr, "error writing deflated trace: %s (%d)\n",
strerror(errno), errno);
@@ -923,15 +972,17 @@
if (result != Z_OK) {
fprintf(stderr, "error cleaning up zlib: %d\n", result);
}
-
- free(in);
- free(out);
} else {
- ssize_t sent = 0;
- while ((sent = sendfile(outFd, traceFD, NULL, 64*1024*1024)) > 0);
- if (sent == -1) {
- fprintf(stderr, "error dumping trace: %s (%d)\n", strerror(errno),
- errno);
+ char buf[4096];
+ ssize_t rc;
+ while ((rc = TEMP_FAILURE_RETRY(read(traceFD, buf, sizeof(buf)))) > 0) {
+ if (!android::base::WriteFully(outFd, buf, rc)) {
+ fprintf(stderr, "error writing trace: %s\n", strerror(errno));
+ break;
+ }
+ }
+ if (rc == -1) {
+ fprintf(stderr, "error dumping trace: %s\n", strerror(errno));
}
}
@@ -959,7 +1010,7 @@
static void listSupportedCategories()
{
- for (int i = 0; i < NELEM(k_categories); i++) {
+ for (size_t i = 0; i < arraysize(k_categories); i++) {
const TracingCategory& c = k_categories[i];
if (isCategorySupported(c)) {
printf(" %10s - %s\n", c.name, c.longname);
@@ -981,7 +1032,7 @@
" -k fname,... trace the listed kernel functions\n"
" -n ignore signals\n"
" -s N sleep for N seconds before tracing [default 0]\n"
- " -t N trace for N seconds [defualt 5]\n"
+ " -t N trace for N seconds [default 5]\n"
" -z compress the trace dump\n"
" --async_start start circular trace and return immediatly\n"
" --async_dump dump the current contents of circular trace buffer\n"
@@ -998,6 +1049,29 @@
);
}
+bool findTraceFiles()
+{
+ static const std::string debugfs_path = "/sys/kernel/debug/tracing/";
+ static const std::string tracefs_path = "/sys/kernel/tracing/";
+ static const std::string trace_file = "trace_marker";
+
+ bool tracefs = access((tracefs_path + trace_file).c_str(), F_OK) != -1;
+ bool debugfs = access((debugfs_path + trace_file).c_str(), F_OK) != -1;
+
+ if (!tracefs && !debugfs) {
+ fprintf(stderr, "Error: Did not find trace folder\n");
+ return false;
+ }
+
+ if (tracefs) {
+ g_traceFolder = tracefs_path;
+ } else {
+ g_traceFolder = debugfs_path;
+ }
+
+ return true;
+}
+
int main(int argc, char **argv)
{
bool async = false;
@@ -1011,6 +1085,11 @@
exit(0);
}
+ if (!findTraceFiles()) {
+ fprintf(stderr, "No trace folder found\n");
+ exit(-1);
+ }
+
for (;;) {
int ret;
int option_index = 0;
@@ -1158,7 +1237,7 @@
fflush(stdout);
int outFd = STDOUT_FILENO;
if (g_outputFile) {
- outFd = open(g_outputFile, O_WRONLY | O_CREAT);
+ outFd = open(g_outputFile, O_WRONLY | O_CREAT | O_TRUNC, 0644);
}
if (outFd == -1) {
printf("Failed to open '%s', err=%d", g_outputFile, errno);
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 747cc69..cef41be 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -4,63 +4,131 @@
# Allow writing to the kernel trace log.
chmod 0222 /sys/kernel/debug/tracing/trace_marker
+ chmod 0222 /sys/kernel/tracing/trace_marker
# Allow the shell group to enable (some) kernel tracing.
chown root shell /sys/kernel/debug/tracing/trace_clock
+ chown root shell /sys/kernel/tracing/trace_clock
chown root shell /sys/kernel/debug/tracing/buffer_size_kb
+ chown root shell /sys/kernel/tracing/buffer_size_kb
chown root shell /sys/kernel/debug/tracing/options/overwrite
+ chown root shell /sys/kernel/tracing/options/overwrite
chown root shell /sys/kernel/debug/tracing/options/print-tgid
+ chown root shell /sys/kernel/tracing/options/print-tgid
chown root shell /sys/kernel/debug/tracing/events/sched/sched_switch/enable
+ chown root shell /sys/kernel/tracing/events/sched/sched_switch/enable
chown root shell /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
+ chown root shell /sys/kernel/tracing/events/sched/sched_wakeup/enable
chown root shell /sys/kernel/debug/tracing/events/sched/sched_blocked_reason/enable
+ chown root shell /sys/kernel/tracing/events/sched/sched_blocked_reason/enable
chown root shell /sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug/enable
+ chown root shell /sys/kernel/tracing/events/sched/sched_cpu_hotplug/enable
chown root shell /sys/kernel/debug/tracing/events/power/cpu_frequency/enable
+ chown root shell /sys/kernel/tracing/events/power/cpu_frequency/enable
chown root shell /sys/kernel/debug/tracing/events/power/cpu_idle/enable
+ chown root shell /sys/kernel/tracing/events/power/cpu_idle/enable
chown root shell /sys/kernel/debug/tracing/events/power/clock_set_rate/enable
+ chown root shell /sys/kernel/tracing/events/power/clock_set_rate/enable
chown root shell /sys/kernel/debug/tracing/events/power/cpu_frequency_limits/enable
+ chown root shell /sys/kernel/tracing/events/power/cpu_frequency_limits/enable
chown root shell /sys/kernel/debug/tracing/events/cpufreq_interactive/enable
+ chown root shell /sys/kernel/tracing/events/cpufreq_interactive/enable
chown root shell /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
+ chown root shell /sys/kernel/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
chown root shell /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable
+ chown root shell /sys/kernel/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable
chown root shell /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable
+ chown root shell /sys/kernel/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable
chown root shell /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable
+ chown root shell /sys/kernel/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable
chown root shell /sys/kernel/debug/tracing/events/binder/binder_transaction/enable
+ chown root shell /sys/kernel/tracing/events/binder/binder_transaction/enable
chown root shell /sys/kernel/debug/tracing/events/binder/binder_transaction_received/enable
+ chown root shell /sys/kernel/tracing/events/binder/binder_transaction_received/enable
chown root shell /sys/kernel/debug/tracing/events/binder/binder_lock/enable
+ chown root shell /sys/kernel/tracing/events/binder/binder_lock/enable
chown root shell /sys/kernel/debug/tracing/events/binder/binder_locked/enable
+ chown root shell /sys/kernel/tracing/events/binder/binder_locked/enable
chown root shell /sys/kernel/debug/tracing/events/binder/binder_unlock/enable
+ chown root shell /sys/kernel/tracing/events/binder/binder_unlock/enable
chown root shell /sys/kernel/debug/tracing/tracing_on
+ chown root shell /sys/kernel/tracing/tracing_on
chmod 0664 /sys/kernel/debug/tracing/trace_clock
+ chmod 0664 /sys/kernel/tracing/trace_clock
chmod 0664 /sys/kernel/debug/tracing/buffer_size_kb
+ chmod 0664 /sys/kernel/tracing/buffer_size_kb
chmod 0664 /sys/kernel/debug/tracing/options/overwrite
+ chmod 0664 /sys/kernel/tracing/options/overwrite
chmod 0664 /sys/kernel/debug/tracing/options/print-tgid
+ chmod 0664 /sys/kernel/tracing/options/print-tgid
chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_switch/enable
+ chmod 0664 /sys/kernel/tracing/events/sched/sched_switch/enable
chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
+ chmod 0664 /sys/kernel/tracing/events/sched/sched_wakeup/enable
chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_blocked_reason/enable
+ chmod 0664 /sys/kernel/tracing/events/sched/sched_blocked_reason/enable
chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_cpu_hotplug/enable
+ chmod 0664 /sys/kernel/tracing/events/sched/sched_cpu_hotplug/enable
chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_frequency/enable
+ chmod 0664 /sys/kernel/tracing/events/power/cpu_frequency/enable
chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_idle/enable
+ chmod 0664 /sys/kernel/tracing/events/power/cpu_idle/enable
chmod 0664 /sys/kernel/debug/tracing/events/power/clock_set_rate/enable
+ chmod 0664 /sys/kernel/tracing/events/power/clock_set_rate/enable
chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_frequency_limits/enable
+ chmod 0664 /sys/kernel/tracing/events/power/cpu_frequency_limits/enable
chmod 0664 /sys/kernel/debug/tracing/events/cpufreq_interactive/enable
+ chmod 0664 /sys/kernel/tracing/events/cpufreq_interactive/enable
chmod 0664 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
+ chmod 0664 /sys/kernel/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
chmod 0664 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable
+ chmod 0664 /sys/kernel/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable
chmod 0664 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable
+ chmod 0664 /sys/kernel/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable
chmod 0664 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable
+ chmod 0664 /sys/kernel/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable
chmod 0664 /sys/kernel/debug/tracing/tracing_on
+ chmod 0664 /sys/kernel/tracing/tracing_on
chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_transaction/enable
+ chmod 0664 /sys/kernel/tracing/events/binder/binder_transaction/enable
chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_transaction_received/enable
+ chmod 0664 /sys/kernel/tracing/events/binder/binder_transaction_received/enable
chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_lock/enable
+ chmod 0664 /sys/kernel/tracing/events/binder/binder_lock/enable
chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_locked/enable
+ chmod 0664 /sys/kernel/tracing/events/binder/binder_locked/enable
chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_unlock/enable
+ chmod 0664 /sys/kernel/tracing/events/binder/binder_unlock/enable
+ chmod 0664 /sys/kernel/debug/tracing/events/i2c/enable
+ chmod 0664 /sys/kernel/tracing/events/i2c/enable
+ chmod 0664 /sys/kernel/debug/tracing/events/i2c/i2c_read/enable
+ chmod 0664 /sys/kernel/tracing/events/i2c/i2c_read/enable
+ chmod 0664 /sys/kernel/debug/tracing/events/i2c/i2c_write/enable
+ chmod 0664 /sys/kernel/tracing/events/i2c/i2c_write/enable
+ chmod 0664 /sys/kernel/debug/tracing/events/i2c/i2c_result/enable
+ chmod 0664 /sys/kernel/tracing/events/i2c/i2c_result/enable
+ chmod 0664 /sys/kernel/debug/tracing/events/i2c/i2c_reply/enable
+ chmod 0664 /sys/kernel/tracing/events/i2c/i2c_reply/enable
+ chmod 0664 /sys/kernel/debug/tracing/events/i2c/smbus_read/enable
+ chmod 0664 /sys/kernel/tracing/events/i2c/smbus_read/enable
+ chmod 0664 /sys/kernel/debug/tracing/events/i2c/smbus_write/enable
+ chmod 0664 /sys/kernel/tracing/events/i2c/smbus_write/enable
+ chmod 0664 /sys/kernel/debug/tracing/events/i2c/smbus_result/enable
+ chmod 0664 /sys/kernel/tracing/events/i2c/smbus_result/enable
+ chmod 0664 /sys/kernel/debug/tracing/events/i2c/smbus_reply/enable
+ chmod 0664 /sys/kernel/tracing/events/i2c/smbus_reply/enable
# Tracing disabled by default
write /sys/kernel/debug/tracing/tracing_on 0
+ write /sys/kernel/tracing/tracing_on 0
# Allow only the shell group to read and truncate the kernel trace.
chown root shell /sys/kernel/debug/tracing/trace
+ chown root shell /sys/kernel/tracing/trace
chmod 0660 /sys/kernel/debug/tracing/trace
+ chmod 0660 /sys/kernel/tracing/trace
on property:persist.debug.atrace.boottrace=1
start boottrace
diff --git a/cmds/bugreport/Android.bp b/cmds/bugreport/Android.bp
new file mode 100644
index 0000000..139e4b2
--- /dev/null
+++ b/cmds/bugreport/Android.bp
@@ -0,0 +1,6 @@
+cc_binary {
+ name: "bugreport",
+ srcs: ["bugreport.cpp"],
+ cflags: ["-Wall"],
+ shared_libs: ["libcutils"],
+}
diff --git a/cmds/bugreport/Android.mk b/cmds/bugreport/Android.mk
deleted file mode 100644
index ced5d30..0000000
--- a/cmds/bugreport/Android.mk
+++ /dev/null
@@ -1,12 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= bugreport.cpp
-
-LOCAL_MODULE:= bugreport
-
-LOCAL_CFLAGS := -Wall
-
-LOCAL_SHARED_LIBRARIES := libcutils
-
-include $(BUILD_EXECUTABLE)
diff --git a/cmds/bugreportz/readme.md b/cmds/bugreportz/readme.md
index 2697f09..eb0d898 100644
--- a/cmds/bugreportz/readme.md
+++ b/cmds/bugreportz/readme.md
@@ -17,3 +17,4 @@
- `OK:<path_to_bugreport_file>` in case of success.
- `FAIL:<error message>` in case of failure.
+
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
new file mode 100644
index 0000000..3db41c2
--- /dev/null
+++ b/cmds/dumpstate/Android.bp
@@ -0,0 +1,4 @@
+cc_library_static {
+ name: "libdumpstate.default",
+ srcs: ["libdumpstate_default.cpp"],
+}
diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk
index 791a7c4..40484ef 100644
--- a/cmds/dumpstate/Android.mk
+++ b/cmds/dumpstate/Android.mk
@@ -1,22 +1,14 @@
LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := libdumpstate_default.cpp
-LOCAL_MODULE := libdumpstate.default
-include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
-ifdef BOARD_WLAN_DEVICE
-LOCAL_CFLAGS := -DFWDUMP_$(BOARD_WLAN_DEVICE)
-endif
-
LOCAL_SRC_FILES := dumpstate.cpp utils.cpp
LOCAL_MODULE := dumpstate
-LOCAL_SHARED_LIBRARIES := libcutils liblog libselinux libbase
+LOCAL_SHARED_LIBRARIES := libcutils libdebuggerd_client liblog libselinux libbase
# ZipArchive support, the order matters here to get all symbols.
-LOCAL_STATIC_LIBRARIES := libziparchive libz libmincrypt
+LOCAL_STATIC_LIBRARIES := libziparchive libz libcrypto
LOCAL_HAL_STATIC_LIBRARIES := libdumpstate
LOCAL_CFLAGS += -Wall -Werror -Wno-unused-parameter
LOCAL_INIT_RC := dumpstate.rc
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 0929d9b..bb56984 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#define LOG_TAG "dumpstate"
#include <dirent.h>
#include <errno.h>
@@ -37,18 +38,16 @@
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
#include <cutils/properties.h>
-#include "private/android_filesystem_config.h"
-
-#define LOG_TAG "dumpstate"
-#include <cutils/log.h>
+#include <private/android_filesystem_config.h>
+#include <private/android_logger.h>
#include "dumpstate.h"
-#include "ScopedFd.h"
#include "ziparchive/zip_writer.h"
-#include "mincrypt/sha256.h"
+#include <openssl/sha.h>
using android::base::StringPrintf;
@@ -646,102 +645,14 @@
return 0;
}
-/* Copied policy from system/core/logd/LogBuffer.cpp */
-
-#define LOG_BUFFER_SIZE (256 * 1024)
-#define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
-#define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
-
-static bool valid_size(unsigned long value) {
- if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) {
- return false;
- }
-
- long pages = sysconf(_SC_PHYS_PAGES);
- if (pages < 1) {
- return true;
- }
-
- long pagesize = sysconf(_SC_PAGESIZE);
- if (pagesize <= 1) {
- pagesize = PAGE_SIZE;
- }
-
- // maximum memory impact a somewhat arbitrary ~3%
- pages = (pages + 31) / 32;
- unsigned long maximum = pages * pagesize;
-
- if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) {
- return true;
- }
-
- return value <= maximum;
-}
-
-static unsigned long property_get_size(const char *key) {
- unsigned long value;
- char *cp, property[PROPERTY_VALUE_MAX];
-
- property_get(key, property, "");
- value = strtoul(property, &cp, 10);
-
- switch(*cp) {
- case 'm':
- case 'M':
- value *= 1024;
- /* FALLTHRU */
- case 'k':
- case 'K':
- value *= 1024;
- /* FALLTHRU */
- case '\0':
- break;
-
- default:
- value = 0;
- }
-
- if (!valid_size(value)) {
- value = 0;
- }
-
- return value;
-}
-
/* timeout in ms */
static unsigned long logcat_timeout(const char *name) {
- static const char global_tuneable[] = "persist.logd.size"; // Settings App
- static const char global_default[] = "ro.logd.size"; // BoardConfig.mk
- char key[PROP_NAME_MAX];
- unsigned long property_size, default_size;
-
- default_size = property_get_size(global_tuneable);
- if (!default_size) {
- default_size = property_get_size(global_default);
- }
-
- snprintf(key, sizeof(key), "%s.%s", global_tuneable, name);
- property_size = property_get_size(key);
-
- if (!property_size) {
- snprintf(key, sizeof(key), "%s.%s", global_default, name);
- property_size = property_get_size(key);
- }
-
- if (!property_size) {
- property_size = default_size;
- }
-
- if (!property_size) {
- property_size = LOG_BUFFER_SIZE;
- }
-
+ log_id_t id = android_name_to_log_id(name);
+ unsigned long property_size = __android_logger_get_buffer_size(id);
/* Engineering margin is ten-fold our guess */
return 10 * (property_size + worst_write_perf) / worst_write_perf;
}
-/* End copy from system/core/logd/LogBuffer.cpp */
-
/* dumps the current system state to stdout */
static void print_header(std::string version) {
char build[PROPERTY_VALUE_MAX], fingerprint[PROPERTY_VALUE_MAX];
@@ -838,8 +749,9 @@
}
bool add_zip_entry(const std::string& entry_name, const std::string& entry_path) {
- ScopedFd fd(TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
- if (fd.get() == -1) {
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(entry_path.c_str(), O_RDONLY | O_NONBLOCK
+ | O_CLOEXEC)));
+ if (fd == -1) {
MYLOGE("open(%s): %s\n", entry_path.c_str(), strerror(errno));
return false;
}
@@ -971,7 +883,8 @@
dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
dump_file("MEMORY INFO", "/proc/meminfo");
- run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-H", NULL);
+ run_command("CPU INFO", 10, "top", "-b", "-n", "1", "-H", "-s", "6",
+ "-o", "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name", NULL);
run_command("PROCRANK", 20, SU_PATH, "root", "procrank", NULL);
dump_file("VIRTUAL MEMORY STATS", "/proc/vmstat");
dump_file("VMALLOC INFO", "/proc/vmallocinfo");
@@ -985,11 +898,12 @@
dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
dump_file("KERNEL SYNC", "/d/sync");
- run_command("PROCESSES AND THREADS", 10, "ps", "-Z", "-t", "-p", "-P", NULL);
+ run_command("PROCESSES AND THREADS", 10, "ps", "-A", "-T", "-Z",
+ "-O", "pri,nice,rtprio,sched,pcy", NULL);
run_command("LIBRANK", 10, SU_PATH, "root", "librank", NULL);
run_command("PRINTENV", 10, "printenv", NULL);
- run_command("NETSTAT", 10, "netstat", "-n", NULL);
+ run_command("NETSTAT", 10, "netstat", "-nW", NULL);
run_command("LSMOD", 10, "lsmod", NULL);
do_dmesg();
@@ -1095,34 +1009,13 @@
run_command("MULTICAST ADDRESSES", 10, "ip", "maddr", NULL);
run_command("WIFI NETWORKS", 20, "wpa_cli", "IFNAME=wlan0", "list_networks", NULL);
-#ifdef FWDUMP_bcmdhd
- run_command("ND OFFLOAD TABLE", 5,
- SU_PATH, "root", WLUTIL, "nd_hostip", NULL);
-
- run_command("DUMP WIFI INTERNAL COUNTERS (1)", 20,
- SU_PATH, "root", WLUTIL, "counters", NULL);
-
- run_command("ND OFFLOAD STATUS (1)", 5,
- SU_PATH, "root", WLUTIL, "nd_status", NULL);
-
-#endif
dump_file("INTERRUPTS (1)", "/proc/interrupts");
run_command("NETWORK DIAGNOSTICS", 10, "dumpsys", "-t", "10", "connectivity", "--diag", NULL);
-#ifdef FWDUMP_bcmdhd
- run_command("DUMP WIFI STATUS", 20,
- SU_PATH, "root", "dhdutil", "-i", "wlan0", "dump", NULL);
-
- run_command("DUMP WIFI INTERNAL COUNTERS (2)", 20,
- SU_PATH, "root", WLUTIL, "counters", NULL);
-
- run_command("ND OFFLOAD STATUS (2)", 5,
- SU_PATH, "root", WLUTIL, "nd_status", NULL);
-#endif
dump_file("INTERRUPTS (2)", "/proc/interrupts");
- print_properties();
+ run_command("SYSTEM PROPERTIES", 5, "getprop", NULL);
run_command("VOLD DUMP", 10, "vdc", "dump", NULL);
run_command("SECURE CONTAINERS", 10, "vdc", "asec", "list", NULL);
@@ -1284,15 +1177,15 @@
}
static std::string SHA256_file_hash(std::string filepath) {
- ScopedFd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC
- | O_NOFOLLOW)));
- if (fd.get() == -1) {
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(filepath.c_str(), O_RDONLY | O_NONBLOCK
+ | O_CLOEXEC | O_NOFOLLOW)));
+ if (fd == -1) {
MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
return NULL;
}
SHA256_CTX ctx;
- SHA256_init(&ctx);
+ SHA256_Init(&ctx);
std::vector<uint8_t> buffer(65536);
while (1) {
@@ -1304,13 +1197,14 @@
return NULL;
}
- SHA256_update(&ctx, buffer.data(), bytes_read);
+ SHA256_Update(&ctx, buffer.data(), bytes_read);
}
- uint8_t hash[SHA256_DIGEST_SIZE];
- memcpy(hash, SHA256_final(&ctx), SHA256_DIGEST_SIZE);
- char hash_buffer[SHA256_DIGEST_SIZE * 2 + 1];
- for(size_t i = 0; i < SHA256_DIGEST_SIZE; i++) {
+ uint8_t hash[SHA256_DIGEST_LENGTH];
+ SHA256_Final(hash, &ctx);
+
+ char hash_buffer[SHA256_DIGEST_LENGTH * 2 + 1];
+ for(size_t i = 0; i < SHA256_DIGEST_LENGTH; i++) {
sprintf(hash_buffer + (i * 2), "%02x", hash[i]);
}
hash_buffer[sizeof(hash_buffer) - 1] = 0;
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 514af59..0b6aaab 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -145,9 +145,6 @@
/* updates the overall progress of dumpstate by the given weight increment */
void update_progress(int weight);
-/* prints all the system properties */
-void print_properties();
-
/** opens a socket and returns its file descriptor */
int open_socket(const char *service);
@@ -221,7 +218,7 @@
*/
class DurationReporter {
public:
- DurationReporter(const char *title);
+ explicit DurationReporter(const char *title);
DurationReporter(const char *title, FILE* out);
~DurationReporter();
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index af6c666..6ec636e 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "dumpstate"
+
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
@@ -23,27 +25,25 @@
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string>
#include <string.h>
#include <sys/capability.h>
#include <sys/inotify.h>
+#include <sys/klog.h>
+#include <sys/prctl.h>
#include <sys/stat.h>
-#include <sys/sysconf.h>
#include <sys/time.h>
#include <sys/wait.h>
-#include <sys/klog.h>
#include <time.h>
#include <unistd.h>
-#include <vector>
-#include <sys/prctl.h>
-#define LOG_TAG "dumpstate"
+#include <string>
+#include <vector>
#include <android-base/file.h>
-#include <cutils/debugger.h>
-#include <cutils/log.h>
#include <cutils/properties.h>
#include <cutils/sockets.h>
+#include <debuggerd/client.h>
+#include <log/log.h>
#include <private/android_filesystem_config.h>
#include <selinux/android.h>
@@ -181,7 +181,7 @@
void for_each_pid(for_each_pid_func func, const char *header) {
ON_DRY_RUN_RETURN();
- __for_each_pid(for_each_pid_helper, header, (void *)func);
+ __for_each_pid(for_each_pid_helper, header, (void *) func);
}
static void for_each_tid_helper(int pid, const char *cmdline, void *arg) {
@@ -578,6 +578,7 @@
* stuck.
*/
int dump_file_from_fd(const char *title, const char *path, int fd) {
+ ON_DRY_RUN_RETURN(0);
int flags = fcntl(fd, F_GETFL);
if (flags == -1) {
printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
@@ -828,8 +829,7 @@
}
gid_t groups[] = { AID_LOG, AID_SDCARD_R, AID_SDCARD_RW,
- AID_MOUNT, AID_INET, AID_NET_BW_STATS, AID_READPROC,
- AID_BLUETOOTH };
+ AID_MOUNT, AID_INET, AID_NET_BW_STATS, AID_READPROC, AID_BLUETOOTH };
if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
MYLOGE("Unable to setgroups, aborting: %s\n", strerror(errno));
return false;
@@ -882,40 +882,6 @@
run_command_always(NULL, DROP_ROOT, REDIRECT_TO_STDERR, 20, am_args);
}
-size_t num_props = 0;
-static char* props[2000];
-
-static void print_prop(const char *key, const char *name, void *user) {
- (void) user;
- if (num_props < sizeof(props) / sizeof(props[0])) {
- char buf[PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX + 10];
- snprintf(buf, sizeof(buf), "[%s]: [%s]\n", key, name);
- props[num_props++] = strdup(buf);
- }
-}
-
-static int compare_prop(const void *a, const void *b) {
- return strcmp(*(char * const *) a, *(char * const *) b);
-}
-
-/* prints all the system properties */
-void print_properties() {
- const char* title = "SYSTEM PROPERTIES";
- DurationReporter duration_reporter(title);
- printf("------ %s ------\n", title);
- ON_DRY_RUN_RETURN();
- size_t i;
- num_props = 0;
- property_list(print_prop, NULL);
- qsort(&props, num_props, sizeof(props[0]), compare_prop);
-
- for (i = 0; i < num_props; ++i) {
- fputs(props[i], stdout);
- free(props[i]);
- }
- printf("\n");
-}
-
int open_socket(const char *service) {
int s = android_get_control_socket(service);
if (s < 0) {
@@ -1018,8 +984,10 @@
}
/* create a new, empty traces.txt file to receive stack dumps */
- int fd = TEMP_FAILURE_RETRY(open(traces_path, O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW | O_CLOEXEC,
- 0666)); /* -rw-rw-rw- */
+ int fd = TEMP_FAILURE_RETRY(
+ open(traces_path,
+ O_CREAT | O_WRONLY | O_APPEND | O_TRUNC | O_NOFOLLOW | O_CLOEXEC,
+ 0666)); /* -rw-rw-rw- */
if (fd < 0) {
MYLOGE("%s: %s\n", traces_path, strerror(errno));
return NULL;
diff --git a/cmds/dumpsys/.clang-format b/cmds/dumpsys/.clang-format
new file mode 100644
index 0000000..fc4eb1b
--- /dev/null
+++ b/cmds/dumpsys/.clang-format
@@ -0,0 +1,13 @@
+BasedOnStyle: Google
+AllowShortBlocksOnASingleLine: false
+AllowShortFunctionsOnASingleLine: false
+
+AccessModifierOffset: -2
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+IndentWidth: 4
+PointerAlignment: Left
+TabWidth: 4
+UseTab: Never
+PenaltyExcessCharacter: 32
diff --git a/cmds/dumpsys/Android.bp b/cmds/dumpsys/Android.bp
new file mode 100644
index 0000000..3476964
--- /dev/null
+++ b/cmds/dumpsys/Android.bp
@@ -0,0 +1,50 @@
+cc_defaults {
+ name: "dumpsys_defaults",
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+
+ srcs: [
+ "dumpsys.cpp",
+ ],
+
+ shared_libs: [
+ "libbase",
+ "libutils",
+ "liblog",
+ "libbinder",
+ ],
+
+ clang: true,
+}
+
+//
+// Static library used in testing and executable
+//
+
+cc_library_static {
+ name: "libdumpsys",
+
+ defaults: ["dumpsys_defaults"],
+
+ export_include_dirs: ["."],
+}
+
+
+//
+// Executable
+//
+
+cc_binary {
+ name: "dumpsys",
+
+ defaults: ["dumpsys_defaults"],
+
+ srcs: [
+ "main.cpp",
+ ],
+}
+
+subdirs = ["tests"]
diff --git a/cmds/dumpsys/Android.mk b/cmds/dumpsys/Android.mk
deleted file mode 100644
index 8335c14..0000000
--- a/cmds/dumpsys/Android.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- dumpsys.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libbase \
- libutils \
- liblog \
- libbinder
-
-
-ifeq ($(TARGET_OS),linux)
- LOCAL_CFLAGS += -DXP_UNIX
- #LOCAL_SHARED_LIBRARIES += librt
-endif
-
-LOCAL_MODULE:= dumpsys
-
-include $(BUILD_EXECUTABLE)
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index d19e98a..f0e7200 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -1,10 +1,19 @@
/*
- * Command that dumps interesting system state to the log.
+ * Copyright (C) 2009 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 "dumpsys"
-
#include <algorithm>
#include <chrono>
#include <thread>
@@ -12,7 +21,6 @@
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
-#include <binder/IServiceManager.h>
#include <binder/Parcel.h>
#include <binder/ProcessState.h>
#include <binder/TextOutput.h>
@@ -30,6 +38,8 @@
#include <sys/types.h>
#include <unistd.h>
+#include "dumpsys.h"
+
using namespace android;
using android::base::StringPrintf;
using android::base::unique_fd;
@@ -53,7 +63,7 @@
" SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n");
}
-bool IsSkipped(const Vector<String16>& skipped, const String16& service) {
+static bool IsSkipped(const Vector<String16>& skipped, const String16& service) {
for (const auto& candidate : skipped) {
if (candidate == service) {
return true;
@@ -62,17 +72,7 @@
return false;
}
-int main(int argc, char* const argv[])
-{
- signal(SIGPIPE, SIG_IGN);
- sp<IServiceManager> sm = defaultServiceManager();
- fflush(stdout);
- if (sm == NULL) {
- ALOGE("Unable to get default service manager!");
- aerr << "dumpsys: Unable to get default service manager!" << endl;
- return 20;
- }
-
+int Dumpsys::main(int argc, char* const argv[]) {
Vector<String16> services;
Vector<String16> args;
Vector<String16> skippedServices;
@@ -85,6 +85,9 @@
{ 0, 0, 0, 0 }
};
+ // Must reset optind, otherwise subsequent calls will fail (wouldn't happen on main.cpp, but
+ // happens on test cases).
+ optind = 1;
while (1) {
int c;
int optionIndex = 0;
@@ -147,7 +150,7 @@
if (services.empty() || showListOnly) {
// gets all services
- services = sm->listServices();
+ services = sm_->listServices();
services.sort(sort_func);
args.add(String16("-a"));
}
@@ -159,8 +162,9 @@
aout << "Currently running services:" << endl;
for (size_t i=0; i<N; i++) {
- sp<IBinder> service = sm->checkService(services[i]);
- if (service != NULL) {
+ sp<IBinder> service = sm_->checkService(services[i]);
+
+ if (service != nullptr) {
bool skipped = IsSkipped(skippedServices, services[i]);
aout << " " << services[i] << (skipped ? " (skipped)" : "") << endl;
}
@@ -175,8 +179,8 @@
String16 service_name = std::move(services[i]);
if (IsSkipped(skippedServices, service_name)) continue;
- sp<IBinder> service = sm->checkService(service_name);
- if (service != NULL) {
+ sp<IBinder> service = sm_->checkService(service_name);
+ if (service != nullptr) {
int sfd[2];
if (pipe(sfd) != 0) {
@@ -203,7 +207,7 @@
// call returns, to terminate our reads if the other end closes their copy of the
// file descriptor, but then hangs for some reason. There doesn't seem to be a good
// way to do this, though.
- remote_end.clear();
+ remote_end.reset();
if (err != 0) {
aerr << "Error dumping service info: (" << strerror(err) << ") " << service_name
@@ -262,7 +266,10 @@
}
if (timed_out) {
- aout << endl << "*** SERVICE DUMP TIMEOUT EXPIRED ***" << endl << endl;
+ aout << endl
+ << "*** SERVICE '" << service_name << "' DUMP TIMEOUT (" << timeoutArg
+ << "s) EXPIRED ***" << endl
+ << endl;
}
if (timed_out || error) {
diff --git a/cmds/dumpsys/dumpsys.h b/cmds/dumpsys/dumpsys.h
new file mode 100644
index 0000000..2534dde
--- /dev/null
+++ b/cmds/dumpsys/dumpsys.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FRAMEWORK_NATIVE_CMD_DUMPSYS_H_
+#define FRAMEWORK_NATIVE_CMD_DUMPSYS_H_
+
+#include <binder/IServiceManager.h>
+
+namespace android {
+
+class Dumpsys {
+ public:
+ Dumpsys(android::IServiceManager* sm) : sm_(sm) {
+ }
+ int main(int argc, char* const argv[]);
+
+ private:
+ android::IServiceManager* sm_;
+};
+}
+
+#endif // FRAMEWORK_NATIVE_CMD_DUMPSYS_H_
diff --git a/cmds/dumpsys/main.cpp b/cmds/dumpsys/main.cpp
new file mode 100644
index 0000000..8ba0eba
--- /dev/null
+++ b/cmds/dumpsys/main.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+/*
+ * Command that dumps interesting system state to the log.
+ */
+
+#include "dumpsys.h"
+
+#include <binder/IServiceManager.h>
+#include <binder/TextOutput.h>
+
+#include <signal.h>
+#include <stdio.h>
+
+using namespace android;
+
+int main(int argc, char* const argv[]) {
+ signal(SIGPIPE, SIG_IGN);
+ sp<IServiceManager> sm = defaultServiceManager();
+ fflush(stdout);
+ if (sm == nullptr) {
+ ALOGE("Unable to get default service manager!");
+ aerr << "dumpsys: Unable to get default service manager!" << endl;
+ return 20;
+ }
+
+ Dumpsys dumpsys(sm.get());
+ return dumpsys.main(argc, argv);
+}
diff --git a/cmds/dumpsys/tests/Android.bp b/cmds/dumpsys/tests/Android.bp
new file mode 100644
index 0000000..127e0f3
--- /dev/null
+++ b/cmds/dumpsys/tests/Android.bp
@@ -0,0 +1,20 @@
+// Build the unit tests for dumpsys
+cc_test {
+ name: "dumpsys_test",
+ test_suites: ["device-tests"],
+
+ srcs: ["dumpsys_test.cpp"],
+
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libutils",
+ ],
+
+ static_libs: [
+ "libdumpsys",
+ "libgmock",
+ ],
+
+ clang: true,
+}
diff --git a/cmds/dumpsys/tests/AndroidTest.xml b/cmds/dumpsys/tests/AndroidTest.xml
new file mode 100644
index 0000000..1a8c67f
--- /dev/null
+++ b/cmds/dumpsys/tests/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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 dumpsys_test">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="dumpsys_test->/data/local/tmp/dumpsys_test" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="dumpsys_test" />
+ </test>
+</configuration>
\ No newline at end of file
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
new file mode 100644
index 0000000..66beb6d
--- /dev/null
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "../dumpsys.h"
+
+#include <vector>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <android-base/file.h>
+#include <utils/String16.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+
+using namespace android;
+
+using ::testing::_;
+using ::testing::Action;
+using ::testing::ActionInterface;
+using ::testing::DoAll;
+using ::testing::Eq;
+using ::testing::HasSubstr;
+using ::testing::MakeAction;
+using ::testing::Not;
+using ::testing::Return;
+using ::testing::StrEq;
+using ::testing::Test;
+using ::testing::WithArg;
+using ::testing::internal::CaptureStderr;
+using ::testing::internal::CaptureStdout;
+using ::testing::internal::GetCapturedStderr;
+using ::testing::internal::GetCapturedStdout;
+
+class ServiceManagerMock : public IServiceManager {
+ public:
+ MOCK_CONST_METHOD1(getService, sp<IBinder>(const String16&));
+ MOCK_CONST_METHOD1(checkService, sp<IBinder>(const String16&));
+ MOCK_METHOD3(addService, status_t(const String16&, const sp<IBinder>&, bool));
+ MOCK_METHOD0(listServices, Vector<String16>());
+
+ protected:
+ MOCK_METHOD0(onAsBinder, IBinder*());
+};
+
+class BinderMock : public BBinder {
+ public:
+ BinderMock() {
+ }
+
+ MOCK_METHOD2(dump, status_t(int, const Vector<String16>&));
+};
+
+// gmock black magic to provide a WithArg<0>(WriteOnFd(output)) matcher
+typedef void WriteOnFdFunction(int);
+
+class WriteOnFdAction : public ActionInterface<WriteOnFdFunction> {
+ public:
+ explicit WriteOnFdAction(const std::string& output) : output_(output) {
+ }
+ virtual Result Perform(const ArgumentTuple& args) {
+ int fd = ::std::tr1::get<0>(args);
+ android::base::WriteStringToFd(output_, fd);
+ }
+
+ private:
+ std::string output_;
+};
+
+// Matcher used to emulate dump() by writing on its file descriptor.
+Action<WriteOnFdFunction> WriteOnFd(const std::string& output) {
+ return MakeAction(new WriteOnFdAction(output));
+}
+
+// Matcher for args using Android's Vector<String16> format
+// TODO: move it to some common testing library
+MATCHER_P(AndroidElementsAre, expected, "") {
+ std::ostringstream errors;
+ if (arg.size() != expected.size()) {
+ errors << " sizes do not match (expected " << expected.size() << ", got " << arg.size()
+ << ")\n";
+ }
+ int i = 0;
+ std::ostringstream actual_stream, expected_stream;
+ for (String16 actual : arg) {
+ std::string actual_str = String8(actual).c_str();
+ std::string expected_str = expected[i];
+ actual_stream << "'" << actual_str << "' ";
+ expected_stream << "'" << expected_str << "' ";
+ if (actual_str != expected_str) {
+ errors << " element mismatch at index " << i << "\n";
+ }
+ i++;
+ }
+
+ if (!errors.str().empty()) {
+ errors << "\nExpected args: " << expected_stream.str()
+ << "\nActual args: " << actual_stream.str();
+ *result_listener << errors.str();
+ return false;
+ }
+ return true;
+}
+
+// Custom action to sleep for timeout seconds
+ACTION_P(Sleep, timeout) {
+ sleep(timeout);
+}
+
+class DumpsysTest : public Test {
+ public:
+ DumpsysTest() : sm_(), dump_(&sm_), stdout_(), stderr_() {
+ }
+
+ void ExpectListServices(std::vector<std::string> services) {
+ Vector<String16> services16;
+ for (auto& service : services) {
+ services16.add(String16(service.c_str()));
+ }
+ EXPECT_CALL(sm_, listServices()).WillRepeatedly(Return(services16));
+ }
+
+ sp<BinderMock> ExpectCheckService(const char* name, bool running = true) {
+ sp<BinderMock> binder_mock;
+ if (running) {
+ binder_mock = new BinderMock;
+ }
+ EXPECT_CALL(sm_, checkService(String16(name))).WillRepeatedly(Return(binder_mock));
+ return binder_mock;
+ }
+
+ void ExpectDump(const char* name, const std::string& output) {
+ sp<BinderMock> binder_mock = ExpectCheckService(name);
+ EXPECT_CALL(*binder_mock, dump(_, _))
+ .WillRepeatedly(DoAll(WithArg<0>(WriteOnFd(output)), Return(0)));
+ }
+
+ void ExpectDumpWithArgs(const char* name, std::vector<std::string> args,
+ const std::string& output) {
+ sp<BinderMock> binder_mock = ExpectCheckService(name);
+ EXPECT_CALL(*binder_mock, dump(_, AndroidElementsAre(args)))
+ .WillRepeatedly(DoAll(WithArg<0>(WriteOnFd(output)), Return(0)));
+ }
+
+ void ExpectDumpAndHang(const char* name, int timeout_s, const std::string& output) {
+ sp<BinderMock> binder_mock = ExpectCheckService(name);
+ EXPECT_CALL(*binder_mock, dump(_, _))
+ .WillRepeatedly(DoAll(Sleep(timeout_s), WithArg<0>(WriteOnFd(output)), Return(0)));
+ }
+
+ void CallMain(const std::vector<std::string>& args) {
+ const char* argv[1024] = {"/some/virtual/dir/dumpsys"};
+ int argc = (int)args.size() + 1;
+ int i = 1;
+ for (const std::string& arg : args) {
+ argv[i++] = arg.c_str();
+ }
+ CaptureStdout();
+ CaptureStderr();
+ int status = dump_.main(argc, const_cast<char**>(argv));
+ stdout_ = GetCapturedStdout();
+ stderr_ = GetCapturedStderr();
+ EXPECT_THAT(status, Eq(0));
+ }
+
+ void AssertRunningServices(const std::vector<std::string>& services) {
+ std::string expected("Currently running services:\n");
+ for (const std::string& service : services) {
+ expected.append(" ").append(service).append("\n");
+ }
+ EXPECT_THAT(stdout_, HasSubstr(expected));
+ }
+
+ void AssertOutput(const std::string& expected) {
+ EXPECT_THAT(stdout_, StrEq(expected));
+ }
+
+ void AssertOutputContains(const std::string& expected) {
+ EXPECT_THAT(stdout_, HasSubstr(expected));
+ }
+
+ void AssertDumped(const std::string& service, const std::string& dump) {
+ EXPECT_THAT(stdout_, HasSubstr("DUMP OF SERVICE " + service + ":\n" + dump));
+ }
+
+ void AssertNotDumped(const std::string& dump) {
+ EXPECT_THAT(stdout_, Not(HasSubstr(dump)));
+ }
+
+ void AssertStopped(const std::string& service) {
+ EXPECT_THAT(stderr_, HasSubstr("Can't find service: " + service + "\n"));
+ }
+
+ ServiceManagerMock sm_;
+ Dumpsys dump_;
+
+ private:
+ std::string stdout_, stderr_;
+};
+
+// Tests 'dumpsys -l' when all services are running
+TEST_F(DumpsysTest, ListAllServices) {
+ ExpectListServices({"Locksmith", "Valet"});
+ ExpectCheckService("Locksmith");
+ ExpectCheckService("Valet");
+
+ CallMain({"-l"});
+
+ AssertRunningServices({"Locksmith", "Valet"});
+}
+
+// Tests 'dumpsys -l' when a service is not running
+TEST_F(DumpsysTest, ListRunningServices) {
+ ExpectListServices({"Locksmith", "Valet"});
+ ExpectCheckService("Locksmith");
+ ExpectCheckService("Valet", false);
+
+ CallMain({"-l"});
+
+ AssertRunningServices({"Locksmith"});
+ AssertNotDumped({"Valet"});
+}
+
+// Tests 'dumpsys service_name' on a service is running
+TEST_F(DumpsysTest, DumpRunningService) {
+ ExpectDump("Valet", "Here's your car");
+
+ CallMain({"Valet"});
+
+ AssertOutput("Here's your car");
+}
+
+// Tests 'dumpsys -t 1 service_name' on a service that times out after 2s
+TEST_F(DumpsysTest, DumpRunningServiceTimeout) {
+ ExpectDumpAndHang("Valet", 2, "Here's your car");
+
+ CallMain({"-t", "1", "Valet"});
+
+ AssertOutputContains("SERVICE 'Valet' DUMP TIMEOUT (1s) EXPIRED");
+ AssertNotDumped("Here's your car");
+
+ // Must wait so binder mock is deleted, otherwise test will fail with a leaked object
+ sleep(1);
+}
+
+// Tests 'dumpsys service_name Y U NO HAVE ARGS' on a service that is running
+TEST_F(DumpsysTest, DumpWithArgsRunningService) {
+ ExpectDumpWithArgs("SERVICE", {"Y", "U", "NO", "HANDLE", "ARGS"}, "I DO!");
+
+ CallMain({"SERVICE", "Y", "U", "NO", "HANDLE", "ARGS"});
+
+ AssertOutput("I DO!");
+}
+
+// Tests 'dumpsys' with no arguments
+TEST_F(DumpsysTest, DumpMultipleServices) {
+ ExpectListServices({"running1", "stopped2", "running3"});
+ ExpectDump("running1", "dump1");
+ ExpectCheckService("stopped2", false);
+ ExpectDump("running3", "dump3");
+
+ CallMain({});
+
+ AssertRunningServices({"running1", "running3"});
+ AssertDumped("running1", "dump1");
+ AssertStopped("stopped2");
+ AssertDumped("running3", "dump3");
+}
+
+// Tests 'dumpsys --skip skipped3 skipped5', which should skip these services
+TEST_F(DumpsysTest, DumpWithSkip) {
+ ExpectListServices({"running1", "stopped2", "skipped3", "running4", "skipped5"});
+ ExpectDump("running1", "dump1");
+ ExpectCheckService("stopped2", false);
+ ExpectDump("skipped3", "dump3");
+ ExpectDump("running4", "dump4");
+ ExpectDump("skipped5", "dump5");
+
+ CallMain({"--skip", "skipped3", "skipped5"});
+
+ AssertRunningServices({"running1", "running4", "skipped3 (skipped)", "skipped5 (skipped)"});
+ AssertDumped("running1", "dump1");
+ AssertDumped("running4", "dump4");
+ AssertStopped("stopped2");
+ AssertNotDumped("dump3");
+ AssertNotDumped("dump5");
+}
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index ddf3aa8..5c04f6c 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -365,6 +365,7 @@
if (!result) {
fprintf(stderr, "Shader source:\n");
printShaderSource(lines);
+ delete[] src;
return false;
}
delete[] src;
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
new file mode 100644
index 0000000..33db6db
--- /dev/null
+++ b/cmds/installd/Android.bp
@@ -0,0 +1,75 @@
+cc_defaults {
+ name: "installd_defaults",
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ srcs: [
+ "CacheItem.cpp",
+ "CacheTracker.cpp",
+ "InstalldNativeService.cpp",
+ "dexopt.cpp",
+ "globals.cpp",
+ "utils.cpp",
+ "binder/android/os/IInstalld.aidl",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "liblog",
+ "liblogwrap",
+ "libselinux",
+ "libutils",
+ ],
+
+ clang: true,
+}
+
+//
+// Static library used in testing and executable
+//
+
+cc_library_static {
+ name: "libinstalld",
+ defaults: ["installd_defaults"],
+
+ export_include_dirs: ["."],
+ aidl: {
+ export_aidl_headers: true,
+ },
+}
+
+//
+// Executable
+//
+
+cc_binary {
+ name: "installd",
+ defaults: ["installd_defaults"],
+ srcs: ["installd.cpp"],
+
+ static_libs: ["libdiskusage"],
+
+ init_rc: ["installd.rc"],
+}
+
+// OTA chroot tool
+
+cc_binary {
+ name: "otapreopt_chroot",
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ clang: true,
+
+ srcs: ["otapreopt_chroot.cpp"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ ],
+}
+
+subdirs = ["tests"]
diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk
index 86df596..d3429ed 100644
--- a/cmds/installd/Android.mk
+++ b/cmds/installd/Android.mk
@@ -1,48 +1,5 @@
LOCAL_PATH := $(call my-dir)
-common_src_files := commands.cpp globals.cpp utils.cpp
-common_cflags := -Wall -Werror
-
-#
-# Static library used in testing and executable
-#
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libinstalld
-LOCAL_MODULE_TAGS := eng tests
-LOCAL_SRC_FILES := $(common_src_files)
-LOCAL_CFLAGS := $(common_cflags)
-LOCAL_SHARED_LIBRARIES := \
- libbase \
- liblogwrap \
- libselinux \
-
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
-LOCAL_CLANG := true
-include $(BUILD_STATIC_LIBRARY)
-
-#
-# Executable
-#
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := installd
-LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS := $(common_cflags)
-LOCAL_SRC_FILES := installd.cpp $(common_src_files)
-LOCAL_SHARED_LIBRARIES := \
- libbase \
- libcutils \
- liblog \
- liblogwrap \
- libselinux \
-
-LOCAL_STATIC_LIBRARIES := libdiskusage
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
-LOCAL_INIT_RC := installd.rc
-LOCAL_CLANG := true
-include $(BUILD_EXECUTABLE)
-
#
# OTA Executable
#
@@ -50,7 +7,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := otapreopt
LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS := $(common_cflags)
+LOCAL_CFLAGS := -Wall -Werror
# Base & ASLR boundaries for boot image creation.
ifndef LIBART_IMG_HOST_MIN_BASE_ADDRESS_DELTA
@@ -67,35 +24,20 @@
LOCAL_CFLAGS += -DART_BASE_ADDRESS_MIN_DELTA=$(LOCAL_LIBART_IMG_HOST_MIN_BASE_ADDRESS_DELTA)
LOCAL_CFLAGS += -DART_BASE_ADDRESS_MAX_DELTA=$(LOCAL_LIBART_IMG_HOST_MAX_BASE_ADDRESS_DELTA)
-LOCAL_SRC_FILES := otapreopt.cpp $(common_src_files)
+LOCAL_SRC_FILES := otapreopt.cpp globals.cpp utils.cpp dexopt.cpp
LOCAL_SHARED_LIBRARIES := \
libbase \
libcutils \
liblog \
liblogwrap \
libselinux \
+ libutils \
LOCAL_STATIC_LIBRARIES := libdiskusage
LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
LOCAL_CLANG := true
include $(BUILD_EXECUTABLE)
-# OTA chroot tool
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := otapreopt_chroot
-LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS := $(common_cflags)
-
-LOCAL_SRC_FILES := otapreopt_chroot.cpp
-LOCAL_SHARED_LIBRARIES := \
- libbase \
- liblog \
-
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
-LOCAL_CLANG := true
-include $(BUILD_EXECUTABLE)
-
# OTA slot script
include $(CLEAR_VARS)
@@ -120,7 +62,3 @@
LOCAL_REQUIRED_MODULES := otapreopt otapreopt_chroot otapreopt_slot
include $(BUILD_PREBUILT)
-
-# Tests.
-
-include $(LOCAL_PATH)/tests/Android.mk
\ No newline at end of file
diff --git a/cmds/installd/CacheItem.cpp b/cmds/installd/CacheItem.cpp
new file mode 100644
index 0000000..d1bdded
--- /dev/null
+++ b/cmds/installd/CacheItem.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2017 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 "CacheItem.h"
+
+#include <stdint.h>
+#include <inttypes.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+#include "utils.h"
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace installd {
+
+CacheItem::CacheItem(const std::shared_ptr<CacheItem>& parent, FTSENT* p) : mParent(parent) {
+ level = p->fts_level;
+ directory = S_ISDIR(p->fts_statp->st_mode);
+ size = p->fts_statp->st_blocks * 512;
+ modified = p->fts_statp->st_mtime;
+ mName = p->fts_path;
+}
+
+CacheItem::~CacheItem() {
+}
+
+std::string CacheItem::toString() {
+ return StringPrintf("%s size=%" PRId64 " mod=%ld", buildPath().c_str(), size, modified);
+}
+
+std::string CacheItem::buildPath() {
+ std::string res = mName;
+ std::shared_ptr<CacheItem> parent = mParent;
+ while (parent) {
+ res.insert(0, parent->mName);
+ parent = parent->mParent;
+ }
+ return res;
+}
+
+int CacheItem::purge() {
+ auto path = buildPath();
+ if (directory) {
+ return delete_dir_contents_and_dir(path, true);
+ } else {
+ int res = unlink(path.c_str());
+ if (res != 0) {
+ PLOG(WARNING) << "Failed to unlink " << path;
+ }
+ return res;
+ }
+}
+
+} // namespace installd
+} // namespace android
diff --git a/cmds/installd/CacheItem.h b/cmds/installd/CacheItem.h
new file mode 100644
index 0000000..bec8bc8
--- /dev/null
+++ b/cmds/installd/CacheItem.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_INSTALLD_CACHE_ITEM_H
+#define ANDROID_INSTALLD_CACHE_ITEM_H
+
+#include <memory>
+#include <string>
+
+#include <fts.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <android-base/macros.h>
+
+namespace android {
+namespace installd {
+
+/**
+ * Single cache item that can be purged to free up space. This may be an
+ * isolated file, or an entire directory tree that should be atomically
+ * deleted.
+ */
+class CacheItem {
+public:
+ CacheItem(const std::shared_ptr<CacheItem>& parent, FTSENT* p);
+ ~CacheItem();
+
+ std::string toString();
+ std::string buildPath();
+
+ int purge();
+
+ short level;
+ bool directory;
+ int64_t size;
+ time_t modified;
+
+private:
+ std::shared_ptr<CacheItem> mParent;
+ std::string mName;
+
+ DISALLOW_COPY_AND_ASSIGN(CacheItem);
+};
+
+} // namespace installd
+} // namespace android
+
+#endif // ANDROID_INSTALLD_CACHE_ITEM_H
diff --git a/cmds/installd/CacheTracker.cpp b/cmds/installd/CacheTracker.cpp
new file mode 100644
index 0000000..23c4330
--- /dev/null
+++ b/cmds/installd/CacheTracker.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2017 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 ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
+
+#include "CacheTracker.h"
+
+#include <fts.h>
+#include <sys/quota.h>
+#include <utils/Trace.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+#include "utils.h"
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace installd {
+
+CacheTracker::CacheTracker(userid_t userId, appid_t appId, const std::string& quotaDevice) :
+ cacheUsed(0), cacheQuota(0), mUserId(userId), mAppId(appId), mQuotaDevice(quotaDevice),
+ mItemsLoaded(false) {
+}
+
+CacheTracker::~CacheTracker() {
+}
+
+std::string CacheTracker::toString() {
+ return StringPrintf("UID=%d used=%" PRId64 " quota=%" PRId64 " ratio=%d",
+ multiuser_get_uid(mUserId, mAppId), cacheUsed, cacheQuota, getCacheRatio());
+}
+
+void CacheTracker::addDataPath(const std::string& dataPath) {
+ mDataPaths.push_back(dataPath);
+}
+
+void CacheTracker::loadStats() {
+ int cacheGid = multiuser_get_cache_gid(mUserId, mAppId);
+ if (cacheGid != -1 && !mQuotaDevice.empty()) {
+ ATRACE_BEGIN("loadStats quota");
+ struct dqblk dq;
+ if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), mQuotaDevice.c_str(), cacheGid,
+ reinterpret_cast<char*>(&dq)) != 0) {
+ ATRACE_END();
+ if (errno != ESRCH) {
+ PLOG(ERROR) << "Failed to quotactl " << mQuotaDevice << " for GID " << cacheGid;
+ }
+ } else {
+ cacheUsed = dq.dqb_curspace;
+ ATRACE_END();
+ return;
+ }
+ }
+
+ ATRACE_BEGIN("loadStats tree");
+ cacheUsed = 0;
+ for (auto path : mDataPaths) {
+ auto cachePath = read_path_inode(path, "cache", kXattrInodeCache);
+ auto codeCachePath = read_path_inode(path, "code_cache", kXattrInodeCodeCache);
+ calculate_tree_size(cachePath, &cacheUsed);
+ calculate_tree_size(codeCachePath, &cacheUsed);
+ }
+ ATRACE_END();
+}
+
+void CacheTracker::loadItemsFrom(const std::string& path) {
+ FTS *fts;
+ FTSENT *p;
+ char *argv[] = { (char*) path.c_str(), nullptr };
+ if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_XDEV, NULL))) {
+ PLOG(WARNING) << "Failed to fts_open " << path;
+ return;
+ }
+ // TODO: add support for "user.atomic" and "user.tombstone" xattrs
+ while ((p = fts_read(fts)) != NULL) {
+ switch (p->fts_info) {
+ case FTS_D:
+ // Track the newest mtime of anything inside so we consider
+ // deleting the directory last
+ p->fts_number = p->fts_statp->st_mtime;
+ break;
+ case FTS_DP:
+ p->fts_statp->st_mtime = p->fts_number;
+
+ // Ignore the actual top-level cache directories
+ if (p->fts_level == 0) break;
+ case FTS_DEFAULT:
+ case FTS_F:
+ case FTS_SL:
+ case FTS_SLNONE:
+ // TODO: optimize path memory footprint
+ items.push_back(std::shared_ptr<CacheItem>(new CacheItem(nullptr, p)));
+
+ // Track the newest modified item under this tree
+ p->fts_parent->fts_number =
+ std::max(p->fts_parent->fts_number, p->fts_statp->st_mtime);
+ break;
+ }
+ }
+ fts_close(fts);
+}
+
+void CacheTracker::loadItems() {
+ items.clear();
+
+ ATRACE_BEGIN("loadItems");
+ for (auto path : mDataPaths) {
+ loadItemsFrom(read_path_inode(path, "cache", kXattrInodeCache));
+ loadItemsFrom(read_path_inode(path, "code_cache", kXattrInodeCodeCache));
+ }
+ ATRACE_END();
+
+ ATRACE_BEGIN("sortItems");
+ auto cmp = [](std::shared_ptr<CacheItem> left, std::shared_ptr<CacheItem> right) {
+ // TODO: sort dotfiles last
+ // TODO: sort code_cache last
+ if (left->modified != right->modified) {
+ return (left->modified > right->modified);
+ }
+ if (left->level != right->level) {
+ return (left->level < right->level);
+ }
+ return left->directory;
+ };
+ std::sort(items.begin(), items.end(), cmp);
+ ATRACE_END();
+}
+
+void CacheTracker::ensureItems() {
+ if (mItemsLoaded) {
+ return;
+ } else {
+ loadItems();
+ mItemsLoaded = true;
+ }
+}
+
+int CacheTracker::getCacheRatio() {
+ if (cacheQuota == 0) {
+ return 0;
+ } else {
+ return (cacheUsed * 10000) / cacheQuota;
+ }
+}
+
+} // namespace installd
+} // namespace android
diff --git a/cmds/installd/CacheTracker.h b/cmds/installd/CacheTracker.h
new file mode 100644
index 0000000..91692d7
--- /dev/null
+++ b/cmds/installd/CacheTracker.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_INSTALLD_CACHE_TRACKER_H
+#define ANDROID_INSTALLD_CACHE_TRACKER_H
+
+#include <memory>
+#include <string>
+#include <queue>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <android-base/macros.h>
+#include <cutils/multiuser.h>
+
+#include "CacheItem.h"
+
+namespace android {
+namespace installd {
+
+/**
+ * Cache tracker for a single UID. Each tracker is used in two modes: first
+ * for loading lightweight "stats", and then by loading detailed "items"
+ * which can then be purged to free up space.
+ */
+class CacheTracker {
+public:
+ CacheTracker(userid_t userId, appid_t appId, const std::string& quotaDevice);
+ ~CacheTracker();
+
+ std::string toString();
+
+ void addDataPath(const std::string& dataPath);
+
+ void loadStats();
+ void loadItems();
+
+ void ensureItems();
+
+ int getCacheRatio();
+
+ int64_t cacheUsed;
+ int64_t cacheQuota;
+
+ std::vector<std::shared_ptr<CacheItem>> items;
+
+private:
+ userid_t mUserId;
+ appid_t mAppId;
+ std::string mQuotaDevice;
+ bool mItemsLoaded;
+
+ std::vector<std::string> mDataPaths;
+
+ void loadItemsFrom(const std::string& path);
+
+ DISALLOW_COPY_AND_ASSIGN(CacheTracker);
+};
+
+} // namespace installd
+} // namespace android
+
+#endif // ANDROID_INSTALLD_CACHE_TRACKER_H
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
new file mode 100644
index 0000000..b5f0fb2
--- /dev/null
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -0,0 +1,1997 @@
+/*
+** Copyright 2008, 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 "InstalldNativeService.h"
+
+#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER
+
+#include <errno.h>
+#include <inttypes.h>
+#include <fstream>
+#include <fts.h>
+#include <regex>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/capability.h>
+#include <sys/file.h>
+#include <sys/resource.h>
+#include <sys/quota.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/xattr.h>
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <cutils/fs.h>
+#include <cutils/properties.h>
+#include <cutils/sched_policy.h>
+#include <log/log.h> // TODO: Move everything to base/logging.
+#include <logwrap/logwrap.h>
+#include <private/android_filesystem_config.h>
+#include <selinux/android.h>
+#include <system/thread_defs.h>
+#include <utils/Trace.h>
+
+#include "dexopt.h"
+#include "globals.h"
+#include "installd_deps.h"
+#include "otapreopt_utils.h"
+#include "utils.h"
+
+#include "CacheTracker.h"
+#include "MatchExtensionGen.h"
+
+#ifndef LOG_TAG
+#define LOG_TAG "installd"
+#endif
+
+using android::base::StringPrintf;
+using std::endl;
+
+namespace android {
+namespace installd {
+
+static constexpr const char* kCpPath = "/system/bin/cp";
+static constexpr const char* kXattrDefault = "user.default";
+
+static constexpr const char* PKG_LIB_POSTFIX = "/lib";
+static constexpr const char* CACHE_DIR_POSTFIX = "/cache";
+static constexpr const char* CODE_CACHE_DIR_POSTFIX = "/code_cache";
+
+static constexpr const char* IDMAP_PREFIX = "/data/resource-cache/";
+static constexpr const char* IDMAP_SUFFIX = "@idmap";
+
+// NOTE: keep in sync with Installer
+static constexpr int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
+static constexpr int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 9;
+static constexpr int FLAG_USE_QUOTA = 1 << 12;
+static constexpr int FLAG_FREE_CACHE_V2 = 1 << 13;
+static constexpr int FLAG_FREE_CACHE_NOOP = 1 << 14;
+
+#define MIN_RESTRICTED_HOME_SDK_VERSION 24 // > M
+namespace {
+
+constexpr const char* kDump = "android.permission.DUMP";
+
+static binder::Status ok() {
+ return binder::Status::ok();
+}
+
+static binder::Status exception(uint32_t code, const std::string& msg) {
+ return binder::Status::fromExceptionCode(code, String8(msg.c_str()));
+}
+
+static binder::Status error() {
+ return binder::Status::fromServiceSpecificError(errno);
+}
+
+static binder::Status error(const std::string& msg) {
+ PLOG(ERROR) << msg;
+ return binder::Status::fromServiceSpecificError(errno, String8(msg.c_str()));
+}
+
+static binder::Status error(uint32_t code, const std::string& msg) {
+ LOG(ERROR) << msg << " (" << code << ")";
+ return binder::Status::fromServiceSpecificError(code, String8(msg.c_str()));
+}
+
+binder::Status checkPermission(const char* permission) {
+ pid_t pid;
+ uid_t uid;
+
+ if (checkCallingPermission(String16(permission), reinterpret_cast<int32_t*>(&pid),
+ reinterpret_cast<int32_t*>(&uid))) {
+ return ok();
+ } else {
+ return exception(binder::Status::EX_SECURITY,
+ StringPrintf("UID %d / PID %d lacks permission %s", uid, pid, permission));
+ }
+}
+
+binder::Status checkUid(uid_t expectedUid) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (uid == expectedUid || uid == AID_ROOT) {
+ return ok();
+ } else {
+ return exception(binder::Status::EX_SECURITY,
+ StringPrintf("UID %d is not expected UID %d", uid, expectedUid));
+ }
+}
+
+binder::Status checkArgumentUuid(const std::unique_ptr<std::string>& uuid) {
+ if (!uuid || is_valid_filename(*uuid)) {
+ return ok();
+ } else {
+ return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
+ StringPrintf("UUID %s is malformed", uuid->c_str()));
+ }
+}
+
+binder::Status checkArgumentPackageName(const std::string& packageName) {
+ if (is_valid_package_name(packageName.c_str())) {
+ return ok();
+ } else {
+ return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
+ StringPrintf("Package name %s is malformed", packageName.c_str()));
+ }
+}
+
+#define ENFORCE_UID(uid) { \
+ binder::Status status = checkUid((uid)); \
+ if (!status.isOk()) { \
+ return status; \
+ } \
+}
+
+#define CHECK_ARGUMENT_UUID(uuid) { \
+ binder::Status status = checkArgumentUuid((uuid)); \
+ if (!status.isOk()) { \
+ return status; \
+ } \
+}
+
+#define CHECK_ARGUMENT_PACKAGE_NAME(packageName) { \
+ binder::Status status = \
+ checkArgumentPackageName((packageName)); \
+ if (!status.isOk()) { \
+ return status; \
+ } \
+}
+
+} // namespace
+
+status_t InstalldNativeService::start() {
+ IPCThreadState::self()->disableBackgroundScheduling(true);
+ status_t ret = BinderService<InstalldNativeService>::publish();
+ if (ret != android::OK) {
+ return ret;
+ }
+ sp<ProcessState> ps(ProcessState::self());
+ ps->startThreadPool();
+ ps->giveThreadPoolName();
+ return android::OK;
+}
+
+status_t InstalldNativeService::dump(int fd, const Vector<String16> & /* args */) {
+ auto out = std::fstream(StringPrintf("/proc/self/fd/%d", fd));
+ const binder::Status dump_permission = checkPermission(kDump);
+ if (!dump_permission.isOk()) {
+ out << dump_permission.toString8() << endl;
+ return PERMISSION_DENIED;
+ }
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ out << "installd is happy!" << endl;
+
+ out << endl << "Devices with quota support:" << endl;
+ for (const auto& n : mQuotaDevices) {
+ out << " " << n.first << " = " << n.second << endl;
+ }
+
+ out << endl << "Per-UID cache quotas:" << endl;
+ for (const auto& n : mCacheQuotas) {
+ out << " " << n.first << " = " << n.second << endl;
+ }
+
+ out << endl;
+ out.flush();
+
+ return NO_ERROR;
+}
+
+/**
+ * Perform restorecon of the given path, but only perform recursive restorecon
+ * if the label of that top-level file actually changed. This can save us
+ * significant time by avoiding no-op traversals of large filesystem trees.
+ */
+static int restorecon_app_data_lazy(const std::string& path, const std::string& seInfo, uid_t uid,
+ bool existing) {
+ int res = 0;
+ char* before = nullptr;
+ char* after = nullptr;
+
+ // Note that SELINUX_ANDROID_RESTORECON_DATADATA flag is set by
+ // libselinux. Not needed here.
+
+ if (lgetfilecon(path.c_str(), &before) < 0) {
+ PLOG(ERROR) << "Failed before getfilecon for " << path;
+ goto fail;
+ }
+ if (selinux_android_restorecon_pkgdir(path.c_str(), seInfo.c_str(), uid, 0) < 0) {
+ PLOG(ERROR) << "Failed top-level restorecon for " << path;
+ goto fail;
+ }
+ if (lgetfilecon(path.c_str(), &after) < 0) {
+ PLOG(ERROR) << "Failed after getfilecon for " << path;
+ goto fail;
+ }
+
+ // If the initial top-level restorecon above changed the label, then go
+ // back and restorecon everything recursively
+ if (strcmp(before, after)) {
+ if (existing) {
+ LOG(DEBUG) << "Detected label change from " << before << " to " << after << " at "
+ << path << "; running recursive restorecon";
+ }
+ if (selinux_android_restorecon_pkgdir(path.c_str(), seInfo.c_str(), uid,
+ SELINUX_ANDROID_RESTORECON_RECURSE) < 0) {
+ PLOG(ERROR) << "Failed recursive restorecon for " << path;
+ goto fail;
+ }
+ }
+
+ goto done;
+fail:
+ res = -1;
+done:
+ free(before);
+ free(after);
+ return res;
+}
+
+static int restorecon_app_data_lazy(const std::string& parent, const char* name,
+ const std::string& seInfo, uid_t uid, bool existing) {
+ return restorecon_app_data_lazy(StringPrintf("%s/%s", parent.c_str(), name), seInfo, uid,
+ existing);
+}
+
+static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid) {
+ if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, uid) != 0) {
+ PLOG(ERROR) << "Failed to prepare " << path;
+ return -1;
+ }
+ return 0;
+}
+
+binder::Status InstalldNativeService::createAppData(const std::unique_ptr<std::string>& uuid,
+ const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
+ const std::string& seInfo, int32_t targetSdkVersion, int64_t* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+ const char* pkgname = packageName.c_str();
+
+ // Assume invalid inode unless filled in below
+ if (_aidl_return != nullptr) *_aidl_return = -1;
+
+ int32_t uid = multiuser_get_uid(userId, appId);
+ int32_t cacheGid = multiuser_get_cache_gid(userId, appId);
+ mode_t targetMode = targetSdkVersion >= MIN_RESTRICTED_HOME_SDK_VERSION ? 0700 : 0751;
+
+ // If UID doesn't have a specific cache GID, use UID value
+ if (cacheGid == -1) {
+ cacheGid = uid;
+ }
+
+ if (flags & FLAG_STORAGE_CE) {
+ auto path = create_data_user_ce_package_path(uuid_, userId, pkgname);
+ bool existing = (access(path.c_str(), F_OK) == 0);
+
+ if (prepare_app_dir(path, targetMode, uid) ||
+ prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid) ||
+ prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid)) {
+ return error("Failed to prepare " + path);
+ }
+
+ // Consider restorecon over contents if label changed
+ if (restorecon_app_data_lazy(path, seInfo, uid, existing) ||
+ restorecon_app_data_lazy(path, "cache", seInfo, uid, existing) ||
+ restorecon_app_data_lazy(path, "code_cache", seInfo, uid, existing)) {
+ return error("Failed to restorecon " + path);
+ }
+
+ // Remember inode numbers of cache directories so that we can clear
+ // contents while CE storage is locked
+ if (write_path_inode(path, "cache", kXattrInodeCache) ||
+ write_path_inode(path, "code_cache", kXattrInodeCodeCache)) {
+ return error("Failed to write_path_inode for " + path);
+ }
+
+ // And return the CE inode of the top-level data directory so we can
+ // clear contents while CE storage is locked
+ if ((_aidl_return != nullptr)
+ && get_path_inode(path, reinterpret_cast<ino_t*>(_aidl_return)) != 0) {
+ return error("Failed to get_path_inode for " + path);
+ }
+ }
+ if (flags & FLAG_STORAGE_DE) {
+ auto path = create_data_user_de_package_path(uuid_, userId, pkgname);
+ bool existing = (access(path.c_str(), F_OK) == 0);
+
+ if (prepare_app_dir(path, targetMode, uid) ||
+ prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid) ||
+ prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid)) {
+ return error("Failed to prepare " + path);
+ }
+
+ // Consider restorecon over contents if label changed
+ if (restorecon_app_data_lazy(path, seInfo, uid, existing)) {
+ return error("Failed to restorecon " + path);
+ }
+
+ if (property_get_bool("dalvik.vm.usejitprofiles", false)) {
+ const std::string profile_dir =
+ create_primary_current_profile_package_dir_path(userId, pkgname);
+ // read-write-execute only for the app user.
+ if (fs_prepare_dir_strict(profile_dir.c_str(), 0700, uid, uid) != 0) {
+ return error("Failed to prepare " + profile_dir);
+ }
+ const std::string profile_file = create_current_profile_path(userId, pkgname,
+ /*is_secondary_dex*/false);
+ // read-write only for the app user.
+ if (fs_prepare_file_strict(profile_file.c_str(), 0600, uid, uid) != 0) {
+ return error("Failed to prepare " + profile_file);
+ }
+ const std::string ref_profile_path =
+ create_primary_reference_profile_package_dir_path(pkgname);
+ // dex2oat/profman runs under the shared app gid and it needs to read/write reference
+ // profiles.
+ int shared_app_gid = multiuser_get_shared_gid(0, appId);
+ if ((shared_app_gid != -1) && fs_prepare_dir_strict(
+ ref_profile_path.c_str(), 0700, shared_app_gid, shared_app_gid) != 0) {
+ return error("Failed to prepare " + ref_profile_path);
+ }
+ }
+ }
+ return ok();
+}
+
+binder::Status InstalldNativeService::migrateAppData(const std::unique_ptr<std::string>& uuid,
+ const std::string& packageName, int32_t userId, int32_t flags) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+ const char* pkgname = packageName.c_str();
+
+ // This method only exists to upgrade system apps that have requested
+ // forceDeviceEncrypted, so their default storage always lives in a
+ // consistent location. This only works on non-FBE devices, since we
+ // never want to risk exposing data on a device with real CE/DE storage.
+
+ auto ce_path = create_data_user_ce_package_path(uuid_, userId, pkgname);
+ auto de_path = create_data_user_de_package_path(uuid_, userId, pkgname);
+
+ // If neither directory is marked as default, assume CE is default
+ if (getxattr(ce_path.c_str(), kXattrDefault, nullptr, 0) == -1
+ && getxattr(de_path.c_str(), kXattrDefault, nullptr, 0) == -1) {
+ if (setxattr(ce_path.c_str(), kXattrDefault, nullptr, 0, 0) != 0) {
+ return error("Failed to mark default storage " + ce_path);
+ }
+ }
+
+ // Migrate default data location if needed
+ auto target = (flags & FLAG_STORAGE_DE) ? de_path : ce_path;
+ auto source = (flags & FLAG_STORAGE_DE) ? ce_path : de_path;
+
+ if (getxattr(target.c_str(), kXattrDefault, nullptr, 0) == -1) {
+ LOG(WARNING) << "Requested default storage " << target
+ << " is not active; migrating from " << source;
+ if (delete_dir_contents_and_dir(target) != 0) {
+ return error("Failed to delete " + target);
+ }
+ if (rename(source.c_str(), target.c_str()) != 0) {
+ return error("Failed to rename " + source + " to " + target);
+ }
+ }
+
+ return ok();
+}
+
+
+binder::Status InstalldNativeService::clearAppProfiles(const std::string& packageName) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ binder::Status res = ok();
+ if (!clear_primary_reference_profile(packageName)) {
+ res = error("Failed to clear reference profile for " + packageName);
+ }
+ if (!clear_primary_current_profiles(packageName)) {
+ res = error("Failed to clear current profiles for " + packageName);
+ }
+ return res;
+}
+
+binder::Status InstalldNativeService::clearAppData(const std::unique_ptr<std::string>& uuid,
+ const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+ const char* pkgname = packageName.c_str();
+
+ binder::Status res = ok();
+ if (flags & FLAG_STORAGE_CE) {
+ auto path = create_data_user_ce_package_path(uuid_, userId, pkgname, ceDataInode);
+ if (flags & FLAG_CLEAR_CACHE_ONLY) {
+ path = read_path_inode(path, "cache", kXattrInodeCache);
+ } else if (flags & FLAG_CLEAR_CODE_CACHE_ONLY) {
+ path = read_path_inode(path, "code_cache", kXattrInodeCodeCache);
+ }
+ if (access(path.c_str(), F_OK) == 0) {
+ if (delete_dir_contents(path) != 0) {
+ res = error("Failed to delete contents of " + path);
+ }
+ }
+ }
+ if (flags & FLAG_STORAGE_DE) {
+ std::string suffix = "";
+ bool only_cache = false;
+ if (flags & FLAG_CLEAR_CACHE_ONLY) {
+ suffix = CACHE_DIR_POSTFIX;
+ only_cache = true;
+ } else if (flags & FLAG_CLEAR_CODE_CACHE_ONLY) {
+ suffix = CODE_CACHE_DIR_POSTFIX;
+ only_cache = true;
+ }
+
+ auto path = create_data_user_de_package_path(uuid_, userId, pkgname) + suffix;
+ if (access(path.c_str(), F_OK) == 0) {
+ if (delete_dir_contents(path) != 0) {
+ res = error("Failed to delete contents of " + path);
+ }
+ }
+ if (!only_cache) {
+ if (!clear_primary_current_profile(packageName, userId)) {
+ res = error("Failed to clear current profile for " + packageName);
+ }
+ }
+ }
+ return res;
+}
+
+static int destroy_app_reference_profile(const std::string& pkgname) {
+ return delete_dir_contents_and_dir(
+ create_primary_reference_profile_package_dir_path(pkgname),
+ /*ignore_if_missing*/ true);
+}
+
+static int destroy_app_current_profiles(const std::string& pkgname, userid_t userid) {
+ return delete_dir_contents_and_dir(
+ create_primary_current_profile_package_dir_path(userid, pkgname),
+ /*ignore_if_missing*/ true);
+}
+
+binder::Status InstalldNativeService::destroyAppProfiles(const std::string& packageName) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ binder::Status res = ok();
+ std::vector<userid_t> users = get_known_users(/*volume_uuid*/ nullptr);
+ for (auto user : users) {
+ if (destroy_app_current_profiles(packageName, user) != 0) {
+ res = error("Failed to destroy current profiles for " + packageName);
+ }
+ }
+ if (destroy_app_reference_profile(packageName) != 0) {
+ res = error("Failed to destroy reference profile for " + packageName);
+ }
+ return res;
+}
+
+binder::Status InstalldNativeService::destroyAppData(const std::unique_ptr<std::string>& uuid,
+ const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+ const char* pkgname = packageName.c_str();
+
+ binder::Status res = ok();
+ if (flags & FLAG_STORAGE_CE) {
+ auto path = create_data_user_ce_package_path(uuid_, userId, pkgname, ceDataInode);
+ if (delete_dir_contents_and_dir(path) != 0) {
+ res = error("Failed to delete " + path);
+ }
+ }
+ if (flags & FLAG_STORAGE_DE) {
+ auto path = create_data_user_de_package_path(uuid_, userId, pkgname);
+ if (delete_dir_contents_and_dir(path) != 0) {
+ res = error("Failed to delete " + path);
+ }
+ destroy_app_current_profiles(packageName, userId);
+ // TODO(calin): If the package is still installed by other users it's probably
+ // beneficial to keep the reference profile around.
+ // Verify if it's ok to do that.
+ destroy_app_reference_profile(packageName);
+ }
+ return res;
+}
+
+binder::Status InstalldNativeService::moveCompleteApp(const std::unique_ptr<std::string>& fromUuid,
+ const std::unique_ptr<std::string>& toUuid, const std::string& packageName,
+ const std::string& dataAppName, int32_t appId, const std::string& seInfo,
+ int32_t targetSdkVersion) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(fromUuid);
+ CHECK_ARGUMENT_UUID(toUuid);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ const char* from_uuid = fromUuid ? fromUuid->c_str() : nullptr;
+ const char* to_uuid = toUuid ? toUuid->c_str() : nullptr;
+ const char* package_name = packageName.c_str();
+ const char* data_app_name = dataAppName.c_str();
+
+ binder::Status res = ok();
+ std::vector<userid_t> users = get_known_users(from_uuid);
+
+ // Copy app
+ {
+ auto from = create_data_app_package_path(from_uuid, data_app_name);
+ auto to = create_data_app_package_path(to_uuid, data_app_name);
+ auto to_parent = create_data_app_path(to_uuid);
+
+ char *argv[] = {
+ (char*) kCpPath,
+ (char*) "-F", /* delete any existing destination file first (--remove-destination) */
+ (char*) "-p", /* preserve timestamps, ownership, and permissions */
+ (char*) "-R", /* recurse into subdirectories (DEST must be a directory) */
+ (char*) "-P", /* Do not follow symlinks [default] */
+ (char*) "-d", /* don't dereference symlinks */
+ (char*) from.c_str(),
+ (char*) to_parent.c_str()
+ };
+
+ LOG(DEBUG) << "Copying " << from << " to " << to;
+ int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true);
+ if (rc != 0) {
+ res = error(rc, "Failed copying " + from + " to " + to);
+ goto fail;
+ }
+
+ if (selinux_android_restorecon(to.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
+ res = error("Failed to restorecon " + to);
+ goto fail;
+ }
+ }
+
+ // Copy private data for all known users
+ for (auto user : users) {
+
+ // Data source may not exist for all users; that's okay
+ auto from_ce = create_data_user_ce_package_path(from_uuid, user, package_name);
+ if (access(from_ce.c_str(), F_OK) != 0) {
+ LOG(INFO) << "Missing source " << from_ce;
+ continue;
+ }
+
+ if (!createAppData(toUuid, packageName, user, FLAG_STORAGE_CE | FLAG_STORAGE_DE, appId,
+ seInfo, targetSdkVersion, nullptr).isOk()) {
+ res = error("Failed to create package target");
+ goto fail;
+ }
+
+ char *argv[] = {
+ (char*) kCpPath,
+ (char*) "-F", /* delete any existing destination file first (--remove-destination) */
+ (char*) "-p", /* preserve timestamps, ownership, and permissions */
+ (char*) "-R", /* recurse into subdirectories (DEST must be a directory) */
+ (char*) "-P", /* Do not follow symlinks [default] */
+ (char*) "-d", /* don't dereference symlinks */
+ nullptr,
+ nullptr
+ };
+
+ {
+ auto from = create_data_user_de_package_path(from_uuid, user, package_name);
+ auto to = create_data_user_de_path(to_uuid, user);
+ argv[6] = (char*) from.c_str();
+ argv[7] = (char*) to.c_str();
+
+ LOG(DEBUG) << "Copying " << from << " to " << to;
+ int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true);
+ if (rc != 0) {
+ res = error(rc, "Failed copying " + from + " to " + to);
+ goto fail;
+ }
+ }
+ {
+ auto from = create_data_user_ce_package_path(from_uuid, user, package_name);
+ auto to = create_data_user_ce_path(to_uuid, user);
+ argv[6] = (char*) from.c_str();
+ argv[7] = (char*) to.c_str();
+
+ LOG(DEBUG) << "Copying " << from << " to " << to;
+ int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true);
+ if (rc != 0) {
+ res = error(rc, "Failed copying " + from + " to " + to);
+ goto fail;
+ }
+ }
+
+ if (!restoreconAppData(toUuid, packageName, user, FLAG_STORAGE_CE | FLAG_STORAGE_DE,
+ appId, seInfo).isOk()) {
+ res = error("Failed to restorecon");
+ goto fail;
+ }
+ }
+
+ // We let the framework scan the new location and persist that before
+ // deleting the data in the old location; this ordering ensures that
+ // we can recover from things like battery pulls.
+ return ok();
+
+fail:
+ // Nuke everything we might have already copied
+ {
+ auto to = create_data_app_package_path(to_uuid, data_app_name);
+ if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
+ LOG(WARNING) << "Failed to rollback " << to;
+ }
+ }
+ for (auto user : users) {
+ {
+ auto to = create_data_user_de_package_path(to_uuid, user, package_name);
+ if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
+ LOG(WARNING) << "Failed to rollback " << to;
+ }
+ }
+ {
+ auto to = create_data_user_ce_package_path(to_uuid, user, package_name);
+ if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
+ LOG(WARNING) << "Failed to rollback " << to;
+ }
+ }
+ }
+ return res;
+}
+
+binder::Status InstalldNativeService::createUserData(const std::unique_ptr<std::string>& uuid,
+ int32_t userId, int32_t userSerial ATTRIBUTE_UNUSED, int32_t flags) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+ if (flags & FLAG_STORAGE_DE) {
+ if (uuid_ == nullptr) {
+ if (ensure_config_user_dirs(userId) != 0) {
+ return error(StringPrintf("Failed to ensure dirs for %d", userId));
+ }
+ }
+ }
+ return ok();
+}
+
+binder::Status InstalldNativeService::destroyUserData(const std::unique_ptr<std::string>& uuid,
+ int32_t userId, int32_t flags) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+ binder::Status res = ok();
+ if (flags & FLAG_STORAGE_DE) {
+ auto path = create_data_user_de_path(uuid_, userId);
+ if (delete_dir_contents_and_dir(path, true) != 0) {
+ res = error("Failed to delete " + path);
+ }
+ if (uuid_ == nullptr) {
+ path = create_data_misc_legacy_path(userId);
+ if (delete_dir_contents_and_dir(path, true) != 0) {
+ res = error("Failed to delete " + path);
+ }
+ path = create_primary_cur_profile_dir_path(userId);
+ if (delete_dir_contents_and_dir(path, true) != 0) {
+ res = error("Failed to delete " + path);
+ }
+ }
+ }
+ if (flags & FLAG_STORAGE_CE) {
+ auto path = create_data_user_ce_path(uuid_, userId);
+ if (delete_dir_contents_and_dir(path, true) != 0) {
+ res = error("Failed to delete " + path);
+ }
+ path = create_data_media_path(uuid_, userId);
+ if (delete_dir_contents_and_dir(path, true) != 0) {
+ res = error("Failed to delete " + path);
+ }
+ }
+ return res;
+}
+
+/* Try to ensure free_size bytes of storage are available.
+ * Returns 0 on success.
+ * This is rather simple-minded because doing a full LRU would
+ * be potentially memory-intensive, and without atime it would
+ * also require that apps constantly modify file metadata even
+ * when just reading from the cache, which is pretty awful.
+ */
+binder::Status InstalldNativeService::freeCache(const std::unique_ptr<std::string>& uuid,
+ int64_t freeStorageSize, int32_t flags) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ // TODO: remove this once framework is more robust
+ invalidateMounts();
+
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+ auto data_path = create_data_path(uuid_);
+ auto device = findQuotaDeviceForUuid(uuid);
+ auto noop = (flags & FLAG_FREE_CACHE_NOOP);
+
+ int64_t free = data_disk_free(data_path);
+ int64_t needed = freeStorageSize - free;
+ if (free < 0) {
+ return error("Failed to determine free space for " + data_path);
+ } else if (free >= freeStorageSize) {
+ return ok();
+ }
+
+ LOG(DEBUG) << "Found " << data_path << " with " << free << " free; caller requested "
+ << freeStorageSize;
+
+ if (flags & FLAG_FREE_CACHE_V2) {
+ // This new cache strategy fairly removes files from UIDs by deleting
+ // files from the UIDs which are most over their allocated quota
+
+ // 1. Create trackers for every known UID
+ ATRACE_BEGIN("create");
+ std::unordered_map<uid_t, std::shared_ptr<CacheTracker>> trackers;
+ for (auto user : get_known_users(uuid_)) {
+ FTS *fts;
+ FTSENT *p;
+ char *argv[] = {
+ (char*) create_data_user_ce_path(uuid_, user).c_str(),
+ (char*) create_data_user_de_path(uuid_, user).c_str(),
+ nullptr
+ };
+ if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_XDEV, NULL))) {
+ return error("Failed to fts_open");
+ }
+ while ((p = fts_read(fts)) != NULL) {
+ if (p->fts_info == FTS_D && p->fts_level == 1) {
+ uid_t uid = p->fts_statp->st_uid;
+ auto search = trackers.find(uid);
+ if (search != trackers.end()) {
+ search->second->addDataPath(p->fts_path);
+ } else {
+ auto tracker = std::shared_ptr<CacheTracker>(new CacheTracker(
+ multiuser_get_user_id(uid), multiuser_get_app_id(uid), device));
+ tracker->addDataPath(p->fts_path);
+ tracker->cacheQuota = mCacheQuotas[uid];
+ if (tracker->cacheQuota == 0) {
+ LOG(WARNING) << "UID " << uid << " has no cache quota; assuming 64MB";
+ tracker->cacheQuota = 67108864;
+ }
+ trackers[uid] = tracker;
+ }
+ fts_set(fts, p, FTS_SKIP);
+ }
+ }
+ fts_close(fts);
+ }
+ ATRACE_END();
+
+ // 2. Populate tracker stats and insert into priority queue
+ ATRACE_BEGIN("populate");
+ auto cmp = [](std::shared_ptr<CacheTracker> left, std::shared_ptr<CacheTracker> right) {
+ return (left->getCacheRatio() < right->getCacheRatio());
+ };
+ std::priority_queue<std::shared_ptr<CacheTracker>,
+ std::vector<std::shared_ptr<CacheTracker>>, decltype(cmp)> queue(cmp);
+ for (const auto& it : trackers) {
+ it.second->loadStats();
+ queue.push(it.second);
+ }
+ ATRACE_END();
+
+ // 3. Bounce across the queue, freeing items from whichever tracker is
+ // the most over their assigned quota
+ ATRACE_BEGIN("bounce");
+ std::shared_ptr<CacheTracker> active;
+ while (active || !queue.empty()) {
+ // Find the best tracker to work with; this might involve swapping
+ // if the active tracker is no longer the most over quota
+ bool nextBetter = active && !queue.empty()
+ && active->getCacheRatio() < queue.top()->getCacheRatio();
+ if (!active || nextBetter) {
+ if (active) {
+ // Current tracker still has items, so we'll consider it
+ // again later once it bubbles up to surface
+ queue.push(active);
+ }
+ active = queue.top(); queue.pop();
+ active->ensureItems();
+ continue;
+ }
+
+ // If no items remain, go find another tracker
+ if (active->items.empty()) {
+ active = nullptr;
+ continue;
+ } else {
+ auto item = active->items.back();
+ active->items.pop_back();
+
+ LOG(DEBUG) << "Purging " << item->toString() << " from " << active->toString();
+ if (!noop) {
+ item->purge();
+ }
+ active->cacheUsed -= item->size;
+ needed -= item->size;
+ }
+
+ // Verify that we're actually done before bailing, since sneaky
+ // apps might be using hardlinks
+ if (needed <= 0) {
+ free = data_disk_free(data_path);
+ needed = freeStorageSize - free;
+ if (needed <= 0) {
+ break;
+ } else {
+ LOG(WARNING) << "Expected to be done but still need " << needed;
+ }
+ }
+ }
+ ATRACE_END();
+
+ } else {
+ ATRACE_BEGIN("start");
+ cache_t* cache = start_cache_collection();
+ ATRACE_END();
+
+ ATRACE_BEGIN("add");
+ for (auto user : get_known_users(uuid_)) {
+ add_cache_files(cache, create_data_user_ce_path(uuid_, user));
+ add_cache_files(cache, create_data_user_de_path(uuid_, user));
+ add_cache_files(cache,
+ StringPrintf("%s/Android/data", create_data_media_path(uuid_, user).c_str()));
+ }
+ ATRACE_END();
+
+ ATRACE_BEGIN("clear");
+ clear_cache_files(data_path, cache, freeStorageSize);
+ ATRACE_END();
+
+ ATRACE_BEGIN("finish");
+ finish_cache_collection(cache);
+ ATRACE_END();
+ }
+
+ free = data_disk_free(data_path);
+ if (free >= freeStorageSize) {
+ return ok();
+ } else {
+ return error(StringPrintf("Failed to free up %" PRId64 " on %s; final free space %" PRId64,
+ freeStorageSize, data_path.c_str(), free));
+ }
+}
+
+binder::Status InstalldNativeService::rmdex(const std::string& codePath,
+ const std::string& instructionSet) {
+ ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ char dex_path[PKG_PATH_MAX];
+
+ const char* path = codePath.c_str();
+ const char* instruction_set = instructionSet.c_str();
+
+ if (validate_apk_path(path) && validate_system_app_path(path)) {
+ return error("Invalid path " + codePath);
+ }
+
+ if (!create_cache_path(dex_path, path, instruction_set)) {
+ return error("Failed to create cache path for " + codePath);
+ }
+
+ ALOGV("unlink %s\n", dex_path);
+ if (unlink(dex_path) < 0) {
+ return error(StringPrintf("Failed to unlink %s", dex_path));
+ } else {
+ return ok();
+ }
+}
+
+struct stats {
+ int64_t codeSize;
+ int64_t dataSize;
+ int64_t cacheSize;
+};
+
+#if MEASURE_DEBUG
+static std::string toString(std::vector<int64_t> values) {
+ std::stringstream res;
+ res << "[";
+ for (size_t i = 0; i < values.size(); i++) {
+ res << values[i];
+ if (i < values.size() - 1) {
+ res << ",";
+ }
+ }
+ res << "]";
+ return res.str();
+}
+#endif
+
+static void collectQuotaStats(const std::string& device, int32_t userId,
+ int32_t appId, struct stats* stats, struct stats* extStats) {
+ if (device.empty()) return;
+
+ struct dqblk dq;
+
+ uid_t uid = multiuser_get_uid(userId, appId);
+ if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
+ reinterpret_cast<char*>(&dq)) != 0) {
+ if (errno != ESRCH) {
+ PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
+ }
+ } else {
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
+#endif
+ stats->dataSize += dq.dqb_curspace;
+ }
+
+ int cacheGid = multiuser_get_cache_gid(userId, appId);
+ if (cacheGid != -1) {
+ if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), cacheGid,
+ reinterpret_cast<char*>(&dq)) != 0) {
+ if (errno != ESRCH) {
+ PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << cacheGid;
+ }
+ } else {
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "quotactl() for GID " << cacheGid << " " << dq.dqb_curspace;
+#endif
+ stats->cacheSize += dq.dqb_curspace;
+ }
+ }
+
+ int extGid = multiuser_get_ext_gid(userId, appId);
+ if (extGid != -1) {
+ if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), extGid,
+ reinterpret_cast<char*>(&dq)) != 0) {
+ if (errno != ESRCH) {
+ PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << extGid;
+ }
+ } else {
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "quotactl() for GID " << extGid << " " << dq.dqb_curspace;
+#endif
+ extStats->dataSize += dq.dqb_curspace;
+ }
+ }
+
+ int sharedGid = multiuser_get_shared_gid(userId, appId);
+ if (sharedGid != -1) {
+ if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), sharedGid,
+ reinterpret_cast<char*>(&dq)) != 0) {
+ if (errno != ESRCH) {
+ PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << sharedGid;
+ }
+ } else {
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "quotactl() for GID " << sharedGid << " " << dq.dqb_curspace;
+#endif
+ stats->codeSize += dq.dqb_curspace;
+ }
+ }
+}
+
+static void collectManualStats(const std::string& path, struct stats* stats) {
+ DIR *d;
+ int dfd;
+ struct dirent *de;
+ struct stat s;
+
+ d = opendir(path.c_str());
+ if (d == nullptr) {
+ if (errno != ENOENT) {
+ PLOG(WARNING) << "Failed to open " << path;
+ }
+ return;
+ }
+ dfd = dirfd(d);
+ while ((de = readdir(d))) {
+ const char *name = de->d_name;
+
+ int64_t size = 0;
+ if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
+ size = s.st_blocks * 512;
+ }
+
+ if (de->d_type == DT_DIR) {
+ if (!strcmp(name, ".")) {
+ // Don't recurse, but still count node size
+ } else if (!strcmp(name, "..")) {
+ // Don't recurse or count node size
+ continue;
+ } else {
+ // Measure all children nodes
+ size = 0;
+ calculate_tree_size(StringPrintf("%s/%s", path.c_str(), name), &size);
+ }
+
+ if (!strcmp(name, "cache") || !strcmp(name, "code_cache")) {
+ stats->cacheSize += size;
+ }
+ }
+
+ // Legacy symlink isn't owned by app
+ if (de->d_type == DT_LNK && !strcmp(name, "lib")) {
+ continue;
+ }
+
+ // Everything found inside is considered data
+ stats->dataSize += size;
+ }
+ closedir(d);
+}
+
+static void collectManualStatsForUser(const std::string& path, struct stats* stats,
+ bool exclude_apps = false) {
+ DIR *d;
+ int dfd;
+ struct dirent *de;
+ struct stat s;
+
+ d = opendir(path.c_str());
+ if (d == nullptr) {
+ if (errno != ENOENT) {
+ PLOG(WARNING) << "Failed to open " << path;
+ }
+ return;
+ }
+ dfd = dirfd(d);
+ while ((de = readdir(d))) {
+ if (de->d_type == DT_DIR) {
+ const char *name = de->d_name;
+ if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) != 0) {
+ continue;
+ }
+ if (!strcmp(name, ".") || !strcmp(name, "..")) {
+ continue;
+ } else if (exclude_apps && (s.st_uid >= AID_APP_START && s.st_uid <= AID_APP_END)) {
+ continue;
+ } else {
+ collectManualStats(StringPrintf("%s/%s", path.c_str(), name), stats);
+ }
+ }
+ }
+ closedir(d);
+}
+
+static void collectManualExternalStatsForUser(const std::string& path, struct stats* stats) {
+ FTS *fts;
+ FTSENT *p;
+ char *argv[] = { (char*) path.c_str(), nullptr };
+ if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_XDEV, NULL))) {
+ PLOG(ERROR) << "Failed to fts_open " << path;
+ return;
+ }
+ while ((p = fts_read(fts)) != NULL) {
+ p->fts_number = p->fts_parent->fts_number;
+ switch (p->fts_info) {
+ case FTS_D:
+ if (p->fts_level == 4
+ && !strcmp(p->fts_name, "cache")
+ && !strcmp(p->fts_parent->fts_parent->fts_name, "data")
+ && !strcmp(p->fts_parent->fts_parent->fts_parent->fts_name, "Android")) {
+ p->fts_number = 1;
+ }
+ // Fall through to count the directory
+ case FTS_DEFAULT:
+ case FTS_F:
+ case FTS_SL:
+ case FTS_SLNONE:
+ int64_t size = (p->fts_statp->st_blocks * 512);
+ if (p->fts_number == 1) {
+ stats->cacheSize += size;
+ }
+ stats->dataSize += size;
+ break;
+ }
+ }
+ fts_close(fts);
+}
+
+binder::Status InstalldNativeService::getAppSize(const std::unique_ptr<std::string>& uuid,
+ const std::vector<std::string>& packageNames, int32_t userId, int32_t flags,
+ int32_t appId, const std::vector<int64_t>& ceDataInodes,
+ const std::vector<std::string>& codePaths, std::vector<int64_t>* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ for (auto packageName : packageNames) {
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ }
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ // When modifying this logic, always verify using tests:
+ // runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java -m testGetAppSize
+
+#if MEASURE_DEBUG
+ LOG(INFO) << "Measuring user " << userId << " app " << appId;
+#endif
+
+ // Here's a summary of the common storage locations across the platform,
+ // and how they're each tagged:
+ //
+ // /data/app/com.example UID system
+ // /data/app/com.example/oat UID system
+ // /data/user/0/com.example UID u0_a10 GID u0_a10
+ // /data/user/0/com.example/cache UID u0_a10 GID u0_a10_cache
+ // /data/media/0/foo.txt UID u0_media_rw
+ // /data/media/0/bar.jpg UID u0_media_rw GID u0_media_image
+ // /data/media/0/Android/data/com.example UID u0_media_rw GID u0_a10_ext
+ // /data/media/0/Android/data/com.example/cache UID u0_media_rw GID u0_a10_ext_cache
+ // /data/media/obb/com.example UID system
+
+ struct stats stats;
+ struct stats extStats;
+ memset(&stats, 0, sizeof(stats));
+ memset(&extStats, 0, sizeof(extStats));
+
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+
+ auto device = findQuotaDeviceForUuid(uuid);
+ if (device.empty()) {
+ flags &= ~FLAG_USE_QUOTA;
+ }
+
+ ATRACE_BEGIN("obb");
+ for (auto packageName : packageNames) {
+ auto obbCodePath = create_data_media_obb_path(uuid_, packageName.c_str());
+ calculate_tree_size(obbCodePath, &extStats.codeSize);
+ }
+ ATRACE_END();
+
+ if (flags & FLAG_USE_QUOTA && appId >= AID_APP_START) {
+ ATRACE_BEGIN("code");
+ for (auto codePath : codePaths) {
+ calculate_tree_size(codePath, &stats.codeSize, -1,
+ multiuser_get_shared_gid(userId, appId));
+ }
+ ATRACE_END();
+
+ ATRACE_BEGIN("quota");
+ collectQuotaStats(device, userId, appId, &stats, &extStats);
+ ATRACE_END();
+
+ } else {
+ ATRACE_BEGIN("code");
+ for (auto codePath : codePaths) {
+ calculate_tree_size(codePath, &stats.codeSize);
+ }
+ ATRACE_END();
+
+ for (size_t i = 0; i < packageNames.size(); i++) {
+ const char* pkgname = packageNames[i].c_str();
+
+ ATRACE_BEGIN("data");
+ auto cePath = create_data_user_ce_package_path(uuid_, userId, pkgname, ceDataInodes[i]);
+ collectManualStats(cePath, &stats);
+ auto dePath = create_data_user_de_package_path(uuid_, userId, pkgname);
+ collectManualStats(dePath, &stats);
+ ATRACE_END();
+
+ ATRACE_BEGIN("profiles");
+ auto userProfilePath = create_primary_current_profile_package_dir_path(userId, pkgname);
+ calculate_tree_size(userProfilePath, &stats.dataSize);
+ auto refProfilePath = create_primary_reference_profile_package_dir_path(pkgname);
+ calculate_tree_size(refProfilePath, &stats.codeSize);
+ ATRACE_END();
+
+ ATRACE_BEGIN("external");
+ auto extPath = create_data_media_package_path(uuid_, userId, "data", pkgname);
+ collectManualStats(extPath, &extStats);
+ auto mediaPath = create_data_media_package_path(uuid_, userId, "media", pkgname);
+ calculate_tree_size(mediaPath, &extStats.dataSize);
+ ATRACE_END();
+ }
+
+ ATRACE_BEGIN("dalvik");
+ int32_t sharedGid = multiuser_get_shared_gid(userId, appId);
+ if (sharedGid != -1) {
+ calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize,
+ sharedGid, -1);
+ }
+ calculate_tree_size(create_primary_cur_profile_dir_path(userId), &stats.dataSize,
+ multiuser_get_uid(userId, appId), -1);
+ ATRACE_END();
+ }
+
+ std::vector<int64_t> ret;
+ ret.push_back(stats.codeSize);
+ ret.push_back(stats.dataSize);
+ ret.push_back(stats.cacheSize);
+ ret.push_back(extStats.codeSize);
+ ret.push_back(extStats.dataSize);
+ ret.push_back(extStats.cacheSize);
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "Final result " << toString(ret);
+#endif
+ *_aidl_return = ret;
+ return ok();
+}
+
+binder::Status InstalldNativeService::getUserSize(const std::unique_ptr<std::string>& uuid,
+ int32_t userId, int32_t flags, const std::vector<int32_t>& appIds,
+ std::vector<int64_t>* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ // When modifying this logic, always verify using tests:
+ // runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java -m testGetUserSize
+
+#if MEASURE_DEBUG
+ LOG(INFO) << "Measuring user " << userId;
+#endif
+
+ struct stats stats;
+ struct stats extStats;
+ memset(&stats, 0, sizeof(stats));
+ memset(&extStats, 0, sizeof(extStats));
+
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+
+ auto device = findQuotaDeviceForUuid(uuid);
+ if (device.empty()) {
+ flags &= ~FLAG_USE_QUOTA;
+ }
+
+ if (flags & FLAG_USE_QUOTA) {
+ struct dqblk dq;
+
+ ATRACE_BEGIN("obb");
+ if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), AID_MEDIA_OBB,
+ reinterpret_cast<char*>(&dq)) != 0) {
+ if (errno != ESRCH) {
+ PLOG(ERROR) << "Failed to quotactl " << device << " for GID " << AID_MEDIA_OBB;
+ }
+ } else {
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "quotactl() for GID " << AID_MEDIA_OBB << " " << dq.dqb_curspace;
+#endif
+ extStats.codeSize += dq.dqb_curspace;
+ }
+ ATRACE_END();
+
+ ATRACE_BEGIN("code");
+ calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize, -1, -1, true);
+ ATRACE_END();
+
+ ATRACE_BEGIN("data");
+ auto cePath = create_data_user_ce_path(uuid_, userId);
+ collectManualStatsForUser(cePath, &stats, true);
+ auto dePath = create_data_user_de_path(uuid_, userId);
+ collectManualStatsForUser(dePath, &stats, true);
+ ATRACE_END();
+
+ ATRACE_BEGIN("profile");
+ auto userProfilePath = create_primary_cur_profile_dir_path(userId);
+ calculate_tree_size(userProfilePath, &stats.dataSize, -1, -1, true);
+ auto refProfilePath = create_primary_ref_profile_dir_path();
+ calculate_tree_size(refProfilePath, &stats.codeSize, -1, -1, true);
+ ATRACE_END();
+
+ ATRACE_BEGIN("external");
+ uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW);
+ if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
+ reinterpret_cast<char*>(&dq)) != 0) {
+ if (errno != ESRCH) {
+ PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
+ }
+ } else {
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
+#endif
+ extStats.dataSize += dq.dqb_curspace;
+ }
+ ATRACE_END();
+
+ ATRACE_BEGIN("dalvik");
+ calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize,
+ -1, -1, true);
+ calculate_tree_size(create_primary_cur_profile_dir_path(userId), &stats.dataSize,
+ -1, -1, true);
+ ATRACE_END();
+
+ ATRACE_BEGIN("quota");
+ for (auto appId : appIds) {
+ if (appId >= AID_APP_START) {
+ collectQuotaStats(device, userId, appId, &stats, &extStats);
+#if MEASURE_DEBUG
+ // Sleep to make sure we don't lose logs
+ usleep(1);
+#endif
+ }
+ }
+ ATRACE_END();
+ } else {
+ ATRACE_BEGIN("obb");
+ auto obbPath = create_data_path(uuid_) + "/media/obb";
+ calculate_tree_size(obbPath, &extStats.codeSize);
+ ATRACE_END();
+
+ ATRACE_BEGIN("code");
+ calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize);
+ ATRACE_END();
+
+ ATRACE_BEGIN("data");
+ auto cePath = create_data_user_ce_path(uuid_, userId);
+ collectManualStatsForUser(cePath, &stats);
+ auto dePath = create_data_user_de_path(uuid_, userId);
+ collectManualStatsForUser(dePath, &stats);
+ ATRACE_END();
+
+ ATRACE_BEGIN("profile");
+ auto userProfilePath = create_primary_cur_profile_dir_path(userId);
+ calculate_tree_size(userProfilePath, &stats.dataSize);
+ auto refProfilePath = create_primary_ref_profile_dir_path();
+ calculate_tree_size(refProfilePath, &stats.codeSize);
+ ATRACE_END();
+
+ ATRACE_BEGIN("external");
+ auto dataMediaPath = create_data_media_path(uuid_, userId);
+ collectManualExternalStatsForUser(dataMediaPath, &extStats);
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "Measured external data " << extStats.dataSize << " cache "
+ << extStats.cacheSize;
+#endif
+ ATRACE_END();
+
+ ATRACE_BEGIN("dalvik");
+ calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize);
+ calculate_tree_size(create_primary_cur_profile_dir_path(userId), &stats.dataSize);
+ ATRACE_END();
+ }
+
+ std::vector<int64_t> ret;
+ ret.push_back(stats.codeSize);
+ ret.push_back(stats.dataSize);
+ ret.push_back(stats.cacheSize);
+ ret.push_back(extStats.codeSize);
+ ret.push_back(extStats.dataSize);
+ ret.push_back(extStats.cacheSize);
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "Final result " << toString(ret);
+#endif
+ *_aidl_return = ret;
+ return ok();
+}
+
+binder::Status InstalldNativeService::getExternalSize(const std::unique_ptr<std::string>& uuid,
+ int32_t userId, int32_t flags, std::vector<int64_t>* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ // When modifying this logic, always verify using tests:
+ // runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java -m testGetExternalSize
+
+#if MEASURE_DEBUG
+ LOG(INFO) << "Measuring external " << userId;
+#endif
+
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+
+ int64_t totalSize = 0;
+ int64_t audioSize = 0;
+ int64_t videoSize = 0;
+ int64_t imageSize = 0;
+
+ auto device = findQuotaDeviceForUuid(uuid);
+ if (device.empty()) {
+ flags &= ~FLAG_USE_QUOTA;
+ }
+
+ if (flags & FLAG_USE_QUOTA) {
+ struct dqblk dq;
+
+ uid_t uid = multiuser_get_uid(userId, AID_MEDIA_RW);
+ if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
+ reinterpret_cast<char*>(&dq)) != 0) {
+ if (errno != ESRCH) {
+ PLOG(ERROR) << "Failed to quotactl " << device << " for UID " << uid;
+ }
+ } else {
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "quotactl() for UID " << uid << " " << dq.dqb_curspace;
+#endif
+ totalSize = dq.dqb_curspace;
+ }
+
+ gid_t audioGid = multiuser_get_uid(userId, AID_MEDIA_AUDIO);
+ if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), audioGid,
+ reinterpret_cast<char*>(&dq)) == 0) {
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "quotactl() for GID " << audioGid << " " << dq.dqb_curspace;
+#endif
+ audioSize = dq.dqb_curspace;
+ }
+ gid_t videoGid = multiuser_get_uid(userId, AID_MEDIA_VIDEO);
+ if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), videoGid,
+ reinterpret_cast<char*>(&dq)) == 0) {
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "quotactl() for GID " << videoGid << " " << dq.dqb_curspace;
+#endif
+ videoSize = dq.dqb_curspace;
+ }
+ gid_t imageGid = multiuser_get_uid(userId, AID_MEDIA_IMAGE);
+ if (quotactl(QCMD(Q_GETQUOTA, GRPQUOTA), device.c_str(), imageGid,
+ reinterpret_cast<char*>(&dq)) == 0) {
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "quotactl() for GID " << imageGid << " " << dq.dqb_curspace;
+#endif
+ imageSize = dq.dqb_curspace;
+ }
+ } else {
+ FTS *fts;
+ FTSENT *p;
+ auto path = create_data_media_path(uuid_, userId);
+ char *argv[] = { (char*) path.c_str(), nullptr };
+ if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_XDEV, NULL))) {
+ return error("Failed to fts_open " + path);
+ }
+ while ((p = fts_read(fts)) != NULL) {
+ char* ext;
+ int64_t size = (p->fts_statp->st_blocks * 512);
+ switch (p->fts_info) {
+ case FTS_F:
+ // Only categorize files not belonging to apps
+ if (p->fts_statp->st_gid < AID_APP_START) {
+ ext = strrchr(p->fts_name, '.');
+ if (ext != nullptr) {
+ switch (MatchExtension(++ext)) {
+ case AID_MEDIA_AUDIO: audioSize += size; break;
+ case AID_MEDIA_VIDEO: videoSize += size; break;
+ case AID_MEDIA_IMAGE: imageSize += size; break;
+ }
+ }
+ }
+ // Fall through to always count against total
+ case FTS_D:
+ case FTS_DEFAULT:
+ case FTS_SL:
+ case FTS_SLNONE:
+ totalSize += size;
+ break;
+ }
+ }
+ fts_close(fts);
+ }
+
+ std::vector<int64_t> ret;
+ ret.push_back(totalSize);
+ ret.push_back(audioSize);
+ ret.push_back(videoSize);
+ ret.push_back(imageSize);
+#if MEASURE_DEBUG
+ LOG(DEBUG) << "Final result " << toString(ret);
+#endif
+ *_aidl_return = ret;
+ return ok();
+}
+
+binder::Status InstalldNativeService::setAppQuota(const std::unique_ptr<std::string>& uuid,
+ int32_t userId, int32_t appId, int64_t cacheQuota) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ int32_t uid = multiuser_get_uid(userId, appId);
+ mCacheQuotas[uid] = cacheQuota;
+
+ return ok();
+}
+
+// Dumps the contents of a profile file, using pkgname's dex files for pretty
+// printing the result.
+binder::Status InstalldNativeService::dumpProfiles(int32_t uid, const std::string& packageName,
+ const std::string& codePaths, bool* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ const char* pkgname = packageName.c_str();
+ const char* code_paths = codePaths.c_str();
+
+ *_aidl_return = dump_profiles(uid, pkgname, code_paths);
+ return ok();
+}
+
+// TODO: Consider returning error codes.
+binder::Status InstalldNativeService::mergeProfiles(int32_t uid, const std::string& packageName,
+ bool* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ *_aidl_return = analyze_primary_profiles(uid, packageName);
+ return ok();
+}
+
+binder::Status InstalldNativeService::dexopt(const std::string& apkPath, int32_t uid,
+ const std::unique_ptr<std::string>& packageName, const std::string& instructionSet,
+ int32_t dexoptNeeded, const std::unique_ptr<std::string>& outputPath, int32_t dexFlags,
+ const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid,
+ const std::unique_ptr<std::string>& sharedLibraries) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ if (packageName && *packageName != "*") {
+ CHECK_ARGUMENT_PACKAGE_NAME(*packageName);
+ }
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ const char* apk_path = apkPath.c_str();
+ const char* pkgname = packageName ? packageName->c_str() : "*";
+ const char* instruction_set = instructionSet.c_str();
+ const char* oat_dir = outputPath ? outputPath->c_str() : nullptr;
+ const char* compiler_filter = compilerFilter.c_str();
+ const char* volume_uuid = uuid ? uuid->c_str() : nullptr;
+ const char* shared_libraries = sharedLibraries ? sharedLibraries->c_str() : nullptr;
+
+ int res = android::installd::dexopt(apk_path, uid, pkgname, instruction_set, dexoptNeeded,
+ oat_dir, dexFlags, compiler_filter, volume_uuid, shared_libraries);
+ return res ? error(res, "Failed to dexopt") : ok();
+}
+
+binder::Status InstalldNativeService::markBootComplete(const std::string& instructionSet) {
+ ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ const char* instruction_set = instructionSet.c_str();
+
+ char boot_marker_path[PKG_PATH_MAX];
+ sprintf(boot_marker_path,
+ "%s/%s/%s/.booting",
+ android_data_dir.path,
+ DALVIK_CACHE,
+ instruction_set);
+
+ ALOGV("mark_boot_complete : %s", boot_marker_path);
+ if (unlink(boot_marker_path) != 0) {
+ return error(StringPrintf("Failed to unlink %s", boot_marker_path));
+ }
+ return ok();
+}
+
+void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid,
+ struct stat* statbuf)
+{
+ while (path[basepos] != 0) {
+ if (path[basepos] == '/') {
+ path[basepos] = 0;
+ if (lstat(path, statbuf) < 0) {
+ ALOGV("Making directory: %s\n", path);
+ if (mkdir(path, mode) == 0) {
+ chown(path, uid, gid);
+ } else {
+ ALOGW("Unable to make directory %s: %s\n", path, strerror(errno));
+ }
+ }
+ path[basepos] = '/';
+ basepos++;
+ }
+ basepos++;
+ }
+}
+
+binder::Status InstalldNativeService::linkNativeLibraryDirectory(
+ const std::unique_ptr<std::string>& uuid, const std::string& packageName,
+ const std::string& nativeLibPath32, int32_t userId) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+ const char* pkgname = packageName.c_str();
+ const char* asecLibDir = nativeLibPath32.c_str();
+ struct stat s, libStat;
+ binder::Status res = ok();
+
+ auto _pkgdir = create_data_user_ce_package_path(uuid_, userId, pkgname);
+ auto _libsymlink = _pkgdir + PKG_LIB_POSTFIX;
+
+ const char* pkgdir = _pkgdir.c_str();
+ const char* libsymlink = _libsymlink.c_str();
+
+ if (stat(pkgdir, &s) < 0) {
+ return error("Failed to stat " + _pkgdir);
+ }
+
+ if (chown(pkgdir, AID_INSTALL, AID_INSTALL) < 0) {
+ return error("Failed to chown " + _pkgdir);
+ }
+
+ if (chmod(pkgdir, 0700) < 0) {
+ res = error("Failed to chmod " + _pkgdir);
+ goto out;
+ }
+
+ if (lstat(libsymlink, &libStat) < 0) {
+ if (errno != ENOENT) {
+ res = error("Failed to stat " + _libsymlink);
+ goto out;
+ }
+ } else {
+ if (S_ISDIR(libStat.st_mode)) {
+ if (delete_dir_contents(libsymlink, 1, NULL) < 0) {
+ res = error("Failed to delete " + _libsymlink);
+ goto out;
+ }
+ } else if (S_ISLNK(libStat.st_mode)) {
+ if (unlink(libsymlink) < 0) {
+ res = error("Failed to unlink " + _libsymlink);
+ goto out;
+ }
+ }
+ }
+
+ if (symlink(asecLibDir, libsymlink) < 0) {
+ res = error("Failed to symlink " + _libsymlink + " to " + nativeLibPath32);
+ goto out;
+ }
+
+out:
+ if (chmod(pkgdir, s.st_mode) < 0) {
+ auto msg = "Failed to cleanup chmod " + _pkgdir;
+ if (res.isOk()) {
+ res = error(msg);
+ } else {
+ PLOG(ERROR) << msg;
+ }
+ }
+
+ if (chown(pkgdir, s.st_uid, s.st_gid) < 0) {
+ auto msg = "Failed to cleanup chown " + _pkgdir;
+ if (res.isOk()) {
+ res = error(msg);
+ } else {
+ PLOG(ERROR) << msg;
+ }
+ }
+
+ return res;
+}
+
+static void run_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd)
+{
+ static const char *IDMAP_BIN = "/system/bin/idmap";
+ static const size_t MAX_INT_LEN = 32;
+ char idmap_str[MAX_INT_LEN];
+
+ snprintf(idmap_str, sizeof(idmap_str), "%d", idmap_fd);
+
+ execl(IDMAP_BIN, IDMAP_BIN, "--fd", target_apk, overlay_apk, idmap_str, (char*)NULL);
+ ALOGE("execl(%s) failed: %s\n", IDMAP_BIN, strerror(errno));
+}
+
+// Transform string /a/b/c.apk to (prefix)/a@b@c.apk@(suffix)
+// eg /a/b/c.apk to /data/resource-cache/a@b@c.apk@idmap
+static int flatten_path(const char *prefix, const char *suffix,
+ const char *overlay_path, char *idmap_path, size_t N)
+{
+ if (overlay_path == NULL || idmap_path == NULL) {
+ return -1;
+ }
+ const size_t len_overlay_path = strlen(overlay_path);
+ // will access overlay_path + 1 further below; requires absolute path
+ if (len_overlay_path < 2 || *overlay_path != '/') {
+ return -1;
+ }
+ const size_t len_idmap_root = strlen(prefix);
+ const size_t len_suffix = strlen(suffix);
+ if (SIZE_MAX - len_idmap_root < len_overlay_path ||
+ SIZE_MAX - (len_idmap_root + len_overlay_path) < len_suffix) {
+ // additions below would cause overflow
+ return -1;
+ }
+ if (N < len_idmap_root + len_overlay_path + len_suffix) {
+ return -1;
+ }
+ memset(idmap_path, 0, N);
+ snprintf(idmap_path, N, "%s%s%s", prefix, overlay_path + 1, suffix);
+ char *ch = idmap_path + len_idmap_root;
+ while (*ch != '\0') {
+ if (*ch == '/') {
+ *ch = '@';
+ }
+ ++ch;
+ }
+ return 0;
+}
+
+binder::Status InstalldNativeService::idmap(const std::string& targetApkPath,
+ const std::string& overlayApkPath, int32_t uid) {
+ ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ const char* target_apk = targetApkPath.c_str();
+ const char* overlay_apk = overlayApkPath.c_str();
+ ALOGV("idmap target_apk=%s overlay_apk=%s uid=%d\n", target_apk, overlay_apk, uid);
+
+ int idmap_fd = -1;
+ char idmap_path[PATH_MAX];
+
+ if (flatten_path(IDMAP_PREFIX, IDMAP_SUFFIX, overlay_apk,
+ idmap_path, sizeof(idmap_path)) == -1) {
+ ALOGE("idmap cannot generate idmap path for overlay %s\n", overlay_apk);
+ goto fail;
+ }
+
+ unlink(idmap_path);
+ idmap_fd = open(idmap_path, O_RDWR | O_CREAT | O_EXCL, 0644);
+ if (idmap_fd < 0) {
+ ALOGE("idmap cannot open '%s' for output: %s\n", idmap_path, strerror(errno));
+ goto fail;
+ }
+ if (fchown(idmap_fd, AID_SYSTEM, uid) < 0) {
+ ALOGE("idmap cannot chown '%s'\n", idmap_path);
+ goto fail;
+ }
+ if (fchmod(idmap_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) {
+ ALOGE("idmap cannot chmod '%s'\n", idmap_path);
+ goto fail;
+ }
+
+ pid_t pid;
+ pid = fork();
+ if (pid == 0) {
+ /* child -- drop privileges before continuing */
+ if (setgid(uid) != 0) {
+ ALOGE("setgid(%d) failed during idmap\n", uid);
+ exit(1);
+ }
+ if (setuid(uid) != 0) {
+ ALOGE("setuid(%d) failed during idmap\n", uid);
+ exit(1);
+ }
+ if (flock(idmap_fd, LOCK_EX | LOCK_NB) != 0) {
+ ALOGE("flock(%s) failed during idmap: %s\n", idmap_path, strerror(errno));
+ exit(1);
+ }
+
+ run_idmap(target_apk, overlay_apk, idmap_fd);
+ exit(1); /* only if exec call to idmap failed */
+ } else {
+ int status = wait_child(pid);
+ if (status != 0) {
+ ALOGE("idmap failed, status=0x%04x\n", status);
+ goto fail;
+ }
+ }
+
+ close(idmap_fd);
+ return ok();
+fail:
+ if (idmap_fd >= 0) {
+ close(idmap_fd);
+ unlink(idmap_path);
+ }
+ return error();
+}
+
+binder::Status InstalldNativeService::restoreconAppData(const std::unique_ptr<std::string>& uuid,
+ const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
+ const std::string& seInfo) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(uuid);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ binder::Status res = ok();
+
+ // SELINUX_ANDROID_RESTORECON_DATADATA flag is set by libselinux. Not needed here.
+ unsigned int seflags = SELINUX_ANDROID_RESTORECON_RECURSE;
+ const char* uuid_ = uuid ? uuid->c_str() : nullptr;
+ const char* pkgName = packageName.c_str();
+ const char* seinfo = seInfo.c_str();
+
+ uid_t uid = multiuser_get_uid(userId, appId);
+ if (flags & FLAG_STORAGE_CE) {
+ auto path = create_data_user_ce_package_path(uuid_, userId, pkgName);
+ if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid, seflags) < 0) {
+ res = error("restorecon failed for " + path);
+ }
+ }
+ if (flags & FLAG_STORAGE_DE) {
+ auto path = create_data_user_de_package_path(uuid_, userId, pkgName);
+ if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid, seflags) < 0) {
+ res = error("restorecon failed for " + path);
+ }
+ }
+ return res;
+}
+
+binder::Status InstalldNativeService::createOatDir(const std::string& oatDir,
+ const std::string& instructionSet) {
+ ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ const char* oat_dir = oatDir.c_str();
+ const char* instruction_set = instructionSet.c_str();
+ char oat_instr_dir[PKG_PATH_MAX];
+
+ if (validate_apk_path(oat_dir)) {
+ return error("Invalid path " + oatDir);
+ }
+ if (fs_prepare_dir(oat_dir, S_IRWXU | S_IRWXG | S_IXOTH, AID_SYSTEM, AID_INSTALL)) {
+ return error("Failed to prepare " + oatDir);
+ }
+ if (selinux_android_restorecon(oat_dir, 0)) {
+ return error("Failed to restorecon " + oatDir);
+ }
+ snprintf(oat_instr_dir, PKG_PATH_MAX, "%s/%s", oat_dir, instruction_set);
+ if (fs_prepare_dir(oat_instr_dir, S_IRWXU | S_IRWXG | S_IXOTH, AID_SYSTEM, AID_INSTALL)) {
+ return error(StringPrintf("Failed to prepare %s", oat_instr_dir));
+ }
+ return ok();
+}
+
+binder::Status InstalldNativeService::rmPackageDir(const std::string& packageDir) {
+ ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ if (validate_apk_path(packageDir.c_str())) {
+ return error("Invalid path " + packageDir);
+ }
+ if (delete_dir_contents_and_dir(packageDir) != 0) {
+ return error("Failed to delete " + packageDir);
+ }
+ return ok();
+}
+
+binder::Status InstalldNativeService::linkFile(const std::string& relativePath,
+ const std::string& fromBase, const std::string& toBase) {
+ ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ const char* relative_path = relativePath.c_str();
+ const char* from_base = fromBase.c_str();
+ const char* to_base = toBase.c_str();
+ char from_path[PKG_PATH_MAX];
+ char to_path[PKG_PATH_MAX];
+ snprintf(from_path, PKG_PATH_MAX, "%s/%s", from_base, relative_path);
+ snprintf(to_path, PKG_PATH_MAX, "%s/%s", to_base, relative_path);
+
+ if (validate_apk_path_subdirs(from_path)) {
+ return error(StringPrintf("Invalid from path %s", from_path));
+ }
+
+ if (validate_apk_path_subdirs(to_path)) {
+ return error(StringPrintf("Invalid to path %s", to_path));
+ }
+
+ if (link(from_path, to_path) < 0) {
+ return error(StringPrintf("Failed to link from %s to %s", from_path, to_path));
+ }
+
+ return ok();
+}
+
+binder::Status InstalldNativeService::moveAb(const std::string& apkPath,
+ const std::string& instructionSet, const std::string& outputPath) {
+ ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ const char* apk_path = apkPath.c_str();
+ const char* instruction_set = instructionSet.c_str();
+ const char* oat_dir = outputPath.c_str();
+
+ bool success = move_ab(apk_path, instruction_set, oat_dir);
+ return success ? ok() : error();
+}
+
+binder::Status InstalldNativeService::deleteOdex(const std::string& apkPath,
+ const std::string& instructionSet, const std::string& outputPath) {
+ ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ const char* apk_path = apkPath.c_str();
+ const char* instruction_set = instructionSet.c_str();
+ const char* oat_dir = outputPath.c_str();
+
+ bool res = delete_odex(apk_path, instruction_set, oat_dir);
+ return res ? ok() : error();
+}
+
+binder::Status InstalldNativeService::reconcileSecondaryDexFile(
+ const std::string& dexPath, const std::string& packageName, int32_t uid,
+ const std::vector<std::string>& isas, const std::unique_ptr<std::string>& volumeUuid,
+ int32_t storage_flag, bool* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ CHECK_ARGUMENT_UUID(volumeUuid);
+ CHECK_ARGUMENT_PACKAGE_NAME(packageName);
+
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+ bool result = android::installd::reconcile_secondary_dex_file(
+ dexPath, packageName, uid, isas, volumeUuid, storage_flag, _aidl_return);
+ return result ? ok() : error();
+}
+
+binder::Status InstalldNativeService::invalidateMounts() {
+ ENFORCE_UID(AID_SYSTEM);
+ std::lock_guard<std::recursive_mutex> lock(mLock);
+
+ mQuotaDevices.clear();
+
+ std::ifstream in("/proc/mounts");
+ if (!in.is_open()) {
+ return error("Failed to read mounts");
+ }
+
+ std::string source;
+ std::string target;
+ std::string ignored;
+ struct dqblk dq;
+ while (!in.eof()) {
+ std::getline(in, source, ' ');
+ std::getline(in, target, ' ');
+ std::getline(in, ignored);
+
+ if (source.compare(0, 11, "/dev/block/") == 0) {
+ if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), source.c_str(), 0,
+ reinterpret_cast<char*>(&dq)) == 0) {
+ LOG(DEBUG) << "Found " << source << " with quota";
+ mQuotaDevices[target] = source;
+ }
+ }
+ }
+ return ok();
+}
+
+std::string InstalldNativeService::findQuotaDeviceForUuid(
+ const std::unique_ptr<std::string>& uuid) {
+ auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
+ return mQuotaDevices[path];
+}
+
+} // namespace installd
+} // namespace android
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
new file mode 100644
index 0000000..37e0090
--- /dev/null
+++ b/cmds/installd/InstalldNativeService.h
@@ -0,0 +1,128 @@
+/*
+**
+** Copyright 2008, 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 COMMANDS_H_
+#define COMMANDS_H_
+
+#include <inttypes.h>
+#include <unistd.h>
+
+#include <vector>
+#include <unordered_map>
+
+#include <android-base/macros.h>
+#include <binder/BinderService.h>
+#include <cutils/multiuser.h>
+
+#include "android/os/BnInstalld.h"
+#include "installd_constants.h"
+
+namespace android {
+namespace installd {
+
+class InstalldNativeService : public BinderService<InstalldNativeService>, public os::BnInstalld {
+public:
+ static status_t start();
+ static char const* getServiceName() { return "installd"; }
+ virtual status_t dump(int fd, const Vector<String16> &args) override;
+
+ binder::Status createUserData(const std::unique_ptr<std::string>& uuid, int32_t userId,
+ int32_t userSerial, int32_t flags);
+ binder::Status destroyUserData(const std::unique_ptr<std::string>& uuid, int32_t userId,
+ int32_t flags);
+
+ binder::Status createAppData(const std::unique_ptr<std::string>& uuid,
+ const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
+ const std::string& seInfo, int32_t targetSdkVersion, int64_t* _aidl_return);
+ binder::Status restoreconAppData(const std::unique_ptr<std::string>& uuid,
+ const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
+ const std::string& seInfo);
+ binder::Status migrateAppData(const std::unique_ptr<std::string>& uuid,
+ const std::string& packageName, int32_t userId, int32_t flags);
+ binder::Status clearAppData(const std::unique_ptr<std::string>& uuid,
+ const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode);
+ binder::Status destroyAppData(const std::unique_ptr<std::string>& uuid,
+ const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode);
+
+ binder::Status getAppSize(const std::unique_ptr<std::string>& uuid,
+ const std::vector<std::string>& packageNames, int32_t userId, int32_t flags,
+ int32_t appId, const std::vector<int64_t>& ceDataInodes,
+ const std::vector<std::string>& codePaths, std::vector<int64_t>* _aidl_return);
+ binder::Status getUserSize(const std::unique_ptr<std::string>& uuid,
+ int32_t userId, int32_t flags, const std::vector<int32_t>& appIds,
+ std::vector<int64_t>* _aidl_return);
+ binder::Status getExternalSize(const std::unique_ptr<std::string>& uuid,
+ int32_t userId, int32_t flags, std::vector<int64_t>* _aidl_return);
+
+ binder::Status setAppQuota(const std::unique_ptr<std::string>& uuid,
+ int32_t userId, int32_t appId, int64_t cacheQuota);
+
+ binder::Status moveCompleteApp(const std::unique_ptr<std::string>& fromUuid,
+ const std::unique_ptr<std::string>& toUuid, const std::string& packageName,
+ const std::string& dataAppName, int32_t appId, const std::string& seInfo,
+ int32_t targetSdkVersion);
+
+ binder::Status dexopt(const std::string& apkPath, int32_t uid,
+ const std::unique_ptr<std::string>& packageName, const std::string& instructionSet,
+ int32_t dexoptNeeded, const std::unique_ptr<std::string>& outputPath, int32_t dexFlags,
+ const std::string& compilerFilter, const std::unique_ptr<std::string>& uuid,
+ const std::unique_ptr<std::string>& sharedLibraries);
+
+ binder::Status rmdex(const std::string& codePath, const std::string& instructionSet);
+
+ binder::Status mergeProfiles(int32_t uid, const std::string& packageName, bool* _aidl_return);
+ binder::Status dumpProfiles(int32_t uid, const std::string& packageName,
+ const std::string& codePaths, bool* _aidl_return);
+ binder::Status clearAppProfiles(const std::string& packageName);
+ binder::Status destroyAppProfiles(const std::string& packageName);
+
+ binder::Status idmap(const std::string& targetApkPath, const std::string& overlayApkPath,
+ int32_t uid);
+ binder::Status rmPackageDir(const std::string& packageDir);
+ binder::Status markBootComplete(const std::string& instructionSet);
+ binder::Status freeCache(const std::unique_ptr<std::string>& uuid, int64_t freeStorageSize,
+ int32_t flags);
+ binder::Status linkNativeLibraryDirectory(const std::unique_ptr<std::string>& uuid,
+ const std::string& packageName, const std::string& nativeLibPath32, int32_t userId);
+ binder::Status createOatDir(const std::string& oatDir, const std::string& instructionSet);
+ binder::Status linkFile(const std::string& relativePath, const std::string& fromBase,
+ const std::string& toBase);
+ binder::Status moveAb(const std::string& apkPath, const std::string& instructionSet,
+ const std::string& outputPath);
+ binder::Status deleteOdex(const std::string& apkPath, const std::string& instructionSet,
+ const std::string& outputPath);
+ binder::Status reconcileSecondaryDexFile(const std::string& dexPath,
+ const std::string& packageName, int32_t uid, const std::vector<std::string>& isa,
+ const std::unique_ptr<std::string>& volumeUuid, int32_t storage_flag, bool* _aidl_return);
+
+ binder::Status invalidateMounts();
+
+private:
+ std::recursive_mutex mLock;
+
+ /* Map from mount point to underlying device node */
+ std::unordered_map<std::string, std::string> mQuotaDevices;
+ /* Map from UID to cache quota size */
+ std::unordered_map<uid_t, int64_t> mCacheQuotas;
+
+ std::string findQuotaDeviceForUuid(const std::unique_ptr<std::string>& uuid);
+};
+
+} // namespace installd
+} // namespace android
+
+#endif // COMMANDS_H_
diff --git a/cmds/installd/MatchExtensionGen.h b/cmds/installd/MatchExtensionGen.h
new file mode 100644
index 0000000..fded6b7
--- /dev/null
+++ b/cmds/installd/MatchExtensionGen.h
@@ -0,0 +1,628 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+/******************************************************************
+ * THIS CODE WAS GENERATED BY matchgen.py, DO NOT MODIFY DIRECTLY *
+ ******************************************************************/
+
+#include <private/android_filesystem_config.h>
+
+int MatchExtension(const char* ext) {
+
+ switch (ext[0]) {
+ case '3':
+ switch (ext[1]) {
+ case 'g': case 'G':
+ switch (ext[2]) {
+ case '2':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ }
+ case 'p': case 'P':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ case 'p': case 'P':
+ switch (ext[4]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ case '2':
+ switch (ext[5]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ }
+ }
+ }
+ }
+ }
+ case 'a': case 'A':
+ switch (ext[1]) {
+ case 'a': case 'A':
+ switch (ext[2]) {
+ case 'c': case 'C':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_AUDIO;
+ }
+ }
+ case 'i': case 'I':
+ switch (ext[2]) {
+ case 'f': case 'F':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_AUDIO;
+ case 'c': case 'C':
+ switch (ext[4]) {
+ case '\0': return AID_MEDIA_AUDIO;
+ }
+ case 'f': case 'F':
+ switch (ext[4]) {
+ case '\0': return AID_MEDIA_AUDIO;
+ }
+ }
+ }
+ case 'm': case 'M':
+ switch (ext[2]) {
+ case 'r': case 'R':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_AUDIO;
+ }
+ }
+ case 'r': case 'R':
+ switch (ext[2]) {
+ case 't': case 'T':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ case 'w': case 'W':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ case 's': case 'S':
+ switch (ext[2]) {
+ case 'f': case 'F':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ }
+ case 'x': case 'X':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ }
+ }
+ case 'v': case 'V':
+ switch (ext[2]) {
+ case 'i': case 'I':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ }
+ }
+ case 'w': case 'W':
+ switch (ext[2]) {
+ case 'b': case 'B':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_AUDIO;
+ }
+ }
+ }
+ case 'b': case 'B':
+ switch (ext[1]) {
+ case 'm': case 'M':
+ switch (ext[2]) {
+ case 'p': case 'P':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ }
+ case 'c': case 'C':
+ switch (ext[1]) {
+ case 'r': case 'R':
+ switch (ext[2]) {
+ case '2':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ }
+ case 'd': case 'D':
+ switch (ext[1]) {
+ case 'i': case 'I':
+ switch (ext[2]) {
+ case 'f': case 'F':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ }
+ }
+ case 'l': case 'L':
+ switch (ext[2]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ }
+ case 'n': case 'N':
+ switch (ext[2]) {
+ case 'g': case 'G':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ case 'v': case 'V':
+ switch (ext[2]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ }
+ }
+ case 'f': case 'F':
+ switch (ext[1]) {
+ case 'l': case 'L':
+ switch (ext[2]) {
+ case 'a': case 'A':
+ switch (ext[3]) {
+ case 'c': case 'C':
+ switch (ext[4]) {
+ case '\0': return AID_MEDIA_AUDIO;
+ }
+ }
+ case 'i': case 'I':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ }
+ }
+ }
+ case 'g': case 'G':
+ switch (ext[1]) {
+ case 'i': case 'I':
+ switch (ext[2]) {
+ case 'f': case 'F':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ case 's': case 'S':
+ switch (ext[2]) {
+ case 'm': case 'M':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_AUDIO;
+ }
+ }
+ }
+ case 'j': case 'J':
+ switch (ext[1]) {
+ case 'n': case 'N':
+ switch (ext[2]) {
+ case 'g': case 'G':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ case 'p': case 'P':
+ switch (ext[2]) {
+ case 'e': case 'E':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ case 'g': case 'G':
+ switch (ext[4]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ case 'g': case 'G':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ }
+ case 'l': case 'L':
+ switch (ext[1]) {
+ case 's': case 'S':
+ switch (ext[2]) {
+ case 'f': case 'F':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ }
+ case 'x': case 'X':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ }
+ }
+ }
+ case 'm': case 'M':
+ switch (ext[1]) {
+ case '3':
+ switch (ext[2]) {
+ case 'u': case 'U':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_AUDIO;
+ }
+ }
+ case '4':
+ switch (ext[2]) {
+ case 'a': case 'A':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_AUDIO;
+ }
+ case 'v': case 'V':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ }
+ }
+ case 'k': case 'K':
+ switch (ext[2]) {
+ case 'a': case 'A':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_AUDIO;
+ }
+ case 'v': case 'V':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ }
+ }
+ case 'n': case 'N':
+ switch (ext[2]) {
+ case 'g': case 'G':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ }
+ }
+ case 'o': case 'O':
+ switch (ext[2]) {
+ case 'v': case 'V':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ case 'i': case 'I':
+ switch (ext[4]) {
+ case 'e': case 'E':
+ switch (ext[5]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ }
+ }
+ }
+ }
+ case 'p': case 'P':
+ switch (ext[2]) {
+ case '2':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_AUDIO;
+ }
+ case '3':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_AUDIO;
+ }
+ case '4':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ }
+ case 'e': case 'E':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ case 'g': case 'G':
+ switch (ext[4]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ case 'a': case 'A':
+ switch (ext[5]) {
+ case '\0': return AID_MEDIA_AUDIO;
+ }
+ }
+ }
+ case 'g': case 'G':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ case 'a': case 'A':
+ switch (ext[4]) {
+ case '\0': return AID_MEDIA_AUDIO;
+ }
+ }
+ }
+ case 'x': case 'X':
+ switch (ext[2]) {
+ case 'u': case 'U':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ }
+ }
+ }
+ case 'n': case 'N':
+ switch (ext[1]) {
+ case 'e': case 'E':
+ switch (ext[2]) {
+ case 'f': case 'F':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ case 'r': case 'R':
+ switch (ext[2]) {
+ case 'w': case 'W':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ }
+ case 'o': case 'O':
+ switch (ext[1]) {
+ case 'g': case 'G':
+ switch (ext[2]) {
+ case 'a': case 'A':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_AUDIO;
+ }
+ case 'g': case 'G':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_AUDIO;
+ }
+ }
+ case 'r': case 'R':
+ switch (ext[2]) {
+ case 'f': case 'F':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ }
+ case 'p': case 'P':
+ switch (ext[1]) {
+ case 'b': case 'B':
+ switch (ext[2]) {
+ case 'm': case 'M':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ case 'c': case 'C':
+ switch (ext[2]) {
+ case 'x': case 'X':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ case 'e': case 'E':
+ switch (ext[2]) {
+ case 'f': case 'F':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ case 'g': case 'G':
+ switch (ext[2]) {
+ case 'm': case 'M':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ case 'l': case 'L':
+ switch (ext[2]) {
+ case 's': case 'S':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_AUDIO;
+ }
+ }
+ case 'n': case 'N':
+ switch (ext[2]) {
+ case 'g': case 'G':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ case 'm': case 'M':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ case 'p': case 'P':
+ switch (ext[2]) {
+ case 'm': case 'M':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ case 's': case 'S':
+ switch (ext[2]) {
+ case 'd': case 'D':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ }
+ case 'q': case 'Q':
+ switch (ext[1]) {
+ case 't': case 'T':
+ switch (ext[2]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ }
+ }
+ case 'r': case 'R':
+ switch (ext[1]) {
+ case 'a': case 'A':
+ switch (ext[2]) {
+ case '\0': return AID_MEDIA_AUDIO;
+ case 'm': case 'M':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_AUDIO;
+ }
+ case 's': case 'S':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ case 'g': case 'G':
+ switch (ext[2]) {
+ case 'b': case 'B':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ case 'm': case 'M':
+ switch (ext[2]) {
+ case '\0': return AID_MEDIA_AUDIO;
+ }
+ case 'w': case 'W':
+ switch (ext[2]) {
+ case '2':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ }
+ case 's': case 'S':
+ switch (ext[1]) {
+ case 'd': case 'D':
+ switch (ext[2]) {
+ case '2':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_AUDIO;
+ }
+ }
+ case 'n': case 'N':
+ switch (ext[2]) {
+ case 'd': case 'D':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_AUDIO;
+ }
+ }
+ case 'r': case 'R':
+ switch (ext[2]) {
+ case 'w': case 'W':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ case 'v': case 'V':
+ switch (ext[2]) {
+ case 'g': case 'G':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ case 'z': case 'Z':
+ switch (ext[4]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ }
+ }
+ case 't': case 'T':
+ switch (ext[1]) {
+ case 'i': case 'I':
+ switch (ext[2]) {
+ case 'f': case 'F':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ case 'f': case 'F':
+ switch (ext[4]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ }
+ case 's': case 'S':
+ switch (ext[2]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ }
+ }
+ case 'v': case 'V':
+ switch (ext[1]) {
+ case 'o': case 'O':
+ switch (ext[2]) {
+ case 'b': case 'B':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ }
+ }
+ }
+ case 'w': case 'W':
+ switch (ext[1]) {
+ case 'a': case 'A':
+ switch (ext[2]) {
+ case 'v': case 'V':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_AUDIO;
+ }
+ case 'x': case 'X':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_AUDIO;
+ }
+ }
+ case 'b': case 'B':
+ switch (ext[2]) {
+ case 'm': case 'M':
+ switch (ext[3]) {
+ case 'p': case 'P':
+ switch (ext[4]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ }
+ case 'e': case 'E':
+ switch (ext[2]) {
+ case 'b': case 'B':
+ switch (ext[3]) {
+ case 'm': case 'M':
+ switch (ext[4]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ }
+ case 'p': case 'P':
+ switch (ext[4]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ }
+ case 'm': case 'M':
+ switch (ext[2]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ case 'a': case 'A':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_AUDIO;
+ }
+ case 'v': case 'V':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ }
+ case 'x': case 'X':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ }
+ }
+ case 'r': case 'R':
+ switch (ext[2]) {
+ case 'f': case 'F':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ }
+ }
+ case 'v': case 'V':
+ switch (ext[2]) {
+ case 'x': case 'X':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_VIDEO;
+ }
+ }
+ }
+ case 'x': case 'X':
+ switch (ext[1]) {
+ case 'b': case 'B':
+ switch (ext[2]) {
+ case 'm': case 'M':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ case 'p': case 'P':
+ switch (ext[2]) {
+ case 'm': case 'M':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ case 'w': case 'W':
+ switch (ext[2]) {
+ case 'd': case 'D':
+ switch (ext[3]) {
+ case '\0': return AID_MEDIA_IMAGE;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
new file mode 100644
index 0000000..4dbfa91
--- /dev/null
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/** {@hide} */
+interface IInstalld {
+ void createUserData(@nullable @utf8InCpp String uuid, int userId, int userSerial, int flags);
+ void destroyUserData(@nullable @utf8InCpp String uuid, int userId, int flags);
+
+ long createAppData(@nullable @utf8InCpp String uuid, in @utf8InCpp String packageName,
+ int userId, int flags, int appId, in @utf8InCpp String seInfo, int targetSdkVersion);
+ void restoreconAppData(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
+ int userId, int flags, int appId, @utf8InCpp String seInfo);
+ void migrateAppData(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
+ int userId, int flags);
+ void clearAppData(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
+ int userId, int flags, long ceDataInode);
+ void destroyAppData(@nullable @utf8InCpp String uuid, @utf8InCpp String packageName,
+ int userId, int flags, long ceDataInode);
+
+ long[] getAppSize(@nullable @utf8InCpp String uuid, in @utf8InCpp String[] packageNames,
+ int userId, int flags, int appId, in long[] ceDataInodes,
+ in @utf8InCpp String[] codePaths);
+ long[] getUserSize(@nullable @utf8InCpp String uuid, int userId, int flags, in int[] appIds);
+ long[] getExternalSize(@nullable @utf8InCpp String uuid, int userId, int flags);
+
+ void setAppQuota(@nullable @utf8InCpp String uuid, int userId, int appId, long cacheQuota);
+
+ void moveCompleteApp(@nullable @utf8InCpp String fromUuid, @nullable @utf8InCpp String toUuid,
+ @utf8InCpp String packageName, @utf8InCpp String dataAppName, int appId,
+ @utf8InCpp String seInfo, int targetSdkVersion);
+
+ void dexopt(@utf8InCpp String apkPath, int uid, @nullable @utf8InCpp String packageName,
+ @utf8InCpp String instructionSet, int dexoptNeeded,
+ @nullable @utf8InCpp String outputPath, int dexFlags,
+ @utf8InCpp String compilerFilter, @nullable @utf8InCpp String uuid,
+ @nullable @utf8InCpp String sharedLibraries);
+
+ void rmdex(@utf8InCpp String codePath, @utf8InCpp String instructionSet);
+
+ boolean mergeProfiles(int uid, @utf8InCpp String packageName);
+ boolean dumpProfiles(int uid, @utf8InCpp String packageName, @utf8InCpp String codePaths);
+ void clearAppProfiles(@utf8InCpp String packageName);
+ void destroyAppProfiles(@utf8InCpp String packageName);
+
+ void idmap(@utf8InCpp String targetApkPath, @utf8InCpp String overlayApkPath, int uid);
+ void rmPackageDir(@utf8InCpp String packageDir);
+ void markBootComplete(@utf8InCpp String instructionSet);
+ void freeCache(@nullable @utf8InCpp String uuid, long freeStorageSize, int flags);
+ void linkNativeLibraryDirectory(@nullable @utf8InCpp String uuid,
+ @utf8InCpp String packageName, @utf8InCpp String nativeLibPath32, int userId);
+ void createOatDir(@utf8InCpp String oatDir, @utf8InCpp String instructionSet);
+ void linkFile(@utf8InCpp String relativePath, @utf8InCpp String fromBase,
+ @utf8InCpp String toBase);
+ void moveAb(@utf8InCpp String apkPath, @utf8InCpp String instructionSet,
+ @utf8InCpp String outputPath);
+ void deleteOdex(@utf8InCpp String apkPath, @utf8InCpp String instructionSet,
+ @utf8InCpp String outputPath);
+
+ boolean reconcileSecondaryDexFile(@utf8InCpp String dexPath, @utf8InCpp String pkgName,
+ int uid, in @utf8InCpp String[] isas, @nullable @utf8InCpp String volume_uuid,
+ int storage_flag);
+
+ void invalidateMounts();
+}
diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
deleted file mode 100644
index 271c75b..0000000
--- a/cmds/installd/commands.cpp
+++ /dev/null
@@ -1,2294 +0,0 @@
-/*
-** Copyright 2008, 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 "commands.h"
-
-#include <errno.h>
-#include <inttypes.h>
-#include <regex>
-#include <stdlib.h>
-#include <sys/capability.h>
-#include <sys/file.h>
-#include <sys/resource.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/xattr.h>
-#include <unistd.h>
-
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <android-base/unique_fd.h>
-#include <cutils/fs.h>
-#include <cutils/log.h> // TODO: Move everything to base/logging.
-#include <cutils/sched_policy.h>
-#include <diskusage/dirsize.h>
-#include <logwrap/logwrap.h>
-#include <private/android_filesystem_config.h>
-#include <selinux/android.h>
-#include <system/thread_defs.h>
-
-#include <globals.h>
-#include <installd_deps.h>
-#include <otapreopt_utils.h>
-#include <utils.h>
-
-#ifndef LOG_TAG
-#define LOG_TAG "installd"
-#endif
-
-using android::base::EndsWith;
-using android::base::StringPrintf;
-
-namespace android {
-namespace installd {
-
-static constexpr const char* kCpPath = "/system/bin/cp";
-static constexpr const char* kXattrDefault = "user.default";
-
-static constexpr const char* PKG_LIB_POSTFIX = "/lib";
-static constexpr const char* CACHE_DIR_POSTFIX = "/cache";
-static constexpr const char* CODE_CACHE_DIR_POSTFIX = "/code_cache";
-
-static constexpr const char* IDMAP_PREFIX = "/data/resource-cache/";
-static constexpr const char* IDMAP_SUFFIX = "@idmap";
-
-// NOTE: keep in sync with StorageManager
-static constexpr int FLAG_STORAGE_DE = 1 << 0;
-static constexpr int FLAG_STORAGE_CE = 1 << 1;
-
-// NOTE: keep in sync with Installer
-static constexpr int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
-static constexpr int FLAG_CLEAR_CODE_CACHE_ONLY = 1 << 9;
-
-/* dexopt needed flags matching those in dalvik.system.DexFile */
-static constexpr int DEXOPT_DEX2OAT_NEEDED = 1;
-static constexpr int DEXOPT_PATCHOAT_NEEDED = 2;
-static constexpr int DEXOPT_SELF_PATCHOAT_NEEDED = 3;
-
-#define MIN_RESTRICTED_HOME_SDK_VERSION 24 // > M
-
-typedef int fd_t;
-
-static bool property_get_bool(const char* property_name, bool default_value = false) {
- char tmp_property_value[kPropertyValueMax];
- bool have_property = get_property(property_name, tmp_property_value, nullptr) > 0;
- if (!have_property) {
- return default_value;
- }
- return strcmp(tmp_property_value, "true") == 0;
-}
-
-// Keep profile paths in sync with ActivityThread.
-constexpr const char* PRIMARY_PROFILE_NAME = "primary.prof";
-static std::string create_primary_profile(const std::string& profile_dir) {
- return StringPrintf("%s/%s", profile_dir.c_str(), PRIMARY_PROFILE_NAME);
-}
-
-/**
- * Perform restorecon of the given path, but only perform recursive restorecon
- * if the label of that top-level file actually changed. This can save us
- * significant time by avoiding no-op traversals of large filesystem trees.
- */
-static int restorecon_app_data_lazy(const std::string& path, const char* seinfo, uid_t uid) {
- int res = 0;
- char* before = nullptr;
- char* after = nullptr;
-
- // Note that SELINUX_ANDROID_RESTORECON_DATADATA flag is set by
- // libselinux. Not needed here.
-
- if (lgetfilecon(path.c_str(), &before) < 0) {
- PLOG(ERROR) << "Failed before getfilecon for " << path;
- goto fail;
- }
- if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid, 0) < 0) {
- PLOG(ERROR) << "Failed top-level restorecon for " << path;
- goto fail;
- }
- if (lgetfilecon(path.c_str(), &after) < 0) {
- PLOG(ERROR) << "Failed after getfilecon for " << path;
- goto fail;
- }
-
- // If the initial top-level restorecon above changed the label, then go
- // back and restorecon everything recursively
- if (strcmp(before, after)) {
- LOG(DEBUG) << "Detected label change from " << before << " to " << after << " at " << path
- << "; running recursive restorecon";
- if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid,
- SELINUX_ANDROID_RESTORECON_RECURSE) < 0) {
- PLOG(ERROR) << "Failed recursive restorecon for " << path;
- goto fail;
- }
- }
-
- goto done;
-fail:
- res = -1;
-done:
- free(before);
- free(after);
- return res;
-}
-
-static int restorecon_app_data_lazy(const std::string& parent, const char* name, const char* seinfo,
- uid_t uid) {
- return restorecon_app_data_lazy(StringPrintf("%s/%s", parent.c_str(), name), seinfo, uid);
-}
-
-static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid) {
- if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, uid) != 0) {
- PLOG(ERROR) << "Failed to prepare " << path;
- return -1;
- }
- return 0;
-}
-
-static int prepare_app_dir(const std::string& parent, const char* name, mode_t target_mode,
- uid_t uid) {
- return prepare_app_dir(StringPrintf("%s/%s", parent.c_str(), name), target_mode, uid);
-}
-
-int create_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags,
- appid_t appid, const char* seinfo, int target_sdk_version) {
- uid_t uid = multiuser_get_uid(userid, appid);
- mode_t target_mode = target_sdk_version >= MIN_RESTRICTED_HOME_SDK_VERSION ? 0700 : 0751;
- if (flags & FLAG_STORAGE_CE) {
- auto path = create_data_user_ce_package_path(uuid, userid, pkgname);
- if (prepare_app_dir(path, target_mode, uid) ||
- prepare_app_dir(path, "cache", 0771, uid) ||
- prepare_app_dir(path, "code_cache", 0771, uid)) {
- return -1;
- }
-
- // Consider restorecon over contents if label changed
- if (restorecon_app_data_lazy(path, seinfo, uid) ||
- restorecon_app_data_lazy(path, "cache", seinfo, uid) ||
- restorecon_app_data_lazy(path, "code_cache", seinfo, uid)) {
- return -1;
- }
-
- // Remember inode numbers of cache directories so that we can clear
- // contents while CE storage is locked
- if (write_path_inode(path, "cache", kXattrInodeCache) ||
- write_path_inode(path, "code_cache", kXattrInodeCodeCache)) {
- return -1;
- }
- }
- if (flags & FLAG_STORAGE_DE) {
- auto path = create_data_user_de_package_path(uuid, userid, pkgname);
- if (prepare_app_dir(path, target_mode, uid)) {
- // TODO: include result once 25796509 is fixed
- return 0;
- }
-
- // Consider restorecon over contents if label changed
- if (restorecon_app_data_lazy(path, seinfo, uid)) {
- return -1;
- }
-
- if (property_get_bool("dalvik.vm.usejitprofiles")) {
- const std::string profile_path = create_data_user_profile_package_path(userid, pkgname);
- // read-write-execute only for the app user.
- if (fs_prepare_dir_strict(profile_path.c_str(), 0700, uid, uid) != 0) {
- PLOG(ERROR) << "Failed to prepare " << profile_path;
- return -1;
- }
- std::string profile_file = create_primary_profile(profile_path);
- // read-write only for the app user.
- if (fs_prepare_file_strict(profile_file.c_str(), 0600, uid, uid) != 0) {
- PLOG(ERROR) << "Failed to prepare " << profile_path;
- return -1;
- }
- const std::string ref_profile_path = create_data_ref_profile_package_path(pkgname);
- // dex2oat/profman runs under the shared app gid and it needs to read/write reference
- // profiles.
- appid_t shared_app_gid = multiuser_get_shared_app_gid(uid);
- if (fs_prepare_dir_strict(
- ref_profile_path.c_str(), 0700, shared_app_gid, shared_app_gid) != 0) {
- PLOG(ERROR) << "Failed to prepare " << ref_profile_path;
- return -1;
- }
- }
- }
- return 0;
-}
-
-int migrate_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags) {
- // This method only exists to upgrade system apps that have requested
- // forceDeviceEncrypted, so their default storage always lives in a
- // consistent location. This only works on non-FBE devices, since we
- // never want to risk exposing data on a device with real CE/DE storage.
-
- auto ce_path = create_data_user_ce_package_path(uuid, userid, pkgname);
- auto de_path = create_data_user_de_package_path(uuid, userid, pkgname);
-
- // If neither directory is marked as default, assume CE is default
- if (getxattr(ce_path.c_str(), kXattrDefault, nullptr, 0) == -1
- && getxattr(de_path.c_str(), kXattrDefault, nullptr, 0) == -1) {
- if (setxattr(ce_path.c_str(), kXattrDefault, nullptr, 0, 0) != 0) {
- PLOG(ERROR) << "Failed to mark default storage " << ce_path;
- return -1;
- }
- }
-
- // Migrate default data location if needed
- auto target = (flags & FLAG_STORAGE_DE) ? de_path : ce_path;
- auto source = (flags & FLAG_STORAGE_DE) ? ce_path : de_path;
-
- if (getxattr(target.c_str(), kXattrDefault, nullptr, 0) == -1) {
- LOG(WARNING) << "Requested default storage " << target
- << " is not active; migrating from " << source;
- if (delete_dir_contents_and_dir(target) != 0) {
- PLOG(ERROR) << "Failed to delete";
- return -1;
- }
- if (rename(source.c_str(), target.c_str()) != 0) {
- PLOG(ERROR) << "Failed to rename";
- return -1;
- }
- }
-
- return 0;
-}
-
-static bool clear_profile(const std::string& profile) {
- base::unique_fd ufd(open(profile.c_str(), O_WRONLY | O_NOFOLLOW | O_CLOEXEC));
- if (ufd.get() < 0) {
- if (errno != ENOENT) {
- PLOG(WARNING) << "Could not open profile " << profile;
- return false;
- } else {
- // Nothing to clear. That's ok.
- return true;
- }
- }
-
- if (flock(ufd.get(), LOCK_EX | LOCK_NB) != 0) {
- if (errno != EWOULDBLOCK) {
- PLOG(WARNING) << "Error locking profile " << profile;
- }
- // This implies that the app owning this profile is running
- // (and has acquired the lock).
- //
- // If we can't acquire the lock bail out since clearing is useless anyway
- // (the app will write again to the profile).
- //
- // Note:
- // This does not impact the this is not an issue for the profiling correctness.
- // In case this is needed because of an app upgrade, profiles will still be
- // eventually cleared by the app itself due to checksum mismatch.
- // If this is needed because profman advised, then keeping the data around
- // until the next run is again not an issue.
- //
- // If the app attempts to acquire a lock while we've held one here,
- // it will simply skip the current write cycle.
- return false;
- }
-
- bool truncated = ftruncate(ufd.get(), 0) == 0;
- if (!truncated) {
- PLOG(WARNING) << "Could not truncate " << profile;
- }
- if (flock(ufd.get(), LOCK_UN) != 0) {
- PLOG(WARNING) << "Error unlocking profile " << profile;
- }
- return truncated;
-}
-
-static bool clear_reference_profile(const char* pkgname) {
- std::string reference_profile_dir = create_data_ref_profile_package_path(pkgname);
- std::string reference_profile = create_primary_profile(reference_profile_dir);
- return clear_profile(reference_profile);
-}
-
-static bool clear_current_profile(const char* pkgname, userid_t user) {
- std::string profile_dir = create_data_user_profile_package_path(user, pkgname);
- std::string profile = create_primary_profile(profile_dir);
- return clear_profile(profile);
-}
-
-static bool clear_current_profiles(const char* pkgname) {
- bool success = true;
- std::vector<userid_t> users = get_known_users(/*volume_uuid*/ nullptr);
- for (auto user : users) {
- success &= clear_current_profile(pkgname, user);
- }
- return success;
-}
-
-int clear_app_profiles(const char* pkgname) {
- bool success = true;
- success &= clear_reference_profile(pkgname);
- success &= clear_current_profiles(pkgname);
- return success ? 0 : -1;
-}
-
-int clear_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags,
- ino_t ce_data_inode) {
- int res = 0;
- if (flags & FLAG_STORAGE_CE) {
- auto path = create_data_user_ce_package_path(uuid, userid, pkgname, ce_data_inode);
- if (flags & FLAG_CLEAR_CACHE_ONLY) {
- path = read_path_inode(path, "cache", kXattrInodeCache);
- } else if (flags & FLAG_CLEAR_CODE_CACHE_ONLY) {
- path = read_path_inode(path, "code_cache", kXattrInodeCodeCache);
- }
- if (access(path.c_str(), F_OK) == 0) {
- res |= delete_dir_contents(path);
- }
- }
- if (flags & FLAG_STORAGE_DE) {
- std::string suffix = "";
- bool only_cache = false;
- if (flags & FLAG_CLEAR_CACHE_ONLY) {
- suffix = CACHE_DIR_POSTFIX;
- only_cache = true;
- } else if (flags & FLAG_CLEAR_CODE_CACHE_ONLY) {
- suffix = CODE_CACHE_DIR_POSTFIX;
- only_cache = true;
- }
-
- auto path = create_data_user_de_package_path(uuid, userid, pkgname) + suffix;
- if (access(path.c_str(), F_OK) == 0) {
- // TODO: include result once 25796509 is fixed
- delete_dir_contents(path);
- }
- if (!only_cache) {
- if (!clear_current_profile(pkgname, userid)) {
- res |= -1;
- }
- }
- }
- return res;
-}
-
-static int destroy_app_reference_profile(const char *pkgname) {
- return delete_dir_contents_and_dir(
- create_data_ref_profile_package_path(pkgname),
- /*ignore_if_missing*/ true);
-}
-
-static int destroy_app_current_profiles(const char *pkgname, userid_t userid) {
- return delete_dir_contents_and_dir(
- create_data_user_profile_package_path(userid, pkgname),
- /*ignore_if_missing*/ true);
-}
-
-int destroy_app_profiles(const char *pkgname) {
- int result = 0;
- std::vector<userid_t> users = get_known_users(/*volume_uuid*/ nullptr);
- for (auto user : users) {
- result |= destroy_app_current_profiles(pkgname, user);
- }
- result |= destroy_app_reference_profile(pkgname);
- return result;
-}
-
-int destroy_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags,
- ino_t ce_data_inode) {
- int res = 0;
- if (flags & FLAG_STORAGE_CE) {
- res |= delete_dir_contents_and_dir(
- create_data_user_ce_package_path(uuid, userid, pkgname, ce_data_inode));
- }
- if (flags & FLAG_STORAGE_DE) {
- res |= delete_dir_contents_and_dir(
- create_data_user_de_package_path(uuid, userid, pkgname));
- destroy_app_current_profiles(pkgname, userid);
- // TODO(calin): If the package is still installed by other users it's probably
- // beneficial to keep the reference profile around.
- // Verify if it's ok to do that.
- destroy_app_reference_profile(pkgname);
- }
- return res;
-}
-
-int move_complete_app(const char *from_uuid, const char *to_uuid, const char *package_name,
- const char *data_app_name, appid_t appid, const char* seinfo, int target_sdk_version) {
- std::vector<userid_t> users = get_known_users(from_uuid);
-
- // Copy app
- {
- auto from = create_data_app_package_path(from_uuid, data_app_name);
- auto to = create_data_app_package_path(to_uuid, data_app_name);
- auto to_parent = create_data_app_path(to_uuid);
-
- char *argv[] = {
- (char*) kCpPath,
- (char*) "-F", /* delete any existing destination file first (--remove-destination) */
- (char*) "-p", /* preserve timestamps, ownership, and permissions */
- (char*) "-R", /* recurse into subdirectories (DEST must be a directory) */
- (char*) "-P", /* Do not follow symlinks [default] */
- (char*) "-d", /* don't dereference symlinks */
- (char*) from.c_str(),
- (char*) to_parent.c_str()
- };
-
- LOG(DEBUG) << "Copying " << from << " to " << to;
- int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true);
-
- if (rc != 0) {
- LOG(ERROR) << "Failed copying " << from << " to " << to
- << ": status " << rc;
- goto fail;
- }
-
- if (selinux_android_restorecon(to.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
- LOG(ERROR) << "Failed to restorecon " << to;
- goto fail;
- }
- }
-
- // Copy private data for all known users
- for (auto user : users) {
-
- // Data source may not exist for all users; that's okay
- auto from_ce = create_data_user_ce_package_path(from_uuid, user, package_name);
- if (access(from_ce.c_str(), F_OK) != 0) {
- LOG(INFO) << "Missing source " << from_ce;
- continue;
- }
-
- if (create_app_data(to_uuid, package_name, user, FLAG_STORAGE_CE | FLAG_STORAGE_DE,
- appid, seinfo, target_sdk_version) != 0) {
- LOG(ERROR) << "Failed to create package target on " << to_uuid;
- goto fail;
- }
-
- char *argv[] = {
- (char*) kCpPath,
- (char*) "-F", /* delete any existing destination file first (--remove-destination) */
- (char*) "-p", /* preserve timestamps, ownership, and permissions */
- (char*) "-R", /* recurse into subdirectories (DEST must be a directory) */
- (char*) "-P", /* Do not follow symlinks [default] */
- (char*) "-d", /* don't dereference symlinks */
- nullptr,
- nullptr
- };
-
- {
- auto from = create_data_user_de_package_path(from_uuid, user, package_name);
- auto to = create_data_user_de_path(to_uuid, user);
- argv[6] = (char*) from.c_str();
- argv[7] = (char*) to.c_str();
-
- LOG(DEBUG) << "Copying " << from << " to " << to;
- int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true);
- if (rc != 0) {
- LOG(ERROR) << "Failed copying " << from << " to " << to << " with status " << rc;
- goto fail;
- }
- }
- {
- auto from = create_data_user_ce_package_path(from_uuid, user, package_name);
- auto to = create_data_user_ce_path(to_uuid, user);
- argv[6] = (char*) from.c_str();
- argv[7] = (char*) to.c_str();
-
- LOG(DEBUG) << "Copying " << from << " to " << to;
- int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true);
- if (rc != 0) {
- LOG(ERROR) << "Failed copying " << from << " to " << to << " with status " << rc;
- goto fail;
- }
- }
-
- if (restorecon_app_data(to_uuid, package_name, user, FLAG_STORAGE_CE | FLAG_STORAGE_DE,
- appid, seinfo) != 0) {
- LOG(ERROR) << "Failed to restorecon";
- goto fail;
- }
- }
-
- // We let the framework scan the new location and persist that before
- // deleting the data in the old location; this ordering ensures that
- // we can recover from things like battery pulls.
- return 0;
-
-fail:
- // Nuke everything we might have already copied
- {
- auto to = create_data_app_package_path(to_uuid, data_app_name);
- if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
- LOG(WARNING) << "Failed to rollback " << to;
- }
- }
- for (auto user : users) {
- {
- auto to = create_data_user_de_package_path(to_uuid, user, package_name);
- if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
- LOG(WARNING) << "Failed to rollback " << to;
- }
- }
- {
- auto to = create_data_user_ce_package_path(to_uuid, user, package_name);
- if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
- LOG(WARNING) << "Failed to rollback " << to;
- }
- }
- }
- return -1;
-}
-
-int create_user_data(const char *uuid, userid_t userid, int user_serial ATTRIBUTE_UNUSED,
- int flags) {
- if (flags & FLAG_STORAGE_DE) {
- if (uuid == nullptr) {
- return ensure_config_user_dirs(userid);
- }
- }
- return 0;
-}
-
-int destroy_user_data(const char *uuid, userid_t userid, int flags) {
- int res = 0;
- if (flags & FLAG_STORAGE_DE) {
- res |= delete_dir_contents_and_dir(create_data_user_de_path(uuid, userid), true);
- if (uuid == nullptr) {
- res |= delete_dir_contents_and_dir(create_data_misc_legacy_path(userid), true);
- res |= delete_dir_contents_and_dir(create_data_user_profiles_path(userid), true);
- }
- }
- if (flags & FLAG_STORAGE_CE) {
- res |= delete_dir_contents_and_dir(create_data_user_ce_path(uuid, userid), true);
- res |= delete_dir_contents_and_dir(create_data_media_path(uuid, userid), true);
- }
- return res;
-}
-
-/* Try to ensure free_size bytes of storage are available.
- * Returns 0 on success.
- * This is rather simple-minded because doing a full LRU would
- * be potentially memory-intensive, and without atime it would
- * also require that apps constantly modify file metadata even
- * when just reading from the cache, which is pretty awful.
- */
-int free_cache(const char *uuid, int64_t free_size) {
- cache_t* cache;
- int64_t avail;
-
- auto data_path = create_data_path(uuid);
-
- avail = data_disk_free(data_path);
- if (avail < 0) return -1;
-
- ALOGI("free_cache(%" PRId64 ") avail %" PRId64 "\n", free_size, avail);
- if (avail >= free_size) return 0;
-
- cache = start_cache_collection();
-
- auto users = get_known_users(uuid);
- for (auto user : users) {
- add_cache_files(cache, create_data_user_ce_path(uuid, user));
- add_cache_files(cache, create_data_user_de_path(uuid, user));
- add_cache_files(cache,
- StringPrintf("%s/Android/data", create_data_media_path(uuid, user).c_str()));
- }
-
- clear_cache_files(data_path, cache, free_size);
- finish_cache_collection(cache);
-
- return data_disk_free(data_path) >= free_size ? 0 : -1;
-}
-
-int rm_dex(const char *path, const char *instruction_set)
-{
- char dex_path[PKG_PATH_MAX];
-
- if (validate_apk_path(path) && validate_system_app_path(path)) {
- ALOGE("invalid apk path '%s' (bad prefix)\n", path);
- return -1;
- }
-
- if (!create_cache_path(dex_path, path, instruction_set)) return -1;
-
- ALOGV("unlink %s\n", dex_path);
- if (unlink(dex_path) < 0) {
- if (errno != ENOENT) {
- ALOGE("Couldn't unlink %s: %s\n", dex_path, strerror(errno));
- }
- return -1;
- } else {
- return 0;
- }
-}
-
-static void add_app_data_size(std::string& path, int64_t *codesize, int64_t *datasize,
- int64_t *cachesize) {
- DIR *d;
- int dfd;
- struct dirent *de;
- struct stat s;
-
- d = opendir(path.c_str());
- if (d == nullptr) {
- PLOG(WARNING) << "Failed to open " << path;
- return;
- }
- dfd = dirfd(d);
- while ((de = readdir(d))) {
- const char *name = de->d_name;
-
- int64_t statsize = 0;
- if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
- statsize = stat_size(&s);
- }
-
- if (de->d_type == DT_DIR) {
- int subfd;
- int64_t dirsize = 0;
- /* always skip "." and ".." */
- if (name[0] == '.') {
- if (name[1] == 0) continue;
- if ((name[1] == '.') && (name[2] == 0)) continue;
- }
- subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
- if (subfd >= 0) {
- dirsize = calculate_dir_size(subfd);
- close(subfd);
- }
- // TODO: check xattrs!
- if (!strcmp(name, "cache") || !strcmp(name, "code_cache")) {
- *datasize += statsize;
- *cachesize += dirsize;
- } else {
- *datasize += dirsize + statsize;
- }
- } else if (de->d_type == DT_LNK && !strcmp(name, "lib")) {
- *codesize += statsize;
- } else {
- *datasize += statsize;
- }
- }
- closedir(d);
-}
-
-int get_app_size(const char *uuid, const char *pkgname, int userid, int flags, ino_t ce_data_inode,
- const char *code_path, int64_t *codesize, int64_t *datasize, int64_t *cachesize,
- int64_t* asecsize) {
- DIR *d;
- int dfd;
-
- d = opendir(code_path);
- if (d != nullptr) {
- dfd = dirfd(d);
- *codesize += calculate_dir_size(dfd);
- closedir(d);
- }
-
- if (flags & FLAG_STORAGE_CE) {
- auto path = create_data_user_ce_package_path(uuid, userid, pkgname, ce_data_inode);
- add_app_data_size(path, codesize, datasize, cachesize);
- }
- if (flags & FLAG_STORAGE_DE) {
- auto path = create_data_user_de_package_path(uuid, userid, pkgname);
- add_app_data_size(path, codesize, datasize, cachesize);
- }
-
- *asecsize = 0;
-
- return 0;
-}
-
-int get_app_data_inode(const char *uuid, const char *pkgname, int userid, int flags, ino_t *inode) {
- if (flags & FLAG_STORAGE_CE) {
- auto path = create_data_user_ce_package_path(uuid, userid, pkgname);
- return get_path_inode(path, inode);
- }
- return -1;
-}
-
-static int split_count(const char *str)
-{
- char *ctx;
- int count = 0;
- char buf[kPropertyValueMax];
-
- strncpy(buf, str, sizeof(buf));
- char *pBuf = buf;
-
- while(strtok_r(pBuf, " ", &ctx) != NULL) {
- count++;
- pBuf = NULL;
- }
-
- return count;
-}
-
-static int split(char *buf, const char **argv)
-{
- char *ctx;
- int count = 0;
- char *tok;
- char *pBuf = buf;
-
- while((tok = strtok_r(pBuf, " ", &ctx)) != NULL) {
- argv[count++] = tok;
- pBuf = NULL;
- }
-
- return count;
-}
-
-static void run_patchoat(int input_fd, int oat_fd, const char* input_file_name,
- const char* output_file_name, const char *pkgname ATTRIBUTE_UNUSED, const char *instruction_set)
-{
- static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig
- static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
-
- static const char* PATCHOAT_BIN = "/system/bin/patchoat";
- if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
- ALOGE("Instruction set %s longer than max length of %d",
- instruction_set, MAX_INSTRUCTION_SET_LEN);
- return;
- }
-
- /* input_file_name/input_fd should be the .odex/.oat file that is precompiled. I think*/
- char instruction_set_arg[strlen("--instruction-set=") + MAX_INSTRUCTION_SET_LEN];
- char output_oat_fd_arg[strlen("--output-oat-fd=") + MAX_INT_LEN];
- char input_oat_fd_arg[strlen("--input-oat-fd=") + MAX_INT_LEN];
- const char* patched_image_location_arg = "--patched-image-location=/system/framework/boot.art";
- // The caller has already gotten all the locks we need.
- const char* no_lock_arg = "--no-lock-output";
- sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set);
- sprintf(output_oat_fd_arg, "--output-oat-fd=%d", oat_fd);
- sprintf(input_oat_fd_arg, "--input-oat-fd=%d", input_fd);
- ALOGV("Running %s isa=%s in-fd=%d (%s) out-fd=%d (%s)\n",
- PATCHOAT_BIN, instruction_set, input_fd, input_file_name, oat_fd, output_file_name);
-
- /* patchoat, patched-image-location, no-lock, isa, input-fd, output-fd */
- char* argv[7];
- argv[0] = (char*) PATCHOAT_BIN;
- argv[1] = (char*) patched_image_location_arg;
- argv[2] = (char*) no_lock_arg;
- argv[3] = instruction_set_arg;
- argv[4] = output_oat_fd_arg;
- argv[5] = input_oat_fd_arg;
- argv[6] = NULL;
-
- execv(PATCHOAT_BIN, (char* const *)argv);
- ALOGE("execv(%s) failed: %s\n", PATCHOAT_BIN, strerror(errno));
-}
-
-static void run_dex2oat(int zip_fd, int oat_fd, int image_fd, const char* input_file_name,
- const char* output_file_name, int swap_fd, const char *instruction_set,
- const char* compiler_filter, bool vm_safe_mode, bool debuggable, bool post_bootcomplete,
- int profile_fd, const char* shared_libraries) {
- static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
-
- if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
- ALOGE("Instruction set %s longer than max length of %d",
- instruction_set, MAX_INSTRUCTION_SET_LEN);
- return;
- }
-
- char dex2oat_Xms_flag[kPropertyValueMax];
- bool have_dex2oat_Xms_flag = get_property("dalvik.vm.dex2oat-Xms", dex2oat_Xms_flag, NULL) > 0;
-
- char dex2oat_Xmx_flag[kPropertyValueMax];
- bool have_dex2oat_Xmx_flag = get_property("dalvik.vm.dex2oat-Xmx", dex2oat_Xmx_flag, NULL) > 0;
-
- char dex2oat_threads_buf[kPropertyValueMax];
- bool have_dex2oat_threads_flag = get_property(post_bootcomplete
- ? "dalvik.vm.dex2oat-threads"
- : "dalvik.vm.boot-dex2oat-threads",
- dex2oat_threads_buf,
- NULL) > 0;
- char dex2oat_threads_arg[kPropertyValueMax + 2];
- if (have_dex2oat_threads_flag) {
- sprintf(dex2oat_threads_arg, "-j%s", dex2oat_threads_buf);
- }
-
- char dex2oat_isa_features_key[kPropertyKeyMax];
- sprintf(dex2oat_isa_features_key, "dalvik.vm.isa.%s.features", instruction_set);
- char dex2oat_isa_features[kPropertyValueMax];
- bool have_dex2oat_isa_features = get_property(dex2oat_isa_features_key,
- dex2oat_isa_features, NULL) > 0;
-
- char dex2oat_isa_variant_key[kPropertyKeyMax];
- sprintf(dex2oat_isa_variant_key, "dalvik.vm.isa.%s.variant", instruction_set);
- char dex2oat_isa_variant[kPropertyValueMax];
- bool have_dex2oat_isa_variant = get_property(dex2oat_isa_variant_key,
- dex2oat_isa_variant, NULL) > 0;
-
- const char *dex2oat_norelocation = "-Xnorelocate";
- bool have_dex2oat_relocation_skip_flag = false;
-
- char dex2oat_flags[kPropertyValueMax];
- int dex2oat_flags_count = get_property("dalvik.vm.dex2oat-flags",
- dex2oat_flags, NULL) <= 0 ? 0 : split_count(dex2oat_flags);
- ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags);
-
- // If we booting without the real /data, don't spend time compiling.
- char vold_decrypt[kPropertyValueMax];
- bool have_vold_decrypt = get_property("vold.decrypt", vold_decrypt, "") > 0;
- bool skip_compilation = (have_vold_decrypt &&
- (strcmp(vold_decrypt, "trigger_restart_min_framework") == 0 ||
- (strcmp(vold_decrypt, "1") == 0)));
-
- bool generate_debug_info = property_get_bool("debug.generate-debug-info");
-
- char app_image_format[kPropertyValueMax];
- char image_format_arg[strlen("--image-format=") + kPropertyValueMax];
- bool have_app_image_format =
- image_fd >= 0 && get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
- if (have_app_image_format) {
- sprintf(image_format_arg, "--image-format=%s", app_image_format);
- }
-
- char dex2oat_large_app_threshold[kPropertyValueMax];
- bool have_dex2oat_large_app_threshold =
- get_property("dalvik.vm.dex2oat-very-large", dex2oat_large_app_threshold, NULL) > 0;
- char dex2oat_large_app_threshold_arg[strlen("--very-large-app-threshold=") + kPropertyValueMax];
- if (have_dex2oat_large_app_threshold) {
- sprintf(dex2oat_large_app_threshold_arg,
- "--very-large-app-threshold=%s",
- dex2oat_large_app_threshold);
- }
-
- static const char* DEX2OAT_BIN = "/system/bin/dex2oat";
-
- static const char* RUNTIME_ARG = "--runtime-arg";
-
- static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig
-
- char zip_fd_arg[strlen("--zip-fd=") + MAX_INT_LEN];
- char zip_location_arg[strlen("--zip-location=") + PKG_PATH_MAX];
- char oat_fd_arg[strlen("--oat-fd=") + MAX_INT_LEN];
- char oat_location_arg[strlen("--oat-location=") + PKG_PATH_MAX];
- char instruction_set_arg[strlen("--instruction-set=") + MAX_INSTRUCTION_SET_LEN];
- char instruction_set_variant_arg[strlen("--instruction-set-variant=") + kPropertyValueMax];
- char instruction_set_features_arg[strlen("--instruction-set-features=") + kPropertyValueMax];
- char dex2oat_Xms_arg[strlen("-Xms") + kPropertyValueMax];
- char dex2oat_Xmx_arg[strlen("-Xmx") + kPropertyValueMax];
- char dex2oat_compiler_filter_arg[strlen("--compiler-filter=") + kPropertyValueMax];
- bool have_dex2oat_swap_fd = false;
- char dex2oat_swap_fd[strlen("--swap-fd=") + MAX_INT_LEN];
- bool have_dex2oat_image_fd = false;
- char dex2oat_image_fd[strlen("--app-image-fd=") + MAX_INT_LEN];
-
- sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd);
- sprintf(zip_location_arg, "--zip-location=%s", input_file_name);
- sprintf(oat_fd_arg, "--oat-fd=%d", oat_fd);
- sprintf(oat_location_arg, "--oat-location=%s", output_file_name);
- sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set);
- sprintf(instruction_set_variant_arg, "--instruction-set-variant=%s", dex2oat_isa_variant);
- sprintf(instruction_set_features_arg, "--instruction-set-features=%s", dex2oat_isa_features);
- if (swap_fd >= 0) {
- have_dex2oat_swap_fd = true;
- sprintf(dex2oat_swap_fd, "--swap-fd=%d", swap_fd);
- }
- if (image_fd >= 0) {
- have_dex2oat_image_fd = true;
- sprintf(dex2oat_image_fd, "--app-image-fd=%d", image_fd);
- }
-
- if (have_dex2oat_Xms_flag) {
- sprintf(dex2oat_Xms_arg, "-Xms%s", dex2oat_Xms_flag);
- }
- if (have_dex2oat_Xmx_flag) {
- sprintf(dex2oat_Xmx_arg, "-Xmx%s", dex2oat_Xmx_flag);
- }
-
- // Compute compiler filter.
-
- bool have_dex2oat_compiler_filter_flag;
- if (skip_compilation) {
- strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=verify-none");
- have_dex2oat_compiler_filter_flag = true;
- have_dex2oat_relocation_skip_flag = true;
- } else if (vm_safe_mode) {
- strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=interpret-only");
- have_dex2oat_compiler_filter_flag = true;
- } else if (compiler_filter != nullptr &&
- strlen(compiler_filter) + strlen("--compiler-filter=") <
- arraysize(dex2oat_compiler_filter_arg)) {
- sprintf(dex2oat_compiler_filter_arg, "--compiler-filter=%s", compiler_filter);
- have_dex2oat_compiler_filter_flag = true;
- } else {
- char dex2oat_compiler_filter_flag[kPropertyValueMax];
- have_dex2oat_compiler_filter_flag = get_property("dalvik.vm.dex2oat-filter",
- dex2oat_compiler_filter_flag, NULL) > 0;
- if (have_dex2oat_compiler_filter_flag) {
- sprintf(dex2oat_compiler_filter_arg,
- "--compiler-filter=%s",
- dex2oat_compiler_filter_flag);
- }
- }
-
- // Check whether all apps should be compiled debuggable.
- if (!debuggable) {
- char prop_buf[kPropertyValueMax];
- debuggable =
- (get_property("dalvik.vm.always_debuggable", prop_buf, "0") > 0) &&
- (prop_buf[0] == '1');
- }
- char profile_arg[strlen("--profile-file-fd=") + MAX_INT_LEN];
- if (profile_fd != -1) {
- sprintf(profile_arg, "--profile-file-fd=%d", profile_fd);
- }
-
-
- ALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, input_file_name, output_file_name);
-
- const char* argv[7 // program name, mandatory arguments and the final NULL
- + (have_dex2oat_isa_variant ? 1 : 0)
- + (have_dex2oat_isa_features ? 1 : 0)
- + (have_dex2oat_Xms_flag ? 2 : 0)
- + (have_dex2oat_Xmx_flag ? 2 : 0)
- + (have_dex2oat_compiler_filter_flag ? 1 : 0)
- + (have_dex2oat_threads_flag ? 1 : 0)
- + (have_dex2oat_swap_fd ? 1 : 0)
- + (have_dex2oat_image_fd ? 1 : 0)
- + (have_dex2oat_relocation_skip_flag ? 2 : 0)
- + (generate_debug_info ? 1 : 0)
- + (debuggable ? 1 : 0)
- + (have_app_image_format ? 1 : 0)
- + dex2oat_flags_count
- + (profile_fd == -1 ? 0 : 1)
- + (shared_libraries != nullptr ? 4 : 0)
- + (have_dex2oat_large_app_threshold ? 1 : 0)];
- int i = 0;
- argv[i++] = DEX2OAT_BIN;
- argv[i++] = zip_fd_arg;
- argv[i++] = zip_location_arg;
- argv[i++] = oat_fd_arg;
- argv[i++] = oat_location_arg;
- argv[i++] = instruction_set_arg;
- if (have_dex2oat_isa_variant) {
- argv[i++] = instruction_set_variant_arg;
- }
- if (have_dex2oat_isa_features) {
- argv[i++] = instruction_set_features_arg;
- }
- if (have_dex2oat_Xms_flag) {
- argv[i++] = RUNTIME_ARG;
- argv[i++] = dex2oat_Xms_arg;
- }
- if (have_dex2oat_Xmx_flag) {
- argv[i++] = RUNTIME_ARG;
- argv[i++] = dex2oat_Xmx_arg;
- }
- if (have_dex2oat_compiler_filter_flag) {
- argv[i++] = dex2oat_compiler_filter_arg;
- }
- if (have_dex2oat_threads_flag) {
- argv[i++] = dex2oat_threads_arg;
- }
- if (have_dex2oat_swap_fd) {
- argv[i++] = dex2oat_swap_fd;
- }
- if (have_dex2oat_image_fd) {
- argv[i++] = dex2oat_image_fd;
- }
- if (generate_debug_info) {
- argv[i++] = "--generate-debug-info";
- }
- if (debuggable) {
- argv[i++] = "--debuggable";
- }
- if (have_app_image_format) {
- argv[i++] = image_format_arg;
- }
- if (have_dex2oat_large_app_threshold) {
- argv[i++] = dex2oat_large_app_threshold_arg;
- }
- if (dex2oat_flags_count) {
- i += split(dex2oat_flags, argv + i);
- }
- if (have_dex2oat_relocation_skip_flag) {
- argv[i++] = RUNTIME_ARG;
- argv[i++] = dex2oat_norelocation;
- }
- if (profile_fd != -1) {
- argv[i++] = profile_arg;
- }
- if (shared_libraries != nullptr) {
- argv[i++] = RUNTIME_ARG;
- argv[i++] = "-classpath";
- argv[i++] = RUNTIME_ARG;
- argv[i++] = shared_libraries;
- }
- // Do not add after dex2oat_flags, they should override others for debugging.
- argv[i] = NULL;
-
- execv(DEX2OAT_BIN, (char * const *)argv);
- ALOGE("execv(%s) failed: %s\n", DEX2OAT_BIN, strerror(errno));
-}
-
-/*
- * Whether dexopt should use a swap file when compiling an APK.
- *
- * If kAlwaysProvideSwapFile, do this on all devices (dex2oat will make a more informed decision
- * itself, anyways).
- *
- * Otherwise, read "dalvik.vm.dex2oat-swap". If the property exists, return whether it is "true".
- *
- * Otherwise, return true if this is a low-mem device.
- *
- * Otherwise, return default value.
- */
-static bool kAlwaysProvideSwapFile = false;
-static bool kDefaultProvideSwapFile = true;
-
-static bool ShouldUseSwapFileForDexopt() {
- if (kAlwaysProvideSwapFile) {
- return true;
- }
-
- // Check the "override" property. If it exists, return value == "true".
- char dex2oat_prop_buf[kPropertyValueMax];
- if (get_property("dalvik.vm.dex2oat-swap", dex2oat_prop_buf, "") > 0) {
- if (strcmp(dex2oat_prop_buf, "true") == 0) {
- return true;
- } else {
- return false;
- }
- }
-
- // Shortcut for default value. This is an implementation optimization for the process sketched
- // above. If the default value is true, we can avoid to check whether this is a low-mem device,
- // as low-mem is never returning false. The compiler will optimize this away if it can.
- if (kDefaultProvideSwapFile) {
- return true;
- }
-
- bool is_low_mem = property_get_bool("ro.config.low_ram");
- if (is_low_mem) {
- return true;
- }
-
- // Default value must be false here.
- return kDefaultProvideSwapFile;
-}
-
-static void SetDex2OatAndPatchOatScheduling(bool set_to_bg) {
- if (set_to_bg) {
- if (set_sched_policy(0, SP_BACKGROUND) < 0) {
- ALOGE("set_sched_policy failed: %s\n", strerror(errno));
- exit(70);
- }
- if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
- ALOGE("setpriority failed: %s\n", strerror(errno));
- exit(71);
- }
- }
-}
-
-static void close_all_fds(const std::vector<fd_t>& fds, const char* description) {
- for (size_t i = 0; i < fds.size(); i++) {
- if (close(fds[i]) != 0) {
- PLOG(WARNING) << "Failed to close fd for " << description << " at index " << i;
- }
- }
-}
-
-static fd_t open_profile_dir(const std::string& profile_dir) {
- fd_t profile_dir_fd = TEMP_FAILURE_RETRY(open(profile_dir.c_str(),
- O_PATH | O_CLOEXEC | O_DIRECTORY | O_NOFOLLOW));
- if (profile_dir_fd < 0) {
- // In a multi-user environment, these directories can be created at
- // different points and it's possible we'll attempt to open a profile
- // dir before it exists.
- if (errno != ENOENT) {
- PLOG(ERROR) << "Failed to open profile_dir: " << profile_dir;
- }
- }
- return profile_dir_fd;
-}
-
-static fd_t open_primary_profile_file_from_dir(const std::string& profile_dir, mode_t open_mode) {
- fd_t profile_dir_fd = open_profile_dir(profile_dir);
- if (profile_dir_fd < 0) {
- return -1;
- }
-
- fd_t profile_fd = -1;
- std::string profile_file = create_primary_profile(profile_dir);
-
- profile_fd = TEMP_FAILURE_RETRY(open(profile_file.c_str(), open_mode | O_NOFOLLOW));
- if (profile_fd == -1) {
- // It's not an error if the profile file does not exist.
- if (errno != ENOENT) {
- PLOG(ERROR) << "Failed to lstat profile_dir: " << profile_dir;
- }
- }
- // TODO(calin): use AutoCloseFD instead of closing the fd manually.
- if (close(profile_dir_fd) != 0) {
- PLOG(WARNING) << "Could not close profile dir " << profile_dir;
- }
- return profile_fd;
-}
-
-static fd_t open_primary_profile_file(userid_t user, const char* pkgname) {
- std::string profile_dir = create_data_user_profile_package_path(user, pkgname);
- return open_primary_profile_file_from_dir(profile_dir, O_RDONLY);
-}
-
-static fd_t open_reference_profile(uid_t uid, const char* pkgname, bool read_write) {
- std::string reference_profile_dir = create_data_ref_profile_package_path(pkgname);
- int flags = read_write ? O_RDWR | O_CREAT : O_RDONLY;
- fd_t fd = open_primary_profile_file_from_dir(reference_profile_dir, flags);
- if (fd < 0) {
- return -1;
- }
- if (read_write) {
- // Fix the owner.
- if (fchown(fd, uid, uid) < 0) {
- close(fd);
- return -1;
- }
- }
- return fd;
-}
-
-static void open_profile_files(uid_t uid, const char* pkgname,
- /*out*/ std::vector<fd_t>* profiles_fd, /*out*/ fd_t* reference_profile_fd) {
- // Open the reference profile in read-write mode as profman might need to save the merge.
- *reference_profile_fd = open_reference_profile(uid, pkgname, /*read_write*/ true);
- if (*reference_profile_fd < 0) {
- // We can't access the reference profile file.
- return;
- }
-
- std::vector<userid_t> users = get_known_users(/*volume_uuid*/ nullptr);
- for (auto user : users) {
- fd_t profile_fd = open_primary_profile_file(user, pkgname);
- // Add to the lists only if both fds are valid.
- if (profile_fd >= 0) {
- profiles_fd->push_back(profile_fd);
- }
- }
-}
-
-static void drop_capabilities(uid_t uid) {
- if (setgid(uid) != 0) {
- ALOGE("setgid(%d) failed in installd during dexopt\n", uid);
- exit(64);
- }
- if (setuid(uid) != 0) {
- ALOGE("setuid(%d) failed in installd during dexopt\n", uid);
- exit(65);
- }
- // drop capabilities
- struct __user_cap_header_struct capheader;
- struct __user_cap_data_struct capdata[2];
- memset(&capheader, 0, sizeof(capheader));
- memset(&capdata, 0, sizeof(capdata));
- capheader.version = _LINUX_CAPABILITY_VERSION_3;
- if (capset(&capheader, &capdata[0]) < 0) {
- ALOGE("capset failed: %s\n", strerror(errno));
- exit(66);
- }
-}
-
-static constexpr int PROFMAN_BIN_RETURN_CODE_COMPILE = 0;
-static constexpr int PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION = 1;
-static constexpr int PROFMAN_BIN_RETURN_CODE_BAD_PROFILES = 2;
-static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_IO = 3;
-static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING = 4;
-
-static void run_profman_merge(const std::vector<fd_t>& profiles_fd, fd_t reference_profile_fd) {
- static const size_t MAX_INT_LEN = 32;
- static const char* PROFMAN_BIN = "/system/bin/profman";
-
- std::vector<std::string> profile_args(profiles_fd.size());
- char profile_buf[strlen("--profile-file-fd=") + MAX_INT_LEN];
- for (size_t k = 0; k < profiles_fd.size(); k++) {
- sprintf(profile_buf, "--profile-file-fd=%d", profiles_fd[k]);
- profile_args[k].assign(profile_buf);
- }
- char reference_profile_arg[strlen("--reference-profile-file-fd=") + MAX_INT_LEN];
- sprintf(reference_profile_arg, "--reference-profile-file-fd=%d", reference_profile_fd);
-
- // program name, reference profile fd, the final NULL and the profile fds
- const char* argv[3 + profiles_fd.size()];
- int i = 0;
- argv[i++] = PROFMAN_BIN;
- argv[i++] = reference_profile_arg;
- for (size_t k = 0; k < profile_args.size(); k++) {
- argv[i++] = profile_args[k].c_str();
- }
- // Do not add after dex2oat_flags, they should override others for debugging.
- argv[i] = NULL;
-
- execv(PROFMAN_BIN, (char * const *)argv);
- ALOGE("execv(%s) failed: %s\n", PROFMAN_BIN, strerror(errno));
- exit(68); /* only get here on exec failure */
-}
-
-// Decides if profile guided compilation is needed or not based on existing profiles.
-// Returns true if there is enough information in the current profiles that worth
-// a re-compilation of the package.
-// If the return value is true all the current profiles would have been merged into
-// the reference profiles accessible with open_reference_profile().
-static bool analyse_profiles(uid_t uid, const char* pkgname) {
- std::vector<fd_t> profiles_fd;
- fd_t reference_profile_fd = -1;
- open_profile_files(uid, pkgname, &profiles_fd, &reference_profile_fd);
- if (profiles_fd.empty() || (reference_profile_fd == -1)) {
- // Skip profile guided compilation because no profiles were found.
- // Or if the reference profile info couldn't be opened.
- close_all_fds(profiles_fd, "profiles_fd");
- if ((reference_profile_fd != - 1) && (close(reference_profile_fd) != 0)) {
- PLOG(WARNING) << "Failed to close fd for reference profile";
- }
- return false;
- }
-
- ALOGV("PROFMAN (MERGE): --- BEGIN '%s' ---\n", pkgname);
-
- pid_t pid = fork();
- if (pid == 0) {
- /* child -- drop privileges before continuing */
- drop_capabilities(uid);
- run_profman_merge(profiles_fd, reference_profile_fd);
- exit(68); /* only get here on exec failure */
- }
- /* parent */
- int return_code = wait_child(pid);
- bool need_to_compile = false;
- bool should_clear_current_profiles = false;
- bool should_clear_reference_profile = false;
- if (!WIFEXITED(return_code)) {
- LOG(WARNING) << "profman failed for package " << pkgname << ": " << return_code;
- } else {
- return_code = WEXITSTATUS(return_code);
- switch (return_code) {
- case PROFMAN_BIN_RETURN_CODE_COMPILE:
- need_to_compile = true;
- should_clear_current_profiles = true;
- should_clear_reference_profile = false;
- break;
- case PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION:
- need_to_compile = false;
- should_clear_current_profiles = false;
- should_clear_reference_profile = false;
- break;
- case PROFMAN_BIN_RETURN_CODE_BAD_PROFILES:
- LOG(WARNING) << "Bad profiles for package " << pkgname;
- need_to_compile = false;
- should_clear_current_profiles = true;
- should_clear_reference_profile = true;
- break;
- case PROFMAN_BIN_RETURN_CODE_ERROR_IO: // fall-through
- case PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING:
- // Temporary IO problem (e.g. locking). Ignore but log a warning.
- LOG(WARNING) << "IO error while reading profiles for package " << pkgname;
- need_to_compile = false;
- should_clear_current_profiles = false;
- should_clear_reference_profile = false;
- break;
- default:
- // Unknown return code or error. Unlink profiles.
- LOG(WARNING) << "Unknown error code while processing profiles for package " << pkgname
- << ": " << return_code;
- need_to_compile = false;
- should_clear_current_profiles = true;
- should_clear_reference_profile = true;
- break;
- }
- }
- close_all_fds(profiles_fd, "profiles_fd");
- if (close(reference_profile_fd) != 0) {
- PLOG(WARNING) << "Failed to close fd for reference profile";
- }
- if (should_clear_current_profiles) {
- clear_current_profiles(pkgname);
- }
- if (should_clear_reference_profile) {
- clear_reference_profile(pkgname);
- }
- return need_to_compile;
-}
-
-static void run_profman_dump(const std::vector<fd_t>& profile_fds,
- fd_t reference_profile_fd,
- const std::vector<std::string>& dex_locations,
- const std::vector<fd_t>& apk_fds,
- fd_t output_fd) {
- std::vector<std::string> profman_args;
- static const char* PROFMAN_BIN = "/system/bin/profman";
- profman_args.push_back(PROFMAN_BIN);
- profman_args.push_back("--dump-only");
- profman_args.push_back(StringPrintf("--dump-output-to-fd=%d", output_fd));
- if (reference_profile_fd != -1) {
- profman_args.push_back(StringPrintf("--reference-profile-file-fd=%d",
- reference_profile_fd));
- }
- for (fd_t profile_fd : profile_fds) {
- profman_args.push_back(StringPrintf("--profile-file-fd=%d", profile_fd));
- }
- for (const std::string& dex_location : dex_locations) {
- profman_args.push_back(StringPrintf("--dex-location=%s", dex_location.c_str()));
- }
- for (fd_t apk_fd : apk_fds) {
- profman_args.push_back(StringPrintf("--apk-fd=%d", apk_fd));
- }
- const char **argv = new const char*[profman_args.size() + 1];
- size_t i = 0;
- for (const std::string& profman_arg : profman_args) {
- argv[i++] = profman_arg.c_str();
- }
- argv[i] = NULL;
-
- execv(PROFMAN_BIN, (char * const *)argv);
- ALOGE("execv(%s) failed: %s\n", PROFMAN_BIN, strerror(errno));
- exit(68); /* only get here on exec failure */
-}
-
-static const char* get_location_from_path(const char* path) {
- static constexpr char kLocationSeparator = '/';
- const char *location = strrchr(path, kLocationSeparator);
- if (location == NULL) {
- return path;
- } else {
- // Skip the separator character.
- return location + 1;
- }
-}
-
-// Dumps the contents of a profile file, using pkgname's dex files for pretty
-// printing the result.
-bool dump_profile(uid_t uid, const char* pkgname, const char* code_path_string) {
- std::vector<fd_t> profile_fds;
- fd_t reference_profile_fd = -1;
- std::string out_file_name = StringPrintf("/data/misc/profman/%s.txt", pkgname);
-
- ALOGV("PROFMAN (DUMP): --- BEGIN '%s' ---\n", pkgname);
-
- open_profile_files(uid, pkgname, &profile_fds, &reference_profile_fd);
-
- const bool has_reference_profile = (reference_profile_fd != -1);
- const bool has_profiles = !profile_fds.empty();
-
- if (!has_reference_profile && !has_profiles) {
- ALOGE("profman dump: no profiles to dump for '%s'", pkgname);
- return false;
- }
-
- fd_t output_fd = open(out_file_name.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW);
- if (fchmod(output_fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) {
- ALOGE("installd cannot chmod '%s' dump_profile\n", out_file_name.c_str());
- return false;
- }
- std::vector<std::string> code_full_paths = base::Split(code_path_string, ";");
- std::vector<std::string> dex_locations;
- std::vector<fd_t> apk_fds;
- for (const std::string& code_full_path : code_full_paths) {
- const char* full_path = code_full_path.c_str();
- fd_t apk_fd = open(full_path, O_RDONLY | O_NOFOLLOW);
- if (apk_fd == -1) {
- ALOGE("installd cannot open '%s'\n", full_path);
- return false;
- }
- dex_locations.push_back(get_location_from_path(full_path));
- apk_fds.push_back(apk_fd);
- }
-
- pid_t pid = fork();
- if (pid == 0) {
- /* child -- drop privileges before continuing */
- drop_capabilities(uid);
- run_profman_dump(profile_fds, reference_profile_fd, dex_locations,
- apk_fds, output_fd);
- exit(68); /* only get here on exec failure */
- }
- /* parent */
- close_all_fds(apk_fds, "apk_fds");
- close_all_fds(profile_fds, "profile_fds");
- if (close(reference_profile_fd) != 0) {
- PLOG(WARNING) << "Failed to close fd for reference profile";
- }
- int return_code = wait_child(pid);
- if (!WIFEXITED(return_code)) {
- LOG(WARNING) << "profman failed for package " << pkgname << ": "
- << return_code;
- return false;
- }
- return true;
-}
-
-// Translate the given oat path to an art (app image) path. An empty string
-// denotes an error.
-static std::string create_image_filename(const std::string& oat_path) {
- // A standard dalvik-cache entry. Replace ".dex" with ".art."
- if (EndsWith(oat_path, ".dex")) {
- std::string art_path = oat_path;
- art_path.replace(art_path.length() - strlen("dex"), strlen("dex"), "art");
- CHECK(EndsWith(art_path, ".art"));
- return art_path;
- }
-
- // An odex entry. Not that this may not be an extension, e.g., in the OTA
- // case (where the base name will have an extension for the B artifact).
- size_t odex_pos = oat_path.rfind(".odex");
- if (odex_pos != std::string::npos) {
- std::string art_path = oat_path;
- art_path.replace(odex_pos, strlen(".odex"), ".art");
- CHECK_NE(art_path.find(".art"), std::string::npos);
- return art_path;
- }
-
- // Don't know how to handle this.
- return "";
-}
-
-static bool add_extension_to_file_name(char* file_name, const char* extension) {
- if (strlen(file_name) + strlen(extension) + 1 > PKG_PATH_MAX) {
- return false;
- }
- strcat(file_name, extension);
- return true;
-}
-
-static int open_output_file(const char* file_name, bool recreate, int permissions) {
- int flags = O_RDWR | O_CREAT;
- if (recreate) {
- if (unlink(file_name) < 0) {
- if (errno != ENOENT) {
- PLOG(ERROR) << "open_output_file: Couldn't unlink " << file_name;
- }
- }
- flags |= O_EXCL;
- }
- return open(file_name, flags, permissions);
-}
-
-static bool set_permissions_and_ownership(int fd, bool is_public, int uid, const char* path) {
- if (fchmod(fd,
- S_IRUSR|S_IWUSR|S_IRGRP |
- (is_public ? S_IROTH : 0)) < 0) {
- ALOGE("installd cannot chmod '%s' during dexopt\n", path);
- return false;
- } else if (fchown(fd, AID_SYSTEM, uid) < 0) {
- ALOGE("installd cannot chown '%s' during dexopt\n", path);
- return false;
- }
- return true;
-}
-
-static bool create_oat_out_path(const char* apk_path, const char* instruction_set,
- const char* oat_dir, /*out*/ char* out_path) {
- // Early best-effort check whether we can fit the the path into our buffers.
- // Note: the cache path will require an additional 5 bytes for ".swap", but we'll try to run
- // without a swap file, if necessary. Reference profiles file also add an extra ".prof"
- // extension to the cache path (5 bytes).
- if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {
- ALOGE("apk_path too long '%s'\n", apk_path);
- return false;
- }
-
- if (oat_dir != NULL && oat_dir[0] != '!') {
- if (validate_apk_path(oat_dir)) {
- ALOGE("invalid oat_dir '%s'\n", oat_dir);
- return false;
- }
- if (!calculate_oat_file_path(out_path, oat_dir, apk_path, instruction_set)) {
- return false;
- }
- } else {
- if (!create_cache_path(out_path, apk_path, instruction_set)) {
- return false;
- }
- }
- return true;
-}
-
-// TODO: Consider returning error codes.
-bool merge_profiles(uid_t uid, const char *pkgname) {
- return analyse_profiles(uid, pkgname);
-}
-
-static const char* parse_null(const char* arg) {
- if (strcmp(arg, "!") == 0) {
- return nullptr;
- } else {
- return arg;
- }
-}
-
-int dexopt(const char* const params[DEXOPT_PARAM_COUNT]) {
- return dexopt(params[0], // apk_path
- atoi(params[1]), // uid
- params[2], // pkgname
- params[3], // instruction_set
- atoi(params[4]), // dexopt_needed
- params[5], // oat_dir
- atoi(params[6]), // dexopt_flags
- params[7], // compiler_filter
- parse_null(params[8]), // volume_uuid
- parse_null(params[9])); // shared_libraries
- static_assert(DEXOPT_PARAM_COUNT == 10U, "Unexpected dexopt param count");
-}
-
-// Helper for fd management. This is similar to a unique_fd in that it closes the file descriptor
-// on destruction. It will also run the given cleanup (unless told not to) after closing.
-//
-// Usage example:
-//
-// Dex2oatFileWrapper<std::function<void ()>> file(open(...),
-// [name]() {
-// unlink(name.c_str());
-// });
-// // Note: care needs to be taken about name, as it needs to have a lifetime longer than the
-// wrapper if captured as a reference.
-//
-// if (file.get() == -1) {
-// // Error opening...
-// }
-//
-// ...
-// if (error) {
-// // At this point, when the Dex2oatFileWrapper is destructed, the cleanup function will run
-// // and delete the file (after the fd is closed).
-// return -1;
-// }
-//
-// (Success case)
-// file.SetCleanup(false);
-// // At this point, when the Dex2oatFileWrapper is destructed, the cleanup function will not run
-// // (leaving the file around; after the fd is closed).
-//
-template <typename Cleanup>
-class Dex2oatFileWrapper {
- public:
- Dex2oatFileWrapper() : value_(-1), cleanup_(), do_cleanup_(true) {
- }
-
- Dex2oatFileWrapper(int value, Cleanup cleanup)
- : value_(value), cleanup_(cleanup), do_cleanup_(true) {}
-
- ~Dex2oatFileWrapper() {
- reset(-1);
- }
-
- int get() {
- return value_;
- }
-
- void SetCleanup(bool cleanup) {
- do_cleanup_ = cleanup;
- }
-
- void reset(int new_value) {
- if (value_ >= 0) {
- close(value_);
- }
- if (do_cleanup_ && cleanup_ != nullptr) {
- cleanup_();
- }
-
- value_ = new_value;
- }
-
- void reset(int new_value, Cleanup new_cleanup) {
- if (value_ >= 0) {
- close(value_);
- }
- if (do_cleanup_ && cleanup_ != nullptr) {
- cleanup_();
- }
-
- value_ = new_value;
- cleanup_ = new_cleanup;
- }
-
- private:
- int value_;
- Cleanup cleanup_;
- bool do_cleanup_;
-};
-
-int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* instruction_set,
- int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
- const char* volume_uuid ATTRIBUTE_UNUSED, const char* shared_libraries)
-{
- bool is_public = ((dexopt_flags & DEXOPT_PUBLIC) != 0);
- bool vm_safe_mode = (dexopt_flags & DEXOPT_SAFEMODE) != 0;
- bool debuggable = (dexopt_flags & DEXOPT_DEBUGGABLE) != 0;
- bool boot_complete = (dexopt_flags & DEXOPT_BOOTCOMPLETE) != 0;
- bool profile_guided = (dexopt_flags & DEXOPT_PROFILE_GUIDED) != 0;
-
- // Don't use profile for vm_safe_mode. b/30688277
- profile_guided = profile_guided && !vm_safe_mode;
-
- CHECK(pkgname != nullptr);
- CHECK(pkgname[0] != 0);
-
- // Public apps should not be compiled with profile information ever. Same goes for the special
- // package '*' used for the system server.
- Dex2oatFileWrapper<std::function<void ()>> reference_profile_fd;
- if (!is_public && pkgname[0] != '*') {
- // Open reference profile in read only mode as dex2oat does not get write permissions.
- const std::string pkgname_str(pkgname);
- reference_profile_fd.reset(open_reference_profile(uid, pkgname, /*read_write*/ false),
- [pkgname_str]() {
- clear_reference_profile(pkgname_str.c_str());
- });
- // Note: it's OK to not find a profile here.
- }
-
- if ((dexopt_flags & ~DEXOPT_MASK) != 0) {
- LOG_FATAL("dexopt flags contains unknown fields\n");
- }
-
- char out_path[PKG_PATH_MAX];
- if (!create_oat_out_path(apk_path, instruction_set, oat_dir, out_path)) {
- return false;
- }
-
- const char *input_file;
- char in_odex_path[PKG_PATH_MAX];
- switch (dexopt_needed) {
- case DEXOPT_DEX2OAT_NEEDED:
- input_file = apk_path;
- break;
-
- case DEXOPT_PATCHOAT_NEEDED:
- if (!calculate_odex_file_path(in_odex_path, apk_path, instruction_set)) {
- return -1;
- }
- input_file = in_odex_path;
- break;
-
- case DEXOPT_SELF_PATCHOAT_NEEDED:
- input_file = out_path;
- break;
-
- default:
- ALOGE("Invalid dexopt needed: %d\n", dexopt_needed);
- return 72;
- }
-
- struct stat input_stat;
- memset(&input_stat, 0, sizeof(input_stat));
- stat(input_file, &input_stat);
-
- base::unique_fd input_fd(open(input_file, O_RDONLY, 0));
- if (input_fd.get() < 0) {
- ALOGE("installd cannot open '%s' for input during dexopt\n", input_file);
- return -1;
- }
-
- const std::string out_path_str(out_path);
- Dex2oatFileWrapper<std::function<void ()>> out_fd(
- open_output_file(out_path, /*recreate*/true, /*permissions*/0644),
- [out_path_str]() { unlink(out_path_str.c_str()); });
- if (out_fd.get() < 0) {
- ALOGE("installd cannot open '%s' for output during dexopt\n", out_path);
- return -1;
- }
- if (!set_permissions_and_ownership(out_fd.get(), is_public, uid, out_path)) {
- return -1;
- }
-
- // Create a swap file if necessary.
- base::unique_fd swap_fd;
- if (ShouldUseSwapFileForDexopt()) {
- // Make sure there really is enough space.
- char swap_file_name[PKG_PATH_MAX];
- strcpy(swap_file_name, out_path);
- if (add_extension_to_file_name(swap_file_name, ".swap")) {
- swap_fd.reset(open_output_file(swap_file_name, /*recreate*/true, /*permissions*/0600));
- }
- if (swap_fd.get() < 0) {
- // Could not create swap file. Optimistically go on and hope that we can compile
- // without it.
- ALOGE("installd could not create '%s' for swap during dexopt\n", swap_file_name);
- } else {
- // Immediately unlink. We don't really want to hit flash.
- if (unlink(swap_file_name) < 0) {
- PLOG(ERROR) << "Couldn't unlink swap file " << swap_file_name;
- }
- }
- }
-
- // Avoid generating an app image for extract only since it will not contain any classes.
- Dex2oatFileWrapper<std::function<void ()>> image_fd;
- const std::string image_path = create_image_filename(out_path);
- if (!image_path.empty()) {
- char app_image_format[kPropertyValueMax];
- bool have_app_image_format =
- get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
- // Use app images only if it is enabled (by a set image format) and we are compiling
- // profile-guided (so the app image doesn't conservatively contain all classes).
- if (profile_guided && have_app_image_format) {
- // Recreate is true since we do not want to modify a mapped image. If the app is
- // already running and we modify the image file, it can cause crashes (b/27493510).
- image_fd.reset(open_output_file(image_path.c_str(),
- true /*recreate*/,
- 0600 /*permissions*/),
- [image_path]() { unlink(image_path.c_str()); }
- );
- if (image_fd.get() < 0) {
- // Could not create application image file. Go on since we can compile without
- // it.
- LOG(ERROR) << "installd could not create '"
- << image_path
- << "' for image file during dexopt";
- } else if (!set_permissions_and_ownership(image_fd.get(),
- is_public,
- uid,
- image_path.c_str())) {
- image_fd.reset(-1);
- }
- }
- // If we have a valid image file path but no image fd, explicitly erase the image file.
- if (image_fd.get() < 0) {
- if (unlink(image_path.c_str()) < 0) {
- if (errno != ENOENT) {
- PLOG(ERROR) << "Couldn't unlink image file " << image_path;
- }
- }
- }
- }
-
- ALOGV("DexInv: --- BEGIN '%s' ---\n", input_file);
-
- pid_t pid = fork();
- if (pid == 0) {
- /* child -- drop privileges before continuing */
- drop_capabilities(uid);
-
- SetDex2OatAndPatchOatScheduling(boot_complete);
- if (flock(out_fd.get(), LOCK_EX | LOCK_NB) != 0) {
- ALOGE("flock(%s) failed: %s\n", out_path, strerror(errno));
- _exit(67);
- }
-
- if (dexopt_needed == DEXOPT_PATCHOAT_NEEDED
- || dexopt_needed == DEXOPT_SELF_PATCHOAT_NEEDED) {
- run_patchoat(input_fd.get(),
- out_fd.get(),
- input_file,
- out_path,
- pkgname,
- instruction_set);
- } else if (dexopt_needed == DEXOPT_DEX2OAT_NEEDED) {
- // Pass dex2oat the relative path to the input file.
- const char *input_file_name = get_location_from_path(input_file);
- run_dex2oat(input_fd.get(),
- out_fd.get(),
- image_fd.get(),
- input_file_name,
- out_path,
- swap_fd.get(),
- instruction_set,
- compiler_filter,
- vm_safe_mode,
- debuggable,
- boot_complete,
- reference_profile_fd.get(),
- shared_libraries);
- } else {
- ALOGE("Invalid dexopt needed: %d\n", dexopt_needed);
- _exit(73);
- }
- _exit(68); /* only get here on exec failure */
- } else {
- int res = wait_child(pid);
- if (res == 0) {
- ALOGV("DexInv: --- END '%s' (success) ---\n", input_file);
- } else {
- ALOGE("DexInv: --- END '%s' --- status=0x%04x, process failed\n", input_file, res);
- return -1;
- }
- }
-
- struct utimbuf ut;
- ut.actime = input_stat.st_atime;
- ut.modtime = input_stat.st_mtime;
- utime(out_path, &ut);
-
- // We've been successful, don't delete output.
- out_fd.SetCleanup(false);
- image_fd.SetCleanup(false);
- reference_profile_fd.SetCleanup(false);
-
- return 0;
-}
-
-int mark_boot_complete(const char* instruction_set)
-{
- char boot_marker_path[PKG_PATH_MAX];
- sprintf(boot_marker_path,
- "%s/%s/%s/.booting",
- android_data_dir.path,
- DALVIK_CACHE,
- instruction_set);
-
- ALOGV("mark_boot_complete : %s", boot_marker_path);
- if (unlink(boot_marker_path) != 0) {
- ALOGE("Unable to unlink boot marker at %s, error=%s", boot_marker_path,
- strerror(errno));
- return -1;
- }
-
- return 0;
-}
-
-void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid,
- struct stat* statbuf)
-{
- while (path[basepos] != 0) {
- if (path[basepos] == '/') {
- path[basepos] = 0;
- if (lstat(path, statbuf) < 0) {
- ALOGV("Making directory: %s\n", path);
- if (mkdir(path, mode) == 0) {
- chown(path, uid, gid);
- } else {
- ALOGW("Unable to make directory %s: %s\n", path, strerror(errno));
- }
- }
- path[basepos] = '/';
- basepos++;
- }
- basepos++;
- }
-}
-
-int linklib(const char* uuid, const char* pkgname, const char* asecLibDir, int userId)
-{
- struct stat s, libStat;
- int rc = 0;
-
- std::string _pkgdir(create_data_user_ce_package_path(uuid, userId, pkgname));
- std::string _libsymlink(_pkgdir + PKG_LIB_POSTFIX);
-
- const char* pkgdir = _pkgdir.c_str();
- const char* libsymlink = _libsymlink.c_str();
-
- if (stat(pkgdir, &s) < 0) return -1;
-
- if (chown(pkgdir, AID_INSTALL, AID_INSTALL) < 0) {
- ALOGE("failed to chown '%s': %s\n", pkgdir, strerror(errno));
- return -1;
- }
-
- if (chmod(pkgdir, 0700) < 0) {
- ALOGE("linklib() 1: failed to chmod '%s': %s\n", pkgdir, strerror(errno));
- rc = -1;
- goto out;
- }
-
- if (lstat(libsymlink, &libStat) < 0) {
- if (errno != ENOENT) {
- ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
- rc = -1;
- goto out;
- }
- } else {
- if (S_ISDIR(libStat.st_mode)) {
- if (delete_dir_contents(libsymlink, 1, NULL) < 0) {
- rc = -1;
- goto out;
- }
- } else if (S_ISLNK(libStat.st_mode)) {
- if (unlink(libsymlink) < 0) {
- ALOGE("couldn't unlink lib dir: %s\n", strerror(errno));
- rc = -1;
- goto out;
- }
- }
- }
-
- if (symlink(asecLibDir, libsymlink) < 0) {
- ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libsymlink, asecLibDir,
- strerror(errno));
- rc = -errno;
- goto out;
- }
-
-out:
- if (chmod(pkgdir, s.st_mode) < 0) {
- ALOGE("linklib() 2: failed to chmod '%s': %s\n", pkgdir, strerror(errno));
- rc = -errno;
- }
-
- if (chown(pkgdir, s.st_uid, s.st_gid) < 0) {
- ALOGE("failed to chown '%s' : %s\n", pkgdir, strerror(errno));
- return -errno;
- }
-
- return rc;
-}
-
-static void run_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd)
-{
- static const char *IDMAP_BIN = "/system/bin/idmap";
- static const size_t MAX_INT_LEN = 32;
- char idmap_str[MAX_INT_LEN];
-
- snprintf(idmap_str, sizeof(idmap_str), "%d", idmap_fd);
-
- execl(IDMAP_BIN, IDMAP_BIN, "--fd", target_apk, overlay_apk, idmap_str, (char*)NULL);
- ALOGE("execl(%s) failed: %s\n", IDMAP_BIN, strerror(errno));
-}
-
-// Transform string /a/b/c.apk to (prefix)/a@b@c.apk@(suffix)
-// eg /a/b/c.apk to /data/resource-cache/a@b@c.apk@idmap
-static int flatten_path(const char *prefix, const char *suffix,
- const char *overlay_path, char *idmap_path, size_t N)
-{
- if (overlay_path == NULL || idmap_path == NULL) {
- return -1;
- }
- const size_t len_overlay_path = strlen(overlay_path);
- // will access overlay_path + 1 further below; requires absolute path
- if (len_overlay_path < 2 || *overlay_path != '/') {
- return -1;
- }
- const size_t len_idmap_root = strlen(prefix);
- const size_t len_suffix = strlen(suffix);
- if (SIZE_MAX - len_idmap_root < len_overlay_path ||
- SIZE_MAX - (len_idmap_root + len_overlay_path) < len_suffix) {
- // additions below would cause overflow
- return -1;
- }
- if (N < len_idmap_root + len_overlay_path + len_suffix) {
- return -1;
- }
- memset(idmap_path, 0, N);
- snprintf(idmap_path, N, "%s%s%s", prefix, overlay_path + 1, suffix);
- char *ch = idmap_path + len_idmap_root;
- while (*ch != '\0') {
- if (*ch == '/') {
- *ch = '@';
- }
- ++ch;
- }
- return 0;
-}
-
-int idmap(const char *target_apk, const char *overlay_apk, uid_t uid)
-{
- ALOGV("idmap target_apk=%s overlay_apk=%s uid=%d\n", target_apk, overlay_apk, uid);
-
- int idmap_fd = -1;
- char idmap_path[PATH_MAX];
-
- if (flatten_path(IDMAP_PREFIX, IDMAP_SUFFIX, overlay_apk,
- idmap_path, sizeof(idmap_path)) == -1) {
- ALOGE("idmap cannot generate idmap path for overlay %s\n", overlay_apk);
- goto fail;
- }
-
- unlink(idmap_path);
- idmap_fd = open(idmap_path, O_RDWR | O_CREAT | O_EXCL, 0644);
- if (idmap_fd < 0) {
- ALOGE("idmap cannot open '%s' for output: %s\n", idmap_path, strerror(errno));
- goto fail;
- }
- if (fchown(idmap_fd, AID_SYSTEM, uid) < 0) {
- ALOGE("idmap cannot chown '%s'\n", idmap_path);
- goto fail;
- }
- if (fchmod(idmap_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) {
- ALOGE("idmap cannot chmod '%s'\n", idmap_path);
- goto fail;
- }
-
- pid_t pid;
- pid = fork();
- if (pid == 0) {
- /* child -- drop privileges before continuing */
- if (setgid(uid) != 0) {
- ALOGE("setgid(%d) failed during idmap\n", uid);
- exit(1);
- }
- if (setuid(uid) != 0) {
- ALOGE("setuid(%d) failed during idmap\n", uid);
- exit(1);
- }
- if (flock(idmap_fd, LOCK_EX | LOCK_NB) != 0) {
- ALOGE("flock(%s) failed during idmap: %s\n", idmap_path, strerror(errno));
- exit(1);
- }
-
- run_idmap(target_apk, overlay_apk, idmap_fd);
- exit(1); /* only if exec call to idmap failed */
- } else {
- int status = wait_child(pid);
- if (status != 0) {
- ALOGE("idmap failed, status=0x%04x\n", status);
- goto fail;
- }
- }
-
- close(idmap_fd);
- return 0;
-fail:
- if (idmap_fd >= 0) {
- close(idmap_fd);
- unlink(idmap_path);
- }
- return -1;
-}
-
-int restorecon_app_data(const char* uuid, const char* pkgName, userid_t userid, int flags,
- appid_t appid, const char* seinfo) {
- int res = 0;
-
- // SELINUX_ANDROID_RESTORECON_DATADATA flag is set by libselinux. Not needed here.
- unsigned int seflags = SELINUX_ANDROID_RESTORECON_RECURSE;
-
- if (!pkgName || !seinfo) {
- ALOGE("Package name or seinfo tag is null when trying to restorecon.");
- return -1;
- }
-
- uid_t uid = multiuser_get_uid(userid, appid);
- if (flags & FLAG_STORAGE_CE) {
- auto path = create_data_user_ce_package_path(uuid, userid, pkgName);
- if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid, seflags) < 0) {
- PLOG(ERROR) << "restorecon failed for " << path;
- res = -1;
- }
- }
- if (flags & FLAG_STORAGE_DE) {
- auto path = create_data_user_de_package_path(uuid, userid, pkgName);
- if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid, seflags) < 0) {
- PLOG(ERROR) << "restorecon failed for " << path;
- // TODO: include result once 25796509 is fixed
- }
- }
-
- return res;
-}
-
-int create_oat_dir(const char* oat_dir, const char* instruction_set)
-{
- char oat_instr_dir[PKG_PATH_MAX];
-
- if (validate_apk_path(oat_dir)) {
- ALOGE("invalid apk path '%s' (bad prefix)\n", oat_dir);
- return -1;
- }
- if (fs_prepare_dir(oat_dir, S_IRWXU | S_IRWXG | S_IXOTH, AID_SYSTEM, AID_INSTALL)) {
- return -1;
- }
- if (selinux_android_restorecon(oat_dir, 0)) {
- ALOGE("cannot restorecon dir '%s': %s\n", oat_dir, strerror(errno));
- return -1;
- }
- snprintf(oat_instr_dir, PKG_PATH_MAX, "%s/%s", oat_dir, instruction_set);
- if (fs_prepare_dir(oat_instr_dir, S_IRWXU | S_IRWXG | S_IXOTH, AID_SYSTEM, AID_INSTALL)) {
- return -1;
- }
- return 0;
-}
-
-int rm_package_dir(const char* apk_path)
-{
- if (validate_apk_path(apk_path)) {
- ALOGE("invalid apk path '%s' (bad prefix)\n", apk_path);
- return -1;
- }
- return delete_dir_contents(apk_path, 1 /* also_delete_dir */ , NULL /* exclusion_predicate */);
-}
-
-int link_file(const char* relative_path, const char* from_base, const char* to_base) {
- char from_path[PKG_PATH_MAX];
- char to_path[PKG_PATH_MAX];
- snprintf(from_path, PKG_PATH_MAX, "%s/%s", from_base, relative_path);
- snprintf(to_path, PKG_PATH_MAX, "%s/%s", to_base, relative_path);
-
- if (validate_apk_path_subdirs(from_path)) {
- ALOGE("invalid app data sub-path '%s' (bad prefix)\n", from_path);
- return -1;
- }
-
- if (validate_apk_path_subdirs(to_path)) {
- ALOGE("invalid app data sub-path '%s' (bad prefix)\n", to_path);
- return -1;
- }
-
- const int ret = link(from_path, to_path);
- if (ret < 0) {
- ALOGE("link(%s, %s) failed : %s", from_path, to_path, strerror(errno));
- return -1;
- }
-
- return 0;
-}
-
-// Helper for move_ab, so that we can have common failure-case cleanup.
-static bool unlink_and_rename(const char* from, const char* to) {
- // Check whether "from" exists, and if so whether it's regular. If it is, unlink. Otherwise,
- // return a failure.
- struct stat s;
- if (stat(to, &s) == 0) {
- if (!S_ISREG(s.st_mode)) {
- LOG(ERROR) << from << " is not a regular file to replace for A/B.";
- return false;
- }
- if (unlink(to) != 0) {
- LOG(ERROR) << "Could not unlink " << to << " to move A/B.";
- return false;
- }
- } else {
- // This may be a permission problem. We could investigate the error code, but we'll just
- // let the rename failure do the work for us.
- }
-
- // Try to rename "to" to "from."
- if (rename(from, to) != 0) {
- PLOG(ERROR) << "Could not rename " << from << " to " << to;
- return false;
- }
-
- return true;
-}
-
-// Move/rename a B artifact (from) to an A artifact (to).
-static bool move_ab_path(const std::string& b_path, const std::string& a_path) {
- // Check whether B exists.
- {
- struct stat s;
- if (stat(b_path.c_str(), &s) != 0) {
- // Silently ignore for now. The service calling this isn't smart enough to understand
- // lack of artifacts at the moment.
- return false;
- }
- if (!S_ISREG(s.st_mode)) {
- LOG(ERROR) << "A/B artifact " << b_path << " is not a regular file.";
- // Try to unlink, but swallow errors.
- unlink(b_path.c_str());
- return false;
- }
- }
-
- // Rename B to A.
- if (!unlink_and_rename(b_path.c_str(), a_path.c_str())) {
- // Delete the b_path so we don't try again (or fail earlier).
- if (unlink(b_path.c_str()) != 0) {
- PLOG(ERROR) << "Could not unlink " << b_path;
- }
-
- return false;
- }
-
- return true;
-}
-
-int move_ab(const char* apk_path, const char* instruction_set, const char* oat_dir) {
- if (apk_path == nullptr || instruction_set == nullptr || oat_dir == nullptr) {
- LOG(ERROR) << "Cannot move_ab with null input";
- return -1;
- }
-
- // Get the current slot suffix. No suffix, no A/B.
- std::string slot_suffix;
- {
- char buf[kPropertyValueMax];
- if (get_property("ro.boot.slot_suffix", buf, nullptr) <= 0) {
- return -1;
- }
- slot_suffix = buf;
-
- if (!ValidateTargetSlotSuffix(slot_suffix)) {
- LOG(ERROR) << "Target slot suffix not legal: " << slot_suffix;
- return -1;
- }
- }
-
- // Validate other inputs.
- if (validate_apk_path(apk_path) != 0) {
- LOG(ERROR) << "invalid apk_path " << apk_path;
- return -1;
- }
- if (validate_apk_path(oat_dir) != 0) {
- LOG(ERROR) << "invalid oat_dir " << oat_dir;
- return -1;
- }
-
- char a_path[PKG_PATH_MAX];
- if (!calculate_oat_file_path(a_path, oat_dir, apk_path, instruction_set)) {
- return -1;
- }
- const std::string a_image_path = create_image_filename(a_path);
-
- // B path = A path + slot suffix.
- const std::string b_path = StringPrintf("%s.%s", a_path, slot_suffix.c_str());
- const std::string b_image_path = StringPrintf("%s.%s",
- a_image_path.c_str(),
- slot_suffix.c_str());
-
- bool oat_success = move_ab_path(b_path, a_path);
- bool success;
-
- if (oat_success) {
- // Note: we can live without an app image. As such, ignore failure to move the image file.
- // If we decide to require the app image, or the app image being moved correctly,
- // then change accordingly.
- constexpr bool kIgnoreAppImageFailure = true;
-
- bool art_success = true;
- if (!a_image_path.empty()) {
- art_success = move_ab_path(b_image_path, a_image_path);
- if (!art_success) {
- unlink(a_image_path.c_str());
- }
- }
-
- success = art_success || kIgnoreAppImageFailure;
- } else {
- // Cleanup: delete B image, ignore errors.
- unlink(b_image_path.c_str());
-
- success = false;
- }
-
- return success ? 0 : -1;
-}
-
-bool delete_odex(const char *apk_path, const char *instruction_set, const char *oat_dir) {
- // Delete the oat/odex file.
- char out_path[PKG_PATH_MAX];
- if (!create_oat_out_path(apk_path, instruction_set, oat_dir, out_path)) {
- return false;
- }
-
- // In case of a permission failure report the issue. Otherwise just print a warning.
- auto unlink_and_check = [](const char* path) -> bool {
- int result = unlink(path);
- if (result != 0) {
- if (errno == EACCES || errno == EPERM) {
- PLOG(ERROR) << "Could not unlink " << path;
- return false;
- }
- PLOG(WARNING) << "Could not unlink " << path;
- }
- return true;
- };
-
- // Delete the oat/odex file.
- bool return_value_oat = unlink_and_check(out_path);
-
- // Derive and delete the app image.
- bool return_value_art = unlink_and_check(create_image_filename(out_path).c_str());
-
- // Report success.
- return return_value_oat && return_value_art;
-}
-
-} // namespace installd
-} // namespace android
diff --git a/cmds/installd/commands.h b/cmds/installd/commands.h
deleted file mode 100644
index ba27517..0000000
--- a/cmds/installd/commands.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
-**
-** Copyright 2008, 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 COMMANDS_H_
-#define COMMANDS_H_
-
-#include <inttypes.h>
-#include <unistd.h>
-
-#include <cutils/multiuser.h>
-
-#include <installd_constants.h>
-
-namespace android {
-namespace installd {
-
-static constexpr size_t DEXOPT_PARAM_COUNT = 10U;
-
-int create_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags,
- appid_t appid, const char* seinfo, int target_sdk_version);
-int restorecon_app_data(const char* uuid, const char* pkgName, userid_t userid, int flags,
- appid_t appid, const char* seinfo);
-int migrate_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags);
-int clear_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags,
- ino_t ce_data_inode);
-int destroy_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags,
- ino_t ce_data_inode);
-
-int move_complete_app(const char* from_uuid, const char *to_uuid, const char *package_name,
- const char *data_app_name, appid_t appid, const char* seinfo, int target_sdk_version);
-
-int get_app_size(const char *uuid, const char *pkgname, int userid, int flags, ino_t ce_data_inode,
- const char* code_path, int64_t *codesize, int64_t *datasize, int64_t *cachesize,
- int64_t *asecsize);
-int get_app_data_inode(const char *uuid, const char *pkgname, int userid, int flags, ino_t *inode);
-
-int create_user_data(const char *uuid, userid_t userid, int user_serial, int flags);
-int destroy_user_data(const char *uuid, userid_t userid, int flags);
-
-int rm_dex(const char *path, const char *instruction_set);
-int free_cache(const char *uuid, int64_t free_size);
-
-bool merge_profiles(uid_t uid, const char *pkgname);
-
-bool dump_profile(uid_t uid, const char *pkgname, const char *dex_files);
-
-int dexopt(const char *apk_path,
- uid_t uid,
- const char *pkgName,
- const char *instruction_set,
- int dexopt_needed,
- const char* oat_dir,
- int dexopt_flags,
- const char* compiler_filter,
- const char* volume_uuid,
- const char* shared_libraries);
-static_assert(DEXOPT_PARAM_COUNT == 10U, "Unexpected dexopt param size");
-
-// Helper for the above, converting arguments.
-int dexopt(const char* const params[DEXOPT_PARAM_COUNT]);
-
-int mark_boot_complete(const char *instruction_set);
-int linklib(const char* uuid, const char* pkgname, const char* asecLibDir, int userId);
-int idmap(const char *target_path, const char *overlay_path, uid_t uid);
-int create_oat_dir(const char* oat_dir, const char *instruction_set);
-int rm_package_dir(const char* apk_path);
-int clear_app_profiles(const char* pkgname);
-int destroy_app_profiles(const char* pkgname);
-int link_file(const char *relative_path, const char *from_base, const char *to_base);
-
-// Move a B version over to the A location. Only works for oat_dir != nullptr.
-int move_ab(const char *apk_path, const char *instruction_set, const char* oat_dir);
-
-// Delete odex files generated by dexopt.
-bool delete_odex(const char *apk_path, const char *instruction_set, const char *oat_dir);
-
-} // namespace installd
-} // namespace android
-
-#endif // COMMANDS_H_
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
new file mode 100644
index 0000000..797cc15
--- /dev/null
+++ b/cmds/installd/dexopt.cpp
@@ -0,0 +1,1884 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "installed"
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/capability.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <cutils/fs.h>
+#include <cutils/properties.h>
+#include <cutils/sched_policy.h>
+#include <log/log.h> // TODO: Move everything to base/logging.
+#include <private/android_filesystem_config.h>
+#include <system/thread_defs.h>
+
+#include "dexopt.h"
+#include "installd_deps.h"
+#include "otapreopt_utils.h"
+#include "utils.h"
+
+using android::base::StringPrintf;
+using android::base::EndsWith;
+using android::base::unique_fd;
+
+namespace android {
+namespace installd {
+
+// Deleter using free() for use with std::unique_ptr<>. See also UniqueCPtr<> below.
+struct FreeDelete {
+ // NOTE: Deleting a const object is valid but free() takes a non-const pointer.
+ void operator()(const void* ptr) const {
+ free(const_cast<void*>(ptr));
+ }
+};
+
+// Alias for std::unique_ptr<> that uses the C function free() to delete objects.
+template <typename T>
+using UniqueCPtr = std::unique_ptr<T, FreeDelete>;
+
+static unique_fd invalid_unique_fd() {
+ return unique_fd(-1);
+}
+
+static const char* parse_null(const char* arg) {
+ if (strcmp(arg, "!") == 0) {
+ return nullptr;
+ } else {
+ return arg;
+ }
+}
+
+static bool clear_profile(const std::string& profile) {
+ unique_fd ufd(open(profile.c_str(), O_WRONLY | O_NOFOLLOW | O_CLOEXEC));
+ if (ufd.get() < 0) {
+ if (errno != ENOENT) {
+ PLOG(WARNING) << "Could not open profile " << profile;
+ return false;
+ } else {
+ // Nothing to clear. That's ok.
+ return true;
+ }
+ }
+
+ if (flock(ufd.get(), LOCK_EX | LOCK_NB) != 0) {
+ if (errno != EWOULDBLOCK) {
+ PLOG(WARNING) << "Error locking profile " << profile;
+ }
+ // This implies that the app owning this profile is running
+ // (and has acquired the lock).
+ //
+ // If we can't acquire the lock bail out since clearing is useless anyway
+ // (the app will write again to the profile).
+ //
+ // Note:
+ // This does not impact the this is not an issue for the profiling correctness.
+ // In case this is needed because of an app upgrade, profiles will still be
+ // eventually cleared by the app itself due to checksum mismatch.
+ // If this is needed because profman advised, then keeping the data around
+ // until the next run is again not an issue.
+ //
+ // If the app attempts to acquire a lock while we've held one here,
+ // it will simply skip the current write cycle.
+ return false;
+ }
+
+ bool truncated = ftruncate(ufd.get(), 0) == 0;
+ if (!truncated) {
+ PLOG(WARNING) << "Could not truncate " << profile;
+ }
+ if (flock(ufd.get(), LOCK_UN) != 0) {
+ PLOG(WARNING) << "Error unlocking profile " << profile;
+ }
+ return truncated;
+}
+
+// Clear the reference profile for the given location.
+// The location is the package name for primary apks or the dex path for secondary dex files.
+static bool clear_reference_profile(const std::string& location, bool is_secondary_dex) {
+ return clear_profile(create_reference_profile_path(location, is_secondary_dex));
+}
+
+// Clear the reference profile for the given location.
+// The location is the package name for primary apks or the dex path for secondary dex files.
+static bool clear_current_profile(const std::string& pkgname, userid_t user,
+ bool is_secondary_dex) {
+ return clear_profile(create_current_profile_path(user, pkgname, is_secondary_dex));
+}
+
+// Clear the reference profile for the primary apk of the given package.
+bool clear_primary_reference_profile(const std::string& pkgname) {
+ return clear_reference_profile(pkgname, /*is_secondary_dex*/false);
+}
+
+// Clear all current profile for the primary apk of the given package.
+bool clear_primary_current_profiles(const std::string& pkgname) {
+ bool success = true;
+ // For secondary dex files, we don't really need the user but we use it for sanity checks.
+ std::vector<userid_t> users = get_known_users(/*volume_uuid*/ nullptr);
+ for (auto user : users) {
+ success &= clear_current_profile(pkgname, user, /*is_secondary_dex*/false);
+ }
+ return success;
+}
+
+// Clear the current profile for the primary apk of the given package and user.
+bool clear_primary_current_profile(const std::string& pkgname, userid_t user) {
+ return clear_current_profile(pkgname, user, /*is_secondary_dex*/false);
+}
+
+static int split_count(const char *str)
+{
+ char *ctx;
+ int count = 0;
+ char buf[kPropertyValueMax];
+
+ strncpy(buf, str, sizeof(buf));
+ char *pBuf = buf;
+
+ while(strtok_r(pBuf, " ", &ctx) != NULL) {
+ count++;
+ pBuf = NULL;
+ }
+
+ return count;
+}
+
+static int split(char *buf, const char **argv)
+{
+ char *ctx;
+ int count = 0;
+ char *tok;
+ char *pBuf = buf;
+
+ while((tok = strtok_r(pBuf, " ", &ctx)) != NULL) {
+ argv[count++] = tok;
+ pBuf = NULL;
+ }
+
+ return count;
+}
+
+static const char* get_location_from_path(const char* path) {
+ static constexpr char kLocationSeparator = '/';
+ const char *location = strrchr(path, kLocationSeparator);
+ if (location == NULL) {
+ return path;
+ } else {
+ // Skip the separator character.
+ return location + 1;
+ }
+}
+
+static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vdex_fd, int image_fd,
+ const char* input_file_name, const char* output_file_name, int swap_fd,
+ const char* instruction_set, const char* compiler_filter,
+ bool debuggable, bool post_bootcomplete, int profile_fd, const char* shared_libraries) {
+ static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
+
+ if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
+ ALOGE("Instruction set %s longer than max length of %d",
+ instruction_set, MAX_INSTRUCTION_SET_LEN);
+ return;
+ }
+
+ // Get the relative path to the input file.
+ const char* relative_input_file_name = get_location_from_path(input_file_name);
+
+ char dex2oat_Xms_flag[kPropertyValueMax];
+ bool have_dex2oat_Xms_flag = get_property("dalvik.vm.dex2oat-Xms", dex2oat_Xms_flag, NULL) > 0;
+
+ char dex2oat_Xmx_flag[kPropertyValueMax];
+ bool have_dex2oat_Xmx_flag = get_property("dalvik.vm.dex2oat-Xmx", dex2oat_Xmx_flag, NULL) > 0;
+
+ char dex2oat_threads_buf[kPropertyValueMax];
+ bool have_dex2oat_threads_flag = get_property(post_bootcomplete
+ ? "dalvik.vm.dex2oat-threads"
+ : "dalvik.vm.boot-dex2oat-threads",
+ dex2oat_threads_buf,
+ NULL) > 0;
+ char dex2oat_threads_arg[kPropertyValueMax + 2];
+ if (have_dex2oat_threads_flag) {
+ sprintf(dex2oat_threads_arg, "-j%s", dex2oat_threads_buf);
+ }
+
+ char dex2oat_isa_features_key[kPropertyKeyMax];
+ sprintf(dex2oat_isa_features_key, "dalvik.vm.isa.%s.features", instruction_set);
+ char dex2oat_isa_features[kPropertyValueMax];
+ bool have_dex2oat_isa_features = get_property(dex2oat_isa_features_key,
+ dex2oat_isa_features, NULL) > 0;
+
+ char dex2oat_isa_variant_key[kPropertyKeyMax];
+ sprintf(dex2oat_isa_variant_key, "dalvik.vm.isa.%s.variant", instruction_set);
+ char dex2oat_isa_variant[kPropertyValueMax];
+ bool have_dex2oat_isa_variant = get_property(dex2oat_isa_variant_key,
+ dex2oat_isa_variant, NULL) > 0;
+
+ const char *dex2oat_norelocation = "-Xnorelocate";
+ bool have_dex2oat_relocation_skip_flag = false;
+
+ char dex2oat_flags[kPropertyValueMax];
+ int dex2oat_flags_count = get_property("dalvik.vm.dex2oat-flags",
+ dex2oat_flags, NULL) <= 0 ? 0 : split_count(dex2oat_flags);
+ ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags);
+
+ // If we are booting without the real /data, don't spend time compiling.
+ char vold_decrypt[kPropertyValueMax];
+ bool have_vold_decrypt = get_property("vold.decrypt", vold_decrypt, "") > 0;
+ bool skip_compilation = (have_vold_decrypt &&
+ (strcmp(vold_decrypt, "trigger_restart_min_framework") == 0 ||
+ (strcmp(vold_decrypt, "1") == 0)));
+
+ bool generate_debug_info = property_get_bool("debug.generate-debug-info", false);
+
+ char app_image_format[kPropertyValueMax];
+ char image_format_arg[strlen("--image-format=") + kPropertyValueMax];
+ bool have_app_image_format =
+ image_fd >= 0 && get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
+ if (have_app_image_format) {
+ sprintf(image_format_arg, "--image-format=%s", app_image_format);
+ }
+
+ char dex2oat_large_app_threshold[kPropertyValueMax];
+ bool have_dex2oat_large_app_threshold =
+ get_property("dalvik.vm.dex2oat-very-large", dex2oat_large_app_threshold, NULL) > 0;
+ char dex2oat_large_app_threshold_arg[strlen("--very-large-app-threshold=") + kPropertyValueMax];
+ if (have_dex2oat_large_app_threshold) {
+ sprintf(dex2oat_large_app_threshold_arg,
+ "--very-large-app-threshold=%s",
+ dex2oat_large_app_threshold);
+ }
+
+ static const char* DEX2OAT_BIN = "/system/bin/dex2oat";
+
+ static const char* RUNTIME_ARG = "--runtime-arg";
+
+ static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig
+
+ // clang FORTIFY doesn't let us use strlen in constant array bounds, so we
+ // use arraysize instead.
+ char zip_fd_arg[arraysize("--zip-fd=") + MAX_INT_LEN];
+ char zip_location_arg[arraysize("--zip-location=") + PKG_PATH_MAX];
+ char input_vdex_fd_arg[arraysize("--input-vdex-fd=") + MAX_INT_LEN];
+ char output_vdex_fd_arg[arraysize("--output-vdex-fd=") + MAX_INT_LEN];
+ char oat_fd_arg[arraysize("--oat-fd=") + MAX_INT_LEN];
+ char oat_location_arg[arraysize("--oat-location=") + PKG_PATH_MAX];
+ char instruction_set_arg[arraysize("--instruction-set=") + MAX_INSTRUCTION_SET_LEN];
+ char instruction_set_variant_arg[arraysize("--instruction-set-variant=") + kPropertyValueMax];
+ char instruction_set_features_arg[arraysize("--instruction-set-features=") + kPropertyValueMax];
+ char dex2oat_Xms_arg[arraysize("-Xms") + kPropertyValueMax];
+ char dex2oat_Xmx_arg[arraysize("-Xmx") + kPropertyValueMax];
+ char dex2oat_compiler_filter_arg[arraysize("--compiler-filter=") + kPropertyValueMax];
+ bool have_dex2oat_swap_fd = false;
+ char dex2oat_swap_fd[arraysize("--swap-fd=") + MAX_INT_LEN];
+ bool have_dex2oat_image_fd = false;
+ char dex2oat_image_fd[arraysize("--app-image-fd=") + MAX_INT_LEN];
+
+ sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd);
+ sprintf(zip_location_arg, "--zip-location=%s", relative_input_file_name);
+ sprintf(input_vdex_fd_arg, "--input-vdex-fd=%d", input_vdex_fd);
+ sprintf(output_vdex_fd_arg, "--output-vdex-fd=%d", output_vdex_fd);
+ sprintf(oat_fd_arg, "--oat-fd=%d", oat_fd);
+ sprintf(oat_location_arg, "--oat-location=%s", output_file_name);
+ sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set);
+ sprintf(instruction_set_variant_arg, "--instruction-set-variant=%s", dex2oat_isa_variant);
+ sprintf(instruction_set_features_arg, "--instruction-set-features=%s", dex2oat_isa_features);
+ if (swap_fd >= 0) {
+ have_dex2oat_swap_fd = true;
+ sprintf(dex2oat_swap_fd, "--swap-fd=%d", swap_fd);
+ }
+ if (image_fd >= 0) {
+ have_dex2oat_image_fd = true;
+ sprintf(dex2oat_image_fd, "--app-image-fd=%d", image_fd);
+ }
+
+ if (have_dex2oat_Xms_flag) {
+ sprintf(dex2oat_Xms_arg, "-Xms%s", dex2oat_Xms_flag);
+ }
+ if (have_dex2oat_Xmx_flag) {
+ sprintf(dex2oat_Xmx_arg, "-Xmx%s", dex2oat_Xmx_flag);
+ }
+
+ // Compute compiler filter.
+
+ bool have_dex2oat_compiler_filter_flag = false;
+ if (skip_compilation) {
+ strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=extract");
+ have_dex2oat_compiler_filter_flag = true;
+ have_dex2oat_relocation_skip_flag = true;
+ } else if (compiler_filter != nullptr) {
+ if (strlen(compiler_filter) + strlen("--compiler-filter=") <
+ arraysize(dex2oat_compiler_filter_arg)) {
+ sprintf(dex2oat_compiler_filter_arg, "--compiler-filter=%s", compiler_filter);
+ have_dex2oat_compiler_filter_flag = true;
+ } else {
+ ALOGW("Compiler filter name '%s' is too large (max characters is %zu)",
+ compiler_filter,
+ kPropertyValueMax);
+ }
+ }
+
+ if (!have_dex2oat_compiler_filter_flag) {
+ char dex2oat_compiler_filter_flag[kPropertyValueMax];
+ have_dex2oat_compiler_filter_flag = get_property("dalvik.vm.dex2oat-filter",
+ dex2oat_compiler_filter_flag, NULL) > 0;
+ if (have_dex2oat_compiler_filter_flag) {
+ sprintf(dex2oat_compiler_filter_arg,
+ "--compiler-filter=%s",
+ dex2oat_compiler_filter_flag);
+ }
+ }
+
+ // Check whether all apps should be compiled debuggable.
+ if (!debuggable) {
+ char prop_buf[kPropertyValueMax];
+ debuggable =
+ (get_property("dalvik.vm.always_debuggable", prop_buf, "0") > 0) &&
+ (prop_buf[0] == '1');
+ }
+ char profile_arg[strlen("--profile-file-fd=") + MAX_INT_LEN];
+ if (profile_fd != -1) {
+ sprintf(profile_arg, "--profile-file-fd=%d", profile_fd);
+ }
+
+ // Get the directory of the apk to pass as a base classpath directory.
+ char base_dir[arraysize("--classpath-dir=") + PKG_PATH_MAX];
+ std::string apk_dir(input_file_name);
+ unsigned long dir_index = apk_dir.rfind('/');
+ bool has_base_dir = dir_index != std::string::npos;
+ if (has_base_dir) {
+ apk_dir = apk_dir.substr(0, dir_index);
+ sprintf(base_dir, "--classpath-dir=%s", apk_dir.c_str());
+ }
+
+
+ ALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, relative_input_file_name, output_file_name);
+
+ const char* argv[9 // program name, mandatory arguments and the final NULL
+ + (have_dex2oat_isa_variant ? 1 : 0)
+ + (have_dex2oat_isa_features ? 1 : 0)
+ + (have_dex2oat_Xms_flag ? 2 : 0)
+ + (have_dex2oat_Xmx_flag ? 2 : 0)
+ + (have_dex2oat_compiler_filter_flag ? 1 : 0)
+ + (have_dex2oat_threads_flag ? 1 : 0)
+ + (have_dex2oat_swap_fd ? 1 : 0)
+ + (have_dex2oat_image_fd ? 1 : 0)
+ + (have_dex2oat_relocation_skip_flag ? 2 : 0)
+ + (generate_debug_info ? 1 : 0)
+ + (debuggable ? 1 : 0)
+ + (have_app_image_format ? 1 : 0)
+ + dex2oat_flags_count
+ + (profile_fd == -1 ? 0 : 1)
+ + (shared_libraries != nullptr ? 4 : 0)
+ + (has_base_dir ? 1 : 0)
+ + (have_dex2oat_large_app_threshold ? 1 : 0)];
+ int i = 0;
+ argv[i++] = DEX2OAT_BIN;
+ argv[i++] = zip_fd_arg;
+ argv[i++] = zip_location_arg;
+ argv[i++] = input_vdex_fd_arg;
+ argv[i++] = output_vdex_fd_arg;
+ argv[i++] = oat_fd_arg;
+ argv[i++] = oat_location_arg;
+ argv[i++] = instruction_set_arg;
+ if (have_dex2oat_isa_variant) {
+ argv[i++] = instruction_set_variant_arg;
+ }
+ if (have_dex2oat_isa_features) {
+ argv[i++] = instruction_set_features_arg;
+ }
+ if (have_dex2oat_Xms_flag) {
+ argv[i++] = RUNTIME_ARG;
+ argv[i++] = dex2oat_Xms_arg;
+ }
+ if (have_dex2oat_Xmx_flag) {
+ argv[i++] = RUNTIME_ARG;
+ argv[i++] = dex2oat_Xmx_arg;
+ }
+ if (have_dex2oat_compiler_filter_flag) {
+ argv[i++] = dex2oat_compiler_filter_arg;
+ }
+ if (have_dex2oat_threads_flag) {
+ argv[i++] = dex2oat_threads_arg;
+ }
+ if (have_dex2oat_swap_fd) {
+ argv[i++] = dex2oat_swap_fd;
+ }
+ if (have_dex2oat_image_fd) {
+ argv[i++] = dex2oat_image_fd;
+ }
+ if (generate_debug_info) {
+ argv[i++] = "--generate-debug-info";
+ }
+ if (debuggable) {
+ argv[i++] = "--debuggable";
+ }
+ if (have_app_image_format) {
+ argv[i++] = image_format_arg;
+ }
+ if (have_dex2oat_large_app_threshold) {
+ argv[i++] = dex2oat_large_app_threshold_arg;
+ }
+ if (dex2oat_flags_count) {
+ i += split(dex2oat_flags, argv + i);
+ }
+ if (have_dex2oat_relocation_skip_flag) {
+ argv[i++] = RUNTIME_ARG;
+ argv[i++] = dex2oat_norelocation;
+ }
+ if (profile_fd != -1) {
+ argv[i++] = profile_arg;
+ }
+ if (shared_libraries != nullptr) {
+ argv[i++] = RUNTIME_ARG;
+ argv[i++] = "-classpath";
+ argv[i++] = RUNTIME_ARG;
+ argv[i++] = shared_libraries;
+ }
+ if (has_base_dir) {
+ argv[i++] = base_dir;
+ }
+ // Do not add after dex2oat_flags, they should override others for debugging.
+ argv[i] = NULL;
+
+ execv(DEX2OAT_BIN, (char * const *)argv);
+ ALOGE("execv(%s) failed: %s\n", DEX2OAT_BIN, strerror(errno));
+}
+
+/*
+ * Whether dexopt should use a swap file when compiling an APK.
+ *
+ * If kAlwaysProvideSwapFile, do this on all devices (dex2oat will make a more informed decision
+ * itself, anyways).
+ *
+ * Otherwise, read "dalvik.vm.dex2oat-swap". If the property exists, return whether it is "true".
+ *
+ * Otherwise, return true if this is a low-mem device.
+ *
+ * Otherwise, return default value.
+ */
+static bool kAlwaysProvideSwapFile = false;
+static bool kDefaultProvideSwapFile = true;
+
+static bool ShouldUseSwapFileForDexopt() {
+ if (kAlwaysProvideSwapFile) {
+ return true;
+ }
+
+ // Check the "override" property. If it exists, return value == "true".
+ char dex2oat_prop_buf[kPropertyValueMax];
+ if (get_property("dalvik.vm.dex2oat-swap", dex2oat_prop_buf, "") > 0) {
+ if (strcmp(dex2oat_prop_buf, "true") == 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ // Shortcut for default value. This is an implementation optimization for the process sketched
+ // above. If the default value is true, we can avoid to check whether this is a low-mem device,
+ // as low-mem is never returning false. The compiler will optimize this away if it can.
+ if (kDefaultProvideSwapFile) {
+ return true;
+ }
+
+ bool is_low_mem = property_get_bool("ro.config.low_ram", false);
+ if (is_low_mem) {
+ return true;
+ }
+
+ // Default value must be false here.
+ return kDefaultProvideSwapFile;
+}
+
+static void SetDex2OatScheduling(bool set_to_bg) {
+ if (set_to_bg) {
+ if (set_sched_policy(0, SP_BACKGROUND) < 0) {
+ ALOGE("set_sched_policy failed: %s\n", strerror(errno));
+ exit(70);
+ }
+ if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
+ ALOGE("setpriority failed: %s\n", strerror(errno));
+ exit(71);
+ }
+ }
+}
+
+static bool create_profile(int uid, const std::string& profile) {
+ unique_fd fd(TEMP_FAILURE_RETRY(open(profile.c_str(), O_CREAT | O_NOFOLLOW, 0600)));
+ if (fd.get() < 0) {
+ if (errno == EEXIST) {
+ return true;
+ } else {
+ PLOG(ERROR) << "Failed to create profile " << profile;
+ return false;
+ }
+ }
+ // Profiles should belong to the app; make sure of that by giving ownership to
+ // the app uid. If we cannot do that, there's no point in returning the fd
+ // since dex2oat/profman will fail with SElinux denials.
+ if (fchown(fd.get(), uid, uid) < 0) {
+ PLOG(ERROR) << "Could not chwon profile " << profile;
+ return false;
+ }
+ return true;
+}
+
+static unique_fd open_profile(int uid, const std::string& profile, bool read_write) {
+ // Check if we need to open the profile for a read-write operation. If so, we
+ // might need to create the profile since the file might not be there. Reference
+ // profiles are created on the fly so they might not exist beforehand.
+ if (read_write) {
+ if (!create_profile(uid, profile)) {
+ return invalid_unique_fd();
+ }
+ }
+ int flags = read_write ? O_RDWR : O_RDONLY;
+ // Do not follow symlinks when opening a profile:
+ // - primary profiles should not contain symlinks in their paths
+ // - secondary dex paths should have been already resolved and validated
+ flags |= O_NOFOLLOW;
+
+ unique_fd fd(TEMP_FAILURE_RETRY(open(profile.c_str(), flags)));
+ if (fd.get() < 0) {
+ if (errno != ENOENT) {
+ // Profiles might be missing for various reasons. For example, in a
+ // multi-user environment, the profile directory for one user can be created
+ // after we start a merge. In this case the current profile for that user
+ // will not be found.
+ // Also, the secondary dex profiles might be deleted by the app at any time,
+ // so we can't we need to prepare if they are missing.
+ PLOG(ERROR) << "Failed to open profile " << profile;
+ }
+ return invalid_unique_fd();
+ }
+
+ return fd;
+}
+
+static unique_fd open_current_profile(uid_t uid, userid_t user, const std::string& location,
+ bool is_secondary_dex) {
+ std::string profile = create_current_profile_path(user, location, is_secondary_dex);
+ return open_profile(uid, profile, /*read_write*/false);
+}
+
+static unique_fd open_reference_profile(uid_t uid, const std::string& location, bool read_write,
+ bool is_secondary_dex) {
+ std::string profile = create_reference_profile_path(location, is_secondary_dex);
+ return open_profile(uid, profile, read_write);
+}
+
+static void open_profile_files(uid_t uid, const std::string& location, bool is_secondary_dex,
+ /*out*/ std::vector<unique_fd>* profiles_fd, /*out*/ unique_fd* reference_profile_fd) {
+ // Open the reference profile in read-write mode as profman might need to save the merge.
+ *reference_profile_fd = open_reference_profile(uid, location, /*read_write*/ true,
+ is_secondary_dex);
+
+ // For secondary dex files, we don't really need the user but we use it for sanity checks.
+ // Note: the user owning the dex file should be the current user.
+ std::vector<userid_t> users;
+ if (is_secondary_dex){
+ users.push_back(multiuser_get_user_id(uid));
+ } else {
+ users = get_known_users(/*volume_uuid*/ nullptr);
+ }
+ for (auto user : users) {
+ unique_fd profile_fd = open_current_profile(uid, user, location, is_secondary_dex);
+ // Add to the lists only if both fds are valid.
+ if (profile_fd.get() >= 0) {
+ profiles_fd->push_back(std::move(profile_fd));
+ }
+ }
+}
+
+static void drop_capabilities(uid_t uid) {
+ if (setgid(uid) != 0) {
+ ALOGE("setgid(%d) failed in installd during dexopt\n", uid);
+ exit(64);
+ }
+ if (setuid(uid) != 0) {
+ ALOGE("setuid(%d) failed in installd during dexopt\n", uid);
+ exit(65);
+ }
+ // drop capabilities
+ struct __user_cap_header_struct capheader;
+ struct __user_cap_data_struct capdata[2];
+ memset(&capheader, 0, sizeof(capheader));
+ memset(&capdata, 0, sizeof(capdata));
+ capheader.version = _LINUX_CAPABILITY_VERSION_3;
+ if (capset(&capheader, &capdata[0]) < 0) {
+ ALOGE("capset failed: %s\n", strerror(errno));
+ exit(66);
+ }
+}
+
+static constexpr int PROFMAN_BIN_RETURN_CODE_COMPILE = 0;
+static constexpr int PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION = 1;
+static constexpr int PROFMAN_BIN_RETURN_CODE_BAD_PROFILES = 2;
+static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_IO = 3;
+static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING = 4;
+
+static void run_profman_merge(const std::vector<unique_fd>& profiles_fd,
+ const unique_fd& reference_profile_fd) {
+ static const size_t MAX_INT_LEN = 32;
+ static const char* PROFMAN_BIN = "/system/bin/profman";
+
+ std::vector<std::string> profile_args(profiles_fd.size());
+ char profile_buf[strlen("--profile-file-fd=") + MAX_INT_LEN];
+ for (size_t k = 0; k < profiles_fd.size(); k++) {
+ sprintf(profile_buf, "--profile-file-fd=%d", profiles_fd[k].get());
+ profile_args[k].assign(profile_buf);
+ }
+ char reference_profile_arg[strlen("--reference-profile-file-fd=") + MAX_INT_LEN];
+ sprintf(reference_profile_arg, "--reference-profile-file-fd=%d", reference_profile_fd.get());
+
+ // program name, reference profile fd, the final NULL and the profile fds
+ const char* argv[3 + profiles_fd.size()];
+ int i = 0;
+ argv[i++] = PROFMAN_BIN;
+ argv[i++] = reference_profile_arg;
+ for (size_t k = 0; k < profile_args.size(); k++) {
+ argv[i++] = profile_args[k].c_str();
+ }
+ // Do not add after dex2oat_flags, they should override others for debugging.
+ argv[i] = NULL;
+
+ execv(PROFMAN_BIN, (char * const *)argv);
+ ALOGE("execv(%s) failed: %s\n", PROFMAN_BIN, strerror(errno));
+ exit(68); /* only get here on exec failure */
+}
+
+// Decides if profile guided compilation is needed or not based on existing profiles.
+// The location is the package name for primary apks or the dex path for secondary dex files.
+// Returns true if there is enough information in the current profiles that makes it
+// worth to recompile the given location.
+// If the return value is true all the current profiles would have been merged into
+// the reference profiles accessible with open_reference_profile().
+static bool analyze_profiles(uid_t uid, const std::string& location, bool is_secondary_dex) {
+ std::vector<unique_fd> profiles_fd;
+ unique_fd reference_profile_fd;
+ open_profile_files(uid, location, is_secondary_dex, &profiles_fd, &reference_profile_fd);
+ if (profiles_fd.empty() || (reference_profile_fd.get() < 0)) {
+ // Skip profile guided compilation because no profiles were found.
+ // Or if the reference profile info couldn't be opened.
+ return false;
+ }
+
+ pid_t pid = fork();
+ if (pid == 0) {
+ /* child -- drop privileges before continuing */
+ drop_capabilities(uid);
+ run_profman_merge(profiles_fd, reference_profile_fd);
+ exit(68); /* only get here on exec failure */
+ }
+ /* parent */
+ int return_code = wait_child(pid);
+ bool need_to_compile = false;
+ bool should_clear_current_profiles = false;
+ bool should_clear_reference_profile = false;
+ if (!WIFEXITED(return_code)) {
+ LOG(WARNING) << "profman failed for location " << location << ": " << return_code;
+ } else {
+ return_code = WEXITSTATUS(return_code);
+ switch (return_code) {
+ case PROFMAN_BIN_RETURN_CODE_COMPILE:
+ need_to_compile = true;
+ should_clear_current_profiles = true;
+ should_clear_reference_profile = false;
+ break;
+ case PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION:
+ need_to_compile = false;
+ should_clear_current_profiles = false;
+ should_clear_reference_profile = false;
+ break;
+ case PROFMAN_BIN_RETURN_CODE_BAD_PROFILES:
+ LOG(WARNING) << "Bad profiles for location " << location;
+ need_to_compile = false;
+ should_clear_current_profiles = true;
+ should_clear_reference_profile = true;
+ break;
+ case PROFMAN_BIN_RETURN_CODE_ERROR_IO: // fall-through
+ case PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING:
+ // Temporary IO problem (e.g. locking). Ignore but log a warning.
+ LOG(WARNING) << "IO error while reading profiles for location " << location;
+ need_to_compile = false;
+ should_clear_current_profiles = false;
+ should_clear_reference_profile = false;
+ break;
+ default:
+ // Unknown return code or error. Unlink profiles.
+ LOG(WARNING) << "Unknown error code while processing profiles for location "
+ << location << ": " << return_code;
+ need_to_compile = false;
+ should_clear_current_profiles = true;
+ should_clear_reference_profile = true;
+ break;
+ }
+ }
+
+ if (should_clear_current_profiles) {
+ if (is_secondary_dex) {
+ // For secondary dex files, the owning user is the current user.
+ clear_current_profile(location, multiuser_get_user_id(uid), is_secondary_dex);
+ } else {
+ clear_primary_current_profiles(location);
+ }
+ }
+ if (should_clear_reference_profile) {
+ clear_reference_profile(location, is_secondary_dex);
+ }
+ return need_to_compile;
+}
+
+// Decides if profile guided compilation is needed or not based on existing profiles.
+// The analysis is done for the primary apks of the given package.
+// Returns true if there is enough information in the current profiles that makes it
+// worth to recompile the package.
+// If the return value is true all the current profiles would have been merged into
+// the reference profiles accessible with open_reference_profile().
+bool analyze_primary_profiles(uid_t uid, const std::string& pkgname) {
+ return analyze_profiles(uid, pkgname, /*is_secondary_dex*/false);
+}
+
+static void run_profman_dump(const std::vector<unique_fd>& profile_fds,
+ const unique_fd& reference_profile_fd,
+ const std::vector<std::string>& dex_locations,
+ const std::vector<unique_fd>& apk_fds,
+ const unique_fd& output_fd) {
+ std::vector<std::string> profman_args;
+ static const char* PROFMAN_BIN = "/system/bin/profman";
+ profman_args.push_back(PROFMAN_BIN);
+ profman_args.push_back("--dump-only");
+ profman_args.push_back(StringPrintf("--dump-output-to-fd=%d", output_fd.get()));
+ if (reference_profile_fd != -1) {
+ profman_args.push_back(StringPrintf("--reference-profile-file-fd=%d",
+ reference_profile_fd.get()));
+ }
+ for (size_t i = 0; i < profile_fds.size(); i++) {
+ profman_args.push_back(StringPrintf("--profile-file-fd=%d", profile_fds[i].get()));
+ }
+ for (const std::string& dex_location : dex_locations) {
+ profman_args.push_back(StringPrintf("--dex-location=%s", dex_location.c_str()));
+ }
+ for (size_t i = 0; i < apk_fds.size(); i++) {
+ profman_args.push_back(StringPrintf("--apk-fd=%d", apk_fds[i].get()));
+ }
+ const char **argv = new const char*[profman_args.size() + 1];
+ size_t i = 0;
+ for (const std::string& profman_arg : profman_args) {
+ argv[i++] = profman_arg.c_str();
+ }
+ argv[i] = NULL;
+
+ execv(PROFMAN_BIN, (char * const *)argv);
+ ALOGE("execv(%s) failed: %s\n", PROFMAN_BIN, strerror(errno));
+ exit(68); /* only get here on exec failure */
+}
+
+bool dump_profiles(int32_t uid, const std::string& pkgname, const char* code_paths) {
+ std::vector<unique_fd> profile_fds;
+ unique_fd reference_profile_fd;
+ std::string out_file_name = StringPrintf("/data/misc/profman/%s.txt", pkgname.c_str());
+
+ open_profile_files(uid, pkgname, /*is_secondary_dex*/false,
+ &profile_fds, &reference_profile_fd);
+
+ const bool has_reference_profile = (reference_profile_fd.get() != -1);
+ const bool has_profiles = !profile_fds.empty();
+
+ if (!has_reference_profile && !has_profiles) {
+ LOG(ERROR) << "profman dump: no profiles to dump for " << pkgname;
+ return false;
+ }
+
+ unique_fd output_fd(open(out_file_name.c_str(),
+ O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, 0644));
+ if (fchmod(output_fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) {
+ ALOGE("installd cannot chmod '%s' dump_profile\n", out_file_name.c_str());
+ return false;
+ }
+ std::vector<std::string> code_full_paths = base::Split(code_paths, ";");
+ std::vector<std::string> dex_locations;
+ std::vector<unique_fd> apk_fds;
+ for (const std::string& code_full_path : code_full_paths) {
+ const char* full_path = code_full_path.c_str();
+ unique_fd apk_fd(open(full_path, O_RDONLY | O_NOFOLLOW));
+ if (apk_fd == -1) {
+ ALOGE("installd cannot open '%s'\n", full_path);
+ return false;
+ }
+ dex_locations.push_back(get_location_from_path(full_path));
+ apk_fds.push_back(std::move(apk_fd));
+ }
+
+ pid_t pid = fork();
+ if (pid == 0) {
+ /* child -- drop privileges before continuing */
+ drop_capabilities(uid);
+ run_profman_dump(profile_fds, reference_profile_fd, dex_locations,
+ apk_fds, output_fd);
+ exit(68); /* only get here on exec failure */
+ }
+ /* parent */
+ int return_code = wait_child(pid);
+ if (!WIFEXITED(return_code)) {
+ LOG(WARNING) << "profman failed for package " << pkgname << ": "
+ << return_code;
+ return false;
+ }
+ return true;
+}
+
+static std::string replace_file_extension(const std::string& oat_path, const std::string& new_ext) {
+ // A standard dalvik-cache entry. Replace ".dex" with `new_ext`.
+ if (EndsWith(oat_path, ".dex")) {
+ std::string new_path = oat_path;
+ new_path.replace(new_path.length() - strlen(".dex"), strlen(".dex"), new_ext);
+ CHECK(EndsWith(new_path, new_ext.c_str()));
+ return new_path;
+ }
+
+ // An odex entry. Not that this may not be an extension, e.g., in the OTA
+ // case (where the base name will have an extension for the B artifact).
+ size_t odex_pos = oat_path.rfind(".odex");
+ if (odex_pos != std::string::npos) {
+ std::string new_path = oat_path;
+ new_path.replace(odex_pos, strlen(".odex"), new_ext);
+ CHECK_NE(new_path.find(new_ext), std::string::npos);
+ return new_path;
+ }
+
+ // Don't know how to handle this.
+ return "";
+}
+
+// Translate the given oat path to an art (app image) path. An empty string
+// denotes an error.
+static std::string create_image_filename(const std::string& oat_path) {
+ return replace_file_extension(oat_path, ".art");
+}
+
+// Translate the given oat path to a vdex path. An empty string denotes an error.
+static std::string create_vdex_filename(const std::string& oat_path) {
+ return replace_file_extension(oat_path, ".vdex");
+}
+
+static bool add_extension_to_file_name(char* file_name, const char* extension) {
+ if (strlen(file_name) + strlen(extension) + 1 > PKG_PATH_MAX) {
+ return false;
+ }
+ strcat(file_name, extension);
+ return true;
+}
+
+static int open_output_file(const char* file_name, bool recreate, int permissions) {
+ int flags = O_RDWR | O_CREAT;
+ if (recreate) {
+ if (unlink(file_name) < 0) {
+ if (errno != ENOENT) {
+ PLOG(ERROR) << "open_output_file: Couldn't unlink " << file_name;
+ }
+ }
+ flags |= O_EXCL;
+ }
+ return open(file_name, flags, permissions);
+}
+
+static bool set_permissions_and_ownership(
+ int fd, bool is_public, int uid, const char* path, bool is_secondary_dex) {
+ // Primary apks are owned by the system. Secondary dex files are owned by the app.
+ int owning_uid = is_secondary_dex ? uid : AID_SYSTEM;
+ if (fchmod(fd,
+ S_IRUSR|S_IWUSR|S_IRGRP |
+ (is_public ? S_IROTH : 0)) < 0) {
+ ALOGE("installd cannot chmod '%s' during dexopt\n", path);
+ return false;
+ } else if (fchown(fd, owning_uid, uid) < 0) {
+ ALOGE("installd cannot chown '%s' during dexopt\n", path);
+ return false;
+ }
+ return true;
+}
+
+static bool IsOutputDalvikCache(const char* oat_dir) {
+ // InstallerConnection.java (which invokes installd) transforms Java null arguments
+ // into '!'. Play it safe by handling it both.
+ // TODO: ensure we never get null.
+ // TODO: pass a flag instead of inferring if the output is dalvik cache.
+ return oat_dir == nullptr || oat_dir[0] == '!';
+}
+
+static bool create_oat_out_path(const char* apk_path, const char* instruction_set,
+ const char* oat_dir, bool is_secondary_dex, /*out*/ char* out_oat_path) {
+ // Early best-effort check whether we can fit the the path into our buffers.
+ // Note: the cache path will require an additional 5 bytes for ".swap", but we'll try to run
+ // without a swap file, if necessary. Reference profiles file also add an extra ".prof"
+ // extension to the cache path (5 bytes).
+ if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {
+ ALOGE("apk_path too long '%s'\n", apk_path);
+ return false;
+ }
+
+ if (!IsOutputDalvikCache(oat_dir)) {
+ // Oat dirs for secondary dex files are already validated.
+ if (!is_secondary_dex && validate_apk_path(oat_dir)) {
+ ALOGE("cannot validate apk path with oat_dir '%s'\n", oat_dir);
+ return false;
+ }
+ if (!calculate_oat_file_path(out_oat_path, oat_dir, apk_path, instruction_set)) {
+ return false;
+ }
+ } else {
+ if (!create_cache_path(out_oat_path, apk_path, instruction_set)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// Helper for fd management. This is similar to a unique_fd in that it closes the file descriptor
+// on destruction. It will also run the given cleanup (unless told not to) after closing.
+//
+// Usage example:
+//
+// Dex2oatFileWrapper file(open(...),
+// [name]() {
+// unlink(name.c_str());
+// });
+// // Note: care needs to be taken about name, as it needs to have a lifetime longer than the
+// wrapper if captured as a reference.
+//
+// if (file.get() == -1) {
+// // Error opening...
+// }
+//
+// ...
+// if (error) {
+// // At this point, when the Dex2oatFileWrapper is destructed, the cleanup function will run
+// // and delete the file (after the fd is closed).
+// return -1;
+// }
+//
+// (Success case)
+// file.SetCleanup(false);
+// // At this point, when the Dex2oatFileWrapper is destructed, the cleanup function will not run
+// // (leaving the file around; after the fd is closed).
+//
+class Dex2oatFileWrapper {
+ public:
+ Dex2oatFileWrapper() : value_(-1), cleanup_(), do_cleanup_(true), auto_close_(true) {
+ }
+
+ Dex2oatFileWrapper(int value, std::function<void ()> cleanup)
+ : value_(value), cleanup_(cleanup), do_cleanup_(true), auto_close_(true) {}
+
+ Dex2oatFileWrapper(Dex2oatFileWrapper&& other) {
+ value_ = other.value_;
+ cleanup_ = other.cleanup_;
+ do_cleanup_ = other.do_cleanup_;
+ auto_close_ = other.auto_close_;
+ other.release();
+ }
+
+ Dex2oatFileWrapper& operator=(Dex2oatFileWrapper&& other) {
+ value_ = other.value_;
+ cleanup_ = other.cleanup_;
+ do_cleanup_ = other.do_cleanup_;
+ auto_close_ = other.auto_close_;
+ other.release();
+ return *this;
+ }
+
+ ~Dex2oatFileWrapper() {
+ reset(-1);
+ }
+
+ int get() {
+ return value_;
+ }
+
+ void SetCleanup(bool cleanup) {
+ do_cleanup_ = cleanup;
+ }
+
+ void reset(int new_value) {
+ if (auto_close_ && value_ >= 0) {
+ close(value_);
+ }
+ if (do_cleanup_ && cleanup_ != nullptr) {
+ cleanup_();
+ }
+
+ value_ = new_value;
+ }
+
+ void reset(int new_value, std::function<void ()> new_cleanup) {
+ if (auto_close_ && value_ >= 0) {
+ close(value_);
+ }
+ if (do_cleanup_ && cleanup_ != nullptr) {
+ cleanup_();
+ }
+
+ value_ = new_value;
+ cleanup_ = new_cleanup;
+ }
+
+ void DisableAutoClose() {
+ auto_close_ = false;
+ }
+
+ private:
+ void release() {
+ value_ = -1;
+ do_cleanup_ = false;
+ cleanup_ = nullptr;
+ }
+ int value_;
+ std::function<void ()> cleanup_;
+ bool do_cleanup_;
+ bool auto_close_;
+};
+
+// (re)Creates the app image if needed.
+Dex2oatFileWrapper maybe_open_app_image(const char* out_oat_path, bool profile_guided,
+ bool is_public, int uid, bool is_secondary_dex) {
+ // Use app images only if it is enabled (by a set image format) and we are compiling
+ // profile-guided (so the app image doesn't conservatively contain all classes).
+ // Note that we don't create an image for secondary dex files.
+ if (is_secondary_dex || !profile_guided) {
+ return Dex2oatFileWrapper();
+ }
+
+ const std::string image_path = create_image_filename(out_oat_path);
+ if (image_path.empty()) {
+ // Happens when the out_oat_path has an unknown extension.
+ return Dex2oatFileWrapper();
+ }
+ char app_image_format[kPropertyValueMax];
+ bool have_app_image_format =
+ get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
+ if (!have_app_image_format) {
+ return Dex2oatFileWrapper();
+ }
+ // Recreate is true since we do not want to modify a mapped image. If the app is
+ // already running and we modify the image file, it can cause crashes (b/27493510).
+ Dex2oatFileWrapper wrapper_fd(
+ open_output_file(image_path.c_str(), true /*recreate*/, 0600 /*permissions*/),
+ [image_path]() { unlink(image_path.c_str()); });
+ if (wrapper_fd.get() < 0) {
+ // Could not create application image file. Go on since we can compile without it.
+ LOG(ERROR) << "installd could not create '" << image_path
+ << "' for image file during dexopt";
+ // If we have a valid image file path but no image fd, explicitly erase the image file.
+ if (unlink(image_path.c_str()) < 0) {
+ if (errno != ENOENT) {
+ PLOG(ERROR) << "Couldn't unlink image file " << image_path;
+ }
+ }
+ } else if (!set_permissions_and_ownership(
+ wrapper_fd.get(), is_public, uid, image_path.c_str(), is_secondary_dex)) {
+ ALOGE("installd cannot set owner '%s' for image during dexopt\n", image_path.c_str());
+ wrapper_fd.reset(-1);
+ }
+
+ return wrapper_fd;
+}
+
+// Creates the dexopt swap file if necessary and return its fd.
+// Returns -1 if there's no need for a swap or in case of errors.
+unique_fd maybe_open_dexopt_swap_file(const char* out_oat_path) {
+ if (!ShouldUseSwapFileForDexopt()) {
+ return invalid_unique_fd();
+ }
+ // Make sure there really is enough space.
+ char swap_file_name[PKG_PATH_MAX];
+ strcpy(swap_file_name, out_oat_path);
+ if (!add_extension_to_file_name(swap_file_name, ".swap")) {
+ return invalid_unique_fd();
+ }
+ unique_fd swap_fd(open_output_file(
+ swap_file_name, /*recreate*/true, /*permissions*/0600));
+ if (swap_fd.get() < 0) {
+ // Could not create swap file. Optimistically go on and hope that we can compile
+ // without it.
+ ALOGE("installd could not create '%s' for swap during dexopt\n", swap_file_name);
+ } else {
+ // Immediately unlink. We don't really want to hit flash.
+ if (unlink(swap_file_name) < 0) {
+ PLOG(ERROR) << "Couldn't unlink swap file " << swap_file_name;
+ }
+ }
+ return swap_fd;
+}
+
+// Opens the reference profiles if needed.
+// Note that the reference profile might not exist so it's OK if the fd will be -1.
+Dex2oatFileWrapper maybe_open_reference_profile(const std::string& pkgname,
+ const std::string& dex_path, bool profile_guided, bool is_public, int uid,
+ bool is_secondary_dex) {
+ // Public apps should not be compiled with profile information ever. Same goes for the special
+ // package '*' used for the system server.
+ if (!profile_guided || is_public || (pkgname[0] == '*')) {
+ return Dex2oatFileWrapper();
+ }
+
+ // Open reference profile in read only mode as dex2oat does not get write permissions.
+ const std::string location = is_secondary_dex ? dex_path : pkgname;
+ unique_fd ufd = open_reference_profile(uid, location, /*read_write*/false, is_secondary_dex);
+ const auto& cleanup = [location, is_secondary_dex]() {
+ clear_reference_profile(location.c_str(), is_secondary_dex);
+ };
+ return Dex2oatFileWrapper(ufd.release(), cleanup);
+}
+
+// Opens the vdex files and assigns the input fd to in_vdex_wrapper_fd and the output fd to
+// out_vdex_wrapper_fd. Returns true for success or false in case of errors.
+bool open_vdex_files(const char* apk_path, const char* out_oat_path, int dexopt_needed,
+ const char* instruction_set, bool is_public, int uid, bool is_secondary_dex,
+ Dex2oatFileWrapper* in_vdex_wrapper_fd,
+ Dex2oatFileWrapper* out_vdex_wrapper_fd) {
+ CHECK(in_vdex_wrapper_fd != nullptr);
+ CHECK(out_vdex_wrapper_fd != nullptr);
+ // Open the existing VDEX. We do this before creating the new output VDEX, which will
+ // unlink the old one.
+ char in_odex_path[PKG_PATH_MAX];
+ int dexopt_action = abs(dexopt_needed);
+ bool is_odex_location = dexopt_needed < 0;
+ std::string in_vdex_path_str;
+ if (dexopt_action != DEX2OAT_FROM_SCRATCH) {
+ // Open the possibly existing vdex. If none exist, we pass -1 to dex2oat for input-vdex-fd.
+ const char* path = nullptr;
+ if (is_odex_location) {
+ if (calculate_odex_file_path(in_odex_path, apk_path, instruction_set)) {
+ path = in_odex_path;
+ } else {
+ ALOGE("installd cannot compute input vdex location for '%s'\n", apk_path);
+ return false;
+ }
+ } else {
+ path = out_oat_path;
+ }
+ in_vdex_path_str = create_vdex_filename(path);
+ if (in_vdex_path_str.empty()) {
+ ALOGE("installd cannot compute input vdex location for '%s'\n", path);
+ return false;
+ }
+ if (dexopt_action == DEX2OAT_FOR_BOOT_IMAGE) {
+ // When we dex2oat because of boot image change, we are going to update
+ // in-place the vdex file.
+ in_vdex_wrapper_fd->reset(open(in_vdex_path_str.c_str(), O_RDWR, 0));
+ } else {
+ in_vdex_wrapper_fd->reset(open(in_vdex_path_str.c_str(), O_RDONLY, 0));
+ }
+ }
+
+ // Infer the name of the output VDEX and create it.
+ const std::string out_vdex_path_str = create_vdex_filename(out_oat_path);
+ if (out_vdex_path_str.empty()) {
+ return false;
+ }
+
+ // If we are compiling because the boot image is out of date, we do not
+ // need to recreate a vdex, and can use the same existing one.
+ if (dexopt_action == DEX2OAT_FOR_BOOT_IMAGE &&
+ in_vdex_wrapper_fd->get() != -1 &&
+ in_vdex_path_str == out_vdex_path_str) {
+ // We unlink the file in case the invocation of dex2oat fails, to ensure we don't
+ // have bogus stale vdex files.
+ out_vdex_wrapper_fd->reset(
+ in_vdex_wrapper_fd->get(),
+ [out_vdex_path_str]() { unlink(out_vdex_path_str.c_str()); });
+ // Disable auto close for the in wrapper fd (it will be done when destructing the out
+ // wrapper).
+ in_vdex_wrapper_fd->DisableAutoClose();
+ } else {
+ out_vdex_wrapper_fd->reset(
+ open_output_file(out_vdex_path_str.c_str(), /*recreate*/true, /*permissions*/0644),
+ [out_vdex_path_str]() { unlink(out_vdex_path_str.c_str()); });
+ if (out_vdex_wrapper_fd->get() < 0) {
+ ALOGE("installd cannot open vdex'%s' during dexopt\n", out_vdex_path_str.c_str());
+ return false;
+ }
+ }
+ if (!set_permissions_and_ownership(out_vdex_wrapper_fd->get(), is_public, uid,
+ out_vdex_path_str.c_str(), is_secondary_dex)) {
+ ALOGE("installd cannot set owner '%s' for vdex during dexopt\n", out_vdex_path_str.c_str());
+ return false;
+ }
+
+ // If we got here we successfully opened the vdex files.
+ return true;
+}
+
+// Opens the output oat file for the given apk.
+// If successful it stores the output path into out_oat_path and returns true.
+Dex2oatFileWrapper open_oat_out_file(const char* apk_path, const char* oat_dir,
+ bool is_public, int uid, const char* instruction_set, bool is_secondary_dex,
+ char* out_oat_path) {
+ if (!create_oat_out_path(apk_path, instruction_set, oat_dir, is_secondary_dex, out_oat_path)) {
+ return Dex2oatFileWrapper();
+ }
+ const std::string out_oat_path_str(out_oat_path);
+ Dex2oatFileWrapper wrapper_fd(
+ open_output_file(out_oat_path, /*recreate*/true, /*permissions*/0644),
+ [out_oat_path_str]() { unlink(out_oat_path_str.c_str()); });
+ if (wrapper_fd.get() < 0) {
+ PLOG(ERROR) << "installd cannot open output during dexopt" << out_oat_path;
+ } else if (!set_permissions_and_ownership(
+ wrapper_fd.get(), is_public, uid, out_oat_path, is_secondary_dex)) {
+ ALOGE("installd cannot set owner '%s' for output during dexopt\n", out_oat_path);
+ wrapper_fd.reset(-1);
+ }
+ return wrapper_fd;
+}
+
+// Updates the access times of out_oat_path based on those from apk_path.
+void update_out_oat_access_times(const char* apk_path, const char* out_oat_path) {
+ struct stat input_stat;
+ memset(&input_stat, 0, sizeof(input_stat));
+ if (stat(apk_path, &input_stat) != 0) {
+ PLOG(ERROR) << "Could not stat " << apk_path << " during dexopt";
+ return;
+ }
+
+ struct utimbuf ut;
+ ut.actime = input_stat.st_atime;
+ ut.modtime = input_stat.st_mtime;
+ if (utime(out_oat_path, &ut) != 0) {
+ PLOG(WARNING) << "Could not update access times for " << apk_path << " during dexopt";
+ }
+}
+
+// Runs (execv) dexoptanalyzer on the given arguments.
+// The analyzer will check if the dex_file needs to be (re)compiled to match the compiler_filter.
+// If this is for a profile guided compilation, profile_was_updated will tell whether or not
+// the profile has changed.
+static void exec_dexoptanalyzer(const std::string& dex_file, const char* instruction_set,
+ const char* compiler_filter, bool profile_was_updated) {
+ static const char* DEXOPTANALYZER_BIN = "/system/bin/dexoptanalyzer";
+ static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
+
+ if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
+ ALOGE("Instruction set %s longer than max length of %d",
+ instruction_set, MAX_INSTRUCTION_SET_LEN);
+ return;
+ }
+
+ char dex_file_arg[strlen("--dex-file=") + PKG_PATH_MAX];
+ char isa_arg[strlen("--isa=") + MAX_INSTRUCTION_SET_LEN];
+ char compiler_filter_arg[strlen("--compiler-filter=") + kPropertyValueMax];
+ const char* assume_profile_changed = "--assume-profile-changed";
+
+ sprintf(dex_file_arg, "--dex-file=%s", dex_file.c_str());
+ sprintf(isa_arg, "--isa=%s", instruction_set);
+ sprintf(compiler_filter_arg, "--compiler-filter=%s", compiler_filter);
+
+ // program name, dex file, isa, filter, the final NULL
+ const char* argv[5 + (profile_was_updated ? 1 : 0)];
+ int i = 0;
+ argv[i++] = DEXOPTANALYZER_BIN;
+ argv[i++] = dex_file_arg;
+ argv[i++] = isa_arg;
+ argv[i++] = compiler_filter_arg;
+ if (profile_was_updated) {
+ argv[i++] = assume_profile_changed;
+ }
+ argv[i] = NULL;
+
+ execv(DEXOPTANALYZER_BIN, (char * const *)argv);
+ ALOGE("execv(%s) failed: %s\n", DEXOPTANALYZER_BIN, strerror(errno));
+}
+
+// Prepares the oat dir for the secondary dex files.
+static bool prepare_secondary_dex_oat_dir(const std::string& dex_path, int uid,
+ const char* instruction_set, std::string* oat_dir_out) {
+ unsigned long dirIndex = dex_path.rfind('/');
+ if (dirIndex == std::string::npos) {
+ LOG(ERROR ) << "Unexpected dir structure for secondary dex " << dex_path;
+ return false;
+ }
+ std::string dex_dir = dex_path.substr(0, dirIndex);
+
+ // Assign the gid to the cache gid so that the oat file storage
+ // is counted towards the app cache.
+ int32_t cache_gid = multiuser_get_cache_gid(
+ multiuser_get_user_id(uid), multiuser_get_app_id(uid));
+ // If UID doesn't have a specific cache GID, use UID value
+ if (cache_gid == -1) {
+ cache_gid = uid;
+ }
+
+ // Create oat file output directory.
+ if (prepare_app_cache_dir(dex_dir, "oat", 02711, uid, cache_gid) != 0) {
+ LOG(ERROR) << "Could not prepare oat dir for secondary dex: " << dex_path;
+ return false;
+ }
+
+ char oat_dir[PKG_PATH_MAX];
+ snprintf(oat_dir, PKG_PATH_MAX, "%s/oat", dex_dir.c_str());
+ oat_dir_out->assign(oat_dir);
+
+ // Create oat/isa output directory.
+ if (prepare_app_cache_dir(*oat_dir_out, instruction_set, 02711, uid, cache_gid) != 0) {
+ LOG(ERROR) << "Could not prepare oat/isa dir for secondary dex: " << dex_path;
+ return false;
+ }
+
+ return true;
+}
+
+static int constexpr DEXOPTANALYZER_BIN_EXEC_ERROR = 200;
+
+// Verifies the result of dexoptanalyzer executed for the apk_path.
+// If the result is valid returns true and sets dexopt_needed_out to a valid value.
+// Returns false for errors or unexpected result values.
+static bool process_dexoptanalyzer_result(const std::string& dex_path, int result,
+ int* dexopt_needed_out) {
+ // The result values are defined in dexoptanalyzer.
+ switch (result) {
+ case 0: // no_dexopt_needed
+ *dexopt_needed_out = NO_DEXOPT_NEEDED; return true;
+ case 1: // dex2oat_from_scratch
+ *dexopt_needed_out = DEX2OAT_FROM_SCRATCH; return true;
+ case 5: // dex2oat_for_bootimage_odex
+ *dexopt_needed_out = -DEX2OAT_FOR_BOOT_IMAGE; return true;
+ case 6: // dex2oat_for_filter_odex
+ *dexopt_needed_out = -DEX2OAT_FOR_FILTER; return true;
+ case 7: // dex2oat_for_relocation_odex
+ *dexopt_needed_out = -DEX2OAT_FOR_RELOCATION; return true;
+ case 2: // dex2oat_for_bootimage_oat
+ case 3: // dex2oat_for_filter_oat
+ case 4: // dex2oat_for_relocation_oat
+ LOG(ERROR) << "Dexoptnalyzer return the status of an oat file."
+ << " Expected odex file status for secondary dex " << dex_path
+ << " : dexoptanalyzer result=" << result;
+ return false;
+ default:
+ LOG(ERROR) << "Unexpected result for dexoptanalyzer " << dex_path
+ << " exec_dexoptanalyzer result=" << result;
+ return false;
+ }
+}
+
+// Processes the dex_path as a secondary dex files and return true if the path dex file should
+// be compiled. Returns false for errors (logged) or true if the secondary dex path was process
+// successfully.
+// When returning true, dexopt_needed_out is assigned a valid OatFileAsssitant::DexOptNeeded
+// code and oat_dir_out is assigned the oat dir path where the oat file should be stored.
+static bool process_secondary_dex_dexopt(const char* original_dex_path, const char* pkgname,
+ int dexopt_flags, const char* volume_uuid, int uid, const char* instruction_set,
+ const char* compiler_filter, int* dexopt_needed_out, std::string* oat_dir_out,
+ std::string* dex_path_out) {
+ int storage_flag;
+
+ if ((dexopt_flags & DEXOPT_STORAGE_CE) != 0) {
+ storage_flag = FLAG_STORAGE_CE;
+ if ((dexopt_flags & DEXOPT_STORAGE_DE) != 0) {
+ LOG(ERROR) << "Ambiguous secondary dex storage flag. Both, CE and DE, flags are set";
+ return false;
+ }
+ } else if ((dexopt_flags & DEXOPT_STORAGE_DE) != 0) {
+ storage_flag = FLAG_STORAGE_DE;
+ } else {
+ LOG(ERROR) << "Secondary dex storage flag must be set";
+ return false;
+ }
+
+ {
+ // As opposed to the primary apk, secondary dex files might contain symlinks.
+ // Resolve the path before passing it to the validate method to
+ // make sure the verification is done on the real location.
+ UniqueCPtr<char> dex_real_path_cstr(realpath(original_dex_path, nullptr));
+ if (dex_real_path_cstr == nullptr) {
+ PLOG(ERROR) << "Could not get the real path of the secondary dex file "
+ << original_dex_path;
+ return false;
+ } else {
+ dex_path_out->assign(dex_real_path_cstr.get());
+ }
+ }
+ const std::string& dex_path = *dex_path_out;
+ if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid, uid, storage_flag)) {
+ LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
+ return false;
+ }
+
+ // Check if the path exist. If not, there's nothing to do.
+ if (access(dex_path.c_str(), F_OK) != 0) {
+ if (errno == ENOENT) {
+ // Secondary dex files might be deleted any time by the app.
+ // Nothing to do if that's the case
+ ALOGV("Secondary dex does not exist %s", dex_path.c_str());
+ return NO_DEXOPT_NEEDED;
+ } else {
+ PLOG(ERROR) << "Could not access secondary dex " << dex_path;
+ }
+ }
+
+ // Prepare the oat directories.
+ if (!prepare_secondary_dex_oat_dir(dex_path, uid, instruction_set, oat_dir_out)) {
+ return false;
+ }
+
+ // Analyze profiles.
+ bool profile_was_updated = analyze_profiles(uid, dex_path, /*is_secondary_dex*/true);
+
+ pid_t pid = fork();
+ if (pid == 0) {
+ // child -- drop privileges before continuing.
+ drop_capabilities(uid);
+ // Run dexoptanalyzer to get dexopt_needed code.
+ exec_dexoptanalyzer(dex_path, instruction_set, compiler_filter, profile_was_updated);
+ exit(DEXOPTANALYZER_BIN_EXEC_ERROR);
+ }
+
+ /* parent */
+
+ int result = wait_child(pid);
+ if (!WIFEXITED(result)) {
+ LOG(ERROR) << "dexoptanalyzer failed for path " << dex_path << ": " << result;
+ return false;
+ }
+ result = WEXITSTATUS(result);
+ bool success = process_dexoptanalyzer_result(dex_path, result, dexopt_needed_out);
+ // Run dexopt only if needed or forced.
+ // Note that dexoptanalyzer is executed even if force compilation is enabled.
+ // We ignore its valid dexopNeeded result, but still check (in process_dexoptanalyzer_result)
+ // that we only get results for odex files (apk_dir/oat/isa/code.odex) and not
+ // for oat files from dalvik-cache.
+ if (success && ((dexopt_flags & DEXOPT_FORCE) != 0)) {
+ *dexopt_needed_out = DEX2OAT_FROM_SCRATCH;
+ }
+
+ return success;
+}
+
+int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* instruction_set,
+ int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
+ const char* volume_uuid, const char* shared_libraries) {
+ CHECK(pkgname != nullptr);
+ CHECK(pkgname[0] != 0);
+ if ((dexopt_flags & ~DEXOPT_MASK) != 0) {
+ LOG_FATAL("dexopt flags contains unknown fields\n");
+ }
+
+ bool is_public = ((dexopt_flags & DEXOPT_PUBLIC) != 0);
+ bool debuggable = (dexopt_flags & DEXOPT_DEBUGGABLE) != 0;
+ bool boot_complete = (dexopt_flags & DEXOPT_BOOTCOMPLETE) != 0;
+ bool profile_guided = (dexopt_flags & DEXOPT_PROFILE_GUIDED) != 0;
+ bool is_secondary_dex = (dexopt_flags & DEXOPT_SECONDARY_DEX) != 0;
+
+ // Check if we're dealing with a secondary dex file and if we need to compile it.
+ std::string oat_dir_str;
+ std::string dex_real_path;
+ if (is_secondary_dex) {
+ if (process_secondary_dex_dexopt(dex_path, pkgname, dexopt_flags, volume_uuid, uid,
+ instruction_set, compiler_filter, &dexopt_needed, &oat_dir_str, &dex_real_path)) {
+ oat_dir = oat_dir_str.c_str();
+ dex_path = dex_real_path.c_str();
+ if (dexopt_needed == NO_DEXOPT_NEEDED) {
+ return 0; // Nothing to do, report success.
+ }
+ } else {
+ return -1; // We had an error, logged in the process method.
+ }
+ } else {
+ // Currently these flags are only use for secondary dex files.
+ // Verify that they are not set for primary apks.
+ CHECK((dexopt_flags & DEXOPT_STORAGE_CE) == 0);
+ CHECK((dexopt_flags & DEXOPT_STORAGE_DE) == 0);
+ }
+
+ // Open the input file.
+ unique_fd input_fd(open(dex_path, O_RDONLY, 0));
+ if (input_fd.get() < 0) {
+ ALOGE("installd cannot open '%s' for input during dexopt\n", dex_path);
+ return -1;
+ }
+
+ // Create the output OAT file.
+ char out_oat_path[PKG_PATH_MAX];
+ Dex2oatFileWrapper out_oat_fd = open_oat_out_file(dex_path, oat_dir, is_public, uid,
+ instruction_set, is_secondary_dex, out_oat_path);
+ if (out_oat_fd.get() < 0) {
+ return -1;
+ }
+
+ // Open vdex files.
+ Dex2oatFileWrapper in_vdex_fd;
+ Dex2oatFileWrapper out_vdex_fd;
+ if (!open_vdex_files(dex_path, out_oat_path, dexopt_needed, instruction_set, is_public, uid,
+ is_secondary_dex, &in_vdex_fd, &out_vdex_fd)) {
+ return -1;
+ }
+
+ // Create a swap file if necessary.
+ unique_fd swap_fd = maybe_open_dexopt_swap_file(out_oat_path);
+
+ // Create the app image file if needed.
+ Dex2oatFileWrapper image_fd =
+ maybe_open_app_image(out_oat_path, profile_guided, is_public, uid, is_secondary_dex);
+
+ // Open the reference profile if needed.
+ Dex2oatFileWrapper reference_profile_fd = maybe_open_reference_profile(
+ pkgname, dex_path, profile_guided, is_public, uid, is_secondary_dex);
+
+ ALOGV("DexInv: --- BEGIN '%s' ---\n", dex_path);
+
+ pid_t pid = fork();
+ if (pid == 0) {
+ /* child -- drop privileges before continuing */
+ drop_capabilities(uid);
+
+ SetDex2OatScheduling(boot_complete);
+ if (flock(out_oat_fd.get(), LOCK_EX | LOCK_NB) != 0) {
+ ALOGE("flock(%s) failed: %s\n", out_oat_path, strerror(errno));
+ _exit(67);
+ }
+
+ run_dex2oat(input_fd.get(),
+ out_oat_fd.get(),
+ in_vdex_fd.get(),
+ out_vdex_fd.get(),
+ image_fd.get(),
+ dex_path,
+ out_oat_path,
+ swap_fd.get(),
+ instruction_set,
+ compiler_filter,
+ debuggable,
+ boot_complete,
+ reference_profile_fd.get(),
+ shared_libraries);
+ _exit(68); /* only get here on exec failure */
+ } else {
+ int res = wait_child(pid);
+ if (res == 0) {
+ ALOGV("DexInv: --- END '%s' (success) ---\n", dex_path);
+ } else {
+ ALOGE("DexInv: --- END '%s' --- status=0x%04x, process failed\n", dex_path, res);
+ return res;
+ }
+ }
+
+ update_out_oat_access_times(dex_path, out_oat_path);
+
+ // We've been successful, don't delete output.
+ out_oat_fd.SetCleanup(false);
+ out_vdex_fd.SetCleanup(false);
+ image_fd.SetCleanup(false);
+ reference_profile_fd.SetCleanup(false);
+
+ return 0;
+}
+
+// Try to remove the given directory. Log an error if the directory exists
+// and is empty but could not be removed.
+static bool rmdir_if_empty(const char* dir) {
+ if (rmdir(dir) == 0) {
+ return true;
+ }
+ if (errno == ENOENT || errno == ENOTEMPTY) {
+ return true;
+ }
+ PLOG(ERROR) << "Failed to remove dir: " << dir;
+ return false;
+}
+
+// Try to unlink the given file. Log an error if the file exists and could not
+// be unlinked.
+static bool unlink_if_exists(const std::string& file) {
+ if (unlink(file.c_str()) == 0) {
+ return true;
+ }
+ if (errno == ENOENT) {
+ return true;
+
+ }
+ PLOG(ERROR) << "Could not unlink: " << file;
+ return false;
+}
+
+// Create the oat file structure for the secondary dex 'dex_path' and assign
+// the individual path component to the 'out_' parameters.
+static bool create_secondary_dex_oat_layout(const std::string& dex_path, const std::string& isa,
+ /*out*/char* out_oat_dir, /*out*/char* out_oat_isa_dir, /*out*/char* out_oat_path) {
+ size_t dirIndex = dex_path.rfind('/');
+ if (dirIndex == std::string::npos) {
+ LOG(ERROR) << "Unexpected dir structure for dex file " << dex_path;
+ return false;
+ }
+ // TODO(calin): we have similar computations in at lest 3 other places
+ // (InstalldNativeService, otapropt and dexopt). Unify them and get rid of snprintf by
+ // use string append.
+ std::string apk_dir = dex_path.substr(0, dirIndex);
+ snprintf(out_oat_dir, PKG_PATH_MAX, "%s/oat", apk_dir.c_str());
+ snprintf(out_oat_isa_dir, PKG_PATH_MAX, "%s/%s", out_oat_dir, isa.c_str());
+
+ if (!create_oat_out_path(dex_path.c_str(), isa.c_str(), out_oat_dir,
+ /*is_secondary_dex*/true, out_oat_path)) {
+ LOG(ERROR) << "Could not create oat path for secondary dex " << dex_path;
+ return false;
+ }
+ return true;
+}
+
+// Reconcile the secondary dex 'dex_path' and its generated oat files.
+// Return true if all the parameters are valid and the secondary dex file was
+// processed successfully (i.e. the dex_path either exists, or if not, its corresponding
+// oat/vdex/art files where deleted successfully). In this case, out_secondary_dex_exists
+// will be true if the secondary dex file still exists. If the secondary dex file does not exist,
+// the method cleans up any previously generated compiler artifacts (oat, vdex, art).
+// Return false if there were errors during processing. In this case
+// out_secondary_dex_exists will be set to false.
+bool reconcile_secondary_dex_file(const std::string& dex_path,
+ const std::string& pkgname, int uid, const std::vector<std::string>& isas,
+ const std::unique_ptr<std::string>& volume_uuid, int storage_flag,
+ /*out*/bool* out_secondary_dex_exists) {
+ // Set out to false to start with, just in case we have validation errors.
+ *out_secondary_dex_exists = false;
+ if (isas.size() == 0) {
+ LOG(ERROR) << "reconcile_secondary_dex_file called with empty isas vector";
+ return false;
+ }
+
+ const char* volume_uuid_cstr = volume_uuid == nullptr ? nullptr : volume_uuid->c_str();
+ if (!validate_secondary_dex_path(pkgname.c_str(), dex_path.c_str(), volume_uuid_cstr,
+ uid, storage_flag)) {
+ LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
+ return false;
+ }
+
+ if (access(dex_path.c_str(), F_OK) == 0) {
+ // The path exists, nothing to do. The odex files (if any) will be left untouched.
+ *out_secondary_dex_exists = true;
+ return true;
+ } else if (errno != ENOENT) {
+ PLOG(ERROR) << "Failed to check access to secondary dex " << dex_path;
+ return false;
+ }
+
+ // The secondary dex does not exist anymore. Clear any generated files.
+ char oat_path[PKG_PATH_MAX];
+ char oat_dir[PKG_PATH_MAX];
+ char oat_isa_dir[PKG_PATH_MAX];
+ bool result = true;
+ for (size_t i = 0; i < isas.size(); i++) {
+ if (!create_secondary_dex_oat_layout(dex_path, isas[i], oat_dir, oat_isa_dir, oat_path)) {
+ LOG(ERROR) << "Could not create secondary odex layout: " << dex_path;
+ result = false;
+ continue;
+ }
+ result = unlink_if_exists(oat_path) && result;
+ result = unlink_if_exists(create_vdex_filename(oat_path)) && result;
+ result = unlink_if_exists(create_image_filename(oat_path)) && result;
+
+ // Try removing the directories as well, they might be empty.
+ result = rmdir_if_empty(oat_isa_dir) && result;
+ result = rmdir_if_empty(oat_dir) && result;
+ }
+
+ return result;
+}
+
+// Helper for move_ab, so that we can have common failure-case cleanup.
+static bool unlink_and_rename(const char* from, const char* to) {
+ // Check whether "from" exists, and if so whether it's regular. If it is, unlink. Otherwise,
+ // return a failure.
+ struct stat s;
+ if (stat(to, &s) == 0) {
+ if (!S_ISREG(s.st_mode)) {
+ LOG(ERROR) << from << " is not a regular file to replace for A/B.";
+ return false;
+ }
+ if (unlink(to) != 0) {
+ LOG(ERROR) << "Could not unlink " << to << " to move A/B.";
+ return false;
+ }
+ } else {
+ // This may be a permission problem. We could investigate the error code, but we'll just
+ // let the rename failure do the work for us.
+ }
+
+ // Try to rename "to" to "from."
+ if (rename(from, to) != 0) {
+ PLOG(ERROR) << "Could not rename " << from << " to " << to;
+ return false;
+ }
+ return true;
+}
+
+// Move/rename a B artifact (from) to an A artifact (to).
+static bool move_ab_path(const std::string& b_path, const std::string& a_path) {
+ // Check whether B exists.
+ {
+ struct stat s;
+ if (stat(b_path.c_str(), &s) != 0) {
+ // Silently ignore for now. The service calling this isn't smart enough to understand
+ // lack of artifacts at the moment.
+ return false;
+ }
+ if (!S_ISREG(s.st_mode)) {
+ LOG(ERROR) << "A/B artifact " << b_path << " is not a regular file.";
+ // Try to unlink, but swallow errors.
+ unlink(b_path.c_str());
+ return false;
+ }
+ }
+
+ // Rename B to A.
+ if (!unlink_and_rename(b_path.c_str(), a_path.c_str())) {
+ // Delete the b_path so we don't try again (or fail earlier).
+ if (unlink(b_path.c_str()) != 0) {
+ PLOG(ERROR) << "Could not unlink " << b_path;
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+bool move_ab(const char* apk_path, const char* instruction_set, const char* oat_dir) {
+ // Get the current slot suffix. No suffix, no A/B.
+ std::string slot_suffix;
+ {
+ char buf[kPropertyValueMax];
+ if (get_property("ro.boot.slot_suffix", buf, nullptr) <= 0) {
+ return false;
+ }
+ slot_suffix = buf;
+
+ if (!ValidateTargetSlotSuffix(slot_suffix)) {
+ LOG(ERROR) << "Target slot suffix not legal: " << slot_suffix;
+ return false;
+ }
+ }
+
+ // Validate other inputs.
+ if (validate_apk_path(apk_path) != 0) {
+ LOG(ERROR) << "Invalid apk_path: " << apk_path;
+ return false;
+ }
+ if (validate_apk_path(oat_dir) != 0) {
+ LOG(ERROR) << "Invalid oat_dir: " << oat_dir;
+ return false;
+ }
+
+ char a_path[PKG_PATH_MAX];
+ if (!calculate_oat_file_path(a_path, oat_dir, apk_path, instruction_set)) {
+ return false;
+ }
+ const std::string a_vdex_path = create_vdex_filename(a_path);
+ const std::string a_image_path = create_image_filename(a_path);
+
+ // B path = A path + slot suffix.
+ const std::string b_path = StringPrintf("%s.%s", a_path, slot_suffix.c_str());
+ const std::string b_vdex_path = StringPrintf("%s.%s", a_vdex_path.c_str(), slot_suffix.c_str());
+ const std::string b_image_path = StringPrintf("%s.%s",
+ a_image_path.c_str(),
+ slot_suffix.c_str());
+
+ bool success = true;
+ if (move_ab_path(b_path, a_path)) {
+ if (move_ab_path(b_vdex_path, a_vdex_path)) {
+ // Note: we can live without an app image. As such, ignore failure to move the image file.
+ // If we decide to require the app image, or the app image being moved correctly,
+ // then change accordingly.
+ constexpr bool kIgnoreAppImageFailure = true;
+
+ if (!a_image_path.empty()) {
+ if (!move_ab_path(b_image_path, a_image_path)) {
+ unlink(a_image_path.c_str());
+ if (!kIgnoreAppImageFailure) {
+ success = false;
+ }
+ }
+ }
+ } else {
+ // Cleanup: delete B image, ignore errors.
+ unlink(b_image_path.c_str());
+ success = false;
+ }
+ } else {
+ // Cleanup: delete B image, ignore errors.
+ unlink(b_vdex_path.c_str());
+ unlink(b_image_path.c_str());
+ success = false;
+ }
+ return success;
+}
+
+bool delete_odex(const char* apk_path, const char* instruction_set, const char* oat_dir) {
+ // Delete the oat/odex file.
+ char out_path[PKG_PATH_MAX];
+ if (!create_oat_out_path(apk_path, instruction_set, oat_dir,
+ /*is_secondary_dex*/false, out_path)) {
+ return false;
+ }
+
+ // In case of a permission failure report the issue. Otherwise just print a warning.
+ auto unlink_and_check = [](const char* path) -> bool {
+ int result = unlink(path);
+ if (result != 0) {
+ if (errno == EACCES || errno == EPERM) {
+ PLOG(ERROR) << "Could not unlink " << path;
+ return false;
+ }
+ PLOG(WARNING) << "Could not unlink " << path;
+ }
+ return true;
+ };
+
+ // Delete the oat/odex file.
+ bool return_value_oat = unlink_and_check(out_path);
+
+ // Derive and delete the app image.
+ bool return_value_art = unlink_and_check(create_image_filename(out_path).c_str());
+
+ // Report success.
+ return return_value_oat && return_value_art;
+}
+
+int dexopt(const char* const params[DEXOPT_PARAM_COUNT]) {
+ return dexopt(params[0], // apk_path
+ atoi(params[1]), // uid
+ params[2], // pkgname
+ params[3], // instruction_set
+ atoi(params[4]), // dexopt_needed
+ params[5], // oat_dir
+ atoi(params[6]), // dexopt_flags
+ params[7], // compiler_filter
+ parse_null(params[8]), // volume_uuid
+ parse_null(params[9])); // shared_libraries
+ static_assert(DEXOPT_PARAM_COUNT == 10U, "Unexpected dexopt param count");
+}
+
+} // namespace installd
+} // namespace android
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
new file mode 100644
index 0000000..f144be8
--- /dev/null
+++ b/cmds/installd/dexopt.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DEXOPT_H_
+#define DEXOPT_H_
+
+#include <sys/types.h>
+
+#include <cutils/multiuser.h>
+
+namespace android {
+namespace installd {
+
+/* dexopt needed flags matching those in dalvik.system.DexFile */
+static constexpr int NO_DEXOPT_NEEDED = 0;
+static constexpr int DEX2OAT_FROM_SCRATCH = 1;
+static constexpr int DEX2OAT_FOR_BOOT_IMAGE = 2;
+static constexpr int DEX2OAT_FOR_FILTER = 3;
+static constexpr int DEX2OAT_FOR_RELOCATION = 4;
+
+// Clear the reference profile for the primary apk of the given package.
+bool clear_primary_reference_profile(const std::string& pkgname);
+// Clear the current profile for the primary apk of the given package and user.
+bool clear_primary_current_profile(const std::string& pkgname, userid_t user);
+// Clear all current profile for the primary apk of the given package.
+bool clear_primary_current_profiles(const std::string& pkgname);
+
+bool move_ab(const char* apk_path, const char* instruction_set, const char* output_path);
+
+// Decide if profile guided compilation is needed or not based on existing profiles.
+// The analysis is done for the primary apks (base + splits) of the given package.
+// Returns true if there is enough information in the current profiles that makes it
+// worth to recompile the package.
+// If the return value is true all the current profiles would have been merged into
+// the reference profiles accessible with open_reference_profile().
+bool analyze_primary_profiles(uid_t uid, const std::string& pkgname);
+
+bool dump_profiles(int32_t uid, const std::string& pkgname, const char* code_paths);
+
+bool delete_odex(const char* apk_path, const char* instruction_set, const char* output_path);
+
+bool reconcile_secondary_dex_file(const std::string& dex_path,
+ const std::string& pkgname, int uid, const std::vector<std::string>& isas,
+ const std::unique_ptr<std::string>& volumeUuid, int storage_flag,
+ /*out*/bool* out_secondary_dex_exists);
+
+int dexopt(const char *apk_path, uid_t uid, const char *pkgName, const char *instruction_set,
+ int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
+ const char* volume_uuid, const char* shared_libraries);
+
+static constexpr size_t DEXOPT_PARAM_COUNT = 10U;
+static_assert(DEXOPT_PARAM_COUNT == 10U, "Unexpected dexopt param size");
+
+// Helper for the above, converting arguments.
+int dexopt(const char* const params[DEXOPT_PARAM_COUNT]);
+
+} // namespace installd
+} // namespace android
+
+#endif // DEXOPT_H_
diff --git a/cmds/installd/globals.cpp b/cmds/installd/globals.cpp
index 93e1ce5..edcdb6a 100644
--- a/cmds/installd/globals.cpp
+++ b/cmds/installd/globals.cpp
@@ -14,19 +14,17 @@
** limitations under the License.
*/
+#define LOG_TAG "installd"
+
#include <stdlib.h>
#include <string.h>
-#include <cutils/log.h> // TODO: Move everything to base::logging.
+#include <log/log.h> // TODO: Move everything to base::logging.
#include <globals.h>
#include <installd_constants.h>
#include <utils.h>
-#ifndef LOG_TAG
-#define LOG_TAG "installd"
-#endif
-
namespace android {
namespace installd {
diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp
index 8f883db..35936a2 100644
--- a/cmds/installd/installd.cpp
+++ b/cmds/installd/installd.cpp
@@ -13,6 +13,7 @@
** See the License for the specific language governing permissions and
** limitations under the License.
*/
+#define LOG_TAG "installd"
#include <fcntl.h>
#include <selinux/android.h>
@@ -20,30 +21,19 @@
#include <sys/capability.h>
#include <sys/fsuid.h>
#include <sys/prctl.h>
-#include <sys/socket.h>
#include <sys/stat.h>
#include <android-base/logging.h>
#include <cutils/fs.h>
-#include <cutils/log.h> // TODO: Move everything to base::logging.
#include <cutils/properties.h>
-#include <cutils/sockets.h>
+#include <log/log.h> // TODO: Move everything to base::logging.
#include <private/android_filesystem_config.h>
-#include <commands.h>
-#include <globals.h>
-#include <installd_constants.h>
-#include <installd_deps.h> // Need to fill in requirements of commands.
-#include <utils.h>
-
-#ifndef LOG_TAG
-#define LOG_TAG "installd"
-#endif
-#define SOCKET_PATH "installd"
-
-#define BUFFER_MAX 1024 /* input buffer for commands */
-#define TOKEN_MAX 16 /* max number of arguments in buffer */
-#define REPLY_MAX 256 /* largest reply allowed */
+#include "InstalldNativeService.h"
+#include "globals.h"
+#include "installd_constants.h"
+#include "installd_deps.h" // Need to fill in requirements of commands.
+#include "utils.h"
namespace android {
namespace installd {
@@ -65,17 +55,17 @@
const char *oat_dir,
const char *apk_path,
const char *instruction_set) {
- char *file_name_start;
- char *file_name_end;
+ const char *file_name_start;
+ const char *file_name_end;
file_name_start = strrchr(apk_path, '/');
if (file_name_start == NULL) {
- ALOGE("apk_path '%s' has no '/'s in it\n", apk_path);
+ SLOGE("apk_path '%s' has no '/'s in it\n", apk_path);
return false;
}
file_name_end = strrchr(apk_path, '.');
if (file_name_end < file_name_start) {
- ALOGE("apk_path '%s' has no extension\n", apk_path);
+ SLOGE("apk_path '%s' has no extension\n", apk_path);
return false;
}
@@ -101,14 +91,14 @@
const char *instruction_set) {
if (strlen(apk_path) + strlen("oat/") + strlen(instruction_set)
+ strlen("/") + strlen("odex") + 1 > PKG_PATH_MAX) {
- ALOGE("apk_path '%s' may be too long to form odex file path.\n", apk_path);
+ SLOGE("apk_path '%s' may be too long to form odex file path.\n", apk_path);
return false;
}
strcpy(path, apk_path);
char *end = strrchr(path, '/');
if (end == NULL) {
- ALOGE("apk_path '%s' has no '/'s in it?!\n", apk_path);
+ SLOGE("apk_path '%s' has no '/'s in it?!\n", apk_path);
return false;
}
const char *apk_end = apk_path + (end - path); // strrchr(apk_path, '/');
@@ -118,7 +108,7 @@
strcat(path, apk_end); // path = /system/framework/oat/<isa>/whatever.jar\0
end = strrchr(path, '.');
if (end == NULL) {
- ALOGE("apk_path '%s' has no extension.\n", apk_path);
+ SLOGE("apk_path '%s' has no extension.\n", apk_path);
return false;
}
strcpy(end + 1, "odex");
@@ -151,12 +141,11 @@
return false;
}
- sprintf(path,"%s%s/%s/%s%s",
+ sprintf(path,"%s%s/%s/%s",
android_data_dir.path,
DALVIK_CACHE,
instruction_set,
- src + 1, /* skip the leading / */
- DALVIK_CACHE_POSTFIX);
+ src + 1 /* skip the leading / */);
char* tmp =
path +
@@ -171,407 +160,19 @@
}
}
+ strcat(path, DALVIK_CACHE_POSTFIX);
return true;
}
-
-static char* parse_null(char* arg) {
- if (strcmp(arg, "!") == 0) {
- return nullptr;
- } else {
- return arg;
- }
-}
-
-static int do_ping(char **arg ATTRIBUTE_UNUSED, char reply[REPLY_MAX] ATTRIBUTE_UNUSED)
-{
- return 0;
-}
-
-static int do_create_app_data(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
- /* const char *uuid, const char *pkgname, userid_t userid, int flags,
- appid_t appid, const char* seinfo, int target_sdk_version */
- return create_app_data(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]),
- atoi(arg[4]), arg[5], atoi(arg[6]));
-}
-
-static int do_restorecon_app_data(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
- /* const char* uuid, const char* pkgName, userid_t userid, int flags,
- appid_t appid, const char* seinfo */
- return restorecon_app_data(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), atoi(arg[4]), arg[5]);
-}
-
-static int do_migrate_app_data(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
- /* const char *uuid, const char *pkgname, userid_t userid, int flags */
- return migrate_app_data(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]));
-}
-
-static int do_clear_app_data(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
- /* const char *uuid, const char *pkgname, userid_t userid, int flags, ino_t ce_data_inode */
- return clear_app_data(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), atol(arg[4]));
-}
-
-static int do_destroy_app_data(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
- /* const char *uuid, const char *pkgname, userid_t userid, int flags, ino_t ce_data_inode */
- return destroy_app_data(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), atol(arg[4]));
-}
-
-// We use otapreopt_chroot to get into the chroot.
-static constexpr const char* kOtaPreopt = "/system/bin/otapreopt_chroot";
-
-static int do_ota_dexopt(const char* args[DEXOPT_PARAM_COUNT],
- char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
- // Time to fork and run otapreopt.
-
- // Check that the tool exists.
- struct stat s;
- if (stat(kOtaPreopt, &s) != 0) {
- LOG(ERROR) << "Otapreopt chroot tool not found.";
- return -1;
- }
-
- pid_t pid = fork();
- if (pid == 0) {
- const char* argv[1 + DEXOPT_PARAM_COUNT + 1];
- argv[0] = kOtaPreopt;
-
- for (size_t i = 0; i < DEXOPT_PARAM_COUNT; ++i) {
- argv[i + 1] = args[i];
- }
-
- argv[DEXOPT_PARAM_COUNT + 1] = nullptr;
-
- execv(argv[0], (char * const *)argv);
- PLOG(ERROR) << "execv(OTAPREOPT_CHROOT) failed";
- exit(99);
- } else {
- int res = wait_child(pid);
- if (res == 0) {
- ALOGV("DexInv: --- END OTAPREOPT (success) ---\n");
- } else {
- ALOGE("DexInv: --- END OTAPREOPT --- status=0x%04x, process failed\n", res);
- }
- return res;
- }
-}
-
-static int do_regular_dexopt(const char* args[DEXOPT_PARAM_COUNT],
- char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
- return dexopt(args);
-}
-
-using DexoptFn = int (*)(const char* args[DEXOPT_PARAM_COUNT],
- char reply[REPLY_MAX]);
-
-static int do_dexopt(char **arg, char reply[REPLY_MAX])
-{
- const char* args[DEXOPT_PARAM_COUNT];
- for (size_t i = 0; i < DEXOPT_PARAM_COUNT; ++i) {
- CHECK(arg[i] != nullptr);
- args[i] = arg[i];
- }
-
- int dexopt_flags = atoi(arg[6]);
- DexoptFn dexopt_fn;
- if ((dexopt_flags & DEXOPT_OTA) != 0) {
- dexopt_fn = do_ota_dexopt;
- } else {
- dexopt_fn = do_regular_dexopt;
- }
- return dexopt_fn(args, reply);
-}
-
-static int do_merge_profiles(char **arg, char reply[REPLY_MAX])
-{
- uid_t uid = static_cast<uid_t>(atoi(arg[0]));
- const char* pkgname = arg[1];
- if (merge_profiles(uid, pkgname)) {
- strncpy(reply, "true", REPLY_MAX);
- } else {
- strncpy(reply, "false", REPLY_MAX);
- }
- return 0;
-}
-
-static int do_dump_profiles(char **arg, char reply[REPLY_MAX])
-{
- uid_t uid = static_cast<uid_t>(atoi(arg[0]));
- const char* pkgname = arg[1];
- const char* dex_files = arg[2];
- if (dump_profile(uid, pkgname, dex_files)) {
- strncpy(reply, "true", REPLY_MAX);
- } else {
- strncpy(reply, "false", REPLY_MAX);
- }
- return 0;
-}
-
-static int do_mark_boot_complete(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED)
-{
- return mark_boot_complete(arg[0] /* instruction set */);
-}
-
-static int do_rm_dex(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED)
-{
- return rm_dex(arg[0], arg[1]); /* pkgname, instruction_set */
-}
-
-static int do_free_cache(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) /* TODO int:free_size */
-{
- return free_cache(parse_null(arg[0]), (int64_t)atoll(arg[1])); /* uuid, free_size */
-}
-
-static int do_get_app_size(char **arg, char reply[REPLY_MAX]) {
- int64_t codesize = 0;
- int64_t datasize = 0;
- int64_t cachesize = 0;
- int64_t asecsize = 0;
- int res = 0;
-
- /* const char *uuid, const char *pkgname, int userid, int flags, ino_t ce_data_inode,
- const char* code_path */
- res = get_app_size(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), atol(arg[4]),
- arg[5], &codesize, &datasize, &cachesize, &asecsize);
-
- /*
- * Each int64_t can take up 22 characters printed out. Make sure it
- * doesn't go over REPLY_MAX in the future.
- */
- snprintf(reply, REPLY_MAX, "%" PRId64 " %" PRId64 " %" PRId64 " %" PRId64,
- codesize, datasize, cachesize, asecsize);
- return res;
-}
-
-static int do_get_app_data_inode(char **arg, char reply[REPLY_MAX]) {
- ino_t inode = 0;
- int res = 0;
-
- /* const char *uuid, const char *pkgname, int userid, int flags */
- res = get_app_data_inode(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), &inode);
-
- snprintf(reply, REPLY_MAX, "%" PRId64, (int64_t) inode);
- return res;
-}
-
-static int do_move_complete_app(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
- /* const char* from_uuid, const char *to_uuid, const char *package_name,
- const char *data_app_name, appid_t appid, const char* seinfo,
- int target_sdk_version */
- return move_complete_app(parse_null(arg[0]), parse_null(arg[1]), arg[2], arg[3],
- atoi(arg[4]), arg[5], atoi(arg[6]));
-}
-
-static int do_create_user_data(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED)
-{
- /* const char *uuid, userid_t userid, int user_serial, int flags */
- return create_user_data(parse_null(arg[0]), atoi(arg[1]), atoi(arg[2]), atoi(arg[3]));
-}
-
-static int do_destroy_user_data(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED)
-{
- /* const char *uuid, userid_t userid, int flags */
- return destroy_user_data(parse_null(arg[0]), atoi(arg[1]), atoi(arg[2]));
-}
-
-static int do_linklib(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED)
-{
- return linklib(parse_null(arg[0]), arg[1], arg[2], atoi(arg[3]));
-}
-
-static int do_idmap(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED)
-{
- return idmap(arg[0], arg[1], atoi(arg[2]));
-}
-
-static int do_create_oat_dir(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED)
-{
- /* oat_dir, instruction_set */
- return create_oat_dir(arg[0], arg[1]);
-}
-
-static int do_rm_package_dir(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED)
-{
- /* oat_dir */
- return rm_package_dir(arg[0]);
-}
-
-static int do_clear_app_profiles(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED)
-{
- /* package_name */
- return clear_app_profiles(arg[0]);
-}
-
-static int do_destroy_app_profiles(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED)
-{
- /* package_name */
- return destroy_app_profiles(arg[0]);
-}
-
-static int do_link_file(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED)
-{
- /* relative_path, from_base, to_base */
- return link_file(arg[0], arg[1], arg[2]);
-}
-
-static int do_move_ab(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
- // apk_path, instruction_set, oat_dir
- return move_ab(arg[0], arg[1], arg[2]);
-}
-
-static int do_delete_odex(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) {
- // apk_path, instruction_set, oat_dir
- return delete_odex(arg[0], arg[1], arg[2]) ? 0 : -1;
-}
-
-struct cmdinfo {
- const char *name;
- unsigned numargs;
- int (*func)(char **arg, char reply[REPLY_MAX]);
-};
-
-struct cmdinfo cmds[] = {
- { "ping", 0, do_ping },
-
- { "create_app_data", 7, do_create_app_data },
- { "restorecon_app_data", 6, do_restorecon_app_data },
- { "migrate_app_data", 4, do_migrate_app_data },
- { "clear_app_data", 5, do_clear_app_data },
- { "destroy_app_data", 5, do_destroy_app_data },
- { "move_complete_app", 7, do_move_complete_app },
- { "get_app_size", 6, do_get_app_size },
- { "get_app_data_inode", 4, do_get_app_data_inode },
-
- { "create_user_data", 4, do_create_user_data },
- { "destroy_user_data", 3, do_destroy_user_data },
-
- { "dexopt", 10, do_dexopt },
- { "markbootcomplete", 1, do_mark_boot_complete },
- { "rmdex", 2, do_rm_dex },
- { "freecache", 2, do_free_cache },
- { "linklib", 4, do_linklib },
- { "idmap", 3, do_idmap },
- { "createoatdir", 2, do_create_oat_dir },
- { "rmpackagedir", 1, do_rm_package_dir },
- { "clear_app_profiles", 1, do_clear_app_profiles },
- { "destroy_app_profiles", 1, do_destroy_app_profiles },
- { "linkfile", 3, do_link_file },
- { "move_ab", 3, do_move_ab },
- { "merge_profiles", 2, do_merge_profiles },
- { "dump_profiles", 3, do_dump_profiles },
- { "delete_odex", 3, do_delete_odex },
-};
-
-static int readx(int s, void *_buf, int count)
-{
- char *buf = (char *) _buf;
- int n = 0, r;
- if (count < 0) return -1;
- while (n < count) {
- r = read(s, buf + n, count - n);
- if (r < 0) {
- if (errno == EINTR) continue;
- ALOGE("read error: %s\n", strerror(errno));
- return -1;
- }
- if (r == 0) {
- ALOGE("eof\n");
- return -1; /* EOF */
- }
- n += r;
- }
- return 0;
-}
-
-static int writex(int s, const void *_buf, int count)
-{
- const char *buf = (const char *) _buf;
- int n = 0, r;
- if (count < 0) return -1;
- while (n < count) {
- r = write(s, buf + n, count - n);
- if (r < 0) {
- if (errno == EINTR) continue;
- ALOGE("write error: %s\n", strerror(errno));
- return -1;
- }
- n += r;
- }
- return 0;
-}
-
-
-/* Tokenize the command buffer, locate a matching command,
- * ensure that the required number of arguments are provided,
- * call the function(), return the result.
- */
-static int execute(int s, char cmd[BUFFER_MAX])
-{
- char reply[REPLY_MAX];
- char *arg[TOKEN_MAX+1];
- unsigned i;
- unsigned n = 0;
- unsigned short count;
- int ret = -1;
-
- // ALOGI("execute('%s')\n", cmd);
-
- /* default reply is "" */
- reply[0] = 0;
-
- /* n is number of args (not counting arg[0]) */
- arg[0] = cmd;
- while (*cmd) {
- if (isspace(*cmd)) {
- *cmd++ = 0;
- n++;
- arg[n] = cmd;
- if (n == TOKEN_MAX) {
- ALOGE("too many arguments\n");
- goto done;
- }
- }
- if (*cmd) {
- cmd++;
- }
- }
-
- for (i = 0; i < sizeof(cmds) / sizeof(cmds[0]); i++) {
- if (!strcmp(cmds[i].name,arg[0])) {
- if (n != cmds[i].numargs) {
- ALOGE("%s requires %d arguments (%d given)\n",
- cmds[i].name, cmds[i].numargs, n);
- } else {
- ret = cmds[i].func(arg + 1, reply);
- }
- goto done;
- }
- }
- ALOGE("unsupported command '%s'\n", arg[0]);
-
-done:
- if (reply[0]) {
- n = snprintf(cmd, BUFFER_MAX, "%d %s", ret, reply);
- } else {
- n = snprintf(cmd, BUFFER_MAX, "%d", ret);
- }
- if (n > BUFFER_MAX) n = BUFFER_MAX;
- count = n;
-
- // ALOGI("reply: '%s'\n", cmd);
- if (writex(s, &count, sizeof(count))) return -1;
- if (writex(s, cmd, count)) return -1;
- return 0;
-}
-
static bool initialize_globals() {
const char* data_path = getenv("ANDROID_DATA");
if (data_path == nullptr) {
- ALOGE("Could not find ANDROID_DATA");
+ SLOGE("Could not find ANDROID_DATA");
return false;
}
const char* root_path = getenv("ANDROID_ROOT");
if (root_path == nullptr) {
- ALOGE("Could not find ANDROID_ROOT");
+ SLOGE("Could not find ANDROID_ROOT");
return false;
}
@@ -597,12 +198,12 @@
}
if (ensure_config_user_dirs(0) == -1) {
- ALOGE("Failed to setup misc for user 0");
+ SLOGE("Failed to setup misc for user 0");
goto fail;
}
if (version == 2) {
- ALOGD("Upgrading to /data/misc/user directories");
+ SLOGD("Upgrading to /data/misc/user directories");
char misc_dir[PATH_MAX];
snprintf(misc_dir, PATH_MAX, "%smisc", android_data_dir.path);
@@ -643,12 +244,12 @@
gid_t gid = uid;
if (access(keychain_added_dir, F_OK) == 0) {
if (copy_dir_files(keychain_added_dir, misc_added_dir, uid, gid) != 0) {
- ALOGE("Some files failed to copy");
+ SLOGE("Some files failed to copy");
}
}
if (access(keychain_removed_dir, F_OK) == 0) {
if (copy_dir_files(keychain_removed_dir, misc_removed_dir, uid, gid) != 0) {
- ALOGE("Some files failed to copy");
+ SLOGE("Some files failed to copy");
}
}
}
@@ -668,7 +269,7 @@
// Persist layout version if changed
if (version != oldVersion) {
if (fs_write_atomic_int(version_path, version) == -1) {
- ALOGE("Failed to save version to %s: %s", version_path, strerror(errno));
+ SLOGE("Failed to save version to %s: %s", version_path, strerror(errno));
goto fail;
}
}
@@ -702,80 +303,41 @@
}
static int installd_main(const int argc ATTRIBUTE_UNUSED, char *argv[]) {
- char buf[BUFFER_MAX];
- struct sockaddr addr;
- socklen_t alen;
- int lsocket, s;
+ int ret;
int selinux_enabled = (is_selinux_enabled() > 0);
setenv("ANDROID_LOG_TAGS", "*:v", 1);
android::base::InitLogging(argv);
- ALOGI("installd firing up\n");
+ SLOGI("installd firing up");
union selinux_callback cb;
cb.func_log = log_callback;
selinux_set_callback(SELINUX_CB_LOG, cb);
if (!initialize_globals()) {
- ALOGE("Could not initialize globals; exiting.\n");
+ SLOGE("Could not initialize globals; exiting.\n");
exit(1);
}
if (initialize_directories() < 0) {
- ALOGE("Could not create directories; exiting.\n");
+ SLOGE("Could not create directories; exiting.\n");
exit(1);
}
if (selinux_enabled && selinux_status_open(true) < 0) {
- ALOGE("Could not open selinux status; exiting.\n");
+ SLOGE("Could not open selinux status; exiting.\n");
exit(1);
}
- lsocket = android_get_control_socket(SOCKET_PATH);
- if (lsocket < 0) {
- ALOGE("Failed to get socket from environment: %s\n", strerror(errno));
+ if ((ret = InstalldNativeService::start()) != android::OK) {
+ SLOGE("Unable to start InstalldNativeService: %d", ret);
exit(1);
}
- if (listen(lsocket, 5)) {
- ALOGE("Listen on socket failed: %s\n", strerror(errno));
- exit(1);
- }
- fcntl(lsocket, F_SETFD, FD_CLOEXEC);
- for (;;) {
- alen = sizeof(addr);
- s = accept(lsocket, &addr, &alen);
- if (s < 0) {
- ALOGE("Accept failed: %s\n", strerror(errno));
- continue;
- }
- fcntl(s, F_SETFD, FD_CLOEXEC);
+ IPCThreadState::self()->joinThreadPool();
- ALOGI("new connection\n");
- for (;;) {
- unsigned short count;
- if (readx(s, &count, sizeof(count))) {
- ALOGE("failed to read size\n");
- break;
- }
- if ((count < 1) || (count >= BUFFER_MAX)) {
- ALOGE("invalid size %d\n", count);
- break;
- }
- if (readx(s, buf, count)) {
- ALOGE("failed to read command\n");
- break;
- }
- buf[count] = 0;
- if (selinux_enabled && selinux_status_updated() > 0) {
- selinux_android_seapp_context_reload();
- }
- if (execute(s, buf)) break;
- }
- ALOGI("closing connection\n");
- close(s);
- }
+ LOG(INFO) << "installd shutting down";
return 0;
}
diff --git a/cmds/installd/installd.rc b/cmds/installd/installd.rc
index 5e4c925..d5d5236 100644
--- a/cmds/installd/installd.rc
+++ b/cmds/installd/installd.rc
@@ -1,3 +1,2 @@
service installd /system/bin/installd
class main
- socket installd stream 600 system system
diff --git a/cmds/installd/installd_constants.h b/cmds/installd/installd_constants.h
index 41732cc..6a81cfc 100644
--- a/cmds/installd/installd_constants.h
+++ b/cmds/installd/installd_constants.h
@@ -28,8 +28,7 @@
// This is used as a string literal, can't be constants. TODO: std::string...
#define DALVIK_CACHE "dalvik-cache"
-constexpr const char* DALVIK_CACHE_POSTFIX = "/classes.dex";
-constexpr const char* DALVIK_CACHE_POSTFIX2 = "@classes.dex";
+constexpr const char* DALVIK_CACHE_POSTFIX = "@classes.dex";
constexpr size_t PKG_NAME_MAX = 128u; /* largest allowed package name */
constexpr size_t PKG_PATH_MAX = 256u; /* max size of any path we use */
@@ -39,20 +38,32 @@
* frameworks/base/services/core/java/com/android/server/pm/Installer.java
***************************************************************************/
constexpr int DEXOPT_PUBLIC = 1 << 1;
-constexpr int DEXOPT_SAFEMODE = 1 << 2;
-constexpr int DEXOPT_DEBUGGABLE = 1 << 3;
-constexpr int DEXOPT_BOOTCOMPLETE = 1 << 4;
-constexpr int DEXOPT_PROFILE_GUIDED = 1 << 5;
-constexpr int DEXOPT_OTA = 1 << 6;
+constexpr int DEXOPT_DEBUGGABLE = 1 << 2;
+constexpr int DEXOPT_BOOTCOMPLETE = 1 << 3;
+constexpr int DEXOPT_PROFILE_GUIDED = 1 << 4;
+constexpr int DEXOPT_SECONDARY_DEX = 1 << 5;
+// DEXOPT_FORCE, DEXOPT_STORAGE_CE, DEXOPT_STORAGE_DE are exposed for secondary
+// dex files only. Primary apks are analyzed in PackageManager and installd
+// does not need to know if the compilation is forced or on what kind of storage
+// the dex files are.
+constexpr int DEXOPT_FORCE = 1 << 6;
+constexpr int DEXOPT_STORAGE_CE = 1 << 7;
+constexpr int DEXOPT_STORAGE_DE = 1 << 8;
/* all known values for dexopt flags */
constexpr int DEXOPT_MASK =
DEXOPT_PUBLIC
- | DEXOPT_SAFEMODE
| DEXOPT_DEBUGGABLE
| DEXOPT_BOOTCOMPLETE
| DEXOPT_PROFILE_GUIDED
- | DEXOPT_OTA;
+ | DEXOPT_SECONDARY_DEX
+ | DEXOPT_FORCE
+ | DEXOPT_STORAGE_CE
+ | DEXOPT_STORAGE_DE;
+
+// NOTE: keep in sync with StorageManager
+constexpr int FLAG_STORAGE_DE = 1 << 0;
+constexpr int FLAG_STORAGE_CE = 1 << 1;
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
diff --git a/cmds/installd/matchgen.py b/cmds/installd/matchgen.py
new file mode 100644
index 0000000..b37352b
--- /dev/null
+++ b/cmds/installd/matchgen.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2017 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.
+
+import collections
+
+TYPES = {
+ "AID_MEDIA_AUDIO": ["aac","aac","amr","awb","snd","flac","flac","mp3","mpga","mpega","mp2","m4a","aif","aiff","aifc","gsm","mka","m3u","wma","wax","ra","rm","ram","ra","pls","sd2","wav","ogg","oga"],
+ "AID_MEDIA_VIDEO": ["3gpp","3gp","3gpp2","3g2","avi","dl","dif","dv","fli","m4v","ts","mpeg","mpg","mpe","mp4","vob","qt","mov","mxu","webm","lsf","lsx","mkv","mng","asf","asx","wm","wmv","wmx","wvx","movie","wrf"],
+ "AID_MEDIA_IMAGE": ["bmp","gif","jpg","jpeg","jpe","pcx","png","svg","svgz","tiff","tif","wbmp","webp","dng","cr2","ras","art","jng","nef","nrw","orf","rw2","pef","psd","pnm","pbm","pgm","ppm","srw","arw","rgb","xbm","xpm","xwd"]
+}
+
+print """/*
+ * Copyright (C) 2017 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.
+ */
+
+/******************************************************************
+ * THIS CODE WAS GENERATED BY matchgen.py, DO NOT MODIFY DIRECTLY *
+ ******************************************************************/
+
+#include <private/android_filesystem_config.h>
+
+int MatchExtension(const char* ext) {
+"""
+
+trie = collections.defaultdict(lambda: collections.defaultdict(lambda: collections.defaultdict(lambda: collections.defaultdict(lambda: collections.defaultdict(lambda: collections.defaultdict(lambda: ""))))))
+
+for t in TYPES:
+ for v in TYPES[t]:
+ v = v.lower()
+ target = trie
+ for c in v:
+ target = target[c]
+ target["\0"] = t
+
+def dump(target, index):
+ prefix = " " * (index + 1)
+ print "%sswitch (ext[%d]) {" % (prefix, index)
+ for k in sorted(target.keys()):
+ if k == "\0":
+ print "%scase '\\0': return %s;" % (prefix, target[k])
+ else:
+ upper = k.upper()
+ if k != upper:
+ print "%scase '%s': case '%s':" % (prefix, k, upper)
+ else:
+ print "%scase '%s':" % (prefix, k)
+ dump(target[k], index + 1)
+ print "%s}" % (prefix)
+
+dump(trie, 0)
+
+print """
+ return 0;
+}
+"""
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 5fa972a..82b8cc2 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -32,17 +32,17 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <cutils/fs.h>
-#include <cutils/log.h>
#include <cutils/properties.h>
+#include <log/log.h>
#include <private/android_filesystem_config.h>
-#include <commands.h>
-#include <file_parsing.h>
-#include <globals.h>
-#include <installd_deps.h> // Need to fill in requirements of commands.
-#include <otapreopt_utils.h>
-#include <system_properties.h>
-#include <utils.h>
+#include "dexopt.h"
+#include "file_parsing.h"
+#include "globals.h"
+#include "installd_deps.h" // Need to fill in requirements of commands.
+#include "otapreopt_utils.h"
+#include "system_properties.h"
+#include "utils.h"
#ifndef LOG_TAG
#define LOG_TAG "otapreopt"
@@ -823,7 +823,7 @@
DALVIK_CACHE,
instruction_set,
from_src.c_str(),
- DALVIK_CACHE_POSTFIX2);
+ DALVIK_CACHE_POSTFIX);
if (assembled_path.length() + 1 > PKG_PATH_MAX) {
return false;
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index 5ea89e6..cec8f68 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -25,8 +25,9 @@
#include <android-base/macros.h>
#include <android-base/stringprintf.h>
-#include <commands.h>
-#include <otapreopt_utils.h>
+#include "installd_constants.h"
+#include "otapreopt_utils.h"
+#include "dexopt.h"
#ifndef LOG_TAG
#define LOG_TAG "otapreopt"
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
new file mode 100644
index 0000000..a32df22
--- /dev/null
+++ b/cmds/installd/tests/Android.bp
@@ -0,0 +1,16 @@
+// Build the unit tests for installd
+cc_test {
+ name: "installd_utils_test",
+ clang: true,
+ srcs: ["installd_utils_test.cpp"],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libutils",
+ "libcutils",
+ ],
+ static_libs: [
+ "libinstalld",
+ "libdiskusage",
+ ],
+}
diff --git a/cmds/installd/tests/Android.mk b/cmds/installd/tests/Android.mk
deleted file mode 100644
index 38a9f69..0000000
--- a/cmds/installd/tests/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# Build the unit tests for installd
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-# Build the unit tests.
-test_src_files := \
- installd_utils_test.cpp
-
-shared_libraries := \
- libbase \
- libutils \
- libcutils \
-
-static_libraries := \
- libinstalld \
- libdiskusage \
-
-c_includes := \
- frameworks/native/cmds/installd
-
-$(foreach file,$(test_src_files), \
- $(eval include $(CLEAR_VARS)) \
- $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
- $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
- $(eval LOCAL_SRC_FILES := $(file)) \
- $(eval LOCAL_C_INCLUDES := $(c_includes)) \
- $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
- $(eval LOCAL_CLANG := true) \
- $(eval include $(BUILD_NATIVE_TEST)) \
-)
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 9b2de88..d1e5919 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -19,9 +19,9 @@
#include <gtest/gtest.h>
-#include <commands.h>
-#include <globals.h>
-#include <utils.h>
+#include "InstalldNativeService.h"
+#include "globals.h"
+#include "utils.h"
#undef LOG_TAG
#define LOG_TAG "utils_test"
@@ -35,6 +35,8 @@
#define TEST_SYSTEM_DIR1 "/system/app/"
#define TEST_SYSTEM_DIR2 "/vendor/app/"
+#define TEST_PROFILE_DIR "/data/misc/profiles"
+
#define REALLY_LONG_APP_NAME "com.example." \
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \
@@ -74,6 +76,9 @@
android_system_dirs.dirs[1].path = (char*) TEST_SYSTEM_DIR2;
android_system_dirs.dirs[1].len = strlen(TEST_SYSTEM_DIR2);
+
+ android_profiles_dir.path = (char*) TEST_PROFILE_DIR;
+ android_profiles_dir.len = strlen(TEST_PROFILE_DIR);
}
virtual void TearDown() {
@@ -317,6 +322,7 @@
size_t pkgnameSize = PKG_NAME_MAX;
char pkgname[pkgnameSize + 1];
memset(pkgname, 'a', pkgnameSize);
+ pkgname[1] = '.';
pkgname[pkgnameSize] = '\0';
EXPECT_EQ(0, create_pkg_path(path, pkgname, "", 0))
@@ -329,19 +335,6 @@
<< "Package path should be a really long string of a's";
}
-TEST_F(UtilsTest, CreatePkgPath_LongPkgNameFail) {
- char path[PKG_PATH_MAX];
-
- // Create long packagename of "aaaaa..."
- size_t pkgnameSize = PKG_NAME_MAX + 1;
- char pkgname[pkgnameSize + 1];
- memset(pkgname, 'a', pkgnameSize);
- pkgname[pkgnameSize] = '\0';
-
- EXPECT_EQ(-1, create_pkg_path(path, pkgname, "", 0))
- << "Should return error because package name is too long.";
-}
-
TEST_F(UtilsTest, CreatePkgPath_LongPostfixFail) {
char path[PKG_PATH_MAX];
@@ -508,5 +501,71 @@
create_data_user_ce_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 10, "com.example"));
}
+TEST_F(UtilsTest, IsValidPackageName) {
+ EXPECT_EQ(true, is_valid_package_name("android"));
+ EXPECT_EQ(true, is_valid_package_name("com.example"));
+ EXPECT_EQ(true, is_valid_package_name("com.example-1"));
+ EXPECT_EQ(true, is_valid_package_name("com.example-1024"));
+ EXPECT_EQ(true, is_valid_package_name("com.example.foo---KiJFj4a_tePVw95pSrjg=="));
+ EXPECT_EQ(true, is_valid_package_name("really_LONG.a1234.package_name"));
+
+ EXPECT_EQ(false, is_valid_package_name("1234.package"));
+ EXPECT_EQ(false, is_valid_package_name("com.1234.package"));
+ EXPECT_EQ(false, is_valid_package_name(""));
+ EXPECT_EQ(false, is_valid_package_name("."));
+ EXPECT_EQ(false, is_valid_package_name(".."));
+ EXPECT_EQ(false, is_valid_package_name("../"));
+ EXPECT_EQ(false, is_valid_package_name("com.example/../com.evil/"));
+ EXPECT_EQ(false, is_valid_package_name("com.example-1/../com.evil/"));
+ EXPECT_EQ(false, is_valid_package_name("/com.evil"));
+}
+
+TEST_F(UtilsTest, CreateDataUserProfilePath) {
+ EXPECT_EQ("/data/misc/profiles/cur/0", create_primary_cur_profile_dir_path(0));
+ EXPECT_EQ("/data/misc/profiles/cur/1", create_primary_cur_profile_dir_path(1));
+}
+
+TEST_F(UtilsTest, CreateDataUserProfilePackagePath) {
+ EXPECT_EQ("/data/misc/profiles/cur/0/com.example",
+ create_primary_current_profile_package_dir_path(0, "com.example"));
+ EXPECT_EQ("/data/misc/profiles/cur/1/com.example",
+ create_primary_current_profile_package_dir_path(1, "com.example"));
+}
+
+TEST_F(UtilsTest, CreateDataRefProfilePath) {
+ EXPECT_EQ("/data/misc/profiles/ref", create_primary_ref_profile_dir_path());
+}
+
+TEST_F(UtilsTest, CreateDataRefProfilePackagePath) {
+ EXPECT_EQ("/data/misc/profiles/ref/com.example",
+ create_primary_reference_profile_package_dir_path("com.example"));
+}
+
+TEST_F(UtilsTest, CreatePrimaryCurrentProfile) {
+ std::string expected =
+ create_primary_current_profile_package_dir_path(1, "com.example") + "/primary.prof";
+ EXPECT_EQ(expected,
+ create_current_profile_path(/*user*/0, "com.example", /*is_secondary*/false));
+}
+
+TEST_F(UtilsTest, CreatePrimaryReferenceProfile) {
+ std::string expected =
+ create_primary_reference_profile_package_dir_path("com.example") + "/primary.prof";
+ EXPECT_EQ(expected,
+ create_reference_profile_path("com.example", /*is_secondary*/false));
+}
+
+TEST_F(UtilsTest, CreateSecondaryCurrentProfile) {
+ EXPECT_EQ("/data/user/0/com.example/secondary.dex.prof",
+ create_current_profile_path(/*user*/0,
+ "/data/user/0/com.example/secondary.dex", /*is_secondary*/true));
+}
+
+TEST_F(UtilsTest, CreateSecondaryReferenceProfile) {
+ EXPECT_EQ("/data/user/0/com.example/oat/secondary.dex.prof",
+ create_reference_profile_path(
+ "/data/user/0/com.example/secondary.dex", /*is_secondary*/true));
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 674f760..6747f0a 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -18,6 +18,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <fts.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/wait.h>
@@ -32,7 +33,7 @@
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <cutils/fs.h>
-#include <cutils/log.h>
+#include <log/log.h>
#include <private/android_filesystem_config.h>
#include "globals.h" // extern variables.
@@ -53,7 +54,7 @@
* Check that given string is valid filename, and that it attempts no
* parent or child directory traversal.
*/
-static bool is_valid_filename(const std::string& name) {
+bool is_valid_filename(const std::string& name) {
if (name.empty() || (name == ".") || (name == "..")
|| (name.find('/') != std::string::npos)) {
return false;
@@ -64,7 +65,7 @@
static void check_package_name(const char* package_name) {
CHECK(is_valid_filename(package_name));
- CHECK(is_valid_package_name(package_name) == 0);
+ CHECK(is_valid_package_name(package_name));
}
/**
@@ -135,7 +136,7 @@
int create_pkg_path(char path[PKG_PATH_MAX], const char *pkgname,
const char *postfix, userid_t userid) {
- if (is_valid_package_name(pkgname) != 0) {
+ if (!is_valid_package_name(pkgname)) {
path[0] = '\0';
return -1;
}
@@ -169,18 +170,19 @@
/**
* Create the path name for user data for a certain userid.
+ * Keep same implementation as vold to minimize path walking overhead
*/
std::string create_data_user_ce_path(const char* volume_uuid, userid_t userid) {
std::string data(create_data_path(volume_uuid));
- if (volume_uuid == nullptr) {
- if (userid == 0) {
- return StringPrintf("%s/data", data.c_str());
- } else {
- return StringPrintf("%s/user/%u", data.c_str(), userid);
+ if (volume_uuid == nullptr && userid == 0) {
+ std::string legacy = StringPrintf("%s/data", data.c_str());
+ struct stat sb;
+ if (lstat(legacy.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)) {
+ /* /data/data is dir, return /data/data for legacy system */
+ return legacy;
}
- } else {
- return StringPrintf("%s/user/%u", data.c_str(), userid);
}
+ return StringPrintf("%s/user/%u", data.c_str(), userid);
}
/**
@@ -198,22 +200,76 @@
return StringPrintf("%s/media/%u", create_data_path(volume_uuid).c_str(), userid);
}
+std::string create_data_media_obb_path(const char* volume_uuid, const char* package_name) {
+ return StringPrintf("%s/media/obb/%s", create_data_path(volume_uuid).c_str(), package_name);
+}
+
+std::string create_data_media_package_path(const char* volume_uuid, userid_t userid,
+ const char* data_type, const char* package_name) {
+ return StringPrintf("%s/Android/%s/%s", create_data_media_path(volume_uuid, userid).c_str(),
+ data_type, package_name);
+}
+
std::string create_data_misc_legacy_path(userid_t userid) {
return StringPrintf("%s/misc/user/%u", create_data_path(nullptr).c_str(), userid);
}
-std::string create_data_user_profiles_path(userid_t userid) {
+std::string create_primary_cur_profile_dir_path(userid_t userid) {
return StringPrintf("%s/cur/%u", android_profiles_dir.path, userid);
}
-std::string create_data_user_profile_package_path(userid_t user, const char* package_name) {
- check_package_name(package_name);
- return StringPrintf("%s/%s",create_data_user_profiles_path(user).c_str(), package_name);
+std::string create_primary_current_profile_package_dir_path(userid_t user,
+ const std::string& package_name) {
+ check_package_name(package_name.c_str());
+ return StringPrintf("%s/%s",
+ create_primary_cur_profile_dir_path(user).c_str(), package_name.c_str());
}
-std::string create_data_ref_profile_package_path(const char* package_name) {
- check_package_name(package_name);
- return StringPrintf("%s/ref/%s", android_profiles_dir.path, package_name);
+std::string create_primary_ref_profile_dir_path() {
+ return StringPrintf("%s/ref", android_profiles_dir.path);
+}
+
+std::string create_primary_reference_profile_package_dir_path(const std::string& package_name) {
+ check_package_name(package_name.c_str());
+ return StringPrintf("%s/ref/%s", android_profiles_dir.path, package_name.c_str());
+}
+
+std::string create_data_dalvik_cache_path() {
+ return "/data/dalvik-cache";
+}
+
+// Keep profile paths in sync with ActivityThread and LoadedApk.
+const std::string PROFILE_EXT = ".prof";
+const std::string PRIMARY_PROFILE_NAME = "primary" + PROFILE_EXT;
+
+std::string create_current_profile_path(userid_t user, const std::string& location,
+ bool is_secondary_dex) {
+ if (is_secondary_dex) {
+ // Secondary dex profiles are stored next to the dex files using .prof extension.
+ return StringPrintf("%s%s", location.c_str(), PROFILE_EXT.c_str());
+ } else {
+ // Profiles for primary apks are under /data/misc/profiles/cur.
+ std::string profile_dir = create_primary_current_profile_package_dir_path(user, location);
+ return StringPrintf("%s/%s", profile_dir.c_str(), PRIMARY_PROFILE_NAME.c_str());
+ }
+}
+
+std::string create_reference_profile_path(const std::string& location, bool is_secondary_dex) {
+ if (is_secondary_dex) {
+ // Secondary dex reference profiles are stored next to the dex files under the oat folder.
+ size_t dirIndex = location.rfind('/');
+ CHECK(dirIndex != std::string::npos)
+ << "Unexpected dir structure for secondary dex " << location;
+
+ std::string dex_dir = location.substr(0, dirIndex);
+ std::string dex_name = location.substr(dirIndex +1);
+ return StringPrintf("%s/oat/%s%s",
+ dex_dir.c_str(), dex_name.c_str(), PROFILE_EXT.c_str());
+ } else {
+ // Reference profiles for primary apks are stored in /data/misc/profile/ref.
+ std::string profile_dir = create_primary_reference_profile_package_dir_path(location);
+ return StringPrintf("%s/%s", profile_dir.c_str(), PRIMARY_PROFILE_NAME.c_str());
+ }
}
std::vector<userid_t> get_known_users(const char* volume_uuid) {
@@ -248,6 +304,59 @@
return users;
}
+int calculate_tree_size(const std::string& path, int64_t* size,
+ int32_t include_gid, int32_t exclude_gid, bool exclude_apps) {
+ FTS *fts;
+ FTSENT *p;
+ int64_t matchedSize = 0;
+ char *argv[] = { (char*) path.c_str(), nullptr };
+ if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_XDEV, NULL))) {
+ if (errno != ENOENT) {
+ PLOG(ERROR) << "Failed to fts_open " << path;
+ }
+ return -1;
+ }
+ while ((p = fts_read(fts)) != NULL) {
+ switch (p->fts_info) {
+ case FTS_D:
+ case FTS_DEFAULT:
+ case FTS_F:
+ case FTS_SL:
+ case FTS_SLNONE:
+ int32_t uid = p->fts_statp->st_uid;
+ int32_t gid = p->fts_statp->st_gid;
+ int32_t user_uid = multiuser_get_app_id(uid);
+ int32_t user_gid = multiuser_get_app_id(gid);
+ if (exclude_apps && ((user_uid >= AID_APP_START && user_uid <= AID_APP_END)
+ || (user_gid >= AID_CACHE_GID_START && user_gid <= AID_CACHE_GID_END)
+ || (user_gid >= AID_SHARED_GID_START && user_gid <= AID_SHARED_GID_END))) {
+ // Don't traverse inside or measure
+ fts_set(fts, p, FTS_SKIP);
+ break;
+ }
+ if (include_gid != -1 && gid != include_gid) {
+ break;
+ }
+ if (exclude_gid != -1 && gid == exclude_gid) {
+ break;
+ }
+ matchedSize += (p->fts_statp->st_blocks * 512);
+ break;
+ }
+ }
+ fts_close(fts);
+#if MEASURE_DEBUG
+ if ((include_gid == -1) && (exclude_gid == -1)) {
+ LOG(DEBUG) << "Measured " << path << " size " << matchedSize;
+ } else {
+ LOG(DEBUG) << "Measured " << path << " size " << matchedSize << "; include " << include_gid
+ << " exclude " << exclude_gid;
+ }
+#endif
+ *size += matchedSize;
+ return 0;
+}
+
int create_move_path(char path[PKG_PATH_MAX],
const char* pkgname,
const char* leaf,
@@ -266,49 +375,46 @@
* Checks whether the package name is valid. Returns -1 on error and
* 0 on success.
*/
-int is_valid_package_name(const char* pkgname) {
- const char *x = pkgname;
- int alpha = -1;
+bool is_valid_package_name(const std::string& packageName) {
+ // This logic is borrowed from PackageParser.java
+ bool hasSep = false;
+ bool front = true;
- if (strlen(pkgname) > PKG_NAME_MAX) {
- return -1;
- }
-
- while (*x) {
- if (isalnum(*x) || (*x == '_')) {
- /* alphanumeric or underscore are fine */
- } else if (*x == '.') {
- if ((x == pkgname) || (x[1] == '.') || (x[1] == 0)) {
- /* periods must not be first, last, or doubled */
- ALOGE("invalid package name '%s'\n", pkgname);
- return -1;
- }
- } else if (*x == '-') {
- /* Suffix -X is fine to let versioning of packages.
- But whatever follows should be alphanumeric.*/
- alpha = 1;
- } else {
- /* anything not A-Z, a-z, 0-9, _, or . is invalid */
- ALOGE("invalid package name '%s'\n", pkgname);
- return -1;
+ auto it = packageName.begin();
+ for (; it != packageName.end() && *it != '-'; it++) {
+ char c = *it;
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
+ front = false;
+ continue;
}
-
- x++;
- }
-
- if (alpha == 1) {
- // Skip current character
- x++;
- while (*x) {
- if (!isalnum(*x)) {
- ALOGE("invalid package name '%s' should include only numbers after -\n", pkgname);
- return -1;
+ if (!front) {
+ if ((c >= '0' && c <= '9') || c == '_') {
+ continue;
}
- x++;
}
+ if (c == '.') {
+ hasSep = true;
+ front = true;
+ continue;
+ }
+ LOG(WARNING) << "Bad package character " << c << " in " << packageName;
+ return false;
}
- return 0;
+ if (front) {
+ LOG(WARNING) << "Missing separator in " << packageName;
+ return false;
+ }
+
+ for (; it != packageName.end(); it++) {
+ char c = *it;
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) continue;
+ if ((c >= '0' && c <= '9') || c == '_' || c == '-' || c == '=') continue;
+ LOG(WARNING) << "Bad suffix character " << c << " in " << packageName;
+ return false;
+ }
+
+ return true;
}
static int _delete_dir_contents(DIR *d,
@@ -1087,6 +1193,27 @@
return -1;
}
+bool validate_secondary_dex_path(const std::string& pkgname, const std::string& dex_path,
+ const char* volume_uuid, int uid, int storage_flag) {
+ CHECK(storage_flag == FLAG_STORAGE_CE || storage_flag == FLAG_STORAGE_DE);
+
+ std::string app_private_dir = storage_flag == FLAG_STORAGE_CE
+ ? create_data_user_ce_package_path(
+ volume_uuid, multiuser_get_user_id(uid), pkgname.c_str())
+ : create_data_user_de_package_path(
+ volume_uuid, multiuser_get_user_id(uid), pkgname.c_str());
+ dir_rec_t dir;
+ if (get_path_from_string(&dir, app_private_dir.c_str()) != 0) {
+ LOG(WARNING) << "Could not get dir rec for " << app_private_dir;
+ return false;
+ }
+ // Usually secondary dex files have a nested directory structure.
+ // Pick at most 10 subdirectories when validating (arbitrary value).
+ // If the secondary dex file is >10 directory nested then validation will
+ // fail and the file will not be compiled.
+ return validate_path(&dir, dex_path.c_str(), /*max_subdirs*/ 10) == 0;
+}
+
/**
* Get the contents of a environment variable that contains a path. Caller
* owns the string that is inserted into the directory record. Returns
@@ -1286,5 +1413,73 @@
}
}
+/**
+ * Prepare an app cache directory, which offers to fix-up the GID and
+ * directory mode flags during a platform upgrade.
+ * The app cache directory path will be 'parent'/'name'.
+ */
+int prepare_app_cache_dir(const std::string& parent, const char* name, mode_t target_mode,
+ uid_t uid, gid_t gid) {
+ auto path = StringPrintf("%s/%s", parent.c_str(), name);
+ struct stat st;
+ if (stat(path.c_str(), &st) != 0) {
+ if (errno == ENOENT) {
+ // This is fine, just create it
+ if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, gid) != 0) {
+ PLOG(ERROR) << "Failed to prepare " << path;
+ return -1;
+ } else {
+ return 0;
+ }
+ } else {
+ PLOG(ERROR) << "Failed to stat " << path;
+ return -1;
+ }
+ }
+
+ mode_t actual_mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID);
+ if (st.st_uid != uid) {
+ // Mismatched UID is real trouble; we can't recover
+ LOG(ERROR) << "Mismatched UID at " << path << ": found " << st.st_uid
+ << " but expected " << uid;
+ return -1;
+ } else if (st.st_gid == gid && actual_mode == target_mode) {
+ // Everything looks good!
+ return 0;
+ }
+
+ // Directory is owned correctly, but GID or mode mismatch means it's
+ // probably a platform upgrade so we need to fix them
+ FTS *fts;
+ FTSENT *p;
+ char *argv[] = { (char*) path.c_str(), nullptr };
+ if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_XDEV, NULL))) {
+ PLOG(ERROR) << "Failed to fts_open " << path;
+ return -1;
+ }
+ while ((p = fts_read(fts)) != NULL) {
+ switch (p->fts_info) {
+ case FTS_DP:
+ if (chmod(p->fts_accpath, target_mode) != 0) {
+ PLOG(WARNING) << "Failed to chmod " << p->fts_path;
+ }
+ // Intentional fall through to also set GID
+ case FTS_F:
+ if (chown(p->fts_accpath, -1, gid) != 0) {
+ PLOG(WARNING) << "Failed to chown " << p->fts_path;
+ }
+ break;
+ case FTS_SL:
+ case FTS_SLNONE:
+ if (lchown(p->fts_accpath, -1, gid) != 0) {
+ PLOG(WARNING) << "Failed to chown " << p->fts_path;
+ }
+ break;
+ }
+ }
+ fts_close(fts);
+ return 0;
+}
+
} // namespace installd
} // namespace android
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index 8123e9b..c540c52 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -30,6 +30,8 @@
#include <installd_constants.h>
+#define MEASURE_DEBUG 0
+
namespace android {
namespace installd {
@@ -73,7 +75,6 @@
std::string create_data_path(const char* volume_uuid);
std::string create_data_app_path(const char* volume_uuid);
-
std::string create_data_app_package_path(const char* volume_uuid, const char* package_name);
std::string create_data_user_ce_path(const char* volume_uuid, userid_t userid);
@@ -87,15 +88,31 @@
userid_t user, const char* package_name);
std::string create_data_media_path(const char* volume_uuid, userid_t userid);
+std::string create_data_media_obb_path(const char* volume_uuid, const char* package_name);
+std::string create_data_media_package_path(const char* volume_uuid, userid_t userid,
+ const char* data_type, const char* package_name);
std::string create_data_misc_legacy_path(userid_t userid);
-std::string create_data_user_profiles_path(userid_t userid);
-std::string create_data_user_profile_package_path(userid_t user, const char* package_name);
-std::string create_data_ref_profile_package_path(const char* package_name);
+std::string create_data_dalvik_cache_path();
+
+std::string create_primary_cur_profile_dir_path(userid_t userid);
+std::string create_primary_current_profile_package_dir_path(
+ userid_t user, const std::string& package_name);
+
+std::string create_primary_ref_profile_dir_path();
+std::string create_primary_reference_profile_package_dir_path(const std::string& package_name);
+
+std::string create_current_profile_path(
+ userid_t user, const std::string& package_name, bool is_secondary_dex);
+std::string create_reference_profile_path(
+ const std::string& package_name, bool is_secondary_dex);
std::vector<userid_t> get_known_users(const char* volume_uuid);
+int calculate_tree_size(const std::string& path, int64_t* size,
+ int32_t include_gid = -1, int32_t exclude_gid = -1, bool exclude_apps = false);
+
int create_user_config_path(char path[PKG_PATH_MAX], userid_t userid);
int create_move_path(char path[PKG_PATH_MAX],
@@ -103,7 +120,8 @@
const char* leaf,
userid_t userid);
-int is_valid_package_name(const char* pkgname);
+bool is_valid_filename(const std::string& name);
+bool is_valid_package_name(const std::string& packageName);
int delete_dir_contents(const std::string& pathname, bool ignore_if_missing = false);
int delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing = false);
@@ -133,6 +151,8 @@
void finish_cache_collection(cache_t* cache);
int validate_system_app_path(const char* path);
+bool validate_secondary_dex_path(const std::string& pkgname, const std::string& dex_path,
+ const char* volume_uuid, int uid, int storage_flag);
int get_path_from_env(dir_rec_t* rec, const char* var);
@@ -152,6 +172,9 @@
int wait_child(pid_t pid);
+int prepare_app_cache_dir(const std::string& parent, const char* name, mode_t target_mode,
+ uid_t uid, gid_t gid);
+
} // namespace installd
} // namespace android
diff --git a/cmds/ip-up-vpn/ip-up-vpn.c b/cmds/ip-up-vpn/ip-up-vpn.c
index 75b907c..3b8955b 100644
--- a/cmds/ip-up-vpn/ip-up-vpn.c
+++ b/cmds/ip-up-vpn/ip-up-vpn.c
@@ -14,22 +14,22 @@
* limitations under the License.
*/
+#define LOG_TAG "ip-up-vpn"
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <linux/if.h>
+#include <linux/route.h>
+#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <errno.h>
-
-#include <arpa/inet.h>
-#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <linux/if.h>
-#include <linux/route.h>
-#define LOG_TAG "ip-up-vpn"
-#include <cutils/log.h>
+#include <log/log.h>
#define DIR "/data/misc/vpn/"
diff --git a/cmds/lshal/Android.bp b/cmds/lshal/Android.bp
new file mode 100644
index 0000000..67b5b46
--- /dev/null
+++ b/cmds/lshal/Android.bp
@@ -0,0 +1,67 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+ name: "liblshal",
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libutils",
+ "libhidlbase",
+ "libhidltransport",
+ "libhidl-gen-utils",
+ "libvintf",
+ ],
+ srcs: [
+ "DebugCommand.cpp",
+ "Lshal.cpp",
+ "ListCommand.cpp",
+ "PipeRelay.cpp",
+ "utils.cpp",
+ ],
+}
+
+cc_defaults {
+ name: "lshal_defaults",
+ shared_libs: [
+ "libbase",
+ "libhidlbase",
+ "libhidltransport",
+ "liblshal",
+ "libutils",
+ ]
+}
+
+cc_binary {
+ name: "lshal",
+ defaults: ["lshal_defaults"],
+ srcs: [
+ "main.cpp"
+ ]
+}
+
+cc_test {
+ name: "lshal_test",
+ defaults: ["lshal_defaults"],
+ gtest: true,
+ static_libs: [
+ "libgmock"
+ ],
+ shared_libs: [
+ "android.hardware.tests.baz@1.0"
+ ],
+ srcs: [
+ "test.cpp"
+ ]
+}
diff --git a/cmds/lshal/DebugCommand.cpp b/cmds/lshal/DebugCommand.cpp
new file mode 100644
index 0000000..672cad6
--- /dev/null
+++ b/cmds/lshal/DebugCommand.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 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 "DebugCommand.h"
+
+#include "Lshal.h"
+
+namespace android {
+namespace lshal {
+
+DebugCommand::DebugCommand(Lshal &lshal) : mLshal(lshal) {
+}
+
+Status DebugCommand::parseArgs(const std::string &command, const Arg &arg) {
+ if (optind >= arg.argc) {
+ mLshal.usage(command);
+ return USAGE;
+ }
+ mInterfaceName = arg.argv[optind];
+ ++optind;
+ for (; optind < arg.argc; ++optind) {
+ mOptions.push_back(arg.argv[optind]);
+ }
+ return OK;
+}
+
+Status DebugCommand::main(const std::string &command, const Arg &arg) {
+ Status status = parseArgs(command, arg);
+ if (status != OK) {
+ return status;
+ }
+ auto pair = splitFirst(mInterfaceName, '/');
+ return mLshal.emitDebugInfo(
+ pair.first, pair.second.empty() ? "default" : pair.second, mOptions,
+ mLshal.out().buf(),
+ mLshal.err());
+}
+
+} // namespace lshal
+} // namespace android
+
diff --git a/cmds/lshal/DebugCommand.h b/cmds/lshal/DebugCommand.h
new file mode 100644
index 0000000..fa0f0fa
--- /dev/null
+++ b/cmds/lshal/DebugCommand.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 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_CMDS_LSHAL_DEBUG_COMMAND_H_
+#define FRAMEWORK_NATIVE_CMDS_LSHAL_DEBUG_COMMAND_H_
+
+#include <string>
+
+#include <android-base/macros.h>
+
+#include "utils.h"
+
+namespace android {
+namespace lshal {
+
+class Lshal;
+
+class DebugCommand {
+public:
+ DebugCommand(Lshal &lshal);
+ Status main(const std::string &command, const Arg &arg);
+private:
+ Status parseArgs(const std::string &command, const Arg &arg);
+
+ Lshal &mLshal;
+ std::string mInterfaceName;
+ std::vector<std::string> mOptions;
+
+ DISALLOW_COPY_AND_ASSIGN(DebugCommand);
+};
+
+
+} // namespace lshal
+} // namespace android
+
+#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_DEBUG_COMMAND_H_
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
new file mode 100644
index 0000000..38b406c
--- /dev/null
+++ b/cmds/lshal/ListCommand.cpp
@@ -0,0 +1,716 @@
+/*
+ * Copyright (C) 2017 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 "ListCommand.h"
+
+#include <getopt.h>
+
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <map>
+#include <sstream>
+#include <regex>
+
+#include <android-base/parseint.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <hidl-util/FQName.h>
+#include <private/android_filesystem_config.h>
+#include <sys/stat.h>
+#include <vintf/HalManifest.h>
+#include <vintf/parse_xml.h>
+
+#include "Lshal.h"
+#include "PipeRelay.h"
+#include "Timeout.h"
+#include "utils.h"
+
+using ::android::hardware::hidl_string;
+using ::android::hidl::manager::V1_0::IServiceManager;
+
+namespace android {
+namespace lshal {
+
+ListCommand::ListCommand(Lshal &lshal) : mLshal(lshal), mErr(lshal.err()), mOut(lshal.out()) {
+}
+
+std::string getCmdline(pid_t pid) {
+ std::ifstream ifs("/proc/" + std::to_string(pid) + "/cmdline");
+ std::string cmdline;
+ if (!ifs.is_open()) {
+ return "";
+ }
+ ifs >> cmdline;
+ return cmdline;
+}
+
+const std::string &ListCommand::getCmdline(pid_t pid) {
+ auto pair = mCmdlines.find(pid);
+ if (pair != mCmdlines.end()) {
+ return pair->second;
+ }
+ mCmdlines[pid] = ::android::lshal::getCmdline(pid);
+ return mCmdlines[pid];
+}
+
+void ListCommand::removeDeadProcesses(Pids *pids) {
+ static const pid_t myPid = getpid();
+ pids->erase(std::remove_if(pids->begin(), pids->end(), [this](auto pid) {
+ return pid == myPid || this->getCmdline(pid).empty();
+ }), pids->end());
+}
+
+bool ListCommand::getReferencedPids(
+ pid_t serverPid, std::map<uint64_t, Pids> *objects) const {
+
+ std::ifstream ifs("/d/binder/proc/" + std::to_string(serverPid));
+ if (!ifs.is_open()) {
+ return false;
+ }
+
+ static const std::regex prefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+");
+
+ std::string line;
+ std::smatch match;
+ while(getline(ifs, line)) {
+ if (!std::regex_search(line, match, prefix)) {
+ // the line doesn't start with the correct prefix
+ continue;
+ }
+ std::string ptrString = "0x" + match.str(2); // use number after c
+ uint64_t ptr;
+ if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
+ // Should not reach here, but just be tolerant.
+ mErr << "Could not parse number " << ptrString << std::endl;
+ continue;
+ }
+ const std::string proc = " proc ";
+ auto pos = line.rfind(proc);
+ if (pos != std::string::npos) {
+ for (const std::string &pidStr : split(line.substr(pos + proc.size()), ' ')) {
+ int32_t pid;
+ if (!::android::base::ParseInt(pidStr, &pid)) {
+ mErr << "Could not parse number " << pidStr << std::endl;
+ continue;
+ }
+ (*objects)[ptr].push_back(pid);
+ }
+ }
+ }
+ return true;
+}
+
+// Must process hwbinder services first, then passthrough services.
+void ListCommand::forEachTable(const std::function<void(Table &)> &f) {
+ f(mServicesTable);
+ f(mPassthroughRefTable);
+ f(mImplementationsTable);
+}
+void ListCommand::forEachTable(const std::function<void(const Table &)> &f) const {
+ f(mServicesTable);
+ f(mPassthroughRefTable);
+ f(mImplementationsTable);
+}
+
+void ListCommand::postprocess() {
+ forEachTable([this](Table &table) {
+ if (mSortColumn) {
+ std::sort(table.begin(), table.end(), mSortColumn);
+ }
+ for (TableEntry &entry : table) {
+ entry.serverCmdline = getCmdline(entry.serverPid);
+ removeDeadProcesses(&entry.clientPids);
+ for (auto pid : entry.clientPids) {
+ entry.clientCmdlines.push_back(this->getCmdline(pid));
+ }
+ }
+ });
+ // use a double for loop here because lshal doesn't care about efficiency.
+ for (TableEntry &packageEntry : mImplementationsTable) {
+ std::string packageName = packageEntry.interfaceName;
+ FQName fqPackageName{packageName.substr(0, packageName.find("::"))};
+ if (!fqPackageName.isValid()) {
+ continue;
+ }
+ for (TableEntry &interfaceEntry : mPassthroughRefTable) {
+ if (interfaceEntry.arch != ARCH_UNKNOWN) {
+ continue;
+ }
+ FQName interfaceName{splitFirst(interfaceEntry.interfaceName, '/').first};
+ if (!interfaceName.isValid()) {
+ continue;
+ }
+ if (interfaceName.getPackageAndVersion() == fqPackageName) {
+ interfaceEntry.arch = packageEntry.arch;
+ }
+ }
+ }
+}
+
+void ListCommand::printLine(
+ const std::string &interfaceName,
+ const std::string &transport,
+ const std::string &arch,
+ const std::string &server,
+ const std::string &serverCmdline,
+ const std::string &address, const std::string &clients,
+ const std::string &clientCmdlines) const {
+ if (mSelectedColumns & ENABLE_INTERFACE_NAME)
+ mOut << std::setw(80) << interfaceName << "\t";
+ if (mSelectedColumns & ENABLE_TRANSPORT)
+ mOut << std::setw(10) << transport << "\t";
+ if (mSelectedColumns & ENABLE_ARCH)
+ mOut << std::setw(5) << arch << "\t";
+ if (mSelectedColumns & ENABLE_SERVER_PID) {
+ if (mEnableCmdlines) {
+ mOut << std::setw(15) << serverCmdline << "\t";
+ } else {
+ mOut << std::setw(5) << server << "\t";
+ }
+ }
+ if (mSelectedColumns & ENABLE_SERVER_ADDR)
+ mOut << std::setw(16) << address << "\t";
+ if (mSelectedColumns & ENABLE_CLIENT_PIDS) {
+ if (mEnableCmdlines) {
+ mOut << std::setw(0) << clientCmdlines;
+ } else {
+ mOut << std::setw(0) << clients;
+ }
+ }
+ mOut << std::endl;
+}
+
+void ListCommand::dumpVintf() const {
+ mOut << "<!-- " << std::endl
+ << " This is a skeleton device manifest. Notes: " << std::endl
+ << " 1. android.hidl.*, android.frameworks.*, android.system.* are not included." << std::endl
+ << " 2. If a HAL is supported in both hwbinder and passthrough transport, " << std::endl
+ << " only hwbinder is shown." << std::endl
+ << " 3. It is likely that HALs in passthrough transport does not have" << std::endl
+ << " <interface> declared; users will have to write them by hand." << std::endl
+ << " 4. sepolicy version is set to 0.0. It is recommended that the entry" << std::endl
+ << " is removed from the manifest file and written by assemble_vintf" << std::endl
+ << " at build time." << std::endl
+ << "-->" << std::endl;
+
+ vintf::HalManifest manifest;
+ forEachTable([this, &manifest] (const Table &table) {
+ for (const TableEntry &entry : table) {
+
+ std::string fqInstanceName = entry.interfaceName;
+
+ if (&table == &mImplementationsTable) {
+ // Quick hack to work around *'s
+ replaceAll(&fqInstanceName, '*', 'D');
+ }
+ auto splittedFqInstanceName = splitFirst(fqInstanceName, '/');
+ FQName fqName(splittedFqInstanceName.first);
+ if (!fqName.isValid()) {
+ mErr << "Warning: '" << splittedFqInstanceName.first
+ << "' is not a valid FQName." << std::endl;
+ continue;
+ }
+ // Strip out system libs.
+ if (fqName.inPackage("android.hidl") ||
+ fqName.inPackage("android.frameworks") ||
+ fqName.inPackage("android.system")) {
+ continue;
+ }
+ std::string interfaceName =
+ &table == &mImplementationsTable ? "" : fqName.name();
+ std::string instanceName =
+ &table == &mImplementationsTable ? "" : splittedFqInstanceName.second;
+
+ vintf::Version version{fqName.getPackageMajorVersion(),
+ fqName.getPackageMinorVersion()};
+ vintf::Transport transport;
+ vintf::Arch arch;
+ if (entry.transport == "hwbinder") {
+ transport = vintf::Transport::HWBINDER;
+ arch = vintf::Arch::ARCH_EMPTY;
+ } else if (entry.transport == "passthrough") {
+ transport = vintf::Transport::PASSTHROUGH;
+ switch (entry.arch) {
+ case lshal::ARCH32:
+ arch = vintf::Arch::ARCH_32; break;
+ case lshal::ARCH64:
+ arch = vintf::Arch::ARCH_64; break;
+ case lshal::ARCH_BOTH:
+ arch = vintf::Arch::ARCH_32_64; break;
+ case lshal::ARCH_UNKNOWN: // fallthrough
+ default:
+ mErr << "Warning: '" << fqName.package()
+ << "' doesn't have bitness info, assuming 32+64." << std::endl;
+ arch = vintf::Arch::ARCH_32_64;
+ }
+ } else {
+ mErr << "Warning: '" << entry.transport << "' is not a valid transport." << std::endl;
+ continue;
+ }
+
+ bool done = false;
+ for (vintf::ManifestHal *hal : manifest.getHals(fqName.package())) {
+ if (hal->transport() != transport) {
+ if (transport != vintf::Transport::PASSTHROUGH) {
+ mErr << "Fatal: should not reach here. Generated result may be wrong."
+ << std::endl;
+ }
+ done = true;
+ break;
+ }
+ if (hal->hasVersion(version)) {
+ if (&table != &mImplementationsTable) {
+ hal->interfaces[interfaceName].name = interfaceName;
+ hal->interfaces[interfaceName].instances.insert(instanceName);
+ }
+ done = true;
+ break;
+ }
+ }
+ if (done) {
+ continue; // to next TableEntry
+ }
+ decltype(vintf::ManifestHal::interfaces) interfaces;
+ if (&table != &mImplementationsTable) {
+ interfaces[interfaceName].name = interfaceName;
+ interfaces[interfaceName].instances.insert(instanceName);
+ }
+ if (!manifest.add(vintf::ManifestHal{
+ .format = vintf::HalFormat::HIDL,
+ .name = fqName.package(),
+ .versions = {version},
+ .transportArch = {transport, arch},
+ .interfaces = interfaces})) {
+ mErr << "Warning: cannot add hal '" << fqInstanceName << "'" << std::endl;
+ }
+ }
+ });
+ mOut << vintf::gHalManifestConverter(manifest);
+}
+
+static const std::string &getArchString(Architecture arch) {
+ static const std::string sStr64 = "64";
+ static const std::string sStr32 = "32";
+ static const std::string sStrBoth = "32+64";
+ static const std::string sStrUnknown = "";
+ switch (arch) {
+ case ARCH64:
+ return sStr64;
+ case ARCH32:
+ return sStr32;
+ case ARCH_BOTH:
+ return sStrBoth;
+ case ARCH_UNKNOWN: // fall through
+ default:
+ return sStrUnknown;
+ }
+}
+
+static Architecture fromBaseArchitecture(::android::hidl::base::V1_0::DebugInfo::Architecture a) {
+ switch (a) {
+ case ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_64BIT:
+ return ARCH64;
+ case ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_32BIT:
+ return ARCH32;
+ case ::android::hidl::base::V1_0::DebugInfo::Architecture::UNKNOWN: // fallthrough
+ default:
+ return ARCH_UNKNOWN;
+ }
+}
+
+void ListCommand::dumpTable() {
+ mServicesTable.description =
+ "All binderized services (registered services through hwservicemanager)";
+ mPassthroughRefTable.description =
+ "All interfaces that getService() has ever return as a passthrough interface;\n"
+ "PIDs / processes shown below might be inaccurate because the process\n"
+ "might have relinquished the interface or might have died.\n"
+ "The Server / Server CMD column can be ignored.\n"
+ "The Clients / Clients CMD column shows all process that have ever dlopen'ed \n"
+ "the library and successfully fetched the passthrough implementation.";
+ mImplementationsTable.description =
+ "All available passthrough implementations (all -impl.so files)";
+ forEachTable([this] (const Table &table) {
+ if (!mNeat) {
+ mOut << table.description << std::endl;
+ }
+ mOut << std::left;
+ if (!mNeat) {
+ printLine("Interface", "Transport", "Arch", "Server", "Server CMD",
+ "PTR", "Clients", "Clients CMD");
+ }
+
+ for (const auto &entry : table) {
+ printLine(entry.interfaceName,
+ entry.transport,
+ getArchString(entry.arch),
+ entry.serverPid == NO_PID ? "N/A" : std::to_string(entry.serverPid),
+ entry.serverCmdline,
+ entry.serverObjectAddress == NO_PTR ? "N/A" : toHexString(entry.serverObjectAddress),
+ join(entry.clientPids, " "),
+ join(entry.clientCmdlines, ";"));
+
+ // We're only interested in dumping debug info for already
+ // instantiated services. There's little value in dumping the
+ // debug info for a service we create on the fly, so we only operate
+ // on the "mServicesTable".
+ if (mEmitDebugInfo && &table == &mServicesTable) {
+ auto pair = splitFirst(entry.interfaceName, '/');
+ mLshal.emitDebugInfo(pair.first, pair.second, {}, mOut.buf(),
+ NullableOStream<std::ostream>(nullptr));
+ }
+ }
+ if (!mNeat) {
+ mOut << std::endl;
+ }
+ });
+
+}
+
+void ListCommand::dump() {
+ if (mVintf) {
+ dumpVintf();
+ if (!!mFileOutput) {
+ mFileOutput.buf().close();
+ delete &mFileOutput.buf();
+ mFileOutput = nullptr;
+ }
+ mOut = std::cout;
+ } else {
+ dumpTable();
+ }
+}
+
+void ListCommand::putEntry(TableEntrySource source, TableEntry &&entry) {
+ Table *table = nullptr;
+ switch (source) {
+ case HWSERVICEMANAGER_LIST :
+ table = &mServicesTable; break;
+ case PTSERVICEMANAGER_REG_CLIENT :
+ table = &mPassthroughRefTable; break;
+ case LIST_DLLIB :
+ table = &mImplementationsTable; break;
+ default:
+ mErr << "Error: Unknown source of entry " << source << std::endl;
+ }
+ if (table) {
+ table->entries.push_back(std::forward<TableEntry>(entry));
+ }
+}
+
+Status ListCommand::fetchAllLibraries(const sp<IServiceManager> &manager) {
+ using namespace ::android::hardware;
+ using namespace ::android::hidl::manager::V1_0;
+ using namespace ::android::hidl::base::V1_0;
+ auto ret = timeoutIPC(manager, &IServiceManager::debugDump, [&] (const auto &infos) {
+ std::map<std::string, TableEntry> entries;
+ for (const auto &info : infos) {
+ std::string interfaceName = std::string{info.interfaceName.c_str()} + "/" +
+ std::string{info.instanceName.c_str()};
+ entries.emplace(interfaceName, TableEntry{
+ .interfaceName = interfaceName,
+ .transport = "passthrough",
+ .serverPid = NO_PID,
+ .serverObjectAddress = NO_PTR,
+ .clientPids = {},
+ .arch = ARCH_UNKNOWN
+ }).first->second.arch |= fromBaseArchitecture(info.arch);
+ }
+ for (auto &&pair : entries) {
+ putEntry(LIST_DLLIB, std::move(pair.second));
+ }
+ });
+ if (!ret.isOk()) {
+ mErr << "Error: Failed to call list on getPassthroughServiceManager(): "
+ << ret.description() << std::endl;
+ return DUMP_ALL_LIBS_ERROR;
+ }
+ return OK;
+}
+
+Status ListCommand::fetchPassthrough(const sp<IServiceManager> &manager) {
+ using namespace ::android::hardware;
+ using namespace ::android::hardware::details;
+ using namespace ::android::hidl::manager::V1_0;
+ using namespace ::android::hidl::base::V1_0;
+ auto ret = timeoutIPC(manager, &IServiceManager::debugDump, [&] (const auto &infos) {
+ for (const auto &info : infos) {
+ if (info.clientPids.size() <= 0) {
+ continue;
+ }
+ putEntry(PTSERVICEMANAGER_REG_CLIENT, {
+ .interfaceName =
+ std::string{info.interfaceName.c_str()} + "/" +
+ std::string{info.instanceName.c_str()},
+ .transport = "passthrough",
+ .serverPid = info.clientPids.size() == 1 ? info.clientPids[0] : NO_PID,
+ .serverObjectAddress = NO_PTR,
+ .clientPids = info.clientPids,
+ .arch = fromBaseArchitecture(info.arch)
+ });
+ }
+ });
+ if (!ret.isOk()) {
+ mErr << "Error: Failed to call debugDump on defaultServiceManager(): "
+ << ret.description() << std::endl;
+ return DUMP_PASSTHROUGH_ERROR;
+ }
+ return OK;
+}
+
+Status ListCommand::fetchBinderized(const sp<IServiceManager> &manager) {
+ using namespace ::std;
+ using namespace ::android::hardware;
+ using namespace ::android::hidl::manager::V1_0;
+ using namespace ::android::hidl::base::V1_0;
+ const std::string mode = "hwbinder";
+
+ hidl_vec<hidl_string> fqInstanceNames;
+ // copying out for timeoutIPC
+ auto listRet = timeoutIPC(manager, &IServiceManager::list, [&] (const auto &names) {
+ fqInstanceNames = names;
+ });
+ if (!listRet.isOk()) {
+ mErr << "Error: Failed to list services for " << mode << ": "
+ << listRet.description() << std::endl;
+ return DUMP_BINDERIZED_ERROR;
+ }
+
+ Status status = OK;
+ // server pid, .ptr value of binder object, child pids
+ std::map<std::string, DebugInfo> allDebugInfos;
+ std::map<pid_t, std::map<uint64_t, Pids>> allPids;
+ for (const auto &fqInstanceName : fqInstanceNames) {
+ const auto pair = splitFirst(fqInstanceName, '/');
+ const auto &serviceName = pair.first;
+ const auto &instanceName = pair.second;
+ auto getRet = timeoutIPC(manager, &IServiceManager::get, serviceName, instanceName);
+ if (!getRet.isOk()) {
+ mErr << "Warning: Skipping \"" << fqInstanceName << "\": "
+ << "cannot be fetched from service manager:"
+ << getRet.description() << std::endl;
+ status |= DUMP_BINDERIZED_ERROR;
+ continue;
+ }
+ sp<IBase> service = getRet;
+ if (service == nullptr) {
+ mErr << "Warning: Skipping \"" << fqInstanceName << "\": "
+ << "cannot be fetched from service manager (null)"
+ << std::endl;
+ status |= DUMP_BINDERIZED_ERROR;
+ continue;
+ }
+ auto debugRet = timeoutIPC(service, &IBase::getDebugInfo, [&] (const auto &debugInfo) {
+ allDebugInfos[fqInstanceName] = debugInfo;
+ if (debugInfo.pid >= 0) {
+ allPids[static_cast<pid_t>(debugInfo.pid)].clear();
+ }
+ });
+ if (!debugRet.isOk()) {
+ mErr << "Warning: Skipping \"" << fqInstanceName << "\": "
+ << "debugging information cannot be retrieved:"
+ << debugRet.description() << std::endl;
+ status |= DUMP_BINDERIZED_ERROR;
+ }
+ }
+ for (auto &pair : allPids) {
+ pid_t serverPid = pair.first;
+ if (!getReferencedPids(serverPid, &allPids[serverPid])) {
+ mErr << "Warning: no information for PID " << serverPid
+ << ", are you root?" << std::endl;
+ status |= DUMP_BINDERIZED_ERROR;
+ }
+ }
+ for (const auto &fqInstanceName : fqInstanceNames) {
+ auto it = allDebugInfos.find(fqInstanceName);
+ if (it == allDebugInfos.end()) {
+ putEntry(HWSERVICEMANAGER_LIST, {
+ .interfaceName = fqInstanceName,
+ .transport = mode,
+ .serverPid = NO_PID,
+ .serverObjectAddress = NO_PTR,
+ .clientPids = {},
+ .arch = ARCH_UNKNOWN
+ });
+ continue;
+ }
+ const DebugInfo &info = it->second;
+ putEntry(HWSERVICEMANAGER_LIST, {
+ .interfaceName = fqInstanceName,
+ .transport = mode,
+ .serverPid = info.pid,
+ .serverObjectAddress = info.ptr,
+ .clientPids = info.pid == NO_PID || info.ptr == NO_PTR
+ ? Pids{} : allPids[info.pid][info.ptr],
+ .arch = fromBaseArchitecture(info.arch),
+ });
+ }
+ return status;
+}
+
+Status ListCommand::fetch() {
+ Status status = OK;
+ auto bManager = mLshal.serviceManager();
+ if (bManager == nullptr) {
+ mErr << "Failed to get defaultServiceManager()!" << std::endl;
+ status |= NO_BINDERIZED_MANAGER;
+ } else {
+ status |= fetchBinderized(bManager);
+ // Passthrough PIDs are registered to the binderized manager as well.
+ status |= fetchPassthrough(bManager);
+ }
+
+ auto pManager = mLshal.passthroughManager();
+ if (pManager == nullptr) {
+ mErr << "Failed to get getPassthroughServiceManager()!" << std::endl;
+ status |= NO_PASSTHROUGH_MANAGER;
+ } else {
+ status |= fetchAllLibraries(pManager);
+ }
+ return status;
+}
+
+Status ListCommand::parseArgs(const std::string &command, const Arg &arg) {
+ static struct option longOptions[] = {
+ // long options with short alternatives
+ {"help", no_argument, 0, 'h' },
+ {"interface", no_argument, 0, 'i' },
+ {"transport", no_argument, 0, 't' },
+ {"arch", no_argument, 0, 'r' },
+ {"pid", no_argument, 0, 'p' },
+ {"address", no_argument, 0, 'a' },
+ {"clients", no_argument, 0, 'c' },
+ {"cmdline", no_argument, 0, 'm' },
+ {"debug", optional_argument, 0, 'd' },
+
+ // long options without short alternatives
+ {"sort", required_argument, 0, 's' },
+ {"init-vintf",optional_argument, 0, 'v' },
+ {"neat", no_argument, 0, 'n' },
+ { 0, 0, 0, 0 }
+ };
+
+ int optionIndex;
+ int c;
+ // Lshal::parseArgs has set optind to the next option to parse
+ for (;;) {
+ // using getopt_long in case we want to add other options in the future
+ c = getopt_long(arg.argc, arg.argv,
+ "hitrpacmd", longOptions, &optionIndex);
+ if (c == -1) {
+ break;
+ }
+ switch (c) {
+ case 's': {
+ if (strcmp(optarg, "interface") == 0 || strcmp(optarg, "i") == 0) {
+ mSortColumn = TableEntry::sortByInterfaceName;
+ } else if (strcmp(optarg, "pid") == 0 || strcmp(optarg, "p") == 0) {
+ mSortColumn = TableEntry::sortByServerPid;
+ } else {
+ mErr << "Unrecognized sorting column: " << optarg << std::endl;
+ mLshal.usage(command);
+ return USAGE;
+ }
+ break;
+ }
+ case 'v': {
+ if (optarg) {
+ mFileOutput = new std::ofstream{optarg};
+ mOut = mFileOutput;
+ if (!mFileOutput.buf().is_open()) {
+ mErr << "Could not open file '" << optarg << "'." << std::endl;
+ return IO_ERROR;
+ }
+ }
+ mVintf = true;
+ }
+ case 'i': {
+ mSelectedColumns |= ENABLE_INTERFACE_NAME;
+ break;
+ }
+ case 't': {
+ mSelectedColumns |= ENABLE_TRANSPORT;
+ break;
+ }
+ case 'r': {
+ mSelectedColumns |= ENABLE_ARCH;
+ break;
+ }
+ case 'p': {
+ mSelectedColumns |= ENABLE_SERVER_PID;
+ break;
+ }
+ case 'a': {
+ mSelectedColumns |= ENABLE_SERVER_ADDR;
+ break;
+ }
+ case 'c': {
+ mSelectedColumns |= ENABLE_CLIENT_PIDS;
+ break;
+ }
+ case 'm': {
+ mEnableCmdlines = true;
+ break;
+ }
+ case 'd': {
+ mEmitDebugInfo = true;
+
+ if (optarg) {
+ mFileOutput = new std::ofstream{optarg};
+ mOut = mFileOutput;
+ if (!mFileOutput.buf().is_open()) {
+ mErr << "Could not open file '" << optarg << "'." << std::endl;
+ return IO_ERROR;
+ }
+ chown(optarg, AID_SHELL, AID_SHELL);
+ }
+ break;
+ }
+ case 'n': {
+ mNeat = true;
+ break;
+ }
+ case 'h': // falls through
+ default: // see unrecognized options
+ mLshal.usage(command);
+ return USAGE;
+ }
+ }
+ if (optind < arg.argc) {
+ // see non option
+ mErr << "Unrecognized option `" << arg.argv[optind] << "`" << std::endl;
+ }
+
+ if (mSelectedColumns == 0) {
+ mSelectedColumns = ENABLE_INTERFACE_NAME | ENABLE_SERVER_PID | ENABLE_CLIENT_PIDS;
+ }
+ return OK;
+}
+
+Status ListCommand::main(const std::string &command, const Arg &arg) {
+ Status status = parseArgs(command, arg);
+ if (status != OK) {
+ return status;
+ }
+ status = fetch();
+ postprocess();
+ dump();
+ return status;
+}
+
+} // namespace lshal
+} // namespace android
+
diff --git a/cmds/lshal/ListCommand.h b/cmds/lshal/ListCommand.h
new file mode 100644
index 0000000..f367d7f
--- /dev/null
+++ b/cmds/lshal/ListCommand.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2017 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_CMDS_LSHAL_LIST_COMMAND_H_
+#define FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_
+
+#include <stdint.h>
+
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include <android-base/macros.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
+
+#include "NullableOStream.h"
+#include "TableEntry.h"
+#include "utils.h"
+
+namespace android {
+namespace lshal {
+
+class Lshal;
+
+class ListCommand {
+public:
+ ListCommand(Lshal &lshal);
+ Status main(const std::string &command, const Arg &arg);
+private:
+ Status parseArgs(const std::string &command, const Arg &arg);
+ Status fetch();
+ void postprocess();
+ void dump();
+ void putEntry(TableEntrySource source, TableEntry &&entry);
+ Status fetchPassthrough(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
+ Status fetchBinderized(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
+ Status fetchAllLibraries(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
+ bool getReferencedPids(
+ pid_t serverPid, std::map<uint64_t, Pids> *objects) const;
+ void dumpTable();
+ void dumpVintf() const;
+ void printLine(
+ const std::string &interfaceName,
+ const std::string &transport,
+ const std::string &arch,
+ const std::string &server,
+ const std::string &serverCmdline,
+ const std::string &address, const std::string &clients,
+ const std::string &clientCmdlines) const ;
+ // Return /proc/{pid}/cmdline if it exists, else empty string.
+ const std::string &getCmdline(pid_t pid);
+ // Call getCmdline on all pid in pids. If it returns empty string, the process might
+ // have died, and the pid is removed from pids.
+ void removeDeadProcesses(Pids *pids);
+ void forEachTable(const std::function<void(Table &)> &f);
+ void forEachTable(const std::function<void(const Table &)> &f) const;
+
+ Lshal &mLshal;
+
+ Table mServicesTable{};
+ Table mPassthroughRefTable{};
+ Table mImplementationsTable{};
+
+ NullableOStream<std::ostream> mErr;
+ NullableOStream<std::ostream> mOut;
+ NullableOStream<std::ofstream> mFileOutput = nullptr;
+ TableEntryCompare mSortColumn = nullptr;
+ TableEntrySelect mSelectedColumns = 0;
+ // If true, cmdlines will be printed instead of pid.
+ bool mEnableCmdlines = false;
+
+ // If true, calls IBase::debug(...) on each service.
+ bool mEmitDebugInfo = false;
+
+ // If true, output in VINTF format.
+ bool mVintf = false;
+
+ // If true, explanatory text are not emitted.
+ bool mNeat = false;
+
+ // If an entry does not exist, need to ask /proc/{pid}/cmdline to get it.
+ // If an entry exist but is an empty string, process might have died.
+ // If an entry exist and not empty, it contains the cached content of /proc/{pid}/cmdline.
+ std::map<pid_t, std::string> mCmdlines;
+
+ DISALLOW_COPY_AND_ASSIGN(ListCommand);
+};
+
+
+} // namespace lshal
+} // namespace android
+
+#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
new file mode 100644
index 0000000..9db42f1
--- /dev/null
+++ b/cmds/lshal/Lshal.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2017 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 "lshal"
+#include <android-base/logging.h>
+
+#include "Lshal.h"
+
+#include <set>
+#include <string>
+
+#include <hidl/ServiceManagement.h>
+
+#include "DebugCommand.h"
+#include "ListCommand.h"
+#include "PipeRelay.h"
+
+namespace android {
+namespace lshal {
+
+using ::android::hidl::manager::V1_0::IServiceManager;
+
+Lshal::Lshal()
+ : mOut(std::cout), mErr(std::cerr),
+ mServiceManager(::android::hardware::defaultServiceManager()),
+ mPassthroughManager(::android::hardware::getPassthroughServiceManager()) {
+}
+
+Lshal::Lshal(std::ostream &out, std::ostream &err,
+ sp<hidl::manager::V1_0::IServiceManager> serviceManager,
+ sp<hidl::manager::V1_0::IServiceManager> passthroughManager)
+ : mOut(out), mErr(err),
+ mServiceManager(serviceManager),
+ mPassthroughManager(passthroughManager) {
+
+}
+
+void Lshal::usage(const std::string &command) const {
+ static const std::string helpSummary =
+ "lshal: List and debug HALs.\n"
+ "\n"
+ "commands:\n"
+ " help Print help message\n"
+ " list list HALs\n"
+ " debug debug a specified HAL\n"
+ "\n"
+ "If no command is specified, `list` is the default.\n";
+
+ static const std::string list =
+ "list:\n"
+ " lshal\n"
+ " lshal list\n"
+ " List all hals with default ordering and columns (`lshal list -ipc`)\n"
+ " lshal list [-h|--help]\n"
+ " -h, --help: Print help message for list (`lshal help list`)\n"
+ " lshal [list] [--interface|-i] [--transport|-t] [-r|--arch]\n"
+ " [--pid|-p] [--address|-a] [--clients|-c] [--cmdline|-m]\n"
+ " [--sort={interface|i|pid|p}] [--init-vintf[=<output file>]]\n"
+ " [--debug|-d[=<output file>]]\n"
+ " -i, --interface: print the interface name column\n"
+ " -n, --instance: print the instance name column\n"
+ " -t, --transport: print the transport mode column\n"
+ " -r, --arch: print if the HAL is in 64-bit or 32-bit\n"
+ " -p, --pid: print the server PID, or server cmdline if -m is set\n"
+ " -a, --address: print the server object address column\n"
+ " -c, --clients: print the client PIDs, or client cmdlines if -m is set\n"
+ " -m, --cmdline: print cmdline instead of PIDs\n"
+ " -d[=<output file>], --debug[=<output file>]: emit debug info from \n"
+ " IBase::debug with empty options\n"
+ " --sort=i, --sort=interface: sort by interface name\n"
+ " --sort=p, --sort=pid: sort by server pid\n"
+ " --init-vintf=<output file>: form a skeleton HAL manifest to specified\n"
+ " file, or stdout if no file specified.\n";
+
+ static const std::string debug =
+ "debug:\n"
+ " lshal debug <interface> [options [options [...]]] \n"
+ " Print debug information of a specified interface.\n"
+ " <inteface>: Format is `android.hardware.foo@1.0::IFoo/default`.\n"
+ " If instance name is missing `default` is used.\n"
+ " options: space separated options to IBase::debug.\n";
+
+ static const std::string help =
+ "help:\n"
+ " lshal -h\n"
+ " lshal --help\n"
+ " lshal help\n"
+ " Print this help message\n"
+ " lshal help list\n"
+ " Print help message for list\n"
+ " lshal help debug\n"
+ " Print help message for debug\n";
+
+ if (command == "list") {
+ mErr << list;
+ return;
+ }
+ if (command == "debug") {
+ mErr << debug;
+ return;
+ }
+
+ mErr << helpSummary << "\n" << list << "\n" << debug << "\n" << help;
+}
+
+// A unique_ptr type using a custom deleter function.
+template<typename T>
+using deleted_unique_ptr = std::unique_ptr<T, std::function<void(T *)> >;
+
+static hardware::hidl_vec<hardware::hidl_string> convert(const std::vector<std::string> &v) {
+ hardware::hidl_vec<hardware::hidl_string> hv;
+ hv.resize(v.size());
+ for (size_t i = 0; i < v.size(); ++i) {
+ hv[i].setToExternal(v[i].c_str(), v[i].size());
+ }
+ return hv;
+}
+
+Status Lshal::emitDebugInfo(
+ const std::string &interfaceName,
+ const std::string &instanceName,
+ const std::vector<std::string> &options,
+ std::ostream &out,
+ NullableOStream<std::ostream> err) const {
+ using android::hidl::base::V1_0::IBase;
+
+ hardware::Return<sp<IBase>> retBase = serviceManager()->get(interfaceName, instanceName);
+
+ if (!retBase.isOk()) {
+ std::string msg = "Cannot get " + interfaceName + "/" + instanceName + ": "
+ + retBase.description();
+ err << msg << std::endl;
+ LOG(ERROR) << msg;
+ return TRANSACTION_ERROR;
+ }
+
+ sp<IBase> base = retBase;
+ if (base == nullptr) {
+ std::string msg = interfaceName + "/" + instanceName + " does not exist, or "
+ + "no permission to connect.";
+ err << msg << std::endl;
+ LOG(ERROR) << msg;
+ return NO_INTERFACE;
+ }
+
+ PipeRelay relay(out);
+
+ if (relay.initCheck() != OK) {
+ std::string msg = "PipeRelay::initCheck() FAILED w/ " + std::to_string(relay.initCheck());
+ err << msg << std::endl;
+ LOG(ERROR) << msg;
+ return IO_ERROR;
+ }
+
+ deleted_unique_ptr<native_handle_t> fdHandle(
+ native_handle_create(1 /* numFds */, 0 /* numInts */),
+ native_handle_delete);
+
+ fdHandle->data[0] = relay.fd();
+
+ hardware::Return<void> ret = base->debug(fdHandle.get(), convert(options));
+
+ if (!ret.isOk()) {
+ std::string msg = "debug() FAILED on " + interfaceName + "/" + instanceName + ": "
+ + ret.description();
+ err << msg << std::endl;
+ LOG(ERROR) << msg;
+ return TRANSACTION_ERROR;
+ }
+ return OK;
+}
+
+Status Lshal::parseArgs(const Arg &arg) {
+ static std::set<std::string> sAllCommands{"list", "debug", "help"};
+ optind = 1;
+ if (optind >= arg.argc) {
+ // no options at all.
+ return OK;
+ }
+ mCommand = arg.argv[optind];
+ if (sAllCommands.find(mCommand) != sAllCommands.end()) {
+ ++optind;
+ return OK; // mCommand is set correctly
+ }
+
+ if (mCommand.size() > 0 && mCommand[0] == '-') {
+ // first argument is an option, set command to "" (which is recognized as "list")
+ mCommand = "";
+ return OK;
+ }
+
+ mErr << arg.argv[0] << ": unrecognized option `" << arg.argv[optind] << "`" << std::endl;
+ usage();
+ return USAGE;
+}
+
+void signalHandler(int sig) {
+ if (sig == SIGINT) {
+ int retVal;
+ pthread_exit(&retVal);
+ }
+}
+
+Status Lshal::main(const Arg &arg) {
+ // Allow SIGINT to terminate all threads.
+ signal(SIGINT, signalHandler);
+
+ Status status = parseArgs(arg);
+ if (status != OK) {
+ return status;
+ }
+ if (mCommand == "help") {
+ usage(optind < arg.argc ? arg.argv[optind] : "");
+ return USAGE;
+ }
+ // Default command is list
+ if (mCommand == "list" || mCommand == "") {
+ return ListCommand{*this}.main(mCommand, arg);
+ }
+ if (mCommand == "debug") {
+ return DebugCommand{*this}.main(mCommand, arg);
+ }
+ usage();
+ return USAGE;
+}
+
+NullableOStream<std::ostream> Lshal::err() const {
+ return mErr;
+}
+NullableOStream<std::ostream> Lshal::out() const {
+ return mOut;
+}
+
+const sp<IServiceManager> &Lshal::serviceManager() const {
+ return mServiceManager;
+}
+
+const sp<IServiceManager> &Lshal::passthroughManager() const {
+ return mPassthroughManager;
+}
+
+} // namespace lshal
+} // namespace android
diff --git a/cmds/lshal/Lshal.h b/cmds/lshal/Lshal.h
new file mode 100644
index 0000000..00db5d0
--- /dev/null
+++ b/cmds/lshal/Lshal.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2017 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_CMDS_LSHAL_LSHAL_H_
+#define FRAMEWORK_NATIVE_CMDS_LSHAL_LSHAL_H_
+
+#include <iostream>
+#include <string>
+
+#include <android-base/macros.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <utils/StrongPointer.h>
+
+#include "NullableOStream.h"
+#include "utils.h"
+
+namespace android {
+namespace lshal {
+
+class Lshal {
+public:
+ Lshal();
+ Lshal(std::ostream &out, std::ostream &err,
+ sp<hidl::manager::V1_0::IServiceManager> serviceManager,
+ sp<hidl::manager::V1_0::IServiceManager> passthroughManager);
+ Status main(const Arg &arg);
+ void usage(const std::string &command = "") const;
+ NullableOStream<std::ostream> err() const;
+ NullableOStream<std::ostream> out() const;
+ const sp<hidl::manager::V1_0::IServiceManager> &serviceManager() const;
+ const sp<hidl::manager::V1_0::IServiceManager> &passthroughManager() const;
+
+ Status emitDebugInfo(
+ const std::string &interfaceName,
+ const std::string &instanceName,
+ const std::vector<std::string> &options,
+ std::ostream &out,
+ NullableOStream<std::ostream> err) const;
+private:
+ Status parseArgs(const Arg &arg);
+ std::string mCommand;
+ Arg mCmdArgs;
+ NullableOStream<std::ostream> mOut;
+ NullableOStream<std::ostream> mErr;
+
+ sp<hidl::manager::V1_0::IServiceManager> mServiceManager;
+ sp<hidl::manager::V1_0::IServiceManager> mPassthroughManager;
+
+ DISALLOW_COPY_AND_ASSIGN(Lshal);
+};
+
+} // namespace lshal
+} // namespace android
+
+#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_LSHAL_H_
diff --git a/cmds/lshal/NullableOStream.h b/cmds/lshal/NullableOStream.h
new file mode 100644
index 0000000..ab37a04
--- /dev/null
+++ b/cmds/lshal/NullableOStream.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_NULLABLE_O_STREAM_H_
+#define FRAMEWORK_NATIVE_CMDS_LSHAL_NULLABLE_O_STREAM_H_
+
+#include <iostream>
+
+namespace android {
+namespace lshal {
+
+template<typename S>
+class NullableOStream {
+public:
+ NullableOStream(S &os) : mOs(&os) {}
+ NullableOStream(S *os) : mOs(os) {}
+ NullableOStream &operator=(S &os) {
+ mOs = &os;
+ return *this;
+ }
+ NullableOStream &operator=(S *os) {
+ mOs = os;
+ return *this;
+ }
+ template<typename Other>
+ NullableOStream &operator=(const NullableOStream<Other> &other) {
+ mOs = other.mOs;
+ return *this;
+ }
+
+ const NullableOStream &operator<<(std::ostream& (*pf)(std::ostream&)) const {
+ if (mOs) {
+ (*mOs) << pf;
+ }
+ return *this;
+ }
+ template<typename T>
+ const NullableOStream &operator<<(const T &rhs) const {
+ if (mOs) {
+ (*mOs) << rhs;
+ }
+ return *this;
+ }
+ S& buf() const {
+ return *mOs;
+ }
+ operator bool() const {
+ return mOs != nullptr;
+ }
+private:
+ template<typename>
+ friend class NullableOStream;
+
+ S *mOs = nullptr;
+};
+
+} // namespace lshal
+} // namespace android
+
+#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_NULLABLE_O_STREAM_H_
diff --git a/cmds/lshal/PipeRelay.cpp b/cmds/lshal/PipeRelay.cpp
new file mode 100644
index 0000000..54d19f6
--- /dev/null
+++ b/cmds/lshal/PipeRelay.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2017 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 "PipeRelay.h"
+
+#include <sys/socket.h>
+#include <utils/Thread.h>
+
+namespace android {
+namespace lshal {
+
+struct PipeRelay::RelayThread : public Thread {
+ explicit RelayThread(int fd, std::ostream &os);
+
+ bool threadLoop() override;
+
+private:
+ int mFd;
+ std::ostream &mOutStream;
+
+ DISALLOW_COPY_AND_ASSIGN(RelayThread);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+PipeRelay::RelayThread::RelayThread(int fd, std::ostream &os)
+ : mFd(fd),
+ mOutStream(os) {
+}
+
+bool PipeRelay::RelayThread::threadLoop() {
+ char buffer[1024];
+ ssize_t n = read(mFd, buffer, sizeof(buffer));
+
+ if (n <= 0) {
+ return false;
+ }
+
+ mOutStream.write(buffer, n);
+
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+PipeRelay::PipeRelay(std::ostream &os)
+ : mOutStream(os),
+ mInitCheck(NO_INIT) {
+ int res = socketpair(AF_UNIX, SOCK_STREAM, 0 /* protocol */, mFds);
+
+ if (res < 0) {
+ mInitCheck = -errno;
+ return;
+ }
+
+ mThread = new RelayThread(mFds[0], os);
+ mInitCheck = mThread->run("RelayThread");
+}
+
+void PipeRelay::CloseFd(int *fd) {
+ if (*fd >= 0) {
+ close(*fd);
+ *fd = -1;
+ }
+}
+
+PipeRelay::~PipeRelay() {
+ if (mFds[1] >= 0) {
+ shutdown(mFds[1], SHUT_WR);
+ }
+
+ if (mFds[0] >= 0) {
+ shutdown(mFds[0], SHUT_RD);
+ }
+
+ if (mThread != NULL) {
+ mThread->join();
+ mThread.clear();
+ }
+
+ CloseFd(&mFds[1]);
+ CloseFd(&mFds[0]);
+}
+
+status_t PipeRelay::initCheck() const {
+ return mInitCheck;
+}
+
+int PipeRelay::fd() const {
+ return mFds[1];
+}
+
+} // namespace lshal
+} // namespace android
diff --git a/cmds/lshal/PipeRelay.h b/cmds/lshal/PipeRelay.h
new file mode 100644
index 0000000..76b2b23
--- /dev/null
+++ b/cmds/lshal/PipeRelay.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2017 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 FRAMEWORKS_NATIVE_CMDS_LSHAL_PIPE_RELAY_H_
+
+#define FRAMEWORKS_NATIVE_CMDS_LSHAL_PIPE_RELAY_H_
+
+#include <android-base/macros.h>
+#include <ostream>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+namespace android {
+namespace lshal {
+
+/* Creates an AF_UNIX socketpair and spawns a thread that relays any data
+ * written to the "write"-end of the pair to the specified output stream "os".
+ */
+struct PipeRelay {
+ explicit PipeRelay(std::ostream &os);
+ ~PipeRelay();
+
+ status_t initCheck() const;
+
+ // Returns the file descriptor corresponding to the "write"-end of the
+ // connection.
+ int fd() const;
+
+private:
+ struct RelayThread;
+
+ std::ostream &mOutStream;
+ status_t mInitCheck;
+ int mFds[2];
+ sp<RelayThread> mThread;
+
+ static void CloseFd(int *fd);
+
+ DISALLOW_COPY_AND_ASSIGN(PipeRelay);
+};
+
+} // namespace lshal
+} // namespace android
+
+#endif // FRAMEWORKS_NATIVE_CMDS_LSHAL_PIPE_RELAY_H_
+
diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h
new file mode 100644
index 0000000..9ae8f78
--- /dev/null
+++ b/cmds/lshal/TableEntry.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_TABLE_ENTRY_H_
+#define FRAMEWORK_NATIVE_CMDS_LSHAL_TABLE_ENTRY_H_
+
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+#include <iostream>
+
+namespace android {
+namespace lshal {
+
+using Pids = std::vector<int32_t>;
+
+enum : unsigned int {
+ HWSERVICEMANAGER_LIST, // through defaultServiceManager()->list()
+ PTSERVICEMANAGER_REG_CLIENT, // through registerPassthroughClient
+ LIST_DLLIB, // through listing dynamic libraries
+};
+using TableEntrySource = unsigned int;
+
+enum : unsigned int {
+ ARCH_UNKNOWN = 0,
+ ARCH32 = 1 << 0,
+ ARCH64 = 1 << 1,
+ ARCH_BOTH = ARCH32 | ARCH64
+};
+using Architecture = unsigned int;
+
+struct TableEntry {
+ std::string interfaceName;
+ std::string transport;
+ int32_t serverPid;
+ std::string serverCmdline;
+ uint64_t serverObjectAddress;
+ Pids clientPids;
+ std::vector<std::string> clientCmdlines;
+ Architecture arch;
+
+ static bool sortByInterfaceName(const TableEntry &a, const TableEntry &b) {
+ return a.interfaceName < b.interfaceName;
+ };
+ static bool sortByServerPid(const TableEntry &a, const TableEntry &b) {
+ return a.serverPid < b.serverPid;
+ };
+};
+
+struct Table {
+ using Entries = std::vector<TableEntry>;
+ std::string description;
+ Entries entries;
+
+ Entries::iterator begin() { return entries.begin(); }
+ Entries::const_iterator begin() const { return entries.begin(); }
+ Entries::iterator end() { return entries.end(); }
+ Entries::const_iterator end() const { return entries.end(); }
+};
+
+using TableEntryCompare = std::function<bool(const TableEntry &, const TableEntry &)>;
+
+enum : unsigned int {
+ ENABLE_INTERFACE_NAME = 1 << 0,
+ ENABLE_TRANSPORT = 1 << 1,
+ ENABLE_SERVER_PID = 1 << 2,
+ ENABLE_SERVER_ADDR = 1 << 3,
+ ENABLE_CLIENT_PIDS = 1 << 4,
+ ENABLE_ARCH = 1 << 5
+};
+
+using TableEntrySelect = unsigned int;
+
+enum {
+ NO_PID = -1,
+ NO_PTR = 0
+};
+
+} // namespace lshal
+} // namespace android
+
+#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_TABLE_ENTRY_H_
diff --git a/cmds/lshal/Timeout.h b/cmds/lshal/Timeout.h
new file mode 100644
index 0000000..ca477bf
--- /dev/null
+++ b/cmds/lshal/Timeout.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <condition_variable>
+#include <chrono>
+#include <functional>
+#include <mutex>
+#include <thread>
+
+#include <hidl/Status.h>
+
+namespace android {
+namespace lshal {
+
+static constexpr std::chrono::milliseconds IPC_CALL_WAIT{500};
+
+class BackgroundTaskState {
+public:
+ BackgroundTaskState(std::function<void(void)> &&func)
+ : mFunc(std::forward<decltype(func)>(func)) {}
+ void notify() {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mFinished = true;
+ lock.unlock();
+ mCondVar.notify_all();
+ }
+ template<class C, class D>
+ bool wait(std::chrono::time_point<C, D> end) {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mCondVar.wait_until(lock, end, [this](){ return this->mFinished; });
+ return mFinished;
+ }
+ void operator()() {
+ mFunc();
+ }
+private:
+ std::mutex mMutex;
+ std::condition_variable mCondVar;
+ bool mFinished = false;
+ std::function<void(void)> mFunc;
+};
+
+void *callAndNotify(void *data) {
+ BackgroundTaskState &state = *static_cast<BackgroundTaskState *>(data);
+ state();
+ state.notify();
+ return NULL;
+}
+
+template<class R, class P>
+bool timeout(std::chrono::duration<R, P> delay, std::function<void(void)> &&func) {
+ auto now = std::chrono::system_clock::now();
+ BackgroundTaskState state{std::forward<decltype(func)>(func)};
+ pthread_t thread;
+ if (pthread_create(&thread, NULL, callAndNotify, &state)) {
+ std::cerr << "FATAL: could not create background thread." << std::endl;
+ return false;
+ }
+ bool success = state.wait(now + delay);
+ if (!success) {
+ pthread_kill(thread, SIGINT);
+ }
+ pthread_join(thread, NULL);
+ return success;
+}
+
+template<class Function, class I, class... Args>
+typename std::result_of<Function(I *, Args...)>::type
+timeoutIPC(const sp<I> &interfaceObject, Function &&func, Args &&... args) {
+ using ::android::hardware::Status;
+ typename std::result_of<Function(I *, Args...)>::type ret{Status::ok()};
+ auto boundFunc = std::bind(std::forward<Function>(func),
+ interfaceObject.get(), std::forward<Args>(args)...);
+ bool success = timeout(IPC_CALL_WAIT, [&ret, &boundFunc] {
+ ret = std::move(boundFunc());
+ });
+ if (!success) {
+ return Status::fromStatusT(TIMED_OUT);
+ }
+ return ret;
+}
+
+} // namespace lshal
+} // namespace android
diff --git a/cmds/lshal/main.cpp b/cmds/lshal/main.cpp
new file mode 100644
index 0000000..366c938
--- /dev/null
+++ b/cmds/lshal/main.cpp
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2017 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 "Lshal.h"
+
+int main(int argc, char **argv) {
+ using namespace ::android::lshal;
+ return Lshal{}.main(Arg{argc, argv});
+}
diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp
new file mode 100644
index 0000000..972d508
--- /dev/null
+++ b/cmds/lshal/test.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2017 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 "Lshal"
+#include <android-base/logging.h>
+
+#include <sstream>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+#include <android/hardware/tests/baz/1.0/IQuux.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "Lshal.h"
+
+#define NELEMS(array) static_cast<int>(sizeof(array) / sizeof(array[0]))
+
+using namespace testing;
+
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hidl::manager::V1_0::IServiceManager;
+using ::android::hidl::manager::V1_0::IServiceNotification;
+using ::android::hardware::hidl_death_recipient;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+
+namespace android {
+namespace hardware {
+namespace tests {
+namespace baz {
+namespace V1_0 {
+namespace implementation {
+struct Quux : android::hardware::tests::baz::V1_0::IQuux {
+ ::android::hardware::Return<void> debug(const hidl_handle& hh, const hidl_vec<hidl_string>& options) override {
+ const native_handle_t *handle = hh.getNativeHandle();
+ if (handle->numFds < 1) {
+ return Void();
+ }
+ int fd = handle->data[0];
+ std::string content{descriptor};
+ for (const auto &option : options) {
+ content += "\n";
+ content += option.c_str();
+ }
+ ssize_t written = write(fd, content.c_str(), content.size());
+ if (written != (ssize_t)content.size()) {
+ LOG(WARNING) << "SERVER(Quux) debug writes " << written << " bytes < "
+ << content.size() << " bytes, errno = " << errno;
+ }
+ return Void();
+ }
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace baz
+} // namespace tests
+} // namespace hardware
+
+namespace lshal {
+
+
+class MockServiceManager : public IServiceManager {
+public:
+ template<typename T>
+ using R = ::android::hardware::Return<T>;
+ using String = const hidl_string&;
+ ~MockServiceManager() = default;
+
+#define MOCK_METHOD_CB(name) MOCK_METHOD1(name, R<void>(IServiceManager::name##_cb))
+
+ MOCK_METHOD2(get, R<sp<IBase>>(String, String));
+ MOCK_METHOD2(add, R<bool>(String, const sp<IBase>&));
+ MOCK_METHOD2(getTransport, R<IServiceManager::Transport>(String, String));
+ MOCK_METHOD_CB(list);
+ MOCK_METHOD2(listByInterface, R<void>(String, listByInterface_cb));
+ MOCK_METHOD3(registerForNotifications, R<bool>(String, String, const sp<IServiceNotification>&));
+ MOCK_METHOD_CB(debugDump);
+ MOCK_METHOD2(registerPassthroughClient, R<void>(String, String));
+ MOCK_METHOD_CB(interfaceChain);
+ MOCK_METHOD2(debug, R<void>(const hidl_handle&, const hidl_vec<hidl_string>&));
+ MOCK_METHOD_CB(interfaceDescriptor);
+ MOCK_METHOD_CB(getHashChain);
+ MOCK_METHOD0(setHalInstrumentation, R<void>());
+ MOCK_METHOD2(linkToDeath, R<bool>(const sp<hidl_death_recipient>&, uint64_t));
+ MOCK_METHOD0(ping, R<void>());
+ MOCK_METHOD_CB(getDebugInfo);
+ MOCK_METHOD0(notifySyspropsChanged, R<void>());
+ MOCK_METHOD1(unlinkToDeath, R<bool>(const sp<hidl_death_recipient>&));
+
+};
+
+class LshalTest : public ::testing::Test {
+public:
+ void SetUp() override {
+ using ::android::hardware::tests::baz::V1_0::IQuux;
+ using ::android::hardware::tests::baz::V1_0::implementation::Quux;
+
+ err.str("");
+ out.str("");
+ serviceManager = new testing::NiceMock<MockServiceManager>();
+ ON_CALL(*serviceManager, get(_, _)).WillByDefault(Invoke(
+ [](const auto &iface, const auto &inst) -> ::android::hardware::Return<sp<IBase>> {
+ if (iface == IQuux::descriptor && inst == "default")
+ return new Quux();
+ return nullptr;
+ }));
+ }
+ void TearDown() override {}
+
+ std::stringstream err;
+ std::stringstream out;
+ sp<MockServiceManager> serviceManager;
+};
+
+TEST_F(LshalTest, Debug) {
+ const char *args[] = {
+ "lshal", "debug", "android.hardware.tests.baz@1.0::IQuux/default", "foo", "bar"
+ };
+ EXPECT_EQ(0u, Lshal(out, err, serviceManager, serviceManager)
+ .main({NELEMS(args), const_cast<char **>(args)}));
+ EXPECT_THAT(out.str(), StrEq("android.hardware.tests.baz@1.0::IQuux\nfoo\nbar"));
+ EXPECT_THAT(err.str(), IsEmpty());
+}
+
+TEST_F(LshalTest, Debug2) {
+ const char *args[] = {
+ "lshal", "debug", "android.hardware.tests.baz@1.0::IQuux", "baz", "quux"
+ };
+ EXPECT_EQ(0u, Lshal(out, err, serviceManager, serviceManager)
+ .main({NELEMS(args), const_cast<char **>(args)}));
+ EXPECT_THAT(out.str(), StrEq("android.hardware.tests.baz@1.0::IQuux\nbaz\nquux"));
+ EXPECT_THAT(err.str(), IsEmpty());
+}
+
+TEST_F(LshalTest, Debug3) {
+ const char *args[] = {
+ "lshal", "debug", "android.hardware.tests.doesnotexist@1.0::IDoesNotExist",
+ };
+ EXPECT_NE(0u, Lshal(out, err, serviceManager, serviceManager)
+ .main({NELEMS(args), const_cast<char **>(args)}));
+ EXPECT_THAT(err.str(), HasSubstr("does not exist"));
+}
+
+} // namespace lshal
+} // namespace android
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleMock(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/cmds/lshal/utils.cpp b/cmds/lshal/utils.cpp
new file mode 100644
index 0000000..5550721
--- /dev/null
+++ b/cmds/lshal/utils.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 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 "utils.h"
+
+namespace android {
+namespace lshal {
+
+std::string toHexString(uint64_t t) {
+ std::ostringstream os;
+ os << std::hex << std::setfill('0') << std::setw(16) << t;
+ return os.str();
+}
+
+std::vector<std::string> split(const std::string &s, char c) {
+ std::vector<std::string> components{};
+ size_t startPos = 0;
+ size_t matchPos;
+ while ((matchPos = s.find(c, startPos)) != std::string::npos) {
+ components.push_back(s.substr(startPos, matchPos - startPos));
+ startPos = matchPos + 1;
+ }
+
+ if (startPos <= s.length()) {
+ components.push_back(s.substr(startPos));
+ }
+ return components;
+}
+
+void replaceAll(std::string *s, char from, char to) {
+ for (size_t i = 0; i < s->size(); ++i) {
+ if (s->at(i) == from) {
+ s->at(i) = to;
+ }
+ }
+}
+
+} // namespace lshal
+} // namespace android
+
diff --git a/cmds/lshal/utils.h b/cmds/lshal/utils.h
new file mode 100644
index 0000000..45b922c
--- /dev/null
+++ b/cmds/lshal/utils.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2017 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_CMDS_LSHAL_UTILS_H_
+#define FRAMEWORK_NATIVE_CMDS_LSHAL_UTILS_H_
+
+#include <iomanip>
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <utility>
+#include <vector>
+
+namespace android {
+namespace lshal {
+
+enum : unsigned int {
+ OK = 0,
+ USAGE = 1 << 0,
+ NO_BINDERIZED_MANAGER = 1 << 1,
+ NO_PASSTHROUGH_MANAGER = 1 << 2,
+ DUMP_BINDERIZED_ERROR = 1 << 3,
+ DUMP_PASSTHROUGH_ERROR = 1 << 4,
+ DUMP_ALL_LIBS_ERROR = 1 << 5,
+ IO_ERROR = 1 << 6,
+ NO_INTERFACE = 1 << 7,
+ TRANSACTION_ERROR = 1 << 8,
+};
+using Status = unsigned int;
+
+struct Arg {
+ int argc;
+ char **argv;
+};
+
+template <typename A>
+std::string join(const A &components, const std::string &separator) {
+ std::stringstream out;
+ bool first = true;
+ for (const auto &component : components) {
+ if (!first) {
+ out << separator;
+ }
+ out << component;
+
+ first = false;
+ }
+ return out.str();
+}
+
+std::string toHexString(uint64_t t);
+
+template<typename String>
+std::pair<String, String> splitFirst(const String &s, char c) {
+ const char *pos = strchr(s.c_str(), c);
+ if (pos == nullptr) {
+ return {s, {}};
+ }
+ return {String(s.c_str(), pos - s.c_str()), String(pos + 1)};
+}
+
+std::vector<std::string> split(const std::string &s, char c);
+
+void replaceAll(std::string *s, char from, char to);
+
+} // namespace lshal
+} // namespace android
+
+#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_UTILS_H_
diff --git a/cmds/service/Android.bp b/cmds/service/Android.bp
new file mode 100644
index 0000000..8cffb3c
--- /dev/null
+++ b/cmds/service/Android.bp
@@ -0,0 +1,13 @@
+cc_binary {
+ name: "service",
+
+ srcs: ["service.cpp"],
+
+ shared_libs: [
+ "libutils",
+ "libbinder",
+ ],
+
+ cflags: ["-DXP_UNIX"],
+ //shared_libs: ["librt"],
+}
diff --git a/cmds/service/Android.mk b/cmds/service/Android.mk
deleted file mode 100644
index 275bbb2..0000000
--- a/cmds/service/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- service.cpp
-
-LOCAL_SHARED_LIBRARIES := libutils libbinder
-
-ifeq ($(TARGET_OS),linux)
- LOCAL_CFLAGS += -DXP_UNIX
- #LOCAL_SHARED_LIBRARIES += librt
-endif
-
-LOCAL_MODULE:= service
-
-include $(BUILD_EXECUTABLE)
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
new file mode 100644
index 0000000..dc8e675
--- /dev/null
+++ b/cmds/servicemanager/Android.bp
@@ -0,0 +1,36 @@
+cc_defaults {
+ name: "servicemanager_flags",
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+ product_variables: {
+ binder32bit: {
+ cflags: ["-DBINDER_IPC_32BIT=1"],
+ },
+ },
+
+ shared_libs: ["liblog"],
+}
+
+cc_binary {
+ name: "bctest",
+ defaults: ["servicemanager_flags"],
+ srcs: [
+ "bctest.c",
+ "binder.c",
+ ],
+}
+
+cc_binary {
+ name: "servicemanager",
+ defaults: ["servicemanager_flags"],
+ srcs: [
+ "service_manager.c",
+ "binder.c",
+ ],
+ shared_libs: ["libcutils", "libselinux"],
+ init_rc: ["servicemanager.rc"],
+}
diff --git a/cmds/servicemanager/Android.mk b/cmds/servicemanager/Android.mk
deleted file mode 100644
index b214f19..0000000
--- a/cmds/servicemanager/Android.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-svc_c_flags = \
- -Wall -Wextra -Werror \
-
-ifneq ($(TARGET_USES_64_BIT_BINDER),true)
-ifneq ($(TARGET_IS_64_BIT),true)
-svc_c_flags += -DBINDER_IPC_32BIT=1
-endif
-endif
-
-include $(CLEAR_VARS)
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_SRC_FILES := bctest.c binder.c
-LOCAL_CFLAGS += $(svc_c_flags)
-LOCAL_MODULE := bctest
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-LOCAL_SHARED_LIBRARIES := liblog libcutils libselinux
-LOCAL_SRC_FILES := service_manager.c binder.c
-LOCAL_CFLAGS += $(svc_c_flags)
-LOCAL_MODULE := servicemanager
-LOCAL_INIT_RC := servicemanager.rc
-include $(BUILD_EXECUTABLE)
diff --git a/cmds/servicemanager/binder.c b/cmds/servicemanager/binder.c
index 27c461a..753aeb5 100644
--- a/cmds/servicemanager/binder.c
+++ b/cmds/servicemanager/binder.c
@@ -1,14 +1,18 @@
/* Copyright 2008 The Android Open Source Project
*/
+#define LOG_TAG "Binder"
+
+#include <errno.h>
+#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
#include <sys/mman.h>
+#include <unistd.h>
+
+#include <log/log.h>
#include "binder.h"
@@ -16,9 +20,6 @@
#define TRACE 0
-#define LOG_TAG "Binder"
-#include <cutils/log.h>
-
void bio_init_from_txn(struct binder_io *io, struct binder_transaction_data *txn);
#if TRACE
diff --git a/cmds/servicemanager/binder.h b/cmds/servicemanager/binder.h
index 7915fc2..881ab07 100644
--- a/cmds/servicemanager/binder.h
+++ b/cmds/servicemanager/binder.h
@@ -5,7 +5,7 @@
#define _BINDER_H_
#include <sys/ioctl.h>
-#include <linux/binder.h>
+#include <linux/android/binder.h>
struct binder_state;
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index 68e3ceb..43c4c8b 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -22,7 +22,7 @@
#define ALOGE(x...) fprintf(stderr, "svcmgr: " x)
#else
#define LOG_TAG "ServiceManager"
-#include <cutils/log.h>
+#include <log/log.h>
#endif
struct audit_data {
@@ -60,7 +60,6 @@
return 1;
}
-static int selinux_enabled;
static char *service_manager_context;
static struct selabel_handle* sehandle;
@@ -89,10 +88,6 @@
static bool check_mac_perms_from_getcon(pid_t spid, uid_t uid, const char *perm)
{
- if (selinux_enabled <= 0) {
- return true;
- }
-
return check_mac_perms(spid, uid, service_manager_context, perm, NULL);
}
@@ -101,10 +96,6 @@
bool allowed;
char *tctx = NULL;
- if (selinux_enabled <= 0) {
- return true;
- }
-
if (!sehandle) {
ALOGE("SELinux: Failed to find sehandle. Aborting service_manager.\n");
abort();
@@ -372,6 +363,7 @@
int main()
{
struct binder_state *bs;
+ union selinux_callback cb;
bs = binder_open(128*1024);
if (!bs) {
@@ -384,28 +376,25 @@
return -1;
}
- selinux_enabled = is_selinux_enabled();
- sehandle = selinux_android_service_context_handle();
- selinux_status_open(true);
-
- if (selinux_enabled > 0) {
- if (sehandle == NULL) {
- ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n");
- abort();
- }
-
- if (getcon(&service_manager_context) != 0) {
- ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n");
- abort();
- }
- }
-
- union selinux_callback cb;
cb.func_audit = audit_callback;
selinux_set_callback(SELINUX_CB_AUDIT, cb);
cb.func_log = selinux_log_callback;
selinux_set_callback(SELINUX_CB_LOG, cb);
+ sehandle = selinux_android_service_context_handle();
+ selinux_status_open(true);
+
+ if (sehandle == NULL) {
+ ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n");
+ abort();
+ }
+
+ if (getcon(&service_manager_context) != 0) {
+ ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n");
+ abort();
+ }
+
+
binder_loop(bs, svcmgr_handler);
return 0;
diff --git a/data/etc/android.hardware.wifi.nan.xml b/data/etc/android.hardware.telephony.carrierlock.xml
similarity index 76%
copy from data/etc/android.hardware.wifi.nan.xml
copy to data/etc/android.hardware.telephony.carrierlock.xml
index e557610..50b1fe9 100644
--- a/data/etc/android.hardware.wifi.nan.xml
+++ b/data/etc/android.hardware.telephony.carrierlock.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!-- Copyright (C) 2017 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.
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<!-- This is the standard feature indicating that the device includes WiFi NAN. -->
+<!-- Feature for devices with telephony carrier restriction mechanism. -->
<permissions>
- <feature name="android.hardware.wifi.nan" />
+ <feature name="android.hardware.telephony.carrierlock" />
</permissions>
diff --git a/data/etc/android.hardware.wifi.nan.xml b/data/etc/android.hardware.wifi.aware.xml
similarity index 90%
rename from data/etc/android.hardware.wifi.nan.xml
rename to data/etc/android.hardware.wifi.aware.xml
index e557610..ae6272e 100644
--- a/data/etc/android.hardware.wifi.nan.xml
+++ b/data/etc/android.hardware.wifi.aware.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<!-- This is the standard feature indicating that the device includes WiFi NAN. -->
+<!-- This is the standard feature indicating that the device includes WiFi Aware. -->
<permissions>
- <feature name="android.hardware.wifi.nan" />
+ <feature name="android.hardware.wifi.aware" />
</permissions>
diff --git a/include/android/asset_manager.h b/include/android/asset_manager.h
index d654839..7ef3ecb 100644
--- a/include/android/asset_manager.h
+++ b/include/android/asset_manager.h
@@ -26,6 +26,9 @@
#ifndef ANDROID_ASSET_MANAGER_H
#define ANDROID_ASSET_MANAGER_H
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -131,6 +134,7 @@
*/
off_t AAsset_seek(AAsset* asset, off_t offset, int whence);
+#if __ANDROID_API__ >= 13
/**
* Seek to the specified offset within the asset data. 'whence' uses the
* same constants as lseek()/fseek().
@@ -141,6 +145,7 @@
* Returns the new position on success, or (off64_t) -1 on error.
*/
off64_t AAsset_seek64(AAsset* asset, off64_t offset, int whence);
+#endif
/**
* Close the asset, freeing all associated resources.
@@ -159,23 +164,27 @@
*/
off_t AAsset_getLength(AAsset* asset);
+#if __ANDROID_API__ >= 13
/**
* Report the total size of the asset data. Reports the size using a 64-bit
* number insted of 32-bit as AAsset_getLength.
*/
off64_t AAsset_getLength64(AAsset* asset);
+#endif
/**
* Report the total amount of asset data that can be read from the current position.
*/
off_t AAsset_getRemainingLength(AAsset* asset);
+#if __ANDROID_API__ >= 13
/**
* Report the total amount of asset data that can be read from the current position.
*
* Uses a 64-bit number instead of a 32-bit number as AAsset_getRemainingLength does.
*/
off64_t AAsset_getRemainingLength64(AAsset* asset);
+#endif
/**
* Open a new file descriptor that can be used to read the asset data. If the
@@ -187,6 +196,7 @@
*/
int AAsset_openFileDescriptor(AAsset* asset, off_t* outStart, off_t* outLength);
+#if __ANDROID_API__ >= 13
/**
* Open a new file descriptor that can be used to read the asset data.
*
@@ -197,6 +207,7 @@
* compressed).
*/
int AAsset_openFileDescriptor64(AAsset* asset, off64_t* outStart, off64_t* outLength);
+#endif
/**
* Returns whether this asset's internal buffer is allocated in ordinary RAM (i.e. not
diff --git a/include/android/bitmap.h b/include/android/bitmap.h
index 261e64f..2def64d 100644
--- a/include/android/bitmap.h
+++ b/include/android/bitmap.h
@@ -56,9 +56,9 @@
ANDROID_BITMAP_FORMAT_RGBA_8888 = 1,
/** Red: 5 bits, Green: 6 bits, Blue: 5 bits. **/
ANDROID_BITMAP_FORMAT_RGB_565 = 4,
- /** Red: 4 bits, Green: 4 bits, Blue: 4 bits, Alpha: 4 bits. **/
+ /** Deprecated in API level 13. Because of the poor quality of this configuration, it is advised to use ARGB_8888 instead. **/
ANDROID_BITMAP_FORMAT_RGBA_4444 = 7,
- /** Deprecated. */
+ /** Alpha: 8 bits. */
ANDROID_BITMAP_FORMAT_A_8 = 8,
};
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index 02c83dc..43346fe 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -30,6 +30,8 @@
__BEGIN_DECLS
+#if __ANDROID_API__ >= 24
+
struct AChoreographer;
typedef struct AChoreographer AChoreographer;
@@ -62,6 +64,9 @@
*/
void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer,
AChoreographer_frameCallback callback, void* data, long delayMillis);
+
+#endif /* __ANDROID_API__ >= 24 */
+
__END_DECLS
#endif // ANDROID_CHOREOGRAPHER_H
diff --git a/include/android/configuration.h b/include/android/configuration.h
index 81f71a9..8e10f67 100644
--- a/include/android/configuration.h
+++ b/include/android/configuration.h
@@ -26,6 +26,8 @@
#ifndef ANDROID_CONFIGURATION_H
#define ANDROID_CONFIGURATION_H
+#include <sys/cdefs.h>
+
#include <android/asset_manager.h>
#ifdef __cplusplus
@@ -628,6 +630,7 @@
*/
void AConfiguration_setUiModeNight(AConfiguration* config, int32_t uiModeNight);
+#if __ANDROID_API__ >= 13
/**
* Return the current configuration screen width in dp units, or
* ACONFIGURATION_SCREEN_WIDTH_DP_ANY if not set.
@@ -660,7 +663,9 @@
* Set the configuration's smallest screen width in dp units.
*/
void AConfiguration_setSmallestScreenWidthDp(AConfiguration* config, int32_t value);
+#endif /* __ANDROID_API__ >= 13 */
+#if __ANDROID_API__ >= 17
/**
* Return the configuration's layout direction, or
* ACONFIGURATION_LAYOUTDIR_ANY if not set.
@@ -671,6 +676,7 @@
* Set the configuration's layout direction.
*/
void AConfiguration_setLayoutDirection(AConfiguration* config, int32_t value);
+#endif /* __ANDROID_API__ >= 17 */
/**
* Perform a diff between two configurations. Returns a bit mask of
diff --git a/include/android/input.h b/include/android/input.h
index fd9fa98..f928c6e 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -26,6 +26,8 @@
#ifndef _ANDROID_INPUT_H
#define _ANDROID_INPUT_H
+#include <sys/cdefs.h>
+
/******************************************************************
*
* IMPORTANT NOTICE:
@@ -978,8 +980,10 @@
*/
int32_t AMotionEvent_getMetaState(const AInputEvent* motion_event);
+#if __ANDROID_API__ >= 14
/** Get the button state of all buttons that are pressed. */
int32_t AMotionEvent_getButtonState(const AInputEvent* motion_event);
+#endif
/**
* Get a bitfield indicating which edges, if any, were touched by this motion event.
@@ -1044,12 +1048,14 @@
*/
int32_t AMotionEvent_getPointerId(const AInputEvent* motion_event, size_t pointer_index);
+#if __ANDROID_API__ >= 14
/**
* Get the tool type of a pointer for the given pointer index.
* The tool type indicates the type of tool used to make contact such as a
* finger or stylus, if known.
*/
int32_t AMotionEvent_getToolType(const AInputEvent* motion_event, size_t pointer_index);
+#endif
/**
* Get the original raw X coordinate of this event.
@@ -1139,9 +1145,11 @@
*/
float AMotionEvent_getOrientation(const AInputEvent* motion_event, size_t pointer_index);
+#if __ANDROID_API__ >= 13
/** Get the value of the request axis for the given pointer index. */
float AMotionEvent_getAxisValue(const AInputEvent* motion_event,
int32_t axis, size_t pointer_index);
+#endif
/**
* Get the number of historical points in this event. These are movements that
@@ -1272,12 +1280,14 @@
float AMotionEvent_getHistoricalOrientation(const AInputEvent* motion_event, size_t pointer_index,
size_t history_index);
+#if __ANDROID_API__ >= 13
/**
* Get the historical value of the request axis for the given pointer index
* that occurred between this event and the previous motion event.
*/
float AMotionEvent_getHistoricalAxisValue(const AInputEvent* motion_event,
int32_t axis, size_t pointer_index, size_t history_index);
+#endif
struct AInputQueue;
diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h
index 6c718c9..be01518 100644
--- a/include/android/multinetwork.h
+++ b/include/android/multinetwork.h
@@ -51,6 +51,7 @@
* on failure with an appropriate errno value set.
*/
+#if __ANDROID_API__ >= 24
/**
* Set the network to be used by the given socket file descriptor.
@@ -104,6 +105,8 @@
const char *node, const char *service,
const struct addrinfo *hints, struct addrinfo **res);
+#endif /* __ANDROID_API__ >= 24 */
+
__END_DECLS
#endif // ANDROID_MULTINETWORK_H
diff --git a/include/android/native_window.h b/include/android/native_window.h
index cf07f1a..b60b9f1 100644
--- a/include/android/native_window.h
+++ b/include/android/native_window.h
@@ -26,6 +26,8 @@
#ifndef ANDROID_NATIVE_WINDOW_H
#define ANDROID_NATIVE_WINDOW_H
+#include <sys/cdefs.h>
+
#include <android/rect.h>
#ifdef __cplusplus
diff --git a/include/android/native_window_jni.h b/include/android/native_window_jni.h
index 60a36c3..1ec2a67 100644
--- a/include/android/native_window_jni.h
+++ b/include/android/native_window_jni.h
@@ -26,6 +26,8 @@
#ifndef ANDROID_NATIVE_WINDOW_JNI_H
#define ANDROID_NATIVE_WINDOW_JNI_H
+#include <sys/cdefs.h>
+
#include <android/native_window.h>
#include <jni.h>
@@ -42,6 +44,16 @@
*/
ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface);
+#if __ANDROID_API__ >= 13
+/**
+ * Return the ANativeWindow associated with a Java SurfaceTexture object,
+ * for interacting with it through native code. This acquires a reference
+ * on the ANativeWindow that is returned; be sure to use ANativeWindow_release()
+ * when done with it so that it doesn't leak.
+ */
+ANativeWindow* ANativeWindow_fromSurfaceTexture(JNIEnv* env, jobject surfaceTexture);
+#endif
+
#ifdef __cplusplus
};
#endif
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 5a61213..6c12972 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -48,6 +48,7 @@
*
*/
+#include <stdbool.h>
#include <sys/types.h>
#include <android/looper.h>
@@ -367,12 +368,14 @@
*/
ASensor const* ASensorManager_getDefaultSensor(ASensorManager* manager, int type);
+#if __ANDROID_API__ >= 21
/**
* Returns the default sensor with the given type and wakeUp properties or NULL if no sensor
* of this type and wakeUp properties exists.
*/
ASensor const* ASensorManager_getDefaultSensorEx(ASensorManager* manager, int type,
bool wakeUp);
+#endif
/**
* Creates a new sensor event queue and associate it with a looper.
@@ -395,6 +398,7 @@
/**
* Enable the selected sensor with a specified sampling period and max batch report latency.
* Returns a negative error code on failure.
+ * Note: To disable the selected sensor, use ASensorEventQueue_disableSensor() same as before.
*/
int ASensorEventQueue_registerSensor(ASensorEventQueue* queue, ASensor const* sensor,
int32_t samplingPeriodUs, int maxBatchReportLatencyUs);
@@ -471,6 +475,7 @@
*/
int ASensor_getMinDelay(ASensor const* sensor);
+#if __ANDROID_API__ >= 21
/**
* Returns the maximum size of batches for this sensor. Batches will often be
* smaller, as the hardware fifo might be used for other sensors.
@@ -496,6 +501,7 @@
* Returns true if this is a wake up sensor, false otherwise.
*/
bool ASensor_isWakeUpSensor(ASensor const* sensor);
+#endif /* __ANDROID_API__ >= 21 */
#ifdef __cplusplus
};
diff --git a/include/android/trace.h b/include/android/trace.h
index e42e334..6cdcfeb 100644
--- a/include/android/trace.h
+++ b/include/android/trace.h
@@ -19,11 +19,14 @@
#define ANDROID_NATIVE_TRACE_H
#include <stdbool.h>
+#include <sys/cdefs.h>
#ifdef __cplusplus
extern "C" {
#endif
+#if __ANDROID_API__ >= 23
+
/**
* Returns true if tracing is enabled. Use this signal to avoid expensive computation only necessary
* when tracing is enabled.
@@ -48,6 +51,8 @@
*/
void ATrace_endSection();
+#endif /* __ANDROID_API__ >= 23 */
+
#ifdef __cplusplus
};
#endif
diff --git a/include/batteryservice/IBatteryPropertiesListener.h b/include/batteryservice/IBatteryPropertiesListener.h
index b02d8e9..9154076 100644
--- a/include/batteryservice/IBatteryPropertiesListener.h
+++ b/include/batteryservice/IBatteryPropertiesListener.h
@@ -33,7 +33,7 @@
class IBatteryPropertiesListener : public IInterface {
public:
- DECLARE_META_INTERFACE(BatteryPropertiesListener);
+ DECLARE_META_INTERFACE(BatteryPropertiesListener)
virtual void batteryPropertiesChanged(struct BatteryProperties props) = 0;
};
diff --git a/include/batteryservice/IBatteryPropertiesRegistrar.h b/include/batteryservice/IBatteryPropertiesRegistrar.h
index eca075d..a7dbea6 100644
--- a/include/batteryservice/IBatteryPropertiesRegistrar.h
+++ b/include/batteryservice/IBatteryPropertiesRegistrar.h
@@ -27,15 +27,17 @@
REGISTER_LISTENER = IBinder::FIRST_CALL_TRANSACTION,
UNREGISTER_LISTENER,
GET_PROPERTY,
+ SCHEDULE_UPDATE,
};
class IBatteryPropertiesRegistrar : public IInterface {
public:
- DECLARE_META_INTERFACE(BatteryPropertiesRegistrar);
+ DECLARE_META_INTERFACE(BatteryPropertiesRegistrar)
virtual void registerListener(const sp<IBatteryPropertiesListener>& listener) = 0;
virtual void unregisterListener(const sp<IBatteryPropertiesListener>& listener) = 0;
virtual status_t getProperty(int id, struct BatteryProperty *val) = 0;
+ virtual void scheduleUpdate() = 0;
};
class BnBatteryPropertiesRegistrar : public BnInterface<IBatteryPropertiesRegistrar> {
diff --git a/include/binder/Binder.h b/include/binder/Binder.h
index f849fd4..3404881 100644
--- a/include/binder/Binder.h
+++ b/include/binder/Binder.h
@@ -80,7 +80,7 @@
class BpRefBase : public virtual RefBase
{
protected:
- BpRefBase(const sp<IBinder>& o);
+ explicit BpRefBase(const sp<IBinder>& o);
virtual ~BpRefBase();
virtual void onFirstRef();
virtual void onLastStrongRef(const void* id);
diff --git a/include/binder/IAppOpsCallback.h b/include/binder/IAppOpsCallback.h
index 7f8eb01..b62e9e2 100644
--- a/include/binder/IAppOpsCallback.h
+++ b/include/binder/IAppOpsCallback.h
@@ -27,7 +27,7 @@
class IAppOpsCallback : public IInterface
{
public:
- DECLARE_META_INTERFACE(AppOpsCallback);
+ DECLARE_META_INTERFACE(AppOpsCallback)
virtual void opChanged(int32_t op, const String16& packageName) = 0;
diff --git a/include/binder/IAppOpsService.h b/include/binder/IAppOpsService.h
index cd81efa..dc18045 100644
--- a/include/binder/IAppOpsService.h
+++ b/include/binder/IAppOpsService.h
@@ -28,7 +28,7 @@
class IAppOpsService : public IInterface
{
public:
- DECLARE_META_INTERFACE(AppOpsService);
+ DECLARE_META_INTERFACE(AppOpsService)
virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
diff --git a/include/binder/IBatteryStats.h b/include/binder/IBatteryStats.h
index 5f38186..e15d6f0 100644
--- a/include/binder/IBatteryStats.h
+++ b/include/binder/IBatteryStats.h
@@ -26,7 +26,7 @@
class IBatteryStats : public IInterface
{
public:
- DECLARE_META_INTERFACE(BatteryStats);
+ DECLARE_META_INTERFACE(BatteryStats)
virtual void noteStartSensor(int uid, int sensor) = 0;
virtual void noteStopSensor(int uid, int sensor) = 0;
diff --git a/include/binder/IBinder.h b/include/binder/IBinder.h
index 5f1e87c..9097cb3 100644
--- a/include/binder/IBinder.h
+++ b/include/binder/IBinder.h
@@ -90,12 +90,24 @@
Parcel* reply,
uint32_t flags = 0) = 0;
+ // DeathRecipient is pure abstract, there is no virtual method
+ // implementation to put in a translation unit in order to silence the
+ // weak vtables warning.
+ #if defined(__clang__)
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wweak-vtables"
+ #endif
+
class DeathRecipient : public virtual RefBase
{
public:
virtual void binderDied(const wp<IBinder>& who) = 0;
};
+ #if defined(__clang__)
+ #pragma clang diagnostic pop
+ #endif
+
/**
* Register the @a recipient for a notification if this binder
* goes away. If this binder object unexpectedly goes away
diff --git a/include/binder/IInterface.h b/include/binder/IInterface.h
index 4ce3613..be72d44 100644
--- a/include/binder/IInterface.h
+++ b/include/binder/IInterface.h
@@ -63,7 +63,7 @@
class BpInterface : public INTERFACE, public BpRefBase
{
public:
- BpInterface(const sp<IBinder>& remote);
+ explicit BpInterface(const sp<IBinder>& remote);
protected:
virtual IBinder* onAsBinder();
@@ -105,7 +105,7 @@
#define CHECK_INTERFACE(interface, data, reply) \
- if (!data.checkInterface(this)) { return PERMISSION_DENIED; } \
+ if (!(data).checkInterface(this)) { return PERMISSION_DENIED; } \
// ----------------------------------------------------------------------
diff --git a/include/binder/IMediaResourceMonitor.h b/include/binder/IMediaResourceMonitor.h
index c671f7a..b21047f 100644
--- a/include/binder/IMediaResourceMonitor.h
+++ b/include/binder/IMediaResourceMonitor.h
@@ -25,7 +25,7 @@
class IMediaResourceMonitor : public IInterface {
public:
- DECLARE_META_INTERFACE(MediaResourceMonitor);
+ DECLARE_META_INTERFACE(MediaResourceMonitor)
// Values should be in sync with Intent.EXTRA_MEDIA_RESOURCE_TYPE_XXX.
enum {
diff --git a/include/binder/IMemory.h b/include/binder/IMemory.h
index 2d0db00..15a104f 100644
--- a/include/binder/IMemory.h
+++ b/include/binder/IMemory.h
@@ -32,7 +32,7 @@
class IMemoryHeap : public IInterface
{
public:
- DECLARE_META_INTERFACE(MemoryHeap);
+ DECLARE_META_INTERFACE(MemoryHeap)
// flags returned by getFlags()
enum {
@@ -70,7 +70,7 @@
class IMemory : public IInterface
{
public:
- DECLARE_META_INTERFACE(Memory);
+ DECLARE_META_INTERFACE(Memory)
virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const = 0;
diff --git a/include/binder/IPermissionController.h b/include/binder/IPermissionController.h
index 4e5fb34..25f3431 100644
--- a/include/binder/IPermissionController.h
+++ b/include/binder/IPermissionController.h
@@ -28,7 +28,7 @@
class IPermissionController : public IInterface
{
public:
- DECLARE_META_INTERFACE(PermissionController);
+ DECLARE_META_INTERFACE(PermissionController)
virtual bool checkPermission(const String16& permission, int32_t pid, int32_t uid) = 0;
diff --git a/include/binder/IProcessInfoService.h b/include/binder/IProcessInfoService.h
index 69dc9a7..2669f91 100644
--- a/include/binder/IProcessInfoService.h
+++ b/include/binder/IProcessInfoService.h
@@ -25,7 +25,7 @@
class IProcessInfoService : public IInterface {
public:
- DECLARE_META_INTERFACE(ProcessInfoService);
+ DECLARE_META_INTERFACE(ProcessInfoService)
virtual status_t getProcessStatesFromPids( size_t length,
/*in*/ int32_t* pids,
diff --git a/include/binder/IResultReceiver.h b/include/binder/IResultReceiver.h
index 02dc6a6..e494fba 100644
--- a/include/binder/IResultReceiver.h
+++ b/include/binder/IResultReceiver.h
@@ -27,7 +27,7 @@
class IResultReceiver : public IInterface
{
public:
- DECLARE_META_INTERFACE(ResultReceiver);
+ DECLARE_META_INTERFACE(ResultReceiver)
virtual void send(int32_t resultCode) = 0;
diff --git a/include/binder/IServiceManager.h b/include/binder/IServiceManager.h
index 7ccd9fe..3b23f81 100644
--- a/include/binder/IServiceManager.h
+++ b/include/binder/IServiceManager.h
@@ -30,7 +30,7 @@
class IServiceManager : public IInterface
{
public:
- DECLARE_META_INTERFACE(ServiceManager);
+ DECLARE_META_INTERFACE(ServiceManager)
/**
* Retrieve an existing service, blocking for a few seconds
diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
index 2490b82..b0d53ef 100644
--- a/include/binder/Parcel.h
+++ b/include/binder/Parcel.h
@@ -20,14 +20,14 @@
#include <string>
#include <vector>
+#include <android-base/unique_fd.h>
#include <cutils/native_handle.h>
-#include <nativehelper/ScopedFd.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
#include <utils/String16.h>
#include <utils/Vector.h>
#include <utils/Flattenable.h>
-#include <linux/binder.h>
+#include <linux/android/binder.h>
#include <binder/IInterface.h>
#include <binder/Parcelable.h>
@@ -166,6 +166,10 @@
template<typename T>
status_t write(const LightFlattenable<T>& val);
+ template<typename T>
+ status_t writeVectorSize(const std::vector<T>& val);
+ template<typename T>
+ status_t writeVectorSize(const std::unique_ptr<std::vector<T>>& val);
// Place a native_handle into the parcel (the native_handle's file-
// descriptors are dup'ed, so it is safe to delete the native_handle
@@ -186,14 +190,14 @@
// semantics of the smart file descriptor. A new descriptor will be
// created, and will be closed when the parcel is destroyed.
status_t writeUniqueFileDescriptor(
- const ScopedFd& fd);
+ const base::unique_fd& fd);
// Place a vector of file desciptors into the parcel. Each descriptor is
// dup'd as in writeDupFileDescriptor
status_t writeUniqueFileDescriptorVector(
- const std::unique_ptr<std::vector<ScopedFd>>& val);
+ const std::unique_ptr<std::vector<base::unique_fd>>& val);
status_t writeUniqueFileDescriptorVector(
- const std::vector<ScopedFd>& val);
+ const std::vector<base::unique_fd>& val);
// Writes a blob to the parcel.
// If the blob is small, then it is stored in-place, otherwise it is
@@ -246,12 +250,14 @@
const char* readCString() const;
String8 readString8() const;
+ status_t readString8(String8* pArg) const;
String16 readString16() const;
status_t readString16(String16* pArg) const;
status_t readString16(std::unique_ptr<String16>* pArg) const;
const char16_t* readString16Inplace(size_t* outLen) const;
sp<IBinder> readStrongBinder() const;
status_t readStrongBinder(sp<IBinder>* val) const;
+ status_t readNullableStrongBinder(sp<IBinder>* val) const;
wp<IBinder> readWeakBinder() const;
template<typename T>
@@ -268,6 +274,9 @@
template<typename T>
status_t readStrongBinder(sp<T>* val) const;
+ template<typename T>
+ status_t readNullableStrongBinder(sp<T>* val) const;
+
status_t readStrongBinderVector(std::unique_ptr<std::vector<sp<IBinder>>>* val) const;
status_t readStrongBinderVector(std::vector<sp<IBinder>>* val) const;
@@ -300,6 +309,11 @@
template<typename T>
status_t read(LightFlattenable<T>& val) const;
+ template<typename T>
+ status_t resizeOutVector(std::vector<T>* val) const;
+ template<typename T>
+ status_t resizeOutVector(std::unique_ptr<std::vector<T>>* val) const;
+
// Like Parcel.java's readExceptionCode(). Reads the first int32
// off of a Parcel's header, returning 0 or the negative error
// code on exceptions, but also deals with skipping over rich
@@ -320,14 +334,14 @@
// Retrieve a smart file descriptor from the parcel.
status_t readUniqueFileDescriptor(
- ScopedFd* val) const;
+ base::unique_fd* val) const;
// Retrieve a vector of smart file descriptors from the parcel.
status_t readUniqueFileDescriptorVector(
- std::unique_ptr<std::vector<ScopedFd>>* val) const;
+ std::unique_ptr<std::vector<base::unique_fd>>* val) const;
status_t readUniqueFileDescriptorVector(
- std::vector<ScopedFd>* val) const;
+ std::vector<base::unique_fd>* val) const;
// Reads a blob from the parcel.
// The caller should call release() on the blob after reading its contents.
@@ -437,7 +451,7 @@
void clear();
void release();
inline size_t size() const { return mSize; }
- inline int fd() const { return mFd; };
+ inline int fd() const { return mFd; }
inline bool isMutable() const { return mMutable; }
protected:
@@ -449,6 +463,11 @@
bool mMutable;
};
+ #if defined(__clang__)
+ #pragma clang diagnostic push
+ #pragma clang diagnostic ignored "-Wweak-vtables"
+ #endif
+
class FlattenableHelperInterface {
protected:
~FlattenableHelperInterface() { }
@@ -459,12 +478,18 @@
virtual status_t unflatten(void const* buffer, size_t size, int const* fds, size_t count) = 0;
};
+ #if defined(__clang__)
+ #pragma clang diagnostic pop
+ #endif
+
template<typename T>
class FlattenableHelper : public FlattenableHelperInterface {
friend class Parcel;
const Flattenable<T>& val;
- explicit FlattenableHelper(const Flattenable<T>& val) : val(val) { }
+ explicit FlattenableHelper(const Flattenable<T>& _val) : val(_val) { }
+ protected:
+ ~FlattenableHelper() = default;
public:
virtual size_t getFlattenedSize() const {
return val.getFlattenedSize();
@@ -517,7 +542,10 @@
status_t Parcel::write(const LightFlattenable<T>& val) {
size_t size(val.getFlattenedSize());
if (!val.isFixedSize()) {
- status_t err = writeInt32(size);
+ if (size > INT32_MAX) {
+ return BAD_VALUE;
+ }
+ status_t err = writeInt32(static_cast<int32_t>(size));
if (err != NO_ERROR) {
return err;
}
@@ -548,7 +576,7 @@
if (err != NO_ERROR) {
return err;
}
- size = s;
+ size = static_cast<size_t>(s);
}
if (size) {
void const* buffer = readInplace(size);
@@ -559,6 +587,54 @@
}
template<typename T>
+status_t Parcel::writeVectorSize(const std::vector<T>& val) {
+ if (val.size() > INT32_MAX) {
+ return BAD_VALUE;
+ }
+ return writeInt32(static_cast<int32_t>(val.size()));
+}
+
+template<typename T>
+status_t Parcel::writeVectorSize(const std::unique_ptr<std::vector<T>>& val) {
+ if (!val) {
+ return writeInt32(-1);
+ }
+
+ return writeVectorSize(*val);
+}
+
+template<typename T>
+status_t Parcel::resizeOutVector(std::vector<T>* val) const {
+ int32_t size;
+ status_t err = readInt32(&size);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ if (size < 0) {
+ return UNEXPECTED_NULL;
+ }
+ val->resize(size_t(size));
+ return OK;
+}
+
+template<typename T>
+status_t Parcel::resizeOutVector(std::unique_ptr<std::vector<T>>* val) const {
+ int32_t size;
+ status_t err = readInt32(&size);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ val->reset();
+ if (size >= 0) {
+ val->reset(new std::vector<T>(size_t(size)));
+ }
+
+ return OK;
+}
+
+template<typename T>
status_t Parcel::readStrongBinder(sp<T>* val) const {
sp<IBinder> tmp;
status_t ret = readStrongBinder(&tmp);
@@ -574,6 +650,22 @@
return ret;
}
+template<typename T>
+status_t Parcel::readNullableStrongBinder(sp<T>* val) const {
+ sp<IBinder> tmp;
+ status_t ret = readNullableStrongBinder(&tmp);
+
+ if (ret == OK) {
+ *val = interface_cast<T>(tmp);
+
+ if (val->get() == nullptr && tmp.get() != nullptr) {
+ ret = UNKNOWN_ERROR;
+ }
+ }
+
+ return ret;
+}
+
template<typename T, typename U>
status_t Parcel::unsafeReadTypedVector(
std::vector<T>* val,
@@ -589,13 +681,13 @@
return UNEXPECTED_NULL;
}
- if (val->max_size() < size) {
+ if (val->max_size() < static_cast<size_t>(size)) {
return NO_MEMORY;
}
- val->resize(size);
+ val->resize(static_cast<size_t>(size));
- if (val->size() < size) {
+ if (val->size() < static_cast<size_t>(size)) {
return NO_MEMORY;
}
@@ -619,7 +711,7 @@
template<typename T>
status_t Parcel::readNullableTypedVector(std::unique_ptr<std::vector<T>>* val,
status_t(Parcel::*read_func)(T*) const) const {
- const int32_t start = dataPosition();
+ const size_t start = dataPosition();
int32_t size;
status_t status = readInt32(&size);
val->reset();
@@ -647,7 +739,7 @@
return BAD_VALUE;
}
- status_t status = this->writeInt32(val.size());
+ status_t status = this->writeInt32(static_cast<int32_t>(val.size()));
if (status != OK) {
return status;
@@ -703,7 +795,7 @@
template<typename T>
status_t Parcel::readParcelableVector(std::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const {
- const int32_t start = dataPosition();
+ const size_t start = dataPosition();
int32_t size;
status_t status = readInt32(&size);
val->reset();
@@ -726,7 +818,7 @@
template<typename T>
status_t Parcel::readParcelable(std::unique_ptr<T>* parcelable) const {
- const int32_t start = dataPosition();
+ const size_t start = dataPosition();
int32_t present;
status_t status = readInt32(&present);
parcelable->reset();
diff --git a/include/binder/Parcelable.h b/include/binder/Parcelable.h
index faf0d34..a9166e2 100644
--- a/include/binder/Parcelable.h
+++ b/include/binder/Parcelable.h
@@ -26,11 +26,19 @@
class Parcel;
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wweak-vtables"
+#endif
+
// Abstract interface of all parcelables.
class Parcelable {
public:
virtual ~Parcelable() = default;
+ Parcelable() = default;
+ Parcelable(const Parcelable&) = default;
+
// Write |this| parcelable to the given |parcel|. Keep in mind that
// implementations of writeToParcel must be manually kept in sync
// with readFromParcel and the Java equivalent versions of these methods.
@@ -46,6 +54,10 @@
virtual status_t readFromParcel(const Parcel* parcel) = 0;
}; // class Parcelable
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
} // namespace android
#endif // ANDROID_PARCELABLE_H
diff --git a/include/binder/PersistableBundle.h b/include/binder/PersistableBundle.h
index fe5619f..322fef9 100644
--- a/include/binder/PersistableBundle.h
+++ b/include/binder/PersistableBundle.h
@@ -18,6 +18,7 @@
#define ANDROID_PERSISTABLE_BUNDLE_H
#include <map>
+#include <set>
#include <vector>
#include <binder/Parcelable.h>
@@ -79,6 +80,19 @@
bool getStringVector(const String16& key, std::vector<String16>* out) const;
bool getPersistableBundle(const String16& key, PersistableBundle* out) const;
+ /* Getters for all keys for each value type */
+ std::set<String16> getBooleanKeys() const;
+ std::set<String16> getIntKeys() const;
+ std::set<String16> getLongKeys() const;
+ std::set<String16> getDoubleKeys() const;
+ std::set<String16> getStringKeys() const;
+ std::set<String16> getBooleanVectorKeys() const;
+ std::set<String16> getIntVectorKeys() const;
+ std::set<String16> getLongVectorKeys() const;
+ std::set<String16> getDoubleVectorKeys() const;
+ std::set<String16> getStringVectorKeys() const;
+ std::set<String16> getPersistableBundleKeys() const;
+
friend bool operator==(const PersistableBundle& lhs, const PersistableBundle& rhs) {
return (lhs.mBoolMap == rhs.mBoolMap && lhs.mIntMap == rhs.mIntMap &&
lhs.mLongMap == rhs.mLongMap && lhs.mDoubleMap == rhs.mDoubleMap &&
diff --git a/include/binder/Status.h b/include/binder/Status.h
index ce947fa..c3738f8 100644
--- a/include/binder/Status.h
+++ b/include/binder/Status.h
@@ -18,6 +18,7 @@
#define ANDROID_BINDER_STATUS_H
#include <cstdint>
+#include <sstream>
#include <binder/Parcel.h>
#include <utils/String8.h>
@@ -61,6 +62,7 @@
EX_NETWORK_MAIN_THREAD = -6,
EX_UNSUPPORTED_OPERATION = -7,
EX_SERVICE_SPECIFIC = -8,
+ EX_PARCELABLE = -9,
// This is special and Java specific; see Parcel.java.
EX_HAS_REPLY_HEADER = -128,
@@ -71,6 +73,7 @@
// A more readable alias for the default constructor.
static Status ok();
+
// Authors should explicitly pick whether their integer is:
// - an exception code (EX_* above)
// - service specific error code
@@ -83,9 +86,15 @@
static Status fromExceptionCode(int32_t exceptionCode);
static Status fromExceptionCode(int32_t exceptionCode,
const String8& message);
+ static Status fromExceptionCode(int32_t exceptionCode,
+ const char* message);
+
static Status fromServiceSpecificError(int32_t serviceSpecificErrorCode);
static Status fromServiceSpecificError(int32_t serviceSpecificErrorCode,
const String8& message);
+ static Status fromServiceSpecificError(int32_t serviceSpecificErrorCode,
+ const char* message);
+
static Status fromStatusT(status_t status);
Status() = default;
@@ -142,11 +151,7 @@
}; // class Status
// For gtest output logging
-template<typename T>
-T& operator<< (T& stream, const Status& s) {
- stream << s.toString8().string();
- return stream;
-}
+std::stringstream& operator<< (std::stringstream& stream, const Status& s);
} // namespace binder
} // namespace android
diff --git a/include/binder/TextOutput.h b/include/binder/TextOutput.h
index 974a194..851e01f 100644
--- a/include/binder/TextOutput.h
+++ b/include/binder/TextOutput.h
@@ -18,16 +18,15 @@
#define ANDROID_TEXTOUTPUT_H
#include <utils/Errors.h>
+#include <utils/String8.h>
#include <stdint.h>
#include <string.h>
+#include <sstream>
// ---------------------------------------------------------------------------
namespace android {
-class String8;
-class String16;
-
class TextOutput
{
public:
@@ -66,30 +65,26 @@
TextOutput& indent(TextOutput& to);
TextOutput& dedent(TextOutput& to);
-TextOutput& operator<<(TextOutput& to, const char* str);
-TextOutput& operator<<(TextOutput& to, char); // writes raw character
-TextOutput& operator<<(TextOutput& to, bool);
-TextOutput& operator<<(TextOutput& to, int);
-TextOutput& operator<<(TextOutput& to, long);
-TextOutput& operator<<(TextOutput& to, unsigned int);
-TextOutput& operator<<(TextOutput& to, unsigned long);
-TextOutput& operator<<(TextOutput& to, long long);
-TextOutput& operator<<(TextOutput& to, unsigned long long);
-TextOutput& operator<<(TextOutput& to, float);
-TextOutput& operator<<(TextOutput& to, double);
-TextOutput& operator<<(TextOutput& to, TextOutputManipFunc func);
-TextOutput& operator<<(TextOutput& to, const void*);
-TextOutput& operator<<(TextOutput& to, const String8& val);
-TextOutput& operator<<(TextOutput& to, const String16& val);
+template<typename T>
+TextOutput& operator<<(TextOutput& to, const T& val)
+{
+ std::stringstream strbuf;
+ strbuf << val;
+ std::string str = strbuf.str();
+ to.print(str.c_str(), str.size());
+ return to;
+}
-class TypeCode
+TextOutput& operator<<(TextOutput& to, TextOutputManipFunc func);
+
+class TypeCode
{
public:
inline TypeCode(uint32_t code);
inline ~TypeCode();
inline uint32_t typeCode() const;
-
+
private:
uint32_t mCode;
};
@@ -124,6 +119,32 @@
};
TextOutput& operator<<(TextOutput& to, const HexDump& val);
+inline TextOutput& operator<<(TextOutput& to,
+ decltype(std::endl<char,
+ std::char_traits<char>>)
+ /*val*/) {
+ endl(to);
+ return to;
+}
+
+inline TextOutput& operator<<(TextOutput& to, const char &c)
+{
+ to.print(&c, 1);
+ return to;
+}
+
+inline TextOutput& operator<<(TextOutput& to, const bool &val)
+{
+ if (val) to.print("true", 4);
+ else to.print("false", 5);
+ return to;
+}
+
+inline TextOutput& operator<<(TextOutput& to, const String16& val)
+{
+ to << String8(val).string();
+ return to;
+}
// ---------------------------------------------------------------------------
// No user servicable parts below.
@@ -146,18 +167,6 @@
return to;
}
-inline TextOutput& operator<<(TextOutput& to, const char* str)
-{
- to.print(str, strlen(str));
- return to;
-}
-
-inline TextOutput& operator<<(TextOutput& to, char c)
-{
- to.print(&c, 1);
- return to;
-}
-
inline TextOutput& operator<<(TextOutput& to, TextOutputManipFunc func)
{
return (*func)(to);
diff --git a/include/gui/BitTube.h b/include/gui/BitTube.h
index 3ecac52..9d65fad 100644
--- a/include/gui/BitTube.h
+++ b/include/gui/BitTube.h
@@ -20,10 +20,9 @@
#include <stdint.h>
#include <sys/types.h>
+#include <android/log.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
-#include <cutils/log.h>
-
namespace android {
// ----------------------------------------------------------------------------
diff --git a/include/gui/BufferItem.h b/include/gui/BufferItem.h
index f45d852..5232d0f 100644
--- a/include/gui/BufferItem.h
+++ b/include/gui/BufferItem.h
@@ -46,6 +46,8 @@
enum { INVALID_BUFFER_SLOT = -1 };
BufferItem();
~BufferItem();
+ BufferItem(const BufferItem&) = default;
+ BufferItem& operator=(const BufferItem&) = default;
static const char* scalingModeName(uint32_t scalingMode);
@@ -72,13 +74,7 @@
// to set by queueBuffer each time this slot is queued. This value
// is guaranteed to be monotonically increasing for each newly
// acquired buffer.
- union {
- int64_t mTimestamp;
- struct {
- uint32_t mTimestampLo;
- uint32_t mTimestampHi;
- };
- };
+ int64_t mTimestamp;
// mIsAutoTimestamp indicates whether mTimestamp was generated
// automatically when the buffer was queued.
@@ -90,13 +86,7 @@
android_dataspace mDataSpace;
// mFrameNumber is the number of the queued frame for this slot.
- union {
- uint64_t mFrameNumber;
- struct {
- uint32_t mFrameNumberLo;
- uint32_t mFrameNumberHi;
- };
- };
+ uint64_t mFrameNumber;
// mSlot is the slot index of this buffer (default INVALID_BUFFER_SLOT).
int mSlot;
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index fe4b1fa..d532e2a 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -60,8 +60,8 @@
// weak references.
class ProxyConsumerListener : public BnConsumerListener {
public:
- ProxyConsumerListener(const wp<ConsumerListener>& consumerListener);
- virtual ~ProxyConsumerListener();
+ explicit ProxyConsumerListener(const wp<ConsumerListener>& consumerListener);
+ ~ProxyConsumerListener() override;
virtual void onFrameAvailable(const BufferItem& item) override;
virtual void onFrameReplaced(const BufferItem& item) override;
virtual void onBuffersReleased() override;
diff --git a/include/gui/BufferQueueConsumer.h b/include/gui/BufferQueueConsumer.h
index 8ec0546..e81f2e4 100644
--- a/include/gui/BufferQueueConsumer.h
+++ b/include/gui/BufferQueueConsumer.h
@@ -31,7 +31,7 @@
public:
BufferQueueConsumer(const sp<BufferQueueCore>& core);
- virtual ~BufferQueueConsumer();
+ ~BufferQueueConsumer() override;
// acquireBuffer attempts to acquire ownership of the next pending buffer in
// the BufferQueue. If no buffer is pending then it returns
@@ -144,7 +144,7 @@
virtual status_t discardFreeBuffers() override;
// dump our state in a String
- virtual void dump(String8& result, const char* prefix) const;
+ virtual void dumpState(String8& result, const char* prefix) const;
// Functions required for backwards compatibility.
// These will be modified/renamed in IGraphicBufferConsumer and will be
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index 1226feb..b1c730a 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -86,7 +86,7 @@
private:
// Dump our state in a string
- void dump(String8& result, const char* prefix) const;
+ void dumpState(String8& result, const char* prefix) const;
// getMinUndequeuedBufferCountLocked returns the minimum number of buffers
// that must remain in a state other than DEQUEUED. The async parameter
@@ -317,13 +317,13 @@
// Cached data about the shared buffer in shared buffer mode
struct SharedBufferCache {
- SharedBufferCache(Rect _crop, uint32_t _transform, int _scalingMode,
- android_dataspace _dataspace)
+ SharedBufferCache(Rect _crop, uint32_t _transform,
+ uint32_t _scalingMode, android_dataspace _dataspace)
: crop(_crop),
transform(_transform),
scalingMode(_scalingMode),
dataspace(_dataspace) {
- };
+ }
Rect crop;
uint32_t transform;
diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h
index 8f613ee..e1d0960 100644
--- a/include/gui/BufferQueueProducer.h
+++ b/include/gui/BufferQueueProducer.h
@@ -22,7 +22,7 @@
namespace android {
-class BufferSlot;
+struct BufferSlot;
class BufferQueueProducer : public BnGraphicBufferProducer,
private IBinder::DeathRecipient {
@@ -30,7 +30,7 @@
friend class BufferQueue; // Needed to access binderDied
BufferQueueProducer(const sp<BufferQueueCore>& core);
- virtual ~BufferQueueProducer();
+ ~BufferQueueProducer() override;
// requestBuffer returns the GraphicBuffer for slot N.
//
diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h
index 0490c3c..2d77459 100644
--- a/include/gui/ConsumerBase.h
+++ b/include/gui/ConsumerBase.h
@@ -43,7 +43,7 @@
virtual void onFrameReplaced(const BufferItem& /* item */) {}
};
- virtual ~ConsumerBase();
+ ~ConsumerBase() override;
// abandon frees all the buffers and puts the ConsumerBase into the
// 'abandoned' state. Once put in this state the ConsumerBase can never
@@ -63,11 +63,11 @@
// log messages.
void setName(const String8& name);
- // dump writes the current state to a string. Child classes should add
+ // dumpState writes the current state to a string. Child classes should add
// their state to the dump by overriding the dumpLocked method, which is
// called by these methods after locking the mutex.
- void dump(String8& result) const;
- void dump(String8& result, const char* prefix) const;
+ void dumpState(String8& result) const;
+ void dumpState(String8& result, const char* prefix) const;
// setFrameAvailableListener sets the listener object that will be notified
// when a new frame becomes available.
@@ -101,7 +101,7 @@
// buffers from the given IGraphicBufferConsumer.
// The controlledByApp flag indicates that this consumer is under the application's
// control.
- ConsumerBase(const sp<IGraphicBufferConsumer>& consumer, bool controlledByApp = false);
+ explicit ConsumerBase(const sp<IGraphicBufferConsumer>& consumer, bool controlledByApp = false);
// onLastStrongRef gets called by RefBase just before the dtor of the most
// derived class. It is used to clean up the buffers so that ConsumerBase
diff --git a/include/gui/DisplayEventReceiver.h b/include/gui/DisplayEventReceiver.h
index a4718b9..cb9b373 100644
--- a/include/gui/DisplayEventReceiver.h
+++ b/include/gui/DisplayEventReceiver.h
@@ -35,13 +35,19 @@
class BitTube;
class IDisplayEventConnection;
-// ----------------------------------------------------------------------------
+static inline constexpr uint32_t fourcc(char c1, char c2, char c3, char c4) {
+ return static_cast<uint32_t>(c1) << 24 |
+ static_cast<uint32_t>(c2) << 16 |
+ static_cast<uint32_t>(c3) << 8 |
+ static_cast<uint32_t>(c4);
+}
+// ----------------------------------------------------------------------------
class DisplayEventReceiver {
public:
enum {
- DISPLAY_EVENT_VSYNC = 'vsyn',
- DISPLAY_EVENT_HOTPLUG = 'plug'
+ DISPLAY_EVENT_VSYNC = fourcc('v', 's', 'y', 'n'),
+ DISPLAY_EVENT_HOTPLUG = fourcc('p', 'l', 'u', 'g'),
};
struct Event {
diff --git a/include/gui/GraphicBufferAlloc.h b/include/gui/GraphicBufferAlloc.h
index 62e3877..af52280 100644
--- a/include/gui/GraphicBufferAlloc.h
+++ b/include/gui/GraphicBufferAlloc.h
@@ -32,7 +32,7 @@
class GraphicBufferAlloc : public BnGraphicBufferAlloc {
public:
GraphicBufferAlloc();
- virtual ~GraphicBufferAlloc();
+ ~GraphicBufferAlloc() override;
virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t width,
uint32_t height, PixelFormat format, uint32_t usage,
std::string requestorName, status_t* error) override;
diff --git a/include/gui/IConsumerListener.h b/include/gui/IConsumerListener.h
index 1efcf3c..460a03d 100644
--- a/include/gui/IConsumerListener.h
+++ b/include/gui/IConsumerListener.h
@@ -41,7 +41,7 @@
class ConsumerListener : public virtual RefBase {
public:
ConsumerListener() { }
- virtual ~ConsumerListener() { }
+ virtual ~ConsumerListener();
// onFrameAvailable is called from queueBuffer each time an additional
// frame becomes available for consumption. This means that frames that
@@ -91,7 +91,7 @@
class IConsumerListener : public ConsumerListener, public IInterface
{
public:
- DECLARE_META_INTERFACE(ConsumerListener);
+ DECLARE_META_INTERFACE(ConsumerListener)
};
// ----------------------------------------------------------------------------
diff --git a/include/gui/IDisplayEventConnection.h b/include/gui/IDisplayEventConnection.h
index 86247de..848368c 100644
--- a/include/gui/IDisplayEventConnection.h
+++ b/include/gui/IDisplayEventConnection.h
@@ -34,7 +34,7 @@
{
public:
- DECLARE_META_INTERFACE(DisplayEventConnection);
+ DECLARE_META_INTERFACE(DisplayEventConnection)
/*
* getDataChannel() returns a BitTube where to receive the events from
diff --git a/include/gui/IGraphicBufferAlloc.h b/include/gui/IGraphicBufferAlloc.h
index 600cf27..acc2f30 100644
--- a/include/gui/IGraphicBufferAlloc.h
+++ b/include/gui/IGraphicBufferAlloc.h
@@ -33,7 +33,7 @@
class IGraphicBufferAlloc : public IInterface
{
public:
- DECLARE_META_INTERFACE(GraphicBufferAlloc);
+ DECLARE_META_INTERFACE(GraphicBufferAlloc)
/* Create a new GraphicBuffer for the client to use.
*/
diff --git a/include/gui/IGraphicBufferConsumer.h b/include/gui/IGraphicBufferConsumer.h
index 3b10d78..dcddca4 100644
--- a/include/gui/IGraphicBufferConsumer.h
+++ b/include/gui/IGraphicBufferConsumer.h
@@ -278,10 +278,10 @@
virtual status_t discardFreeBuffers() = 0;
// dump state into a string
- virtual void dump(String8& result, const char* prefix) const = 0;
+ virtual void dumpState(String8& result, const char* prefix) const = 0;
public:
- DECLARE_META_INTERFACE(GraphicBufferConsumer);
+ DECLARE_META_INTERFACE(GraphicBufferConsumer)
};
// ----------------------------------------------------------------------------
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index bf427fe..c2dba50 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -56,7 +56,7 @@
class IGraphicBufferProducer : public IInterface
{
public:
- DECLARE_META_INTERFACE(GraphicBufferProducer);
+ DECLARE_META_INTERFACE(GraphicBufferProducer)
enum {
// A flag returned by dequeueBuffer when the client needs to call
@@ -294,7 +294,7 @@
struct QueueBufferInput : public Flattenable<QueueBufferInput> {
friend class Flattenable<QueueBufferInput>;
- inline QueueBufferInput(const Parcel& parcel);
+ explicit inline QueueBufferInput(const Parcel& parcel);
// timestamp - a monotonically increasing value in nanoseconds
// isAutoTimestamp - if the timestamp was synthesized at queue time
// dataSpace - description of the contents, interpretation depends on format
@@ -305,12 +305,13 @@
// set this to Fence::NO_FENCE if the buffer is ready immediately
// sticky - the sticky transform set in Surface (only used by the LEGACY
// camera mode).
- inline QueueBufferInput(int64_t timestamp, bool isAutoTimestamp,
- android_dataspace dataSpace, const Rect& crop, int scalingMode,
- uint32_t transform, const sp<Fence>& fence, uint32_t sticky = 0)
- : timestamp(timestamp), isAutoTimestamp(isAutoTimestamp),
- dataSpace(dataSpace), crop(crop), scalingMode(scalingMode),
- transform(transform), stickyTransform(sticky), fence(fence),
+ inline QueueBufferInput(int64_t _timestamp, bool _isAutoTimestamp,
+ android_dataspace _dataSpace, const Rect& _crop,
+ int _scalingMode, uint32_t _transform, const sp<Fence>& _fence,
+ uint32_t _sticky = 0)
+ : timestamp(_timestamp), isAutoTimestamp(_isAutoTimestamp),
+ dataSpace(_dataSpace), crop(_crop), scalingMode(_scalingMode),
+ transform(_transform), stickyTransform(_sticky), fence(_fence),
surfaceDamage() { }
inline void deflate(int64_t* outTimestamp, bool* outIsAutoTimestamp,
android_dataspace* outDataSpace,
@@ -351,7 +352,7 @@
};
// QueueBufferOutput must be a POD structure
- struct __attribute__ ((__packed__)) QueueBufferOutput {
+ struct QueueBufferOutput {
inline QueueBufferOutput() { }
// outWidth - filled with default width applied to the buffer
// outHeight - filled with default height applied to the buffer
diff --git a/include/gui/IProducerListener.h b/include/gui/IProducerListener.h
index b7826c6..e808bd3 100644
--- a/include/gui/IProducerListener.h
+++ b/include/gui/IProducerListener.h
@@ -33,7 +33,7 @@
{
public:
ProducerListener() {}
- virtual ~ProducerListener() {}
+ virtual ~ProducerListener();
// onBufferReleased is called from IGraphicBufferConsumer::releaseBuffer to
// notify the producer that a new buffer is free and ready to be dequeued.
@@ -61,6 +61,7 @@
class DummyProducerListener : public BnProducerListener
{
public:
+ virtual ~DummyProducerListener();
virtual void onBufferReleased() {}
virtual bool needsReleaseNotify() { return false; }
};
diff --git a/include/gui/ISensorEventConnection.h b/include/gui/ISensorEventConnection.h
index f64c6b8..857444b 100644
--- a/include/gui/ISensorEventConnection.h
+++ b/include/gui/ISensorEventConnection.h
@@ -33,7 +33,7 @@
class ISensorEventConnection : public IInterface
{
public:
- DECLARE_META_INTERFACE(SensorEventConnection);
+ DECLARE_META_INTERFACE(SensorEventConnection)
virtual sp<BitTube> getSensorChannel() const = 0;
virtual status_t enableDisable(int handle, bool enabled, nsecs_t samplingPeriodNs,
diff --git a/include/gui/ISensorServer.h b/include/gui/ISensorServer.h
index 571acb5..737c430 100644
--- a/include/gui/ISensorServer.h
+++ b/include/gui/ISensorServer.h
@@ -35,7 +35,7 @@
class ISensorServer : public IInterface
{
public:
- DECLARE_META_INTERFACE(SensorServer);
+ DECLARE_META_INTERFACE(SensorServer)
virtual Vector<Sensor> getSensorList(const String16& opPackageName) = 0;
virtual Vector<Sensor> getDynamicSensorList(const String16& opPackageName) = 0;
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index 74a4123..555a0cc 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -35,8 +35,8 @@
namespace android {
// ----------------------------------------------------------------------------
-class ComposerState;
-class DisplayState;
+struct ComposerState;
+struct DisplayState;
struct DisplayInfo;
struct DisplayStatInfo;
class HdrCapabilities;
@@ -50,7 +50,7 @@
*/
class ISurfaceComposer: public IInterface {
public:
- DECLARE_META_INTERFACE(SurfaceComposer);
+ DECLARE_META_INTERFACE(SurfaceComposer)
// flags for setTransactionState()
enum {
diff --git a/include/gui/ISurfaceComposerClient.h b/include/gui/ISurfaceComposerClient.h
index c27a741..4a4efb6 100644
--- a/include/gui/ISurfaceComposerClient.h
+++ b/include/gui/ISurfaceComposerClient.h
@@ -36,7 +36,7 @@
class ISurfaceComposerClient : public IInterface
{
public:
- DECLARE_META_INTERFACE(SurfaceComposerClient);
+ DECLARE_META_INTERFACE(SurfaceComposerClient)
// flags for createSurface()
enum { // (keep in sync with Surface.java)
diff --git a/include/gui/OccupancyTracker.h b/include/gui/OccupancyTracker.h
index 1d15e7f..d4de8f2 100644
--- a/include/gui/OccupancyTracker.h
+++ b/include/gui/OccupancyTracker.h
@@ -45,12 +45,12 @@
occupancyAverage(0.0f),
usedThirdBuffer(false) {}
- Segment(nsecs_t totalTime, size_t numFrames, float occupancyAverage,
- bool usedThirdBuffer)
- : totalTime(totalTime),
- numFrames(numFrames),
- occupancyAverage(occupancyAverage),
- usedThirdBuffer(usedThirdBuffer) {}
+ Segment(nsecs_t _totalTime, size_t _numFrames, float _occupancyAverage,
+ bool _usedThirdBuffer)
+ : totalTime(_totalTime),
+ numFrames(_numFrames),
+ occupancyAverage(_occupancyAverage),
+ usedThirdBuffer(_usedThirdBuffer) {}
// Parcelable interface
virtual status_t writeToParcel(Parcel* parcel) const override;
diff --git a/include/gui/Sensor.h b/include/gui/Sensor.h
index 094fd16..7506835 100644
--- a/include/gui/Sensor.h
+++ b/include/gui/Sensor.h
@@ -61,6 +61,9 @@
uuid_t() : b{0} {}
};
+ Sensor(const Sensor&) = default;
+ Sensor& operator=(const Sensor&) = default;
+
Sensor(const char * name = "");
Sensor(struct sensor_t const* hwSensor, int halVersion = 0);
Sensor(struct sensor_t const& hwSensor, const uuid_t& uuid, int halVersion = 0);
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index f4a22cb..489d5ea 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -66,7 +66,7 @@
* the controlledByApp flag indicates that this Surface (producer) is
* controlled by the application. This flag is used at connect time.
*/
- Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp = false);
+ explicit Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp = false);
/* getIGraphicBufferProducer() returns the IGraphicBufferProducer this
* Surface was created with. Usually it's an error to use the
diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
index c4f88b6..f2932f2 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/include/gui/SurfaceComposerClient.h
@@ -38,7 +38,7 @@
// ---------------------------------------------------------------------------
-class DisplayInfo;
+struct DisplayInfo;
class Composer;
class HdrCapabilities;
class ISurfaceComposerClient;
diff --git a/include/input/IInputFlinger.h b/include/input/IInputFlinger.h
index 629310f..11bb721 100644
--- a/include/input/IInputFlinger.h
+++ b/include/input/IInputFlinger.h
@@ -30,7 +30,7 @@
*/
class IInputFlinger : public IInterface {
public:
- DECLARE_META_INTERFACE(InputFlinger);
+ DECLARE_META_INTERFACE(InputFlinger)
};
diff --git a/include/input/Input.h b/include/input/Input.h
index 55787e7..cfcafab 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -398,7 +398,7 @@
inline int32_t getButtonState() const { return mButtonState; }
- inline int32_t setButtonState(int32_t buttonState) { mButtonState = buttonState; }
+ inline void setButtonState(int32_t buttonState) { mButtonState = buttonState; }
inline int32_t getActionButton() const { return mActionButton; }
diff --git a/include/input/InputEventLabels.h b/include/input/InputEventLabels.h
index 0bd14ea..20154eb 100644
--- a/include/input/InputEventLabels.h
+++ b/include/input/InputEventLabels.h
@@ -425,30 +425,30 @@
return NULL;
}
-static int32_t getKeyCodeByLabel(const char* label) {
+static inline int32_t getKeyCodeByLabel(const char* label) {
return int32_t(lookupValueByLabel(label, KEYCODES));
}
-static const char* getLabelByKeyCode(int32_t keyCode) {
- if (keyCode >= 0 && keyCode < size(KEYCODES)) {
+static inline const char* getLabelByKeyCode(int32_t keyCode) {
+ if (keyCode >= 0 && keyCode < static_cast<int32_t>(size(KEYCODES))) {
return KEYCODES[keyCode].literal;
}
return NULL;
}
-static uint32_t getKeyFlagByLabel(const char* label) {
+static inline uint32_t getKeyFlagByLabel(const char* label) {
return uint32_t(lookupValueByLabel(label, FLAGS));
}
-static int32_t getAxisByLabel(const char* label) {
+static inline int32_t getAxisByLabel(const char* label) {
return int32_t(lookupValueByLabel(label, AXES));
}
-static const char* getAxisLabel(int32_t axisId) {
+static inline const char* getAxisLabel(int32_t axisId) {
return lookupLabelByValue(axisId, AXES);
}
-static int32_t getLedByLabel(const char* label) {
+static inline int32_t getLedByLabel(const char* label) {
return int32_t(lookupValueByLabel(label, LEDS));
}
diff --git a/include/media/hardware/HDCPAPI.h b/include/media/hardware/HDCPAPI.h
index 3a53e9f..30cd5fd 100644
--- a/include/media/hardware/HDCPAPI.h
+++ b/include/media/hardware/HDCPAPI.h
@@ -73,7 +73,7 @@
// Module can call the notification function to signal completion/failure
// of asynchronous operations (such as initialization) or out of band
// events.
- HDCPModule(void *cookie, ObserverFunc observerNotify) {};
+ HDCPModule(void * /*cookie*/, ObserverFunc /*observerNotify*/) {};
virtual ~HDCPModule() {};
@@ -104,8 +104,8 @@
// 1 for the second and so on)
// inputCTR _will_be_maintained_by_the_callee_ for each PES stream.
virtual status_t encrypt(
- const void *inData, size_t size, uint32_t streamCTR,
- uint64_t *outInputCTR, void *outData) {
+ const void * /*inData*/, size_t /*size*/, uint32_t /*streamCTR*/,
+ uint64_t * /*outInputCTR*/, void * /*outData*/) {
return INVALID_OPERATION;
}
@@ -119,8 +119,8 @@
// 1 for the second and so on)
// inputCTR _will_be_maintained_by_the_callee_ for each PES stream.
virtual status_t encryptNative(
- buffer_handle_t buffer, size_t offset, size_t size,
- uint32_t streamCTR, uint64_t *outInputCTR, void *outData) {
+ buffer_handle_t /*buffer*/, size_t /*offset*/, size_t /*size*/,
+ uint32_t /*streamCTR*/, uint64_t * /*outInputCTR*/, void * /*outData*/) {
return INVALID_OPERATION;
}
// DECRYPTION only:
@@ -133,9 +133,9 @@
// until outData contains size bytes of decrypted data.
// Both streamCTR and inputCTR will be provided by the caller.
virtual status_t decrypt(
- const void *inData, size_t size,
- uint32_t streamCTR, uint64_t inputCTR,
- void *outData) {
+ const void * /*inData*/, size_t /*size*/,
+ uint32_t /*streamCTR*/, uint64_t /*inputCTR*/,
+ void * /*outData*/) {
return INVALID_OPERATION;
}
diff --git a/include/media/hardware/HardwareAPI.h b/include/media/hardware/HardwareAPI.h
index 2c50ad6..cecf715 100644
--- a/include/media/hardware/HardwareAPI.h
+++ b/include/media/hardware/HardwareAPI.h
@@ -270,7 +270,7 @@
// output: fill out the MediaImage fields
MediaImage sMediaImage;
- DescribeColorFormatParams(const DescribeColorFormat2Params&); // for internal use only
+ explicit DescribeColorFormatParams(const DescribeColorFormat2Params&); // for internal use only
};
// A pointer to this struct is passed to OMX_GetParameter when the extension
diff --git a/include/media/hardware/VideoAPI.h b/include/media/hardware/VideoAPI.h
index 3667c4b..a090876 100644
--- a/include/media/hardware/VideoAPI.h
+++ b/include/media/hardware/VideoAPI.h
@@ -110,7 +110,7 @@
// though could verify that nSize is at least the size of the structure at the
// time of implementation. All new fields will be added at the end of the structure
// ensuring backward compatibility.
-struct __attribute__ ((__packed__)) ColorAspects {
+struct __attribute__ ((__packed__, aligned(alignof(uint32_t)))) ColorAspects {
// this is in sync with the range values in graphics.h
enum Range : uint32_t {
RangeUnspecified,
diff --git a/include/media/openmax/OMX_Core.h b/include/media/openmax/OMX_Core.h
index 88dd585..bb974b3 100644
--- a/include/media/openmax/OMX_Core.h
+++ b/include/media/openmax/OMX_Core.h
@@ -738,7 +738,7 @@
pComponentVersion, \
pSpecVersion, \
pComponentUUID) \
- ((OMX_COMPONENTTYPE*)hComponent)->GetComponentVersion( \
+ ((OMX_COMPONENTTYPE*)(hComponent))->GetComponentVersion(\
hComponent, \
pComponentName, \
pComponentVersion, \
@@ -804,7 +804,7 @@
Cmd, \
nParam, \
pCmdData) \
- ((OMX_COMPONENTTYPE*)hComponent)->SendCommand( \
+ ((OMX_COMPONENTTYPE*)(hComponent))->SendCommand( \
hComponent, \
Cmd, \
nParam, \
@@ -843,8 +843,8 @@
#define OMX_GetParameter( \
hComponent, \
nParamIndex, \
- pComponentParameterStructure) \
- ((OMX_COMPONENTTYPE*)hComponent)->GetParameter( \
+ pComponentParameterStructure) \
+ ((OMX_COMPONENTTYPE*)(hComponent))->GetParameter( \
hComponent, \
nParamIndex, \
pComponentParameterStructure) /* Macro End */
@@ -882,8 +882,8 @@
#define OMX_SetParameter( \
hComponent, \
nParamIndex, \
- pComponentParameterStructure) \
- ((OMX_COMPONENTTYPE*)hComponent)->SetParameter( \
+ pComponentParameterStructure) \
+ ((OMX_COMPONENTTYPE*)(hComponent))->SetParameter( \
hComponent, \
nParamIndex, \
pComponentParameterStructure) /* Macro End */
@@ -918,8 +918,8 @@
#define OMX_GetConfig( \
hComponent, \
nConfigIndex, \
- pComponentConfigStructure) \
- ((OMX_COMPONENTTYPE*)hComponent)->GetConfig( \
+ pComponentConfigStructure) \
+ ((OMX_COMPONENTTYPE*)(hComponent))->GetConfig( \
hComponent, \
nConfigIndex, \
pComponentConfigStructure) /* Macro End */
@@ -954,8 +954,8 @@
#define OMX_SetConfig( \
hComponent, \
nConfigIndex, \
- pComponentConfigStructure) \
- ((OMX_COMPONENTTYPE*)hComponent)->SetConfig( \
+ pComponentConfigStructure) \
+ ((OMX_COMPONENTTYPE*)(hComponent))->SetConfig( \
hComponent, \
nConfigIndex, \
pComponentConfigStructure) /* Macro End */
@@ -989,7 +989,7 @@
hComponent, \
cParameterName, \
pIndexType) \
- ((OMX_COMPONENTTYPE*)hComponent)->GetExtensionIndex( \
+ ((OMX_COMPONENTTYPE*)(hComponent))->GetExtensionIndex( \
hComponent, \
cParameterName, \
pIndexType) /* Macro End */
@@ -1015,7 +1015,7 @@
#define OMX_GetState( \
hComponent, \
pState) \
- ((OMX_COMPONENTTYPE*)hComponent)->GetState( \
+ ((OMX_COMPONENTTYPE*)(hComponent))->GetState( \
hComponent, \
pState) /* Macro End */
@@ -1046,7 +1046,7 @@
pAppPrivate, \
nSizeBytes, \
pBuffer) \
- ((OMX_COMPONENTTYPE*)hComponent)->UseBuffer( \
+ ((OMX_COMPONENTTYPE*)(hComponent))->UseBuffer( \
hComponent, \
ppBufferHdr, \
nPortIndex, \
@@ -1088,7 +1088,7 @@
nPortIndex, \
pAppPrivate, \
nSizeBytes) \
- ((OMX_COMPONENTTYPE*)hComponent)->AllocateBuffer( \
+ ((OMX_COMPONENTTYPE*)(hComponent))->AllocateBuffer( \
hComponent, \
ppBuffer, \
nPortIndex, \
@@ -1122,7 +1122,7 @@
hComponent, \
nPortIndex, \
pBuffer) \
- ((OMX_COMPONENTTYPE*)hComponent)->FreeBuffer( \
+ ((OMX_COMPONENTTYPE*)(hComponent))->FreeBuffer( \
hComponent, \
nPortIndex, \
pBuffer) /* Macro End */
@@ -1153,7 +1153,7 @@
#define OMX_EmptyThisBuffer( \
hComponent, \
pBuffer) \
- ((OMX_COMPONENTTYPE*)hComponent)->EmptyThisBuffer( \
+ ((OMX_COMPONENTTYPE*)(hComponent))->EmptyThisBuffer( \
hComponent, \
pBuffer) /* Macro End */
@@ -1183,7 +1183,7 @@
#define OMX_FillThisBuffer( \
hComponent, \
pBuffer) \
- ((OMX_COMPONENTTYPE*)hComponent)->FillThisBuffer( \
+ ((OMX_COMPONENTTYPE*)(hComponent))->FillThisBuffer( \
hComponent, \
pBuffer) /* Macro End */
@@ -1225,7 +1225,7 @@
nPortIndex, \
pAppPrivate, \
eglImage) \
- ((OMX_COMPONENTTYPE*)hComponent)->UseEGLImage( \
+ ((OMX_COMPONENTTYPE*)(hComponent))->UseEGLImage( \
hComponent, \
ppBufferHdr, \
nPortIndex, \
diff --git a/include/powermanager/IPowerManager.h b/include/powermanager/IPowerManager.h
index 461fad7..3230189 100644
--- a/include/powermanager/IPowerManager.h
+++ b/include/powermanager/IPowerManager.h
@@ -50,7 +50,7 @@
CRASH = IBinder::FIRST_CALL_TRANSACTION + 16,
};
- DECLARE_META_INTERFACE(PowerManager);
+ DECLARE_META_INTERFACE(PowerManager)
// The parcels created by these methods must be kept in sync with the
// corresponding methods from IPowerManager.aidl.
diff --git a/include/private/binder/binder_module.h b/include/private/binder/binder_module.h
index a8dd64f..2f11622 100644
--- a/include/private/binder/binder_module.h
+++ b/include/private/binder/binder_module.h
@@ -24,7 +24,7 @@
/* obtain structures and constants from the kernel header */
#include <sys/ioctl.h>
-#include <linux/binder.h>
+#include <linux/android/binder.h>
#ifdef __cplusplus
} // namespace android
diff --git a/include/private/ui/RegionHelper.h b/include/private/ui/RegionHelper.h
index 84eb100..a22b2cb 100644
--- a/include/private/ui/RegionHelper.h
+++ b/include/private/ui/RegionHelper.h
@@ -27,10 +27,10 @@
class region_operator
{
public:
- typedef typename RECT::value_type TYPE;
- static const TYPE max_value = 0x7FFFFFF;
+ typedef typename RECT::value_type TYPE;
+ static const TYPE max_value = std::numeric_limits<TYPE>::max();
- /*
+ /*
* Common boolean operations:
* value is computed as 0b101 op 0b110
* other boolean operation are possible, simply compute
@@ -53,20 +53,20 @@
TYPE dy;
inline region(const region& rhs)
: rects(rhs.rects), count(rhs.count), dx(rhs.dx), dy(rhs.dy) { }
- inline region(RECT const* r, size_t c)
- : rects(r), count(c), dx(), dy() { }
- inline region(RECT const* r, size_t c, TYPE dx, TYPE dy)
- : rects(r), count(c), dx(dx), dy(dy) { }
+ inline region(RECT const* _r, size_t _c)
+ : rects(_r), count(_c), dx(), dy() { }
+ inline region(RECT const* _r, size_t _c, TYPE _dx, TYPE _dy)
+ : rects(_r), count(_c), dx(_dx), dy(_dy) { }
};
class region_rasterizer {
friend class region_operator;
virtual void operator()(const RECT& rect) = 0;
public:
- virtual ~region_rasterizer() { };
+ virtual ~region_rasterizer() { }
};
- inline region_operator(int op, const region& lhs, const region& rhs)
+ inline region_operator(uint32_t op, const region& lhs, const region& rhs)
: op_mask(op), spanner(lhs, rhs)
{
}
@@ -79,8 +79,8 @@
spannerInner.prepare(inside);
do {
TYPE left, right;
- int inside = spannerInner.next(current.left, current.right);
- if ((op_mask >> inside) & 1) {
+ int inner_inside = spannerInner.next(current.left, current.right);
+ if ((op_mask >> inner_inside) & 1) {
if (current.left < current.right &&
current.top < current.bottom) {
rasterizer(current);
@@ -162,8 +162,8 @@
region rhs;
public:
- inline Spanner(const region& lhs, const region& rhs)
- : lhs(lhs), rhs(rhs)
+ inline Spanner(const region& _lhs, const region& _rhs)
+ : lhs(_lhs), rhs(_rhs)
{
if (lhs.count) {
SpannerBase::lhs_head = lhs.rects->top + lhs.dy;
@@ -223,8 +223,8 @@
region rhs;
public:
- inline SpannerInner(const region& lhs, const region& rhs)
- : lhs(lhs), rhs(rhs)
+ inline SpannerInner(const region& _lhs, const region& _rhs)
+ : lhs(_lhs), rhs(_rhs)
{
}
diff --git a/include/ui/Fence.h b/include/ui/Fence.h
index 48a7aa3..1df15f8 100644
--- a/include/ui/Fence.h
+++ b/include/ui/Fence.h
@@ -55,7 +55,7 @@
// Construct a new Fence object to manage a given fence file descriptor.
// When the new Fence object is destructed the file descriptor will be
// closed.
- Fence(int fenceFd);
+ explicit Fence(int fenceFd);
// Check whether the Fence has an open fence file descriptor. Most Fence
// methods treat an invalid file descriptor just like a valid fence that
diff --git a/include/ui/FrameStats.h b/include/ui/FrameStats.h
index 6bfe635..bc9d3ec 100644
--- a/include/ui/FrameStats.h
+++ b/include/ui/FrameStats.h
@@ -25,7 +25,7 @@
class FrameStats : public LightFlattenable<FrameStats> {
public:
- FrameStats() : refreshPeriodNano(0) {};
+ FrameStats() : refreshPeriodNano(0) {}
/*
* Approximate refresh time, in nanoseconds.
diff --git a/include/ui/Gralloc1On0Adapter.h b/include/ui/Gralloc1On0Adapter.h
index 97c9a89..d523c4f 100644
--- a/include/ui/Gralloc1On0Adapter.h
+++ b/include/ui/Gralloc1On0Adapter.h
@@ -81,7 +81,7 @@
uint32_t* outCount,
int32_t* /*gralloc1_capability_t*/ outCapabilities) {
getAdapter(device)->doGetCapabilities(outCount, outCapabilities);
- };
+ }
// getFunction
@@ -104,7 +104,7 @@
// Buffer descriptor lifecycle functions
- class Descriptor;
+ struct Descriptor;
gralloc1_error_t createDescriptor(
gralloc1_buffer_descriptor_t* outDescriptor);
@@ -124,10 +124,10 @@
// Buffer descriptor modification functions
struct Descriptor : public std::enable_shared_from_this<Descriptor> {
- Descriptor(Gralloc1On0Adapter* adapter,
- gralloc1_buffer_descriptor_t id)
- : adapter(adapter),
- id(id),
+ Descriptor(Gralloc1On0Adapter* _adapter,
+ gralloc1_buffer_descriptor_t _id)
+ : adapter(_adapter),
+ id(_id),
width(0),
height(0),
format(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
@@ -416,10 +416,10 @@
if (!outData) {
const auto producerCpuUsage = GRALLOC1_PRODUCER_USAGE_CPU_READ |
GRALLOC1_PRODUCER_USAGE_CPU_WRITE;
- if (producerUsage & producerCpuUsage != 0) {
+ if ((producerUsage & producerCpuUsage) != 0) {
return static_cast<int32_t>(GRALLOC1_ERROR_BAD_VALUE);
}
- if (consumerUsage & GRALLOC1_CONSUMER_USAGE_CPU_READ != 0) {
+ if ((consumerUsage & GRALLOC1_CONSUMER_USAGE_CPU_READ) != 0) {
return static_cast<int32_t>(GRALLOC1_ERROR_BAD_VALUE);
}
}
diff --git a/include/ui/HdrCapabilities.h b/include/ui/HdrCapabilities.h
index a7cd5fb..8f6b7a6 100644
--- a/include/ui/HdrCapabilities.h
+++ b/include/ui/HdrCapabilities.h
@@ -41,7 +41,7 @@
mMaxAverageLuminance(-1.0f),
mMinLuminance(-1.0f) {}
- virtual ~HdrCapabilities() = default;
+ ~HdrCapabilities() override = default;
const std::vector<int32_t /*android_hdr_t*/>& getSupportedHdrTypes() const {
return mSupportedHdrTypes;
diff --git a/include/ui/Point.h b/include/ui/Point.h
index 1d7f64d..d050ede 100644
--- a/include/ui/Point.h
+++ b/include/ui/Point.h
@@ -34,7 +34,7 @@
// Default constructor doesn't initialize the Point
inline Point() {
}
- inline Point(int x, int y) : x(x), y(y) {
+ inline Point(int _x, int _y) : x(_x), y(_y) {
}
inline bool operator == (const Point& rhs) const {
diff --git a/include/ui/Rect.h b/include/ui/Rect.h
index a8513a9..a7eb871 100644
--- a/include/ui/Rect.h
+++ b/include/ui/Rect.h
@@ -20,6 +20,8 @@
#include <utils/Flattenable.h>
#include <utils/Log.h>
#include <utils/TypeHelpers.h>
+#include <log/log.h>
+
#include <ui/Point.h>
#include <android/rect.h>
@@ -42,13 +44,9 @@
template <typename T>
inline Rect(T w, T h) {
if (w > INT32_MAX) {
- ALOG(LOG_WARN, "Rect",
- "Width %u too large for Rect class, clamping", w);
w = INT32_MAX;
}
if (h > INT32_MAX) {
- ALOG(LOG_WARN, "Rect",
- "Height %u too large for Rect class, clamping", h);
h = INT32_MAX;
}
left = top = 0;
diff --git a/include/ui/Region.h b/include/ui/Region.h
index 810f098..7788452 100644
--- a/include/ui/Region.h
+++ b/include/ui/Region.h
@@ -147,21 +147,21 @@
class rasterizer;
friend class rasterizer;
- Region& operationSelf(const Rect& r, int op);
- Region& operationSelf(const Region& r, int op);
- Region& operationSelf(const Region& r, int dx, int dy, int op);
- const Region operation(const Rect& rhs, int op) const;
- const Region operation(const Region& rhs, int op) const;
- const Region operation(const Region& rhs, int dx, int dy, int op) const;
+ Region& operationSelf(const Rect& r, uint32_t op);
+ Region& operationSelf(const Region& r, uint32_t op);
+ Region& operationSelf(const Region& r, int dx, int dy, uint32_t op);
+ const Region operation(const Rect& rhs, uint32_t op) const;
+ const Region operation(const Region& rhs, uint32_t op) const;
+ const Region operation(const Region& rhs, int dx, int dy, uint32_t op) const;
- static void boolean_operation(int op, Region& dst,
+ static void boolean_operation(uint32_t op, Region& dst,
const Region& lhs, const Region& rhs, int dx, int dy);
- static void boolean_operation(int op, Region& dst,
+ static void boolean_operation(uint32_t op, Region& dst,
const Region& lhs, const Rect& rhs, int dx, int dy);
- static void boolean_operation(int op, Region& dst,
+ static void boolean_operation(uint32_t op, Region& dst,
const Region& lhs, const Region& rhs);
- static void boolean_operation(int op, Region& dst,
+ static void boolean_operation(uint32_t op, Region& dst,
const Region& lhs, const Rect& rhs);
static void translate(Region& reg, int dx, int dy);
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
new file mode 100644
index 0000000..f7347ae
--- /dev/null
+++ b/libs/binder/Android.bp
@@ -0,0 +1,79 @@
+// Copyright (C) 2009 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library {
+ name: "libbinder",
+
+ // for vndbinder
+ vendor_available: true,
+
+ srcs: [
+ "AppOpsManager.cpp",
+ "Binder.cpp",
+ "BpBinder.cpp",
+ "BufferedTextOutput.cpp",
+ "Debug.cpp",
+ "IAppOpsCallback.cpp",
+ "IAppOpsService.cpp",
+ "IBatteryStats.cpp",
+ "IInterface.cpp",
+ "IMediaResourceMonitor.cpp",
+ "IMemory.cpp",
+ "IPCThreadState.cpp",
+ "IPermissionController.cpp",
+ "IProcessInfoService.cpp",
+ "IResultReceiver.cpp",
+ "IServiceManager.cpp",
+ "MemoryBase.cpp",
+ "MemoryDealer.cpp",
+ "MemoryHeapBase.cpp",
+ "Parcel.cpp",
+ "PermissionCache.cpp",
+ "PersistableBundle.cpp",
+ "ProcessInfoService.cpp",
+ "ProcessState.cpp",
+ "Static.cpp",
+ "Status.cpp",
+ "TextOutput.cpp",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+ product_variables: {
+ binder32bit: {
+ cflags: ["-DBINDER_IPC_32BIT=1"],
+ },
+ },
+
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libcutils",
+ "libutils",
+ ],
+ export_shared_lib_headers: [
+ "libbase",
+ "libutils",
+ ],
+
+ clang: true,
+ sanitize: {
+ misc_undefined: ["integer"],
+ },
+}
+
+subdirs = ["tests"]
diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk
deleted file mode 100644
index 14be920..0000000
--- a/libs/binder/Android.mk
+++ /dev/null
@@ -1,72 +0,0 @@
-# Copyright (C) 2009 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.
-
-# we have the common sources, plus some device-specific stuff
-sources := \
- AppOpsManager.cpp \
- Binder.cpp \
- BpBinder.cpp \
- BufferedTextOutput.cpp \
- Debug.cpp \
- IAppOpsCallback.cpp \
- IAppOpsService.cpp \
- IBatteryStats.cpp \
- IInterface.cpp \
- IMediaResourceMonitor.cpp \
- IMemory.cpp \
- IPCThreadState.cpp \
- IPermissionController.cpp \
- IProcessInfoService.cpp \
- IResultReceiver.cpp \
- IServiceManager.cpp \
- MemoryBase.cpp \
- MemoryDealer.cpp \
- MemoryHeapBase.cpp \
- Parcel.cpp \
- PermissionCache.cpp \
- PersistableBundle.cpp \
- ProcessInfoService.cpp \
- ProcessState.cpp \
- Static.cpp \
- Status.cpp \
- TextOutput.cpp \
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libbinder
-LOCAL_SHARED_LIBRARIES := liblog libcutils libutils
-
-LOCAL_CLANG := true
-LOCAL_SANITIZE := integer
-LOCAL_SRC_FILES := $(sources)
-ifneq ($(TARGET_USES_64_BIT_BINDER),true)
-ifneq ($(TARGET_IS_64_BIT),true)
-LOCAL_CFLAGS += -DBINDER_IPC_32BIT=1
-endif
-endif
-LOCAL_CFLAGS += -Werror
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libbinder
-LOCAL_STATIC_LIBRARIES += libutils
-LOCAL_SRC_FILES := $(sources)
-ifneq ($(TARGET_USES_64_BIT_BINDER),true)
-ifneq ($(TARGET_IS_64_BIT),true)
-LOCAL_CFLAGS += -DBINDER_IPC_32BIT=1
-endif
-endif
-LOCAL_CFLAGS += -Werror
-include $(BUILD_STATIC_LIBRARY)
diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp
index 9a061a0..f3b86ae 100644
--- a/libs/binder/AppOpsManager.cpp
+++ b/libs/binder/AppOpsManager.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <mutex>
#include <binder/AppOpsManager.h>
#include <binder/Binder.h>
#include <binder/IServiceManager.h>
@@ -22,6 +23,19 @@
namespace android {
+namespace {
+
+#if defined(__BRILLO__)
+// Because Brillo has no application model, security policy is managed
+// statically (at build time) with SELinux controls.
+// As a consequence, it also never runs the AppOpsManager service.
+const int APP_OPS_MANAGER_UNAVAILABLE_MODE = AppOpsManager::MODE_ALLOWED;
+#else
+const int APP_OPS_MANAGER_UNAVAILABLE_MODE = AppOpsManager::MODE_IGNORED;
+#endif // defined(__BRILLO__)
+
+} // namespace
+
static String16 _appops("appops");
static pthread_mutex_t gTokenMutex = PTHREAD_MUTEX_INITIALIZER;
static sp<IBinder> gToken;
@@ -39,10 +53,15 @@
{
}
+#if defined(__BRILLO__)
+// There is no AppOpsService on Brillo
+sp<IAppOpsService> AppOpsManager::getService() { return NULL; }
+#else
sp<IAppOpsService> AppOpsManager::getService()
{
+
+ std::lock_guard<Mutex> scoped_lock(mLock);
int64_t startTime = 0;
- mLock.lock();
sp<IAppOpsService> service = mService;
while (service == NULL || !IInterface::asBinder(service)->isBinderAlive()) {
sp<IBinder> binder = defaultServiceManager()->checkService(_appops);
@@ -53,7 +72,8 @@
ALOGI("Waiting for app ops service");
} else if ((uptimeMillis()-startTime) > 10000) {
ALOGW("Waiting too long for app ops service, giving up");
- return NULL;
+ service = NULL;
+ break;
}
sleep(1);
} else {
@@ -61,25 +81,30 @@
mService = service;
}
}
- mLock.unlock();
return service;
}
+#endif // defined(__BRILLO__)
int32_t AppOpsManager::checkOp(int32_t op, int32_t uid, const String16& callingPackage)
{
sp<IAppOpsService> service = getService();
- return service != NULL ? service->checkOperation(op, uid, callingPackage) : MODE_IGNORED;
+ return service != NULL
+ ? service->checkOperation(op, uid, callingPackage)
+ : APP_OPS_MANAGER_UNAVAILABLE_MODE;
}
int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage) {
sp<IAppOpsService> service = getService();
- return service != NULL ? service->noteOperation(op, uid, callingPackage) : MODE_IGNORED;
+ return service != NULL
+ ? service->noteOperation(op, uid, callingPackage)
+ : APP_OPS_MANAGER_UNAVAILABLE_MODE;
}
int32_t AppOpsManager::startOp(int32_t op, int32_t uid, const String16& callingPackage) {
sp<IAppOpsService> service = getService();
- return service != NULL ? service->startOperation(getToken(service), op, uid, callingPackage)
- : MODE_IGNORED;
+ return service != NULL
+ ? service->startOperation(getToken(service), op, uid, callingPackage)
+ : APP_OPS_MANAGER_UNAVAILABLE_MODE;
}
void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage) {
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index c4d47ca..7ce2a31 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -237,6 +237,10 @@
// XXX can't add virtuals until binaries are updated.
//return shellCommand(in, out, err, args, resultReceiver);
+ (void)in;
+ (void)out;
+ (void)err;
+
if (resultReceiver != NULL) {
resultReceiver->send(INVALID_OPERATION);
}
diff --git a/libs/binder/BufferedTextOutput.cpp b/libs/binder/BufferedTextOutput.cpp
index 1339a67..a2443c0 100644
--- a/libs/binder/BufferedTextOutput.cpp
+++ b/libs/binder/BufferedTextOutput.cpp
@@ -34,7 +34,7 @@
struct BufferedTextOutput::BufferState : public RefBase
{
- BufferState(int32_t _seq)
+ explicit BufferState(int32_t _seq)
: seq(_seq)
, buffer(NULL)
, bufferPos(0)
diff --git a/libs/binder/IAppOpsCallback.cpp b/libs/binder/IAppOpsCallback.cpp
index 2aaf566..f9ec593 100644
--- a/libs/binder/IAppOpsCallback.cpp
+++ b/libs/binder/IAppOpsCallback.cpp
@@ -31,7 +31,7 @@
class BpAppOpsCallback : public BpInterface<IAppOpsCallback>
{
public:
- BpAppOpsCallback(const sp<IBinder>& impl)
+ explicit BpAppOpsCallback(const sp<IBinder>& impl)
: BpInterface<IAppOpsCallback>(impl)
{
}
diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp
index 9558376..638ae5c 100644
--- a/libs/binder/IAppOpsService.cpp
+++ b/libs/binder/IAppOpsService.cpp
@@ -31,7 +31,7 @@
class BpAppOpsService : public BpInterface<IAppOpsService>
{
public:
- BpAppOpsService(const sp<IBinder>& impl)
+ explicit BpAppOpsService(const sp<IBinder>& impl)
: BpInterface<IAppOpsService>(impl)
{
}
diff --git a/libs/binder/IBatteryStats.cpp b/libs/binder/IBatteryStats.cpp
index e32c628..ad1e69f 100644
--- a/libs/binder/IBatteryStats.cpp
+++ b/libs/binder/IBatteryStats.cpp
@@ -29,7 +29,7 @@
class BpBatteryStats : public BpInterface<IBatteryStats>
{
public:
- BpBatteryStats(const sp<IBinder>& impl)
+ explicit BpBatteryStats(const sp<IBinder>& impl)
: BpInterface<IBatteryStats>(impl)
{
}
diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp
index 5f345cf..6b5b1af 100644
--- a/libs/binder/IMemory.cpp
+++ b/libs/binder/IMemory.cpp
@@ -16,22 +16,21 @@
#define LOG_TAG "IMemory"
+#include <atomic>
+#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
-#include <fcntl.h>
-#include <unistd.h>
-
#include <sys/types.h>
#include <sys/mman.h>
+#include <unistd.h>
#include <binder/IMemory.h>
-#include <cutils/log.h>
+#include <binder/Parcel.h>
+#include <log/log.h>
+#include <utils/CallStack.h>
#include <utils/KeyedVector.h>
#include <utils/threads.h>
-#include <utils/Atomic.h>
-#include <binder/Parcel.h>
-#include <utils/CallStack.h>
#define VERBOSE 0
@@ -56,12 +55,15 @@
struct heap_info_t {
sp<IMemoryHeap> heap;
int32_t count;
+ // Note that this cannot be meaningfully copied.
};
void free_heap(const wp<IBinder>& binder);
- Mutex mHeapCacheLock;
+ Mutex mHeapCacheLock; // Protects entire vector below.
KeyedVector< wp<IBinder>, heap_info_t > mHeapCache;
+ // We do not use the copy-on-write capabilities of KeyedVector.
+ // TODO: Reimplemement based on standard C++ container?
};
static sp<HeapCache> gHeapCache = new HeapCache();
@@ -75,7 +77,7 @@
class BpMemoryHeap : public BpInterface<IMemoryHeap>
{
public:
- BpMemoryHeap(const sp<IBinder>& impl);
+ explicit BpMemoryHeap(const sp<IBinder>& impl);
virtual ~BpMemoryHeap();
virtual int getHeapID() const;
@@ -105,7 +107,7 @@
void assertMapped() const;
void assertReallyMapped() const;
- mutable volatile int32_t mHeapId;
+ mutable std::atomic<int32_t> mHeapId;
mutable void* mBase;
mutable size_t mSize;
mutable uint32_t mFlags;
@@ -123,7 +125,7 @@
class BpMemory : public BpInterface<IMemory>
{
public:
- BpMemory(const sp<IBinder>& impl);
+ explicit BpMemory(const sp<IBinder>& impl);
virtual ~BpMemory();
virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const;
@@ -248,8 +250,9 @@
}
BpMemoryHeap::~BpMemoryHeap() {
- if (mHeapId != -1) {
- close(mHeapId);
+ int32_t heapId = mHeapId.load(memory_order_relaxed);
+ if (heapId != -1) {
+ close(heapId);
if (mRealHeap) {
// by construction we're the last one
if (mBase != MAP_FAILED) {
@@ -257,7 +260,7 @@
if (VERBOSE) {
ALOGD("UNMAPPING binder=%p, heap=%p, size=%zu, fd=%d",
- binder.get(), this, mSize, mHeapId);
+ binder.get(), this, mSize, heapId);
CallStack stack(LOG_TAG);
}
@@ -273,17 +276,21 @@
void BpMemoryHeap::assertMapped() const
{
- if (mHeapId == -1) {
+ int32_t heapId = mHeapId.load(memory_order_acquire);
+ if (heapId == -1) {
sp<IBinder> binder(IInterface::asBinder(const_cast<BpMemoryHeap*>(this)));
sp<BpMemoryHeap> heap(static_cast<BpMemoryHeap*>(find_heap(binder).get()));
heap->assertReallyMapped();
if (heap->mBase != MAP_FAILED) {
Mutex::Autolock _l(mLock);
- if (mHeapId == -1) {
+ if (mHeapId.load(memory_order_relaxed) == -1) {
mBase = heap->mBase;
mSize = heap->mSize;
mOffset = heap->mOffset;
- android_atomic_write( dup( heap->mHeapId ), &mHeapId );
+ int fd = dup(heap->mHeapId.load(memory_order_relaxed));
+ ALOGE_IF(fd==-1, "cannot dup fd=%d",
+ heap->mHeapId.load(memory_order_relaxed));
+ mHeapId.store(fd, memory_order_release);
}
} else {
// something went wrong
@@ -294,7 +301,8 @@
void BpMemoryHeap::assertReallyMapped() const
{
- if (mHeapId == -1) {
+ int32_t heapId = mHeapId.load(memory_order_acquire);
+ if (heapId == -1) {
// remote call without mLock held, worse case scenario, we end up
// calling transact() from multiple threads, but that's not a problem,
@@ -313,7 +321,7 @@
parcel_fd, size, err, strerror(-err));
Mutex::Autolock _l(mLock);
- if (mHeapId == -1) {
+ if (mHeapId.load(memory_order_relaxed) == -1) {
int fd = dup( parcel_fd );
ALOGE_IF(fd==-1, "cannot dup fd=%d, size=%zd, err=%d (%s)",
parcel_fd, size, err, strerror(errno));
@@ -322,7 +330,6 @@
if (!(flags & READ_ONLY)) {
access |= PROT_WRITE;
}
-
mRealHeap = true;
mBase = mmap(0, size, access, MAP_SHARED, fd, offset);
if (mBase == MAP_FAILED) {
@@ -333,7 +340,7 @@
mSize = size;
mFlags = flags;
mOffset = offset;
- android_atomic_write(fd, &mHeapId);
+ mHeapId.store(fd, memory_order_release);
}
}
}
@@ -341,7 +348,8 @@
int BpMemoryHeap::getHeapID() const {
assertMapped();
- return mHeapId;
+ // We either stored mHeapId ourselves, or loaded it with acquire semantics.
+ return mHeapId.load(memory_order_relaxed);
}
void* BpMemoryHeap::getBase() const {
@@ -418,9 +426,10 @@
"found binder=%p, heap=%p, size=%zu, fd=%d, count=%d",
binder.get(), info.heap.get(),
static_cast<BpMemoryHeap*>(info.heap.get())->mSize,
- static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId,
+ static_cast<BpMemoryHeap*>(info.heap.get())
+ ->mHeapId.load(memory_order_relaxed),
info.count);
- android_atomic_inc(&info.count);
+ ++info.count;
return info.heap;
} else {
heap_info_t info;
@@ -445,13 +454,13 @@
ssize_t i = mHeapCache.indexOfKey(binder);
if (i>=0) {
heap_info_t& info(mHeapCache.editValueAt(i));
- int32_t c = android_atomic_dec(&info.count);
- if (c == 1) {
+ if (--info.count == 0) {
ALOGD_IF(VERBOSE,
"removing binder=%p, heap=%p, size=%zu, fd=%d, count=%d",
binder.unsafe_get(), info.heap.get(),
static_cast<BpMemoryHeap*>(info.heap.get())->mSize,
- static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId,
+ static_cast<BpMemoryHeap*>(info.heap.get())
+ ->mHeapId.load(memory_order_relaxed),
info.count);
rel = mHeapCache.valueAt(i).heap;
mHeapCache.removeItemsAt(i);
@@ -482,7 +491,7 @@
ALOGD("hey=%p, heap=%p, count=%d, (fd=%d, base=%p, size=%zu)",
mHeapCache.keyAt(i).unsafe_get(),
info.heap.get(), info.count,
- h->mHeapId, h->mBase, h->mSize);
+ h->mHeapId.load(memory_order_relaxed), h->mBase, h->mSize);
}
}
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index eccc400..d0cd8f2 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -65,10 +65,6 @@
namespace android {
-static const char* getReturnString(size_t idx);
-static const void* printReturnCommand(TextOutput& out, const void* _cmd);
-static const void* printCommand(TextOutput& out, const void* _cmd);
-
// Static const and functions will be optimized out if not used,
// when LOG_NDEBUG and references in IF_LOG_COMMANDS() are optimized out.
static const char *kReturnStrings[] = {
@@ -112,8 +108,9 @@
"BC_DEAD_BINDER_DONE"
};
-static const char* getReturnString(size_t idx)
+static const char* getReturnString(uint32_t cmd)
{
+ size_t idx = cmd & 0xff;
if (idx < sizeof(kReturnStrings) / sizeof(kReturnStrings[0]))
return kReturnStrings[idx];
else
@@ -331,6 +328,7 @@
delete st;
pthread_setspecific(gTLS, NULL);
}
+ pthread_key_delete(gTLS);
gHaveTLS = false;
}
}
@@ -512,9 +510,9 @@
}
} while (result != -ECONNREFUSED && result != -EBADF);
- LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p\n",
- (void*)pthread_self(), getpid(), (void*)result);
-
+ LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%d\n",
+ (void*)pthread_self(), getpid(), result);
+
mOut.writeInt32(BC_EXIT_LOOPER);
talkWithDriver(false);
}
@@ -655,7 +653,7 @@
waitForResponse(NULL, &result);
#if LOG_REFCOUNTS
- printf("IPCThreadState::attemptIncStrongHandle(%ld) = %s\n",
+ ALOGV("IPCThreadState::attemptIncStrongHandle(%ld) = %s\n",
handle, result == NO_ERROR ? "SUCCESS" : "FAILURE");
#endif
@@ -670,7 +668,7 @@
void IPCThreadState::expungeHandle(int32_t handle, IBinder* binder)
{
#if LOG_REFCOUNTS
- printf("IPCThreadState::expungeHandle(%ld)\n", handle);
+ ALOGV("IPCThreadState::expungeHandle(%ld)\n", handle);
#endif
self()->mProcess->expungeHandle(handle, binder);
}
@@ -1136,7 +1134,7 @@
break;
default:
- printf("*** BAD COMMAND %d received from Binder driver\n", cmd);
+ ALOGE("*** BAD COMMAND %d received from Binder driver\n", cmd);
result = UNKNOWN_ERROR;
break;
}
diff --git a/libs/binder/IPermissionController.cpp b/libs/binder/IPermissionController.cpp
index 6bba996..674bddf 100644
--- a/libs/binder/IPermissionController.cpp
+++ b/libs/binder/IPermissionController.cpp
@@ -31,7 +31,7 @@
class BpPermissionController : public BpInterface<IPermissionController>
{
public:
- BpPermissionController(const sp<IBinder>& impl)
+ explicit BpPermissionController(const sp<IBinder>& impl)
: BpInterface<IPermissionController>(impl)
{
}
diff --git a/libs/binder/IProcessInfoService.cpp b/libs/binder/IProcessInfoService.cpp
index 76508b8..96e1a8c 100644
--- a/libs/binder/IProcessInfoService.cpp
+++ b/libs/binder/IProcessInfoService.cpp
@@ -25,7 +25,7 @@
class BpProcessInfoService : public BpInterface<IProcessInfoService> {
public:
- BpProcessInfoService(const sp<IBinder>& impl)
+ explicit BpProcessInfoService(const sp<IBinder>& impl)
: BpInterface<IProcessInfoService>(impl) {}
virtual status_t getProcessStatesFromPids(size_t length, /*in*/ int32_t* pids,
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 44d235f..3aeff2e 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -67,11 +67,6 @@
bool checkPermission(const String16& permission, pid_t pid, uid_t uid)
{
-#ifdef __BRILLO__
- // Brillo doesn't currently run ActivityManager or support framework permissions.
- return true;
-#endif
-
sp<IPermissionController> pc;
gDefaultServiceManagerLock.lock();
pc = gPermissionController;
@@ -131,7 +126,7 @@
class BpServiceManager : public BpInterface<IServiceManager>
{
public:
- BpServiceManager(const sp<IBinder>& impl)
+ explicit BpServiceManager(const sp<IBinder>& impl)
: BpInterface<IServiceManager>(impl)
{
}
diff --git a/libs/binder/MemoryDealer.cpp b/libs/binder/MemoryDealer.cpp
index 51eac11..2a15773 100644
--- a/libs/binder/MemoryDealer.cpp
+++ b/libs/binder/MemoryDealer.cpp
@@ -126,7 +126,7 @@
PAGE_ALIGNED = 0x00000001
};
public:
- SimpleBestFitAllocator(size_t size);
+ explicit SimpleBestFitAllocator(size_t size);
~SimpleBestFitAllocator();
size_t allocate(size_t size, uint32_t flags = 0);
diff --git a/libs/binder/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp
index 43a01e4..aed0134 100644
--- a/libs/binder/MemoryHeapBase.cpp
+++ b/libs/binder/MemoryHeapBase.cpp
@@ -16,20 +16,19 @@
#define LOG_TAG "MemoryHeapBase"
-#include <stdlib.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <fcntl.h>
#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdlib.h>
#include <sys/ioctl.h>
-
-#include <cutils/log.h>
-#include <cutils/ashmem.h>
-#include <cutils/atomic.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <binder/MemoryHeapBase.h>
+#include <log/log.h>
+#include <cutils/ashmem.h>
+#include <cutils/atomic.h>
namespace android {
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 19ce3eb..d753eb5 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -100,32 +100,6 @@
BLOB_ASHMEM_MUTABLE = 2,
};
-static dev_t ashmem_rdev()
-{
- static dev_t __ashmem_rdev;
- static pthread_mutex_t __ashmem_rdev_lock = PTHREAD_MUTEX_INITIALIZER;
-
- pthread_mutex_lock(&__ashmem_rdev_lock);
-
- dev_t rdev = __ashmem_rdev;
- if (!rdev) {
- int fd = TEMP_FAILURE_RETRY(open("/dev/ashmem", O_RDONLY));
- if (fd >= 0) {
- struct stat st;
-
- int ret = TEMP_FAILURE_RETRY(fstat(fd, &st));
- close(fd);
- if ((ret >= 0) && S_ISCHR(st.st_mode)) {
- rdev = __ashmem_rdev = st.st_rdev;
- }
- }
- }
-
- pthread_mutex_unlock(&__ashmem_rdev_lock);
-
- return rdev;
-}
-
void acquire_object(const sp<ProcessState>& proc,
const flat_binder_object& obj, const void* who, size_t* outAshmemSize)
{
@@ -154,15 +128,11 @@
return;
}
case BINDER_TYPE_FD: {
- if ((obj.cookie != 0) && (outAshmemSize != NULL)) {
- struct stat st;
- int ret = fstat(obj.handle, &st);
- if (!ret && S_ISCHR(st.st_mode) && (st.st_rdev == ashmem_rdev())) {
- // If we own an ashmem fd, keep track of how much memory it refers to.
- int size = ashmem_get_size_region(obj.handle);
- if (size > 0) {
- *outAshmemSize += size;
- }
+ if ((obj.cookie != 0) && (outAshmemSize != NULL) && ashmem_valid(obj.handle)) {
+ // If we own an ashmem fd, keep track of how much memory it refers to.
+ int size = ashmem_get_size_region(obj.handle);
+ if (size > 0) {
+ *outAshmemSize += size;
}
}
return;
@@ -207,14 +177,10 @@
}
case BINDER_TYPE_FD: {
if (obj.cookie != 0) { // owned
- if (outAshmemSize != NULL) {
- struct stat st;
- int ret = fstat(obj.handle, &st);
- if (!ret && S_ISCHR(st.st_mode) && (st.st_rdev == ashmem_rdev())) {
- int size = ashmem_get_size_region(obj.handle);
- if (size > 0) {
- *outAshmemSize -= size;
- }
+ if ((outAshmemSize != NULL) && ashmem_valid(obj.handle)) {
+ int size = ashmem_get_size_region(obj.handle);
+ if (size > 0) {
+ *outAshmemSize -= size;
}
}
@@ -784,7 +750,7 @@
const uint8_t* strData = (uint8_t*)str.data();
const size_t strLen= str.length();
const ssize_t utf16Len = utf8_to_utf16_length(strData, strLen);
- if (utf16Len < 0 || utf16Len> std::numeric_limits<int32_t>::max()) {
+ if (utf16Len < 0 || utf16Len > std::numeric_limits<int32_t>::max()) {
return BAD_VALUE;
}
@@ -799,7 +765,7 @@
return NO_MEMORY;
}
- utf8_to_utf16(strData, strLen, (char16_t*)dst);
+ utf8_to_utf16(strData, strLen, (char16_t*)dst, (size_t) utf16Len + 1);
return NO_ERROR;
}
@@ -1112,7 +1078,7 @@
}
status_t Parcel::readStrongBinderVector(std::unique_ptr<std::vector<sp<IBinder>>>* val) const {
- return readNullableTypedVector(val, &Parcel::readStrongBinder);
+ return readNullableTypedVector(val, &Parcel::readNullableStrongBinder);
}
status_t Parcel::readStrongBinderVector(std::vector<sp<IBinder>>* val) const {
@@ -1187,15 +1153,15 @@
return err;
}
-status_t Parcel::writeUniqueFileDescriptor(const ScopedFd& fd) {
+status_t Parcel::writeUniqueFileDescriptor(const base::unique_fd& fd) {
return writeDupFileDescriptor(fd.get());
}
-status_t Parcel::writeUniqueFileDescriptorVector(const std::vector<ScopedFd>& val) {
+status_t Parcel::writeUniqueFileDescriptorVector(const std::vector<base::unique_fd>& val) {
return writeTypedVector(val, &Parcel::writeUniqueFileDescriptor);
}
-status_t Parcel::writeUniqueFileDescriptorVector(const std::unique_ptr<std::vector<ScopedFd>>& val) {
+status_t Parcel::writeUniqueFileDescriptorVector(const std::unique_ptr<std::vector<base::unique_fd>>& val) {
return writeNullableTypedVector(val, &Parcel::writeUniqueFileDescriptor);
}
@@ -1842,13 +1808,37 @@
String8 Parcel::readString8() const
{
- int32_t size = readInt32();
- // watch for potential int overflow adding 1 for trailing NUL
- if (size > 0 && size < INT32_MAX) {
- const char* str = (const char*)readInplace(size+1);
- if (str) return String8(str, size);
+ String8 retString;
+ status_t status = readString8(&retString);
+ if (status != OK) {
+ // We don't care about errors here, so just return an empty string.
+ return String8();
}
- return String8();
+ return retString;
+}
+
+status_t Parcel::readString8(String8* pArg) const
+{
+ int32_t size;
+ status_t status = readInt32(&size);
+ if (status != OK) {
+ return status;
+ }
+ // watch for potential int overflow from size+1
+ if (size < 0 || size >= INT32_MAX) {
+ return BAD_VALUE;
+ }
+ // |writeString8| writes nothing for empty string.
+ if (size == 0) {
+ *pArg = String8();
+ return OK;
+ }
+ const char* str = (const char*)readInplace(size + 1);
+ if (str == NULL) {
+ return BAD_VALUE;
+ }
+ pArg->setTo(str, size);
+ return OK;
}
String16 Parcel::readString16() const
@@ -1913,13 +1903,25 @@
status_t Parcel::readStrongBinder(sp<IBinder>* val) const
{
+ status_t status = readNullableStrongBinder(val);
+ if (status == OK && !val->get()) {
+ status = UNEXPECTED_NULL;
+ }
+ return status;
+}
+
+status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const
+{
return unflatten_binder(ProcessState::self(), *this, val);
}
sp<IBinder> Parcel::readStrongBinder() const
{
sp<IBinder> val;
- readStrongBinder(&val);
+ // Note that a lot of code in Android reads binders by hand with this
+ // method, and that code has historically been ok with getting nullptr
+ // back (while ignoring error codes).
+ readNullableStrongBinder(&val);
return val;
}
@@ -1994,7 +1996,7 @@
return BAD_TYPE;
}
-status_t Parcel::readUniqueFileDescriptor(ScopedFd* val) const
+status_t Parcel::readUniqueFileDescriptor(base::unique_fd* val) const
{
int got = readFileDescriptor();
@@ -2012,11 +2014,11 @@
}
-status_t Parcel::readUniqueFileDescriptorVector(std::unique_ptr<std::vector<ScopedFd>>* val) const {
+status_t Parcel::readUniqueFileDescriptorVector(std::unique_ptr<std::vector<base::unique_fd>>* val) const {
return readNullableTypedVector(val, &Parcel::readUniqueFileDescriptor);
}
-status_t Parcel::readUniqueFileDescriptorVector(std::vector<ScopedFd>* val) const {
+status_t Parcel::readUniqueFileDescriptorVector(std::vector<base::unique_fd>* val) const {
return readTypedVector(val, &Parcel::readUniqueFileDescriptor);
}
diff --git a/libs/binder/PersistableBundle.cpp b/libs/binder/PersistableBundle.cpp
index aef791c..e7078ba 100644
--- a/libs/binder/PersistableBundle.cpp
+++ b/libs/binder/PersistableBundle.cpp
@@ -32,6 +32,9 @@
using android::sp;
using android::status_t;
using android::UNEXPECTED_NULL;
+using std::map;
+using std::set;
+using std::vector;
enum {
// Keep in sync with BUNDLE_MAGIC in frameworks/base/core/java/android/os/BaseBundle.java.
@@ -55,12 +58,22 @@
namespace {
template <typename T>
-bool getValue(const android::String16& key, T* out, const std::map<android::String16, T>& map) {
+bool getValue(const android::String16& key, T* out, const map<android::String16, T>& map) {
const auto& it = map.find(key);
if (it == map.end()) return false;
*out = it->second;
return true;
}
+
+template <typename T>
+set<android::String16> getKeys(const map<android::String16, T>& map) {
+ if (map.empty()) return set<android::String16>();
+ set<android::String16> keys;
+ for (const auto& key_value_pair : map) {
+ keys.emplace(key_value_pair.first);
+ }
+ return keys;
+}
} // namespace
namespace android {
@@ -78,7 +91,7 @@
#define RETURN_IF_ENTRY_ERASED(map, key) \
{ \
- size_t num_erased = map.erase(key); \
+ size_t num_erased = (map).erase(key); \
if (num_erased) { \
ALOGE("Failed at %s:%d (%s)", __FILE__, __LINE__, __func__); \
return num_erased; \
@@ -188,27 +201,27 @@
mStringMap[key] = value;
}
-void PersistableBundle::putBooleanVector(const String16& key, const std::vector<bool>& value) {
+void PersistableBundle::putBooleanVector(const String16& key, const vector<bool>& value) {
erase(key);
mBoolVectorMap[key] = value;
}
-void PersistableBundle::putIntVector(const String16& key, const std::vector<int32_t>& value) {
+void PersistableBundle::putIntVector(const String16& key, const vector<int32_t>& value) {
erase(key);
mIntVectorMap[key] = value;
}
-void PersistableBundle::putLongVector(const String16& key, const std::vector<int64_t>& value) {
+void PersistableBundle::putLongVector(const String16& key, const vector<int64_t>& value) {
erase(key);
mLongVectorMap[key] = value;
}
-void PersistableBundle::putDoubleVector(const String16& key, const std::vector<double>& value) {
+void PersistableBundle::putDoubleVector(const String16& key, const vector<double>& value) {
erase(key);
mDoubleVectorMap[key] = value;
}
-void PersistableBundle::putStringVector(const String16& key, const std::vector<String16>& value) {
+void PersistableBundle::putStringVector(const String16& key, const vector<String16>& value) {
erase(key);
mStringVectorMap[key] = value;
}
@@ -238,23 +251,23 @@
return getValue(key, out, mStringMap);
}
-bool PersistableBundle::getBooleanVector(const String16& key, std::vector<bool>* out) const {
+bool PersistableBundle::getBooleanVector(const String16& key, vector<bool>* out) const {
return getValue(key, out, mBoolVectorMap);
}
-bool PersistableBundle::getIntVector(const String16& key, std::vector<int32_t>* out) const {
+bool PersistableBundle::getIntVector(const String16& key, vector<int32_t>* out) const {
return getValue(key, out, mIntVectorMap);
}
-bool PersistableBundle::getLongVector(const String16& key, std::vector<int64_t>* out) const {
+bool PersistableBundle::getLongVector(const String16& key, vector<int64_t>* out) const {
return getValue(key, out, mLongVectorMap);
}
-bool PersistableBundle::getDoubleVector(const String16& key, std::vector<double>* out) const {
+bool PersistableBundle::getDoubleVector(const String16& key, vector<double>* out) const {
return getValue(key, out, mDoubleVectorMap);
}
-bool PersistableBundle::getStringVector(const String16& key, std::vector<String16>* out) const {
+bool PersistableBundle::getStringVector(const String16& key, vector<String16>* out) const {
return getValue(key, out, mStringVectorMap);
}
@@ -262,6 +275,50 @@
return getValue(key, out, mPersistableBundleMap);
}
+set<String16> PersistableBundle::getBooleanKeys() const {
+ return getKeys(mBoolMap);
+}
+
+set<String16> PersistableBundle::getIntKeys() const {
+ return getKeys(mIntMap);
+}
+
+set<String16> PersistableBundle::getLongKeys() const {
+ return getKeys(mLongMap);
+}
+
+set<String16> PersistableBundle::getDoubleKeys() const {
+ return getKeys(mDoubleMap);
+}
+
+set<String16> PersistableBundle::getStringKeys() const {
+ return getKeys(mStringMap);
+}
+
+set<String16> PersistableBundle::getBooleanVectorKeys() const {
+ return getKeys(mBoolVectorMap);
+}
+
+set<String16> PersistableBundle::getIntVectorKeys() const {
+ return getKeys(mIntVectorMap);
+}
+
+set<String16> PersistableBundle::getLongVectorKeys() const {
+ return getKeys(mLongVectorMap);
+}
+
+set<String16> PersistableBundle::getDoubleVectorKeys() const {
+ return getKeys(mDoubleVectorMap);
+}
+
+set<String16> PersistableBundle::getStringVectorKeys() const {
+ return getKeys(mStringVectorMap);
+}
+
+set<String16> PersistableBundle::getPersistableBundleKeys() const {
+ return getKeys(mPersistableBundleMap);
+}
+
status_t PersistableBundle::writeToParcelInner(Parcel* parcel) const {
/*
* To keep this implementation in sync with writeArrayMapInternal() in
@@ -363,7 +420,6 @@
RETURN_IF_FAILED(parcel->readInt32(&num_entries));
for (; num_entries > 0; --num_entries) {
- size_t start_pos = parcel->dataPosition();
String16 key;
int32_t value_type;
RETURN_IF_FAILED(parcel->readString16(&key));
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index f13f49f..5b70501 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -16,8 +16,6 @@
#define LOG_TAG "ProcessState"
-#include <cutils/process_name.h>
-
#include <binder/ProcessState.h>
#include <utils/Atomic.h>
@@ -42,7 +40,7 @@
#include <sys/stat.h>
#include <sys/types.h>
-#define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2))
+#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)
#define DEFAULT_MAX_BINDER_THREADS 15
// -------------------------------------------------------------------------
@@ -52,7 +50,7 @@
class PoolThread : public Thread
{
public:
- PoolThread(bool isMain)
+ explicit PoolThread(bool isMain)
: mIsMain(isMain)
{
}
@@ -366,6 +364,13 @@
ProcessState::~ProcessState()
{
+ if (mDriverFD >= 0) {
+ if (mVMStart != MAP_FAILED) {
+ munmap(mVMStart, BINDER_VM_SIZE);
+ }
+ close(mDriverFD);
+ }
+ mDriverFD = -1;
}
}; // namespace android
diff --git a/libs/binder/Static.cpp b/libs/binder/Static.cpp
index cd9509f..f0613d1 100644
--- a/libs/binder/Static.cpp
+++ b/libs/binder/Static.cpp
@@ -48,7 +48,7 @@
class FdTextOutput : public BufferedTextOutput
{
public:
- FdTextOutput(int fd) : BufferedTextOutput(MULTITHREADED), mFD(fd) { }
+ explicit FdTextOutput(int fd) : BufferedTextOutput(MULTITHREADED), mFD(fd) { }
virtual ~FdTextOutput() { };
protected:
diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp
index d3520d6..006f7f9 100644
--- a/libs/binder/Status.cpp
+++ b/libs/binder/Status.cpp
@@ -32,6 +32,11 @@
return Status(exceptionCode, OK, message);
}
+Status Status::fromExceptionCode(int32_t exceptionCode,
+ const char* message) {
+ return fromExceptionCode(exceptionCode, String8(message));
+}
+
Status Status::fromServiceSpecificError(int32_t serviceSpecificErrorCode) {
return Status(EX_SERVICE_SPECIFIC, serviceSpecificErrorCode);
}
@@ -41,6 +46,11 @@
return Status(EX_SERVICE_SPECIFIC, serviceSpecificErrorCode, message);
}
+Status Status::fromServiceSpecificError(int32_t serviceSpecificErrorCode,
+ const char* message) {
+ return fromServiceSpecificError(serviceSpecificErrorCode, String8(message));
+}
+
Status Status::fromStatusT(status_t status) {
Status ret;
ret.setFromStatusT(status);
@@ -94,6 +104,16 @@
if (mException == EX_SERVICE_SPECIFIC) {
status = parcel.readInt32(&mErrorCode);
+ } else if (mException == EX_PARCELABLE) {
+ // Skip over the blob of Parcelable data
+ const int32_t header_start = parcel.dataPosition();
+ int32_t header_size;
+ status = parcel.readInt32(&header_size);
+ if (status != OK) {
+ setFromStatusT(status);
+ return status;
+ }
+ parcel.setDataPosition(header_start + header_size);
}
if (status != OK) {
setFromStatusT(status);
@@ -117,11 +137,12 @@
return status;
}
status = parcel->writeString16(String16(mMessage));
- if (mException != EX_SERVICE_SPECIFIC) {
- // We have no more information to write.
- return status;
+ if (mException == EX_SERVICE_SPECIFIC) {
+ status = parcel->writeInt32(mErrorCode);
+ } else if (mException == EX_PARCELABLE) {
+ // Sending Parcelable blobs currently not supported
+ status = parcel->writeInt32(0);
}
- status = parcel->writeInt32(mErrorCode);
return status;
}
@@ -158,5 +179,10 @@
return ret;
}
+std::stringstream& operator<< (std::stringstream& stream, const Status& s) {
+ stream << s.toString8().string();
+ return stream;
+}
+
} // namespace binder
} // namespace android
diff --git a/libs/binder/TextOutput.cpp b/libs/binder/TextOutput.cpp
index 2ed5188..101eba3 100644
--- a/libs/binder/TextOutput.cpp
+++ b/libs/binder/TextOutput.cpp
@@ -29,111 +29,14 @@
// ---------------------------------------------------------------------------
-TextOutput::TextOutput() {
+TextOutput::TextOutput() {
}
-TextOutput::~TextOutput() {
+TextOutput::~TextOutput() {
}
// ---------------------------------------------------------------------------
-TextOutput& operator<<(TextOutput& to, bool val)
-{
- if (val) to.print("true", 4);
- else to.print("false", 5);
- return to;
-}
-
-TextOutput& operator<<(TextOutput& to, int val)
-{
- char buf[16];
- sprintf(buf, "%d", val);
- to.print(buf, strlen(buf));
- return to;
-}
-
-TextOutput& operator<<(TextOutput& to, long val)
-{
- char buf[16];
- sprintf(buf, "%ld", val);
- to.print(buf, strlen(buf));
- return to;
-}
-
-TextOutput& operator<<(TextOutput& to, unsigned int val)
-{
- char buf[16];
- sprintf(buf, "%u", val);
- to.print(buf, strlen(buf));
- return to;
-}
-
-TextOutput& operator<<(TextOutput& to, unsigned long val)
-{
- char buf[16];
- sprintf(buf, "%lu", val);
- to.print(buf, strlen(buf));
- return to;
-}
-
-TextOutput& operator<<(TextOutput& to, long long val)
-{
- char buf[32];
- sprintf(buf, "%Ld", val);
- to.print(buf, strlen(buf));
- return to;
-}
-
-TextOutput& operator<<(TextOutput& to, unsigned long long val)
-{
- char buf[32];
- sprintf(buf, "%Lu", val);
- to.print(buf, strlen(buf));
- return to;
-}
-
-static TextOutput& print_float(TextOutput& to, double value)
-{
- char buf[64];
- sprintf(buf, "%g", value);
- if( !strchr(buf, '.') && !strchr(buf, 'e') &&
- !strchr(buf, 'E') ) {
- strncat(buf, ".0", sizeof(buf)-1);
- }
- to.print(buf, strlen(buf));
- return to;
-}
-
-TextOutput& operator<<(TextOutput& to, float val)
-{
- return print_float(to,val);
-}
-
-TextOutput& operator<<(TextOutput& to, double val)
-{
- return print_float(to,val);
-}
-
-TextOutput& operator<<(TextOutput& to, const void* val)
-{
- char buf[32];
- snprintf(buf, sizeof(buf), "%p", val);
- to.print(buf, strlen(buf));
- return to;
-}
-
-TextOutput& operator<<(TextOutput& to, const String8& val)
-{
- to << val.string();
- return to;
-}
-
-TextOutput& operator<<(TextOutput& to, const String16& val)
-{
- to << String8(val).string();
- return to;
-}
-
static void textOutputPrinter(void* cookie, const char* txt)
{
((TextOutput*)cookie)->print(txt, strlen(txt));
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
new file mode 100644
index 0000000..acd0538
--- /dev/null
+++ b/libs/binder/tests/Android.bp
@@ -0,0 +1,73 @@
+//
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ product_variables: {
+ binder32bit: {
+ cflags: ["-DBINDER_IPC_32BIT=1"],
+ },
+ },
+
+ name: "binderDriverInterfaceTest",
+ srcs: ["binderDriverInterfaceTest.cpp"],
+}
+
+cc_test {
+ name: "binderLibTest",
+ srcs: ["binderLibTest.cpp"],
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ ],
+}
+
+cc_test {
+ name: "binderThroughputTest",
+ srcs: ["binderThroughputTest.cpp"],
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ ],
+ clang: true,
+ cflags: [
+ "-g",
+ "-Wall",
+ "-Werror",
+ "-Wno-missing-field-initializers",
+ "-Wno-sign-compare",
+ "-O3",
+ ],
+}
+
+cc_test {
+ name: "binderTextOutputTest",
+ srcs: ["binderTextOutputTest.cpp"],
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ "libbase",
+ ],
+}
+
+cc_test {
+ name: "schd-dbg",
+ srcs: ["schd-dbg.cpp"],
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ "libbase",
+ ],
+}
diff --git a/libs/binder/tests/Android.mk b/libs/binder/tests/Android.mk
deleted file mode 100644
index a40523d..0000000
--- a/libs/binder/tests/Android.mk
+++ /dev/null
@@ -1,42 +0,0 @@
-#
-# Copyright (C) 2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-ifneq ($(TARGET_USES_64_BIT_BINDER),true)
-ifneq ($(TARGET_IS_64_BIT),true)
-LOCAL_CFLAGS += -DBINDER_IPC_32BIT=1
-endif
-endif
-
-LOCAL_MODULE := binderDriverInterfaceTest
-LOCAL_SRC_FILES := binderDriverInterfaceTest.cpp
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := binderLibTest
-LOCAL_SRC_FILES := binderLibTest.cpp
-LOCAL_SHARED_LIBRARIES := libbinder libutils
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := binderThroughputTest
-LOCAL_SRC_FILES := binderThroughputTest.cpp
-LOCAL_SHARED_LIBRARIES := libbinder libutils
-LOCAL_CLANG := true
-LOCAL_CFLAGS += -g -Wall -Werror -std=c++11 -Wno-missing-field-initializers -Wno-sign-compare -O3
-include $(BUILD_NATIVE_TEST)
diff --git a/libs/binder/tests/binderDriverInterfaceTest.cpp b/libs/binder/tests/binderDriverInterfaceTest.cpp
index 0277550..ff5912f 100644
--- a/libs/binder/tests/binderDriverInterfaceTest.cpp
+++ b/libs/binder/tests/binderDriverInterfaceTest.cpp
@@ -20,7 +20,7 @@
#include <stdlib.h>
#include <gtest/gtest.h>
-#include <linux/binder.h>
+#include <linux/android/binder.h>
#include <binder/IBinder.h>
#include <sys/mman.h>
#include <poll.h>
@@ -229,7 +229,9 @@
.sender_euid = 0,
.data_size = 0,
.offsets_size = 0,
- .data = {0, 0},
+ .data = {
+ .ptr = {0, 0},
+ },
},
};
struct {
@@ -350,4 +352,3 @@
return RUN_ALL_TESTS();
}
-
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 3df3acf..54e12b6 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -34,6 +34,7 @@
static testing::Environment* binder_env;
static char *binderservername;
+static char *binderserversuffix;
static char binderserverarg[] = "--binderserver";
static String16 binderLibTestServiceName = String16("test.binderLib");
@@ -70,6 +71,7 @@
binderserverarg,
stri,
strpipefd1,
+ binderserversuffix,
NULL
};
@@ -252,14 +254,10 @@
int ret;
pthread_mutex_lock(&m_waitMutex);
if (!m_eventTriggered) {
-#if defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)
- pthread_cond_timeout_np(&m_waitCond, &m_waitMutex, timeout_s * 1000);
-#else
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += timeout_s;
pthread_cond_timedwait(&m_waitCond, &m_waitMutex, &ts);
-#endif
}
ret = m_eventTriggered ? NO_ERROR : TIMED_OUT;
pthread_mutex_unlock(&m_waitMutex);
@@ -739,14 +737,10 @@
}
if (ret > 0) {
if (m_serverStartRequested) {
-#if defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)
- ret = pthread_cond_timeout_np(&m_serverWaitCond, &m_serverWaitMutex, 5000);
-#else
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += 5;
ret = pthread_cond_timedwait(&m_serverWaitCond, &m_serverWaitMutex, &ts);
-#endif
}
if (m_serverStartRequested) {
m_serverStartRequested = false;
@@ -906,6 +900,8 @@
int run_server(int index, int readypipefd)
{
+ binderLibTestServiceName += String16(binderserversuffix);
+
status_t ret;
sp<IServiceManager> sm = defaultServiceManager();
{
@@ -936,15 +932,19 @@
int main(int argc, char **argv) {
int ret;
- if (argc == 3 && !strcmp(argv[1], "--servername")) {
+ if (argc == 4 && !strcmp(argv[1], "--servername")) {
binderservername = argv[2];
} else {
binderservername = argv[0];
}
- if (argc == 4 && !strcmp(argv[1], binderserverarg)) {
+ if (argc == 5 && !strcmp(argv[1], binderserverarg)) {
+ binderserversuffix = argv[4];
return run_server(atoi(argv[2]), atoi(argv[3]));
}
+ binderserversuffix = new char[16];
+ snprintf(binderserversuffix, 16, "%d", getpid());
+ binderLibTestServiceName += String16(binderserversuffix);
::testing::InitGoogleTest(&argc, argv);
binder_env = AddGlobalTestEnvironment(new BinderLibTestEnv());
diff --git a/libs/binder/tests/binderTextOutputTest.cpp b/libs/binder/tests/binderTextOutputTest.cpp
new file mode 100644
index 0000000..f6dd22d
--- /dev/null
+++ b/libs/binder/tests/binderTextOutputTest.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits>
+#include <cstddef>
+
+#include "android-base/file.h"
+#include "android-base/test_utils.h"
+#include <gtest/gtest.h>
+
+#include <binder/Parcel.h>
+#include <binder/TextOutput.h>
+#include <binder/Debug.h>
+
+static void CheckMessage(const CapturedStderr& cap,
+ const char* expected,
+ bool singleline) {
+ std::string output;
+ ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
+ android::base::ReadFdToString(cap.fd(), &output);
+ if (singleline)
+ output.erase(std::remove(output.begin(), output.end(), '\n'));
+ ASSERT_STREQ(output.c_str(), expected);
+}
+
+#define CHECK_LOG_(input, expect, singleline) \
+{ \
+ CapturedStderr cap; \
+ android::aerr << input << android::endl; \
+ CheckMessage(cap, expect, singleline); \
+} \
+
+#define CHECK_VAL_(val, singleline) \
+{ \
+ std::stringstream ss; \
+ ss << val; \
+ std::string s = ss.str(); \
+ CHECK_LOG_(val, s.c_str(), singleline); \
+} \
+
+#define CHECK_LOG(input, expect) CHECK_LOG_(input, expect, true)
+#define CHECK_VAL(val) CHECK_VAL_(val, true)
+
+TEST(TextOutput, HandlesStdEndl) {
+ CapturedStderr cap;
+ android::aerr << "foobar" << std::endl;
+ std::string output;
+ ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
+ android::base::ReadFdToString(cap.fd(), &output);
+ ASSERT_STREQ(output.c_str(), "foobar\n");
+}
+
+TEST(TextOutput, HandlesCEndl) {
+ CapturedStderr cap;
+ android::aerr << "foobar" << "\n";
+ std::string output;
+ ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
+ android::base::ReadFdToString(cap.fd(), &output);
+ ASSERT_STREQ(output.c_str(), "foobar\n");
+}
+
+TEST(TextOutput, HandlesAndroidEndl) {
+ CapturedStderr cap;
+ android::aerr << "foobar" << android::endl;
+ std::string output;
+ ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
+ android::base::ReadFdToString(cap.fd(), &output);
+ ASSERT_STREQ(output.c_str(), "foobar\n");
+}
+
+TEST(TextOutput, HandleEmptyString) {
+ CHECK_LOG("", "");
+}
+
+TEST(TextOutput, HandleString) {
+ CHECK_LOG("foobar", "foobar");
+}
+
+TEST(TextOutput, HandleNum) {
+ CHECK_LOG(12345, "12345");
+}
+
+TEST(TextOutput, HandleBool) {
+ CHECK_LOG(false, "false");
+}
+
+TEST(TextOutput, HandleChar) {
+ CHECK_LOG('T', "T");
+}
+
+TEST(TextOutput, HandleParcel) {
+ android::Parcel val;
+ CHECK_LOG(val, "Parcel(NULL)");
+}
+
+TEST(TextOutput, HandleHexDump) {
+ const char buf[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+ android::HexDump val(buf, sizeof(buf));
+ CHECK_LOG(val, "03020100 07060504 0b0a0908 0f0e0d0c '................'");
+}
+
+TEST(TextOutput, HandleHexDumpCustom) {
+ const char buf[4] = {0x11,0x22,0x33,0x44};
+ android::HexDump val(buf, sizeof(buf), 4);
+ CHECK_LOG(val, "11 22 33 44 '.\"3D'");
+}
+
+TEST(TextOutput, HandleTypeCode) {
+ android::TypeCode val(1234);
+ CHECK_LOG(val, "'\\x04\\xd2'");
+}
+
+TEST(TextOutput, HandleCookie) {
+ int32_t val = 321; //0x141
+ CHECK_LOG((void*)(long)val, "0x141");
+}
+
+TEST(TextOutput, HandleString8) {
+ android::String8 val("foobar");
+ CHECK_LOG(val, "foobar");
+}
+
+TEST(TextOutput, HandleString16) {
+ android::String16 val("foobar");
+ CHECK_LOG(val, "foobar");
+}
+
+template <typename T>
+class TextTest : public testing::Test {};
+
+typedef testing::Types<short, unsigned short,
+ int, unsigned int,
+ long, unsigned long,
+ long long, unsigned long long,
+ float, double, long double> TestTypes;
+TYPED_TEST_CASE(TextTest, TestTypes);
+
+TYPED_TEST(TextTest, TextMax)
+{
+ TypeParam max = std::numeric_limits<TypeParam>::max();
+ CHECK_VAL(max);
+}
+
+TYPED_TEST(TextTest, TestMin)
+{
+ TypeParam min = std::numeric_limits<TypeParam>::min();
+ CHECK_VAL(min);
+}
+
+TYPED_TEST(TextTest, TestDenom)
+{
+ TypeParam min = std::numeric_limits<TypeParam>::denorm_min();
+ CHECK_VAL(min);
+}
+
+TYPED_TEST(TextTest, TestEpsilon)
+{
+ TypeParam eps = std::numeric_limits<TypeParam>::epsilon();
+ CHECK_VAL(eps);
+}
diff --git a/libs/binder/tests/schd-dbg.cpp b/libs/binder/tests/schd-dbg.cpp
new file mode 100644
index 0000000..2732071
--- /dev/null
+++ b/libs/binder/tests/schd-dbg.cpp
@@ -0,0 +1,426 @@
+#include <binder/Binder.h>
+#include <binder/IBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <string>
+
+#include <iomanip>
+#include <iostream>
+#include <tuple>
+#include <vector>
+
+#include <pthread.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+using namespace std;
+using namespace android;
+
+enum BinderWorkerServiceCode {
+ BINDER_NOP = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+#define ASSERT(cond) \
+ do { \
+ if (!(cond)) { \
+ cerr << __func__ << ":" << __LINE__ << " condition:" << #cond \
+ << " failed\n" \
+ << endl; \
+ exit(EXIT_FAILURE); \
+ } \
+ } while (0)
+
+vector<sp<IBinder> > workers;
+
+// the ratio that the service is synced on the same cpu beyond
+// GOOD_SYNC_MIN is considered as good
+#define GOOD_SYNC_MIN (0.6)
+
+#define DUMP_PRICISION 3
+
+// the default value
+int no_process = 2;
+int iterations = 100;
+int payload_size = 16;
+int no_inherent = 0;
+int no_sync = 0;
+int verbose = 0;
+
+// the deadline latency that we are interested in
+uint64_t deadline_us = 2500;
+
+int thread_pri() {
+ struct sched_param param;
+ int policy;
+ ASSERT(!pthread_getschedparam(pthread_self(), &policy, ¶m));
+ return param.sched_priority;
+}
+
+void thread_dump(const char* prefix) {
+ struct sched_param param;
+ int policy;
+ if (!verbose) return;
+ cout << "--------------------------------------------------" << endl;
+ cout << setw(12) << left << prefix << " pid: " << getpid()
+ << " tid: " << gettid() << " cpu: " << sched_getcpu() << endl;
+ ASSERT(!pthread_getschedparam(pthread_self(), &policy, ¶m));
+ string s = (policy == SCHED_OTHER)
+ ? "SCHED_OTHER"
+ : (policy == SCHED_FIFO)
+ ? "SCHED_FIFO"
+ : (policy == SCHED_RR) ? "SCHED_RR" : "???";
+ cout << setw(12) << left << s << param.sched_priority << endl;
+ return;
+}
+
+class BinderWorkerService : public BBinder {
+ public:
+ BinderWorkerService() {
+ }
+ ~BinderWorkerService() {
+ }
+ virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags = 0) {
+ (void)flags;
+ (void)data;
+ (void)reply;
+ switch (code) {
+ // The transaction format is like
+ //
+ // data[in]: int32: caller priority
+ // int32: caller cpu
+ //
+ // reply[out]: int32: 1 if caller's priority != callee's priority
+ // int32: 1 if caller's cpu != callee's cpu
+ //
+ // note the caller cpu read here is not always correct
+ // there're still chances that the caller got switched out
+ // right after it read the cpu number and still before the transaction.
+ case BINDER_NOP: {
+ thread_dump("binder");
+ int priority = thread_pri();
+ int priority_caller = data.readInt32();
+ int h = 0, s = 0;
+ if (priority_caller != priority) {
+ h++;
+ if (verbose) {
+ cout << "err priority_caller:" << priority_caller
+ << ", priority:" << priority << endl;
+ }
+ }
+ if (priority == sched_get_priority_max(SCHED_FIFO)) {
+ int cpu = sched_getcpu();
+ int cpu_caller = data.readInt32();
+ if (cpu != cpu_caller) {
+ s++;
+ }
+ }
+ reply->writeInt32(h);
+ reply->writeInt32(s);
+ return NO_ERROR;
+ }
+ default:
+ return UNKNOWN_TRANSACTION;
+ };
+ }
+};
+
+class Pipe {
+ int m_readFd;
+ int m_writeFd;
+ Pipe(int readFd, int writeFd) : m_readFd{readFd}, m_writeFd{writeFd} {
+ }
+ Pipe(const Pipe&) = delete;
+ Pipe& operator=(const Pipe&) = delete;
+ Pipe& operator=(const Pipe&&) = delete;
+
+ public:
+ Pipe(Pipe&& rval) noexcept {
+ m_readFd = rval.m_readFd;
+ m_writeFd = rval.m_writeFd;
+ rval.m_readFd = 0;
+ rval.m_writeFd = 0;
+ }
+ ~Pipe() {
+ if (m_readFd) close(m_readFd);
+ if (m_writeFd) close(m_writeFd);
+ }
+ void signal() {
+ bool val = true;
+ int error = write(m_writeFd, &val, sizeof(val));
+ ASSERT(error >= 0);
+ };
+ void wait() {
+ bool val = false;
+ int error = read(m_readFd, &val, sizeof(val));
+ ASSERT(error >= 0);
+ }
+ template <typename T>
+ void send(const T& v) {
+ int error = write(m_writeFd, &v, sizeof(T));
+ ASSERT(error >= 0);
+ }
+ template <typename T>
+ void recv(T& v) {
+ int error = read(m_readFd, &v, sizeof(T));
+ ASSERT(error >= 0);
+ }
+ static tuple<Pipe, Pipe> createPipePair() {
+ int a[2];
+ int b[2];
+
+ int error1 = pipe(a);
+ int error2 = pipe(b);
+ ASSERT(error1 >= 0);
+ ASSERT(error2 >= 0);
+
+ return make_tuple(Pipe(a[0], b[1]), Pipe(b[0], a[1]));
+ }
+};
+
+typedef chrono::time_point<chrono::high_resolution_clock> Tick;
+
+static inline Tick tickNow() {
+ return chrono::high_resolution_clock::now();
+}
+
+static inline uint64_t tickNano(Tick& sta, Tick& end) {
+ return uint64_t(chrono::duration_cast<chrono::nanoseconds>(end - sta).count());
+}
+
+struct Results {
+ uint64_t m_best = 0xffffffffffffffffULL;
+ uint64_t m_worst = 0;
+ uint64_t m_transactions = 0;
+ uint64_t m_total_time = 0;
+ uint64_t m_miss = 0;
+
+ void add_time(uint64_t nano) {
+ m_best = min(nano, m_best);
+ m_worst = max(nano, m_worst);
+ m_transactions += 1;
+ m_total_time += nano;
+ if (nano > deadline_us * 1000) m_miss++;
+ }
+ void dump() {
+ double best = (double)m_best / 1.0E6;
+ double worst = (double)m_worst / 1.0E6;
+ double average = (double)m_total_time / m_transactions / 1.0E6;
+ // FIXME: libjson?
+ cout << std::setprecision(DUMP_PRICISION) << "{ \"avg\":" << setw(5) << left
+ << average << ", \"wst\":" << setw(5) << left << worst
+ << ", \"bst\":" << setw(5) << left << best << ", \"miss\":" << m_miss
+ << "}";
+ }
+};
+
+String16 generateServiceName(int num) {
+ char num_str[32];
+ snprintf(num_str, sizeof(num_str), "%d", num);
+ String16 serviceName = String16("binderWorker") + String16(num_str);
+ return serviceName;
+}
+
+static void parcel_fill(Parcel& data, int sz, int priority, int cpu) {
+ ASSERT(sz >= (int)sizeof(uint32_t) * 2);
+ data.writeInt32(priority);
+ data.writeInt32(cpu);
+ sz -= sizeof(uint32_t);
+ while (sz > (int)sizeof(uint32_t)) {
+ data.writeInt32(0);
+ sz -= sizeof(uint32_t);
+ }
+}
+
+static void* thread_start(void* p) {
+ Results* results_fifo = (Results*)p;
+ Parcel data, reply;
+ Tick sta, end;
+
+ parcel_fill(data, payload_size, thread_pri(), sched_getcpu());
+ thread_dump("fifo-caller");
+
+ sta = tickNow();
+ status_t ret = workers[0]->transact(BINDER_NOP, data, &reply);
+ end = tickNow();
+ results_fifo->add_time(tickNano(sta, end));
+
+ no_inherent += reply.readInt32();
+ no_sync += reply.readInt32();
+ return 0;
+}
+
+// create a fifo thread to transact and wait it to finished
+static void thread_transaction(Results* results_fifo) {
+ void* dummy;
+ pthread_t thread;
+ pthread_attr_t attr;
+ struct sched_param param;
+ ASSERT(!pthread_attr_init(&attr));
+ ASSERT(!pthread_attr_setschedpolicy(&attr, SCHED_FIFO));
+ param.sched_priority = sched_get_priority_max(SCHED_FIFO);
+ ASSERT(!pthread_attr_setschedparam(&attr, ¶m));
+ ASSERT(!pthread_create(&thread, &attr, &thread_start, results_fifo));
+ ASSERT(!pthread_join(thread, &dummy));
+}
+
+#define is_client(_num) ((_num) >= (no_process / 2))
+
+void worker_fx(int num, int no_process, int iterations, int payload_size,
+ Pipe p) {
+ int dummy;
+ Results results_other, results_fifo;
+
+ // Create BinderWorkerService and for go.
+ ProcessState::self()->startThreadPool();
+ sp<IServiceManager> serviceMgr = defaultServiceManager();
+ sp<BinderWorkerService> service = new BinderWorkerService;
+ serviceMgr->addService(generateServiceName(num), service);
+ p.signal();
+ p.wait();
+
+ // If client/server pairs, then half the workers are
+ // servers and half are clients
+ int server_count = no_process / 2;
+
+ for (int i = 0; i < server_count; i++) {
+ // self service is in-process so just skip
+ if (num == i) continue;
+ workers.push_back(serviceMgr->getService(generateServiceName(i)));
+ }
+
+ // Client for each pair iterates here
+ // each iterations contains exatcly 2 transactions
+ for (int i = 0; is_client(num) && i < iterations; i++) {
+ Parcel data, reply;
+ Tick sta, end;
+ // the target is paired to make it easier to diagnose
+ int target = num % server_count;
+
+ // 1. transaction by fifo thread
+ thread_transaction(&results_fifo);
+ parcel_fill(data, payload_size, thread_pri(), sched_getcpu());
+ thread_dump("other-caller");
+
+ // 2. transaction by other thread
+ sta = tickNow();
+ ASSERT(NO_ERROR == workers[target]->transact(BINDER_NOP, data, &reply));
+ end = tickNow();
+ results_other.add_time(tickNano(sta, end));
+
+ no_inherent += reply.readInt32();
+ no_sync += reply.readInt32();
+ }
+ // Signal completion to master and wait.
+ p.signal();
+ p.wait();
+
+ p.send(&dummy);
+ p.wait();
+ // Client for each pair dump here
+ if (is_client(num)) {
+ int no_trans = iterations * 2;
+ double sync_ratio = (1.0 - (double)no_sync / no_trans);
+ // FIXME: libjson?
+ cout << "\"P" << (num - server_count) << "\":{\"SYNC\":\""
+ << ((sync_ratio > GOOD_SYNC_MIN) ? "GOOD" : "POOR") << "\","
+ << "\"S\":" << (no_trans - no_sync) << ",\"I\":" << no_trans << ","
+ << "\"R\":" << sync_ratio << "," << endl;
+
+ cout << " \"other_ms\":";
+ results_other.dump();
+ cout << "," << endl;
+ cout << " \"fifo_ms\": ";
+ results_fifo.dump();
+ cout << endl;
+ cout << "}," << endl;
+ }
+ exit(no_inherent);
+}
+
+Pipe make_process(int num, int iterations, int no_process, int payload_size) {
+ auto pipe_pair = Pipe::createPipePair();
+ pid_t pid = fork();
+ if (pid) {
+ // parent
+ return move(get<0>(pipe_pair));
+ } else {
+ // child
+ thread_dump(is_client(num) ? "client" : "server");
+ worker_fx(num, no_process, iterations, payload_size,
+ move(get<1>(pipe_pair)));
+ // never get here
+ return move(get<0>(pipe_pair));
+ }
+}
+
+void wait_all(vector<Pipe>& v) {
+ for (size_t i = 0; i < v.size(); i++) {
+ v[i].wait();
+ }
+}
+
+void signal_all(vector<Pipe>& v) {
+ for (size_t i = 0; i < v.size(); i++) {
+ v[i].signal();
+ }
+}
+
+// This test is modified from binderThroughputTest.cpp
+int main(int argc, char** argv) {
+ for (int i = 1; i < argc; i++) {
+ if (string(argv[i]) == "-i") {
+ iterations = atoi(argv[i + 1]);
+ i++;
+ continue;
+ }
+ if (string(argv[i]) == "-pair") {
+ no_process = 2 * atoi(argv[i + 1]);
+ i++;
+ continue;
+ }
+ if (string(argv[i]) == "-deadline_us") {
+ deadline_us = atoi(argv[i + 1]);
+ i++;
+ continue;
+ }
+ if (string(argv[i]) == "-v") {
+ verbose = 1;
+ i++;
+ }
+ }
+ vector<Pipe> pipes;
+ thread_dump("main");
+ // FIXME: libjson?
+ cout << "{" << endl;
+ cout << "\"cfg\":{\"pair\":" << (no_process / 2)
+ << ",\"iterations\":" << iterations << ",\"deadline_us\":" << deadline_us
+ << "}," << endl;
+
+ // the main process fork 2 processes for each pairs
+ // 1 server + 1 client
+ // each has a pipe to communicate with
+ for (int i = 0; i < no_process; i++) {
+ pipes.push_back(make_process(i, iterations, no_process, payload_size));
+ }
+ wait_all(pipes);
+ signal_all(pipes);
+ wait_all(pipes);
+ signal_all(pipes);
+ for (int i = 0; i < no_process; i++) {
+ int status;
+ pipes[i].signal();
+ wait(&status);
+ // the exit status is number of transactions without priority inheritance
+ // detected in the child process
+ no_inherent += status;
+ }
+ // FIXME: libjson?
+ cout << "\"inheritance\": " << (no_inherent == 0 ? "\"PASS\"" : "\"FAIL\"")
+ << endl;
+ cout << "}" << endl;
+ return -no_inherent;
+}
diff --git a/libs/diskusage/Android.bp b/libs/diskusage/Android.bp
new file mode 100644
index 0000000..156ddff
--- /dev/null
+++ b/libs/diskusage/Android.bp
@@ -0,0 +1,18 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_static {
+ name: "libdiskusage",
+ srcs: ["dirsize.c"],
+}
diff --git a/libs/diskusage/Android.mk b/libs/diskusage/Android.mk
deleted file mode 100644
index d54f8ad..0000000
--- a/libs/diskusage/Android.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libdiskusage
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := dirsize.c
-
-include $(BUILD_STATIC_LIBRARY)
\ No newline at end of file
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
new file mode 100644
index 0000000..7ac03f1
--- /dev/null
+++ b/libs/gui/Android.bp
@@ -0,0 +1,113 @@
+// Copyright 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+ name: "libgui",
+
+ clang: true,
+ cppflags: [
+ "-Weverything",
+ "-Werror",
+
+ // The static constructors and destructors in this library have not been noted to
+ // introduce significant overheads
+ "-Wno-exit-time-destructors",
+ "-Wno-global-constructors",
+
+ // We only care about compiling as C++14
+ "-Wno-c++98-compat-pedantic",
+
+ // We don't need to enumerate every case in a switch as long as a default case
+ // is present
+ "-Wno-switch-enum",
+
+ // Allow calling variadic macros without a __VA_ARGS__ list
+ "-Wno-gnu-zero-variadic-macro-arguments",
+
+ // Don't warn about struct padding
+ "-Wno-padded",
+
+ // android/sensors.h uses nested anonymous unions and anonymous structs
+ "-Wno-nested-anon-types",
+ "-Wno-gnu-anonymous-struct",
+
+ "-DDEBUG_ONLY_CODE=0",
+ ],
+
+ product_variables: {
+ brillo: {
+ cflags: ["-DHAVE_NO_SURFACE_FLINGER"],
+ },
+ debuggable: {
+ cppflags: [
+ "-UDEBUG_ONLY_CODE",
+ "-DDEBUG_ONLY_CODE=1",
+ ],
+ },
+ },
+
+ srcs: [
+ "IGraphicBufferConsumer.cpp",
+ "IConsumerListener.cpp",
+ "BitTube.cpp",
+ "BufferItem.cpp",
+ "BufferItemConsumer.cpp",
+ "BufferQueue.cpp",
+ "BufferQueueConsumer.cpp",
+ "BufferQueueCore.cpp",
+ "BufferQueueProducer.cpp",
+ "BufferSlot.cpp",
+ "ConsumerBase.cpp",
+ "CpuConsumer.cpp",
+ "DisplayEventReceiver.cpp",
+ "GLConsumer.cpp",
+ "GraphicBufferAlloc.cpp",
+ "GraphicsEnv.cpp",
+ "GuiConfig.cpp",
+ "IDisplayEventConnection.cpp",
+ "IGraphicBufferAlloc.cpp",
+ "IGraphicBufferProducer.cpp",
+ "IProducerListener.cpp",
+ "ISensorEventConnection.cpp",
+ "ISensorServer.cpp",
+ "ISurfaceComposer.cpp",
+ "ISurfaceComposerClient.cpp",
+ "LayerState.cpp",
+ "OccupancyTracker.cpp",
+ "Sensor.cpp",
+ "SensorEventQueue.cpp",
+ "SensorManager.cpp",
+ "StreamSplitter.cpp",
+ "Surface.cpp",
+ "SurfaceControl.cpp",
+ "SurfaceComposerClient.cpp",
+ "SyncFeatures.cpp",
+ ],
+
+ shared_libs: [
+ "libnativeloader",
+ "libbinder",
+ "libcutils",
+ "libEGL",
+ "libGLESv2",
+ "libsync",
+ "libui",
+ "libutils",
+ "liblog",
+ ],
+
+ export_shared_lib_headers: ["libbinder"],
+}
+
+subdirs = ["tests"]
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
deleted file mode 100644
index 9e2fc2b..0000000
--- a/libs/gui/Android.mk
+++ /dev/null
@@ -1,103 +0,0 @@
-# Copyright 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_CLANG := true
-LOCAL_CPPFLAGS := -std=c++1y -Weverything -Werror
-
-# The static constructors and destructors in this library have not been noted to
-# introduce significant overheads
-LOCAL_CPPFLAGS += -Wno-exit-time-destructors
-LOCAL_CPPFLAGS += -Wno-global-constructors
-
-# We only care about compiling as C++14
-LOCAL_CPPFLAGS += -Wno-c++98-compat-pedantic
-
-# We don't need to enumerate every case in a switch as long as a default case
-# is present
-LOCAL_CPPFLAGS += -Wno-switch-enum
-
-# Allow calling variadic macros without a __VA_ARGS__ list
-LOCAL_CPPFLAGS += -Wno-gnu-zero-variadic-macro-arguments
-
-# Don't warn about struct padding
-LOCAL_CPPFLAGS += -Wno-padded
-
-LOCAL_CPPFLAGS += -DDEBUG_ONLY_CODE=$(if $(filter userdebug eng,$(TARGET_BUILD_VARIANT)),1,0)
-
-LOCAL_SRC_FILES := \
- IGraphicBufferConsumer.cpp \
- IConsumerListener.cpp \
- BitTube.cpp \
- BufferItem.cpp \
- BufferItemConsumer.cpp \
- BufferQueue.cpp \
- BufferQueueConsumer.cpp \
- BufferQueueCore.cpp \
- BufferQueueProducer.cpp \
- BufferSlot.cpp \
- ConsumerBase.cpp \
- CpuConsumer.cpp \
- DisplayEventReceiver.cpp \
- GLConsumer.cpp \
- GraphicBufferAlloc.cpp \
- GraphicsEnv.cpp \
- GuiConfig.cpp \
- IDisplayEventConnection.cpp \
- IGraphicBufferAlloc.cpp \
- IGraphicBufferProducer.cpp \
- IProducerListener.cpp \
- ISensorEventConnection.cpp \
- ISensorServer.cpp \
- ISurfaceComposer.cpp \
- ISurfaceComposerClient.cpp \
- LayerState.cpp \
- OccupancyTracker.cpp \
- Sensor.cpp \
- SensorEventQueue.cpp \
- SensorManager.cpp \
- StreamSplitter.cpp \
- Surface.cpp \
- SurfaceControl.cpp \
- SurfaceComposerClient.cpp \
- SyncFeatures.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
- libnativeloader \
- libbinder \
- libcutils \
- libEGL \
- libGLESv2 \
- libsync \
- libui \
- libutils \
- liblog
-
-
-LOCAL_MODULE := libgui
-
-ifeq ($(TARGET_BOARD_PLATFORM), tegra)
- LOCAL_CFLAGS += -DDONT_USE_FENCE_SYNC
-endif
-ifeq ($(TARGET_BOARD_PLATFORM), tegra3)
- LOCAL_CFLAGS += -DDONT_USE_FENCE_SYNC
-endif
-
-include $(BUILD_SHARED_LIBRARY)
-
-ifeq (,$(ONE_SHOT_MAKEFILE))
-include $(call first-makefiles-under,$(LOCAL_PATH))
-endif
diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp
index 5e3924a..1357a4a 100644
--- a/libs/gui/BufferItem.cpp
+++ b/libs/gui/BufferItem.cpp
@@ -23,6 +23,21 @@
namespace android {
+template<typename T>
+static inline constexpr uint32_t low32(const T n) {
+ return static_cast<uint32_t>(static_cast<uint64_t>(n));
+}
+
+template<typename T>
+static inline constexpr uint32_t high32(const T n) {
+ return static_cast<uint32_t>(static_cast<uint64_t>(n)>>32);
+}
+
+template<typename T>
+static inline constexpr T to64(const uint32_t lo, const uint32_t hi) {
+ return static_cast<T>(static_cast<uint64_t>(hi)<<32 | lo);
+}
+
BufferItem::BufferItem() :
mGraphicBuffer(NULL),
mFence(NULL),
@@ -56,12 +71,12 @@
addAligned(size, mCrop);
addAligned(size, mTransform);
addAligned(size, mScalingMode);
- addAligned(size, mTimestampLo);
- addAligned(size, mTimestampHi);
+ addAligned(size, low32(mTimestamp));
+ addAligned(size, high32(mTimestamp));
addAligned(size, mIsAutoTimestamp);
addAligned(size, mDataSpace);
- addAligned(size, mFrameNumberLo);
- addAligned(size, mFrameNumberHi);
+ addAligned(size, low32(mFrameNumber));
+ addAligned(size, high32(mFrameNumber));
addAligned(size, mSlot);
addAligned(size, mIsDroppable);
addAligned(size, mAcquireCalled);
@@ -141,12 +156,12 @@
writeAligned(buffer, size, mCrop);
writeAligned(buffer, size, mTransform);
writeAligned(buffer, size, mScalingMode);
- writeAligned(buffer, size, mTimestampLo);
- writeAligned(buffer, size, mTimestampHi);
+ writeAligned(buffer, size, low32(mTimestamp));
+ writeAligned(buffer, size, high32(mTimestamp));
writeAligned(buffer, size, mIsAutoTimestamp);
writeAligned(buffer, size, mDataSpace);
- writeAligned(buffer, size, mFrameNumberLo);
- writeAligned(buffer, size, mFrameNumberHi);
+ writeAligned(buffer, size, low32(mFrameNumber));
+ writeAligned(buffer, size, high32(mFrameNumber));
writeAligned(buffer, size, mSlot);
writeAligned(buffer, size, mIsDroppable);
writeAligned(buffer, size, mAcquireCalled);
@@ -194,15 +209,20 @@
return NO_MEMORY;
}
+ uint32_t timestampLo = 0, timestampHi = 0;
+ uint32_t frameNumberLo = 0, frameNumberHi = 0;
+
readAligned(buffer, size, mCrop);
readAligned(buffer, size, mTransform);
readAligned(buffer, size, mScalingMode);
- readAligned(buffer, size, mTimestampLo);
- readAligned(buffer, size, mTimestampHi);
+ readAligned(buffer, size, timestampLo);
+ readAligned(buffer, size, timestampHi);
+ mTimestamp = to64<int64_t>(timestampLo, timestampHi);
readAligned(buffer, size, mIsAutoTimestamp);
readAligned(buffer, size, mDataSpace);
- readAligned(buffer, size, mFrameNumberLo);
- readAligned(buffer, size, mFrameNumberHi);
+ readAligned(buffer, size, frameNumberLo);
+ readAligned(buffer, size, frameNumberHi);
+ mFrameNumber = to64<uint64_t>(frameNumberLo, frameNumberHi);
readAligned(buffer, size, mSlot);
readAligned(buffer, size, mIsDroppable);
readAligned(buffer, size, mAcquireCalled);
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 73d2042..ee4c58c 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -259,7 +259,8 @@
// decrease.
mCore->mDequeueCondition.broadcast();
- ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size());
+ ATRACE_INT(mCore->mConsumerName.string(),
+ static_cast<int32_t>(mCore->mQueue.size()));
mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size());
VALIDATE_CONSISTENCY();
@@ -732,7 +733,7 @@
return NO_ERROR;
}
-void BufferQueueConsumer::dump(String8& result, const char* prefix) const {
+void BufferQueueConsumer::dumpState(String8& result, const char* prefix) const {
const IPCThreadState* ipc = IPCThreadState::self();
const pid_t pid = ipc->getCallingPid();
const uid_t uid = ipc->getCallingUid();
@@ -741,9 +742,10 @@
"android.permission.DUMP"), pid, uid)) {
result.appendFormat("Permission Denial: can't dump BufferQueueConsumer "
"from pid=%d, uid=%d\n", pid, uid);
- android_errorWriteWithInfoLog(0x534e4554, "27046057", uid, NULL, 0);
+ android_errorWriteWithInfoLog(0x534e4554, "27046057",
+ static_cast<int32_t>(uid), NULL, 0);
} else {
- mCore->dump(result, prefix);
+ mCore->dumpState(result, prefix);
}
}
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index c4714e3..6e6cce2 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -28,8 +28,11 @@
#include <inttypes.h>
+#include <cutils/properties.h>
+
#include <gui/BufferItem.h>
#include <gui/BufferQueueCore.h>
+#include <gui/GraphicBufferAlloc.h>
#include <gui/IConsumerListener.h>
#include <gui/IGraphicBufferAlloc.h>
#include <gui/IProducerListener.h>
@@ -94,8 +97,24 @@
mUniqueId(getUniqueId())
{
if (allocator == NULL) {
- sp<ISurfaceComposer> composer(ComposerService::getComposerService());
- mAllocator = composer->createGraphicBufferAlloc();
+
+#ifdef HAVE_NO_SURFACE_FLINGER
+ // Without a SurfaceFlinger, allocate in-process. This only makes
+ // sense in systems with static SELinux configurations and no
+ // applications (since applications need dynamic SELinux policy).
+ mAllocator = new GraphicBufferAlloc();
+#else
+ // Run time check for headless, where we also allocate in-process.
+ char value[PROPERTY_VALUE_MAX];
+ property_get("config.headless", value, "0");
+ if (atoi(value) == 1) {
+ mAllocator = new GraphicBufferAlloc();
+ } else {
+ sp<ISurfaceComposer> composer(ComposerService::getComposerService());
+ mAllocator = composer->createGraphicBufferAlloc();
+ }
+#endif // HAVE_NO_SURFACE_FLINGER
+
if (mAllocator == NULL) {
BQ_LOGE("createGraphicBufferAlloc failed");
}
@@ -113,7 +132,7 @@
BufferQueueCore::~BufferQueueCore() {}
-void BufferQueueCore::dump(String8& result, const char* prefix) const {
+void BufferQueueCore::dumpState(String8& result, const char* prefix) const {
Mutex::Autolock lock(mMutex);
String8 fifo;
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index b2169c8..f0e701e 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -721,6 +721,7 @@
mSlots[*outSlot].mFence = Fence::NO_FENCE;
mSlots[*outSlot].mRequestBufferCalled = true;
mSlots[*outSlot].mAcquireCalled = false;
+ mSlots[*outSlot].mNeedsReallocation = false;
mCore->mActiveBuffers.insert(found);
VALIDATE_CONSISTENCY();
@@ -905,7 +906,8 @@
static_cast<uint32_t>(mCore->mQueue.size()),
mCore->mFrameCounter + 1);
- ATRACE_INT(mCore->mConsumerName.string(), mCore->mQueue.size());
+ ATRACE_INT(mCore->mConsumerName.string(),
+ static_cast<int32_t>(mCore->mQueue.size()));
mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size());
// Take a ticket for the callback functions
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 65e4fee..3cf3078 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -254,11 +254,11 @@
return mConsumer->discardFreeBuffers();
}
-void ConsumerBase::dump(String8& result) const {
- dump(result, "");
+void ConsumerBase::dumpState(String8& result) const {
+ dumpState(result, "");
}
-void ConsumerBase::dump(String8& result, const char* prefix) const {
+void ConsumerBase::dumpState(String8& result, const char* prefix) const {
Mutex::Autolock _l(mMutex);
dumpLocked(result, prefix);
}
@@ -267,7 +267,7 @@
result.appendFormat("%smAbandoned=%d\n", prefix, int(mAbandoned));
if (!mAbandoned) {
- mConsumer->dump(result, prefix);
+ mConsumer->dumpState(result, prefix);
}
}
diff --git a/libs/gui/GraphicBufferAlloc.cpp b/libs/gui/GraphicBufferAlloc.cpp
index e6150f4..a8f40e0 100644
--- a/libs/gui/GraphicBufferAlloc.cpp
+++ b/libs/gui/GraphicBufferAlloc.cpp
@@ -15,7 +15,7 @@
** limitations under the License.
*/
-#include <cutils/log.h>
+#include <log/log.h>
#include <ui/GraphicBuffer.h>
diff --git a/libs/gui/IConsumerListener.cpp b/libs/gui/IConsumerListener.cpp
index 9a06011..ff7b83a 100644
--- a/libs/gui/IConsumerListener.cpp
+++ b/libs/gui/IConsumerListener.cpp
@@ -37,7 +37,7 @@
class BpConsumerListener : public BpInterface<IConsumerListener>
{
public:
- BpConsumerListener(const sp<IBinder>& impl)
+ explicit BpConsumerListener(const sp<IBinder>& impl)
: BpInterface<IConsumerListener>(impl) {
}
@@ -153,6 +153,7 @@
return BBinder::onTransact(code, data, reply, flags);
}
+ConsumerListener::~ConsumerListener() = default;
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/libs/gui/IDisplayEventConnection.cpp b/libs/gui/IDisplayEventConnection.cpp
index 9890f44..b1d3b00 100644
--- a/libs/gui/IDisplayEventConnection.cpp
+++ b/libs/gui/IDisplayEventConnection.cpp
@@ -39,7 +39,7 @@
class BpDisplayEventConnection : public BpInterface<IDisplayEventConnection>
{
public:
- BpDisplayEventConnection(const sp<IBinder>& impl)
+ explicit BpDisplayEventConnection(const sp<IBinder>& impl)
: BpInterface<IDisplayEventConnection>(impl)
{
}
diff --git a/libs/gui/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp
index 7b3b7c1..2fb380c 100644
--- a/libs/gui/IGraphicBufferAlloc.cpp
+++ b/libs/gui/IGraphicBufferAlloc.cpp
@@ -37,7 +37,7 @@
class BpGraphicBufferAlloc : public BpInterface<IGraphicBufferAlloc>
{
public:
- BpGraphicBufferAlloc(const sp<IBinder>& impl)
+ explicit BpGraphicBufferAlloc(const sp<IBinder>& impl)
: BpInterface<IGraphicBufferAlloc>(impl)
{
}
@@ -96,7 +96,7 @@
class BufferReference : public BBinder {
sp<GraphicBuffer> mBuffer;
public:
- BufferReference(const sp<GraphicBuffer>& buffer) : mBuffer(buffer) {}
+ explicit BufferReference(const sp<GraphicBuffer>& buffer) : mBuffer(buffer) {}
};
diff --git a/libs/gui/IGraphicBufferConsumer.cpp b/libs/gui/IGraphicBufferConsumer.cpp
index c8eff00..2401464 100644
--- a/libs/gui/IGraphicBufferConsumer.cpp
+++ b/libs/gui/IGraphicBufferConsumer.cpp
@@ -60,7 +60,7 @@
class BpGraphicBufferConsumer : public BpInterface<IGraphicBufferConsumer>
{
public:
- BpGraphicBufferConsumer(const sp<IBinder>& impl)
+ explicit BpGraphicBufferConsumer(const sp<IBinder>& impl)
: BpInterface<IGraphicBufferConsumer>(impl)
{
}
@@ -302,7 +302,7 @@
return result;
}
- virtual void dump(String8& result, const char* prefix) const {
+ virtual void dumpState(String8& result, const char* prefix) const {
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferConsumer::getInterfaceDescriptor());
data.writeString8(result);
@@ -480,7 +480,7 @@
CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
String8 result = data.readString8();
String8 prefix = data.readString8();
- static_cast<IGraphicBufferConsumer*>(this)->dump(result, prefix);
+ static_cast<IGraphicBufferConsumer*>(this)->dumpState(result, prefix);
reply->writeString8(result);
return NO_ERROR;
}
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index f4ba3bf..0149a3f 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -61,12 +61,12 @@
class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
{
public:
- BpGraphicBufferProducer(const sp<IBinder>& impl)
+ explicit BpGraphicBufferProducer(const sp<IBinder>& impl)
: BpInterface<IGraphicBufferProducer>(impl)
{
}
- virtual ~BpGraphicBufferProducer();
+ ~BpGraphicBufferProducer() override;
virtual status_t requestBuffer(int bufferIdx, sp<GraphicBuffer>* buf) {
Parcel data, reply;
diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp
index da54ce1..62abfa8 100644
--- a/libs/gui/IProducerListener.cpp
+++ b/libs/gui/IProducerListener.cpp
@@ -28,7 +28,7 @@
class BpProducerListener : public BpInterface<IProducerListener>
{
public:
- BpProducerListener(const sp<IBinder>& impl)
+ explicit BpProducerListener(const sp<IBinder>& impl)
: BpInterface<IProducerListener>(impl) {}
virtual ~BpProducerListener();
@@ -78,6 +78,10 @@
return BBinder::onTransact(code, data, reply, flags);
}
+ProducerListener::~ProducerListener() = default;
+
+DummyProducerListener::~DummyProducerListener() = default;
+
bool BnProducerListener::needsReleaseNotify() {
return true;
}
diff --git a/libs/gui/ISensorEventConnection.cpp b/libs/gui/ISensorEventConnection.cpp
index dc7a35c..59ecee7 100644
--- a/libs/gui/ISensorEventConnection.cpp
+++ b/libs/gui/ISensorEventConnection.cpp
@@ -40,7 +40,7 @@
class BpSensorEventConnection : public BpInterface<ISensorEventConnection>
{
public:
- BpSensorEventConnection(const sp<IBinder>& impl)
+ explicit BpSensorEventConnection(const sp<IBinder>& impl)
: BpInterface<ISensorEventConnection>(impl)
{
}
diff --git a/libs/gui/ISensorServer.cpp b/libs/gui/ISensorServer.cpp
index 3a4c7e4..07c507a 100644
--- a/libs/gui/ISensorServer.cpp
+++ b/libs/gui/ISensorServer.cpp
@@ -42,7 +42,7 @@
class BpSensorServer : public BpInterface<ISensorServer>
{
public:
- BpSensorServer(const sp<IBinder>& impl)
+ explicit BpSensorServer(const sp<IBinder>& impl)
: BpInterface<ISensorServer>(impl)
{
}
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index f0b0ada..0a8e6a5 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -49,7 +49,7 @@
class BpSurfaceComposer : public BpInterface<ISurfaceComposer>
{
public:
- BpSurfaceComposer(const sp<IBinder>& impl)
+ explicit BpSurfaceComposer(const sp<IBinder>& impl)
: BpInterface<ISurfaceComposer>(impl)
{
}
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index dd5b169..47cb047 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -48,7 +48,7 @@
class BpSurfaceComposerClient : public BpInterface<ISurfaceComposerClient>
{
public:
- BpSurfaceComposerClient(const sp<IBinder>& impl)
+ explicit BpSurfaceComposerClient(const sp<IBinder>& impl)
: BpInterface<ISurfaceComposerClient>(impl) {
}
diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp
index 053d153..2c87562 100644
--- a/libs/gui/Sensor.cpp
+++ b/libs/gui/Sensor.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+#include <inttypes.h>
+#include <stdint.h>
+#include <sys/limits.h>
+#include <sys/types.h>
#include <binder/AppOpsManager.h>
#include <binder/IServiceManager.h>
@@ -24,11 +28,6 @@
#include <utils/String8.h>
#include <utils/Flattenable.h>
-#include <inttypes.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <sys/limits.h>
-
// ----------------------------------------------------------------------------
namespace android {
// ----------------------------------------------------------------------------
@@ -220,7 +219,10 @@
break;
case SENSOR_TYPE_DYNAMIC_SENSOR_META:
mStringType = SENSOR_STRING_TYPE_DYNAMIC_SENSOR_META;
- mFlags = SENSOR_FLAG_SPECIAL_REPORTING_MODE; // special trigger and non-wake up
+ mFlags |= SENSOR_FLAG_SPECIAL_REPORTING_MODE; // special trigger
+ if (halVersion < SENSORS_DEVICE_API_VERSION_1_3) {
+ mFlags |= SENSOR_FLAG_WAKE_UP;
+ }
break;
case SENSOR_TYPE_POSE_6DOF:
mStringType = SENSOR_STRING_TYPE_POSE_6DOF;
diff --git a/libs/gui/SensorManager.cpp b/libs/gui/SensorManager.cpp
index 9fcf9ab..57c3073 100644
--- a/libs/gui/SensorManager.cpp
+++ b/libs/gui/SensorManager.cpp
@@ -139,7 +139,7 @@
mSensorManager.sensorManagerDied();
}
public:
- DeathObserver(SensorManager& mgr) : mSensorManager(mgr) { }
+ explicit DeathObserver(SensorManager& mgr) : mSensorManager(mgr) { }
};
LOG_ALWAYS_FATAL_IF(mSensorServer.get() == NULL, "getService(SensorService) NULL");
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 5a2ca8d..c681051 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -414,7 +414,7 @@
timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
isAutoTimestamp = true;
ALOGV("Surface::queueBuffer making up timestamp: %.2f ms",
- timestamp / 1000000.f);
+ timestamp / 1000000.0);
} else {
timestamp = mTimestamp;
}
@@ -1178,7 +1178,8 @@
static status_t copyBlt(
const sp<GraphicBuffer>& dst,
const sp<GraphicBuffer>& src,
- const Region& reg)
+ const Region& reg,
+ int *dstFenceFd)
{
// src and dst with, height and format must be identical. no verification
// is done here.
@@ -1189,9 +1190,10 @@
ALOGE_IF(err, "error locking src buffer %s", strerror(-err));
uint8_t* dst_bits = NULL;
- err = dst->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(),
- reinterpret_cast<void**>(&dst_bits));
+ err = dst->lockAsync(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(),
+ reinterpret_cast<void**>(&dst_bits), *dstFenceFd);
ALOGE_IF(err, "error locking dst buffer %s", strerror(-err));
+ *dstFenceFd = -1;
Region::const_iterator head(reg.begin());
Region::const_iterator tail(reg.end());
@@ -1225,7 +1227,7 @@
src->unlock();
if (dst_bits)
- dst->unlock();
+ dst->unlockAsync(dstFenceFd);
return err;
}
@@ -1275,8 +1277,9 @@
if (canCopyBack) {
// copy the area that is invalid and not repainted this round
const Region copyback(mDirtyRegion.subtract(newDirtyRegion));
- if (!copyback.isEmpty())
- copyBlt(backBuffer, frontBuffer, copyback);
+ if (!copyback.isEmpty()) {
+ copyBlt(backBuffer, frontBuffer, copyback, &fenceFd);
+ }
} else {
// if we can't copy-back anything, modify the user's dirty
// region to make sure they redraw the whole buffer
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index b78de2e..43506e9 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -69,7 +69,7 @@
mComposerService.composerServiceDied();
}
public:
- DeathObserver(ComposerService& mgr) : mComposerService(mgr) { }
+ explicit DeathObserver(ComposerService& mgr) : mComposerService(mgr) { }
};
mDeathObserver = new DeathObserver(*const_cast<ComposerService*>(this));
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
new file mode 100644
index 0000000..4779003
--- /dev/null
+++ b/libs/gui/tests/Android.bp
@@ -0,0 +1,43 @@
+// Build the unit tests,
+
+// Build the binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
+// to integrate with auto-test framework.
+cc_test {
+ name: "libgui_test",
+ test_suites: ["device-tests"],
+
+ clang: true,
+
+ srcs: [
+ "BufferQueue_test.cpp",
+ "CpuConsumer_test.cpp",
+ "FillBuffer.cpp",
+ "GLTest.cpp",
+ "IGraphicBufferProducer_test.cpp",
+ "MultiTextureConsumer_test.cpp",
+ "Sensor_test.cpp",
+ "SRGB_test.cpp",
+ "StreamSplitter_test.cpp",
+ "SurfaceTextureClient_test.cpp",
+ "SurfaceTextureFBO_test.cpp",
+ "SurfaceTextureGLThreadToGL_test.cpp",
+ "SurfaceTextureGLToGL_test.cpp",
+ "SurfaceTextureGL_test.cpp",
+ "SurfaceTextureMultiContextGL_test.cpp",
+ "Surface_test.cpp",
+ "TextureRenderer.cpp",
+ ],
+
+ shared_libs: [
+ "liblog",
+ "libEGL",
+ "libGLESv1_CM",
+ "libGLESv2",
+ "libbinder",
+ "libcutils",
+ "libgui",
+ "libsync",
+ "libui",
+ "libutils",
+ ],
+}
diff --git a/libs/gui/tests/Android.mk b/libs/gui/tests/Android.mk
deleted file mode 100644
index 6ad9986..0000000
--- a/libs/gui/tests/Android.mk
+++ /dev/null
@@ -1,52 +0,0 @@
-# Build the unit tests,
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_CLANG := true
-
-LOCAL_MODULE := libgui_test
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := \
- BufferQueue_test.cpp \
- CpuConsumer_test.cpp \
- FillBuffer.cpp \
- GLTest.cpp \
- IGraphicBufferProducer_test.cpp \
- MultiTextureConsumer_test.cpp \
- SRGB_test.cpp \
- StreamSplitter_test.cpp \
- SurfaceTextureClient_test.cpp \
- SurfaceTextureFBO_test.cpp \
- SurfaceTextureGLThreadToGL_test.cpp \
- SurfaceTextureGLToGL_test.cpp \
- SurfaceTextureGL_test.cpp \
- SurfaceTextureMultiContextGL_test.cpp \
- Surface_test.cpp \
- TextureRenderer.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
- libEGL \
- libGLESv1_CM \
- libGLESv2 \
- libbinder \
- libcutils \
- libgui \
- libsync \
- libui \
- libutils \
-
-# Build the binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
-# to integrate with auto-test framework.
-include $(BUILD_NATIVE_TEST)
-
-# Include subdirectory makefiles
-# ============================================================
-
-# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
-# team really wants is to build the stuff defined by this makefile.
-ifeq (,$(ONE_SHOT_MAKEFILE))
-include $(call first-makefiles-under,$(LOCAL_PATH))
-endif
diff --git a/libs/gui/tests/AndroidTest.xml b/libs/gui/tests/AndroidTest.xml
new file mode 100644
index 0000000..c02e020
--- /dev/null
+++ b/libs/gui/tests/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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 libgui_test">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="libgui_test->/data/local/tmp/libgui_test" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="libgui_test" />
+ </test>
+</configuration>
\ No newline at end of file
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 8a9eeee..65df7dc 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -1044,7 +1044,7 @@
// Check no free buffers in dump
String8 dumpString;
- mConsumer->dump(dumpString, nullptr);
+ mConsumer->dumpState(dumpString, nullptr);
// Parse the dump to ensure that all buffer slots that are FREE also
// have a null GraphicBuffer
diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp
index 289cc74..9c2e838 100644
--- a/libs/gui/tests/CpuConsumer_test.cpp
+++ b/libs/gui/tests/CpuConsumer_test.cpp
@@ -160,7 +160,7 @@
};
#define ASSERT_NO_ERROR(err, msg) \
- ASSERT_EQ(NO_ERROR, err) << msg << strerror(-err)
+ ASSERT_EQ(NO_ERROR, err) << (msg) << strerror(-(err))
void checkPixel(const CpuConsumer::LockedBuffer &buf,
uint32_t x, uint32_t y, uint32_t r, uint32_t g=0, uint32_t b=0) {
diff --git a/libs/gui/tests/SRGB_test.cpp b/libs/gui/tests/SRGB_test.cpp
index 3b11b97..c2640cd 100644
--- a/libs/gui/tests/SRGB_test.cpp
+++ b/libs/gui/tests/SRGB_test.cpp
@@ -435,9 +435,6 @@
ASSERT_EQ(NO_ERROR, mCpuConsumer->unlockBuffer(mLockedBuffer));
// Switch to SRGB window surface
-#define EGL_GL_COLORSPACE_KHR EGL_VG_COLORSPACE
-#define EGL_GL_COLORSPACE_SRGB_KHR EGL_VG_COLORSPACE_sRGB
-
static const int srgbAttribs[] = {
EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR,
EGL_NONE,
diff --git a/libs/gui/tests/Sensor_test.cpp b/libs/gui/tests/Sensor_test.cpp
new file mode 100644
index 0000000..fbf282d
--- /dev/null
+++ b/libs/gui/tests/Sensor_test.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2012 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 "Sensor_test"
+
+#include <gui/Sensor.h>
+#include <hardware/sensors.h>
+#include <utils/Errors.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+
+// Returns true if the two sensors have the same attributes. Does not compare
+// UUID since that should not be transmitted via flatten/unflatten.
+static bool sensorsMatch(const Sensor& a, const Sensor& b) {
+ return a.getName() == b.getName () &&
+ a.getVendor() == b.getVendor () &&
+ a.getHandle() == b.getHandle () &&
+ a.getType() == b.getType () &&
+ a.getMinValue() == b.getMinValue () &&
+ a.getMaxValue() == b.getMaxValue () &&
+ a.getResolution() == b.getResolution () &&
+ a.getPowerUsage() == b.getPowerUsage () &&
+ a.getMinDelay() == b.getMinDelay () &&
+ a.getMinDelayNs() == b.getMinDelayNs () &&
+ a.getVersion() == b.getVersion () &&
+ a.getFifoReservedEventCount() == b.getFifoReservedEventCount () &&
+ a.getFifoMaxEventCount() == b.getFifoMaxEventCount () &&
+ a.getStringType() == b.getStringType () &&
+ a.getRequiredPermission() == b.getRequiredPermission () &&
+ a.isRequiredPermissionRuntime() == b.isRequiredPermissionRuntime () &&
+ a.getRequiredAppOp() == b.getRequiredAppOp () &&
+ a.getMaxDelay() == b.getMaxDelay () &&
+ a.getFlags() == b.getFlags () &&
+ a.isWakeUpSensor() == b.isWakeUpSensor () &&
+ a.isDynamicSensor() == b.isDynamicSensor () &&
+ a.hasAdditionalInfo() == b.hasAdditionalInfo () &&
+ a.getReportingMode() == b.getReportingMode();
+}
+
+// Creates and returns a sensor_t struct with some default values filled in.
+static sensor_t getTestSensorT() {
+ sensor_t hwSensor = {};
+ hwSensor.name = "Test Sensor";
+ hwSensor.vendor = "Test Vendor";
+ hwSensor.version = 1;
+ hwSensor.handle = 2;
+ hwSensor.type = SENSOR_TYPE_ACCELEROMETER;
+ hwSensor.maxRange = 10.f;
+ hwSensor.resolution = 1.f;
+ hwSensor.power = 5.f;
+ hwSensor.minDelay = 1000;
+ hwSensor.fifoReservedEventCount = 50;
+ hwSensor.fifoMaxEventCount = 100;
+ hwSensor.stringType = SENSOR_STRING_TYPE_ACCELEROMETER;
+ hwSensor.requiredPermission = "";
+ hwSensor.maxDelay = 5000;
+ hwSensor.flags = SENSOR_FLAG_CONTINUOUS_MODE;
+ return hwSensor;
+}
+
+TEST(SensorTest, FlattenAndUnflatten) {
+ sensor_t hwSensor = getTestSensorT();
+ Sensor sensor1(&hwSensor, SENSORS_DEVICE_API_VERSION_1_4);
+ Sensor sensor2;
+
+ std::vector<uint8_t> buffer(sensor1.getFlattenedSize());
+ ASSERT_EQ(OK, sensor1.flatten(buffer.data(), buffer.size()));
+ ASSERT_EQ(OK, sensor2.unflatten(buffer.data(), buffer.size()));
+
+ EXPECT_TRUE(sensorsMatch(sensor1, sensor2));
+}
+
+} // namespace android
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index a1578f6..b10d4eb 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -535,7 +535,7 @@
return false;
}
public:
- MyThread(const sp<GLConsumer>& mST)
+ explicit MyThread(const sp<GLConsumer>& mST)
: mST(mST), mBufferRetired(false) {
ctx = eglGetCurrentContext();
sur = eglGetCurrentSurface(EGL_DRAW);
diff --git a/libs/gui/tests/SurfaceTextureGL_test.cpp b/libs/gui/tests/SurfaceTextureGL_test.cpp
index 5311c59..308bd7d 100644
--- a/libs/gui/tests/SurfaceTextureGL_test.cpp
+++ b/libs/gui/tests/SurfaceTextureGL_test.cpp
@@ -437,7 +437,7 @@
class ProducerThread : public Thread {
public:
- ProducerThread(const sp<ANativeWindow>& anw):
+ explicit ProducerThread(const sp<ANativeWindow>& anw):
mANW(anw) {
}
@@ -620,7 +620,7 @@
TEST_F(SurfaceTextureGLTest, AbandonUnblocksDequeueBuffer) {
class ProducerThread : public Thread {
public:
- ProducerThread(const sp<ANativeWindow>& anw):
+ explicit ProducerThread(const sp<ANativeWindow>& anw):
mANW(anw),
mDequeueError(NO_ERROR) {
}
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
new file mode 100644
index 0000000..9485d5b
--- /dev/null
+++ b/libs/input/Android.bp
@@ -0,0 +1,63 @@
+// Copyright (C) 2013 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.
+
+// libinput is partially built for the host (used by build time keymap validation tool)
+
+cc_library {
+ name: "libinput",
+ host_supported: true,
+
+ srcs: [
+ "Input.cpp",
+ "InputDevice.cpp",
+ "Keyboard.cpp",
+ "KeyCharacterMap.cpp",
+ "KeyLayoutMap.cpp",
+ "VirtualKeyMap.cpp",
+ ],
+
+ clang: true,
+
+ shared_libs: [
+ "liblog",
+ "libcutils",
+ ],
+
+ target: {
+ android: {
+ srcs: [
+ "IInputFlinger.cpp",
+ "InputTransport.cpp",
+ "VelocityControl.cpp",
+ "VelocityTracker.cpp",
+ ],
+
+ shared_libs: [
+ "libutils",
+ "libbinder",
+ ],
+
+ sanitize: {
+ misc_undefined: ["integer"],
+ },
+ },
+ host: {
+ shared: {
+ enabled: false,
+ },
+ },
+ },
+}
+
+subdirs = ["tests"]
diff --git a/libs/input/Android.mk b/libs/input/Android.mk
deleted file mode 100644
index 746de66..0000000
--- a/libs/input/Android.mk
+++ /dev/null
@@ -1,82 +0,0 @@
-# Copyright (C) 2013 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-# libinput is partially built for the host (used by build time keymap validation tool)
-# These files are common to host and target builds.
-
-commonSources := \
- Input.cpp \
- InputDevice.cpp \
- Keyboard.cpp \
- KeyCharacterMap.cpp \
- KeyLayoutMap.cpp \
- VirtualKeyMap.cpp
-
-deviceSources := \
- $(commonSources) \
- IInputFlinger.cpp \
- InputTransport.cpp \
- VelocityControl.cpp \
- VelocityTracker.cpp
-
-hostSources := \
- $(commonSources)
-
-# For the host
-# =====================================================
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= $(hostSources)
-
-LOCAL_MODULE:= libinput
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-
-# For the device
-# =====================================================
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= $(deviceSources)
-
-LOCAL_CLANG := true
-LOCAL_SANITIZE := integer
-
-LOCAL_SHARED_LIBRARIES := \
- liblog \
- libcutils \
- libutils \
- libbinder
-
-LOCAL_MODULE:= libinput
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-
-# Include subdirectory makefiles
-# ============================================================
-
-# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
-# team really wants is to build the stuff defined by this makefile.
-ifeq (,$(ONE_SHOT_MAKEFILE))
-include $(call first-makefiles-under,$(LOCAL_PATH))
-endif
diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp
index e009731..003e73d 100644
--- a/libs/input/IInputFlinger.cpp
+++ b/libs/input/IInputFlinger.cpp
@@ -28,7 +28,7 @@
class BpInputFlinger : public BpInterface<IInputFlinger> {
public:
- BpInputFlinger(const sp<IBinder>& impl) :
+ explicit BpInputFlinger(const sp<IBinder>& impl) :
BpInterface<IInputFlinger>(impl) { }
virtual status_t doSomething() {
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 2dff4e0..af1c0af 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -19,19 +19,18 @@
// Log debug messages about touch event resampling
#define DEBUG_RESAMPLING 0
-
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <math.h>
-#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/types.h>
#include <unistd.h>
-#include <cutils/log.h>
#include <cutils/properties.h>
-#include <input/InputTransport.h>
+#include <log/log.h>
+#include <input/InputTransport.h>
namespace android {
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
new file mode 100644
index 0000000..029a420
--- /dev/null
+++ b/libs/input/tests/Android.bp
@@ -0,0 +1,28 @@
+// Build the unit tests.
+cc_test {
+ name: "libinput_tests",
+ test_per_src: true,
+ srcs: [
+ "InputChannel_test.cpp",
+ "InputEvent_test.cpp",
+ "InputPublisherAndConsumer_test.cpp",
+ ],
+ shared_libs: [
+ "libinput",
+ "libcutils",
+ "libutils",
+ "libbinder",
+ "libui",
+ ]
+}
+
+// NOTE: This is a compile time test, and does not need to be
+// run. All assertions are static_asserts and will fail during
+// buildtime if something's wrong.
+cc_library_static {
+ name: "StructLayout_test",
+ srcs: ["StructLayout_test.cpp"],
+ cflags: [
+ "-O0",
+ ],
+}
diff --git a/libs/input/tests/Android.mk b/libs/input/tests/Android.mk
deleted file mode 100644
index 5bfa3d4..0000000
--- a/libs/input/tests/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-# Build the unit tests.
-LOCAL_PATH:= $(call my-dir)
-
-# Build the unit tests.
-test_src_files := \
- InputChannel_test.cpp \
- InputEvent_test.cpp \
- InputPublisherAndConsumer_test.cpp
-
-shared_libraries := \
- libinput \
- libcutils \
- libutils \
- libbinder \
- libui \
-
-$(foreach file,$(test_src_files), \
- $(eval include $(CLEAR_VARS)) \
- $(eval LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk) \
- $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
- $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
- $(eval LOCAL_SRC_FILES := $(file)) \
- $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
- $(eval include $(BUILD_NATIVE_TEST)) \
-)
-
-# NOTE: This is a compile time test, and does not need to be
-# run. All assertions are static_asserts and will fail during
-# buildtime if something's wrong.
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_SRC_FILES := StructLayout_test.cpp
-LOCAL_MODULE := StructLayout_test
-LOCAL_CFLAGS := -std=c++11 -O0
-LOCAL_MULTILIB := both
-include $(BUILD_STATIC_LIBRARY)
-
-
-# Build the manual test programs.
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index 8d73f45..81b9953 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -20,7 +20,7 @@
namespace android {
#define CHECK_OFFSET(type, member, expected_offset) \
- static_assert((offsetof(type, member) == expected_offset), "")
+ static_assert((offsetof(type, member) == (expected_offset)), "")
struct Foo {
uint32_t dummy;
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
new file mode 100644
index 0000000..d5ff753
--- /dev/null
+++ b/libs/ui/Android.bp
@@ -0,0 +1,68 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+ name: "libui",
+
+ clang: true,
+ cppflags: [
+ "-Weverything",
+ "-Werror",
+
+ // The static constructors and destructors in this library have not been noted to
+ // introduce significant overheads
+ "-Wno-exit-time-destructors",
+ "-Wno-global-constructors",
+
+ // We only care about compiling as C++14
+ "-Wno-c++98-compat-pedantic",
+
+ // We use four-character constants for the GraphicBuffer header, and don't care
+ // that they're non-portable as long as they're consistent within one execution
+ "-Wno-four-char-constants",
+
+ // Don't warn about struct padding
+ "-Wno-padded",
+ ],
+
+ sanitize: {
+ //misc_undefined: ["integer"],
+ },
+
+ srcs: [
+ "Fence.cpp",
+ "FrameStats.cpp",
+ "Gralloc1.cpp",
+ "Gralloc1On0Adapter.cpp",
+ "GraphicBuffer.cpp",
+ "GraphicBufferAllocator.cpp",
+ "GraphicBufferMapper.cpp",
+ "HdrCapabilities.cpp",
+ "PixelFormat.cpp",
+ "Rect.cpp",
+ "Region.cpp",
+ "UiConfig.cpp",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "libcutils",
+ "libhardware",
+ "libsync",
+ "libutils",
+ "liblog",
+ ],
+}
+
+subdirs = ["tests"]
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
deleted file mode 100644
index e690ede..0000000
--- a/libs/ui/Android.mk
+++ /dev/null
@@ -1,75 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_CLANG := true
-LOCAL_CPPFLAGS := -std=c++1y -Weverything -Werror
-# LOCAL_SANITIZE := integer
-
-# The static constructors and destructors in this library have not been noted to
-# introduce significant overheads
-LOCAL_CPPFLAGS += -Wno-exit-time-destructors
-LOCAL_CPPFLAGS += -Wno-global-constructors
-
-# We only care about compiling as C++14
-LOCAL_CPPFLAGS += -Wno-c++98-compat-pedantic
-
-# We use four-character constants for the GraphicBuffer header, and don't care
-# that they're non-portable as long as they're consistent within one execution
-LOCAL_CPPFLAGS += -Wno-four-char-constants
-
-# Don't warn about struct padding
-LOCAL_CPPFLAGS += -Wno-padded
-
-LOCAL_SRC_FILES := \
- Fence.cpp \
- FrameStats.cpp \
- Gralloc1.cpp \
- Gralloc1On0Adapter.cpp \
- GraphicBuffer.cpp \
- GraphicBufferAllocator.cpp \
- GraphicBufferMapper.cpp \
- HdrCapabilities.cpp \
- PixelFormat.cpp \
- Rect.cpp \
- Region.cpp \
- UiConfig.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libbinder \
- libcutils \
- libhardware \
- libsync \
- libutils \
- liblog
-
-ifneq ($(BOARD_FRAMEBUFFER_FORCE_FORMAT),)
-LOCAL_CFLAGS += -DFRAMEBUFFER_FORCE_FORMAT=$(BOARD_FRAMEBUFFER_FORCE_FORMAT)
-endif
-
-LOCAL_MODULE := libui
-
-include $(BUILD_SHARED_LIBRARY)
-
-
-# Include subdirectory makefiles
-# ============================================================
-
-# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
-# team really wants is to build the stuff defined by this makefile.
-ifeq (,$(ONE_SHOT_MAKEFILE))
-include $(call first-makefiles-under,$(LOCAL_PATH))
-endif
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index edfff4d..75dd8df 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -18,8 +18,7 @@
#define LOG_TAG "GraphicBufferAllocator"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <cutils/log.h>
-
+#include <log/log.h>
#include <utils/Singleton.h>
#include <utils/String8.h>
#include <utils/Trace.h>
@@ -56,7 +55,7 @@
const alloc_rec_t& rec(list.valueAt(i));
if (rec.size) {
snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %8X | 0x%08x | %s\n",
- list.keyAt(i), rec.size/1024.0f,
+ list.keyAt(i), rec.size/1024.0,
rec.width, rec.stride, rec.height, rec.format, rec.usage,
rec.requestorName.c_str());
} else {
@@ -68,7 +67,7 @@
result.append(buffer);
total += rec.size;
}
- snprintf(buffer, SIZE, "Total allocated (estimate): %.2f KB\n", total/1024.0f);
+ snprintf(buffer, SIZE, "Total allocated (estimate): %.2f KB\n", total/1024.0);
result.append(buffer);
std::string deviceDump = mDevice->dump();
result.append(deviceDump.c_str(), deviceDump.size());
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index ee152bf..b53c563 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -294,7 +294,7 @@
Region& Region::subtractSelf(const Rect& r) {
return operationSelf(r, op_nand);
}
-Region& Region::operationSelf(const Rect& r, int op) {
+Region& Region::operationSelf(const Rect& r, uint32_t op) {
Region lhs(*this);
boolean_operation(op, *this, lhs, r);
return *this;
@@ -314,7 +314,7 @@
Region& Region::subtractSelf(const Region& rhs) {
return operationSelf(rhs, op_nand);
}
-Region& Region::operationSelf(const Region& rhs, int op) {
+Region& Region::operationSelf(const Region& rhs, uint32_t op) {
Region lhs(*this);
boolean_operation(op, *this, lhs, rhs);
return *this;
@@ -339,7 +339,7 @@
const Region Region::subtract(const Rect& rhs) const {
return operation(rhs, op_nand);
}
-const Region Region::operation(const Rect& rhs, int op) const {
+const Region Region::operation(const Rect& rhs, uint32_t op) const {
Region result;
boolean_operation(op, result, *this, rhs);
return result;
@@ -359,7 +359,7 @@
const Region Region::subtract(const Region& rhs) const {
return operation(rhs, op_nand);
}
-const Region Region::operation(const Region& rhs, int op) const {
+const Region Region::operation(const Region& rhs, uint32_t op) const {
Region result;
boolean_operation(op, result, *this, rhs);
return result;
@@ -385,7 +385,7 @@
Region& Region::subtractSelf(const Region& rhs, int dx, int dy) {
return operationSelf(rhs, dx, dy, op_nand);
}
-Region& Region::operationSelf(const Region& rhs, int dx, int dy, int op) {
+Region& Region::operationSelf(const Region& rhs, int dx, int dy, uint32_t op) {
Region lhs(*this);
boolean_operation(op, *this, lhs, rhs, dx, dy);
return *this;
@@ -405,7 +405,7 @@
const Region Region::subtract(const Region& rhs, int dx, int dy) const {
return operation(rhs, dx, dy, op_nand);
}
-const Region Region::operation(const Region& rhs, int dx, int dy, int op) const {
+const Region Region::operation(const Region& rhs, int dx, int dy, uint32_t op) const {
Region result;
boolean_operation(op, result, *this, rhs, dx, dy);
return result;
@@ -424,7 +424,7 @@
Vector<Rect> span;
Rect* cur;
public:
- rasterizer(Region& reg)
+ explicit rasterizer(Region& reg)
: bounds(INT_MAX, 0, INT_MIN, 0), storage(reg.mStorage), head(), tail(), cur() {
storage.clear();
}
@@ -489,7 +489,8 @@
merge = false;
break;
}
- p++, q++;
+ p++;
+ q++;
}
}
}
@@ -582,7 +583,7 @@
return result;
}
-void Region::boolean_operation(int op, Region& dst,
+void Region::boolean_operation(uint32_t op, Region& dst,
const Region& lhs,
const Region& rhs, int dx, int dy)
{
@@ -692,7 +693,7 @@
#endif
}
-void Region::boolean_operation(int op, Region& dst,
+void Region::boolean_operation(uint32_t op, Region& dst,
const Region& lhs,
const Rect& rhs, int dx, int dy)
{
@@ -721,13 +722,13 @@
#endif
}
-void Region::boolean_operation(int op, Region& dst,
+void Region::boolean_operation(uint32_t op, Region& dst,
const Region& lhs, const Region& rhs)
{
boolean_operation(op, dst, lhs, rhs, 0, 0);
}
-void Region::boolean_operation(int op, Region& dst,
+void Region::boolean_operation(uint32_t op, Region& dst,
const Region& lhs, const Rect& rhs)
{
boolean_operation(op, dst, lhs, rhs, 0, 0);
diff --git a/libs/ui/UiConfig.cpp b/libs/ui/UiConfig.cpp
index 9e7ba8e..7730690 100644
--- a/libs/ui/UiConfig.cpp
+++ b/libs/ui/UiConfig.cpp
@@ -18,20 +18,10 @@
namespace android {
-#ifdef FRAMEBUFFER_FORCE_FORMAT
-// We need the two-level macro to stringify the contents of a macro argument
-#define STRINGIFY(x) #x
-#define TOSTRING(x) STRINGIFY(x)
-#endif
-
void appendUiConfigString(String8& configStr)
{
static const char* config =
- " [libui"
-#ifdef FRAMEBUFFER_FORCE_FORMAT
- " FRAMEBUFFER_FORCE_FORMAT=" TOSTRING(FRAMEBUFFER_FORCE_FORMAT)
-#endif
- "]";
+ " [libui]";
configStr.append(config);
}
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
new file mode 100644
index 0000000..8cdab8c
--- /dev/null
+++ b/libs/ui/tests/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2014 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "Region_test",
+ shared_libs: ["libui"],
+ srcs: ["Region_test.cpp"],
+}
+
+cc_test {
+ name: "vec_test",
+ srcs: ["vec_test.cpp"],
+}
+
+cc_test {
+ name: "mat_test",
+ srcs: ["mat_test.cpp"],
+}
diff --git a/libs/ui/tests/Android.mk b/libs/ui/tests/Android.mk
deleted file mode 100644
index 6438b1f..0000000
--- a/libs/ui/tests/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-#
-# Copyright (C) 2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_SHARED_LIBRARIES := libui
-LOCAL_SRC_FILES := Region_test.cpp
-LOCAL_MODULE := Region_test
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_SRC_FILES := vec_test.cpp
-LOCAL_MODULE := vec_test
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_SRC_FILES := mat_test.cpp
-LOCAL_MODULE := mat_test
-include $(BUILD_NATIVE_TEST)
diff --git a/opengl/Android.bp b/opengl/Android.bp
new file mode 100644
index 0000000..c520bda
--- /dev/null
+++ b/opengl/Android.bp
@@ -0,0 +1,57 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+ndk_headers {
+ name: "libEGL_headers",
+ from: "include",
+ to: "",
+ srcs: ["include/EGL/**/*.h"],
+ license: "include/EGL/NOTICE",
+}
+
+ndk_headers {
+ name: "libGLESv1_CM_headers",
+ from: "include",
+ to: "",
+ srcs: ["include/GLES/**/*.h"],
+ license: "include/GLES/NOTICE",
+}
+
+ndk_headers {
+ name: "libGLESv2_headers",
+ from: "include",
+ to: "",
+ srcs: ["include/GLES2/**/*.h"],
+ license: "include/GLES2/NOTICE",
+}
+
+ndk_headers {
+ name: "libGLESv3_headers",
+ from: "include",
+ to: "",
+ srcs: ["include/GLES3/**/*.h"],
+ license: "include/GLES3/NOTICE",
+}
+
+ndk_headers {
+ name: "khr_headers",
+ from: "include",
+ to: "",
+ srcs: ["include/KHR/**/*.h"],
+ license: "include/KHR/NOTICE",
+}
+
+subdirs = [
+ "*",
+]
diff --git a/opengl/include/EGL/NOTICE b/opengl/include/EGL/NOTICE
new file mode 100644
index 0000000..55f5efa
--- /dev/null
+++ b/opengl/include/EGL/NOTICE
@@ -0,0 +1,20 @@
+Copyright (c) 2007-2009 The Khronos Group Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and/or associated documentation files (the
+"Materials"), to deal in the Materials without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Materials, and to
+permit persons to whom the Materials are furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Materials.
+
+THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
diff --git a/opengl/include/EGL/egl.h b/opengl/include/EGL/egl.h
index 99ea342..ccb54ea 100644
--- a/opengl/include/EGL/egl.h
+++ b/opengl/include/EGL/egl.h
@@ -65,13 +65,13 @@
#define EGL_TRUE 1
/* Out-of-band handle values */
-#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0)
-#define EGL_NO_CONTEXT ((EGLContext)0)
-#define EGL_NO_DISPLAY ((EGLDisplay)0)
-#define EGL_NO_SURFACE ((EGLSurface)0)
+#define EGL_DEFAULT_DISPLAY EGL_CAST(EGLNativeDisplayType, 0)
+#define EGL_NO_CONTEXT EGL_CAST(EGLContext, 0)
+#define EGL_NO_DISPLAY EGL_CAST(EGLDisplay, 0)
+#define EGL_NO_SURFACE EGL_CAST(EGLSurface, 0)
/* Out-of-band attribute value */
-#define EGL_DONT_CARE ((EGLint)-1)
+#define EGL_DONT_CARE EGL_CAST(EGLint, -1)
/* Errors / GetError return values */
#define EGL_SUCCESS 0x3000
@@ -198,7 +198,7 @@
#define EGL_DISPLAY_SCALING 10000
/* Unknown display resolution/aspect ratio */
-#define EGL_UNKNOWN ((EGLint)-1)
+#define EGL_UNKNOWN EGL_CAST(EGLint, -1)
/* Back buffer swap behaviors */
#define EGL_BUFFER_PRESERVED 0x3094 /* EGL_SWAP_BEHAVIOR value */
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 2e18698..8b48032 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -79,7 +79,7 @@
#define EGL_KHR_image 1
#define EGL_NATIVE_PIXMAP_KHR 0x30B0 /* eglCreateImageKHR target */
typedef void *EGLImageKHR;
-#define EGL_NO_IMAGE_KHR ((EGLImageKHR)0)
+#define EGL_NO_IMAGE_KHR EGL_CAST(EGLImageKHR, 0)
#ifdef EGL_EGLEXT_PROTOTYPES
EGLAPI EGLImageKHR EGLAPIENTRY eglCreateImageKHR (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image);
@@ -115,6 +115,13 @@
#define EGL_GL_TEXTURE_ZOFFSET_KHR 0x30BD /* eglCreateImageKHR attribute */
#endif
+#ifndef EGL_KHR_gl_colorspace
+#define EGL_KHR_gl_colorspace 1
+#define EGL_GL_COLORSPACE_KHR 0x309D
+#define EGL_GL_COLORSPACE_SRGB_KHR 0x3089
+#define EGL_GL_COLORSPACE_LINEAR_KHR 0x308A
+#endif
+
#ifndef EGL_KHR_gl_renderbuffer_image
#define EGL_KHR_gl_renderbuffer_image 1
#define EGL_GL_RENDERBUFFER_KHR 0x30B9 /* eglCreateImageKHR target */
@@ -136,7 +143,7 @@
#define EGL_SYNC_REUSABLE_KHR 0x30FA
#define EGL_SYNC_FLUSH_COMMANDS_BIT_KHR 0x0001 /* eglClientWaitSyncKHR <flags> bitfield */
#define EGL_FOREVER_KHR 0xFFFFFFFFFFFFFFFFull
-#define EGL_NO_SYNC_KHR ((EGLSyncKHR)0)
+#define EGL_NO_SYNC_KHR EGL_CAST(EGLSyncKHR, 0)
#ifdef EGL_EGLEXT_PROTOTYPES
EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list);
EGLAPI EGLBoolean EGLAPIENTRY eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync);
@@ -213,7 +220,7 @@
#define EGL_SYNC_TYPE_NV 0x30ED
#define EGL_SYNC_CONDITION_NV 0x30EE
#define EGL_SYNC_FENCE_NV 0x30EF
-#define EGL_NO_SYNC_NV ((EGLSyncNV)0)
+#define EGL_NO_SYNC_NV EGL_CAST(EGLSyncNV, 0)
typedef void* EGLSyncNV;
typedef khronos_utime_nanoseconds_t EGLTimeNV;
#ifdef EGL_EGLEXT_PROTOTYPES
@@ -339,7 +346,7 @@
#define EGL_KHR_stream 1
typedef void* EGLStreamKHR;
typedef khronos_uint64_t EGLuint64KHR;
-#define EGL_NO_STREAM_KHR ((EGLStreamKHR)0)
+#define EGL_NO_STREAM_KHR EGL_CAST(EGLStreamKHR, 0)
#define EGL_CONSUMER_LATENCY_USEC_KHR 0x3210
#define EGL_PRODUCER_FRAME_KHR 0x3212
#define EGL_CONSUMER_FRAME_KHR 0x3213
@@ -466,7 +473,7 @@
#ifndef EGL_KHR_stream_cross_process_fd
#define EGL_KHR_stream_cross_process_fd 1
typedef int EGLNativeFileDescriptorKHR;
-#define EGL_NO_FILE_DESCRIPTOR_KHR ((EGLNativeFileDescriptorKHR)(-1))
+#define EGL_NO_FILE_DESCRIPTOR_KHR EGL_CAST(EGLNativeFileDescriptorKHR, -1)
#ifdef EGL_EGLEXT_PROTOTYPES
EGLAPI EGLNativeFileDescriptorKHR EGLAPIENTRY eglGetStreamFileDescriptorKHR(EGLDisplay dpy, EGLStreamKHR stream);
EGLAPI EGLStreamKHR EGLAPIENTRY eglCreateStreamFromFileDescriptorKHR(EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor);
@@ -545,7 +552,7 @@
#define EGL_SYNC_NATIVE_FENCE_ANDROID 0x3144
#define EGL_SYNC_NATIVE_FENCE_FD_ANDROID 0x3145
#define EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID 0x3146
-#define EGL_NO_NATIVE_FENCE_FD_ANDROID -1
+#define EGL_NO_NATIVE_FENCE_FD_ANDROID (-1)
#ifdef EGL_EGLEXT_PROTOTYPES
EGLAPI EGLint EGLAPIENTRY eglDupNativeFenceFDANDROID( EGLDisplay dpy, EGLSyncKHR);
#endif /* EGL_EGLEXT_PROTOTYPES */
@@ -607,7 +614,7 @@
#ifdef EGL_EGLEXT_PROTOTYPES
EGLAPI EGLClientBuffer eglCreateNativeClientBufferANDROID (const EGLint *attrib_list);
#else
-typedef EGLAPI EGLClientBuffer (EGLAPIENTRYP PFNEGLCREATENATIVECLIENTBUFFERANDROID) (const EGLint *attrib_list);
+typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLCREATENATIVECLIENTBUFFERANDROID) (const EGLint *attrib_list);
#endif
#endif
@@ -634,8 +641,8 @@
EGLAPI EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface, EGLint framesAgo, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values);
EGLAPI EGLBoolean eglQueryTimestampSupportedANDROID(EGLDisplay dpy, EGLSurface surface, EGLint timestamp);
#else
-typedef EGLAPI EGLBoolean (EGLAPIENTRYP PFNEGLGETFRAMETIMESTAMPSANDROID) (EGLDisplay dpy, EGLSurface surface, EGLint framesAgo, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values);
-typedef EGLAPI EGLBoolean (EGLAPIENTRYP PFNEGLQUERYTIMESTAMPSUPPORTEDANDROID) (EGLDisplay dpy, EGLSurface surface, EGLint timestamp);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETFRAMETIMESTAMPSANDROID) (EGLDisplay dpy, EGLSurface surface, EGLint framesAgo, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYTIMESTAMPSUPPORTEDANDROID) (EGLDisplay dpy, EGLSurface surface, EGLint timestamp);
#endif
#endif
diff --git a/opengl/include/EGL/eglplatform.h b/opengl/include/EGL/eglplatform.h
index 354ac22..54011c8 100644
--- a/opengl/include/EGL/eglplatform.h
+++ b/opengl/include/EGL/eglplatform.h
@@ -121,4 +121,10 @@
*/
typedef khronos_int32_t EGLint;
+#if defined(__cplusplus)
+#define EGL_CAST(type, value) (static_cast<type>(value))
+#else
+#define EGL_CAST(type, value) ((type) (value))
+#endif
+
#endif /* __eglplatform_h */
diff --git a/opengl/include/GLES/NOTICE b/opengl/include/GLES/NOTICE
new file mode 100644
index 0000000..4dc6614
--- /dev/null
+++ b/opengl/include/GLES/NOTICE
@@ -0,0 +1,2 @@
+This document is licensed under the SGI Free Software B License Version 2.0.
+For details, see http://oss.sgi.com/projects/FreeB/ .
diff --git a/opengl/include/GLES2/NOTICE b/opengl/include/GLES2/NOTICE
new file mode 100644
index 0000000..7a94373
--- /dev/null
+++ b/opengl/include/GLES2/NOTICE
@@ -0,0 +1,20 @@
+Copyright (c) 2013-2015 The Khronos Group Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and/or associated documentation files (the
+"Materials"), to deal in the Materials without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Materials, and to
+permit persons to whom the Materials are furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Materials.
+
+THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
diff --git a/opengl/include/GLES3/NOTICE b/opengl/include/GLES3/NOTICE
new file mode 100644
index 0000000..7a94373
--- /dev/null
+++ b/opengl/include/GLES3/NOTICE
@@ -0,0 +1,20 @@
+Copyright (c) 2013-2015 The Khronos Group Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and/or associated documentation files (the
+"Materials"), to deal in the Materials without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Materials, and to
+permit persons to whom the Materials are furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Materials.
+
+THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
diff --git a/opengl/include/KHR/NOTICE b/opengl/include/KHR/NOTICE
new file mode 100644
index 0000000..36796e8
--- /dev/null
+++ b/opengl/include/KHR/NOTICE
@@ -0,0 +1,20 @@
+Copyright (c) 2008-2009 The Khronos Group Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and/or associated documentation files (the
+"Materials"), to deal in the Materials without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Materials, and to
+permit persons to whom the Materials are furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Materials.
+
+THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
diff --git a/opengl/libagl/arch-mips/fixed_asm.S b/opengl/libagl/arch-mips/fixed_asm.S
index e1a53bc..a30ffc5 100644
--- a/opengl/libagl/arch-mips/fixed_asm.S
+++ b/opengl/libagl/arch-mips/fixed_asm.S
@@ -17,7 +17,7 @@
.text
- .align
+ .align 4
/*
* this version rounds-to-nearest and saturates numbers
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index c1efd1c..48bf676 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -18,16 +18,16 @@
#include <assert.h>
#include <atomic>
#include <errno.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/mman.h>
+#include <unistd.h>
-#include <cutils/log.h>
+#include <log/log.h>
#include <utils/threads.h>
#include <ui/ANativeObjectBase.h>
@@ -740,6 +740,7 @@
case GGL_PIXEL_FORMAT_RGB_565: size *= 2; break;
case GGL_PIXEL_FORMAT_RGBA_8888: size *= 4; break;
case GGL_PIXEL_FORMAT_RGBX_8888: size *= 4; break;
+ case GGL_PIXEL_FORMAT_BGRA_8888: size *= 4; break;
default:
ALOGE("incompatible pixel format for pbuffer (format=%d)", f);
pbuffer.data = 0;
@@ -1027,6 +1028,19 @@
{ EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
};
+// BGRA 8888 config
+static config_pair_t const config_8_attribute_list[] = {
+ { EGL_BUFFER_SIZE, 32 },
+ { EGL_ALPHA_SIZE, 8 },
+ { EGL_BLUE_SIZE, 8 },
+ { EGL_GREEN_SIZE, 8 },
+ { EGL_RED_SIZE, 8 },
+ { EGL_DEPTH_SIZE, 0 },
+ { EGL_CONFIG_ID, 8 },
+ { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_BGRA_8888 },
+ { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
+};
+
static configs_t const gConfigs[] = {
{ config_0_attribute_list, NELEM(config_0_attribute_list) },
{ config_1_attribute_list, NELEM(config_1_attribute_list) },
@@ -1036,6 +1050,7 @@
{ config_5_attribute_list, NELEM(config_5_attribute_list) },
{ config_6_attribute_list, NELEM(config_6_attribute_list) },
{ config_7_attribute_list, NELEM(config_7_attribute_list) },
+ { config_8_attribute_list, NELEM(config_8_attribute_list) },
};
static config_management_t const gConfigManagement[] = {
@@ -1118,6 +1133,10 @@
pixelFormat = GGL_PIXEL_FORMAT_A_8;
depthFormat = GGL_PIXEL_FORMAT_Z_16;
break;
+ case 8:
+ pixelFormat = GGL_PIXEL_FORMAT_BGRA_8888;
+ depthFormat = 0;
+ break;
default:
return NAME_NOT_FOUND;
}
@@ -1459,6 +1478,9 @@
if (egl_display_t::is_valid(dpy) == EGL_FALSE)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+ if (ggl_unlikely(num_config==NULL))
+ return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+
GLint numConfigs = NELEM(gConfigs);
if (!configs) {
*num_config = numConfigs;
@@ -1478,8 +1500,8 @@
{
if (egl_display_t::is_valid(dpy) == EGL_FALSE)
return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
- if (ggl_unlikely(num_config==0)) {
+
+ if (ggl_unlikely(num_config==NULL)) {
return setError(EGL_BAD_PARAMETER, EGL_FALSE);
}
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
new file mode 100644
index 0000000..c1056a7
--- /dev/null
+++ b/opengl/libs/Android.bp
@@ -0,0 +1,164 @@
+// Build the ETC1 library
+cc_library {
+ name: "libETC1",
+ srcs: ["ETC1/etc1.cpp"],
+ host_supported: true,
+
+ target: {
+ android: {
+ static: {
+ enabled: false,
+ },
+ },
+ host: {
+ shared: {
+ enabled: false,
+ },
+ },
+ windows: {
+ enabled: true,
+ },
+ },
+}
+
+// The headers modules are in frameworks/native/opengl/Android.bp.
+ndk_library {
+ name: "libEGL",
+ symbol_file: "libEGL.map.txt",
+ first_version: "9",
+ unversioned_until: "current",
+}
+
+ndk_library {
+ name: "libGLESv1_CM",
+ symbol_file: "libGLESv1_CM.map.txt",
+ first_version: "9",
+ unversioned_until: "current",
+}
+
+ndk_library {
+ name: "libGLESv2",
+ symbol_file: "libGLESv2.map.txt",
+ first_version: "9",
+ unversioned_until: "current",
+}
+
+ndk_library {
+ name: "libGLESv3",
+ symbol_file: "libGLESv3.map.txt",
+ first_version: "18",
+ unversioned_until: "current",
+}
+
+cc_defaults {
+ name: "gl_libs_defaults",
+ cflags: [
+ "-DGL_GLEXT_PROTOTYPES",
+ "-DEGL_EGLEXT_PROTOTYPES",
+ "-fvisibility=hidden",
+ ],
+ shared_libs: [
+ "libcutils",
+ "liblog",
+ "libdl",
+ ],
+
+ // we need to access the private Bionic header <bionic_tls.h>
+ include_dirs: ["bionic/libc/private"],
+}
+
+//##############################################################################
+// Build META EGL library
+//
+cc_defaults {
+ name: "egl_libs_defaults",
+ defaults: ["gl_libs_defaults"],
+ cflags: [
+ "-DLOG_TAG=\"libEGL\"",
+ ],
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ "libui",
+ ],
+}
+
+cc_library_static {
+ name: "libEGL_getProcAddress",
+ defaults: ["egl_libs_defaults"],
+ srcs: ["EGL/getProcAddress.cpp"],
+ arch: {
+ arm: {
+ instruction_set: "arm",
+ },
+ },
+}
+
+cc_library_shared {
+ name: "libEGL",
+ defaults: ["egl_libs_defaults"],
+ srcs: [
+ "EGL/egl_tls.cpp",
+ "EGL/egl_cache.cpp",
+ "EGL/egl_display.cpp",
+ "EGL/egl_object.cpp",
+ "EGL/egl.cpp",
+ "EGL/eglApi.cpp",
+ "EGL/Loader.cpp",
+ ],
+ static_libs: ["libEGL_getProcAddress"],
+ ldflags: ["-Wl,--exclude-libs=ALL"],
+
+ required: ["egl.cfg"],
+}
+
+cc_defaults {
+ name: "gles_libs_defaults",
+ defaults: ["gl_libs_defaults"],
+ arch: {
+ arm: {
+ instruction_set: "arm",
+
+ // TODO: This is to work around b/20093774. Remove after root cause is fixed
+ ldflags: ["-Wl,--hash-style,both"],
+ },
+ },
+ shared_libs: ["libEGL"],
+}
+
+//##############################################################################
+// Build the wrapper OpenGL ES 1.x library
+//
+cc_library_shared {
+ name: "libGLESv1_CM",
+ defaults: ["gles_libs_defaults"],
+ srcs: ["GLES_CM/gl.cpp"],
+
+ cflags: ["-DLOG_TAG=\"libGLESv1\""],
+}
+
+//##############################################################################
+// Build the wrapper OpenGL ES 2.x library
+//
+cc_library_shared {
+ name: "libGLESv2",
+ defaults: ["gles_libs_defaults"],
+ srcs: ["GLES2/gl2.cpp"],
+
+ shared_libs: ["libutils"],
+
+ cflags: ["-DLOG_TAG=\"libGLESv2\""],
+}
+
+//##############################################################################
+// Build the wrapper OpenGL ES 3.x library (this is just different name for v2)
+//
+cc_library_shared {
+ name: "libGLESv3",
+ defaults: ["gles_libs_defaults"],
+ srcs: ["GLES2/gl2.cpp"],
+
+ shared_libs: ["libutils"],
+
+ cflags: ["-DLOG_TAG=\"libGLESv3\""],
+}
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index 24e4c19..21e76f5 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -1,13 +1,7 @@
LOCAL_PATH:= $(call my-dir)
-###############################################################################
-# Build META EGL library
-#
-
-egl.cfg_config_module :=
# OpenGL drivers config file
ifneq ($(BOARD_EGL_CFG),)
-
include $(CLEAR_VARS)
LOCAL_MODULE := egl.cfg
LOCAL_MODULE_TAGS := optional
@@ -15,168 +9,4 @@
LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/egl
LOCAL_SRC_FILES := ../../../../$(BOARD_EGL_CFG)
include $(BUILD_PREBUILT)
-egl.cfg_config_module := $(LOCAL_MODULE)
endif
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- EGL/egl_tls.cpp \
- EGL/egl_cache.cpp \
- EGL/egl_display.cpp \
- EGL/egl_object.cpp \
- EGL/egl.cpp \
- EGL/eglApi.cpp \
- EGL/getProcAddress.cpp.arm \
- EGL/Loader.cpp \
-#
-
-LOCAL_SHARED_LIBRARIES += libbinder libcutils libutils liblog libui
-LOCAL_MODULE:= libEGL
-LOCAL_LDFLAGS += -Wl,--exclude-libs=ALL
-LOCAL_SHARED_LIBRARIES += libdl
-# we need to access the private Bionic header <bionic_tls.h>
-LOCAL_C_INCLUDES += bionic/libc/private
-
-LOCAL_CFLAGS += -DLOG_TAG=\"libEGL\"
-LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-LOCAL_CFLAGS += -fvisibility=hidden
-
-ifeq ($(BOARD_ALLOW_EGL_HIBERNATION),true)
- LOCAL_CFLAGS += -DBOARD_ALLOW_EGL_HIBERNATION
-endif
-ifneq ($(MAX_EGL_CACHE_ENTRY_SIZE),)
- LOCAL_CFLAGS += -DMAX_EGL_CACHE_ENTRY_SIZE=$(MAX_EGL_CACHE_ENTRY_SIZE)
-endif
-
-ifneq ($(MAX_EGL_CACHE_KEY_SIZE),)
- LOCAL_CFLAGS += -DMAX_EGL_CACHE_KEY_SIZE=$(MAX_EGL_CACHE_KEY_SIZE)
-endif
-
-ifneq ($(MAX_EGL_CACHE_SIZE),)
- LOCAL_CFLAGS += -DMAX_EGL_CACHE_SIZE=$(MAX_EGL_CACHE_SIZE)
-endif
-
-ifneq ($(filter address,$(SANITIZE_TARGET)),)
- LOCAL_CFLAGS_32 += -DEGL_WRAPPER_DIR=\"/$(TARGET_COPY_OUT_DATA)/lib\"
- LOCAL_CFLAGS_64 += -DEGL_WRAPPER_DIR=\"/$(TARGET_COPY_OUT_DATA)/lib64\"
-endif
-
-LOCAL_REQUIRED_MODULES := $(egl.cfg_config_module)
-egl.cfg_config_module :=
-
-include $(BUILD_SHARED_LIBRARY)
-
-###############################################################################
-# Build the wrapper OpenGL ES 1.x library
-#
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- GLES_CM/gl.cpp.arm \
-#
-
-LOCAL_CLANG := false
-LOCAL_SHARED_LIBRARIES += libcutils liblog libEGL
-LOCAL_MODULE:= libGLESv1_CM
-
-LOCAL_SHARED_LIBRARIES += libdl
-# we need to access the private Bionic header <bionic_tls.h>
-LOCAL_C_INCLUDES += bionic/libc/private
-
-LOCAL_CFLAGS += -DLOG_TAG=\"libGLESv1\"
-LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-LOCAL_CFLAGS += -fvisibility=hidden
-
-# TODO: This is to work around b/20093774. Remove after root cause is fixed
-LOCAL_LDFLAGS_arm += -Wl,--hash-style,both
-
-include $(BUILD_SHARED_LIBRARY)
-
-
-###############################################################################
-# Build the wrapper OpenGL ES 2.x library
-#
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- GLES2/gl2.cpp \
-#
-
-LOCAL_CLANG := false
-LOCAL_ARM_MODE := arm
-LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libEGL
-LOCAL_MODULE:= libGLESv2
-
-LOCAL_SHARED_LIBRARIES += libdl
-# we need to access the private Bionic header <bionic_tls.h>
-LOCAL_C_INCLUDES += bionic/libc/private
-
-LOCAL_CFLAGS += -DLOG_TAG=\"libGLESv2\"
-LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-LOCAL_CFLAGS += -fvisibility=hidden
-
-# TODO: This is to work around b/20093774. Remove after root cause is fixed
-LOCAL_LDFLAGS_arm += -Wl,--hash-style,both
-
-include $(BUILD_SHARED_LIBRARY)
-
-###############################################################################
-# Build the wrapper OpenGL ES 3.x library (this is just different name for v2)
-#
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- GLES2/gl2.cpp \
-#
-
-LOCAL_CLANG := false
-LOCAL_ARM_MODE := arm
-LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libEGL
-LOCAL_MODULE:= libGLESv3
-LOCAL_SHARED_LIBRARIES += libdl
-# we need to access the private Bionic header <bionic_tls.h>
-LOCAL_C_INCLUDES += bionic/libc/private
-
-LOCAL_CFLAGS += -DLOG_TAG=\"libGLESv3\"
-LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-LOCAL_CFLAGS += -fvisibility=hidden
-
-# TODO: This is to work around b/20093774. Remove after root cause is fixed
-LOCAL_LDFLAGS_arm += -Wl,--hash-style,both
-
-include $(BUILD_SHARED_LIBRARY)
-
-###############################################################################
-# Build the ETC1 host static library
-#
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- ETC1/etc1.cpp \
-#
-
-LOCAL_MODULE:= libETC1
-LOCAL_MODULE_HOST_OS := darwin linux windows
-
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-###############################################################################
-# Build the ETC1 device library
-#
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- ETC1/etc1.cpp \
-#
-
-LOCAL_MODULE:= libETC1
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index ca5e6e8..69e3c13 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -19,17 +19,17 @@
#include <array>
#include <ctype.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <dlfcn.h>
-#include <limits.h>
#include <dirent.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <android/dlext.h>
-#include <cutils/log.h>
#include <cutils/properties.h>
+#include <log/log.h>
#include <utils/Trace.h>
#include <EGL/egl.h>
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index 04a8e41..d0435e7 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -48,7 +48,7 @@
GLESv2 = 0x04
};
struct driver_t {
- driver_t(void* gles);
+ explicit driver_t(void* gles);
~driver_t();
status_t set(void* hnd, int32_t api);
void* dso[3];
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 18cf261..ee83ada 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -24,10 +24,9 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
-#include <cutils/log.h>
#include <cutils/atomic.h>
#include <cutils/properties.h>
-
+#include <log/log.h>
#include <utils/CallStack.h>
#include <utils/String8.h>
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 436ea30..f8e25b4 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -16,8 +16,8 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <dlfcn.h>
#include <ctype.h>
+#include <dlfcn.h>
#include <stdlib.h>
#include <string.h>
@@ -27,11 +27,11 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
-#include <cutils/log.h>
#include <cutils/atomic.h>
#include <cutils/compiler.h>
-#include <cutils/properties.h>
#include <cutils/memory.h>
+#include <cutils/properties.h>
+#include <log/log.h>
#include <gui/ISurfaceComposer.h>
@@ -56,10 +56,6 @@
using namespace android;
-// This extension has not been ratified yet, so can't be shipped.
-// Implementation is incomplete and untested.
-#define ENABLE_EGL_KHR_GL_COLORSPACE 0
-
#define ENABLE_EGL_ANDROID_GET_FRAME_TIMESTAMPS 0
// ----------------------------------------------------------------------------
@@ -101,9 +97,7 @@
"EGL_KHR_image_base " // mandatory
"EGL_KHR_image_pixmap "
"EGL_KHR_lock_surface "
-#if (ENABLE_EGL_KHR_GL_COLORSPACE != 0)
"EGL_KHR_gl_colorspace "
-#endif
"EGL_KHR_gl_texture_2D_image "
"EGL_KHR_gl_texture_3D_image "
"EGL_KHR_gl_texture_cubemap_image "
@@ -129,6 +123,7 @@
"EGL_KHR_mutable_render_buffer "
"EGL_EXT_yuv_surface "
"EGL_EXT_protected_content "
+ "EGL_IMG_context_priority "
;
// extensions not exposed to applications but used by the ANDROID system
@@ -443,12 +438,6 @@
// surfaces
// ----------------------------------------------------------------------------
-// The EGL_KHR_gl_colorspace spec hasn't been ratified yet, so these haven't
-// been added to the Khronos egl.h.
-#define EGL_GL_COLORSPACE_KHR EGL_VG_COLORSPACE
-#define EGL_GL_COLORSPACE_SRGB_KHR EGL_VG_COLORSPACE_sRGB
-#define EGL_GL_COLORSPACE_LINEAR_KHR EGL_VG_COLORSPACE_LINEAR
-
// Turn linear formats into corresponding sRGB formats when colorspace is
// EGL_GL_COLORSPACE_SRGB_KHR, or turn sRGB formats into corresponding linear
// formats when colorspace is EGL_GL_COLORSPACE_LINEAR_KHR. In any cases where
@@ -515,17 +504,7 @@
if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) {
for (const EGLint* attr = attrib_list; *attr != EGL_NONE; attr += 2) {
if (*attr == EGL_GL_COLORSPACE_KHR) {
- if (ENABLE_EGL_KHR_GL_COLORSPACE) {
- dataSpace = modifyBufferDataspace(dataSpace, *(attr+1));
- } else {
- // Normally we'd pass through unhandled attributes to
- // the driver. But in case the driver implements this
- // extension but we're disabling it, we want to prevent
- // it getting through -- support will be broken without
- // our help.
- ALOGE("sRGB window surfaces not supported");
- return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
- }
+ dataSpace = modifyBufferDataspace(dataSpace, *(attr+1));
}
}
}
@@ -1353,13 +1332,14 @@
{
clearError();
- // If there is context bound to the thread, release it
- egl_display_t::loseCurrent(get_context(getContext()));
-
egl_connection_t* const cnx = &gEGLImpl;
if (cnx->dso && cnx->egl.eglReleaseThread) {
cnx->egl.eglReleaseThread();
}
+
+ // If there is context bound to the thread, release it
+ egl_display_t::loseCurrent(get_context(getContext()));
+
egl_tls_t::clearTLS();
return EGL_TRUE;
}
diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp
index 8c135c8..1fe322d 100644
--- a/opengl/libs/EGL/egl_cache.cpp
+++ b/opengl/libs/EGL/egl_cache.cpp
@@ -27,22 +27,10 @@
#include <sys/types.h>
#include <unistd.h>
-#ifndef MAX_EGL_CACHE_ENTRY_SIZE
-#define MAX_EGL_CACHE_ENTRY_SIZE (16 * 1024);
-#endif
-
-#ifndef MAX_EGL_CACHE_KEY_SIZE
-#define MAX_EGL_CACHE_KEY_SIZE (1024);
-#endif
-
-#ifndef MAX_EGL_CACHE_SIZE
-#define MAX_EGL_CACHE_SIZE (64 * 1024);
-#endif
-
// Cache size limits.
-static const size_t maxKeySize = MAX_EGL_CACHE_KEY_SIZE;
-static const size_t maxValueSize = MAX_EGL_CACHE_ENTRY_SIZE;
-static const size_t maxTotalSize = MAX_EGL_CACHE_SIZE;
+static const size_t maxKeySize = 12 * 1024;
+static const size_t maxValueSize = 64 * 1024;
+static const size_t maxTotalSize = 2 * 1024 * 1024;
// Cache file header
static const char* cacheFileMagic = "EGL$";
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index acd70d1..d7df40c 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -218,8 +218,6 @@
*major = VERSION_MAJOR;
if (minor != NULL)
*minor = VERSION_MINOR;
-
- mHibernation.setDisplayValid(true);
}
{
@@ -268,8 +266,6 @@
res = EGL_TRUE;
}
- mHibernation.setDisplayValid(false);
-
// Reset the extension string since it will be regenerated if we get
// reinitialized.
mExtensionString.setTo("");
@@ -348,16 +344,12 @@
disp.dpy, impl_draw, impl_read, impl_ctx);
if (result == EGL_TRUE) {
c->onMakeCurrent(draw, read);
- if (!cur_c) {
- mHibernation.incWakeCount(HibernationMachine::STRONG);
- }
}
} else {
result = cur_c->cnx->egl.eglMakeCurrent(
disp.dpy, impl_draw, impl_read, impl_ctx);
if (result == EGL_TRUE) {
cur_c->onLooseCurrent();
- mHibernation.decWakeCount(HibernationMachine::STRONG);
}
}
}
@@ -382,63 +374,5 @@
}
// ----------------------------------------------------------------------------
-
-bool egl_display_t::HibernationMachine::incWakeCount(WakeRefStrength strength) {
- Mutex::Autolock _l(mLock);
- ALOGE_IF(mWakeCount < 0 || mWakeCount == INT32_MAX,
- "Invalid WakeCount (%d) on enter\n", mWakeCount);
-
- mWakeCount++;
- if (strength == STRONG)
- mAttemptHibernation = false;
-
- if (CC_UNLIKELY(mHibernating)) {
- ALOGV("Awakening\n");
- egl_connection_t* const cnx = &gEGLImpl;
-
- // These conditions should be guaranteed before entering hibernation;
- // we don't want to get into a state where we can't wake up.
- ALOGD_IF(!mDpyValid || !cnx->egl.eglAwakenProcessIMG,
- "Invalid hibernation state, unable to awaken\n");
-
- if (!cnx->egl.eglAwakenProcessIMG()) {
- ALOGE("Failed to awaken EGL implementation\n");
- return false;
- }
- mHibernating = false;
- }
- return true;
-}
-
-void egl_display_t::HibernationMachine::decWakeCount(WakeRefStrength strength) {
- Mutex::Autolock _l(mLock);
- ALOGE_IF(mWakeCount <= 0, "Invalid WakeCount (%d) on leave\n", mWakeCount);
-
- mWakeCount--;
- if (strength == STRONG)
- mAttemptHibernation = true;
-
- if (mWakeCount == 0 && CC_UNLIKELY(mAttemptHibernation)) {
- egl_connection_t* const cnx = &gEGLImpl;
- mAttemptHibernation = false;
- if (mAllowHibernation && mDpyValid &&
- cnx->egl.eglHibernateProcessIMG &&
- cnx->egl.eglAwakenProcessIMG) {
- ALOGV("Hibernating\n");
- if (!cnx->egl.eglHibernateProcessIMG()) {
- ALOGE("Failed to hibernate EGL implementation\n");
- return;
- }
- mHibernating = true;
- }
- }
-}
-
-void egl_display_t::HibernationMachine::setDisplayValid(bool valid) {
- Mutex::Autolock _l(mLock);
- mDpyValid = valid;
-}
-
-// ----------------------------------------------------------------------------
}; // namespace android
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index 2d86295..e17558c 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -68,20 +68,6 @@
// add reference to this object. returns true if this is a valid object.
bool getObject(egl_object_t* object) const;
- // These notifications allow the display to keep track of how many window
- // surfaces exist, which it uses to decide whether to hibernate the
- // underlying EGL implementation. They can be called by any thread without
- // holding a lock, but must be called via egl_display_ptr to ensure
- // proper hibernate/wakeup sequencing. If a surface destruction triggers
- // hibernation, hibernation will be delayed at least until the calling
- // thread's egl_display_ptr is destroyed.
- void onWindowSurfaceCreated() {
- mHibernation.incWakeCount(HibernationMachine::STRONG);
- }
- void onWindowSurfaceDestroyed() {
- mHibernation.decWakeCount(HibernationMachine::STRONG);
- }
-
static egl_display_t* get(EGLDisplay dpy);
static EGLDisplay getFromNativeDisplay(EGLNativeDisplayType disp);
@@ -127,8 +113,6 @@
private:
friend class egl_display_ptr;
- bool enter() { return mHibernation.incWakeCount(HibernationMachine::WEAK); }
- void leave() { return mHibernation.decWakeCount(HibernationMachine::WEAK); }
uint32_t refs;
bool eglIsInitialized;
@@ -139,47 +123,6 @@
String8 mVersionString;
String8 mClientApiString;
String8 mExtensionString;
-
- // HibernationMachine uses its own internal mutex to protect its own data.
- // The owning egl_display_t's lock may be but is not required to be held
- // when calling HibernationMachine methods. As a result, nothing in this
- // class may call back up to egl_display_t directly or indirectly.
- class HibernationMachine {
- public:
- // STRONG refs cancel (inc) or initiate (dec) a hibernation attempt
- // the next time the wakecount reaches zero. WEAK refs don't affect
- // whether a hibernation attempt will be made. Use STRONG refs only
- // for infrequent/heavy changes that are likely to indicate the
- // EGLDisplay is entering or leaving a long-term idle state.
- enum WakeRefStrength {
- WEAK = 0,
- STRONG = 1,
- };
-
- HibernationMachine(): mWakeCount(0), mHibernating(false),
- mAttemptHibernation(false), mDpyValid(false),
-#if BOARD_ALLOW_EGL_HIBERNATION
- mAllowHibernation(true)
-#else
- mAllowHibernation(false)
-#endif
- {}
- ~HibernationMachine() {}
-
- bool incWakeCount(WakeRefStrength strenth);
- void decWakeCount(WakeRefStrength strenth);
-
- void setDisplayValid(bool valid);
-
- private:
- Mutex mLock;
- int32_t mWakeCount;
- bool mHibernating;
- bool mAttemptHibernation;
- bool mDpyValid;
- const bool mAllowHibernation;
- };
- HibernationMachine mHibernation;
};
// ----------------------------------------------------------------------------
@@ -190,13 +133,7 @@
// as the egl_display_ptr exists.
class egl_display_ptr {
public:
- explicit egl_display_ptr(egl_display_t* dpy): mDpy(dpy) {
- if (mDpy) {
- if (CC_UNLIKELY(!mDpy->enter())) {
- mDpy = NULL;
- }
- }
- }
+ explicit egl_display_ptr(egl_display_t* dpy): mDpy(dpy) {}
// We only really need a C++11 move constructor, not a copy constructor.
// A move constructor would save an enter()/leave() pair on every EGL API
@@ -208,17 +145,9 @@
// other.mDpy = NULL;
// }
//
- egl_display_ptr(const egl_display_ptr& other): mDpy(other.mDpy) {
- if (mDpy) {
- mDpy->enter();
- }
- }
+ egl_display_ptr(const egl_display_ptr& other): mDpy(other.mDpy) {}
- ~egl_display_ptr() {
- if (mDpy) {
- mDpy->leave();
- }
- }
+ ~egl_display_ptr() {}
const egl_display_t* operator->() const { return mDpy; }
egl_display_t* operator->() { return mDpy; }
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index cfecf77..6a76737 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -69,17 +69,12 @@
egl_connection_t const* cnx) :
egl_object_t(dpy), surface(surface), config(config), win(win), cnx(cnx),
enableTimestamps(false), connected(true)
-{
- if (win) {
- getDisplay()->onWindowSurfaceCreated();
- }
-}
+{}
egl_surface_t::~egl_surface_t() {
ANativeWindow* const window = win.get();
if (window != NULL) {
disconnect();
- getDisplay()->onWindowSurfaceDestroyed();
}
}
diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h
index 97eda4c..3150ba6 100644
--- a/opengl/libs/EGL/egl_object.h
+++ b/opengl/libs/EGL/egl_object.h
@@ -48,7 +48,7 @@
virtual void terminate();
public:
- egl_object_t(egl_display_t* display);
+ explicit egl_object_t(egl_display_t* display);
void destroy();
inline void incRef() { count.fetch_add(1, std::memory_order_relaxed); }
@@ -63,7 +63,7 @@
class LocalRef {
egl_object_t* ref;
LocalRef();
- LocalRef(const LocalRef* rhs);
+ explicit LocalRef(const LocalRef* rhs);
public:
~LocalRef();
explicit LocalRef(egl_object_t* rhs);
diff --git a/opengl/libs/EGL/egl_tls.cpp b/opengl/libs/EGL/egl_tls.cpp
index f3739aa..6de5f27 100644
--- a/opengl/libs/EGL/egl_tls.cpp
+++ b/opengl/libs/EGL/egl_tls.cpp
@@ -14,19 +14,17 @@
** limitations under the License.
*/
-#include <stdlib.h>
#include <pthread.h>
+#include <stdlib.h>
-#include <cutils/log.h>
#include <cutils/properties.h>
-
+#include <log/log.h>
#include <utils/CallStack.h>
#include <EGL/egl.h>
#include "egl_tls.h"
-
namespace android {
pthread_key_t egl_tls_t::sKey = TLS_KEY_NOT_INITIALIZED;
diff --git a/opengl/libs/EGL/getProcAddress.cpp b/opengl/libs/EGL/getProcAddress.cpp
index 336c264..450c402 100644
--- a/opengl/libs/EGL/getProcAddress.cpp
+++ b/opengl/libs/EGL/getProcAddress.cpp
@@ -15,10 +15,10 @@
*/
#include <ctype.h>
-#include <stdlib.h>
#include <errno.h>
+#include <stdlib.h>
-#include <cutils/log.h>
+#include <android/log.h>
#include "egldefs.h"
diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp
index 6034a8e..c206041 100644
--- a/opengl/libs/GLES2/gl2.cpp
+++ b/opengl/libs/GLES2/gl2.cpp
@@ -15,12 +15,11 @@
*/
#include <ctype.h>
-#include <string.h>
#include <errno.h>
-
+#include <string.h>
#include <sys/ioctl.h>
-#include <cutils/log.h>
+#include <android/log.h>
#include <cutils/properties.h>
#include "../hooks.h"
@@ -34,39 +33,65 @@
#undef API_ENTRY
#undef CALL_GL_API
+#undef CALL_GL_API_INTERNAL_CALL
+#undef CALL_GL_API_INTERNAL_SET_RETURN_VALUE
+#undef CALL_GL_API_INTERNAL_DO_RETURN
#undef CALL_GL_API_RETURN
#if USE_SLOW_BINDING
#define API_ENTRY(_api) _api
- #define CALL_GL_API(_api, ...) \
+ #define CALL_GL_API_INTERNAL_CALL(_api, ...) \
gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
if (_c) return _c->_api(__VA_ARGS__);
+ #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE return 0;
+
+ // This stays blank, since void functions will implicitly return, and
+ // all of the other functions will return 0 based on the previous macro.
+ #define CALL_GL_API_INTERNAL_DO_RETURN
+
#elif defined(__arm__)
#define GET_TLS(reg) "mrc p15, 0, " #reg ", c13, c0, 3 \n"
- #define API_ENTRY(_api) __attribute__((noinline)) _api
+ #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
- #define CALL_GL_API(_api, ...) \
- asm volatile( \
- GET_TLS(r12) \
- "ldr r12, [r12, %[tls]] \n" \
- "cmp r12, #0 \n" \
- "ldrne pc, [r12, %[api]] \n" \
- : \
- : [tls] "J"(TLS_SLOT_OPENGL_API*4), \
- [api] "J"(__builtin_offsetof(gl_hooks_t, gl._api)) \
- : "r12" \
- );
+ #define CALL_GL_API_INTERNAL_CALL(_api, ...) \
+ asm volatile( \
+ GET_TLS(r12) \
+ "ldr r12, [r12, %[tls]] \n" \
+ "cmp r12, #0 \n" \
+ "ldrne pc, [r12, %[api]] \n" \
+ : \
+ : [tls] "J"(TLS_SLOT_OPENGL_API*4), \
+ [api] "J"(__builtin_offsetof(gl_hooks_t, gl._api)) \
+ : "r0", "r1", "r2", "r3", "r12" \
+ );
+
+ #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE \
+ asm volatile( \
+ "mov r0, #0 \n" \
+ : \
+ : \
+ : "r0" \
+ );
+
+
+ #define CALL_GL_API_INTERNAL_DO_RETURN \
+ asm volatile( \
+ "bx lr \n" \
+ : \
+ : \
+ : "r0" \
+ );
#elif defined(__aarch64__)
- #define API_ENTRY(_api) __attribute__((noinline)) _api
+ #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
- #define CALL_GL_API(_api, ...) \
+ #define CALL_GL_API_INTERNAL_CALL(_api, ...) \
asm volatile( \
"mrs x16, tpidr_el0\n" \
"ldr x16, [x16, %[tls]]\n" \
@@ -77,121 +102,173 @@
: \
: [tls] "i" (TLS_SLOT_OPENGL_API * sizeof(void*)), \
[api] "i" (__builtin_offsetof(gl_hooks_t, gl._api)) \
- : "x16" \
+ : "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x16" \
+ );
+
+ #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE \
+ asm volatile( \
+ "mov w0, wzr \n" \
+ : \
+ : \
+ : "w0" \
+ );
+
+ #define CALL_GL_API_INTERNAL_DO_RETURN \
+ asm volatile( \
+ "ret \n" \
+ : \
+ : \
+ : \
);
#elif defined(__i386__)
- #define API_ENTRY(_api) __attribute__((noinline,optimize("omit-frame-pointer"))) _api
+ #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
- #define CALL_GL_API(_api, ...) \
- register void** fn; \
+ #define CALL_GL_API_INTERNAL_CALL(_api, ...) \
__asm__ volatile( \
- "mov %%gs:0, %[fn]\n" \
- "mov %P[tls](%[fn]), %[fn]\n" \
- "test %[fn], %[fn]\n" \
+ "mov %%gs:0, %%eax\n" \
+ "mov %P[tls](%%eax), %%eax\n" \
+ "test %%eax, %%eax\n" \
"je 1f\n" \
- "jmp *%P[api](%[fn])\n" \
+ "jmp *%P[api](%%eax)\n" \
"1:\n" \
- : [fn] "=r" (fn) \
+ : \
: [tls] "i" (TLS_SLOT_OPENGL_API*sizeof(void*)), \
[api] "i" (__builtin_offsetof(gl_hooks_t, gl._api)) \
- : "cc" \
+ : "cc", "%eax" \
);
+ #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE \
+ __asm__ volatile( \
+ "xor %%eax, %%eax\n" \
+ : \
+ : \
+ : "%eax" \
+ );
+
+ #define CALL_GL_API_INTERNAL_DO_RETURN \
+ __asm__ volatile( \
+ "ret\n" \
+ : \
+ : \
+ : \
+ );
+
#elif defined(__x86_64__)
- #define API_ENTRY(_api) __attribute__((noinline,optimize("omit-frame-pointer"))) _api
+ #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
- #define CALL_GL_API(_api, ...) \
- register void** fn; \
- __asm__ volatile( \
- "mov %%fs:0, %[fn]\n" \
- "mov %P[tls](%[fn]), %[fn]\n" \
- "test %[fn], %[fn]\n" \
+ #define CALL_GL_API_INTERNAL_CALL(_api, ...) \
+ __asm__ volatile( \
+ "mov %%fs:0, %%rax\n" \
+ "mov %P[tls](%%rax), %%rax\n" \
+ "test %%rax, %%rax\n" \
"je 1f\n" \
- "jmp *%P[api](%[fn])\n" \
+ "jmp *%P[api](%%rax)\n" \
"1:\n" \
- : [fn] "=r" (fn) \
+ : \
: [tls] "i" (TLS_SLOT_OPENGL_API*sizeof(void*)), \
[api] "i" (__builtin_offsetof(gl_hooks_t, gl._api)) \
- : "cc" \
- );
+ : "cc", "%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9", \
+ "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", \
+ "%xmm6", "%xmm7" \
+ );
+
+ #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE \
+ __asm__ volatile( \
+ "xor %%eax, %%eax\n" \
+ : \
+ : \
+ : "%eax" \
+ );
+
+ #define CALL_GL_API_INTERNAL_DO_RETURN \
+ __asm__ volatile( \
+ "retq\n" \
+ : \
+ : \
+ : \
+ );
#elif defined(__mips64)
- #define API_ENTRY(_api) __attribute__((noinline)) _api
+ #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
- #define CALL_GL_API(_api, ...) \
- register unsigned long _t0 asm("$12"); \
- register unsigned long _fn asm("$25"); \
- register unsigned long _tls asm("$3"); \
- register unsigned long _v0 asm("$2"); \
- asm volatile( \
- ".set push\n\t" \
- ".set noreorder\n\t" \
- "rdhwr %[tls], $29\n\t" \
- "ld %[t0], %[OPENGL_API](%[tls])\n\t" \
- "beqz %[t0], 1f\n\t" \
- " move %[fn], $ra\n\t" \
- "ld %[t0], %[API](%[t0])\n\t" \
- "beqz %[t0], 1f\n\t" \
- " nop\n\t" \
- "move %[fn], %[t0]\n\t" \
- "1:\n\t" \
- "jalr $0, %[fn]\n\t" \
- " move %[v0], $0\n\t" \
- ".set pop\n\t" \
- : [fn] "=c"(_fn), \
- [tls] "=&r"(_tls), \
- [t0] "=&r"(_t0), \
- [v0] "=&r"(_v0) \
- : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*sizeof(void*)),\
- [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \
- : \
+ // t0: $12
+ // fn: $25
+ // tls: $3
+ // v0: $2
+ #define CALL_GL_API_INTERNAL_CALL(_api, ...) \
+ asm volatile( \
+ ".set push\n\t" \
+ ".set noreorder\n\t" \
+ "rdhwr $3, $29\n\t" \
+ "ld $12, %[OPENGL_API]($3)\n\t" \
+ "beqz $12, 1f\n\t" \
+ " move $25, $ra\n\t" \
+ "ld $12, %[API]($12)\n\t" \
+ "beqz $12, 1f\n\t" \
+ " nop\n\t" \
+ "move $25, $12\n\t" \
+ "1:\n\t" \
+ "jalr $0, $25\n\t" \
+ " move $2, $0\n\t" \
+ ".set pop\n\t" \
+ : \
+ : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*sizeof(void*)),\
+ [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \
+ : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", \
+ "$10", "$11", "$12", "$25" \
);
+ #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE
+ #define CALL_GL_API_INTERNAL_DO_RETURN
+
#elif defined(__mips__)
- #define API_ENTRY(_api) __attribute__((noinline)) _api
+ #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
- #define CALL_GL_API(_api, ...) \
- register unsigned int _t0 asm("$8"); \
- register unsigned int _fn asm("$25"); \
- register unsigned int _tls asm("$3"); \
- register unsigned int _v0 asm("$2"); \
+ // t0: $8
+ // fn: $25
+ // tls: $3
+ // v0: $2
+ #define CALL_GL_API_INTERNAL_CALL(_api, ...) \
asm volatile( \
".set push\n\t" \
".set noreorder\n\t" \
".set mips32r2\n\t" \
- "rdhwr %[tls], $29\n\t" \
- "lw %[t0], %[OPENGL_API](%[tls])\n\t" \
- "beqz %[t0], 1f\n\t" \
- " move %[fn],$ra\n\t" \
- "lw %[t0], %[API](%[t0])\n\t" \
- "beqz %[t0], 1f\n\t" \
+ "rdhwr $3, $29\n\t" \
+ "lw $3, %[OPENGL_API]($3)\n\t" \
+ "beqz $3, 1f\n\t" \
+ " move $25,$ra\n\t" \
+ "lw $3, %[API]($3)\n\t" \
+ "beqz $3, 1f\n\t" \
" nop\n\t" \
- "move %[fn], %[t0]\n\t" \
+ "move $25, $3\n\t" \
"1:\n\t" \
- "jalr $0, %[fn]\n\t" \
- " move %[v0], $0\n\t" \
+ "jalr $0, $25\n\t" \
+ " move $2, $0\n\t" \
".set pop\n\t" \
- : [fn] "=c"(_fn), \
- [tls] "=&r"(_tls), \
- [t0] "=&r"(_t0), \
- [v0] "=&r"(_v0) \
+ : \
: [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*4), \
[API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \
- : \
- );
+ : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$25" \
+ );
+
+ #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE
+ #define CALL_GL_API_INTERNAL_DO_RETURN
#endif
+#define CALL_GL_API(_api, ...) \
+ CALL_GL_API_INTERNAL_CALL(_api, __VA_ARGS__) \
+ CALL_GL_API_INTERNAL_DO_RETURN
+
#define CALL_GL_API_RETURN(_api, ...) \
- CALL_GL_API(_api, __VA_ARGS__) \
- return 0;
-
-
+ CALL_GL_API_INTERNAL_CALL(_api, __VA_ARGS__) \
+ CALL_GL_API_INTERNAL_SET_RETURN_VALUE \
+ CALL_GL_API_INTERNAL_DO_RETURN
extern "C" {
#pragma GCC diagnostic ignored "-Wunused-parameter"
@@ -202,6 +279,9 @@
#undef API_ENTRY
#undef CALL_GL_API
+#undef CALL_GL_API_INTERNAL_CALL
+#undef CALL_GL_API_INTERNAL_SET_RETURN_VALUE
+#undef CALL_GL_API_INTERNAL_DO_RETURN
#undef CALL_GL_API_RETURN
/*
diff --git a/opengl/libs/GLES_CM/gl.cpp b/opengl/libs/GLES_CM/gl.cpp
index b1b31f8..e698fcd 100644
--- a/opengl/libs/GLES_CM/gl.cpp
+++ b/opengl/libs/GLES_CM/gl.cpp
@@ -1,31 +1,30 @@
-/*
+/*
** Copyright 2007, 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
+ ** 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
+ ** 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
+ ** 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 <ctype.h>
-#include <string.h>
#include <errno.h>
-
+#include <string.h>
#include <sys/ioctl.h>
+#include <android/log.h>
+#include <cutils/properties.h>
+
#include <GLES/gl.h>
#include <GLES/glext.h>
-#include <cutils/log.h>
-#include <cutils/properties.h>
-
#include "../hooks.h"
#include "../egl_impl.h"
@@ -90,39 +89,65 @@
#undef API_ENTRY
#undef CALL_GL_API
+#undef CALL_GL_API_INTERNAL_CALL
+#undef CALL_GL_API_INTERNAL_SET_RETURN_VALUE
+#undef CALL_GL_API_INTERNAL_DO_RETURN
#undef CALL_GL_API_RETURN
#if USE_SLOW_BINDING
#define API_ENTRY(_api) _api
- #define CALL_GL_API(_api, ...) \
+ #define CALL_GL_API_INTERNAL_CALL(_api, ...) \
gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
if (_c) return _c->_api(__VA_ARGS__);
+ #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE return 0;
+
+ // This stays blank, since void functions will implicitly return, and
+ // all of the other functions will return 0 based on the previous macro.
+ #define CALL_GL_API_INTERNAL_DO_RETURN
+
#elif defined(__arm__)
#define GET_TLS(reg) "mrc p15, 0, " #reg ", c13, c0, 3 \n"
- #define API_ENTRY(_api) __attribute__((noinline)) _api
+ #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
- #define CALL_GL_API(_api, ...) \
- asm volatile( \
- GET_TLS(r12) \
- "ldr r12, [r12, %[tls]] \n" \
- "cmp r12, #0 \n" \
- "ldrne pc, [r12, %[api]] \n" \
- : \
- : [tls] "J"(TLS_SLOT_OPENGL_API*4), \
- [api] "J"(__builtin_offsetof(gl_hooks_t, gl._api)) \
- : "r12" \
- );
+ #define CALL_GL_API_INTERNAL_CALL(_api, ...) \
+ asm volatile( \
+ GET_TLS(r12) \
+ "ldr r12, [r12, %[tls]] \n" \
+ "cmp r12, #0 \n" \
+ "ldrne pc, [r12, %[api]] \n" \
+ : \
+ : [tls] "J"(TLS_SLOT_OPENGL_API*4), \
+ [api] "J"(__builtin_offsetof(gl_hooks_t, gl._api)) \
+ : "r0", "r1", "r2", "r3", "r12" \
+ );
+
+ #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE \
+ asm volatile( \
+ "mov r0, #0 \n" \
+ : \
+ : \
+ : "r0" \
+ );
+
+
+ #define CALL_GL_API_INTERNAL_DO_RETURN \
+ asm volatile( \
+ "bx lr \n" \
+ : \
+ : \
+ : "r0" \
+ );
#elif defined(__aarch64__)
- #define API_ENTRY(_api) __attribute__((noinline)) _api
+ #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
- #define CALL_GL_API(_api, ...) \
+ #define CALL_GL_API_INTERNAL_CALL(_api, ...) \
asm volatile( \
"mrs x16, tpidr_el0\n" \
"ldr x16, [x16, %[tls]]\n" \
@@ -133,120 +158,173 @@
: \
: [tls] "i" (TLS_SLOT_OPENGL_API * sizeof(void*)), \
[api] "i" (__builtin_offsetof(gl_hooks_t, gl._api)) \
- : "x16" \
+ : "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x16" \
+ );
+
+ #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE \
+ asm volatile( \
+ "mov w0, wzr \n" \
+ : \
+ : \
+ : "w0" \
+ );
+
+ #define CALL_GL_API_INTERNAL_DO_RETURN \
+ asm volatile( \
+ "ret \n" \
+ : \
+ : \
+ : \
);
#elif defined(__i386__)
- #define API_ENTRY(_api) __attribute__((noinline,optimize("omit-frame-pointer"))) _api
+ #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
- #define CALL_GL_API(_api, ...) \
- register void* fn; \
+ #define CALL_GL_API_INTERNAL_CALL(_api, ...) \
__asm__ volatile( \
- "mov %%gs:0, %[fn]\n" \
- "mov %P[tls](%[fn]), %[fn]\n" \
- "test %[fn], %[fn]\n" \
+ "mov %%gs:0, %%eax\n" \
+ "mov %P[tls](%%eax), %%eax\n" \
+ "test %%eax, %%eax\n" \
"je 1f\n" \
- "jmp *%P[api](%[fn])\n" \
+ "jmp *%P[api](%%eax)\n" \
"1:\n" \
- : [fn] "=r" (fn) \
+ : \
: [tls] "i" (TLS_SLOT_OPENGL_API*sizeof(void*)), \
[api] "i" (__builtin_offsetof(gl_hooks_t, gl._api)) \
- : "cc" \
- );
+ : "cc", "%eax" \
+ );
+
+ #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE \
+ __asm__ volatile( \
+ "xor %%eax, %%eax\n" \
+ : \
+ : \
+ : "%eax" \
+ );
+
+ #define CALL_GL_API_INTERNAL_DO_RETURN \
+ __asm__ volatile( \
+ "ret\n" \
+ : \
+ : \
+ : \
+ );
#elif defined(__x86_64__)
- #define API_ENTRY(_api) __attribute__((noinline,optimize("omit-frame-pointer"))) _api
+ #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
- #define CALL_GL_API(_api, ...) \
- register void** fn; \
- __asm__ volatile( \
- "mov %%fs:0, %[fn]\n" \
- "mov %P[tls](%[fn]), %[fn]\n" \
- "test %[fn], %[fn]\n" \
+ #define CALL_GL_API_INTERNAL_CALL(_api, ...) \
+ __asm__ volatile( \
+ "mov %%fs:0, %%rax\n" \
+ "mov %P[tls](%%rax), %%rax\n" \
+ "test %%rax, %%rax\n" \
"je 1f\n" \
- "jmp *%P[api](%[fn])\n" \
+ "jmp *%P[api](%%rax)\n" \
"1:\n" \
- : [fn] "=r" (fn) \
+ : \
: [tls] "i" (TLS_SLOT_OPENGL_API*sizeof(void*)), \
[api] "i" (__builtin_offsetof(gl_hooks_t, gl._api)) \
- : "cc" \
- );
+ : "cc", "%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9", \
+ "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", \
+ "%xmm6", "%xmm7" \
+ );
+
+ #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE \
+ __asm__ volatile( \
+ "xor %%eax, %%eax\n" \
+ : \
+ : \
+ : "%eax" \
+ );
+
+ #define CALL_GL_API_INTERNAL_DO_RETURN \
+ __asm__ volatile( \
+ "retq\n" \
+ : \
+ : \
+ : \
+ );
#elif defined(__mips64)
- #define API_ENTRY(_api) __attribute__((noinline)) _api
+ #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
- #define CALL_GL_API(_api, ...) \
- register unsigned long _t0 asm("$12"); \
- register unsigned long _fn asm("$25"); \
- register unsigned long _tls asm("$3"); \
- register unsigned long _v0 asm("$2"); \
- asm volatile( \
- ".set push\n\t" \
- ".set noreorder\n\t" \
- "rdhwr %[tls], $29\n\t" \
- "ld %[t0], %[OPENGL_API](%[tls])\n\t" \
- "beqz %[t0], 1f\n\t" \
- " move %[fn], $ra\n\t" \
- "ld %[t0], %[API](%[t0])\n\t" \
- "beqz %[t0], 1f\n\t" \
- " nop\n\t" \
- "move %[fn], %[t0]\n\t" \
- "1:\n\t" \
- "jalr $0, %[fn]\n\t" \
- " move %[v0], $0\n\t" \
- ".set pop\n\t" \
- : [fn] "=c"(_fn), \
- [tls] "=&r"(_tls), \
- [t0] "=&r"(_t0), \
- [v0] "=&r"(_v0) \
- : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*sizeof(void*)),\
- [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \
- : \
+ // t0: $12
+ // fn: $25
+ // tls: $3
+ // v0: $2
+ #define CALL_GL_API_INTERNAL_CALL(_api, ...) \
+ asm volatile( \
+ ".set push\n\t" \
+ ".set noreorder\n\t" \
+ "rdhwr $3, $29\n\t" \
+ "ld $12, %[OPENGL_API]($3)\n\t" \
+ "beqz $12, 1f\n\t" \
+ " move $25, $ra\n\t" \
+ "ld $12, %[API]($12)\n\t" \
+ "beqz $12, 1f\n\t" \
+ " nop\n\t" \
+ "move $25, $12\n\t" \
+ "1:\n\t" \
+ "jalr $0, $25\n\t" \
+ " move $2, $0\n\t" \
+ ".set pop\n\t" \
+ : \
+ : [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*sizeof(void*)),\
+ [API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \
+ : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", \
+ "$10", "$11", "$12", "$25" \
);
+ #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE
+ #define CALL_GL_API_INTERNAL_DO_RETURN
+
#elif defined(__mips__)
- #define API_ENTRY(_api) __attribute__((noinline)) _api
+ #define API_ENTRY(_api) __attribute__((naked,noinline)) _api
- #define CALL_GL_API(_api, ...) \
- register unsigned int _t0 asm("$8"); \
- register unsigned int _fn asm("$25"); \
- register unsigned int _tls asm("$3"); \
- register unsigned int _v0 asm("$2"); \
+ // t0: $8
+ // fn: $25
+ // tls: $3
+ // v0: $2
+ #define CALL_GL_API_INTERNAL_CALL(_api, ...) \
asm volatile( \
".set push\n\t" \
".set noreorder\n\t" \
".set mips32r2\n\t" \
- "rdhwr %[tls], $29\n\t" \
- "lw %[t0], %[OPENGL_API](%[tls])\n\t" \
- "beqz %[t0], 1f\n\t" \
- " move %[fn], $ra\n\t" \
- "lw %[t0], %[API](%[t0])\n\t" \
- "beqz %[t0], 1f\n\t" \
+ "rdhwr $3, $29\n\t" \
+ "lw $3, %[OPENGL_API]($3)\n\t" \
+ "beqz $3, 1f\n\t" \
+ " move $25,$ra\n\t" \
+ "lw $3, %[API]($3)\n\t" \
+ "beqz $3, 1f\n\t" \
" nop\n\t" \
- "move %[fn], %[t0]\n\t" \
+ "move $25, $3\n\t" \
"1:\n\t" \
- "jalr $0, %[fn]\n\t" \
- " move %[v0], $0\n\t" \
+ "jalr $0, $25\n\t" \
+ " move $2, $0\n\t" \
".set pop\n\t" \
- : [fn] "=c"(_fn), \
- [tls] "=&r"(_tls), \
- [t0] "=&r"(_t0), \
- [v0] "=&r"(_v0) \
+ : \
: [OPENGL_API] "I"(TLS_SLOT_OPENGL_API*4), \
[API] "I"(__builtin_offsetof(gl_hooks_t, gl._api)) \
- : \
- );
+ : "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$25" \
+ );
+
+ #define CALL_GL_API_INTERNAL_SET_RETURN_VALUE
+ #define CALL_GL_API_INTERNAL_DO_RETURN
#endif
-#define CALL_GL_API_RETURN(_api, ...) \
- CALL_GL_API(_api, __VA_ARGS__) \
- return 0;
+#define CALL_GL_API(_api, ...) \
+ CALL_GL_API_INTERNAL_CALL(_api, __VA_ARGS__) \
+ CALL_GL_API_INTERNAL_DO_RETURN
+#define CALL_GL_API_RETURN(_api, ...) \
+ CALL_GL_API_INTERNAL_CALL(_api, __VA_ARGS__) \
+ CALL_GL_API_INTERNAL_SET_RETURN_VALUE \
+ CALL_GL_API_INTERNAL_DO_RETURN
extern "C" {
#pragma GCC diagnostic ignored "-Wunused-parameter"
@@ -257,6 +335,9 @@
#undef API_ENTRY
#undef CALL_GL_API
+#undef CALL_GL_API_INTERNAL_CALL
+#undef CALL_GL_API_INTERNAL_SET_RETURN_VALUE
+#undef CALL_GL_API_INTERNAL_DO_RETURN
#undef CALL_GL_API_RETURN
/*
diff --git a/opengl/libs/hooks.h b/opengl/libs/hooks.h
index e14075c..81dbe0e 100644
--- a/opengl/libs/hooks.h
+++ b/opengl/libs/hooks.h
@@ -56,8 +56,8 @@
#undef GL_ENTRY
#undef EGL_ENTRY
-#define GL_ENTRY(_r, _api, ...) _r (*_api)(__VA_ARGS__);
-#define EGL_ENTRY(_r, _api, ...) _r (*_api)(__VA_ARGS__);
+#define GL_ENTRY(_r, _api, ...) _r (*(_api))(__VA_ARGS__);
+#define EGL_ENTRY(_r, _api, ...) _r (*(_api))(__VA_ARGS__);
struct egl_t {
#include "EGL/egl_entries.in"
diff --git a/opengl/libs/libEGL.map.txt b/opengl/libs/libEGL.map.txt
new file mode 100644
index 0000000..c8b83f5
--- /dev/null
+++ b/opengl/libs/libEGL.map.txt
@@ -0,0 +1,67 @@
+LIBEGL {
+ global:
+ eglBindAPI;
+ eglBindTexImage;
+ eglChooseConfig;
+ eglClientWaitSyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ eglCopyBuffers;
+ eglCreateContext;
+ eglCreateImageKHR;
+ eglCreateNativeClientBufferANDROID; # introduced=24
+ eglCreatePbufferFromClientBuffer;
+ eglCreatePbufferSurface;
+ eglCreatePixmapSurface;
+ eglCreateStreamFromFileDescriptorKHR; # introduced=23
+ eglCreateStreamKHR; # introduced=23
+ eglCreateStreamProducerSurfaceKHR; # introduced=23
+ eglCreateSyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ eglCreateWindowSurface;
+ eglDestroyContext;
+ eglDestroyImageKHR;
+ eglDestroyStreamKHR; # introduced=23
+ eglDestroySurface;
+ eglDestroySyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ eglGetConfigAttrib;
+ eglGetConfigs;
+ eglGetCurrentContext;
+ eglGetCurrentDisplay;
+ eglGetCurrentSurface;
+ eglGetDisplay;
+ eglGetError;
+ eglGetProcAddress;
+ eglGetStreamFileDescriptorKHR; # introduced=23
+ eglGetSyncAttribKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ eglGetSystemTimeFrequencyNV; # introduced-arm=14 introduced-arm64=21 introduced-mips=14 introduced-mips64=21 introduced-x86=14 introduced-x86_64=21
+ eglGetSystemTimeNV; # introduced-arm=14 introduced-arm64=21 introduced-mips=14 introduced-mips64=21 introduced-x86=14 introduced-x86_64=21
+ eglInitialize;
+ eglLockSurfaceKHR;
+ eglMakeCurrent;
+ eglPresentationTimeANDROID; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ eglQueryAPI;
+ eglQueryContext;
+ eglQueryStreamKHR; # introduced=23
+ eglQueryStreamTimeKHR; # introduced=23
+ eglQueryStreamu64KHR; # introduced=23
+ eglQueryString;
+ eglQuerySurface;
+ eglReleaseTexImage;
+ eglReleaseThread;
+ eglSetDamageRegionKHR; # introduced=23
+ eglSignalSyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ eglStreamAttribKHR; # introduced=23
+ eglStreamConsumerAcquireKHR; # introduced=23
+ eglStreamConsumerGLTextureExternalKHR; # introduced=23
+ eglStreamConsumerReleaseKHR; # introduced=23
+ eglSurfaceAttrib;
+ eglSwapBuffers;
+ eglSwapBuffersWithDamageKHR; # introduced=23
+ eglSwapInterval;
+ eglTerminate;
+ eglUnlockSurfaceKHR;
+ eglWaitClient;
+ eglWaitGL;
+ eglWaitNative;
+ eglWaitSyncKHR; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
+ local:
+ *;
+};
diff --git a/opengl/libs/libGLESv1_CM.map.txt b/opengl/libs/libGLESv1_CM.map.txt
new file mode 100644
index 0000000..8ba91e6
--- /dev/null
+++ b/opengl/libs/libGLESv1_CM.map.txt
@@ -0,0 +1,283 @@
+LIBGLESV1_CM {
+ global:
+ glActiveTexture;
+ glAlphaFunc;
+ glAlphaFuncx;
+ glAlphaFuncxOES;
+ glBindBuffer;
+ glBindFramebufferOES;
+ glBindRenderbufferOES;
+ glBindTexture;
+ glBindVertexArrayOES; # introduced-mips=9 introduced-x86=9
+ glBlendEquationOES;
+ glBlendEquationSeparateOES;
+ glBlendFunc;
+ glBlendFuncSeparateOES;
+ glBufferData;
+ glBufferSubData;
+ glCheckFramebufferStatusOES;
+ glClear;
+ glClearColor;
+ glClearColorx;
+ glClearColorxOES;
+ glClearDepthf;
+ glClearDepthfOES;
+ glClearDepthx;
+ glClearDepthxOES;
+ glClearStencil;
+ glClientActiveTexture;
+ glClipPlanef;
+ glClipPlanefIMG; # introduced-mips=9 introduced-x86=9
+ glClipPlanefOES;
+ glClipPlanex;
+ glClipPlanexIMG; # introduced-mips=9 introduced-x86=9
+ glClipPlanexOES;
+ glColor4f;
+ glColor4ub;
+ glColor4x;
+ glColor4xOES;
+ glColorMask;
+ glColorPointer;
+ glColorPointerBounds;
+ glCompressedTexImage2D;
+ glCompressedTexSubImage2D;
+ glCopyTexImage2D;
+ glCopyTexSubImage2D;
+ glCullFace;
+ glCurrentPaletteMatrixOES;
+ glDeleteBuffers;
+ glDeleteFencesNV; # introduced-mips=9 introduced-x86=9
+ glDeleteFramebuffersOES;
+ glDeleteRenderbuffersOES;
+ glDeleteTextures;
+ glDeleteVertexArraysOES; # introduced-mips=9 introduced-x86=9
+ glDepthFunc;
+ glDepthMask;
+ glDepthRangef;
+ glDepthRangefOES;
+ glDepthRangex;
+ glDepthRangexOES;
+ glDisable;
+ glDisableClientState;
+ glDisableDriverControlQCOM; # introduced-mips=9 introduced-x86=9
+ glDiscardFramebufferEXT; # introduced-mips=9 introduced-x86=9
+ glDrawArrays;
+ glDrawElements;
+ glDrawTexfOES;
+ glDrawTexfvOES;
+ glDrawTexiOES;
+ glDrawTexivOES;
+ glDrawTexsOES;
+ glDrawTexsvOES;
+ glDrawTexxOES;
+ glDrawTexxvOES;
+ glEGLImageTargetRenderbufferStorageOES;
+ glEGLImageTargetTexture2DOES;
+ glEnable;
+ glEnableClientState;
+ glEnableDriverControlQCOM; # introduced-mips=9 introduced-x86=9
+ glEndTilingQCOM; # introduced-mips=9 introduced-x86=9
+ glExtGetBufferPointervQCOM; # introduced-mips=9 introduced-x86=9
+ glExtGetBuffersQCOM; # introduced-mips=9 introduced-x86=9
+ glExtGetFramebuffersQCOM; # introduced-mips=9 introduced-x86=9
+ glExtGetProgramBinarySourceQCOM; # introduced-mips=9 introduced-x86=9
+ glExtGetProgramsQCOM; # introduced-mips=9 introduced-x86=9
+ glExtGetRenderbuffersQCOM; # introduced-mips=9 introduced-x86=9
+ glExtGetShadersQCOM; # introduced-mips=9 introduced-x86=9
+ glExtGetTexLevelParameterivQCOM; # introduced-mips=9 introduced-x86=9
+ glExtGetTexSubImageQCOM; # introduced-mips=9 introduced-x86=9
+ glExtGetTexturesQCOM; # introduced-mips=9 introduced-x86=9
+ glExtIsProgramBinaryQCOM; # introduced-mips=9 introduced-x86=9
+ glExtTexObjectStateOverrideiQCOM; # introduced-mips=9 introduced-x86=9
+ glFinish;
+ glFinishFenceNV; # introduced-mips=9 introduced-x86=9
+ glFlush;
+ glFogf;
+ glFogfv;
+ glFogx;
+ glFogxOES;
+ glFogxv;
+ glFogxvOES;
+ glFramebufferRenderbufferOES;
+ glFramebufferTexture2DMultisampleIMG; # introduced-mips=9 introduced-x86=9
+ glFramebufferTexture2DOES;
+ glFrontFace;
+ glFrustumf;
+ glFrustumfOES;
+ glFrustumx;
+ glFrustumxOES;
+ glGenBuffers;
+ glGenFencesNV; # introduced-mips=9 introduced-x86=9
+ glGenFramebuffersOES;
+ glGenRenderbuffersOES;
+ glGenTextures;
+ glGenVertexArraysOES; # introduced-mips=9 introduced-x86=9
+ glGenerateMipmapOES;
+ glGetBooleanv;
+ glGetBufferParameteriv;
+ glGetBufferPointervOES;
+ glGetClipPlanef;
+ glGetClipPlanefOES;
+ glGetClipPlanex;
+ glGetClipPlanexOES;
+ glGetDriverControlStringQCOM; # introduced-mips=9 introduced-x86=9
+ glGetDriverControlsQCOM; # introduced-mips=9 introduced-x86=9
+ glGetError;
+ glGetFenceivNV; # introduced-mips=9 introduced-x86=9
+ glGetFixedv;
+ glGetFixedvOES;
+ glGetFloatv;
+ glGetFramebufferAttachmentParameterivOES;
+ glGetIntegerv;
+ glGetLightfv;
+ glGetLightxv;
+ glGetLightxvOES;
+ glGetMaterialfv;
+ glGetMaterialxv;
+ glGetMaterialxvOES;
+ glGetPointerv;
+ glGetRenderbufferParameterivOES;
+ glGetString;
+ glGetTexEnvfv;
+ glGetTexEnviv;
+ glGetTexEnvxv;
+ glGetTexEnvxvOES;
+ glGetTexGenfvOES;
+ glGetTexGenivOES;
+ glGetTexGenxvOES;
+ glGetTexParameterfv;
+ glGetTexParameteriv;
+ glGetTexParameterxv;
+ glGetTexParameterxvOES;
+ glHint;
+ glIsBuffer;
+ glIsEnabled;
+ glIsFenceNV; # introduced-mips=9 introduced-x86=9
+ glIsFramebufferOES;
+ glIsRenderbufferOES;
+ glIsTexture;
+ glIsVertexArrayOES; # introduced-mips=9 introduced-x86=9
+ glLightModelf;
+ glLightModelfv;
+ glLightModelx;
+ glLightModelxOES;
+ glLightModelxv;
+ glLightModelxvOES;
+ glLightf;
+ glLightfv;
+ glLightx;
+ glLightxOES;
+ glLightxv;
+ glLightxvOES;
+ glLineWidth;
+ glLineWidthx;
+ glLineWidthxOES;
+ glLoadIdentity;
+ glLoadMatrixf;
+ glLoadMatrixx;
+ glLoadMatrixxOES;
+ glLoadPaletteFromModelViewMatrixOES;
+ glLogicOp;
+ glMapBufferOES;
+ glMaterialf;
+ glMaterialfv;
+ glMaterialx;
+ glMaterialxOES;
+ glMaterialxv;
+ glMaterialxvOES;
+ glMatrixIndexPointerOES;
+ glMatrixIndexPointerOESBounds; # introduced-mips=9 introduced-x86=9
+ glMatrixMode;
+ glMultMatrixf;
+ glMultMatrixx;
+ glMultMatrixxOES;
+ glMultiDrawArraysEXT; # introduced-mips=9 introduced-x86=9
+ glMultiDrawElementsEXT; # introduced-mips=9 introduced-x86=9
+ glMultiTexCoord4f;
+ glMultiTexCoord4x;
+ glMultiTexCoord4xOES;
+ glNormal3f;
+ glNormal3x;
+ glNormal3xOES;
+ glNormalPointer;
+ glNormalPointerBounds;
+ glOrthof;
+ glOrthofOES;
+ glOrthox;
+ glOrthoxOES;
+ glPixelStorei;
+ glPointParameterf;
+ glPointParameterfv;
+ glPointParameterx;
+ glPointParameterxOES;
+ glPointParameterxv;
+ glPointParameterxvOES;
+ glPointSize;
+ glPointSizePointerOES;
+ glPointSizePointerOESBounds; # introduced-mips=9 introduced-x86=9
+ glPointSizex;
+ glPointSizexOES;
+ glPolygonOffset;
+ glPolygonOffsetx;
+ glPolygonOffsetxOES;
+ glPopMatrix;
+ glPushMatrix;
+ glQueryMatrixxOES;
+ glReadPixels;
+ glRenderbufferStorageMultisampleIMG; # introduced-mips=9 introduced-x86=9
+ glRenderbufferStorageOES;
+ glRotatef;
+ glRotatex;
+ glRotatexOES;
+ glSampleCoverage;
+ glSampleCoveragex;
+ glSampleCoveragexOES;
+ glScalef;
+ glScalex;
+ glScalexOES;
+ glScissor;
+ glSetFenceNV; # introduced-mips=9 introduced-x86=9
+ glShadeModel;
+ glStartTilingQCOM; # introduced-mips=9 introduced-x86=9
+ glStencilFunc;
+ glStencilMask;
+ glStencilOp;
+ glTestFenceNV; # introduced-mips=9 introduced-x86=9
+ glTexCoordPointer;
+ glTexCoordPointerBounds;
+ glTexEnvf;
+ glTexEnvfv;
+ glTexEnvi;
+ glTexEnviv;
+ glTexEnvx;
+ glTexEnvxOES;
+ glTexEnvxv;
+ glTexEnvxvOES;
+ glTexGenfOES;
+ glTexGenfvOES;
+ glTexGeniOES;
+ glTexGenivOES;
+ glTexGenxOES;
+ glTexGenxvOES;
+ glTexImage2D;
+ glTexParameterf;
+ glTexParameterfv;
+ glTexParameteri;
+ glTexParameteriv;
+ glTexParameterx;
+ glTexParameterxOES;
+ glTexParameterxv;
+ glTexParameterxvOES;
+ glTexSubImage2D;
+ glTranslatef;
+ glTranslatex;
+ glTranslatexOES;
+ glUnmapBufferOES;
+ glVertexPointer;
+ glVertexPointerBounds;
+ glViewport;
+ glWeightPointerOES;
+ glWeightPointerOESBounds; # introduced-mips=9 introduced-x86=9
+ local:
+ *;
+};
diff --git a/opengl/libs/libGLESv2.map.txt b/opengl/libs/libGLESv2.map.txt
new file mode 100644
index 0000000..1b0042a
--- /dev/null
+++ b/opengl/libs/libGLESv2.map.txt
@@ -0,0 +1,207 @@
+LIBGLESV2 {
+ global:
+ glActiveTexture;
+ glAttachShader;
+ glBeginPerfMonitorAMD;
+ glBindAttribLocation;
+ glBindBuffer;
+ glBindFramebuffer;
+ glBindRenderbuffer;
+ glBindTexture;
+ glBindVertexArrayOES; # introduced-mips=9 introduced-x86=9
+ glBlendColor;
+ glBlendEquation;
+ glBlendEquationSeparate;
+ glBlendFunc;
+ glBlendFuncSeparate;
+ glBufferData;
+ glBufferSubData;
+ glCheckFramebufferStatus;
+ glClear;
+ glClearColor;
+ glClearDepthf;
+ glClearStencil;
+ glColorMask;
+ glCompileShader;
+ glCompressedTexImage2D;
+ glCompressedTexImage3DOES;
+ glCompressedTexSubImage2D;
+ glCompressedTexSubImage3DOES;
+ glCopyTexImage2D;
+ glCopyTexSubImage2D;
+ glCopyTexSubImage3DOES;
+ glCoverageMaskNV; # introduced-mips=9 introduced-x86=9
+ glCoverageOperationNV; # introduced-mips=9 introduced-x86=9
+ glCreateProgram;
+ glCreateShader;
+ glCullFace;
+ glDeleteBuffers;
+ glDeleteFencesNV;
+ glDeleteFramebuffers;
+ glDeletePerfMonitorsAMD;
+ glDeleteProgram;
+ glDeleteRenderbuffers;
+ glDeleteShader;
+ glDeleteTextures;
+ glDeleteVertexArraysOES; # introduced-mips=9 introduced-x86=9
+ glDepthFunc;
+ glDepthMask;
+ glDepthRangef;
+ glDetachShader;
+ glDisable;
+ glDisableDriverControlQCOM;
+ glDisableVertexAttribArray;
+ glDiscardFramebufferEXT; # introduced-mips=9 introduced-x86=9
+ glDrawArrays;
+ glDrawElements;
+ glEGLImageTargetRenderbufferStorageOES;
+ glEGLImageTargetTexture2DOES;
+ glEnable;
+ glEnableDriverControlQCOM;
+ glEnableVertexAttribArray;
+ glEndPerfMonitorAMD;
+ glEndTilingQCOM; # introduced-mips=9 introduced-x86=9
+ glExtGetBufferPointervQCOM; # introduced-mips=9 introduced-x86=9
+ glExtGetBuffersQCOM; # introduced-mips=9 introduced-x86=9
+ glExtGetFramebuffersQCOM; # introduced-mips=9 introduced-x86=9
+ glExtGetProgramBinarySourceQCOM; # introduced-mips=9 introduced-x86=9
+ glExtGetProgramsQCOM; # introduced-mips=9 introduced-x86=9
+ glExtGetRenderbuffersQCOM; # introduced-mips=9 introduced-x86=9
+ glExtGetShadersQCOM; # introduced-mips=9 introduced-x86=9
+ glExtGetTexLevelParameterivQCOM; # introduced-mips=9 introduced-x86=9
+ glExtGetTexSubImageQCOM; # introduced-mips=9 introduced-x86=9
+ glExtGetTexturesQCOM; # introduced-mips=9 introduced-x86=9
+ glExtIsProgramBinaryQCOM; # introduced-mips=9 introduced-x86=9
+ glExtTexObjectStateOverrideiQCOM; # introduced-mips=9 introduced-x86=9
+ glFinish;
+ glFinishFenceNV;
+ glFlush;
+ glFramebufferRenderbuffer;
+ glFramebufferTexture2D;
+ glFramebufferTexture2DMultisampleIMG; # introduced-mips=9 introduced-x86=9
+ glFramebufferTexture3DOES;
+ glFrontFace;
+ glGenBuffers;
+ glGenFencesNV;
+ glGenFramebuffers;
+ glGenPerfMonitorsAMD;
+ glGenRenderbuffers;
+ glGenTextures;
+ glGenVertexArraysOES; # introduced-mips=9 introduced-x86=9
+ glGenerateMipmap;
+ glGetActiveAttrib;
+ glGetActiveUniform;
+ glGetAttachedShaders;
+ glGetAttribLocation;
+ glGetBooleanv;
+ glGetBufferParameteriv;
+ glGetBufferPointervOES;
+ glGetDriverControlStringQCOM;
+ glGetDriverControlsQCOM;
+ glGetError;
+ glGetFenceivNV;
+ glGetFloatv;
+ glGetFramebufferAttachmentParameteriv;
+ glGetIntegerv;
+ glGetPerfMonitorCounterDataAMD;
+ glGetPerfMonitorCounterInfoAMD;
+ glGetPerfMonitorCounterStringAMD;
+ glGetPerfMonitorCountersAMD;
+ glGetPerfMonitorGroupStringAMD;
+ glGetPerfMonitorGroupsAMD;
+ glGetProgramBinaryOES;
+ glGetProgramInfoLog;
+ glGetProgramiv;
+ glGetRenderbufferParameteriv;
+ glGetShaderInfoLog;
+ glGetShaderPrecisionFormat;
+ glGetShaderSource;
+ glGetShaderiv;
+ glGetString;
+ glGetTexParameterfv;
+ glGetTexParameteriv;
+ glGetUniformLocation;
+ glGetUniformfv;
+ glGetUniformiv;
+ glGetVertexAttribPointerv;
+ glGetVertexAttribfv;
+ glGetVertexAttribiv;
+ glHint;
+ glIsBuffer;
+ glIsEnabled;
+ glIsFenceNV;
+ glIsFramebuffer;
+ glIsProgram;
+ glIsRenderbuffer;
+ glIsShader;
+ glIsTexture;
+ glIsVertexArrayOES; # introduced-mips=9 introduced-x86=9
+ glLineWidth;
+ glLinkProgram;
+ glMapBufferOES;
+ glMultiDrawArraysEXT; # introduced-mips=9 introduced-x86=9
+ glMultiDrawElementsEXT; # introduced-mips=9 introduced-x86=9
+ glPixelStorei;
+ glPolygonOffset;
+ glProgramBinaryOES;
+ glReadPixels;
+ glReleaseShaderCompiler;
+ glRenderbufferStorage;
+ glRenderbufferStorageMultisampleIMG; # introduced-mips=9 introduced-x86=9
+ glSampleCoverage;
+ glScissor;
+ glSelectPerfMonitorCountersAMD;
+ glSetFenceNV;
+ glShaderBinary;
+ glShaderSource;
+ glStartTilingQCOM; # introduced-mips=9 introduced-x86=9
+ glStencilFunc;
+ glStencilFuncSeparate;
+ glStencilMask;
+ glStencilMaskSeparate;
+ glStencilOp;
+ glStencilOpSeparate;
+ glTestFenceNV;
+ glTexImage2D;
+ glTexImage3DOES;
+ glTexParameterf;
+ glTexParameterfv;
+ glTexParameteri;
+ glTexParameteriv;
+ glTexSubImage2D;
+ glTexSubImage3DOES;
+ glUniform1f;
+ glUniform1fv;
+ glUniform1i;
+ glUniform1iv;
+ glUniform2f;
+ glUniform2fv;
+ glUniform2i;
+ glUniform2iv;
+ glUniform3f;
+ glUniform3fv;
+ glUniform3i;
+ glUniform3iv;
+ glUniform4f;
+ glUniform4fv;
+ glUniform4i;
+ glUniform4iv;
+ glUniformMatrix2fv;
+ glUniformMatrix3fv;
+ glUniformMatrix4fv;
+ glUnmapBufferOES;
+ glUseProgram;
+ glValidateProgram;
+ glVertexAttrib1f;
+ glVertexAttrib1fv;
+ glVertexAttrib2f;
+ glVertexAttrib2fv;
+ glVertexAttrib3f;
+ glVertexAttrib3fv;
+ glVertexAttrib4f;
+ glVertexAttrib4fv;
+ glVertexAttribPointer;
+ glViewport;
+ local:
+ *;
+};
diff --git a/opengl/libs/libGLESv3.map.txt b/opengl/libs/libGLESv3.map.txt
new file mode 100644
index 0000000..21f6cb6
--- /dev/null
+++ b/opengl/libs/libGLESv3.map.txt
@@ -0,0 +1,416 @@
+LIBGLESV3 {
+ global:
+ glActiveShaderProgram; # introduced=21
+ glActiveTexture;
+ glAttachShader;
+ glBeginQuery;
+ glBeginTransformFeedback;
+ glBindAttribLocation;
+ glBindBuffer;
+ glBindBufferBase;
+ glBindBufferRange;
+ glBindFramebuffer;
+ glBindImageTexture; # introduced=21
+ glBindProgramPipeline; # introduced=21
+ glBindRenderbuffer;
+ glBindSampler;
+ glBindTexture;
+ glBindTransformFeedback;
+ glBindVertexArray;
+ glBindVertexArrayOES;
+ glBindVertexBuffer; # introduced=21
+ glBlendBarrier; # introduced=24
+ glBlendBarrierKHR; # introduced=21
+ glBlendColor;
+ glBlendEquation;
+ glBlendEquationSeparate;
+ glBlendEquationSeparatei; # introduced=24
+ glBlendEquationSeparateiEXT; # introduced=21
+ glBlendEquationi; # introduced=24
+ glBlendEquationiEXT; # introduced=21
+ glBlendFunc;
+ glBlendFuncSeparate;
+ glBlendFuncSeparatei; # introduced=24
+ glBlendFuncSeparateiEXT; # introduced=21
+ glBlendFunci; # introduced=24
+ glBlendFunciEXT; # introduced=21
+ glBlitFramebuffer;
+ glBufferData;
+ glBufferSubData;
+ glCheckFramebufferStatus;
+ glClear;
+ glClearBufferfi;
+ glClearBufferfv;
+ glClearBufferiv;
+ glClearBufferuiv;
+ glClearColor;
+ glClearDepthf;
+ glClearStencil;
+ glClientWaitSync;
+ glColorMask;
+ glColorMaski; # introduced=24
+ glColorMaskiEXT; # introduced=21
+ glCompileShader;
+ glCompressedTexImage2D;
+ glCompressedTexImage3D;
+ glCompressedTexImage3DOES;
+ glCompressedTexSubImage2D;
+ glCompressedTexSubImage3D;
+ glCompressedTexSubImage3DOES;
+ glCopyBufferSubData;
+ glCopyImageSubData; # introduced=24
+ glCopyImageSubDataEXT; # introduced=21
+ glCopyTexImage2D;
+ glCopyTexSubImage2D;
+ glCopyTexSubImage3D;
+ glCopyTexSubImage3DOES;
+ glCreateProgram;
+ glCreateShader;
+ glCreateShaderProgramv; # introduced=21
+ glCullFace;
+ glDebugMessageCallback; # introduced=24
+ glDebugMessageCallbackKHR; # introduced=21
+ glDebugMessageControl; # introduced=24
+ glDebugMessageControlKHR; # introduced=21
+ glDebugMessageInsert; # introduced=24
+ glDebugMessageInsertKHR; # introduced=21
+ glDeleteBuffers;
+ glDeleteFramebuffers;
+ glDeleteProgram;
+ glDeleteProgramPipelines; # introduced=21
+ glDeleteQueries;
+ glDeleteRenderbuffers;
+ glDeleteSamplers;
+ glDeleteShader;
+ glDeleteSync;
+ glDeleteTextures;
+ glDeleteTransformFeedbacks;
+ glDeleteVertexArrays;
+ glDeleteVertexArraysOES;
+ glDepthFunc;
+ glDepthMask;
+ glDepthRangef;
+ glDetachShader;
+ glDisable;
+ glDisableVertexAttribArray;
+ glDisablei; # introduced=24
+ glDisableiEXT; # introduced=21
+ glDispatchCompute; # introduced=21
+ glDispatchComputeIndirect; # introduced=21
+ glDrawArrays;
+ glDrawArraysIndirect; # introduced=21
+ glDrawArraysInstanced;
+ glDrawBuffers;
+ glDrawElements;
+ glDrawElementsBaseVertex; # introduced=24
+ glDrawElementsIndirect; # introduced=21
+ glDrawElementsInstanced;
+ glDrawElementsInstancedBaseVertex; # introduced=24
+ glDrawRangeElements;
+ glDrawRangeElementsBaseVertex; # introduced=24
+ glEGLImageTargetRenderbufferStorageOES;
+ glEGLImageTargetTexture2DOES;
+ glEnable;
+ glEnableVertexAttribArray;
+ glEnablei; # introduced=24
+ glEnableiEXT; # introduced=21
+ glEndQuery;
+ glEndTransformFeedback;
+ glFenceSync;
+ glFinish;
+ glFlush;
+ glFlushMappedBufferRange;
+ glFramebufferParameteri; # introduced=21
+ glFramebufferRenderbuffer;
+ glFramebufferTexture; # introduced=24
+ glFramebufferTexture2D;
+ glFramebufferTexture3DOES;
+ glFramebufferTextureEXT; # introduced=21
+ glFramebufferTextureLayer;
+ glFrontFace;
+ glGenBuffers;
+ glGenFramebuffers;
+ glGenProgramPipelines; # introduced=21
+ glGenQueries;
+ glGenRenderbuffers;
+ glGenSamplers;
+ glGenTextures;
+ glGenTransformFeedbacks;
+ glGenVertexArrays;
+ glGenVertexArraysOES;
+ glGenerateMipmap;
+ glGetActiveAttrib;
+ glGetActiveUniform;
+ glGetActiveUniformBlockName;
+ glGetActiveUniformBlockiv;
+ glGetActiveUniformsiv;
+ glGetAttachedShaders;
+ glGetAttribLocation;
+ glGetBooleani_v; # introduced=21
+ glGetBooleanv;
+ glGetBufferParameteri64v;
+ glGetBufferParameteriv;
+ glGetBufferPointerv;
+ glGetBufferPointervOES;
+ glGetDebugMessageLog; # introduced=24
+ glGetDebugMessageLogKHR; # introduced=21
+ glGetError;
+ glGetFloatv;
+ glGetFragDataLocation;
+ glGetFramebufferAttachmentParameteriv;
+ glGetFramebufferParameteriv; # introduced=21
+ glGetGraphicsResetStatus; # introduced=24
+ glGetInteger64i_v;
+ glGetInteger64v;
+ glGetIntegeri_v;
+ glGetIntegerv;
+ glGetInternalformativ;
+ glGetMultisamplefv; # introduced=21
+ glGetObjectLabel; # introduced=24
+ glGetObjectLabelKHR; # introduced=21
+ glGetObjectPtrLabel; # introduced=24
+ glGetObjectPtrLabelKHR; # introduced=21
+ glGetPointerv; # introduced=24
+ glGetPointervKHR; # introduced=21
+ glGetProgramBinary;
+ glGetProgramBinaryOES;
+ glGetProgramInfoLog;
+ glGetProgramInterfaceiv; # introduced=21
+ glGetProgramPipelineInfoLog; # introduced=21
+ glGetProgramPipelineiv; # introduced=21
+ glGetProgramResourceIndex; # introduced=21
+ glGetProgramResourceLocation; # introduced=21
+ glGetProgramResourceName; # introduced=21
+ glGetProgramResourceiv; # introduced=21
+ glGetProgramiv;
+ glGetQueryObjectuiv;
+ glGetQueryiv;
+ glGetRenderbufferParameteriv;
+ glGetSamplerParameterIiv; # introduced=24
+ glGetSamplerParameterIivEXT; # introduced=21
+ glGetSamplerParameterIuiv; # introduced=24
+ glGetSamplerParameterIuivEXT; # introduced=21
+ glGetSamplerParameterfv;
+ glGetSamplerParameteriv;
+ glGetShaderInfoLog;
+ glGetShaderPrecisionFormat;
+ glGetShaderSource;
+ glGetShaderiv;
+ glGetString;
+ glGetStringi;
+ glGetSynciv;
+ glGetTexLevelParameterfv; # introduced=21
+ glGetTexLevelParameteriv; # introduced=21
+ glGetTexParameterIiv; # introduced=24
+ glGetTexParameterIivEXT; # introduced=21
+ glGetTexParameterIuiv; # introduced=24
+ glGetTexParameterIuivEXT; # introduced=21
+ glGetTexParameterfv;
+ glGetTexParameteriv;
+ glGetTransformFeedbackVarying;
+ glGetUniformBlockIndex;
+ glGetUniformIndices;
+ glGetUniformLocation;
+ glGetUniformfv;
+ glGetUniformiv;
+ glGetUniformuiv;
+ glGetVertexAttribIiv;
+ glGetVertexAttribIuiv;
+ glGetVertexAttribPointerv;
+ glGetVertexAttribfv;
+ glGetVertexAttribiv;
+ glGetnUniformfv; # introduced=24
+ glGetnUniformiv; # introduced=24
+ glGetnUniformuiv; # introduced=24
+ glHint;
+ glInvalidateFramebuffer;
+ glInvalidateSubFramebuffer;
+ glIsBuffer;
+ glIsEnabled;
+ glIsEnabledi; # introduced=24
+ glIsEnablediEXT; # introduced=21
+ glIsFramebuffer;
+ glIsProgram;
+ glIsProgramPipeline; # introduced=21
+ glIsQuery;
+ glIsRenderbuffer;
+ glIsSampler;
+ glIsShader;
+ glIsSync;
+ glIsTexture;
+ glIsTransformFeedback;
+ glIsVertexArray;
+ glIsVertexArrayOES;
+ glLineWidth;
+ glLinkProgram;
+ glMapBufferOES;
+ glMapBufferRange;
+ glMemoryBarrier; # introduced=21
+ glMemoryBarrierByRegion; # introduced=21
+ glMinSampleShading; # introduced=24
+ glMinSampleShadingOES; # introduced=21
+ glObjectLabel; # introduced=24
+ glObjectLabelKHR; # introduced=21
+ glObjectPtrLabel; # introduced=24
+ glObjectPtrLabelKHR; # introduced=21
+ glPatchParameteri; # introduced=24
+ glPatchParameteriEXT; # introduced=21
+ glPauseTransformFeedback;
+ glPixelStorei;
+ glPolygonOffset;
+ glPopDebugGroup; # introduced=24
+ glPopDebugGroupKHR; # introduced=21
+ glPrimitiveBoundingBox; # introduced=24
+ glPrimitiveBoundingBoxEXT; # introduced=21
+ glProgramBinary;
+ glProgramBinaryOES;
+ glProgramParameteri;
+ glProgramUniform1f; # introduced=21
+ glProgramUniform1fv; # introduced=21
+ glProgramUniform1i; # introduced=21
+ glProgramUniform1iv; # introduced=21
+ glProgramUniform1ui; # introduced=21
+ glProgramUniform1uiv; # introduced=21
+ glProgramUniform2f; # introduced=21
+ glProgramUniform2fv; # introduced=21
+ glProgramUniform2i; # introduced=21
+ glProgramUniform2iv; # introduced=21
+ glProgramUniform2ui; # introduced=21
+ glProgramUniform2uiv; # introduced=21
+ glProgramUniform3f; # introduced=21
+ glProgramUniform3fv; # introduced=21
+ glProgramUniform3i; # introduced=21
+ glProgramUniform3iv; # introduced=21
+ glProgramUniform3ui; # introduced=21
+ glProgramUniform3uiv; # introduced=21
+ glProgramUniform4f; # introduced=21
+ glProgramUniform4fv; # introduced=21
+ glProgramUniform4i; # introduced=21
+ glProgramUniform4iv; # introduced=21
+ glProgramUniform4ui; # introduced=21
+ glProgramUniform4uiv; # introduced=21
+ glProgramUniformMatrix2fv; # introduced=21
+ glProgramUniformMatrix2x3fv; # introduced=21
+ glProgramUniformMatrix2x4fv; # introduced=21
+ glProgramUniformMatrix3fv; # introduced=21
+ glProgramUniformMatrix3x2fv; # introduced=21
+ glProgramUniformMatrix3x4fv; # introduced=21
+ glProgramUniformMatrix4fv; # introduced=21
+ glProgramUniformMatrix4x2fv; # introduced=21
+ glProgramUniformMatrix4x3fv; # introduced=21
+ glPushDebugGroup; # introduced=24
+ glPushDebugGroupKHR; # introduced=21
+ glReadBuffer;
+ glReadPixels;
+ glReadnPixels; # introduced=24
+ glReleaseShaderCompiler;
+ glRenderbufferStorage;
+ glRenderbufferStorageMultisample;
+ glResumeTransformFeedback;
+ glSampleCoverage;
+ glSampleMaski; # introduced=21
+ glSamplerParameterIiv; # introduced=24
+ glSamplerParameterIivEXT; # introduced=21
+ glSamplerParameterIuiv; # introduced=24
+ glSamplerParameterIuivEXT; # introduced=21
+ glSamplerParameterf;
+ glSamplerParameterfv;
+ glSamplerParameteri;
+ glSamplerParameteriv;
+ glScissor;
+ glShaderBinary;
+ glShaderSource;
+ glStencilFunc;
+ glStencilFuncSeparate;
+ glStencilMask;
+ glStencilMaskSeparate;
+ glStencilOp;
+ glStencilOpSeparate;
+ glTexBuffer; # introduced=24
+ glTexBufferEXT; # introduced=21
+ glTexBufferRange; # introduced=24
+ glTexBufferRangeEXT; # introduced=21
+ glTexImage2D;
+ glTexImage3D;
+ glTexImage3DOES;
+ glTexParameterIiv; # introduced=24
+ glTexParameterIivEXT; # introduced=21
+ glTexParameterIuiv; # introduced=24
+ glTexParameterIuivEXT; # introduced=21
+ glTexParameterf;
+ glTexParameterfv;
+ glTexParameteri;
+ glTexParameteriv;
+ glTexStorage2D;
+ glTexStorage2DMultisample; # introduced=21
+ glTexStorage3D;
+ glTexStorage3DMultisample; # introduced=24
+ glTexStorage3DMultisampleOES; # introduced=21
+ glTexSubImage2D;
+ glTexSubImage3D;
+ glTexSubImage3DOES;
+ glTransformFeedbackVaryings;
+ glUniform1f;
+ glUniform1fv;
+ glUniform1i;
+ glUniform1iv;
+ glUniform1ui;
+ glUniform1uiv;
+ glUniform2f;
+ glUniform2fv;
+ glUniform2i;
+ glUniform2iv;
+ glUniform2ui;
+ glUniform2uiv;
+ glUniform3f;
+ glUniform3fv;
+ glUniform3i;
+ glUniform3iv;
+ glUniform3ui;
+ glUniform3uiv;
+ glUniform4f;
+ glUniform4fv;
+ glUniform4i;
+ glUniform4iv;
+ glUniform4ui;
+ glUniform4uiv;
+ glUniformBlockBinding;
+ glUniformMatrix2fv;
+ glUniformMatrix2x3fv;
+ glUniformMatrix2x4fv;
+ glUniformMatrix3fv;
+ glUniformMatrix3x2fv;
+ glUniformMatrix3x4fv;
+ glUniformMatrix4fv;
+ glUniformMatrix4x2fv;
+ glUniformMatrix4x3fv;
+ glUnmapBuffer;
+ glUnmapBufferOES;
+ glUseProgram;
+ glUseProgramStages; # introduced=21
+ glValidateProgram;
+ glValidateProgramPipeline; # introduced=21
+ glVertexAttrib1f;
+ glVertexAttrib1fv;
+ glVertexAttrib2f;
+ glVertexAttrib2fv;
+ glVertexAttrib3f;
+ glVertexAttrib3fv;
+ glVertexAttrib4f;
+ glVertexAttrib4fv;
+ glVertexAttribBinding; # introduced=21
+ glVertexAttribDivisor;
+ glVertexAttribFormat; # introduced=21
+ glVertexAttribI4i;
+ glVertexAttribI4iv;
+ glVertexAttribI4ui;
+ glVertexAttribI4uiv;
+ glVertexAttribIFormat; # introduced=21
+ glVertexAttribIPointer;
+ glVertexAttribPointer;
+ glVertexBindingDivisor; # introduced=21
+ glViewport;
+ glWaitSync;
+ local:
+ *;
+};
diff --git a/opengl/tests/angeles/demo.c b/opengl/tests/angeles/demo.c
index 802f398..39d871e 100644
--- a/opengl/tests/angeles/demo.c
+++ b/opengl/tests/angeles/demo.c
@@ -666,7 +666,7 @@
y[2] /= mag;
}
-#define M(row,col) m[col*4+row]
+#define M(row,col) m[(col)*4+(row)]
M(0, 0) = x[0];
M(0, 1) = x[1];
M(0, 2) = x[2];
diff --git a/opengl/tests/hwc/hwcColorEquiv.cpp b/opengl/tests/hwc/hwcColorEquiv.cpp
index f1361b8..a9bbcb6 100644
--- a/opengl/tests/hwc/hwcColorEquiv.cpp
+++ b/opengl/tests/hwc/hwcColorEquiv.cpp
@@ -116,7 +116,7 @@
#define CMD_START_FRAMEWORK "start 2>&1"
// Macros
-#define NUMA(a) (sizeof(a) / sizeof(a [0])) // Num elements in an array
+#define NUMA(a) (sizeof(a) / sizeof((a)[0])) // Num elements in an array
#define MEMCLR(addr, size) do { \
memset((addr), 0, (size)); \
} while (0)
diff --git a/opengl/tests/hwc/hwcCommit.cpp b/opengl/tests/hwc/hwcCommit.cpp
index 6b287e9..3686dab 100644
--- a/opengl/tests/hwc/hwcCommit.cpp
+++ b/opengl/tests/hwc/hwcCommit.cpp
@@ -156,12 +156,12 @@
#define CMD_START_FRAMEWORK "start 2>&1"
// Macros
-#define NUMA(a) (sizeof(a) / sizeof(a [0])) // Num elements in an array
+#define NUMA(a) (sizeof(a) / sizeof((a)[0])) // Num elements in an array
// Local types
class Rectangle {
public:
- Rectangle(uint32_t graphicFormat = defaultFormat,
+ explicit Rectangle(uint32_t graphicFormat = defaultFormat,
HwcTestDim dfDim = HwcTestDim(1, 1),
HwcTestDim sDim = HwcTestDim(1, 1));
void setSourceDim(HwcTestDim dim);
diff --git a/opengl/tests/hwc/hwcRects.cpp b/opengl/tests/hwc/hwcRects.cpp
index 2e2b204..69e56ff 100644
--- a/opengl/tests/hwc/hwcRects.cpp
+++ b/opengl/tests/hwc/hwcRects.cpp
@@ -137,7 +137,7 @@
#define CMD_START_FRAMEWORK "start 2>&1"
// Macros
-#define NUMA(a) (sizeof(a) / sizeof(a [0])) // Num elements in an array
+#define NUMA(a) (sizeof(a) / sizeof((a)[0])) // Num elements in an array
// Local types
class Rectangle {
diff --git a/opengl/tests/hwc/hwcStress.cpp b/opengl/tests/hwc/hwcStress.cpp
index 60c29ef..1469f7c 100644
--- a/opengl/tests/hwc/hwcStress.cpp
+++ b/opengl/tests/hwc/hwcStress.cpp
@@ -162,7 +162,7 @@
#define CMD_STOP_FRAMEWORK "stop 2>&1"
#define CMD_START_FRAMEWORK "start 2>&1"
-#define NUMA(a) (sizeof(a) / sizeof(a [0]))
+#define NUMA(a) (sizeof(a) / sizeof((a)[0]))
#define MEMCLR(addr, size) do { \
memset((addr), 0, (size)); \
} while (0)
diff --git a/opengl/tests/hwc/hwcTestLib.h b/opengl/tests/hwc/hwcTestLib.h
index a942c10..922fc19 100644
--- a/opengl/tests/hwc/hwcTestLib.h
+++ b/opengl/tests/hwc/hwcTestLib.h
@@ -71,7 +71,7 @@
class ColorRGB {
public:
ColorRGB(): _r(0.0), _g(0.0), _b(0.0) {};
- ColorRGB(float f): _r(f), _g(f), _b(f) {}; // Gray
+ ColorRGB(float f): _r(f), _g(f), _b(f) {}; // Gray, NOLINT(implicit)
ColorRGB(float r, float g, float b): _r(r), _g(g), _b(b) {};
float r(void) const { return _r; }
float g(void) const { return _g; }
diff --git a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
index f5506ba..026cb37 100644
--- a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
+++ b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
@@ -131,6 +131,7 @@
pointer = _env->CallStaticLongMethod(nioAccessClass,
getBasePointerID, buffer);
if (pointer != 0L) {
+ *offset = 0;
*array = NULL;
return reinterpret_cast<void *>(pointer);
}
@@ -138,6 +139,7 @@
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
getBaseArrayID, buffer);
if (*array == NULL) {
+ *offset = 0;
return (void*) NULL;
}
*offset = _env->CallStaticIntMethod(nioAccessClass,
diff --git a/services/batteryservice/Android.bp b/services/batteryservice/Android.bp
new file mode 100644
index 0000000..79db871
--- /dev/null
+++ b/services/batteryservice/Android.bp
@@ -0,0 +1,22 @@
+cc_library_static {
+ name: "libbatteryservice",
+
+ srcs: [
+ "BatteryProperties.cpp",
+ "BatteryProperty.cpp",
+ "IBatteryPropertiesListener.cpp",
+ "IBatteryPropertiesRegistrar.cpp",
+ ],
+
+ static_libs: [
+ "libutils",
+ "libbinder",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+}
diff --git a/services/batteryservice/Android.mk b/services/batteryservice/Android.mk
deleted file mode 100644
index e4097d7..0000000
--- a/services/batteryservice/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- BatteryProperties.cpp \
- BatteryProperty.cpp \
- IBatteryPropertiesListener.cpp \
- IBatteryPropertiesRegistrar.cpp
-
-LOCAL_STATIC_LIBRARIES := \
- libutils \
- libbinder
-
-LOCAL_MODULE:= libbatteryservice
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/services/batteryservice/IBatteryPropertiesListener.cpp b/services/batteryservice/IBatteryPropertiesListener.cpp
index 8aff26c..7555f4b 100644
--- a/services/batteryservice/IBatteryPropertiesListener.cpp
+++ b/services/batteryservice/IBatteryPropertiesListener.cpp
@@ -24,7 +24,7 @@
class BpBatteryPropertiesListener : public BpInterface<IBatteryPropertiesListener>
{
public:
- BpBatteryPropertiesListener(const sp<IBinder>& impl)
+ explicit BpBatteryPropertiesListener(const sp<IBinder>& impl)
: BpInterface<IBatteryPropertiesListener>(impl)
{
}
diff --git a/services/batteryservice/IBatteryPropertiesRegistrar.cpp b/services/batteryservice/IBatteryPropertiesRegistrar.cpp
index 46934e0..01a65ae 100644
--- a/services/batteryservice/IBatteryPropertiesRegistrar.cpp
+++ b/services/batteryservice/IBatteryPropertiesRegistrar.cpp
@@ -28,7 +28,7 @@
class BpBatteryPropertiesRegistrar : public BpInterface<IBatteryPropertiesRegistrar> {
public:
- BpBatteryPropertiesRegistrar(const sp<IBinder>& impl)
+ explicit BpBatteryPropertiesRegistrar(const sp<IBinder>& impl)
: BpInterface<IBatteryPropertiesRegistrar>(impl) {}
void registerListener(const sp<IBatteryPropertiesListener>& listener) {
@@ -60,6 +60,12 @@
val->readFromParcel(&reply);
return ret;
}
+
+ void scheduleUpdate() {
+ Parcel data;
+ data.writeInterfaceToken(IBatteryPropertiesRegistrar::getInterfaceDescriptor());
+ remote()->transact(SCHEDULE_UPDATE, data, NULL);
+ }
};
IMPLEMENT_META_INTERFACE(BatteryPropertiesRegistrar, "android.os.IBatteryPropertiesRegistrar");
@@ -97,6 +103,12 @@
val.writeToParcel(reply);
return OK;
}
+
+ case SCHEDULE_UPDATE: {
+ CHECK_INTERFACE(IBatteryPropertiesRegistrar, data, reply);
+ scheduleUpdate();
+ return OK;
+ }
}
return BBinder::onTransact(code, data, reply, flags);
};
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
new file mode 100644
index 0000000..4fd98e2
--- /dev/null
+++ b/services/inputflinger/Android.bp
@@ -0,0 +1,51 @@
+// Copyright (C) 2013 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+ name: "libinputflinger",
+
+ srcs: [
+ "EventHub.cpp",
+ "InputApplication.cpp",
+ "InputDispatcher.cpp",
+ "InputListener.cpp",
+ "InputManager.cpp",
+ "InputReader.cpp",
+ "InputWindow.cpp",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "libcrypto",
+ "libcutils",
+ "libinput",
+ "liblog",
+ "libutils",
+ "libui",
+ "libhardware_legacy",
+ ],
+
+ cflags: [
+ "-Wno-unused-parameter",
+ // TODO: Move inputflinger to its own process and mark it hidden
+ //-fvisibility=hidden
+ ],
+
+ export_include_dirs: ["."],
+}
+
+subdirs = [
+ "host",
+ "tests",
+]
diff --git a/services/inputflinger/Android.mk b/services/inputflinger/Android.mk
deleted file mode 100644
index ed867d8..0000000
--- a/services/inputflinger/Android.mk
+++ /dev/null
@@ -1,49 +0,0 @@
-# Copyright (C) 2013 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- EventHub.cpp \
- InputApplication.cpp \
- InputDispatcher.cpp \
- InputListener.cpp \
- InputManager.cpp \
- InputReader.cpp \
- InputWindow.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libbinder \
- libcrypto \
- libcutils \
- libinput \
- liblog \
- libutils \
- libui \
- libhardware_legacy
-
-
-# TODO: Move inputflinger to its own process and mark it hidden
-#LOCAL_CFLAGS += -fvisibility=hidden
-
-LOCAL_CFLAGS += -Wno-unused-parameter
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-
-LOCAL_MODULE := libinputflinger
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index 2a53dec..d2f8995 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -55,10 +55,10 @@
* operation with a byte that only has the relevant bit set.
* eg. to check for the 12th bit, we do (array[1] & 1<<4)
*/
-#define test_bit(bit, array) (array[bit/8] & (1<<(bit%8)))
+#define test_bit(bit, array) ((array)[(bit)/8] & (1<<((bit)%8)))
/* this macro computes the number of bytes needed to represent a bit array of the specified size */
-#define sizeof_bit_array(bits) ((bits + 7) / 8)
+#define sizeof_bit_array(bits) (((bits) + 7) / 8)
#define INDENT " "
#define INDENT2 " "
diff --git a/services/inputflinger/InputApplication.cpp b/services/inputflinger/InputApplication.cpp
index a99e637..9e90631 100644
--- a/services/inputflinger/InputApplication.cpp
+++ b/services/inputflinger/InputApplication.cpp
@@ -18,7 +18,7 @@
#include "InputApplication.h"
-#include <cutils/log.h>
+#include <android/log.h>
namespace android {
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 3f69d49..89475e9 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -45,16 +45,16 @@
#include "InputDispatcher.h"
-#include <utils/Trace.h>
-#include <cutils/log.h>
-#include <powermanager/PowerManager.h>
-#include <ui/Region.h>
-
-#include <stddef.h>
-#include <unistd.h>
#include <errno.h>
#include <limits.h>
+#include <stddef.h>
#include <time.h>
+#include <unistd.h>
+
+#include <log/log.h>
+#include <utils/Trace.h>
+#include <powermanager/PowerManager.h>
+#include <ui/Region.h>
#define INDENT " "
#define INDENT2 " "
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 1c054f5..90c69ce 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -455,7 +455,7 @@
};
struct ConfigurationChangedEntry : EventEntry {
- ConfigurationChangedEntry(nsecs_t eventTime);
+ explicit ConfigurationChangedEntry(nsecs_t eventTime);
virtual void appendDescription(String8& msg) const;
protected:
@@ -591,7 +591,7 @@
class Connection;
struct CommandEntry : Link<CommandEntry> {
- CommandEntry(Command command);
+ explicit CommandEntry(Command command);
~CommandEntry();
Command command;
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index dded47d..2ee222b 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -20,7 +20,7 @@
#include "InputListener.h"
-#include <cutils/log.h>
+#include <android/log.h>
namespace android {
diff --git a/services/inputflinger/InputListener.h b/services/inputflinger/InputListener.h
index 1ec09ce..ea3dd1c 100644
--- a/services/inputflinger/InputListener.h
+++ b/services/inputflinger/InputListener.h
@@ -40,7 +40,7 @@
inline NotifyConfigurationChangedArgs() { }
- NotifyConfigurationChangedArgs(nsecs_t eventTime);
+ explicit NotifyConfigurationChangedArgs(nsecs_t eventTime);
NotifyConfigurationChangedArgs(const NotifyConfigurationChangedArgs& other);
@@ -178,7 +178,7 @@
virtual ~QueuedInputListener();
public:
- QueuedInputListener(const sp<InputListenerInterface>& innerListener);
+ explicit QueuedInputListener(const sp<InputListenerInterface>& innerListener);
virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args);
virtual void notifyKey(const NotifyKeyArgs* args);
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 6a6547b..519faa6 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -20,7 +20,7 @@
#include "InputManager.h"
-#include <cutils/log.h>
+#include <log/log.h>
namespace android {
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index b9be675..c1e6365 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -44,17 +44,18 @@
#include "InputReader.h"
-#include <cutils/log.h>
-#include <input/Keyboard.h>
-#include <input/VirtualKeyMap.h>
-
+#include <errno.h>
#include <inttypes.h>
+#include <limits.h>
+#include <math.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
-#include <errno.h>
-#include <limits.h>
-#include <math.h>
+
+#include <log/log.h>
+
+#include <input/Keyboard.h>
+#include <input/VirtualKeyMap.h>
#define INDENT " "
#define INDENT2 " "
@@ -6652,6 +6653,7 @@
size_t inCount = mMultiTouchMotionAccumulator.getSlotCount();
size_t outCount = 0;
BitSet32 newPointerIdBits;
+ mHavePointerIds = true;
for (size_t inIndex = 0; inIndex < inCount; inIndex++) {
const MultiTouchMotionAccumulator::Slot* inSlot =
@@ -6696,33 +6698,33 @@
outPointer.isHovering = isHovering;
// Assign pointer id using tracking id if available.
- mHavePointerIds = true;
- int32_t trackingId = inSlot->getTrackingId();
- int32_t id = -1;
- if (trackingId >= 0) {
- for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) {
- uint32_t n = idBits.clearFirstMarkedBit();
- if (mPointerTrackingIdMap[n] == trackingId) {
- id = n;
+ if (mHavePointerIds) {
+ int32_t trackingId = inSlot->getTrackingId();
+ int32_t id = -1;
+ if (trackingId >= 0) {
+ for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) {
+ uint32_t n = idBits.clearFirstMarkedBit();
+ if (mPointerTrackingIdMap[n] == trackingId) {
+ id = n;
+ }
+ }
+
+ if (id < 0 && !mPointerIdBits.isFull()) {
+ id = mPointerIdBits.markFirstUnmarkedBit();
+ mPointerTrackingIdMap[id] = trackingId;
}
}
-
- if (id < 0 && !mPointerIdBits.isFull()) {
- id = mPointerIdBits.markFirstUnmarkedBit();
- mPointerTrackingIdMap[id] = trackingId;
+ if (id < 0) {
+ mHavePointerIds = false;
+ outState->rawPointerData.clearIdBits();
+ newPointerIdBits.clear();
+ } else {
+ outPointer.id = id;
+ outState->rawPointerData.idToIndex[id] = outCount;
+ outState->rawPointerData.markIdBit(id, isHovering);
+ newPointerIdBits.markBit(id);
}
}
- if (id < 0) {
- mHavePointerIds = false;
- outState->rawPointerData.clearIdBits();
- newPointerIdBits.clear();
- } else {
- outPointer.id = id;
- outState->rawPointerData.idToIndex[id] = outCount;
- outState->rawPointerData.markIdBit(id, isHovering);
- newPointerIdBits.markBit(id);
- }
-
outCount += 1;
}
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index 076f3d6..8e2fe95 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -484,7 +484,7 @@
InputReader* mReader;
public:
- ContextImpl(InputReader* reader);
+ explicit ContextImpl(InputReader* reader);
virtual void updateGlobalMetaState();
virtual int32_t getGlobalMetaState();
@@ -568,7 +568,7 @@
/* Reads raw events from the event hub and processes them, endlessly. */
class InputReaderThread : public Thread {
public:
- InputReaderThread(const sp<InputReaderInterface>& reader);
+ explicit InputReaderThread(const sp<InputReaderInterface>& reader);
virtual ~InputReaderThread();
private:
@@ -1007,7 +1007,7 @@
*/
class InputMapper {
public:
- InputMapper(InputDevice* device);
+ explicit InputMapper(InputDevice* device);
virtual ~InputMapper();
inline InputDevice* getDevice() { return mDevice; }
@@ -1058,7 +1058,7 @@
class SwitchInputMapper : public InputMapper {
public:
- SwitchInputMapper(InputDevice* device);
+ explicit SwitchInputMapper(InputDevice* device);
virtual ~SwitchInputMapper();
virtual uint32_t getSources();
@@ -1078,7 +1078,7 @@
class VibratorInputMapper : public InputMapper {
public:
- VibratorInputMapper(InputDevice* device);
+ explicit VibratorInputMapper(InputDevice* device);
virtual ~VibratorInputMapper();
virtual uint32_t getSources();
@@ -1178,7 +1178,7 @@
class CursorInputMapper : public InputMapper {
public:
- CursorInputMapper(InputDevice* device);
+ explicit CursorInputMapper(InputDevice* device);
virtual ~CursorInputMapper();
virtual uint32_t getSources();
@@ -1243,7 +1243,7 @@
class RotaryEncoderInputMapper : public InputMapper {
public:
- RotaryEncoderInputMapper(InputDevice* device);
+ explicit RotaryEncoderInputMapper(InputDevice* device);
virtual ~RotaryEncoderInputMapper();
virtual uint32_t getSources();
@@ -1264,7 +1264,7 @@
class TouchInputMapper : public InputMapper {
public:
- TouchInputMapper(InputDevice* device);
+ explicit TouchInputMapper(InputDevice* device);
virtual ~TouchInputMapper();
virtual uint32_t getSources();
@@ -1887,7 +1887,7 @@
class SingleTouchInputMapper : public TouchInputMapper {
public:
- SingleTouchInputMapper(InputDevice* device);
+ explicit SingleTouchInputMapper(InputDevice* device);
virtual ~SingleTouchInputMapper();
virtual void reset(nsecs_t when);
@@ -1905,7 +1905,7 @@
class MultiTouchInputMapper : public TouchInputMapper {
public:
- MultiTouchInputMapper(InputDevice* device);
+ explicit MultiTouchInputMapper(InputDevice* device);
virtual ~MultiTouchInputMapper();
virtual void reset(nsecs_t when);
@@ -1926,7 +1926,7 @@
class ExternalStylusInputMapper : public InputMapper {
public:
- ExternalStylusInputMapper(InputDevice* device);
+ explicit ExternalStylusInputMapper(InputDevice* device);
virtual ~ExternalStylusInputMapper() = default;
virtual uint32_t getSources();
@@ -1948,7 +1948,7 @@
class JoystickInputMapper : public InputMapper {
public:
- JoystickInputMapper(InputDevice* device);
+ explicit JoystickInputMapper(InputDevice* device);
virtual ~JoystickInputMapper();
virtual uint32_t getSources();
diff --git a/services/inputflinger/InputWindow.cpp b/services/inputflinger/InputWindow.cpp
index d7b514b..5e82d75 100644
--- a/services/inputflinger/InputWindow.cpp
+++ b/services/inputflinger/InputWindow.cpp
@@ -19,7 +19,7 @@
#include "InputWindow.h"
-#include <cutils/log.h>
+#include <log/log.h>
#include <ui/Rect.h>
#include <ui/Region.h>
diff --git a/services/inputflinger/InputWindow.h b/services/inputflinger/InputWindow.h
index e243637..feca6cf 100644
--- a/services/inputflinger/InputWindow.h
+++ b/services/inputflinger/InputWindow.h
@@ -196,7 +196,7 @@
void releaseInfo();
protected:
- InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle);
+ explicit InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle);
virtual ~InputWindowHandle();
InputWindowInfo* mInfo;
diff --git a/services/inputflinger/host/Android.bp b/services/inputflinger/host/Android.bp
new file mode 100644
index 0000000..b8e9bce
--- /dev/null
+++ b/services/inputflinger/host/Android.bp
@@ -0,0 +1,57 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+ name: "libinputflingerhost",
+
+ srcs: [
+ "InputFlinger.cpp",
+ "InputDriver.cpp",
+ "InputHost.cpp",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "libcrypto",
+ "libcutils",
+ "libinput",
+ "liblog",
+ "libutils",
+ "libhardware",
+ ],
+
+ cflags: [
+ "-Wno-unused-parameter",
+ // TODO: Move inputflinger to its own process and mark it hidden
+ //-fvisibility=hidden
+ ],
+
+ export_include_dirs: ["."],
+}
+
+//#######################################################################
+// build input flinger executable
+cc_binary {
+ name: "inputflinger",
+
+ srcs: ["main.cpp"],
+
+ shared_libs: [
+ "libbinder",
+ "libinputflingerhost",
+ "libutils",
+ ],
+
+ init_rc: ["inputflinger.rc"],
+}
diff --git a/services/inputflinger/host/Android.mk b/services/inputflinger/host/Android.mk
deleted file mode 100644
index 0a7fc27..0000000
--- a/services/inputflinger/host/Android.mk
+++ /dev/null
@@ -1,63 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_CLANG := true
-
-LOCAL_SRC_FILES:= \
- InputFlinger.cpp \
- InputDriver.cpp \
- InputHost.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libbinder \
- libcrypto \
- libcutils \
- libinput \
- liblog \
- libutils \
- libhardware
-
-
-# TODO: Move inputflinger to its own process and mark it hidden
-#LOCAL_CFLAGS += -fvisibility=hidden
-
-LOCAL_CFLAGS += -Wno-unused-parameter
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-
-LOCAL_MODULE := libinputflingerhost
-
-include $(BUILD_SHARED_LIBRARY)
-
-########################################################################
-# build input flinger executable
-include $(CLEAR_VARS)
-
-LOCAL_CLANG := true
-
-LOCAL_SRC_FILES:= \
- main.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libbinder \
- libinputflingerhost \
- libutils
-
-LOCAL_MODULE := inputflinger
-LOCAL_INIT_RC := inputflinger.rc
-
-include $(BUILD_EXECUTABLE)
diff --git a/services/inputflinger/host/InputDriver.h b/services/inputflinger/host/InputDriver.h
index 8d5a31e..e56673b 100644
--- a/services/inputflinger/host/InputDriver.h
+++ b/services/inputflinger/host/InputDriver.h
@@ -82,7 +82,7 @@
class InputDriver : public InputDriverInterface {
public:
- InputDriver(const char* name);
+ explicit InputDriver(const char* name);
virtual ~InputDriver() = default;
virtual void init() override;
diff --git a/services/inputflinger/host/InputFlinger.cpp b/services/inputflinger/host/InputFlinger.cpp
index 859c3b8..f1d3726 100644
--- a/services/inputflinger/host/InputFlinger.cpp
+++ b/services/inputflinger/host/InputFlinger.cpp
@@ -16,21 +16,19 @@
#define LOG_TAG "InputFlinger"
-
#include <stdint.h>
-#include <unistd.h>
-
#include <sys/types.h>
-
-#include "InputFlinger.h"
-#include "InputDriver.h"
+#include <unistd.h>
#include <binder/IPCThreadState.h>
#include <binder/PermissionCache.h>
#include <hardware/input.h>
-#include <cutils/log.h>
+#include <log/log.h>
#include <private/android_filesystem_config.h>
+#include "InputFlinger.h"
+#include "InputDriver.h"
+
namespace android {
const String16 sAccessInputFlingerPermission("android.permission.ACCESS_INPUT_FLINGER");
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
new file mode 100644
index 0000000..29d93f0
--- /dev/null
+++ b/services/inputflinger/tests/Android.bp
@@ -0,0 +1,23 @@
+// Build the unit tests.
+
+cc_test {
+ name: "inputflinger_tests",
+ srcs: [
+ "InputReader_test.cpp",
+ "InputDispatcher_test.cpp",
+ ],
+ test_per_src: true,
+ cflags: ["-Wno-unused-parameter"],
+ shared_libs = [
+ "libcutils",
+ "liblog",
+ "libutils",
+ "libhardware",
+ "libhardware_legacy",
+ "libui",
+ "libskia",
+ "libinput",
+ "libinputflinger",
+ "libinputservice",
+ ],
+}
diff --git a/services/inputflinger/tests/Android.mk b/services/inputflinger/tests/Android.mk
deleted file mode 100644
index 4c43392..0000000
--- a/services/inputflinger/tests/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-# Build the unit tests.
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# Build the unit tests.
-test_src_files := \
- InputReader_test.cpp \
- InputDispatcher_test.cpp
-
-shared_libraries := \
- libcutils \
- liblog \
- libutils \
- libhardware \
- libhardware_legacy \
- libui \
- libskia \
- libinput \
- libinputflinger \
- libinputservice
-
-c_includes := \
- external/skia/include/core
-
-
-module_tags := tests
-
-$(foreach file,$(test_src_files), \
- $(eval include $(CLEAR_VARS)) \
- $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
- $(eval LOCAL_C_INCLUDES := $(c_includes)) \
- $(eval LOCAL_CFLAGS += -Wno-unused-parameter) \
- $(eval LOCAL_SRC_FILES := $(file)) \
- $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
- $(eval LOCAL_MODULE_TAGS := $(module_tags)) \
- $(eval include $(BUILD_NATIVE_TEST)) \
-)
-
-# Build the manual test programs.
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index a7fe69c..f12320d 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -325,7 +325,7 @@
KeyedVector<int32_t, bool> leds;
Vector<VirtualKeyDefinition> virtualKeys;
- Device(uint32_t classes) :
+ explicit Device(uint32_t classes) :
classes(classes) {
}
};
diff --git a/services/nativeperms/.clang-format b/services/nativeperms/.clang-format
new file mode 100644
index 0000000..6006e6f
--- /dev/null
+++ b/services/nativeperms/.clang-format
@@ -0,0 +1,13 @@
+BasedOnStyle: Google
+AllowShortFunctionsOnASingleLine: Inline
+AllowShortIfStatementsOnASingleLine: true
+AllowShortLoopsOnASingleLine: true
+BinPackArguments: true
+BinPackParameters: true
+ColumnLimit: 80
+CommentPragmas: NOLINT:.*
+ContinuationIndentWidth: 8
+DerivePointerAlignment: false
+IndentWidth: 4
+PointerAlignment: Left
+TabWidth: 4
diff --git a/services/nativeperms/Android.mk b/services/nativeperms/Android.mk
new file mode 100644
index 0000000..34ccd0b
--- /dev/null
+++ b/services/nativeperms/Android.mk
@@ -0,0 +1,31 @@
+# Copyright 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := nativeperms
+LOCAL_SRC_FILES := \
+ nativeperms.cpp \
+ android/os/IPermissionController.aidl
+LOCAL_CFLAGS := -Wall -Werror
+LOCAL_SHARED_LIBRARIES := \
+ libbinder \
+ libbrillo \
+ libbrillo-binder \
+ libchrome \
+ libutils
+LOCAL_INIT_RC := nativeperms.rc
+include $(BUILD_EXECUTABLE)
diff --git a/services/nativeperms/android/os/IPermissionController.aidl b/services/nativeperms/android/os/IPermissionController.aidl
new file mode 100644
index 0000000..89db85c
--- /dev/null
+++ b/services/nativeperms/android/os/IPermissionController.aidl
@@ -0,0 +1,25 @@
+/* //device/java/android/android/os/IPowerManager.aidl
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.os;
+
+/** @hide */
+interface IPermissionController {
+ boolean checkPermission(String permission, int pid, int uid);
+ String[] getPackagesForUid(int uid);
+ boolean isRuntimePermission(String permission);
+}
diff --git a/services/nativeperms/android/os/README b/services/nativeperms/android/os/README
new file mode 100644
index 0000000..e414499
--- /dev/null
+++ b/services/nativeperms/android/os/README
@@ -0,0 +1,4 @@
+IPermissionController.aidl in this directory is a verbatim copy of
+https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/os/IPermissionController.aidl,
+because some Brillo manifests do not currently include the frameworks/base repo.
+TODO(jorgelo): Figure out a way to use the .aidl file in frameworks/base.
diff --git a/services/nativeperms/nativeperms.cpp b/services/nativeperms/nativeperms.cpp
new file mode 100644
index 0000000..7f03bed
--- /dev/null
+++ b/services/nativeperms/nativeperms.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <base/at_exit.h>
+#include <base/logging.h>
+#include <base/message_loop/message_loop.h>
+#include <binder/IServiceManager.h>
+#include <binder/Status.h>
+#include <brillo/binder_watcher.h>
+#include <brillo/message_loops/base_message_loop.h>
+#include <brillo/syslog_logging.h>
+#include <utils/String16.h>
+
+#include "android/os/BnPermissionController.h"
+
+namespace {
+static android::String16 serviceName("permission");
+}
+
+namespace android {
+
+class PermissionService : public android::os::BnPermissionController {
+ public:
+ ::android::binder::Status checkPermission(
+ const ::android::String16& permission, int32_t pid, int32_t uid,
+ bool* _aidl_return) {
+ (void)permission;
+ (void)pid;
+ (void)uid;
+ *_aidl_return = true;
+ return binder::Status::ok();
+ }
+
+ ::android::binder::Status getPackagesForUid(
+ int32_t uid, ::std::vector<::android::String16>* _aidl_return) {
+ (void)uid;
+ // Brillo doesn't currently have installable packages.
+ if (_aidl_return) {
+ _aidl_return->clear();
+ }
+ return binder::Status::ok();
+ }
+
+ ::android::binder::Status isRuntimePermission(
+ const ::android::String16& permission, bool* _aidl_return) {
+ (void)permission;
+ // Brillo doesn't currently have runtime permissions.
+ *_aidl_return = false;
+ return binder::Status::ok();
+ }
+};
+
+} // namespace android
+
+int main() {
+ base::AtExitManager atExitManager;
+ brillo::InitLog(brillo::kLogToSyslog);
+ // Register the service with servicemanager.
+ android::status_t status = android::defaultServiceManager()->addService(
+ serviceName, new android::PermissionService());
+ CHECK(status == android::OK) << "Failed to get IPermissionController "
+ "binder from servicemanager.";
+
+ // Create a message loop.
+ base::MessageLoopForIO messageLoopForIo;
+ brillo::BaseMessageLoop messageLoop{&messageLoopForIo};
+
+ // Initialize a binder watcher.
+ brillo::BinderWatcher watcher(&messageLoop);
+ watcher.Init();
+
+ // Run the message loop.
+ messageLoop.Run();
+}
diff --git a/services/nativeperms/nativeperms.rc b/services/nativeperms/nativeperms.rc
new file mode 100644
index 0000000..704c0a2
--- /dev/null
+++ b/services/nativeperms/nativeperms.rc
@@ -0,0 +1,4 @@
+service nativeperms /system/bin/nativeperms
+ class main
+ user system
+ group system
diff --git a/services/powermanager/Android.bp b/services/powermanager/Android.bp
new file mode 100644
index 0000000..7b3af70
--- /dev/null
+++ b/services/powermanager/Android.bp
@@ -0,0 +1,17 @@
+cc_library_shared {
+ name: "libpowermanager",
+
+ srcs: ["IPowerManager.cpp"],
+
+ shared_libs: [
+ "libutils",
+ "libbinder",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+}
diff --git a/services/powermanager/Android.mk b/services/powermanager/Android.mk
deleted file mode 100644
index 4deb115..0000000
--- a/services/powermanager/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- IPowerManager.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libutils \
- libbinder
-
-LOCAL_MODULE:= libpowermanager
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/../../include
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/services/powermanager/IPowerManager.cpp b/services/powermanager/IPowerManager.cpp
index bff8719..ea3a831 100644
--- a/services/powermanager/IPowerManager.cpp
+++ b/services/powermanager/IPowerManager.cpp
@@ -30,7 +30,7 @@
class BpPowerManager : public BpInterface<IPowerManager>
{
public:
- BpPowerManager(const sp<IBinder>& impl)
+ explicit BpPowerManager(const sp<IBinder>& impl)
: BpInterface<IPowerManager>(impl)
{
}
diff --git a/services/sensorservice/RecentEventLogger.h b/services/sensorservice/RecentEventLogger.h
index 8b15e5a..bf1f655 100644
--- a/services/sensorservice/RecentEventLogger.h
+++ b/services/sensorservice/RecentEventLogger.h
@@ -35,7 +35,7 @@
// behavior.
class RecentEventLogger : public Dumpable {
public:
- RecentEventLogger(int sensorType);
+ explicit RecentEventLogger(int sensorType);
void addEvent(const sensors_event_t& event);
bool populateLastEvent(sensors_event_t *event) const;
bool isEmpty() const;
@@ -47,7 +47,7 @@
protected:
struct SensorEventLog {
- SensorEventLog(const sensors_event_t& e);
+ explicit SensorEventLog(const sensors_event_t& e);
timespec mWallTime;
sensors_event_t mEvent;
};
diff --git a/services/sensorservice/RingBuffer.h b/services/sensorservice/RingBuffer.h
index ec98a01..a60eb90 100644
--- a/services/sensorservice/RingBuffer.h
+++ b/services/sensorservice/RingBuffer.h
@@ -39,7 +39,7 @@
/**
* Construct a RingBuffer that can grow up to the given length.
*/
- RingBuffer(size_t length);
+ explicit RingBuffer(size_t length);
/**
* Forward iterator to this class. Implements an std:forward_iterator.
diff --git a/services/sensorservice/RotationVectorSensor.h b/services/sensorservice/RotationVectorSensor.h
index 3cc2248..265b4c4 100644
--- a/services/sensorservice/RotationVectorSensor.h
+++ b/services/sensorservice/RotationVectorSensor.h
@@ -34,7 +34,7 @@
class RotationVectorSensor : public VirtualSensor {
public:
- RotationVectorSensor(int mode = FUSION_9AXIS);
+ explicit RotationVectorSensor(int mode = FUSION_9AXIS);
virtual bool process(sensors_event_t* outEvent, const sensors_event_t& event) override;
virtual status_t activate(void* ident, bool enabled) override;
virtual status_t setDelay(void* ident, int handle, int64_t ns) override;
diff --git a/services/sensorservice/SensorEventAckReceiver.h b/services/sensorservice/SensorEventAckReceiver.h
index 998597a..20fa4c7 100644
--- a/services/sensorservice/SensorEventAckReceiver.h
+++ b/services/sensorservice/SensorEventAckReceiver.h
@@ -27,7 +27,7 @@
sp<SensorService> const mService;
public:
virtual bool threadLoop();
- SensorEventAckReceiver(const sp<SensorService>& service)
+ explicit SensorEventAckReceiver(const sp<SensorService>& service)
: mService(service) {
}
};
diff --git a/services/sensorservice/SensorInterface.h b/services/sensorservice/SensorInterface.h
index dafcf2d..0867dc2 100644
--- a/services/sensorservice/SensorInterface.h
+++ b/services/sensorservice/SensorInterface.h
@@ -47,7 +47,7 @@
class BaseSensor : public SensorInterface {
public:
- BaseSensor(const sensor_t& sensor);
+ explicit BaseSensor(const sensor_t& sensor);
BaseSensor(const sensor_t& sensor, const uint8_t (&uuid)[16]);
// Not all sensors need to support batching.
@@ -74,7 +74,7 @@
class HardwareSensor : public BaseSensor {
public:
- HardwareSensor(const sensor_t& sensor);
+ explicit HardwareSensor(const sensor_t& sensor);
HardwareSensor(const sensor_t& sensor, const uint8_t (&uuid)[16]);
virtual ~HardwareSensor();
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 99da2c4..7b47709 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -950,9 +950,11 @@
status_t SensorService::resetToNormalModeLocked() {
SensorDevice& dev(SensorDevice::getInstance());
- dev.enableAllSensors();
status_t err = dev.setMode(NORMAL);
- mCurrentOperatingMode = NORMAL;
+ if (err == NO_ERROR) {
+ mCurrentOperatingMode = NORMAL;
+ dev.enableAllSensors();
+ }
return err;
}
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 4a63ef0..e969d8a 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -49,9 +49,9 @@
#define IGNORE_HARDWARE_FUSION false
#define DEBUG_CONNECTIONS false
// Max size is 100 KB which is enough to accept a batch of about 1000 events.
-#define MAX_SOCKET_BUFFER_SIZE_BATCHED 100 * 1024
+#define MAX_SOCKET_BUFFER_SIZE_BATCHED (100 * 1024)
// For older HALs which don't support batching, use a smaller socket buffer size.
-#define SOCKET_BUFFER_SIZE_NON_BATCHED 4 * 1024
+#define SOCKET_BUFFER_SIZE_NON_BATCHED (4 * 1024)
#define SENSOR_REGISTRATIONS_BUF_SIZE 200
diff --git a/services/sensorservice/mat.h b/services/sensorservice/mat.h
index a76fc91..495c14e 100644
--- a/services/sensorservice/mat.h
+++ b/services/sensorservice/mat.h
@@ -139,13 +139,13 @@
mat() { }
mat(const mat& rhs) : base(rhs) { }
- mat(const base& rhs) : base(rhs) { }
+ mat(const base& rhs) : base(rhs) { } // NOLINT(implicit)
// -----------------------------------------------------------------------
// conversion constructors
// sets the diagonal to the value, off-diagonal to zero
- mat(pTYPE rhs) {
+ mat(pTYPE rhs) { // NOLINT(implicit)
helpers::doAssign(*this, rhs);
}
@@ -220,7 +220,7 @@
template<size_t PREV_COLUMN>
struct column_builder {
mat& matrix;
- column_builder(mat& matrix) : matrix(matrix) { }
+ explicit column_builder(mat& matrix) : matrix(matrix) { }
};
// operator << is not a method of column_builder<> so we can
@@ -265,9 +265,9 @@
enum { ROWS = R, COLS = 1 };
mat() { }
- mat(const base& rhs) : base(rhs) { }
+ explicit mat(const base& rhs) : base(rhs) { }
mat(const mat& rhs) : base(rhs) { }
- mat(const TYPE& rhs) { helpers::doAssign(*this, rhs); }
+ explicit mat(const TYPE& rhs) { helpers::doAssign(*this, rhs); }
mat& operator=(const mat& rhs) { base::operator=(rhs); return *this; }
mat& operator=(const base& rhs) { base::operator=(rhs); return *this; }
mat& operator=(const TYPE& rhs) { return helpers::doAssign(*this, rhs); }
diff --git a/services/sensorservice/vec.h b/services/sensorservice/vec.h
index a142bad..9e5d280 100644
--- a/services/sensorservice/vec.h
+++ b/services/sensorservice/vec.h
@@ -322,12 +322,12 @@
vec() { }
vec(const vec& rhs) : base(rhs) { }
- vec(const base& rhs) : base(rhs) { }
+ vec(const base& rhs) : base(rhs) { } // NOLINT(implicit)
// -----------------------------------------------------------------------
// conversion constructors
- vec(pTYPE rhs) {
+ vec(pTYPE rhs) { // NOLINT(implicit)
for (size_t i=0 ; i<SIZE ; i++)
base::operator[](i) = rhs;
}
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index ffda035..be537dc 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -124,7 +124,6 @@
endif
LOCAL_CFLAGS += -fvisibility=hidden -Werror=format
-LOCAL_CFLAGS += -std=c++14
LOCAL_STATIC_LIBRARIES := libvkjson
LOCAL_SHARED_LIBRARIES := \
@@ -154,16 +153,12 @@
LOCAL_CLANG := true
-LOCAL_LDFLAGS := -Wl,--version-script,art/sigchainlib/version-script.txt -Wl,--export-dynamic
+LOCAL_LDFLAGS_32 := -Wl,--version-script,art/sigchainlib/version-script32.txt -Wl,--export-dynamic
+LOCAL_LDFLAGS_64 := -Wl,--version-script,art/sigchainlib/version-script64.txt -Wl,--export-dynamic
LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\"
-LOCAL_CPPFLAGS := -std=c++14
LOCAL_INIT_RC := surfaceflinger.rc
-ifneq ($(ENABLE_CPUSETS),)
- LOCAL_CFLAGS += -DENABLE_CPUSETS
-endif
-
ifeq ($(TARGET_USES_HWC2),true)
LOCAL_CFLAGS += -DUSE_HWC2
endif
@@ -199,7 +194,6 @@
LOCAL_CLANG := true
LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\"
-LOCAL_CPPFLAGS := -std=c++14
LOCAL_SRC_FILES := \
DdmConnection.cpp
diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h
index 12db505..9c7d050 100644
--- a/services/surfaceflinger/Client.h
+++ b/services/surfaceflinger/Client.h
@@ -38,7 +38,7 @@
class Client : public BnSurfaceComposerClient
{
public:
- Client(const sp<SurfaceFlinger>& flinger);
+ explicit Client(const sp<SurfaceFlinger>& flinger);
~Client();
status_t initCheck() const;
diff --git a/services/surfaceflinger/Colorizer.h b/services/surfaceflinger/Colorizer.h
index 6524481..f2e6491 100644
--- a/services/surfaceflinger/Colorizer.h
+++ b/services/surfaceflinger/Colorizer.h
@@ -34,7 +34,7 @@
WHITE = 37
};
- Colorizer(bool enabled)
+ explicit Colorizer(bool enabled)
: mEnabled(enabled) {
}
diff --git a/services/surfaceflinger/DdmConnection.cpp b/services/surfaceflinger/DdmConnection.cpp
index 659c2c8..35d55f5 100644
--- a/services/surfaceflinger/DdmConnection.cpp
+++ b/services/surfaceflinger/DdmConnection.cpp
@@ -15,8 +15,10 @@
*/
#include <dlfcn.h>
+#include <sys/types.h>
+#include <unistd.h>
-#include <cutils/log.h>
+#include <log/log.h>
#include "jni.h"
#include "DdmConnection.h"
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index 1a9820d..52c2b84 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -22,20 +22,19 @@
#include <math.h>
-#include <cutils/log.h>
+#include <algorithm>
-#include <ui/Fence.h>
-
+#include <log/log.h>
#include <utils/String8.h>
#include <utils/Thread.h>
#include <utils/Trace.h>
#include <utils/Vector.h>
+#include <ui/Fence.h>
+
#include "DispSync.h"
#include "EventLog/EventLog.h"
-#include <algorithm>
-
using std::max;
using std::min;
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index 537c81b..2763e59 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -61,7 +61,7 @@
virtual void onDispSyncEvent(nsecs_t when) = 0;
};
- DispSync(const char* name);
+ explicit DispSync(const char* name);
~DispSync();
// reset clears the resync samples and error value.
diff --git a/services/surfaceflinger/DisplayHardware/FloatRect.h b/services/surfaceflinger/DisplayHardware/FloatRect.h
index 9ad1040..151eaaa 100644
--- a/services/surfaceflinger/DisplayHardware/FloatRect.h
+++ b/services/surfaceflinger/DisplayHardware/FloatRect.h
@@ -32,7 +32,7 @@
inline FloatRect()
: left(0), top(0), right(0), bottom(0) { }
- inline FloatRect(const Rect& other)
+ inline FloatRect(const Rect& other) // NOLINT(implicit)
: left(other.left), top(other.top), right(other.right), bottom(other.bottom) { }
inline float getWidth() const { return right - left; }
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 7368d77..cdfe34a 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -19,14 +19,13 @@
#undef LOG_TAG
#define LOG_TAG "FramebufferSurface"
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
#include <errno.h>
-
-#include <cutils/log.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <utils/String8.h>
+#include <log/log.h>
#include <ui/Rect.h>
@@ -240,7 +239,7 @@
#endif
void FramebufferSurface::dumpAsString(String8& result) const {
- ConsumerBase::dump(result);
+ ConsumerBase::dumpState(result);
}
void FramebufferSurface::dumpLocked(String8& result, const char* prefix) const
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index fb04af8..32a9de0 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -57,7 +57,7 @@
class Device
{
public:
- Device(hwc2_device_t* device);
+ explicit Device(hwc2_device_t* device);
~Device();
friend class HWC2::Display;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
index cc0dfb0..7f48289 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.cpp
@@ -22,15 +22,16 @@
#include "HWC2On1Adapter.h"
+#include <inttypes.h>
+
+#include <chrono>
+#include <cstdlib>
+#include <sstream>
+
#include <hardware/hwcomposer.h>
#include <log/log.h>
#include <utils/Trace.h>
-#include <cstdlib>
-#include <chrono>
-#include <inttypes.h>
-#include <sstream>
-
using namespace std::chrono_literals;
static bool operator==(const hwc_color_t& lhs, const hwc_color_t& rhs) {
@@ -1992,9 +1993,8 @@
mHasUnsupportedDataspace(false),
mHasUnsupportedPlaneAlpha(false) {}
-bool HWC2On1Adapter::SortLayersByZ::operator()(
- const std::shared_ptr<Layer>& lhs, const std::shared_ptr<Layer>& rhs)
-{
+bool HWC2On1Adapter::SortLayersByZ::operator()(const std::shared_ptr<Layer>& lhs,
+ const std::shared_ptr<Layer>& rhs) const {
return lhs->getZ() < rhs->getZ();
}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h
index bdacc73..45922af 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2On1Adapter.h
@@ -43,7 +43,7 @@
class HWC2On1Adapter : public hwc2_device_t
{
public:
- HWC2On1Adapter(struct hwc_composer_device_1* hwc1Device);
+ explicit HWC2On1Adapter(struct hwc_composer_device_1* hwc1Device);
~HWC2On1Adapter();
struct hwc_composer_device_1* getHwc1Device() const { return mHwc1Device; }
@@ -123,7 +123,7 @@
class SortLayersByZ {
public:
bool operator()(const std::shared_ptr<Layer>& lhs,
- const std::shared_ptr<Layer>& rhs);
+ const std::shared_ptr<Layer>& rhs) const;
};
class DisplayContentsDeleter {
@@ -495,7 +495,7 @@
class Layer {
public:
- Layer(Display& display);
+ explicit Layer(Display& display);
bool operator==(const Layer& other) { return mId == other.mId; }
bool operator!=(const Layer& other) { return !(*this == other); }
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index c87ba72..f0ded39 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -43,8 +43,8 @@
#include <android/configuration.h>
-#include <cutils/log.h>
#include <cutils/properties.h>
+#include <log/log.h>
#include "HWComposer.h"
#include "HWC2On1Adapter.h"
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
index ef41658..52cbb34 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.cpp
@@ -39,8 +39,8 @@
#include <android/configuration.h>
-#include <cutils/log.h>
#include <cutils/properties.h>
+#include <log/log.h>
#include <system/graphics.h>
diff --git a/services/surfaceflinger/DisplayHardware/PowerHAL.cpp b/services/surfaceflinger/DisplayHardware/PowerHAL.cpp
index bd50b4a..a4a1f99 100644
--- a/services/surfaceflinger/DisplayHardware/PowerHAL.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerHAL.cpp
@@ -17,7 +17,7 @@
#include <stdint.h>
#include <sys/types.h>
-#include <cutils/log.h>
+#include <android/log.h>
#include <utils/Errors.h>
#include <binder/IServiceManager.h>
diff --git a/services/surfaceflinger/EventControlThread.h b/services/surfaceflinger/EventControlThread.h
index be6c53a..9368db6 100644
--- a/services/surfaceflinger/EventControlThread.h
+++ b/services/surfaceflinger/EventControlThread.h
@@ -29,7 +29,7 @@
class EventControlThread: public Thread {
public:
- EventControlThread(const sp<SurfaceFlinger>& flinger);
+ explicit EventControlThread(const sp<SurfaceFlinger>& flinger);
virtual ~EventControlThread() {}
void setVsyncEnabled(bool enabled);
diff --git a/services/surfaceflinger/EventLog/EventLog.cpp b/services/surfaceflinger/EventLog/EventLog.cpp
index 47bab83..365a0bd 100644
--- a/services/surfaceflinger/EventLog/EventLog.cpp
+++ b/services/surfaceflinger/EventLog/EventLog.cpp
@@ -16,7 +16,7 @@
#include <stdio.h>
#include <stdlib.h>
-#include <cutils/log.h>
+#include <log/log.h>
#include <utils/String8.h>
#include "EventLog.h"
diff --git a/services/surfaceflinger/EventLog/EventLog.h b/services/surfaceflinger/EventLog/EventLog.h
index 5207514..efc5d70 100644
--- a/services/surfaceflinger/EventLog/EventLog.h
+++ b/services/surfaceflinger/EventLog/EventLog.h
@@ -52,7 +52,7 @@
bool mOverflow;
char mStorage[STORAGE_MAX_SIZE];
public:
- TagBuffer(int32_t tag);
+ explicit TagBuffer(int32_t tag);
// starts list of items
void startList(int8_t count);
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index 34654fa..b635115 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -57,7 +57,7 @@
class EventThread : public Thread, private VSyncSource::Callback {
class Connection : public BnDisplayEventConnection {
public:
- Connection(const sp<EventThread>& eventThread);
+ explicit Connection(const sp<EventThread>& eventThread);
status_t postEvent(const DisplayEventReceiver::Event& event);
// count >= 1 : continuous event. count is the vsync rate
diff --git a/services/surfaceflinger/FrameTracker.cpp b/services/surfaceflinger/FrameTracker.cpp
index c09bbe4..99c4f62 100644
--- a/services/surfaceflinger/FrameTracker.cpp
+++ b/services/surfaceflinger/FrameTracker.cpp
@@ -19,13 +19,12 @@
#include <inttypes.h>
-#include <cutils/log.h>
+#include <android/log.h>
+#include <utils/String8.h>
#include <ui/Fence.h>
#include <ui/FrameStats.h>
-#include <utils/String8.h>
-
#include "FrameTracker.h"
#include "EventLog/EventLog.h"
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
old mode 100644
new mode 100755
index 3ffa655..0a795aa
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -163,9 +163,7 @@
mSurfaceFlingerConsumer->setContentsChangedListener(this);
mSurfaceFlingerConsumer->setName(mName);
-#ifdef TARGET_DISABLE_TRIPLE_BUFFERING
-#warning "disabling triple buffering"
-#else
+#ifndef TARGET_DISABLE_TRIPLE_BUFFERING
mProducer->setMaxDequeuedBufferCount(2);
#endif
@@ -1273,9 +1271,9 @@
bool Layer::isOpaque(const Layer::State& s) const
{
- // if we don't have a buffer yet, we're translucent regardless of the
+ // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the
// layer's opaque flag.
- if (mActiveBuffer == 0) {
+ if ((mSidebandStream == nullptr) && (mActiveBuffer == nullptr)) {
return false;
}
@@ -2238,7 +2236,7 @@
mQueuedFrames, mRefreshPending);
if (mSurfaceFlingerConsumer != 0) {
- mSurfaceFlingerConsumer->dump(result, " ");
+ mSurfaceFlingerConsumer->dumpState(result, " ");
}
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 2ce1340..24de87e 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -477,7 +477,7 @@
class SyncPoint
{
public:
- SyncPoint(uint64_t frameNumber) : mFrameNumber(frameNumber),
+ explicit SyncPoint(uint64_t frameNumber) : mFrameNumber(frameNumber),
mFrameIsAvailable(false), mTransactionIsApplied(false) {}
uint64_t getFrameNumber() const {
diff --git a/services/surfaceflinger/MessageQueue.h b/services/surfaceflinger/MessageQueue.h
index 1004f4c..aed0aa9 100644
--- a/services/surfaceflinger/MessageQueue.h
+++ b/services/surfaceflinger/MessageQueue.h
@@ -69,7 +69,7 @@
MessageQueue& mQueue;
int32_t mEventMask;
public:
- Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) { }
+ explicit Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) { }
virtual void handleMessage(const Message& message);
void dispatchRefresh();
void dispatchInvalidate();
diff --git a/services/surfaceflinger/RenderEngine/Program.cpp b/services/surfaceflinger/RenderEngine/Program.cpp
index 0424e0c..48a8da5 100644
--- a/services/surfaceflinger/RenderEngine/Program.cpp
+++ b/services/surfaceflinger/RenderEngine/Program.cpp
@@ -17,11 +17,11 @@
#include <stdint.h>
#include <log/log.h>
+#include <utils/String8.h>
#include "Program.h"
#include "ProgramCache.h"
#include "Description.h"
-#include <utils/String8.h>
namespace android {
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index d6a032f..3af8a34 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <cutils/log.h>
+#include <log/log.h>
#include <ui/Rect.h>
#include <ui/Region.h>
@@ -380,6 +380,7 @@
attribs[EGL_RED_SIZE] = 8;
attribs[EGL_GREEN_SIZE] = 8;
attribs[EGL_BLUE_SIZE] = 8;
+ attribs[EGL_ALPHA_SIZE] = 8;
wantedAttribute = EGL_NONE;
wantedAttributeValue = EGL_NONE;
} else {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 448f12a..ea95a4e 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -27,8 +27,8 @@
#include <EGL/egl.h>
-#include <cutils/log.h>
#include <cutils/properties.h>
+#include <log/log.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
@@ -656,6 +656,10 @@
}
int SurfaceFlinger::getActiveConfig(const sp<IBinder>& display) {
+ if (display == NULL) {
+ ALOGE("%s : display is NULL", __func__);
+ return BAD_VALUE;
+ }
sp<DisplayDevice> device(getDisplayDevice(display));
if (device != NULL) {
return device->getActiveConfig();
@@ -2139,6 +2143,7 @@
switch (layer->getCompositionType(hwcId)) {
case HWC2::Composition::Cursor:
case HWC2::Composition::Device:
+ case HWC2::Composition::Sideband:
case HWC2::Composition::SolidColor: {
const Layer::State& state(layer->getDrawingState());
if (layer->getClearClientTarget(hwcId) && !firstLayer &&
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index e0e4c61..6f2520b 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -70,6 +70,14 @@
return err;
}
+ if (autoRefresh) {
+ *autoRefresh = item.mAutoRefresh;
+ }
+
+ if (queuedBuffer) {
+ *queuedBuffer = item.mQueuedBuffer;
+ }
+
// We call the rejecter here, in case the caller has a reason to
// not accept this buffer. This is used by SurfaceFlinger to
// reject buffers which have the wrong size
@@ -79,14 +87,6 @@
return BUFFER_REJECTED;
}
- if (autoRefresh) {
- *autoRefresh = item.mAutoRefresh;
- }
-
- if (queuedBuffer) {
- *queuedBuffer = item.mQueuedBuffer;
- }
-
// Release the previous buffer.
#ifdef USE_HWC2
err = updateAndReleaseLocked(item, &mPendingRelease);
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index a371c76..c78fe54 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -16,18 +16,18 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <dlfcn.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <math.h>
+#include <stdatomic.h>
#include <stdint.h>
#include <sys/types.h>
-#include <errno.h>
-#include <math.h>
-#include <dlfcn.h>
-#include <inttypes.h>
-#include <stdatomic.h>
#include <EGL/egl.h>
-#include <cutils/log.h>
#include <cutils/properties.h>
+#include <log/log.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index 53a63bd..f151087 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -45,12 +45,10 @@
set_sched_policy(0, SP_FOREGROUND);
-#ifdef ENABLE_CPUSETS
// Put most SurfaceFlinger threads in the system-background cpuset
// Keeps us from unnecessarily using big cores
// Do this after the binder thread pool init
- set_cpuset_policy(0, SP_SYSTEM);
-#endif
+ if (cpusets_enabled()) set_cpuset_policy(0, SP_SYSTEM);
// initialize before clients can connect
flinger->init();
diff --git a/services/surfaceflinger/tests/hwc2/Android.mk b/services/surfaceflinger/tests/hwc2/Android.mk
new file mode 100644
index 0000000..b8c2133
--- /dev/null
+++ b/services/surfaceflinger/tests/hwc2/Android.mk
@@ -0,0 +1,53 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := test-hwc2
+LOCAL_MODULE_TAGS := tests
+LOCAL_CFLAGS += \
+ -fstack-protector-all \
+ -g \
+ -Wall -Wextra \
+ -Werror \
+ -fno-builtin \
+ -DEGL_EGLEXT_PROTOTYPES \
+ -DGL_GLEXT_PROTOTYPES
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libhardware \
+ libEGL \
+ libGLESv2 \
+ libui \
+ libgui \
+ liblog \
+ libsync
+LOCAL_STATIC_LIBRARIES := \
+ libbase \
+ libadf \
+ libadfhwc
+LOCAL_SRC_FILES := \
+ Hwc2Test.cpp \
+ Hwc2TestProperties.cpp \
+ Hwc2TestLayer.cpp \
+ Hwc2TestLayers.cpp \
+ Hwc2TestBuffer.cpp \
+ Hwc2TestClientTarget.cpp \
+ Hwc2TestVirtualDisplay.cpp
+
+include $(BUILD_NATIVE_TEST)
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
new file mode 100644
index 0000000..062485e
--- /dev/null
+++ b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
@@ -0,0 +1,4556 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <array>
+#include <unordered_set>
+#include <unordered_map>
+#include <gtest/gtest.h>
+#include <dlfcn.h>
+#include <android-base/unique_fd.h>
+#include <hardware/hardware.h>
+#include <sync/sync.h>
+
+#define HWC2_INCLUDE_STRINGIFICATION
+#define HWC2_USE_CPP11
+#include <hardware/hwcomposer2.h>
+#undef HWC2_INCLUDE_STRINGIFICATION
+#undef HWC2_USE_CPP11
+
+#include "Hwc2TestLayer.h"
+#include "Hwc2TestLayers.h"
+#include "Hwc2TestClientTarget.h"
+#include "Hwc2TestVirtualDisplay.h"
+
+void hwc2TestHotplugCallback(hwc2_callback_data_t callbackData,
+ hwc2_display_t display, int32_t connected);
+void hwc2TestVsyncCallback(hwc2_callback_data_t callbackData,
+ hwc2_display_t display, int64_t timestamp);
+
+class Hwc2Test : public testing::Test {
+public:
+
+ virtual void SetUp()
+ {
+ hw_module_t const* hwc2Module;
+
+ int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &hwc2Module);
+ ASSERT_GE(err, 0) << "failed to get hwc hardware module: "
+ << strerror(-err);
+
+ /* The following method will fail if you have not run
+ * "adb shell stop" */
+ err = hwc2_open(hwc2Module, &mHwc2Device);
+ ASSERT_GE(err, 0) << "failed to open hwc hardware module: "
+ << strerror(-err);
+
+ populateDisplays();
+ }
+
+ virtual void TearDown()
+ {
+
+ for (auto itr = mLayers.begin(); itr != mLayers.end();) {
+ hwc2_display_t display = itr->first;
+ hwc2_layer_t layer = itr->second;
+ itr++;
+ /* Destroys and removes the layer from mLayers */
+ destroyLayer(display, layer);
+ }
+
+ for (auto itr = mActiveDisplays.begin(); itr != mActiveDisplays.end();) {
+ hwc2_display_t display = *itr;
+ itr++;
+ /* Sets power mode to off and removes the display from
+ * mActiveDisplays */
+ setPowerMode(display, HWC2_POWER_MODE_OFF);
+ }
+
+ for (auto itr = mVirtualDisplays.begin(); itr != mVirtualDisplays.end();) {
+ hwc2_display_t display = *itr;
+ itr++;
+ /* Destroys virtual displays */
+ destroyVirtualDisplay(display);
+ }
+
+ if (mHwc2Device)
+ hwc2_close(mHwc2Device);
+ }
+
+ void registerCallback(hwc2_callback_descriptor_t descriptor,
+ hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer,
+ hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_REGISTER_CALLBACK>(
+ getFunction(HWC2_FUNCTION_REGISTER_CALLBACK));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, descriptor,
+ callbackData, pointer));
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to register callback";
+ }
+ }
+
+ void getDisplayType(hwc2_display_t display, hwc2_display_type_t* outType,
+ hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_GET_DISPLAY_TYPE>(
+ getFunction(HWC2_FUNCTION_GET_DISPLAY_TYPE));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
+ reinterpret_cast<int32_t*>(outType)));
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get display type";
+ }
+ }
+
+ /* If the populateDisplays function is still receiving displays and the
+ * display is connected, the display handle is stored in mDisplays. */
+ void hotplugCallback(hwc2_display_t display, int32_t connected)
+ {
+ std::lock_guard<std::mutex> lock(mHotplugMutex);
+
+ if (mHotplugStatus != Hwc2TestHotplugStatus::Receiving)
+ return;
+
+ if (connected == HWC2_CONNECTION_CONNECTED)
+ mDisplays.insert(display);
+
+ mHotplugCv.notify_all();
+ }
+
+ void createLayer(hwc2_display_t display, hwc2_layer_t* outLayer,
+ hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_CREATE_LAYER>(
+ getFunction(HWC2_FUNCTION_CREATE_LAYER));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
+ outLayer));
+
+ if (err == HWC2_ERROR_NONE)
+ mLayers.insert(std::make_pair(display, *outLayer));
+
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to create layer";
+ }
+ }
+
+ void destroyLayer(hwc2_display_t display, hwc2_layer_t layer,
+ hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_DESTROY_LAYER>(
+ getFunction(HWC2_FUNCTION_DESTROY_LAYER));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer));
+
+ if (err == HWC2_ERROR_NONE)
+ mLayers.erase(std::make_pair(display, layer));
+
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to destroy layer "
+ << layer;
+ }
+ }
+
+ void getDisplayAttribute(hwc2_display_t display, hwc2_config_t config,
+ hwc2_attribute_t attribute, int32_t* outValue,
+ hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_GET_DISPLAY_ATTRIBUTE>(
+ getFunction(HWC2_FUNCTION_GET_DISPLAY_ATTRIBUTE));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, config,
+ attribute, outValue));
+
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get display attribute "
+ << getAttributeName(attribute) << " for config " << config;
+ }
+ }
+
+ void getDisplayConfigs(hwc2_display_t display,
+ std::vector<hwc2_config_t>* outConfigs,
+ hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_GET_DISPLAY_CONFIGS>(
+ getFunction(HWC2_FUNCTION_GET_DISPLAY_CONFIGS));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ uint32_t numConfigs = 0;
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
+ &numConfigs, nullptr));
+
+ if (err == HWC2_ERROR_NONE) {
+ outConfigs->resize(numConfigs);
+
+ err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
+ &numConfigs, outConfigs->data()));
+ }
+
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get configs for"
+ " display " << display;
+ }
+ }
+
+ void getActiveConfig(hwc2_display_t display, hwc2_config_t* outConfig,
+ hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_GET_ACTIVE_CONFIG>(
+ getFunction(HWC2_FUNCTION_GET_ACTIVE_CONFIG));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
+ outConfig));
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get active config on"
+ " display " << display;
+ }
+ }
+
+ void setActiveConfig(hwc2_display_t display, hwc2_config_t config,
+ hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_SET_ACTIVE_CONFIG>(
+ getFunction(HWC2_FUNCTION_SET_ACTIVE_CONFIG));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, config));
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set active config "
+ << config;
+ }
+ }
+
+ void getDozeSupport(hwc2_display_t display, int32_t* outSupport,
+ hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_GET_DOZE_SUPPORT>(
+ getFunction(HWC2_FUNCTION_GET_DOZE_SUPPORT));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
+ outSupport));
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get doze support on"
+ " display " << display;
+ }
+ }
+
+ void setPowerMode(hwc2_display_t display, hwc2_power_mode_t mode,
+ hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_SET_POWER_MODE>(
+ getFunction(HWC2_FUNCTION_SET_POWER_MODE));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
+ mode));
+ if (outErr) {
+ *outErr = err;
+ if (err != HWC2_ERROR_NONE)
+ return;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set power mode "
+ << getPowerModeName(mode) << " on display " << display;
+ }
+
+ if (mode == HWC2_POWER_MODE_OFF) {
+ mActiveDisplays.erase(display);
+ } else {
+ mActiveDisplays.insert(display);
+ }
+ }
+
+ void setVsyncEnabled(hwc2_display_t display, hwc2_vsync_t enabled,
+ hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_SET_VSYNC_ENABLED>(
+ getFunction(HWC2_FUNCTION_SET_VSYNC_ENABLED));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
+ enabled));
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set vsync enabled "
+ << getVsyncName(enabled);
+ }
+ }
+
+ void vsyncCallback(hwc2_display_t display, int64_t timestamp)
+ {
+ std::lock_guard<std::mutex> lock(mVsyncMutex);
+ mVsyncDisplay = display;
+ mVsyncTimestamp = timestamp;
+ mVsyncCv.notify_all();
+ }
+
+ void getDisplayName(hwc2_display_t display, std::string* outName,
+ hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_GET_DISPLAY_NAME>(
+ getFunction(HWC2_FUNCTION_GET_DISPLAY_NAME));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ uint32_t size = 0;
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, &size,
+ nullptr));
+
+ if (err == HWC2_ERROR_NONE) {
+ std::vector<char> name(size);
+
+ err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, &size,
+ name.data()));
+
+ outName->assign(name.data());
+ }
+
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get display name for "
+ << display;
+ }
+ }
+
+ void setLayerCompositionType(hwc2_display_t display, hwc2_layer_t layer,
+ hwc2_composition_t composition, hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_COMPOSITION_TYPE>(
+ getFunction(HWC2_FUNCTION_SET_LAYER_COMPOSITION_TYPE));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
+ composition));
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer composition"
+ " type " << getCompositionName(composition);
+ }
+ }
+
+ void setCursorPosition(hwc2_display_t display, hwc2_layer_t layer,
+ int32_t x, int32_t y, hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_SET_CURSOR_POSITION>(
+ getFunction(HWC2_FUNCTION_SET_CURSOR_POSITION));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer, x,
+ y));
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set cursor position";
+ }
+ }
+
+ void setLayerBlendMode(hwc2_display_t display, hwc2_layer_t layer,
+ hwc2_blend_mode_t mode, hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_BLEND_MODE>(
+ getFunction(HWC2_FUNCTION_SET_LAYER_BLEND_MODE));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
+ mode));
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer blend mode "
+ << getBlendModeName(mode);
+ }
+ }
+
+ void setLayerBuffer(hwc2_display_t display, hwc2_layer_t layer,
+ buffer_handle_t buffer, int32_t acquireFence,
+ hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_BUFFER>(
+ getFunction(HWC2_FUNCTION_SET_LAYER_BUFFER));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
+ buffer, acquireFence));
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer buffer";
+ }
+ }
+
+ void setLayerColor(hwc2_display_t display, hwc2_layer_t layer,
+ hwc_color_t color, hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_COLOR>(
+ getFunction(HWC2_FUNCTION_SET_LAYER_COLOR));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
+ color));
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer color";
+ }
+ }
+
+ void setLayerDataspace(hwc2_display_t display, hwc2_layer_t layer,
+ android_dataspace_t dataspace, hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_DATASPACE>(
+ getFunction(HWC2_FUNCTION_SET_LAYER_DATASPACE));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
+ layer, dataspace));
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer dataspace";
+ }
+ }
+
+ void setLayerDisplayFrame(hwc2_display_t display, hwc2_layer_t layer,
+ const hwc_rect_t& displayFrame, hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_DISPLAY_FRAME>(
+ getFunction(HWC2_FUNCTION_SET_LAYER_DISPLAY_FRAME));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
+ displayFrame));
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer display"
+ " frame";
+ }
+ }
+
+ void setLayerPlaneAlpha(hwc2_display_t display, hwc2_layer_t layer,
+ float alpha, hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_PLANE_ALPHA>(
+ getFunction(HWC2_FUNCTION_SET_LAYER_PLANE_ALPHA));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
+ alpha));
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer plane alpha "
+ << alpha;
+ }
+ }
+
+ void setLayerSourceCrop(hwc2_display_t display, hwc2_layer_t layer,
+ const hwc_frect_t& sourceCrop, hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_SOURCE_CROP>(
+ getFunction(HWC2_FUNCTION_SET_LAYER_SOURCE_CROP));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
+ sourceCrop));
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer source crop";
+ }
+ }
+
+ void setLayerSurfaceDamage(hwc2_display_t display, hwc2_layer_t layer,
+ const hwc_region_t& surfaceDamage, hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_SURFACE_DAMAGE>(
+ getFunction(HWC2_FUNCTION_SET_LAYER_SURFACE_DAMAGE));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
+ surfaceDamage));
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer surface"
+ " damage";
+ }
+ }
+
+ void setLayerTransform(hwc2_display_t display, hwc2_layer_t layer,
+ hwc_transform_t transform, hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_TRANSFORM>(
+ getFunction(HWC2_FUNCTION_SET_LAYER_TRANSFORM));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
+ transform));
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer transform "
+ << getTransformName(transform);
+ }
+ }
+
+ void setLayerVisibleRegion(hwc2_display_t display, hwc2_layer_t layer,
+ const hwc_region_t& visibleRegion, hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_VISIBLE_REGION>(
+ getFunction(HWC2_FUNCTION_SET_LAYER_VISIBLE_REGION));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
+ visibleRegion));
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer visible"
+ " region";
+ }
+ }
+
+ void setLayerZOrder(hwc2_display_t display, hwc2_layer_t layer,
+ uint32_t zOrder, hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_Z_ORDER>(
+ getFunction(HWC2_FUNCTION_SET_LAYER_Z_ORDER));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
+ zOrder));
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer z order "
+ << zOrder;
+ }
+ }
+
+ void validateDisplay(hwc2_display_t display, uint32_t* outNumTypes,
+ uint32_t* outNumRequests, hwc2_error_t* outErr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_VALIDATE_DISPLAY>(
+ getFunction(HWC2_FUNCTION_VALIDATE_DISPLAY));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ *outErr = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
+ outNumTypes, outNumRequests));
+ }
+
+ void validateDisplay(hwc2_display_t display, uint32_t* outNumTypes,
+ uint32_t* outNumRequests, bool* outHasChanges)
+ {
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ EXPECT_NO_FATAL_FAILURE(validateDisplay(display, outNumTypes,
+ outNumRequests, &err));
+
+ if (err != HWC2_ERROR_HAS_CHANGES) {
+ *outHasChanges = false;
+ EXPECT_EQ(err, HWC2_ERROR_NONE) << "failed to validate display";
+ } else {
+ *outHasChanges = true;
+ }
+ }
+
+ void getDisplayRequests(hwc2_display_t display,
+ hwc2_display_request_t* outDisplayRequests,
+ std::vector<hwc2_layer_t>* outLayers,
+ std::vector<hwc2_layer_request_t>* outLayerRequests,
+ hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_GET_DISPLAY_REQUESTS>(
+ getFunction(HWC2_FUNCTION_GET_DISPLAY_REQUESTS));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ uint32_t numElements = 0;
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
+ reinterpret_cast<int32_t*>(outDisplayRequests), &numElements,
+ nullptr, nullptr));
+
+ if (err == HWC2_ERROR_NONE && numElements > 0) {
+ outLayers->resize(numElements);
+ outLayerRequests->resize(numElements);
+
+ err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
+ reinterpret_cast<int32_t*>(outDisplayRequests), &numElements,
+ reinterpret_cast<uint64_t*>(outLayers->data()),
+ reinterpret_cast<int32_t*>(outLayerRequests->data())));
+ }
+
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get display requests";
+ }
+ }
+
+ void handleRequests(hwc2_display_t display,
+ const std::vector<hwc2_layer_t>& layers, uint32_t numRequests,
+ std::set<hwc2_layer_t>* outClearLayers = nullptr,
+ bool* outFlipClientTarget = nullptr)
+ {
+ hwc2_display_request_t displayRequest =
+ static_cast<hwc2_display_request_t>(0);
+ std::vector<hwc2_layer_t> requestedLayers;
+ std::vector<hwc2_layer_request_t> requests;
+
+ ASSERT_NO_FATAL_FAILURE(getDisplayRequests(display, &displayRequest,
+ &requestedLayers, &requests));
+
+ EXPECT_EQ(numRequests, requests.size()) << "validate returned "
+ << numRequests << " requests and get display requests returned "
+ << requests.size() << " requests";
+
+ for (size_t i = 0; i < requests.size(); i++) {
+ hwc2_layer_t requestedLayer = requestedLayers.at(i);
+ hwc2_layer_request_t request = requests.at(i);
+
+ EXPECT_EQ(std::count(layers.begin(), layers.end(), requestedLayer),
+ 0) << "get display requests returned an unknown layer";
+ EXPECT_NE(request, 0) << "returned empty request for layer "
+ << requestedLayer;
+
+ if (outClearLayers && request
+ == HWC2_LAYER_REQUEST_CLEAR_CLIENT_TARGET)
+ outClearLayers->insert(requestedLayer);
+ }
+
+ if (outFlipClientTarget)
+ *outFlipClientTarget = displayRequest
+ & HWC2_DISPLAY_REQUEST_FLIP_CLIENT_TARGET;
+ }
+
+ void getChangedCompositionTypes(hwc2_display_t display,
+ std::vector<hwc2_layer_t>* outLayers,
+ std::vector<hwc2_composition_t>* outTypes,
+ hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES>(
+ getFunction(HWC2_FUNCTION_GET_CHANGED_COMPOSITION_TYPES));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ uint32_t numElements = 0;
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
+ &numElements, nullptr, nullptr));
+
+ if (err == HWC2_ERROR_NONE && numElements > 0) {
+ outLayers->resize(numElements);
+ outTypes->resize(numElements);
+
+ err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
+ &numElements, reinterpret_cast<uint64_t*>(outLayers->data()),
+ reinterpret_cast<int32_t*>(outTypes->data())));
+ }
+
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get changed"
+ " composition types";
+ }
+ }
+
+ void handleCompositionChanges(hwc2_display_t display,
+ const Hwc2TestLayers& testLayers,
+ const std::vector<hwc2_layer_t>& layers, uint32_t numTypes,
+ std::set<hwc2_layer_t>* outClientLayers = nullptr)
+ {
+ std::vector<hwc2_layer_t> changedLayers;
+ std::vector<hwc2_composition_t> types;
+
+ ASSERT_NO_FATAL_FAILURE(getChangedCompositionTypes(display,
+ &changedLayers, &types));
+
+ EXPECT_EQ(numTypes, types.size()) << "validate returned "
+ << numTypes << " types and get changed composition types"
+ " returned " << types.size() << " types";
+
+ for (size_t i = 0; i < types.size(); i++) {
+
+ auto layer = std::find(layers.begin(), layers.end(),
+ changedLayers.at(i));
+
+ EXPECT_TRUE(layer != layers.end() || !testLayers.contains(*layer))
+ << "get changed composition types returned an unknown layer";
+
+ hwc2_composition_t requestedType = testLayers.getComposition(*layer);
+ hwc2_composition_t returnedType = types.at(i);
+
+ EXPECT_NE(returnedType, HWC2_COMPOSITION_INVALID) << "get changed"
+ " composition types returned invalid composition";
+
+ switch (requestedType) {
+ case HWC2_COMPOSITION_CLIENT:
+ EXPECT_TRUE(false) << getCompositionName(returnedType)
+ << " cannot be changed";
+ break;
+ case HWC2_COMPOSITION_DEVICE:
+ case HWC2_COMPOSITION_SOLID_COLOR:
+ EXPECT_EQ(returnedType, HWC2_COMPOSITION_CLIENT)
+ << "composition of type "
+ << getCompositionName(requestedType)
+ << " can only be changed to "
+ << getCompositionName(HWC2_COMPOSITION_CLIENT);
+ break;
+ case HWC2_COMPOSITION_CURSOR:
+ case HWC2_COMPOSITION_SIDEBAND:
+ EXPECT_TRUE(returnedType == HWC2_COMPOSITION_CLIENT
+ || returnedType == HWC2_COMPOSITION_DEVICE)
+ << "composition of type "
+ << getCompositionName(requestedType)
+ << " can only be changed to "
+ << getCompositionName(HWC2_COMPOSITION_CLIENT) << " or "
+ << getCompositionName(HWC2_COMPOSITION_DEVICE);
+ break;
+ default:
+ EXPECT_TRUE(false) << "unknown type "
+ << getCompositionName(requestedType);
+ break;
+ }
+
+ if (outClientLayers)
+ if (returnedType == HWC2_COMPOSITION_CLIENT)
+ outClientLayers->insert(*layer);
+ }
+
+ if (outClientLayers) {
+ for (auto layer : layers) {
+ if (testLayers.getComposition(layer) == HWC2_COMPOSITION_CLIENT)
+ outClientLayers->insert(layer);
+ }
+ }
+ }
+
+ void acceptDisplayChanges(hwc2_display_t display,
+ hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_ACCEPT_DISPLAY_CHANGES>(
+ getFunction(HWC2_FUNCTION_ACCEPT_DISPLAY_CHANGES));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display));
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to accept display changes";
+ }
+ }
+
+ void getClientTargetSupport(hwc2_display_t display, int32_t width,
+ int32_t height, android_pixel_format_t format,
+ android_dataspace_t dataspace, hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_GET_CLIENT_TARGET_SUPPORT>(
+ getFunction(HWC2_FUNCTION_GET_CLIENT_TARGET_SUPPORT));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, width,
+ height, format, dataspace));
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get client target"
+ " support";
+ }
+ }
+
+ void setClientTarget(hwc2_display_t display, buffer_handle_t handle,
+ int32_t acquireFence, android_dataspace_t dataspace,
+ hwc_region_t damage, hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_SET_CLIENT_TARGET>(
+ getFunction(HWC2_FUNCTION_SET_CLIENT_TARGET));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, handle,
+ acquireFence, dataspace, damage));
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set client target";
+ }
+ }
+
+ void presentDisplay(hwc2_display_t display, int32_t* outPresentFence,
+ hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_PRESENT_DISPLAY>(
+ getFunction(HWC2_FUNCTION_PRESENT_DISPLAY));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
+ outPresentFence));
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to present display";
+ }
+ }
+
+ void getReleaseFences(hwc2_display_t display,
+ std::vector<hwc2_layer_t>* outLayers,
+ std::vector<int32_t>* outFences, hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_GET_RELEASE_FENCES>(
+ getFunction(HWC2_FUNCTION_GET_RELEASE_FENCES));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ uint32_t numElements = 0;
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
+ &numElements, nullptr, nullptr));
+
+ if (err == HWC2_ERROR_NONE) {
+ outLayers->resize(numElements);
+ outFences->resize(numElements);
+
+ err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
+ &numElements, outLayers->data(), outFences->data()));
+ }
+
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get release fences";
+ }
+ }
+
+ void getColorModes(hwc2_display_t display,
+ std::vector<android_color_mode_t>* outColorModes,
+ hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_GET_COLOR_MODES>(
+ getFunction(HWC2_FUNCTION_GET_COLOR_MODES));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ uint32_t numColorModes = 0;
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
+ &numColorModes, nullptr));
+ if (err == HWC2_ERROR_NONE) {
+ outColorModes->resize(numColorModes);
+
+ err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
+ &numColorModes,
+ reinterpret_cast<int32_t*>(outColorModes->data())));
+ }
+
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get color modes for"
+ " display " << display;
+ }
+ }
+
+ void setColorMode(hwc2_display_t display, android_color_mode_t colorMode,
+ hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_SET_COLOR_MODE>(
+ getFunction(HWC2_FUNCTION_SET_COLOR_MODE));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
+ static_cast<int32_t>(colorMode)));
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set color mode "
+ << colorMode;
+ }
+ }
+
+ void getHdrCapabilities(hwc2_display_t display,
+ std::vector<android_hdr_t>* outTypes, float* outMaxLuminance,
+ float* outMaxAverageLuminance, float* outMinLuminance,
+ hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_GET_HDR_CAPABILITIES>(
+ getFunction(HWC2_FUNCTION_GET_HDR_CAPABILITIES));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ uint32_t numTypes = 0;
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
+ &numTypes, nullptr, outMaxLuminance, outMaxAverageLuminance,
+ outMinLuminance));
+
+ if (err == HWC2_ERROR_NONE) {
+ outTypes->resize(numTypes);
+
+ err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, &numTypes,
+ reinterpret_cast<int32_t*>(outTypes->data()), outMaxLuminance,
+ outMaxAverageLuminance, outMinLuminance));
+ }
+
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get hdr capabilities"
+ " for display " << display;
+ }
+ }
+
+ void setColorTransform(hwc2_display_t display,
+ const std::array<float, 16>& matrix, android_color_transform_t hint,
+ hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_SET_COLOR_TRANSFORM>(
+ getFunction(HWC2_FUNCTION_SET_COLOR_TRANSFORM));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
+ matrix.data(), hint));
+
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set color transform "
+ << hint;
+ }
+ }
+
+ void createVirtualDisplay(uint32_t width, uint32_t height,
+ android_pixel_format_t* outFormat, hwc2_display_t* outDisplay,
+ hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_CREATE_VIRTUAL_DISPLAY>(
+ getFunction(HWC2_FUNCTION_CREATE_VIRTUAL_DISPLAY));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, width, height,
+ reinterpret_cast<int32_t*>(outFormat), outDisplay));
+
+ if (err == HWC2_ERROR_NONE)
+ mVirtualDisplays.insert(*outDisplay);
+
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to create virtual display";
+ }
+ }
+
+ void destroyVirtualDisplay(hwc2_display_t display,
+ hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_DESTROY_VIRTUAL_DISPLAY>(
+ getFunction(HWC2_FUNCTION_DESTROY_VIRTUAL_DISPLAY));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display));
+
+ if (err == HWC2_ERROR_NONE)
+ mVirtualDisplays.erase(display);
+
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to destroy virtual display";
+ }
+ }
+
+ void getMaxVirtualDisplayCount(uint32_t* outMaxCnt)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT>(
+ getFunction(HWC2_FUNCTION_GET_MAX_VIRTUAL_DISPLAY_COUNT));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ *outMaxCnt = pfn(mHwc2Device);
+ }
+
+ void setOutputBuffer(hwc2_display_t display, buffer_handle_t buffer,
+ int32_t releaseFence, hwc2_error_t* outErr = nullptr)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_SET_OUTPUT_BUFFER>(
+ getFunction(HWC2_FUNCTION_SET_OUTPUT_BUFFER));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, buffer,
+ releaseFence));
+ if (outErr) {
+ *outErr = err;
+ } else {
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set output buffer";
+ }
+ }
+
+ void dump(std::string* outBuffer)
+ {
+ auto pfn = reinterpret_cast<HWC2_PFN_DUMP>(
+ getFunction(HWC2_FUNCTION_DUMP));
+ ASSERT_TRUE(pfn) << "failed to get function";
+
+ uint32_t size = 0;
+
+ pfn(mHwc2Device, &size, nullptr);
+
+ std::vector<char> buffer(size);
+
+ pfn(mHwc2Device, &size, buffer.data());
+
+ outBuffer->assign(buffer.data());
+ }
+
+ void getBadDisplay(hwc2_display_t* outDisplay)
+ {
+ for (hwc2_display_t display = 0; display < UINT64_MAX; display++) {
+ if (mDisplays.count(display) == 0) {
+ *outDisplay = display;
+ return;
+ }
+ }
+ ASSERT_TRUE(false) << "Unable to find bad display. UINT64_MAX displays"
+ " are registered. This should never happen.";
+ }
+
+ void waitForVsync(hwc2_display_t* outDisplay = nullptr,
+ int64_t* outTimestamp = nullptr)
+ {
+ std::unique_lock<std::mutex> lock(mVsyncMutex);
+ ASSERT_EQ(mVsyncCv.wait_for(lock, std::chrono::seconds(3)),
+ std::cv_status::no_timeout) << "timed out attempting to get"
+ " vsync callback";
+ if (outDisplay)
+ *outDisplay = mVsyncDisplay;
+ if (outTimestamp)
+ *outTimestamp = mVsyncTimestamp;
+ }
+
+ void enableVsync(hwc2_display_t display)
+ {
+ ASSERT_NO_FATAL_FAILURE(registerCallback(HWC2_CALLBACK_VSYNC, this,
+ reinterpret_cast<hwc2_function_pointer_t>(
+ hwc2TestVsyncCallback)));
+ ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_ENABLE));
+ }
+
+ void disableVsync(hwc2_display_t display)
+ {
+ ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE));
+ }
+
+protected:
+ hwc2_function_pointer_t getFunction(hwc2_function_descriptor_t descriptor)
+ {
+ return mHwc2Device->getFunction(mHwc2Device, descriptor);
+ }
+
+ void getCapabilities(std::vector<hwc2_capability_t>* outCapabilities)
+ {
+ uint32_t num = 0;
+
+ mHwc2Device->getCapabilities(mHwc2Device, &num, nullptr);
+
+ outCapabilities->resize(num);
+
+ mHwc2Device->getCapabilities(mHwc2Device, &num,
+ reinterpret_cast<int32_t*>(outCapabilities->data()));
+ }
+
+ /* Registers a hotplug callback and waits for hotplug callbacks. This
+ * function will have no effect if called more than once. */
+ void populateDisplays()
+ {
+ /* Sets the hotplug status to receiving */
+ {
+ std::lock_guard<std::mutex> lock(mHotplugMutex);
+
+ if (mHotplugStatus != Hwc2TestHotplugStatus::Init)
+ return;
+ mHotplugStatus = Hwc2TestHotplugStatus::Receiving;
+ }
+
+ /* Registers the callback. This function call cannot be locked because
+ * a callback could happen on the same thread */
+ ASSERT_NO_FATAL_FAILURE(registerCallback(HWC2_CALLBACK_HOTPLUG, this,
+ reinterpret_cast<hwc2_function_pointer_t>(
+ hwc2TestHotplugCallback)));
+
+ /* Waits for hotplug events. If a hotplug event has not come within 1
+ * second, stop waiting. */
+ std::unique_lock<std::mutex> lock(mHotplugMutex);
+
+ while (mHotplugCv.wait_for(lock, std::chrono::seconds(1)) !=
+ std::cv_status::timeout) { }
+
+ /* Sets the hotplug status to done. Future calls will have no effect */
+ mHotplugStatus = Hwc2TestHotplugStatus::Done;
+ }
+
+ /* NOTE: will create min(newlayerCnt, max supported layers) layers */
+ void createLayers(hwc2_display_t display,
+ std::vector<hwc2_layer_t>* outLayers, size_t newLayerCnt)
+ {
+ std::vector<hwc2_layer_t> newLayers;
+ hwc2_layer_t layer;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ for (size_t i = 0; i < newLayerCnt; i++) {
+
+ EXPECT_NO_FATAL_FAILURE(createLayer(display, &layer, &err));
+ if (err == HWC2_ERROR_NO_RESOURCES)
+ break;
+ if (err != HWC2_ERROR_NONE) {
+ newLayers.clear();
+ ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to create layer";
+ }
+ newLayers.push_back(layer);
+ }
+
+ *outLayers = std::move(newLayers);
+ }
+
+ void destroyLayers(hwc2_display_t display,
+ std::vector<hwc2_layer_t>&& layers)
+ {
+ for (hwc2_layer_t layer : layers) {
+ EXPECT_NO_FATAL_FAILURE(destroyLayer(display, layer));
+ }
+ }
+
+ void getInvalidConfig(hwc2_display_t display, hwc2_config_t* outConfig)
+ {
+ std::vector<hwc2_config_t> configs;
+
+ ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
+
+ hwc2_config_t CONFIG_MAX = UINT32_MAX;
+
+ ASSERT_LE(configs.size() - 1, CONFIG_MAX) << "every config value"
+ " (2^32 values) has been taken which shouldn't happen";
+
+ hwc2_config_t config;
+ for (config = 0; config < CONFIG_MAX; config++) {
+ if (std::count(configs.begin(), configs.end(), config) == 0)
+ break;
+ }
+
+ *outConfig = config;
+ }
+
+ /* Calls a set property function from Hwc2Test to set a property value from
+ * Hwc2TestLayer to hwc2_layer_t on hwc2_display_t */
+ using TestLayerPropertyFunction = void (*)(Hwc2Test* test,
+ hwc2_display_t display, hwc2_layer_t layer,
+ Hwc2TestLayer* testLayer, hwc2_error_t* outErr);
+
+ /* Calls a set property function from Hwc2Test to set property values from
+ * Hwc2TestLayers to hwc2_layer_t on hwc2_display_t */
+ using TestLayerPropertiesFunction = void (*)(Hwc2Test* test,
+ hwc2_display_t display, hwc2_layer_t layer,
+ Hwc2TestLayers* testLayers);
+
+ /* Calls a set property function from Hwc2Test to set a bad property value
+ * on hwc2_layer_t on hwc2_display_t */
+ using TestLayerPropertyBadLayerFunction = void (*)(Hwc2Test* test,
+ hwc2_display_t display, hwc2_layer_t layer,
+ Hwc2TestLayer* testLayer, hwc2_error_t* outErr);
+
+ /* Calls a set property function from Hwc2Test to set a bad property value
+ * on hwc2_layer_t on hwc2_display_t */
+ using TestLayerPropertyBadParameterFunction = void (*)(Hwc2Test* test,
+ hwc2_display_t display, hwc2_layer_t layer, hwc2_error_t* outErr);
+
+ /* Is called after a display is powered on and all layer properties have
+ * been set. It should be used to test functions such as validate, accepting
+ * changes, present, etc. */
+ using TestDisplayLayersFunction = void (*)(Hwc2Test* test,
+ hwc2_display_t display, const std::vector<hwc2_layer_t>& layers,
+ Hwc2TestLayers* testLayers);
+
+ /* It is called on an non validated display */
+ using TestDisplayNonValidatedLayersFunction = void (*)(Hwc2Test* test,
+ hwc2_display_t display, std::vector<hwc2_layer_t>* layers);
+
+ /* Tests client target support on a particular display and config */
+ using TestClientTargetSupportFunction = void (*)(Hwc2Test* test,
+ hwc2_display_t display,
+ const Hwc2TestClientTargetSupport& testClientTargetSupport);
+
+ /* Tests a particular active display config */
+ using TestActiveDisplayConfigFunction = void (*)(Hwc2Test* test,
+ hwc2_display_t display);
+
+ /* Tests a newly created virtual display */
+ using TestCreateVirtualDisplayFunction = void (*)(Hwc2Test* test,
+ hwc2_display_t display, Hwc2TestVirtualDisplay* testVirtualDisplay);
+
+ /* Advances a property of Hwc2TestLayer */
+ using AdvanceProperty = bool (*)(Hwc2TestLayer* testLayer);
+
+ /* Advances properties of Hwc2TestLayers */
+ using AdvanceProperties = bool (*)(Hwc2TestLayers* testLayer);
+
+ /* Advances properties of Hwc2TestClientTargetSupport */
+ using AdvanceClientTargetSupport = bool (*)(
+ Hwc2TestClientTargetSupport* testClientTargetSupport);
+
+ /* For each active display it cycles through each display config and tests
+ * each property value. It creates a layer, sets the property and then
+ * destroys the layer */
+ void setLayerProperty(Hwc2TestCoverage coverage,
+ TestLayerPropertyFunction function, AdvanceProperty advance)
+ {
+ for (auto display : mDisplays) {
+ std::vector<hwc2_config_t> configs;
+
+ ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
+
+ for (auto config : configs) {
+ hwc2_layer_t layer;
+ Area displayArea;
+
+ ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
+ ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display,
+ &displayArea));
+ Hwc2TestLayer testLayer(coverage, displayArea);
+
+ do {
+ ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer));
+
+ ASSERT_NO_FATAL_FAILURE(function(this, display, layer,
+ &testLayer, nullptr));
+
+ ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer));
+ } while (advance(&testLayer));
+ }
+ }
+ }
+
+ /* For each active display it cycles through each display config and tests
+ * each property value. It creates a layer, cycles through each property
+ * value and updates the layer property value and then destroys the layer */
+ void setLayerPropertyUpdate(Hwc2TestCoverage coverage,
+ TestLayerPropertyFunction function, AdvanceProperty advance)
+ {
+ for (auto display : mDisplays) {
+ std::vector<hwc2_config_t> configs;
+
+ ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
+
+ for (auto config : configs) {
+ hwc2_layer_t layer;
+ Area displayArea;
+
+ ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
+ ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display,
+ &displayArea));
+ Hwc2TestLayer testLayer(coverage, displayArea);
+
+ ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer));
+
+ do {
+ ASSERT_NO_FATAL_FAILURE(function(this, display, layer,
+ &testLayer, nullptr));
+ } while (advance(&testLayer));
+
+ ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer));
+ }
+ }
+ }
+
+ /* For each active display it cycles through each display config and tests
+ * each property value. It creates multiple layers, calls the
+ * TestLayerPropertiesFunction to set property values and then
+ * destroys the layers */
+ void setLayerProperties(Hwc2TestCoverage coverage, size_t layerCnt,
+ TestLayerPropertiesFunction function, AdvanceProperties advance)
+ {
+ for (auto display : mDisplays) {
+ std::vector<hwc2_config_t> configs;
+
+ ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
+
+ for (auto config : configs) {
+ std::vector<hwc2_layer_t> layers;
+ Area displayArea;
+
+ ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
+ ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display,
+ &displayArea));
+
+ ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers, layerCnt));
+ Hwc2TestLayers testLayers(layers, coverage, displayArea);
+
+ do {
+ for (auto layer : layers) {
+ EXPECT_NO_FATAL_FAILURE(function(this, display, layer,
+ &testLayers));
+ }
+ } while (advance(&testLayers));
+
+ ASSERT_NO_FATAL_FAILURE(destroyLayers(display, std::move(layers)));
+ }
+ }
+ }
+
+ /* For each active display it cycles through each display config.
+ * 1) It attempts to set a valid property value to bad layer handle.
+ * 2) It creates a layer x and attempts to set a valid property value to
+ * layer x + 1
+ * 3) It destroys the layer x and attempts to set a valid property value to
+ * the destroyed layer x.
+ */
+ void setLayerPropertyBadLayer(Hwc2TestCoverage coverage,
+ TestLayerPropertyBadLayerFunction function)
+ {
+ for (auto display : mDisplays) {
+ std::vector<hwc2_config_t> configs;
+
+ ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
+
+ for (auto config : configs) {
+ hwc2_layer_t layer = 0;
+ Area displayArea;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
+ ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display,
+ &displayArea));
+ Hwc2TestLayer testLayer(coverage, displayArea);
+
+ ASSERT_NO_FATAL_FAILURE(function(this, display, layer,
+ &testLayer, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
+
+ ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer));
+
+ ASSERT_NO_FATAL_FAILURE(function(this, display, layer + 1,
+ &testLayer, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
+
+ ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer));
+
+ ASSERT_NO_FATAL_FAILURE(function(this, display, layer,
+ &testLayer, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
+ }
+ }
+ }
+
+ /* For each active display it cycles through each display config and tests
+ * each property value. It creates a layer, sets a bad property value and
+ * then destroys the layer */
+ void setLayerPropertyBadParameter(TestLayerPropertyBadParameterFunction function)
+ {
+ for (auto display : mDisplays) {
+ std::vector<hwc2_config_t> configs;
+
+ ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
+
+ for (auto config : configs) {
+ hwc2_layer_t layer;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
+
+ ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer));
+
+ ASSERT_NO_FATAL_FAILURE(function(this, display, layer, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong"
+ " error code";
+
+ ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer));
+ }
+ }
+ }
+
+ /* For each active display it powers on the display, cycles through each
+ * config and creates a set of layers with a certain amount of coverage.
+ * For each active display, for each config and for each set of layers,
+ * it calls the TestDisplayLayersFunction */
+ void displayLayers(Hwc2TestCoverage coverage, size_t layerCnt,
+ TestDisplayLayersFunction function)
+ {
+ for (auto display : mDisplays) {
+ std::vector<hwc2_config_t> configs;
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
+
+ ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
+
+ for (auto config : configs) {
+ Area displayArea;
+ std::vector<hwc2_layer_t> layers;
+
+ ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
+ ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display, &displayArea));
+
+ ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers, layerCnt));
+ Hwc2TestLayers testLayers(layers, coverage, displayArea);
+
+ do {
+ bool skip;
+
+ ASSERT_NO_FATAL_FAILURE(setLayerProperties(display, layers,
+ &testLayers, &skip));
+ if (!skip)
+ EXPECT_NO_FATAL_FAILURE(function(this, display, layers,
+ &testLayers));
+
+ } while (testLayers.advance());
+
+ ASSERT_NO_FATAL_FAILURE(destroyLayers(display,
+ std::move(layers)));
+ }
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
+ }
+ }
+
+ /* For each active display, it calls the
+ * TestDisplayNonValidatedLayersFunction on a variety on non-validated
+ * layer combinations */
+ void displayNonValidatedLayers(size_t layerCnt,
+ TestDisplayNonValidatedLayersFunction function)
+ {
+ for (auto display : mDisplays) {
+ uint32_t numTypes, numRequests;
+ std::vector<hwc2_layer_t> layers;
+ bool hasChanges;
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
+
+ EXPECT_NO_FATAL_FAILURE(function(this, display, &layers));
+
+ ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers, layerCnt));
+
+ EXPECT_NO_FATAL_FAILURE(function(this, display, &layers));
+
+ for (auto layer : layers) {
+ ASSERT_NO_FATAL_FAILURE(setLayerCompositionType(display, layer,
+ HWC2_COMPOSITION_CLIENT));
+ }
+
+ EXPECT_NO_FATAL_FAILURE(function(this, display, &layers));
+
+ ASSERT_NO_FATAL_FAILURE(validateDisplay(display, &numTypes,
+ &numRequests, &hasChanges));
+
+ for (auto layer : layers) {
+ ASSERT_NO_FATAL_FAILURE(setLayerCompositionType(display, layer,
+ HWC2_COMPOSITION_DEVICE));
+ }
+
+ EXPECT_NO_FATAL_FAILURE(function(this, display, &layers));
+
+ ASSERT_NO_FATAL_FAILURE(destroyLayers(display, std::move(layers)));
+
+ EXPECT_NO_FATAL_FAILURE(function(this, display, &layers));
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
+ }
+ }
+
+ /* Test client target support on each config on each active display */
+ void setClientTargetSupport(Hwc2TestCoverage coverage,
+ TestClientTargetSupportFunction function,
+ AdvanceClientTargetSupport advance)
+ {
+ for (auto display : mDisplays) {
+ std::vector<hwc2_config_t> configs;
+
+ ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
+
+ for (auto config : configs) {
+ Area displayArea;
+
+ ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
+ ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display,
+ &displayArea));
+ Hwc2TestClientTargetSupport testClientTargetSupport(coverage,
+ displayArea);
+
+ do {
+ EXPECT_NO_FATAL_FAILURE(function(this, display,
+ testClientTargetSupport));
+
+ } while (advance(&testClientTargetSupport));
+ }
+ }
+ }
+
+ /* Cycles through each config on each active display and calls
+ * a TestActiveDisplayConfigFunction */
+ void setActiveDisplayConfig(TestActiveDisplayConfigFunction function)
+ {
+ for (auto display : mDisplays) {
+ std::vector<hwc2_config_t> configs;
+
+ ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
+
+ for (auto config : configs) {
+ ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
+
+ EXPECT_NO_FATAL_FAILURE(function(this, display));
+ }
+ }
+ }
+
+ /* Creates a virtual display for testing */
+ void createVirtualDisplay(Hwc2TestCoverage coverage,
+ TestCreateVirtualDisplayFunction function)
+ {
+ Hwc2TestVirtualDisplay testVirtualDisplay(coverage);
+
+ do {
+ hwc2_display_t display;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ const UnsignedArea& dimension =
+ testVirtualDisplay.getDisplayDimension();
+ android_pixel_format_t desiredFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+
+ ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(dimension.width,
+ dimension.height, &desiredFormat, &display, &err));
+
+ EXPECT_TRUE(err == HWC2_ERROR_NONE || err == HWC2_ERROR_NO_RESOURCES
+ || err == HWC2_ERROR_UNSUPPORTED)
+ << "returned wrong error code";
+ EXPECT_GE(desiredFormat, 0) << "invalid format";
+
+ if (err != HWC2_ERROR_NONE)
+ continue;
+
+ EXPECT_NO_FATAL_FAILURE(function(this, display,
+ &testVirtualDisplay));
+
+ ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display));
+
+ } while (testVirtualDisplay.advance());
+ }
+
+
+ void getActiveConfigAttribute(hwc2_display_t display,
+ hwc2_attribute_t attribute, int32_t* outValue)
+ {
+ hwc2_config_t config;
+ ASSERT_NO_FATAL_FAILURE(getActiveConfig(display, &config));
+ ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config,
+ attribute, outValue));
+ ASSERT_GE(*outValue, 0) << "failed to get valid "
+ << getAttributeName(attribute);
+ }
+
+ void getActiveDisplayArea(hwc2_display_t display, Area* displayArea)
+ {
+ ASSERT_NO_FATAL_FAILURE(getActiveConfigAttribute(display,
+ HWC2_ATTRIBUTE_WIDTH, &displayArea->width));
+ ASSERT_NO_FATAL_FAILURE(getActiveConfigAttribute(display,
+ HWC2_ATTRIBUTE_HEIGHT, &displayArea->height));
+ }
+
+ void closeFences(hwc2_display_t display, int32_t presentFence)
+ {
+ std::vector<hwc2_layer_t> layers;
+ std::vector<int32_t> fences;
+ const int msWait = 3000;
+
+ if (presentFence >= 0) {
+ ASSERT_GE(sync_wait(presentFence, msWait), 0);
+ close(presentFence);
+ }
+
+ ASSERT_NO_FATAL_FAILURE(getReleaseFences(display, &layers, &fences));
+ EXPECT_EQ(layers.size(), fences.size());
+
+ for (int32_t fence : fences) {
+ EXPECT_GE(sync_wait(fence, msWait), 0);
+ if (fence >= 0)
+ close(fence);
+ }
+ }
+
+ void setLayerProperties(hwc2_display_t display, hwc2_layer_t layer,
+ Hwc2TestLayers* testLayers, bool* outSkip)
+ {
+ hwc2_composition_t composition;
+ buffer_handle_t handle = nullptr;
+ int32_t acquireFence;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+ *outSkip = true;
+
+ if (!testLayers->contains(layer))
+ return;
+
+ composition = testLayers->getComposition(layer);
+
+ /* If the device cannot support a buffer format, then do not continue */
+ if ((composition == HWC2_COMPOSITION_DEVICE
+ || composition == HWC2_COMPOSITION_CURSOR)
+ && testLayers->getBuffer(layer, &handle, &acquireFence) < 0)
+ return;
+
+ EXPECT_NO_FATAL_FAILURE(setLayerCompositionType(display, layer,
+ composition, &err));
+ if (err == HWC2_ERROR_UNSUPPORTED)
+ EXPECT_TRUE(composition != HWC2_COMPOSITION_CLIENT
+ && composition != HWC2_COMPOSITION_DEVICE);
+
+ const hwc_rect_t cursor = testLayers->getCursorPosition(layer);
+
+ EXPECT_NO_FATAL_FAILURE(setLayerBuffer(display, layer, handle,
+ acquireFence));
+ EXPECT_NO_FATAL_FAILURE(setLayerBlendMode(display, layer,
+ testLayers->getBlendMode(layer)));
+ EXPECT_NO_FATAL_FAILURE(setLayerColor(display, layer,
+ testLayers->getColor(layer)));
+ EXPECT_NO_FATAL_FAILURE(setCursorPosition(display, layer, cursor.left,
+ cursor.top));
+ EXPECT_NO_FATAL_FAILURE(setLayerDataspace(display, layer,
+ testLayers->getDataspace(layer)));
+ EXPECT_NO_FATAL_FAILURE(setLayerDisplayFrame(display, layer,
+ testLayers->getDisplayFrame(layer)));
+ EXPECT_NO_FATAL_FAILURE(setLayerPlaneAlpha(display, layer,
+ testLayers->getPlaneAlpha(layer)));
+ EXPECT_NO_FATAL_FAILURE(setLayerSourceCrop(display, layer,
+ testLayers->getSourceCrop(layer)));
+ EXPECT_NO_FATAL_FAILURE(setLayerSurfaceDamage(display, layer,
+ testLayers->getSurfaceDamage(layer)));
+ EXPECT_NO_FATAL_FAILURE(setLayerTransform(display, layer,
+ testLayers->getTransform(layer)));
+ EXPECT_NO_FATAL_FAILURE(setLayerVisibleRegion(display, layer,
+ testLayers->getVisibleRegion(layer)));
+ EXPECT_NO_FATAL_FAILURE(setLayerZOrder(display, layer,
+ testLayers->getZOrder(layer)));
+
+ *outSkip = false;
+ }
+
+ void setLayerProperties(hwc2_display_t display,
+ const std::vector<hwc2_layer_t>& layers,
+ Hwc2TestLayers* testLayers, bool* outSkip)
+ {
+ for (auto layer : layers) {
+ EXPECT_NO_FATAL_FAILURE(setLayerProperties(display, layer,
+ testLayers, outSkip));
+ if (*outSkip)
+ return;
+ }
+ }
+
+ void setClientTarget(hwc2_display_t display,
+ Hwc2TestClientTarget* testClientTarget,
+ const Hwc2TestLayers& testLayers,
+ const std::set<hwc2_layer_t>& clientLayers,
+ const std::set<hwc2_layer_t>& clearLayers, bool flipClientTarget,
+ const Area& displayArea)
+ {
+ android_dataspace_t dataspace = HAL_DATASPACE_UNKNOWN;
+ hwc_region_t damage = { };
+ buffer_handle_t handle;
+ int32_t acquireFence;
+
+ ASSERT_EQ(testClientTarget->getBuffer(testLayers, clientLayers,
+ clearLayers, flipClientTarget, displayArea, &handle,
+ &acquireFence), 0);
+ EXPECT_NO_FATAL_FAILURE(setClientTarget(display, handle, acquireFence,
+ dataspace, damage));
+ }
+
+ void presentDisplays(size_t layerCnt, Hwc2TestCoverage coverage,
+ const std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage>&
+ coverageExceptions, bool optimize)
+ {
+ for (auto display : mDisplays) {
+ std::vector<hwc2_config_t> configs;
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
+ ASSERT_NO_FATAL_FAILURE(enableVsync(display));
+
+ ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
+
+ for (auto config : configs) {
+ Area displayArea;
+ std::vector<hwc2_layer_t> layers;
+
+ ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
+ ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display,
+ &displayArea));
+
+ ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers, layerCnt));
+ Hwc2TestLayers testLayers(layers, coverage, displayArea,
+ coverageExceptions);
+
+ if (optimize && !testLayers.optimizeLayouts())
+ continue;
+
+ std::set<hwc2_layer_t> clientLayers;
+ std::set<hwc2_layer_t> clearLayers;
+ Hwc2TestClientTarget testClientTarget;
+
+ do {
+ uint32_t numTypes, numRequests;
+ bool hasChanges, skip;
+ bool flipClientTarget;
+ int32_t presentFence;
+
+ ASSERT_NO_FATAL_FAILURE(setLayerProperties(display, layers,
+ &testLayers, &skip));
+ if (skip)
+ continue;
+
+ ASSERT_NO_FATAL_FAILURE(validateDisplay(display, &numTypes,
+ &numRequests, &hasChanges));
+ if (hasChanges)
+ EXPECT_LE(numTypes, static_cast<uint32_t>(layers.size()))
+ << "wrong number of requests";
+
+ ASSERT_NO_FATAL_FAILURE(handleCompositionChanges(display,
+ testLayers, layers, numTypes, &clientLayers));
+ ASSERT_NO_FATAL_FAILURE(handleRequests(display, layers,
+ numRequests, &clearLayers, &flipClientTarget));
+ ASSERT_NO_FATAL_FAILURE(setClientTarget(display,
+ &testClientTarget, testLayers, clientLayers,
+ clearLayers, flipClientTarget, displayArea));
+ ASSERT_NO_FATAL_FAILURE(acceptDisplayChanges(display));
+
+ ASSERT_NO_FATAL_FAILURE(waitForVsync());
+
+ EXPECT_NO_FATAL_FAILURE(presentDisplay(display,
+ &presentFence));
+
+ ASSERT_NO_FATAL_FAILURE(closeFences(display, presentFence));
+
+ } while (testLayers.advance());
+
+ ASSERT_NO_FATAL_FAILURE(destroyLayers(display,
+ std::move(layers)));
+ }
+
+ ASSERT_NO_FATAL_FAILURE(disableVsync(display));
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
+ }
+ }
+
+ hwc2_device_t* mHwc2Device = nullptr;
+
+ enum class Hwc2TestHotplugStatus {
+ Init = 1,
+ Receiving,
+ Done,
+ };
+
+ std::mutex mHotplugMutex;
+ std::condition_variable mHotplugCv;
+ Hwc2TestHotplugStatus mHotplugStatus = Hwc2TestHotplugStatus::Init;
+ std::unordered_set<hwc2_display_t> mDisplays;
+
+ /* Store all created layers that have not been destroyed. If an ASSERT_*
+ * fails, then destroy the layers on exit */
+ std::set<std::pair<hwc2_display_t, hwc2_layer_t>> mLayers;
+
+ /* Store the power mode state. If it is not HWC2_POWER_MODE_OFF when
+ * tearing down the test cases, change it to HWC2_POWER_MODE_OFF */
+ std::set<hwc2_display_t> mActiveDisplays;
+
+ /* Store all created virtual displays that have not been destroyed. If an
+ * ASSERT_* fails, then destroy the virtual displays on exit */
+ std::set<hwc2_display_t> mVirtualDisplays;
+
+ std::mutex mVsyncMutex;
+ std::condition_variable mVsyncCv;
+ hwc2_display_t mVsyncDisplay;
+ int64_t mVsyncTimestamp = -1;
+};
+
+void hwc2TestHotplugCallback(hwc2_callback_data_t callbackData,
+ hwc2_display_t display, int32_t connection)
+{
+ if (callbackData)
+ static_cast<Hwc2Test*>(callbackData)->hotplugCallback(display,
+ connection);
+}
+
+void hwc2TestVsyncCallback(hwc2_callback_data_t callbackData,
+ hwc2_display_t display, int64_t timestamp)
+{
+ if (callbackData)
+ static_cast<Hwc2Test*>(callbackData)->vsyncCallback(display,
+ timestamp);
+}
+
+void setBlendMode(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
+ Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
+{
+ EXPECT_NO_FATAL_FAILURE(test->setLayerBlendMode(display, layer,
+ testLayer->getBlendMode(), outErr));
+}
+
+void setBuffer(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
+ Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
+{
+ buffer_handle_t handle;
+ android::base::unique_fd acquireFence;
+ hwc2_composition_t composition = testLayer->getComposition();
+
+ if (composition == HWC2_COMPOSITION_CLIENT
+ || composition == HWC2_COMPOSITION_SOLID_COLOR
+ || composition == HWC2_COMPOSITION_SIDEBAND)
+ return;
+
+ if (testLayer->getBuffer(&handle, &acquireFence) < 0)
+ return;
+
+ ASSERT_NO_FATAL_FAILURE(test->setLayerCompositionType(display, layer,
+ composition));
+ EXPECT_NO_FATAL_FAILURE(test->setLayerBuffer(display, layer,
+ handle, acquireFence, outErr));
+}
+
+void setColor(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
+ Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
+{
+ ASSERT_NO_FATAL_FAILURE(test->setLayerCompositionType(display,
+ layer, HWC2_COMPOSITION_SOLID_COLOR));
+ ASSERT_NO_FATAL_FAILURE(test->setLayerPlaneAlpha(display,
+ layer, testLayer->getPlaneAlpha()));
+ ASSERT_NO_FATAL_FAILURE(test->setLayerBlendMode(display,
+ layer, testLayer->getBlendMode()));
+ EXPECT_NO_FATAL_FAILURE(test->setLayerColor(display, layer,
+ testLayer->getColor(), outErr));
+}
+
+void setComposition(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
+ Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
+{
+ hwc2_composition_t composition = testLayer->getComposition();
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(test->setLayerCompositionType(display, layer,
+ composition, &err));
+ if (outErr) {
+ *outErr = err;
+ return;
+ }
+
+ if (composition != HWC2_COMPOSITION_SIDEBAND) {
+ EXPECT_EQ(err, HWC2_ERROR_NONE) << "returned wrong error code";
+ } else {
+ EXPECT_TRUE(err == HWC2_ERROR_NONE || err == HWC2_ERROR_UNSUPPORTED)
+ << "returned wrong error code";
+ }
+}
+
+void setCursorPosition(Hwc2Test* test, hwc2_display_t display,
+ hwc2_layer_t layer, Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
+{
+ ASSERT_NO_FATAL_FAILURE(test->setLayerCompositionType(display,
+ layer, HWC2_COMPOSITION_CURSOR));
+
+ const hwc_rect_t cursorPosition = testLayer->getCursorPosition();
+ EXPECT_NO_FATAL_FAILURE(test->setCursorPosition(display, layer,
+ cursorPosition.left, cursorPosition.top, outErr));
+}
+
+void setDataspace(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
+ Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
+{
+ EXPECT_NO_FATAL_FAILURE(test->setLayerDataspace(display, layer,
+ testLayer->getDataspace(), outErr));
+}
+
+void setDisplayFrame(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
+ Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
+{
+ EXPECT_NO_FATAL_FAILURE(test->setLayerDisplayFrame(display, layer,
+ testLayer->getDisplayFrame(), outErr));
+}
+
+void setPlaneAlpha(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
+ Hwc2TestLayer* testLayer, hwc2_error_t *outErr)
+{
+ ASSERT_NO_FATAL_FAILURE(test->setLayerBlendMode(display, layer,
+ testLayer->getBlendMode()));
+ EXPECT_NO_FATAL_FAILURE(test->setLayerPlaneAlpha(display, layer,
+ testLayer->getPlaneAlpha(), outErr));
+}
+
+void setSourceCrop(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
+ Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
+{
+ EXPECT_NO_FATAL_FAILURE(test->setLayerSourceCrop(display, layer,
+ testLayer->getSourceCrop(), outErr));
+}
+
+void setSurfaceDamage(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
+ Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
+{
+ EXPECT_NO_FATAL_FAILURE(test->setLayerSurfaceDamage(display, layer,
+ testLayer->getSurfaceDamage(), outErr));
+}
+
+void setTransform(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
+ Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
+{
+ EXPECT_NO_FATAL_FAILURE(test->setLayerTransform(display, layer,
+ testLayer->getTransform(), outErr));
+}
+
+void setVisibleRegion(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
+ Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
+{
+ EXPECT_NO_FATAL_FAILURE(test->setLayerVisibleRegion(display, layer,
+ testLayer->getVisibleRegion(), outErr));
+}
+
+void setZOrder(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
+ Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
+{
+ EXPECT_NO_FATAL_FAILURE(test->setLayerZOrder(display, layer,
+ testLayer->getZOrder(), outErr));
+}
+
+bool advanceBlendMode(Hwc2TestLayer* testLayer)
+{
+ return testLayer->advanceBlendMode();
+}
+
+bool advanceBuffer(Hwc2TestLayer* testLayer)
+{
+ if (testLayer->advanceComposition())
+ return true;
+ return testLayer->advanceBufferArea();
+}
+
+bool advanceColor(Hwc2TestLayer* testLayer)
+{
+ /* Color depends on blend mode so advance blend mode last so color is not
+ * force to update as often */
+ if (testLayer->advancePlaneAlpha())
+ return true;
+ if (testLayer->advanceColor())
+ return true;
+ return testLayer->advanceBlendMode();
+}
+
+bool advanceComposition(Hwc2TestLayer* testLayer)
+{
+ return testLayer->advanceComposition();
+}
+
+bool advanceCursorPosition(Hwc2TestLayer* testLayer)
+{
+ return testLayer->advanceCursorPosition();
+}
+
+bool advanceDataspace(Hwc2TestLayer* testLayer)
+{
+ return testLayer->advanceDataspace();
+}
+
+bool advanceDisplayFrame(Hwc2TestLayer* testLayer)
+{
+ return testLayer->advanceDisplayFrame();
+}
+
+bool advancePlaneAlpha(Hwc2TestLayer* testLayer)
+{
+ return testLayer->advancePlaneAlpha();
+}
+
+bool advanceSourceCrop(Hwc2TestLayer* testLayer)
+{
+ if (testLayer->advanceSourceCrop())
+ return true;
+ return testLayer->advanceBufferArea();
+}
+
+bool advanceSurfaceDamage(Hwc2TestLayer* testLayer)
+{
+ if (testLayer->advanceSurfaceDamage())
+ return true;
+ return testLayer->advanceBufferArea();
+}
+
+bool advanceTransform(Hwc2TestLayer* testLayer)
+{
+ return testLayer->advanceTransform();
+}
+
+bool advanceVisibleRegions(Hwc2TestLayers* testLayers)
+{
+ return testLayers->advanceVisibleRegions();
+}
+
+bool advanceClientTargetSupport(
+ Hwc2TestClientTargetSupport* testClientTargetSupport)
+{
+ return testClientTargetSupport->advance();
+}
+
+static const std::array<hwc2_function_descriptor_t, 42> requiredFunctions = {{
+ HWC2_FUNCTION_ACCEPT_DISPLAY_CHANGES,
+ HWC2_FUNCTION_CREATE_LAYER,
+ HWC2_FUNCTION_CREATE_VIRTUAL_DISPLAY,
+ HWC2_FUNCTION_DESTROY_LAYER,
+ HWC2_FUNCTION_DESTROY_VIRTUAL_DISPLAY,
+ HWC2_FUNCTION_DUMP,
+ HWC2_FUNCTION_GET_ACTIVE_CONFIG,
+ HWC2_FUNCTION_GET_CHANGED_COMPOSITION_TYPES,
+ HWC2_FUNCTION_GET_CLIENT_TARGET_SUPPORT,
+ HWC2_FUNCTION_GET_COLOR_MODES,
+ HWC2_FUNCTION_GET_DISPLAY_ATTRIBUTE,
+ HWC2_FUNCTION_GET_DISPLAY_CONFIGS,
+ HWC2_FUNCTION_GET_DISPLAY_NAME,
+ HWC2_FUNCTION_GET_DISPLAY_REQUESTS,
+ HWC2_FUNCTION_GET_DISPLAY_TYPE,
+ HWC2_FUNCTION_GET_DOZE_SUPPORT,
+ HWC2_FUNCTION_GET_HDR_CAPABILITIES,
+ HWC2_FUNCTION_GET_MAX_VIRTUAL_DISPLAY_COUNT,
+ HWC2_FUNCTION_GET_RELEASE_FENCES,
+ HWC2_FUNCTION_PRESENT_DISPLAY,
+ HWC2_FUNCTION_REGISTER_CALLBACK,
+ HWC2_FUNCTION_SET_ACTIVE_CONFIG,
+ HWC2_FUNCTION_SET_CLIENT_TARGET,
+ HWC2_FUNCTION_SET_COLOR_MODE,
+ HWC2_FUNCTION_SET_COLOR_TRANSFORM,
+ HWC2_FUNCTION_SET_CURSOR_POSITION,
+ HWC2_FUNCTION_SET_LAYER_BLEND_MODE,
+ HWC2_FUNCTION_SET_LAYER_BUFFER,
+ HWC2_FUNCTION_SET_LAYER_COLOR,
+ HWC2_FUNCTION_SET_LAYER_COMPOSITION_TYPE,
+ HWC2_FUNCTION_SET_LAYER_DATASPACE,
+ HWC2_FUNCTION_SET_LAYER_DISPLAY_FRAME,
+ HWC2_FUNCTION_SET_LAYER_PLANE_ALPHA,
+ HWC2_FUNCTION_SET_LAYER_SOURCE_CROP,
+ HWC2_FUNCTION_SET_LAYER_SURFACE_DAMAGE,
+ HWC2_FUNCTION_SET_LAYER_TRANSFORM,
+ HWC2_FUNCTION_SET_LAYER_VISIBLE_REGION,
+ HWC2_FUNCTION_SET_LAYER_Z_ORDER,
+ HWC2_FUNCTION_SET_OUTPUT_BUFFER,
+ HWC2_FUNCTION_SET_POWER_MODE,
+ HWC2_FUNCTION_SET_VSYNC_ENABLED,
+ HWC2_FUNCTION_VALIDATE_DISPLAY,
+}};
+
+/* TESTCASE: Tests that the HWC2 supports all required functions. */
+TEST_F(Hwc2Test, GET_FUNCTION)
+{
+ for (hwc2_function_descriptor_t descriptor : requiredFunctions) {
+ hwc2_function_pointer_t pfn = getFunction(descriptor);
+ EXPECT_TRUE(pfn) << "failed to get function "
+ << getFunctionDescriptorName(descriptor);
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 fails to retrieve and invalid function. */
+TEST_F(Hwc2Test, GET_FUNCTION_invalid_function)
+{
+ hwc2_function_pointer_t pfn = getFunction(HWC2_FUNCTION_INVALID);
+ EXPECT_FALSE(pfn) << "failed to get invalid function";
+}
+
+/* TESTCASE: Tests that the HWC2 does not return an invalid capability. */
+TEST_F(Hwc2Test, GET_CAPABILITIES)
+{
+ std::vector<hwc2_capability_t> capabilities;
+
+ getCapabilities(&capabilities);
+
+ EXPECT_EQ(std::count(capabilities.begin(), capabilities.end(),
+ HWC2_CAPABILITY_INVALID), 0);
+}
+
+static const std::array<hwc2_callback_descriptor_t, 3> callbackDescriptors = {{
+ HWC2_CALLBACK_HOTPLUG,
+ HWC2_CALLBACK_REFRESH,
+ HWC2_CALLBACK_VSYNC,
+}};
+
+/* TESTCASE: Tests that the HWC2 can successfully register all required
+ * callback functions. */
+TEST_F(Hwc2Test, REGISTER_CALLBACK)
+{
+ hwc2_callback_data_t data = reinterpret_cast<hwc2_callback_data_t>(
+ const_cast<char*>("data"));
+
+ for (auto descriptor : callbackDescriptors) {
+ ASSERT_NO_FATAL_FAILURE(registerCallback(descriptor, data,
+ []() { return; }));
+ }
+}
+
+/* TESTCASE: Test that the HWC2 fails to register invalid callbacks. */
+TEST_F(Hwc2Test, REGISTER_CALLBACK_bad_parameter)
+{
+ hwc2_callback_data_t data = reinterpret_cast<hwc2_callback_data_t>(
+ const_cast<char*>("data"));
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(registerCallback(HWC2_CALLBACK_INVALID, data,
+ []() { return; }, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong error code";
+}
+
+/* TESTCASE: Tests that the HWC2 can register a callback with null data. */
+TEST_F(Hwc2Test, REGISTER_CALLBACK_null_data)
+{
+ hwc2_callback_data_t data = nullptr;
+
+ for (auto descriptor : callbackDescriptors) {
+ ASSERT_NO_FATAL_FAILURE(registerCallback(descriptor, data,
+ []() { return; }));
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 returns the correct display type for each
+ * physical display. */
+TEST_F(Hwc2Test, GET_DISPLAY_TYPE)
+{
+ for (auto display : mDisplays) {
+ hwc2_display_type_t type;
+
+ ASSERT_NO_FATAL_FAILURE(getDisplayType(display, &type));
+ EXPECT_EQ(type, HWC2_DISPLAY_TYPE_PHYSICAL) << "failed to return"
+ " correct display type";
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 returns an error when the display type of a bad
+ * display is requested. */
+TEST_F(Hwc2Test, GET_DISPLAY_TYPE_bad_display)
+{
+ hwc2_display_t display;
+ hwc2_display_type_t type;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
+
+ ASSERT_NO_FATAL_FAILURE(getDisplayType(display, &type, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+}
+
+/* TESTCASE: Tests that the HWC2 can create and destroy layers. */
+TEST_F(Hwc2Test, CREATE_DESTROY_LAYER)
+{
+ for (auto display : mDisplays) {
+ hwc2_layer_t layer;
+
+ ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer));
+
+ ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer));
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 cannot create a layer for a bad display */
+TEST_F(Hwc2Test, CREATE_LAYER_bad_display)
+{
+ hwc2_display_t display;
+ hwc2_layer_t layer;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
+
+ ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+}
+
+/* TESTCASE: Tests that the HWC2 will either support a large number of resources
+ * or will return no resources. */
+TEST_F(Hwc2Test, CREATE_LAYER_no_resources)
+{
+ const size_t layerCnt = 1000;
+
+ for (auto display : mDisplays) {
+ std::vector<hwc2_layer_t> layers;
+
+ ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers, layerCnt));
+
+ ASSERT_NO_FATAL_FAILURE(destroyLayers(display, std::move(layers)));
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 cannot destroy a layer for a bad display */
+TEST_F(Hwc2Test, DESTROY_LAYER_bad_display)
+{
+ hwc2_display_t badDisplay;
+
+ ASSERT_NO_FATAL_FAILURE(getBadDisplay(&badDisplay));
+
+ for (auto display : mDisplays) {
+ hwc2_layer_t layer = 0;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(destroyLayer(badDisplay, layer, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+
+ ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer));
+
+ ASSERT_NO_FATAL_FAILURE(destroyLayer(badDisplay, layer, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+
+ ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer));
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 cannot destory a bad layer */
+TEST_F(Hwc2Test, DESTROY_LAYER_bad_layer)
+{
+ for (auto display : mDisplays) {
+ hwc2_layer_t layer;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(destroyLayer(display, UINT64_MAX / 2, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
+
+ ASSERT_NO_FATAL_FAILURE(destroyLayer(display, 0, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
+
+ ASSERT_NO_FATAL_FAILURE(destroyLayer(display, UINT64_MAX - 1, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
+
+ ASSERT_NO_FATAL_FAILURE(destroyLayer(display, 1, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
+
+ ASSERT_NO_FATAL_FAILURE(destroyLayer(display, UINT64_MAX, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
+
+ ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer));
+
+ ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer + 1, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
+
+ ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer));
+
+ ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
+ }
+}
+
+static const std::array<hwc2_attribute_t, 2> requiredAttributes = {{
+ HWC2_ATTRIBUTE_WIDTH,
+ HWC2_ATTRIBUTE_HEIGHT,
+}};
+
+static const std::array<hwc2_attribute_t, 3> optionalAttributes = {{
+ HWC2_ATTRIBUTE_VSYNC_PERIOD,
+ HWC2_ATTRIBUTE_DPI_X,
+ HWC2_ATTRIBUTE_DPI_Y,
+}};
+
+/* TESTCASE: Tests that the HWC2 can return display attributes for a valid
+ * config. */
+TEST_F(Hwc2Test, GET_DISPLAY_ATTRIBUTE)
+{
+ for (auto display : mDisplays) {
+ std::vector<hwc2_config_t> configs;
+
+ ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
+
+ for (auto config : configs) {
+ int32_t value;
+
+ for (auto attribute : requiredAttributes) {
+ ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config,
+ attribute, &value));
+ EXPECT_GE(value, 0) << "missing required attribute "
+ << getAttributeName(attribute) << " for config "
+ << config;
+ }
+ for (auto attribute : optionalAttributes) {
+ ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config,
+ attribute, &value));
+ }
+ }
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 will return a value of -1 for an invalid
+ * attribute */
+TEST_F(Hwc2Test, GET_DISPLAY_ATTRIBUTE_invalid_attribute)
+{
+ const hwc2_attribute_t attribute = HWC2_ATTRIBUTE_INVALID;
+
+ for (auto display : mDisplays) {
+ std::vector<hwc2_config_t> configs;
+
+ ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
+
+ for (auto config : configs) {
+ int32_t value;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config,
+ attribute, &value, &err));
+ EXPECT_EQ(value, -1) << "failed to return -1 for an invalid"
+ " attribute for config " << config;
+ }
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 will fail to get attributes for a bad display */
+TEST_F(Hwc2Test, GET_DISPLAY_ATTRIBUTE_bad_display)
+{
+ hwc2_display_t display;
+ const hwc2_config_t config = 0;
+ int32_t value;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
+
+ for (auto attribute : requiredAttributes) {
+ ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config, attribute,
+ &value, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+ }
+
+ for (auto attribute : optionalAttributes) {
+ ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config, attribute,
+ &value, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 will fail to get attributes for a bad config */
+TEST_F(Hwc2Test, GET_DISPLAY_ATTRIBUTE_bad_config)
+{
+ for (auto display : mDisplays) {
+ hwc2_config_t config;
+ int32_t value;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(getInvalidConfig(display, &config));
+
+ for (auto attribute : requiredAttributes) {
+ ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config,
+ attribute, &value, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_CONFIG) << "returned wrong error code";
+ }
+
+ for (auto attribute : optionalAttributes) {
+ ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config,
+ attribute, &value, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_CONFIG) << "returned wrong error code";
+ }
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 will get display configs for active displays */
+TEST_F(Hwc2Test, GET_DISPLAY_CONFIGS)
+{
+ for (auto display : mDisplays) {
+ std::vector<hwc2_config_t> configs;
+
+ ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 will not get display configs for bad displays */
+TEST_F(Hwc2Test, GET_DISPLAY_CONFIGS_bad_display)
+{
+ hwc2_display_t display;
+ std::vector<hwc2_config_t> configs;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
+
+ ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs, &err));
+
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+ EXPECT_TRUE(configs.empty()) << "returned configs for bad display";
+}
+
+/* TESTCASE: Tests that the HWC2 will return the same config list multiple
+ * times in a row. */
+TEST_F(Hwc2Test, GET_DISPLAY_CONFIGS_same)
+{
+ for (auto display : mDisplays) {
+ std::vector<hwc2_config_t> configs1, configs2;
+
+ ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs1));
+ ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs2));
+
+ EXPECT_TRUE(std::is_permutation(configs1.begin(), configs1.end(),
+ configs2.begin())) << "returned two different config sets";
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 does not return duplicate display configs */
+TEST_F(Hwc2Test, GET_DISPLAY_CONFIGS_duplicate)
+{
+ for (auto display : mDisplays) {
+ std::vector<hwc2_config_t> configs;
+
+ ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
+
+ std::unordered_set<hwc2_config_t> configsSet(configs.begin(),
+ configs.end());
+ EXPECT_EQ(configs.size(), configsSet.size()) << "returned duplicate"
+ " configs";
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 returns the active config for a display */
+TEST_F(Hwc2Test, GET_ACTIVE_CONFIG)
+{
+ for (auto display : mDisplays) {
+ std::vector<hwc2_config_t> configs;
+
+ ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
+
+ for (auto config : configs) {
+ hwc2_config_t activeConfig;
+
+ ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
+ ASSERT_NO_FATAL_FAILURE(getActiveConfig(display, &activeConfig));
+
+ EXPECT_EQ(activeConfig, config) << "failed to get active config";
+ }
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 does not return an active config for a bad
+ * display. */
+TEST_F(Hwc2Test, GET_ACTIVE_CONFIG_bad_display)
+{
+ hwc2_display_t display;
+ hwc2_config_t activeConfig;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
+
+ ASSERT_NO_FATAL_FAILURE(getActiveConfig(display, &activeConfig, &err));
+
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+}
+
+/* TESTCASE: Tests that the HWC2 either begins with a valid active config
+ * or returns an error when getActiveConfig is called. */
+TEST_F(Hwc2Test, GET_ACTIVE_CONFIG_bad_config)
+{
+ for (auto display : mDisplays) {
+ std::vector<hwc2_config_t> configs;
+ hwc2_config_t activeConfig;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
+
+ if (configs.empty())
+ return;
+
+ ASSERT_NO_FATAL_FAILURE(getActiveConfig(display, &activeConfig, &err));
+ if (err == HWC2_ERROR_NONE) {
+ EXPECT_NE(std::count(configs.begin(), configs.end(),
+ activeConfig), 0) << "active config is not found in "
+ " configs for display";
+ } else {
+ EXPECT_EQ(err, HWC2_ERROR_BAD_CONFIG) << "returned wrong error code";
+ }
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 can set every display config as an active
+ * config */
+TEST_F(Hwc2Test, SET_ACTIVE_CONFIG)
+{
+ for (auto display : mDisplays) {
+ std::vector<hwc2_config_t> configs;
+
+ ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
+
+ for (auto config : configs) {
+ EXPECT_NO_FATAL_FAILURE(setActiveConfig(display, config));
+ }
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 cannot set an active config for a bad display */
+TEST_F(Hwc2Test, SET_ACTIVE_CONFIG_bad_display)
+{
+ hwc2_display_t display;
+ const hwc2_config_t config = 0;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
+
+ ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+}
+
+/* TESTCASE: Tests that the HWC2 cannot set an invalid active config */
+TEST_F(Hwc2Test, SET_ACTIVE_CONFIG_bad_config)
+{
+ for (auto display : mDisplays) {
+ hwc2_config_t config;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(getInvalidConfig(display, &config));
+
+ ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_CONFIG) << "returned wrong error code";
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 returns a valid value for getDozeSupport. */
+TEST_F(Hwc2Test, GET_DOZE_SUPPORT)
+{
+ for (auto display : mDisplays) {
+ int32_t support = -1;
+
+ ASSERT_NO_FATAL_FAILURE(getDozeSupport(display, &support));
+
+ EXPECT_TRUE(support == 0 || support == 1) << "invalid doze support value";
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 cannot get doze support for a bad display. */
+TEST_F(Hwc2Test, GET_DOZE_SUPPORT_bad_display)
+{
+ hwc2_display_t display;
+ int32_t support = -1;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
+
+ ASSERT_NO_FATAL_FAILURE(getDozeSupport(display, &support, &err));
+
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+}
+
+/* TESTCASE: Tests that the HWC2 can set all supported power modes */
+TEST_F(Hwc2Test, SET_POWER_MODE)
+{
+ for (auto display : mDisplays) {
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
+
+ int32_t support = -1;
+ ASSERT_NO_FATAL_FAILURE(getDozeSupport(display, &support));
+ if (support != 1)
+ return;
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_DOZE));
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display,
+ HWC2_POWER_MODE_DOZE_SUSPEND));
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 cannot set a power mode for a bad display. */
+TEST_F(Hwc2Test, SET_POWER_MODE_bad_display)
+{
+ hwc2_display_t display;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+
+ int32_t support = -1;
+ ASSERT_NO_FATAL_FAILURE(getDozeSupport(display, &support, &err));
+ if (support != 1)
+ return;
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_DOZE, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_DOZE_SUSPEND,
+ &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+}
+
+/* TESTCASE: Tests that the HWC2 cannot set an invalid power mode value. */
+TEST_F(Hwc2Test, SET_POWER_MODE_bad_parameter)
+{
+ for (auto display : mDisplays) {
+ hwc2_power_mode_t mode = static_cast<hwc2_power_mode_t>(
+ HWC2_POWER_MODE_DOZE_SUSPEND + 1);
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, mode, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong error code "
+ << mode;
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 will return unsupported if it does not support
+ * an optional power mode. */
+TEST_F(Hwc2Test, SET_POWER_MODE_unsupported)
+{
+ for (auto display : mDisplays) {
+ int32_t support = -1;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(getDozeSupport(display, &support, &err));
+ if (support == 1)
+ return;
+
+ ASSERT_EQ(support, 0) << "invalid doze support value";
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_DOZE,
+ &err));
+ EXPECT_EQ(err, HWC2_ERROR_UNSUPPORTED) << "returned wrong error code";
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display,
+ HWC2_POWER_MODE_DOZE_SUSPEND, &err));
+ EXPECT_EQ(err, HWC2_ERROR_UNSUPPORTED) << "returned wrong error code";
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 can set the same power mode multiple times. */
+TEST_F(Hwc2Test, SET_POWER_MODE_stress)
+{
+ for (auto display : mDisplays) {
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
+
+ int32_t support = -1;
+ ASSERT_NO_FATAL_FAILURE(getDozeSupport(display, &support));
+ if (support != 1)
+ return;
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_DOZE));
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_DOZE));
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display,
+ HWC2_POWER_MODE_DOZE_SUSPEND));
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display,
+ HWC2_POWER_MODE_DOZE_SUSPEND));
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 can enable and disable vsync on active
+ * displays */
+TEST_F(Hwc2Test, SET_VSYNC_ENABLED)
+{
+ for (auto display : mDisplays) {
+ hwc2_callback_data_t data = reinterpret_cast<hwc2_callback_data_t>(
+ const_cast<char*>("data"));
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
+
+ ASSERT_NO_FATAL_FAILURE(registerCallback(HWC2_CALLBACK_VSYNC, data,
+ []() { return; }));
+
+ ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_ENABLE));
+
+ ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE));
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 issues a valid vsync callback. */
+TEST_F(Hwc2Test, SET_VSYNC_ENABLED_callback)
+{
+ for (auto display : mDisplays) {
+ hwc2_display_t receivedDisplay;
+ int64_t receivedTimestamp;
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
+
+ ASSERT_NO_FATAL_FAILURE(enableVsync(display));
+
+ ASSERT_NO_FATAL_FAILURE(waitForVsync(&receivedDisplay,
+ &receivedTimestamp));
+
+ EXPECT_EQ(receivedDisplay, display) << "failed to get correct display";
+ EXPECT_GE(receivedTimestamp, 0) << "failed to get valid timestamp";
+
+ ASSERT_NO_FATAL_FAILURE(disableVsync(display));
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 cannot enable a vsync for a bad display */
+TEST_F(Hwc2Test, SET_VSYNC_ENABLED_bad_display)
+{
+ hwc2_display_t display;
+ hwc2_callback_data_t data = reinterpret_cast<hwc2_callback_data_t>(
+ const_cast<char*>("data"));
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
+
+ ASSERT_NO_FATAL_FAILURE(registerCallback(HWC2_CALLBACK_VSYNC, data,
+ []() { return; }));
+
+ ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_ENABLE, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+
+ ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+}
+
+/* TESTCASE: Tests that the HWC2 cannot enable an invalid vsync value */
+TEST_F(Hwc2Test, SET_VSYNC_ENABLED_bad_parameter)
+{
+ for (auto display : mDisplays) {
+ hwc2_callback_data_t data = reinterpret_cast<hwc2_callback_data_t>(
+ const_cast<char*>("data"));
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
+
+ ASSERT_NO_FATAL_FAILURE(registerCallback(HWC2_CALLBACK_VSYNC, data,
+ []() { return; }));
+
+ ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_INVALID,
+ &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong error code";
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 can enable and disable a vsync value multiple
+ * times. */
+TEST_F(Hwc2Test, SET_VSYNC_ENABLED_stress)
+{
+ for (auto display : mDisplays) {
+ hwc2_callback_data_t data = reinterpret_cast<hwc2_callback_data_t>(
+ const_cast<char*>("data"));
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
+
+ ASSERT_NO_FATAL_FAILURE(registerCallback(HWC2_CALLBACK_VSYNC, data,
+ []() { return; }));
+
+ ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE));
+
+ ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_ENABLE));
+ ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_ENABLE));
+
+ ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE));
+ ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE));
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 can set a vsync enable value when the display
+ * is off and no callback is registered. */
+TEST_F(Hwc2Test, SET_VSYNC_ENABLED_no_callback_no_power)
+{
+ const uint secs = 1;
+
+ for (auto display : mDisplays) {
+ ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_ENABLE));
+
+ sleep(secs);
+
+ ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE));
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 can set a vsync enable value when no callback
+ * is registered. */
+TEST_F(Hwc2Test, SET_VSYNC_ENABLED_no_callback)
+{
+ const uint secs = 1;
+
+ for (auto display : mDisplays) {
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
+
+ ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_ENABLE));
+
+ sleep(secs);
+
+ ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE));
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 returns a display name for each display */
+TEST_F(Hwc2Test, GET_DISPLAY_NAME)
+{
+ for (auto display : mDisplays) {
+ std::string name;
+
+ ASSERT_NO_FATAL_FAILURE(getDisplayName(display, &name));
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 does not return a display name for a bad
+ * display */
+TEST_F(Hwc2Test, GET_DISPLAY_NAME_bad_display)
+{
+ hwc2_display_t display;
+ std::string name;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
+
+ ASSERT_NO_FATAL_FAILURE(getDisplayName(display, &name, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+}
+
+/* TESTCASE: Tests that the HWC2 can set basic composition types. */
+TEST_F(Hwc2Test, SET_LAYER_COMPOSITION_TYPE)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
+ setComposition, advanceComposition));
+}
+
+/* TESTCASE: Tests that the HWC2 can update a basic composition type on a
+ * layer. */
+TEST_F(Hwc2Test, SET_LAYER_COMPOSITION_TYPE_update)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
+ setComposition, advanceComposition));
+}
+
+/* TESTCASE: Tests that the HWC2 cannot set a composition type for a bad layer */
+TEST_F(Hwc2Test, SET_LAYER_COMPOSITION_TYPE_bad_layer)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
+ setComposition));
+}
+
+/* TESTCASE: Tests that the HWC2 cannot set a bad composition type */
+TEST_F(Hwc2Test, SET_LAYER_COMPOSITION_TYPE_bad_parameter)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadParameter(
+ [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
+ hwc2_error_t* outErr) {
+
+ ASSERT_NO_FATAL_FAILURE(test->setLayerCompositionType(display,
+ layer, HWC2_COMPOSITION_INVALID, outErr));
+ }
+ ));
+}
+
+/* TESTCASE: Tests that the HWC2 can set the cursor position of a layer. */
+TEST_F(Hwc2Test, SET_CURSOR_POSITION)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
+ ::setCursorPosition, advanceCursorPosition));
+}
+
+/* TESTCASE: Tests that the HWC2 can update the cursor position of a layer. */
+TEST_F(Hwc2Test, SET_CURSOR_POSITION_update)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
+ ::setCursorPosition, advanceCursorPosition));
+}
+
+/* TESTCASE: Tests that the HWC2 can set the cursor position of a layer when the
+ * composition type has not been set to HWC2_COMPOSITION_CURSOR. */
+TEST_F(Hwc2Test, SET_CURSOR_POSITION_composition_type_unset)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
+ [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
+ Hwc2TestLayer* testLayer, hwc2_error_t* outErr) {
+
+ const hwc_rect_t cursorPosition = testLayer->getCursorPosition();
+ EXPECT_NO_FATAL_FAILURE(test->setCursorPosition(display, layer,
+ cursorPosition.left, cursorPosition.top, outErr));
+ },
+
+ advanceCursorPosition));
+}
+
+/* TESTCASE: Tests that the HWC2 cannot set the cursor position of a bad
+ * display. */
+TEST_F(Hwc2Test, SET_CURSOR_POSITION_bad_display)
+{
+ hwc2_display_t display;
+ hwc2_layer_t layer = 0;
+ int32_t x = 0, y = 0;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
+
+ ASSERT_NO_FATAL_FAILURE(setCursorPosition(display, layer, x, y, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+}
+
+/* TESTCASE: Tests that the HWC2 cannot set the cursor position of a bad layer. */
+TEST_F(Hwc2Test, SET_CURSOR_POSITION_bad_layer)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
+ [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t badLayer,
+ Hwc2TestLayer* testLayer, hwc2_error_t* outErr) {
+
+ const hwc_rect_t cursorPosition = testLayer->getCursorPosition();
+ EXPECT_NO_FATAL_FAILURE(test->setCursorPosition(display,
+ badLayer, cursorPosition.left, cursorPosition.top,
+ outErr));
+ }
+ ));
+}
+
+/* TESTCASE: Tests that the HWC2 can set a blend mode value of a layer. */
+TEST_F(Hwc2Test, SET_LAYER_BLEND_MODE)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
+ setBlendMode, advanceBlendMode));
+}
+
+/* TESTCASE: Tests that the HWC2 can update a blend mode value of a layer. */
+TEST_F(Hwc2Test, SET_LAYER_BLEND_MODE_update)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
+ setBlendMode, advanceBlendMode));
+}
+
+/* TESTCASE: Tests that the HWC2 cannot set a blend mode for a bad layer. */
+TEST_F(Hwc2Test, SET_LAYER_BLEND_MODE_bad_layer)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
+ setBlendMode));
+}
+
+/* TESTCASE: Tests that the HWC2 cannot set an invalid blend mode. */
+TEST_F(Hwc2Test, SET_LAYER_BLEND_MODE_bad_parameter)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadParameter(
+ [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
+ hwc2_error_t* outErr) {
+
+ ASSERT_NO_FATAL_FAILURE(test->setLayerBlendMode(display,
+ layer, HWC2_BLEND_MODE_INVALID, outErr));
+ }
+ ));
+}
+
+/* TESTCASE: Tests that the HWC2 can set the buffer of a layer. */
+TEST_F(Hwc2Test, SET_LAYER_BUFFER)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
+ setBuffer, advanceBuffer));
+}
+
+/* TESTCASE: Tests that the HWC2 can update the buffer of a layer. */
+TEST_F(Hwc2Test, SET_LAYER_BUFFER_update)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
+ setBuffer, advanceBuffer));
+}
+
+/* TESTCASE: Tests that the HWC2 cannot set the buffer of a bad layer. */
+TEST_F(Hwc2Test, SET_LAYER_BUFFER_bad_layer)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
+ [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t badLayer,
+ Hwc2TestLayer* testLayer, hwc2_error_t* outErr) {
+
+ buffer_handle_t handle = nullptr;
+ android::base::unique_fd acquireFence;
+
+ /* If there is not available buffer for the given buffer
+ * properties, it should not fail this test case */
+ if (testLayer->getBuffer(&handle, &acquireFence) == 0) {
+ *outErr = HWC2_ERROR_BAD_LAYER;
+ return;
+ }
+
+ ASSERT_NO_FATAL_FAILURE(test->setLayerBuffer(display, badLayer,
+ handle, acquireFence, outErr));
+ }
+ ));
+}
+
+/* TESTCASE: Tests that the HWC2 can set an invalid buffer for a layer. */
+TEST_F(Hwc2Test, SET_LAYER_BUFFER_bad_parameter)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadParameter(
+ [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
+ hwc2_error_t* outErr) {
+
+ buffer_handle_t handle = nullptr;
+ int32_t acquireFence = -1;
+
+ ASSERT_NO_FATAL_FAILURE(test->setLayerBuffer(display, layer,
+ handle, acquireFence, outErr));
+ }
+ ));
+}
+
+/* TESTCASE: Tests that the HWC2 can set the color of a layer. */
+TEST_F(Hwc2Test, SET_LAYER_COLOR)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
+ setColor, advanceColor));
+}
+
+/* TESTCASE: Tests that the HWC2 can update the color of a layer. */
+TEST_F(Hwc2Test, SET_LAYER_COLOR_update)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
+ setColor, advanceColor));
+}
+
+/* TESTCASE: Tests that the HWC2 can set the color of a layer when the
+ * composition type has not been set to HWC2_COMPOSITION_SOLID_COLOR. */
+TEST_F(Hwc2Test, SET_LAYER_COLOR_composition_type_unset)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Basic,
+ [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
+ Hwc2TestLayer* testLayer, hwc2_error_t* outErr) {
+
+ EXPECT_NO_FATAL_FAILURE(test->setLayerColor(display, layer,
+ testLayer->getColor(), outErr));
+ },
+
+ advanceColor));
+}
+
+/* TESTCASE: Tests that the HWC2 cannot set the color of a bad layer. */
+TEST_F(Hwc2Test, SET_LAYER_COLOR_bad_layer)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
+ [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t badLayer,
+ Hwc2TestLayer* testLayer, hwc2_error_t* outErr) {
+
+ EXPECT_NO_FATAL_FAILURE(test->setLayerColor(display, badLayer,
+ testLayer->getColor(), outErr));
+ }
+ ));
+}
+
+/* TESTCASE: Tests that the HWC2 can set the dataspace of a layer. */
+TEST_F(Hwc2Test, SET_LAYER_DATASPACE)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
+ setDataspace, advanceDataspace));
+}
+
+/* TESTCASE: Tests that the HWC2 can update the dataspace of a layer. */
+TEST_F(Hwc2Test, SET_LAYER_DATASPACE_update)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
+ setDataspace, advanceDataspace));
+}
+
+/* TESTCASE: Tests that the HWC2 cannot set a dataspace for a bad layer. */
+TEST_F(Hwc2Test, SET_LAYER_DATASPACE_bad_layer)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
+ setDataspace));
+}
+
+/* TESTCASE: Tests that the HWC2 can set the display frame of a layer. */
+TEST_F(Hwc2Test, SET_LAYER_DISPLAY_FRAME)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
+ setDisplayFrame, advanceDisplayFrame));
+}
+
+/* TESTCASE: Tests that the HWC2 can update the display frame of a layer. */
+TEST_F(Hwc2Test, SET_LAYER_DISPLAY_FRAME_update)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
+ setDisplayFrame, advanceDisplayFrame));
+}
+
+/* TESTCASE: Tests that the HWC2 cannot set the display frame of a bad layer. */
+TEST_F(Hwc2Test, SET_LAYER_DISPLAY_FRAME_bad_layer)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
+ setDisplayFrame));
+}
+
+/* TESTCASE: Tests that the HWC2 can set the plane alpha of a layer. */
+TEST_F(Hwc2Test, SET_LAYER_PLANE_ALPHA)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
+ setPlaneAlpha, advancePlaneAlpha));
+}
+
+/* TESTCASE: Tests that the HWC2 can update the plane alpha of a layer. */
+TEST_F(Hwc2Test, SET_LAYER_PLANE_ALPHA_update)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
+ setPlaneAlpha, advancePlaneAlpha));
+}
+
+/* TESTCASE: Tests that the HWC2 cannot set a plane alpha for a bad layer. */
+TEST_F(Hwc2Test, SET_LAYER_PLANE_ALPHA_bad_layer)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
+ [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t badLayer,
+ Hwc2TestLayer* testLayer, hwc2_error_t *outErr) {
+
+ EXPECT_NO_FATAL_FAILURE(test->setLayerPlaneAlpha(display,
+ badLayer, testLayer->getPlaneAlpha(), outErr));
+ }
+ ));
+}
+
+/* TESTCASE: Tests that the HWC2 can set the source crop of a layer. */
+TEST_F(Hwc2Test, SET_LAYER_SOURCE_CROP)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
+ setSourceCrop, advanceSourceCrop));
+}
+
+/* TESTCASE: Tests that the HWC2 can update the source crop of a layer. */
+TEST_F(Hwc2Test, SET_LAYER_SOURCE_CROP_update)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
+ setSourceCrop, advanceSourceCrop));
+}
+
+/* TESTCASE: Tests that the HWC2 cannot set the source crop of a bad layer. */
+TEST_F(Hwc2Test, SET_LAYER_SOURCE_CROP_bad_layer)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
+ setSourceCrop));
+}
+
+/* TESTCASE: Tests that the HWC2 can set the surface damage of a layer. */
+TEST_F(Hwc2Test, SET_LAYER_SURFACE_DAMAGE)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
+ setSurfaceDamage, advanceSurfaceDamage));
+}
+
+/* TESTCASE: Tests that the HWC2 can update the surface damage of a layer. */
+TEST_F(Hwc2Test, SET_LAYER_SURFACE_DAMAGE_update)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
+ setSurfaceDamage, advanceSurfaceDamage));
+}
+
+/* TESTCASE: Tests that the HWC2 cannot set the surface damage of a bad layer. */
+TEST_F(Hwc2Test, SET_LAYER_SURFACE_DAMAGE_bad_layer)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
+ setSurfaceDamage));
+}
+
+/* TESTCASE: Tests that the HWC2 can set the transform value of a layer. */
+TEST_F(Hwc2Test, SET_LAYER_TRANSFORM)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
+ setTransform, advanceTransform));
+}
+
+/* TESTCASE: Tests that the HWC2 can update the transform value of a layer. */
+TEST_F(Hwc2Test, SET_LAYER_TRANSFORM_update)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
+ setTransform, advanceTransform));
+}
+
+/* TESTCASE: Tests that the HWC2 cannot set the transform for a bad layer. */
+TEST_F(Hwc2Test, SET_LAYER_TRANSFORM_bad_layer)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
+ setTransform));
+}
+
+/* TESTCASE: Tests that the HWC2 can set the visible region of a layer. */
+TEST_F(Hwc2Test, SET_LAYER_VISIBLE_REGION)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerProperties(Hwc2TestCoverage::Basic, 5,
+ [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
+ Hwc2TestLayers* testLayers) {
+
+ EXPECT_NO_FATAL_FAILURE(test->setLayerVisibleRegion(display,
+ layer, testLayers->getVisibleRegion(layer)));
+ },
+
+ advanceVisibleRegions));
+}
+
+/* TESTCASE: Tests that the HWC2 cannot set the visible region of a bad layer. */
+TEST_F(Hwc2Test, SET_LAYER_VISIBLE_REGION_bad_layer)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
+ setVisibleRegion));
+}
+
+/* TESTCASE: Tests that the HWC2 can set the z order of a layer. */
+TEST_F(Hwc2Test, SET_LAYER_Z_ORDER)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerProperties(Hwc2TestCoverage::Complete, 10,
+ [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
+ Hwc2TestLayers* testLayers) {
+
+ EXPECT_NO_FATAL_FAILURE(test->setLayerZOrder(display, layer,
+ testLayers->getZOrder(layer)));
+ },
+
+ /* TestLayer z orders are set during the construction of TestLayers
+ * and cannot be updated. There is no need (or ability) to cycle
+ * through additional z order configurations. */
+ [] (Hwc2TestLayers* /*testLayers*/) {
+ return false;
+ }
+ ));
+}
+
+/* TESTCASE: Tests that the HWC2 can update the z order of a layer. */
+TEST_F(Hwc2Test, SET_LAYER_Z_ORDER_update)
+{
+ const std::vector<uint32_t> zOrders = { static_cast<uint32_t>(0),
+ static_cast<uint32_t>(1), static_cast<uint32_t>(UINT32_MAX / 4),
+ static_cast<uint32_t>(UINT32_MAX / 2),
+ static_cast<uint32_t>(UINT32_MAX) };
+
+ for (auto display : mDisplays) {
+ std::vector<hwc2_config_t> configs;
+
+ ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
+
+ for (auto config : configs) {
+ hwc2_layer_t layer;
+
+ ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
+
+ ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer));
+
+ for (uint32_t zOrder : zOrders) {
+ EXPECT_NO_FATAL_FAILURE(setLayerZOrder(display, layer, zOrder));
+ }
+
+ ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer));
+ }
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 cannot set the z order of a bad layer. */
+TEST_F(Hwc2Test, SET_LAYER_Z_ORDER_bad_layer)
+{
+ ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
+ setZOrder));
+}
+
+/* TESTCASE: Tests that the HWC2 can display a layer with basic property
+ * coverage */
+TEST_F(Hwc2Test, VALIDATE_DISPLAY_basic)
+{
+ ASSERT_NO_FATAL_FAILURE(displayLayers(Hwc2TestCoverage::Basic, 1,
+ [] (Hwc2Test* test, hwc2_display_t display,
+ const std::vector<hwc2_layer_t>& layers,
+ Hwc2TestLayers* /*testLayers*/) {
+
+ uint32_t numTypes, numRequests;
+ bool hasChanges = false;
+
+ EXPECT_NO_FATAL_FAILURE(test->validateDisplay(display, &numTypes,
+ &numRequests, &hasChanges));
+ if (hasChanges)
+ EXPECT_LE(numTypes, static_cast<uint32_t>(layers.size()))
+ << "wrong number of requests";
+ }
+ ));
+}
+
+/* TESTCASE: Tests that the HWC2 can display 5 layers with default coverage. */
+TEST_F(Hwc2Test, VALIDATE_DISPLAY_default_5)
+{
+ ASSERT_NO_FATAL_FAILURE(displayLayers(Hwc2TestCoverage::Default, 5,
+ [] (Hwc2Test* test, hwc2_display_t display,
+ const std::vector<hwc2_layer_t>& layers,
+ Hwc2TestLayers* /*testLayers*/) {
+
+ uint32_t numTypes, numRequests;
+ bool hasChanges = false;
+
+ EXPECT_NO_FATAL_FAILURE(test->validateDisplay(display, &numTypes,
+ &numRequests, &hasChanges));
+ if (hasChanges)
+ EXPECT_LE(numTypes, static_cast<uint32_t>(layers.size()))
+ << "wrong number of requests";
+ }
+ ));
+}
+
+/* TESTCASE: Tests that the HWC2 cannot validate a bad display */
+TEST_F(Hwc2Test, VALIDATE_DISPLAY_bad_display)
+{
+ hwc2_display_t display;
+ uint32_t numTypes, numRequests;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
+
+ ASSERT_NO_FATAL_FAILURE(validateDisplay(display, &numTypes, &numRequests,
+ &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+}
+
+/* TESTCASE: Tests that the HWC2 can get display requests after validating a
+ * basic layer. */
+TEST_F(Hwc2Test, GET_DISPLAY_REQUESTS_basic)
+{
+ ASSERT_NO_FATAL_FAILURE(displayLayers(Hwc2TestCoverage::Basic, 1,
+ [] (Hwc2Test* test, hwc2_display_t display,
+ const std::vector<hwc2_layer_t>& layers,
+ Hwc2TestLayers* /*testLayers*/) {
+
+ uint32_t numTypes, numRequests;
+ bool hasChanges = false;
+
+ ASSERT_NO_FATAL_FAILURE(test->validateDisplay(display, &numTypes,
+ &numRequests, &hasChanges));
+ if (hasChanges)
+ EXPECT_LE(numTypes, layers.size())
+ << "wrong number of requests";
+
+ EXPECT_NO_FATAL_FAILURE(test->handleRequests(display, layers,
+ numRequests));
+ }
+ ));
+}
+
+/* TESTCASE: Tests that the HWC2 cannot get display requests from a bad display */
+TEST_F(Hwc2Test, GET_DISPLAY_REQUESTS_bad_display)
+{
+ hwc2_display_t display;
+ hwc2_display_request_t displayRequests;
+ std::vector<hwc2_layer_t> layers;
+ std::vector<hwc2_layer_request_t> layerRequests;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
+
+ EXPECT_NO_FATAL_FAILURE(getDisplayRequests(display, &displayRequests,
+ &layers, &layerRequests, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+}
+
+/* TESTCASE: Tests that the HWC2 cannot get display requests from an non
+ * validated display. */
+TEST_F(Hwc2Test, GET_DISPLAY_REQUESTS_not_validated)
+{
+ ASSERT_NO_FATAL_FAILURE(displayNonValidatedLayers(5,
+ [] (Hwc2Test* test, hwc2_display_t display,
+ std::vector<hwc2_layer_t>* layers) {
+
+ hwc2_display_request_t displayRequests;
+ std::vector<hwc2_layer_request_t> layerRequests;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(test->getDisplayRequests(display,
+ &displayRequests, layers, &layerRequests, &err));
+ EXPECT_EQ(err, HWC2_ERROR_NOT_VALIDATED)
+ << "returned wrong error code";
+ }
+ ));
+}
+
+/* TESTCASE: Tests that the HWC2 can get changed composition types after
+ * validating a basic layer. */
+TEST_F(Hwc2Test, GET_CHANGED_COMPOSITION_TYPES_basic)
+{
+ ASSERT_NO_FATAL_FAILURE(displayLayers(Hwc2TestCoverage::Basic, 1,
+ [] (Hwc2Test* test, hwc2_display_t display,
+ const std::vector<hwc2_layer_t>& layers,
+ Hwc2TestLayers* testLayers) {
+
+ uint32_t numTypes, numRequests;
+ bool hasChanges = false;
+
+ ASSERT_NO_FATAL_FAILURE(test->validateDisplay(display, &numTypes,
+ &numRequests, &hasChanges));
+ if (hasChanges)
+ EXPECT_LE(numTypes, layers.size())
+ << "wrong number of requests";
+
+ EXPECT_NO_FATAL_FAILURE(test->handleCompositionChanges(display,
+ *testLayers, layers, numTypes));
+ }
+ ));
+}
+
+/* TESTCASE: Tests that the HWC2 cannot get changed composition types from a bad
+ * display */
+TEST_F(Hwc2Test, GET_CHANGED_COMPOSITION_TYPES_bad_display)
+{
+ hwc2_display_t display;
+ std::vector<hwc2_layer_t> layers;
+ std::vector<hwc2_composition_t> types;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
+
+ EXPECT_NO_FATAL_FAILURE(getChangedCompositionTypes(display, &layers,
+ &types, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+}
+
+/* TESTCASE: Tests that the HWC2 cannot get changed composition types from an non
+ * validated display. */
+TEST_F(Hwc2Test, GET_CHANGED_COMPOSITION_TYPES_not_validated)
+{
+ ASSERT_NO_FATAL_FAILURE(displayNonValidatedLayers(5,
+ [] (Hwc2Test* test, hwc2_display_t display,
+ std::vector<hwc2_layer_t>* layers) {
+
+ std::vector<hwc2_composition_t> types;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(test->getChangedCompositionTypes(
+ display, layers, &types, &err));
+ EXPECT_EQ(err, HWC2_ERROR_NOT_VALIDATED)
+ << "returned wrong error code";
+ }
+ ));
+}
+
+/* TESTCASE: Tests that the HWC2 can accept display changes after validating a
+ * basic layer. */
+TEST_F(Hwc2Test, ACCEPT_DISPLAY_CHANGES_basic)
+{
+ ASSERT_NO_FATAL_FAILURE(displayLayers(Hwc2TestCoverage::Basic, 1,
+ [] (Hwc2Test* test, hwc2_display_t display,
+ const std::vector<hwc2_layer_t>& layers,
+ Hwc2TestLayers* testLayers) {
+
+ uint32_t numTypes, numRequests;
+ bool hasChanges = false;
+
+ ASSERT_NO_FATAL_FAILURE(test->validateDisplay(display, &numTypes,
+ &numRequests, &hasChanges));
+ if (hasChanges)
+ EXPECT_LE(numTypes, layers.size())
+ << "wrong number of requests";
+
+ ASSERT_NO_FATAL_FAILURE(test->handleCompositionChanges(display,
+ *testLayers, layers, numTypes));
+
+ EXPECT_NO_FATAL_FAILURE(test->acceptDisplayChanges(display));
+ }
+ ));
+}
+
+/* TESTCASE: Tests that the HWC2 cannot accept display changes from a bad
+ * display */
+TEST_F(Hwc2Test, ACCEPT_DISPLAY_CHANGES_bad_display)
+{
+ hwc2_display_t display;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
+
+ EXPECT_NO_FATAL_FAILURE(acceptDisplayChanges(display, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+}
+
+/* TESTCASE: Tests that the HWC2 cannot accept display changes from an non
+ * validated display. */
+TEST_F(Hwc2Test, ACCEPT_DISPLAY_CHANGES_not_validated)
+{
+ ASSERT_NO_FATAL_FAILURE(displayNonValidatedLayers(5,
+ [] (Hwc2Test* test, hwc2_display_t display,
+ std::vector<hwc2_layer_t>* /*layers*/) {
+
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(test->acceptDisplayChanges(display, &err));
+ EXPECT_EQ(err, HWC2_ERROR_NOT_VALIDATED)
+ << "returned wrong error code";
+ }
+ ));
+}
+
+/* TESTCASE: Tests that the HWC2 supports client target with required values */
+TEST_F(Hwc2Test, GET_CLIENT_TARGET_SUPPORT)
+{
+ ASSERT_NO_FATAL_FAILURE(setClientTargetSupport(Hwc2TestCoverage::Default,
+ [] (Hwc2Test* test, hwc2_display_t display,
+ const Hwc2TestClientTargetSupport& testClientTargetSupport) {
+
+ const Area bufferArea = testClientTargetSupport.getBufferArea();
+ const android_pixel_format_t format = HAL_PIXEL_FORMAT_RGBA_8888;
+
+ ASSERT_NO_FATAL_FAILURE(test->getClientTargetSupport(display,
+ bufferArea.width, bufferArea.height, format,
+ testClientTargetSupport.getDataspace()));
+ },
+
+ advanceClientTargetSupport));
+}
+
+/* TESTCASE: Tests that the HWC2 cannot get client target support for a bad
+ * display. */
+TEST_F(Hwc2Test, GET_CLIENT_TARGET_SUPPORT_bad_display)
+{
+ ASSERT_NO_FATAL_FAILURE(setClientTargetSupport(Hwc2TestCoverage::Default,
+ [] (Hwc2Test* test, hwc2_display_t /*display*/,
+ const Hwc2TestClientTargetSupport& testClientTargetSupport) {
+
+ const Area bufferArea = testClientTargetSupport.getBufferArea();
+ const android_pixel_format_t format = HAL_PIXEL_FORMAT_RGBA_8888;
+ hwc2_display_t badDisplay;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(test->getBadDisplay(&badDisplay));
+
+ ASSERT_NO_FATAL_FAILURE(test->getClientTargetSupport(badDisplay,
+ bufferArea.width, bufferArea.height, format,
+ testClientTargetSupport.getDataspace(), &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+ },
+
+ advanceClientTargetSupport));
+}
+
+/* TESTCASE: Tests that the HWC2 either supports or returns error unsupported
+ * for a variety of client target values. */
+TEST_F(Hwc2Test, GET_CLIENT_TARGET_SUPPORT_unsupported)
+{
+ ASSERT_NO_FATAL_FAILURE(setClientTargetSupport(Hwc2TestCoverage::Complete,
+ [] (Hwc2Test* test, hwc2_display_t display,
+ const Hwc2TestClientTargetSupport& testClientTargetSupport) {
+
+ const Area bufferArea = testClientTargetSupport.getBufferArea();
+ const android_pixel_format_t format = HAL_PIXEL_FORMAT_RGBA_8888;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(test->getClientTargetSupport(display,
+ bufferArea.width, bufferArea.height, format,
+ testClientTargetSupport.getDataspace(), &err));
+ EXPECT_TRUE(err == HWC2_ERROR_NONE
+ || err == HWC2_ERROR_UNSUPPORTED)
+ << "returned wrong error code";
+ },
+
+ advanceClientTargetSupport));
+}
+
+/* TESTCASE: Tests that the HWC2 can set a client target buffer for a basic
+ * layer. */
+TEST_F(Hwc2Test, SET_CLIENT_TARGET_basic)
+{
+ const android_dataspace_t dataspace = HAL_DATASPACE_UNKNOWN;
+ const hwc_region_t damage = { };
+ const size_t layerCnt = 1;
+
+ for (auto display : mDisplays) {
+ std::vector<hwc2_config_t> configs;
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
+
+ ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
+
+ for (auto config : configs) {
+ Area displayArea;
+ std::vector<hwc2_layer_t> layers;
+
+ ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
+ ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display, &displayArea));
+
+ ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers, layerCnt));
+ Hwc2TestLayers testLayers(layers, Hwc2TestCoverage::Basic,
+ displayArea);
+
+ if (!testLayers.optimizeLayouts())
+ continue;
+
+ Hwc2TestClientTarget testClientTarget;
+
+ do {
+ std::set<hwc2_layer_t> clientLayers;
+ std::set<hwc2_layer_t> clearLayers;
+ uint32_t numTypes, numRequests;
+ bool hasChanges, skip;
+ bool flipClientTarget;
+ buffer_handle_t handle;
+ int32_t acquireFence;
+
+ ASSERT_NO_FATAL_FAILURE(setLayerProperties(display, layers,
+ &testLayers, &skip));
+ if (skip)
+ continue;
+
+ ASSERT_NO_FATAL_FAILURE(validateDisplay(display, &numTypes,
+ &numRequests, &hasChanges));
+ if (hasChanges)
+ EXPECT_LE(numTypes, layers.size())
+ << "wrong number of requests";
+
+ ASSERT_NO_FATAL_FAILURE(handleCompositionChanges(display,
+ testLayers, layers, numTypes, &clientLayers));
+ ASSERT_NO_FATAL_FAILURE(handleRequests(display, layers,
+ numRequests, &clearLayers, &flipClientTarget));
+ ASSERT_EQ(testClientTarget.getBuffer(testLayers, clientLayers,
+ clearLayers, flipClientTarget, displayArea, &handle,
+ &acquireFence), 0);
+ EXPECT_NO_FATAL_FAILURE(setClientTarget(display, handle,
+ acquireFence, dataspace, damage));
+
+ if (acquireFence >= 0)
+ close(acquireFence);
+
+ } while (testLayers.advance());
+
+ ASSERT_NO_FATAL_FAILURE(destroyLayers(display, std::move(layers)));
+ }
+
+ ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 cannot set a client target for a bad display. */
+TEST_F(Hwc2Test, SET_CLIENT_TARGET_bad_display)
+{
+ hwc2_display_t display;
+ std::vector<hwc2_layer_t> layers;
+ const Area displayArea = {0, 0};
+ Hwc2TestLayers testLayers(layers, Hwc2TestCoverage::Default, displayArea);
+ std::set<hwc2_layer_t> clientLayers;
+ std::set<hwc2_layer_t> flipClientTargetLayers;
+ bool flipClientTarget = true;
+ const android_dataspace_t dataspace = HAL_DATASPACE_UNKNOWN;
+ const hwc_region_t damage = { };
+ buffer_handle_t handle;
+ int32_t acquireFence;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
+
+ Hwc2TestClientTarget testClientTarget;
+
+ ASSERT_EQ(testClientTarget.getBuffer(testLayers, clientLayers,
+ flipClientTargetLayers, flipClientTarget, displayArea, &handle,
+ &acquireFence), 0);
+
+ EXPECT_NO_FATAL_FAILURE(setClientTarget(display, handle, acquireFence,
+ dataspace, damage, &err));
+
+ if (acquireFence >= 0)
+ close(acquireFence);
+
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+}
+
+/* TESTCASE: Tests that the HWC2 can present 1 default layer. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_default_1)
+{
+ const size_t layerCnt = 1;
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions;
+ bool optimize = false;
+
+ ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
+ optimize));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 2 default layers. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_default_2)
+{
+ const size_t layerCnt = 2;
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions;
+ bool optimize = false;
+
+ ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
+ optimize));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 3 default layers. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_default_3)
+{
+ const size_t layerCnt = 3;
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions;
+ bool optimize = false;
+
+ ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
+ optimize));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 4 default layers. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_default_4)
+{
+ const size_t layerCnt = 4;
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions;
+ bool optimize = false;
+
+ ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
+ optimize));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 5 default layers. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_default_5)
+{
+ const size_t layerCnt = 5;
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions;
+ bool optimize = false;
+
+ ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
+ optimize));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 6 default layers. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_default_6)
+{
+ const size_t layerCnt = 6;
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions;
+ bool optimize = false;
+
+ ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
+ optimize));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
+ * blend mode. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_blend_mode_1)
+{
+ const size_t layerCnt = 1;
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
+ {{Hwc2TestPropertyName::BlendMode, Hwc2TestCoverage::Complete},
+ {Hwc2TestPropertyName::Transform, Hwc2TestCoverage::Basic},
+ {Hwc2TestPropertyName::PlaneAlpha, Hwc2TestCoverage::Basic}};
+ bool optimize = false;
+
+ ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
+ optimize));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 2 layers with complete coverage of
+ * blend mode. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_blend_mode_2)
+{
+ const size_t layerCnt = 2;
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
+ {{Hwc2TestPropertyName::BlendMode, Hwc2TestCoverage::Complete},
+ {Hwc2TestPropertyName::PlaneAlpha, Hwc2TestCoverage::Basic}};
+ bool optimize = false;
+
+ ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
+ optimize));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
+ * buffer. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_buffer_1)
+{
+ const size_t layerCnt = 1;
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
+ {{Hwc2TestPropertyName::BufferArea, Hwc2TestCoverage::Complete}};
+ bool optimize = true;
+
+ ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
+ optimize));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
+ * color. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_color_1)
+{
+ const size_t layerCnt = 1;
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
+ {{Hwc2TestPropertyName::Composition, Hwc2TestCoverage::Complete},
+ {Hwc2TestPropertyName::Color, Hwc2TestCoverage::Complete}};
+ bool optimize = true;
+
+ ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
+ optimize));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 2 layers with complete coverage of
+ * color. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_color_2)
+{
+ const size_t layerCnt = 2;
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
+ {{Hwc2TestPropertyName::Composition, Hwc2TestCoverage::Complete},
+ {Hwc2TestPropertyName::BlendMode, Hwc2TestCoverage::Basic},
+ {Hwc2TestPropertyName::PlaneAlpha, Hwc2TestCoverage::Basic},
+ {Hwc2TestPropertyName::Color, Hwc2TestCoverage::Basic}};
+ bool optimize = true;
+
+ ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
+ optimize));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
+ * composition. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_composition_1)
+{
+ const size_t layerCnt = 1;
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
+ {{Hwc2TestPropertyName::Composition, Hwc2TestCoverage::Complete}};
+ bool optimize = true;
+
+ ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
+ optimize));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
+ * cursor. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_cursor_1)
+{
+ const size_t layerCnt = 1;
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
+ {{Hwc2TestPropertyName::Composition, Hwc2TestCoverage::Complete},
+ {Hwc2TestPropertyName::CursorPosition, Hwc2TestCoverage::Complete}};
+ bool optimize = true;
+
+ ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
+ optimize));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 2 layers with complete coverage of
+ * cursor. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_cursor_2)
+{
+ const size_t layerCnt = 2;
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
+ {{Hwc2TestPropertyName::Composition, Hwc2TestCoverage::Complete},
+ {Hwc2TestPropertyName::CursorPosition, Hwc2TestCoverage::Complete},
+ {Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Basic}};
+ bool optimize = true;
+
+ ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
+ optimize));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
+ * dataspace. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_dataspace_1)
+{
+ const size_t layerCnt = 1;
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
+ {{Hwc2TestPropertyName::Dataspace, Hwc2TestCoverage::Complete}};
+ bool optimize = true;
+
+ ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
+ optimize));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
+ * display frame. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_display_frame_1)
+{
+ const size_t layerCnt = 1;
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
+ {{Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Complete}};
+ bool optimize = true;
+
+ ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
+ optimize));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 2 layers with complete coverage of
+ * display frame. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_display_frame_2)
+{
+ const size_t layerCnt = 2;
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
+ {{Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Complete}};
+ bool optimize = true;
+
+ ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
+ optimize));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 3 layers with complete coverage of
+ * display frame. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_display_frame_3)
+{
+ const size_t layerCnt = 3;
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
+ {{Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Complete}};
+ bool optimize = true;
+
+ ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
+ optimize));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 4 layers with complete coverage of
+ * display frame. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_display_frame_4)
+{
+ const size_t layerCnt = 4;
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
+ {{Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Complete}};
+ bool optimize = true;
+
+ ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
+ optimize));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
+ * plane alpha. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_plane_alpha_1)
+{
+ const size_t layerCnt = 1;
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
+ {{Hwc2TestPropertyName::BlendMode, Hwc2TestCoverage::Basic},
+ {Hwc2TestPropertyName::PlaneAlpha, Hwc2TestCoverage::Complete}};
+ bool optimize = false;
+
+ ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
+ optimize));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 2 layers with complete coverage of
+ * plane alpha. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_plane_alpha_2)
+{
+ const size_t layerCnt = 2;
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
+ {{Hwc2TestPropertyName::BlendMode, Hwc2TestCoverage::Basic},
+ {Hwc2TestPropertyName::PlaneAlpha, Hwc2TestCoverage::Complete}};
+ bool optimize = false;
+
+ ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
+ optimize));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
+ * source crop. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_source_crop_1)
+{
+ const size_t layerCnt = 1;
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
+ {{Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Complete},
+ {Hwc2TestPropertyName::SourceCrop, Hwc2TestCoverage::Complete}};
+ bool optimize = true;
+
+ ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
+ optimize));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 2 layers with complete coverage of
+ * source crop. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_source_crop_2)
+{
+ const size_t layerCnt = 2;
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
+ {{Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Complete},
+ {Hwc2TestPropertyName::SourceCrop, Hwc2TestCoverage::Complete}};
+ bool optimize = true;
+
+ ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
+ optimize));
+}
+
+
+/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
+ * surface damage. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_surface_damage_1)
+{
+ const size_t layerCnt = 1;
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
+ {{Hwc2TestPropertyName::SurfaceDamage, Hwc2TestCoverage::Complete}};
+ bool optimize = true;
+
+ ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
+ optimize));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
+ * transform. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_transform_1)
+{
+ const size_t layerCnt = 1;
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
+ {{Hwc2TestPropertyName::Transform, Hwc2TestCoverage::Complete}};
+ bool optimize = true;
+
+ ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
+ optimize));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 2 layers with complete coverage of
+ * transform. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_transform_2)
+{
+ const size_t layerCnt = 2;
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
+ {{Hwc2TestPropertyName::Transform, Hwc2TestCoverage::Complete},
+ {Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Basic}};
+ bool optimize = true;
+
+ ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
+ optimize));
+}
+
+/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
+ * basic. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_basic_1)
+{
+ const size_t layerCnt = 1;
+ Hwc2TestCoverage coverage = Hwc2TestCoverage::Basic;
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions;
+ bool optimize = true;
+
+ ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
+ optimize));
+}
+
+/* TESTCASE: Tests that the HWC2 cannot present a bad display. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_bad_display)
+{
+ hwc2_display_t display;
+ int32_t presentFence;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
+
+ ASSERT_NO_FATAL_FAILURE(presentDisplay(display, &presentFence, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+}
+
+/* TESTCASE: Tests that the HWC2 cannot present an unvalidated display. */
+TEST_F(Hwc2Test, PRESENT_DISPLAY_not_validated)
+{
+ ASSERT_NO_FATAL_FAILURE(displayLayers(Hwc2TestCoverage::Default, 1,
+ [] (Hwc2Test* test, hwc2_display_t display,
+ const std::vector<hwc2_layer_t>& /*layers*/,
+ Hwc2TestLayers* /*testLayers*/) {
+
+ int32_t presentFence;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(test->setPowerMode(display,
+ HWC2_POWER_MODE_ON));
+ ASSERT_NO_FATAL_FAILURE(test->enableVsync(display));
+
+ ASSERT_NO_FATAL_FAILURE(test->waitForVsync());
+
+ ASSERT_NO_FATAL_FAILURE(test->presentDisplay(display,
+ &presentFence, &err));
+ EXPECT_EQ(err, HWC2_ERROR_NOT_VALIDATED)
+ << "returned wrong error code";
+
+ ASSERT_NO_FATAL_FAILURE(test->disableVsync(display));
+ ASSERT_NO_FATAL_FAILURE(test->setPowerMode(display,
+ HWC2_POWER_MODE_OFF));
+ }
+ ));
+}
+
+/* TESTCASE: Tests that the HWC2 cannot get release fences from a bad display. */
+TEST_F(Hwc2Test, GET_RELEASE_FENCES_bad_display)
+{
+ hwc2_display_t display;
+ std::vector<hwc2_layer_t> layers;
+ std::vector<int32_t> fences;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
+
+ ASSERT_NO_FATAL_FAILURE(getReleaseFences(display, &layers, &fences, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+}
+
+static const std::array<android_color_mode, 9> androidColorModes = {{
+ HAL_COLOR_MODE_NATIVE,
+ HAL_COLOR_MODE_STANDARD_BT601_625,
+ HAL_COLOR_MODE_STANDARD_BT601_625_UNADJUSTED,
+ HAL_COLOR_MODE_STANDARD_BT601_525,
+ HAL_COLOR_MODE_STANDARD_BT601_525_UNADJUSTED,
+ HAL_COLOR_MODE_STANDARD_BT709,
+ HAL_COLOR_MODE_DCI_P3,
+ HAL_COLOR_MODE_SRGB,
+ HAL_COLOR_MODE_ADOBE_RGB,
+}};
+
+/* TESTCASE: Tests that the HWC2 can get the color modes for a display. The
+ * display must support HAL_COLOR_MODE_NATIVE */
+TEST_F(Hwc2Test, GET_COLOR_MODES)
+{
+ ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
+ [] (Hwc2Test* test, hwc2_display_t display) {
+
+ std::vector<android_color_mode_t> colorModes;
+
+ ASSERT_NO_FATAL_FAILURE(test->getColorModes(display,
+ &colorModes));
+
+ EXPECT_NE(std::count(colorModes.begin(), colorModes.end(),
+ HAL_COLOR_MODE_NATIVE), 0) << "all displays"
+ " must support HAL_COLOR_MODE_NATIVE";
+ }
+ ));
+}
+
+/* TESTCASE: Tests that the HWC2 cannot get color modes from a bad display. */
+TEST_F(Hwc2Test, GET_COLOR_MODES_bad_display)
+{
+ hwc2_display_t display;
+ std::vector<android_color_mode_t> colorModes;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
+
+ ASSERT_NO_FATAL_FAILURE(getColorModes(display, &colorModes, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+}
+
+/* TESTCASE: Tests that the HWC2 can set the required color mode on a display. */
+TEST_F(Hwc2Test, SET_COLOR_MODES)
+{
+ ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
+ [] (Hwc2Test* test, hwc2_display_t display) {
+
+ const android_color_mode_t colorMode = HAL_COLOR_MODE_NATIVE;
+
+ EXPECT_NO_FATAL_FAILURE(test->setColorMode(display, colorMode));
+ }
+ ));
+}
+
+/* TESTCASE: Tests that the HWC2 cannot set a color mode on a bad display. */
+TEST_F(Hwc2Test, SET_COLOR_MODES_bad_display)
+{
+ hwc2_display_t display;
+ const android_color_mode_t colorMode = HAL_COLOR_MODE_NATIVE;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
+
+ ASSERT_NO_FATAL_FAILURE(setColorMode(display, colorMode, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+}
+
+/* TESTCASE: Tests that the HWC2 cannot set an invalid color mode. */
+TEST_F(Hwc2Test, SET_COLOR_MODES_bad_parameter)
+{
+ ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
+ [] (Hwc2Test* test, hwc2_display_t display) {
+
+ const android_color_mode_t colorMode =
+ static_cast<android_color_mode_t>(-1);
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(test->setColorMode(display, colorMode,
+ &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER)
+ << "returned wrong error code";
+ }
+ ));
+}
+
+/* TESTCASE: Tests that the HWC2 either supports or returns error unsupported
+ * for all valid color modes. */
+TEST_F(Hwc2Test, SET_COLOR_MODES_unsupported)
+{
+ ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
+ [] (Hwc2Test* test, hwc2_display_t display) {
+
+ for (auto colorMode : androidColorModes) {
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(test->setColorMode(display,
+ colorMode, &err));
+
+ EXPECT_TRUE(err == HWC2_ERROR_NONE
+ || err == HWC2_ERROR_UNSUPPORTED)
+ << "returned wrong error code";
+ }
+ }
+ ));
+}
+
+/* TESTCASE: Tests that the HWC2 gets the HDR capabilities for a display and
+ * test if they are valid. */
+TEST_F(Hwc2Test, GET_HDR_CAPABILITIES)
+{
+ ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
+ [] (Hwc2Test* test, hwc2_display_t display) {
+
+ std::vector<android_hdr_t> hdrCapabilities;
+ float maxLuminance, maxAverageLuminance, minLuminance;
+
+ EXPECT_NO_FATAL_FAILURE(test->getHdrCapabilities(display,
+ &hdrCapabilities, &maxLuminance, &maxAverageLuminance,
+ &minLuminance));
+
+ if (hdrCapabilities.empty())
+ return;
+
+ EXPECT_GE(maxLuminance, maxAverageLuminance);
+ EXPECT_GE(maxAverageLuminance, minLuminance);
+ }
+ ));
+}
+
+/* TESTCASE: Tests that the HWC2 cannot get hdr capabilities from a bad display */
+TEST_F(Hwc2Test, GET_HDR_CAPABILITIES_bad_display)
+{
+ hwc2_display_t display;
+ std::vector<android_hdr_t> hdrCapabilities;
+ float maxLuminance, maxAverageLuminance, minLuminance;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
+
+ ASSERT_NO_FATAL_FAILURE(getHdrCapabilities(display, &hdrCapabilities,
+ &maxLuminance, &maxAverageLuminance, &minLuminance, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+}
+
+static const std::array<float, 16> identityMatrix = {{
+ 1.0, 0.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0, 0.0,
+ 0.0, 0.0, 1.0, 0.0,
+ 0.0, 0.0, 0.0, 1.0,
+}};
+
+/* Values for the color transform matrices were precomputed using the source code
+ * in surfaceflinger/Effects/Daltonizer.cpp. */
+
+static const std::array<const std::array<float, 16>, 5> exampleMatrices = {{
+ identityMatrix,
+ /* Converts RGB color to the XYZ space */
+ {{ 0.4124, 0.2126, 0.0193, 0,
+ 0.3576, 0.7152, 0.1192, 0,
+ 0.1805, 0.0722, 0.9505, 0,
+ 0 , 0 , 0 , 1 }},
+ /* Protanomaly */
+ {{ 0.068493, 0.931506, 0, 0,
+ 0.068493, 0.931507, 0, 0,
+ 0.013626, -0.013626, 1, 0,
+ 0, 0, 0, 1 }},
+ /* Deuteranomaly */
+ {{ 0.288299, 0.711701, 0, 0,
+ 0.052709, 0.947291, 0, 0,
+ -0.257912, 0.257912, 1, 0,
+ 0, 0, 0, 1 }},
+ /* Tritanomaly */
+ {{ 1, -0.805712, 0.805712, 0,
+ 0, 0.378838, 0.621162, 0,
+ 0, 0.104823, 0.895177, 0,
+ 0, 0, 0, 1 }},
+}};
+
+/* TESTCASE: Tests that the HWC2 can set the identity color transform */
+TEST_F(Hwc2Test, SET_COLOR_TRANSFORM)
+{
+ ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
+ [] (Hwc2Test* test, hwc2_display_t display) {
+
+ EXPECT_NO_FATAL_FAILURE(test->setColorTransform(display,
+ identityMatrix, HAL_COLOR_TRANSFORM_IDENTITY));
+ }
+ ));
+}
+
+/* TESTCASE: Tests that the HWC2 cannot set the color transform for a bad
+ * display. */
+TEST_F(Hwc2Test, SET_COLOR_TRANSFORM_bad_display)
+{
+ hwc2_display_t display;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
+
+ ASSERT_NO_FATAL_FAILURE(setColorTransform(display, identityMatrix,
+ HAL_COLOR_TRANSFORM_IDENTITY, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+}
+
+/* TESTCASE: Tests that the HWC2 cannot set an invalid color transform. */
+TEST_F(Hwc2Test, SET_COLOR_TRANSFORM_bad_parameter)
+{
+ ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
+ [] (Hwc2Test* test, hwc2_display_t display) {
+
+ const android_color_transform_t hint =
+ static_cast<android_color_transform_t>(-1);
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(test->setColorTransform(display,
+ identityMatrix, hint, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER)
+ << "returned wrong error code";
+ }
+ ));
+}
+
+/* TESTCASE: Tests that the HWC2 can set an arbitrary color matrix. */
+TEST_F(Hwc2Test, SET_COLOR_TRANSFORM_arbitrary_matrix)
+{
+ ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
+ [] (Hwc2Test* test, hwc2_display_t display) {
+
+ const android_color_transform_t hint =
+ HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX;
+
+ for (const std::array<float, 16>& matrix : exampleMatrices) {
+ EXPECT_NO_FATAL_FAILURE(test->setColorTransform(display,
+ matrix, hint));
+ }
+ }
+ ));
+}
+
+/* TESTCASE: Tests that the HWC2 create an destory virtual displays. */
+TEST_F(Hwc2Test, CREATE_DESTROY_VIRTUAL_DISPLAY)
+{
+ ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(Hwc2TestCoverage::Complete,
+ [] (Hwc2Test* /*test*/, hwc2_display_t /*display*/,
+ Hwc2TestVirtualDisplay* /*testVirtualDisplay*/) { }));
+}
+
+/* TESTCASE: Tests that the HWC2 can create and destroy multiple virtual
+ * displays. */
+TEST_F(Hwc2Test, CREATE_DESTROY_VIRTUAL_DISPLAY_multiple)
+{
+ Hwc2TestVirtualDisplay testVirtualDisplay(Hwc2TestCoverage::Complete);
+ std::vector<hwc2_display_t> displays;
+
+ do {
+ const UnsignedArea& dimension =
+ testVirtualDisplay.getDisplayDimension();
+ android_pixel_format_t desiredFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+ hwc2_display_t display;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(dimension.width,
+ dimension.height, &desiredFormat, &display, &err));
+
+ EXPECT_TRUE(err == HWC2_ERROR_NONE || err == HWC2_ERROR_NO_RESOURCES
+ || err == HWC2_ERROR_UNSUPPORTED) << "returned wrong error code";
+ EXPECT_GE(desiredFormat, 0) << "invalid format";
+
+ if (err == HWC2_ERROR_NONE)
+ displays.push_back(display);
+
+ } while (testVirtualDisplay.advance());
+
+ for (hwc2_display_t display : displays) {
+ EXPECT_NO_FATAL_FAILURE(destroyVirtualDisplay(display));
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 cannot destroy a bad virtual displays. */
+TEST_F(Hwc2Test, DESTROY_VIRTUAL_DISPLAY_bad_display)
+{
+ hwc2_display_t display;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
+
+ ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
+}
+
+/* TESTCASE: Tests that the HWC2 cannot destroy a physical display. */
+TEST_F(Hwc2Test, DESTROY_VIRTUAL_DISPLAY_bad_parameter)
+{
+ hwc2_display_t display = HWC_DISPLAY_PRIMARY;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong error code";
+}
+
+/* TESTCASE: Tests that the HWC2 can get the max virtual display count. */
+TEST_F(Hwc2Test, GET_MAX_VIRTUAL_DISPLAY_COUNT)
+{
+ uint32_t maxCnt;
+
+ ASSERT_NO_FATAL_FAILURE(getMaxVirtualDisplayCount(&maxCnt));
+}
+
+/* TESTCASE: Tests that the HWC2 returns the same max virtual display count for
+ * each call. */
+TEST_F(Hwc2Test, GET_MAX_VIRTUAL_DISPLAY_COUNT_duplicate)
+{
+ uint32_t maxCnt1, maxCnt2;
+
+ ASSERT_NO_FATAL_FAILURE(getMaxVirtualDisplayCount(&maxCnt1));
+ ASSERT_NO_FATAL_FAILURE(getMaxVirtualDisplayCount(&maxCnt2));
+
+ EXPECT_EQ(maxCnt1, maxCnt2) << "returned two different max virtual display"
+ " counts";
+}
+
+/* TESTCASE: Tests that the HWC2 can create the max number of virtual displays
+ * that it reports. */
+TEST_F(Hwc2Test, GET_MAX_VIRTUAL_DISPLAY_COUNT_create_max)
+{
+ std::vector<hwc2_display_t> displays;
+ uint32_t maxCnt;
+
+ ASSERT_NO_FATAL_FAILURE(getMaxVirtualDisplayCount(&maxCnt));
+
+ while (displays.size() < maxCnt) {
+ uint32_t width = 1920, height = 1080;
+ android_pixel_format_t desiredFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+ hwc2_display_t display;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(width, height,
+ &desiredFormat, &display, &err));
+
+ EXPECT_TRUE(err == HWC2_ERROR_NONE || err == HWC2_ERROR_UNSUPPORTED)
+ << "returned wrong error code";
+ if (err != HWC2_ERROR_NONE)
+ break;
+
+ displays.push_back(display);
+ }
+
+ for (hwc2_display_t display : displays) {
+ EXPECT_NO_FATAL_FAILURE(destroyVirtualDisplay(display));
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 can set an output buffer for a virtual
+ * display. */
+TEST_F(Hwc2Test, SET_OUTPUT_BUFFER)
+{
+ ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(Hwc2TestCoverage::Complete,
+ [] (Hwc2Test* test, hwc2_display_t display,
+ Hwc2TestVirtualDisplay* testVirtualDisplay) {
+
+ buffer_handle_t handle;
+ android::base::unique_fd acquireFence;
+
+ if (testVirtualDisplay->getBuffer(&handle, &acquireFence) >= 0)
+ EXPECT_NO_FATAL_FAILURE(test->setOutputBuffer(display,
+ handle, acquireFence));
+ }));
+}
+
+/* TESTCASE: Tests that the HWC2 cannot set an output buffer for a bad display */
+TEST_F(Hwc2Test, SET_OUTPUT_BUFFER_bad_display)
+{
+ ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(Hwc2TestCoverage::Default,
+ [] (Hwc2Test* test, hwc2_display_t /*display*/,
+ Hwc2TestVirtualDisplay* testVirtualDisplay) {
+
+ hwc2_display_t badDisplay;
+ buffer_handle_t handle;
+ android::base::unique_fd acquireFence;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(test->getBadDisplay(&badDisplay));
+
+ if (testVirtualDisplay->getBuffer(&handle, &acquireFence) < 0)
+ return;
+
+ ASSERT_NO_FATAL_FAILURE(test->setOutputBuffer(badDisplay,
+ handle, acquireFence, &err));
+ EXPECT_TRUE(err == HWC2_ERROR_BAD_DISPLAY)
+ << "returned wrong error code";
+ }));
+}
+
+/* TESTCASE: Tests that the HWC2 cannot set an invalid output buffer. */
+TEST_F(Hwc2Test, SET_OUTPUT_BUFFER_bad_parameter)
+{
+ ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(Hwc2TestCoverage::Default,
+ [] (Hwc2Test* test, hwc2_display_t display,
+ Hwc2TestVirtualDisplay* /*testVirtualDisplay*/) {
+
+ const buffer_handle_t handle = nullptr;
+ uint32_t releaseFence = -1;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ ASSERT_NO_FATAL_FAILURE(test->setOutputBuffer(display, handle,
+ releaseFence, &err));
+ EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER)
+ << "returned wrong error code";
+ }));
+}
+
+/* TESTCASE: Tests that the HWC2 cannot set an output buffer for non virtual
+ * display */
+TEST_F(Hwc2Test, SET_OUTPUT_BUFFER_unsupported)
+{
+ for (auto display : mDisplays) {
+ Hwc2TestVirtualDisplay testVirtualDisplay(Hwc2TestCoverage::Complete);
+
+ do {
+ buffer_handle_t handle;
+ android::base::unique_fd acquireFence;
+ hwc2_error_t err = HWC2_ERROR_NONE;
+
+ if (testVirtualDisplay.getBuffer(&handle, &acquireFence) < 0)
+ continue;
+
+ ASSERT_NO_FATAL_FAILURE(setOutputBuffer(display, handle,
+ acquireFence, &err));
+ EXPECT_EQ(err, HWC2_ERROR_UNSUPPORTED) << "returned wrong error code";
+
+ } while (testVirtualDisplay.advance());
+ }
+}
+
+/* TESTCASE: Tests that the HWC2 can dump debug information. */
+TEST_F(Hwc2Test, DUMP)
+{
+ std::string buffer;
+
+ ASSERT_NO_FATAL_FAILURE(dump(&buffer));
+}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
new file mode 100644
index 0000000..5f90c7a
--- /dev/null
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
@@ -0,0 +1,695 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <mutex>
+#include <array>
+#include <sstream>
+#include <algorithm>
+
+#include <gui/Surface.h>
+#include <gui/BufferItemConsumer.h>
+
+#include <ui/GraphicBuffer.h>
+#include <ui/vec4.h>
+
+#include <GLES3/gl3.h>
+
+#include "Hwc2TestBuffer.h"
+#include "Hwc2TestLayers.h"
+
+using namespace android;
+
+/* Returns a fence from egl */
+typedef void (*FenceCallback)(int32_t fence, void* callbackArgs);
+
+/* Returns fence to fence generator */
+static void setFence(int32_t fence, void* fenceGenerator);
+
+
+/* Used to receive the surfaces and fences from egl. The egl buffers are thrown
+ * away. The fences are sent to the requester via a callback */
+class Hwc2TestSurfaceManager {
+public:
+ /* Listens for a new frame, detaches the buffer and returns the fence
+ * through saved callback. */
+ class BufferListener : public ConsumerBase::FrameAvailableListener {
+ public:
+ BufferListener(sp<IGraphicBufferConsumer> consumer,
+ FenceCallback callback, void* callbackArgs)
+ : mConsumer(consumer),
+ mCallback(callback),
+ mCallbackArgs(callbackArgs) { }
+
+ void onFrameAvailable(const BufferItem& /*item*/)
+ {
+ BufferItem item;
+
+ if (mConsumer->acquireBuffer(&item, 0))
+ return;
+ if (mConsumer->detachBuffer(item.mSlot))
+ return;
+
+ mCallback(item.mFence->dup(), mCallbackArgs);
+ }
+
+ private:
+ sp<IGraphicBufferConsumer> mConsumer;
+ FenceCallback mCallback;
+ void* mCallbackArgs;
+ };
+
+ /* Creates a buffer listener that waits on a new frame from the buffer
+ * queue. */
+ void initialize(const Area& bufferArea, android_pixel_format_t format,
+ FenceCallback callback, void* callbackArgs)
+ {
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+
+ consumer->setDefaultBufferSize(bufferArea.width, bufferArea.height);
+ consumer->setDefaultBufferFormat(format);
+
+ mBufferItemConsumer = new BufferItemConsumer(consumer, 0);
+
+ mListener = new BufferListener(consumer, callback, callbackArgs);
+ mBufferItemConsumer->setFrameAvailableListener(mListener);
+
+ mSurface = new Surface(producer, true);
+ }
+
+ /* Used by Egl manager. The surface is never displayed. */
+ sp<Surface> getSurface() const
+ {
+ return mSurface;
+ }
+
+private:
+ sp<BufferItemConsumer> mBufferItemConsumer;
+ sp<BufferListener> mListener;
+ /* Used by Egl manager. The surface is never displayed */
+ sp<Surface> mSurface;
+};
+
+
+/* Used to generate valid fences. It is not possible to create a dummy sync
+ * fence for testing. Egl can generate buffers along with a valid fence.
+ * The buffer cannot be guaranteed to be the same format across all devices so
+ * a CPU filled buffer is used instead. The Egl fence is used along with the
+ * CPU filled buffer. */
+class Hwc2TestEglManager {
+public:
+ Hwc2TestEglManager()
+ : mEglDisplay(EGL_NO_DISPLAY),
+ mEglSurface(EGL_NO_SURFACE),
+ mEglContext(EGL_NO_CONTEXT) { }
+
+ ~Hwc2TestEglManager()
+ {
+ cleanup();
+ }
+
+ int initialize(sp<Surface> surface)
+ {
+ mSurface = surface;
+
+ mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ if (mEglDisplay == EGL_NO_DISPLAY) return false;
+
+ EGLint major;
+ EGLint minor;
+ if (!eglInitialize(mEglDisplay, &major, &minor)) {
+ ALOGW("Could not initialize EGL");
+ return false;
+ }
+
+ /* We're going to use a 1x1 pbuffer surface later on
+ * The configuration distance doesn't really matter for what we're
+ * trying to do */
+ EGLint configAttrs[] = {
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 0,
+ EGL_DEPTH_SIZE, 24,
+ EGL_STENCIL_SIZE, 0,
+ EGL_NONE
+ };
+
+ EGLConfig configs[1];
+ EGLint configCnt;
+ if (!eglChooseConfig(mEglDisplay, configAttrs, configs, 1,
+ &configCnt)) {
+ ALOGW("Could not select EGL configuration");
+ eglReleaseThread();
+ eglTerminate(mEglDisplay);
+ return false;
+ }
+
+ if (configCnt <= 0) {
+ ALOGW("Could not find EGL configuration");
+ eglReleaseThread();
+ eglTerminate(mEglDisplay);
+ return false;
+ }
+
+ /* These objects are initialized below but the default "null" values are
+ * used to cleanup properly at any point in the initialization sequence */
+ EGLint attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+ mEglContext = eglCreateContext(mEglDisplay, configs[0], EGL_NO_CONTEXT,
+ attrs);
+ if (mEglContext == EGL_NO_CONTEXT) {
+ ALOGW("Could not create EGL context");
+ cleanup();
+ return false;
+ }
+
+ EGLint surfaceAttrs[] = { EGL_NONE };
+ mEglSurface = eglCreateWindowSurface(mEglDisplay, configs[0],
+ mSurface.get(), surfaceAttrs);
+ if (mEglSurface == EGL_NO_SURFACE) {
+ ALOGW("Could not create EGL surface");
+ cleanup();
+ return false;
+ }
+
+ if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
+ ALOGW("Could not change current EGL context");
+ cleanup();
+ return false;
+ }
+
+ return true;
+ }
+
+ void makeCurrent() const
+ {
+ eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext);
+ }
+
+ void present() const
+ {
+ eglSwapBuffers(mEglDisplay, mEglSurface);
+ }
+
+private:
+ void cleanup()
+ {
+ if (mEglDisplay == EGL_NO_DISPLAY)
+ return;
+ if (mEglSurface != EGL_NO_SURFACE)
+ eglDestroySurface(mEglDisplay, mEglSurface);
+ if (mEglContext != EGL_NO_CONTEXT)
+ eglDestroyContext(mEglDisplay, mEglContext);
+
+ eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
+ EGL_NO_CONTEXT);
+ eglReleaseThread();
+ eglTerminate(mEglDisplay);
+ }
+
+ sp<Surface> mSurface;
+ EGLDisplay mEglDisplay;
+ EGLSurface mEglSurface;
+ EGLContext mEglContext;
+};
+
+
+static const std::array<vec2, 4> triangles = {{
+ { 1.0f, 1.0f },
+ { -1.0f, 1.0f },
+ { 1.0f, -1.0f },
+ { -1.0f, -1.0f },
+}};
+
+class Hwc2TestFenceGenerator {
+public:
+
+ Hwc2TestFenceGenerator()
+ {
+ mSurfaceManager.initialize({1, 1}, HAL_PIXEL_FORMAT_RGBA_8888,
+ setFence, this);
+
+ if (!mEglManager.initialize(mSurfaceManager.getSurface()))
+ return;
+
+ mEglManager.makeCurrent();
+
+ glClearColor(0.0, 0.0, 0.0, 1.0);
+ glEnableVertexAttribArray(0);
+ }
+
+ ~Hwc2TestFenceGenerator()
+ {
+ if (mFence >= 0)
+ close(mFence);
+ mFence = -1;
+
+ mEglManager.makeCurrent();
+ }
+
+ /* It is not possible to simply generate a fence. The easiest way is to
+ * generate a buffer using egl and use the associated fence. The buffer
+ * cannot be guaranteed to be a certain format across all devices using this
+ * method. Instead the buffer is generated using the CPU */
+ int32_t get()
+ {
+ if (mFence >= 0) {
+ return dup(mFence);
+ }
+
+ std::unique_lock<std::mutex> lock(mMutex);
+
+ /* If the pending is still set to false and times out, we cannot recover.
+ * Set an error and return */
+ while (mPending != false) {
+ if (mCv.wait_for(lock, std::chrono::seconds(2)) == std::cv_status::timeout)
+ return -ETIME;
+ }
+
+ /* Generate a fence. The fence will be returned through the setFence
+ * callback */
+ mEglManager.makeCurrent();
+
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, triangles.data());
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ mEglManager.present();
+
+ /* Wait for the setFence callback */
+ while (mPending != true) {
+ if (mCv.wait_for(lock, std::chrono::seconds(2)) == std::cv_status::timeout)
+ return -ETIME;
+ }
+
+ mPending = false;
+
+ return dup(mFence);
+ }
+
+ /* Callback that sets the fence */
+ void set(int32_t fence)
+ {
+ mFence = fence;
+ mPending = true;
+
+ mCv.notify_all();
+ }
+
+private:
+
+ Hwc2TestSurfaceManager mSurfaceManager;
+ Hwc2TestEglManager mEglManager;
+
+ std::mutex mMutex;
+ std::condition_variable mCv;
+
+ int32_t mFence = -1;
+ bool mPending = false;
+};
+
+
+static void setFence(int32_t fence, void* fenceGenerator)
+{
+ static_cast<Hwc2TestFenceGenerator*>(fenceGenerator)->set(fence);
+}
+
+
+/* Sets the pixel of a buffer given the location, format, stride and color.
+ * Currently only supports RGBA_8888 */
+static void setColor(int32_t x, int32_t y,
+ android_pixel_format_t format, uint32_t stride, uint8_t* img, uint8_t r,
+ uint8_t g, uint8_t b, uint8_t a)
+{
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ img[(y * stride + x) * 4 + 0] = r;
+ img[(y * stride + x) * 4 + 1] = g;
+ img[(y * stride + x) * 4 + 2] = b;
+ img[(y * stride + x) * 4 + 3] = a;
+ break;
+ default:
+ break;
+ }
+}
+
+Hwc2TestBuffer::Hwc2TestBuffer()
+ : mFenceGenerator(new Hwc2TestFenceGenerator()) { }
+
+Hwc2TestBuffer::~Hwc2TestBuffer() = default;
+
+/* When the buffer changes sizes, save the new size and invalidate the current
+ * buffer */
+void Hwc2TestBuffer::updateBufferArea(const Area& bufferArea)
+{
+ if (mBufferArea.width == bufferArea.width
+ && mBufferArea.height == bufferArea.height)
+ return;
+
+ mBufferArea.width = bufferArea.width;
+ mBufferArea.height = bufferArea.height;
+
+ mValidBuffer = false;
+}
+
+/* Returns a valid buffer handle and fence. The handle is filled using the CPU
+ * to ensure the correct format across all devices. The fence is created using
+ * egl. */
+int Hwc2TestBuffer::get(buffer_handle_t* outHandle, int32_t* outFence)
+{
+ if (mBufferArea.width == -1 || mBufferArea.height == -1)
+ return -EINVAL;
+
+ /* If the current buffer is valid, the previous buffer can be reused.
+ * Otherwise, create new buffer */
+ if (!mValidBuffer) {
+ int ret = generateBuffer();
+ if (ret)
+ return ret;
+ }
+
+ *outFence = mFenceGenerator->get();
+ *outHandle = mHandle;
+
+ mValidBuffer = true;
+
+ return 0;
+}
+
+/* CPU fills a buffer to guarantee the correct buffer format across all
+ * devices */
+int Hwc2TestBuffer::generateBuffer()
+{
+ /* Create new graphic buffer with correct dimensions */
+ mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height,
+ mFormat, GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER,
+ "hwc2_test_buffer");
+ int ret = mGraphicBuffer->initCheck();
+ if (ret) {
+ return ret;
+ }
+ if (!mGraphicBuffer->handle) {
+ return -EINVAL;
+ }
+
+ /* Locks the buffer for writing */
+ uint8_t* img;
+ mGraphicBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
+
+ uint32_t stride = mGraphicBuffer->getStride();
+
+ /* Iterate from the top row of the buffer to the bottom row */
+ for (int32_t y = 0; y < mBufferArea.height; y++) {
+
+ /* Will be used as R, G and B values for pixel colors */
+ uint8_t max = 255;
+ uint8_t min = 0;
+
+ /* Divide the rows into 3 sections. The first section will contain
+ * the lighest colors. The last section will contain the darkest
+ * colors. */
+ if (y < mBufferArea.height * 1.0 / 3.0) {
+ min = 255 / 2;
+ } else if (y >= mBufferArea.height * 2.0 / 3.0) {
+ max = 255 / 2;
+ }
+
+ /* Divide the columns into 3 sections. The first section is red,
+ * the second is green and the third is blue */
+ int32_t x = 0;
+ for (; x < mBufferArea.width / 3; x++) {
+ setColor(x, y, mFormat, stride, img, max, min, min, 255);
+ }
+
+ for (; x < mBufferArea.width * 2 / 3; x++) {
+ setColor(x, y, mFormat, stride, img, min, max, min, 255);
+ }
+
+ for (; x < mBufferArea.width; x++) {
+ setColor(x, y, mFormat, stride, img, min, min, max, 255);
+ }
+ }
+
+ /* Unlock the buffer for reading */
+ mGraphicBuffer->unlock();
+
+ mHandle = mGraphicBuffer->handle;
+
+ return 0;
+}
+
+
+Hwc2TestClientTargetBuffer::Hwc2TestClientTargetBuffer()
+ : mFenceGenerator(new Hwc2TestFenceGenerator()) { }
+
+Hwc2TestClientTargetBuffer::~Hwc2TestClientTargetBuffer() { }
+
+/* Generates a client target buffer using the layers assigned for client
+ * composition. Takes into account the individual layer properties such as
+ * transform, blend mode, source crop, etc. */
+int Hwc2TestClientTargetBuffer::get(buffer_handle_t* outHandle,
+ int32_t* outFence, const Area& bufferArea,
+ const Hwc2TestLayers* testLayers,
+ const std::set<hwc2_layer_t>* clientLayers,
+ const std::set<hwc2_layer_t>* clearLayers)
+{
+ /* Create new graphic buffer with correct dimensions */
+ mGraphicBuffer = new GraphicBuffer(bufferArea.width, bufferArea.height,
+ mFormat, GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER,
+ "hwc2_test_buffer");
+ int ret = mGraphicBuffer->initCheck();
+ if (ret) {
+ return ret;
+ }
+ if (!mGraphicBuffer->handle) {
+ return -EINVAL;
+ }
+
+ uint8_t* img;
+ mGraphicBuffer->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
+
+ uint32_t stride = mGraphicBuffer->getStride();
+
+ float bWDiv3 = bufferArea.width / 3;
+ float bW2Div3 = bufferArea.width * 2 / 3;
+ float bHDiv3 = bufferArea.height / 3;
+ float bH2Div3 = bufferArea.height * 2 / 3;
+
+ /* Cycle through every pixel in the buffer and determine what color it
+ * should be. */
+ for (int32_t y = 0; y < bufferArea.height; y++) {
+ for (int32_t x = 0; x < bufferArea.width; x++) {
+
+ uint8_t r = 0, g = 0, b = 0;
+ float a = 0.0f;
+
+ /* Cycle through each client layer from back to front and
+ * update the pixel color. */
+ for (auto layer = clientLayers->rbegin();
+ layer != clientLayers->rend(); ++layer) {
+
+ const hwc_rect_t df = testLayers->getDisplayFrame(*layer);
+
+ float dfL = df.left;
+ float dfT = df.top;
+ float dfR = df.right;
+ float dfB = df.bottom;
+
+ /* If the pixel location falls outside of the layer display
+ * frame, skip the layer. */
+ if (x < dfL || x >= dfR || y < dfT || y >= dfB)
+ continue;
+
+ /* If the device has requested the layer be clear, clear
+ * the pixel and continue. */
+ if (clearLayers->count(*layer) != 0) {
+ r = 0;
+ g = 0;
+ b = 0;
+ a = 0.0f;
+ continue;
+ }
+
+ float planeAlpha = testLayers->getPlaneAlpha(*layer);
+
+ /* If the layer is a solid color, fill the color and
+ * continue. */
+ if (testLayers->getComposition(*layer)
+ == HWC2_COMPOSITION_SOLID_COLOR) {
+ const auto color = testLayers->getColor(*layer);
+ r = color.r;
+ g = color.g;
+ b = color.b;
+ a = color.a * planeAlpha;
+ continue;
+ }
+
+ float xPos = x;
+ float yPos = y;
+
+ hwc_transform_t transform = testLayers->getTransform(*layer);
+
+ float dfW = dfR - dfL;
+ float dfH = dfB - dfT;
+
+ /* If a layer has a transform, find which location on the
+ * layer will end up in the current pixel location. We
+ * can calculate the color of the current pixel using that
+ * location. */
+ if (transform > 0) {
+ /* Change origin to be the center of the layer. */
+ xPos = xPos - dfL - dfW / 2.0;
+ yPos = yPos - dfT - dfH / 2.0;
+
+ /* Flip Horizontal by reflecting across the y axis. */
+ if (transform & HWC_TRANSFORM_FLIP_H)
+ xPos = -xPos;
+
+ /* Flip vertical by reflecting across the x axis. */
+ if (transform & HWC_TRANSFORM_FLIP_V)
+ yPos = -yPos;
+
+ /* Rotate 90 by using a basic linear algebra rotation
+ * and scaling the result so the display frame remains
+ * the same. For example, a buffer of size 100x50 should
+ * rotate 90 degress but remain the same dimension
+ * (100x50) at the end of the transformation. */
+ if (transform & HWC_TRANSFORM_ROT_90) {
+ float tmp = xPos;
+ xPos = -yPos * dfW / dfH;
+ yPos = tmp * dfH / dfW;
+ }
+
+ /* Change origin back to the top left corner of the
+ * layer. */
+ xPos = xPos + dfL + dfW / 2.0;
+ yPos = yPos + dfT + dfH / 2.0;
+ }
+
+ hwc_frect_t sc = testLayers->getSourceCrop(*layer);
+ float scL = sc.left, scT = sc.top;
+
+ float dfWDivScW = dfW / (sc.right - scL);
+ float dfHDivScH = dfH / (sc.bottom - scT);
+
+ float max = 255, min = 0;
+
+ /* Choose the pixel color. Similar to generateBuffer,
+ * each layer will be divided into 3x3 colors. Because
+ * both the source crop and display frame must be taken into
+ * account, the formulas are more complicated.
+ *
+ * If the source crop and display frame were not taken into
+ * account, we would simply divide the buffer into three
+ * sections by height. Each section would get one color.
+ * For example the formula for the first section would be:
+ *
+ * if (yPos < bufferArea.height / 3)
+ * //Select first section color
+ *
+ * However the pixel color is chosen based on the source
+ * crop and displayed based on the display frame.
+ *
+ * If the display frame top was 0 and the source crop height
+ * and display frame height were the same. The only factor
+ * would be the source crop top. To calculate the new
+ * section boundary, the section boundary would be moved up
+ * by the height of the source crop top. The formula would
+ * be:
+ * if (yPos < (bufferArea.height / 3 - sourceCrop.top)
+ * //Select first section color
+ *
+ * If the display frame top could also vary but source crop
+ * and display frame heights were the same, the formula
+ * would be:
+ * if (yPos < (bufferArea.height / 3 - sourceCrop.top
+ * + displayFrameTop)
+ * //Select first section color
+ *
+ * If the heights were not the same, the conversion between
+ * the source crop and display frame dimensions must be
+ * taken into account. The formula would be:
+ * if (yPos < ((bufferArea.height / 3) - sourceCrop.top)
+ * * displayFrameHeight / sourceCropHeight
+ * + displayFrameTop)
+ * //Select first section color
+ */
+ if (yPos < ((bHDiv3) - scT) * dfHDivScH + dfT) {
+ min = 255 / 2;
+ } else if (yPos >= ((bH2Div3) - scT) * dfHDivScH + dfT) {
+ max = 255 / 2;
+ }
+
+ uint8_t rCur = min, gCur = min, bCur = min;
+ float aCur = 1.0f;
+
+ /* This further divides the color sections from 3 to 3x3.
+ * The math behind it follows the same logic as the previous
+ * comment */
+ if (xPos < ((bWDiv3) - scL) * (dfWDivScW) + dfL) {
+ rCur = max;
+ } else if (xPos < ((bW2Div3) - scL) * (dfWDivScW) + dfL) {
+ gCur = max;
+ } else {
+ bCur = max;
+ }
+
+
+ /* Blend the pixel color with the previous layers' pixel
+ * colors using the plane alpha and blend mode. The final
+ * pixel color is chosen using the plane alpha and blend
+ * mode formulas found in hwcomposer2.h */
+ hwc2_blend_mode_t blendMode = testLayers->getBlendMode(*layer);
+
+ if (blendMode == HWC2_BLEND_MODE_PREMULTIPLIED) {
+ rCur *= planeAlpha;
+ gCur *= planeAlpha;
+ bCur *= planeAlpha;
+ }
+
+ aCur *= planeAlpha;
+
+ if (blendMode == HWC2_BLEND_MODE_PREMULTIPLIED) {
+ r = rCur + r * (1.0 - aCur);
+ g = gCur + g * (1.0 - aCur);
+ b = bCur + b * (1.0 - aCur);
+ a = aCur + a * (1.0 - aCur);
+ } else if (blendMode == HWC2_BLEND_MODE_COVERAGE) {
+ r = rCur * aCur + r * (1.0 - aCur);
+ g = gCur * aCur + g * (1.0 - aCur);
+ b = bCur * aCur + b * (1.0 - aCur);
+ a = aCur * aCur + a * (1.0 - aCur);
+ } else {
+ r = rCur;
+ g = gCur;
+ b = bCur;
+ a = aCur;
+ }
+ }
+
+ /* Set the pixel color */
+ setColor(x, y, mFormat, stride, img, r, g, b, a * 255);
+ }
+ }
+
+ mGraphicBuffer->unlock();
+
+ *outFence = mFenceGenerator->get();
+ *outHandle = mGraphicBuffer->handle;
+
+ return 0;
+}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h
new file mode 100644
index 0000000..b2b3a66
--- /dev/null
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _HWC2_TEST_BUFFER_H
+#define _HWC2_TEST_BUFFER_H
+
+#include <android-base/unique_fd.h>
+#include <set>
+
+#include <hardware/hwcomposer2.h>
+
+#include <ui/GraphicBuffer.h>
+
+#include "Hwc2TestProperties.h"
+
+class Hwc2TestFenceGenerator;
+class Hwc2TestLayers;
+
+class Hwc2TestBuffer {
+public:
+ Hwc2TestBuffer();
+ ~Hwc2TestBuffer();
+
+ void updateBufferArea(const Area& bufferArea);
+
+ int get(buffer_handle_t* outHandle, int32_t* outFence);
+
+protected:
+ int generateBuffer();
+
+ android::sp<android::GraphicBuffer> mGraphicBuffer;
+
+ std::unique_ptr<Hwc2TestFenceGenerator> mFenceGenerator;
+
+ Area mBufferArea = {-1, -1};
+ const android_pixel_format_t mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+
+ bool mValidBuffer = false;
+ buffer_handle_t mHandle = nullptr;
+};
+
+
+class Hwc2TestClientTargetBuffer {
+public:
+ Hwc2TestClientTargetBuffer();
+ ~Hwc2TestClientTargetBuffer();
+
+ int get(buffer_handle_t* outHandle, int32_t* outFence,
+ const Area& bufferArea, const Hwc2TestLayers* testLayers,
+ const std::set<hwc2_layer_t>* clientLayers,
+ const std::set<hwc2_layer_t>* clearLayers);
+
+protected:
+ android::sp<android::GraphicBuffer> mGraphicBuffer;
+
+ std::unique_ptr<Hwc2TestFenceGenerator> mFenceGenerator;
+
+ const android_pixel_format_t mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+};
+
+#endif /* ifndef _HWC2_TEST_BUFFER_H */
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.cpp
new file mode 100644
index 0000000..6925492
--- /dev/null
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sstream>
+
+#include <ui/Rect.h>
+
+#include "Hwc2TestClientTarget.h"
+
+int Hwc2TestClientTarget::getBuffer(const Hwc2TestLayers& testLayers,
+ const std::set<hwc2_layer_t>& clientLayers,
+ const std::set<hwc2_layer_t>& clearLayers, bool flipClientTarget,
+ const Area& displayArea, buffer_handle_t* outHandle,
+ int32_t* outAcquireFence)
+{
+ if (!flipClientTarget) {
+ bool needsClientTarget = false;
+
+ for (auto clientLayer : clientLayers) {
+ if (testLayers.getVisibleRegion(clientLayer).numRects > 0) {
+ needsClientTarget = true;
+ break;
+ }
+ }
+
+ if (!needsClientTarget) {
+ *outHandle = nullptr;
+ *outAcquireFence = -1;
+ return 0;
+ }
+ }
+
+ return mBuffer.get(outHandle, outAcquireFence, displayArea,
+ &testLayers, &clientLayers, &clearLayers);
+}
+
+
+Hwc2TestClientTargetSupport::Hwc2TestClientTargetSupport(
+ Hwc2TestCoverage coverage, const Area& displayArea)
+ : mBufferArea(coverage, displayArea),
+ mDataspace(coverage),
+ mSurfaceDamage(coverage)
+{
+ mBufferArea.setDependent(&mSurfaceDamage);
+}
+
+std::string Hwc2TestClientTargetSupport::dump() const
+{
+ std::stringstream dmp;
+
+ dmp << "client target: \n";
+
+ for (auto property : properties) {
+ dmp << property->dump();
+ }
+
+ return dmp.str();
+}
+
+void Hwc2TestClientTargetSupport::reset()
+{
+ for (auto property : properties) {
+ property->reset();
+ }
+}
+
+bool Hwc2TestClientTargetSupport::advance()
+{
+ for (auto property : properties) {
+ if (property->advance())
+ return true;
+ }
+ return false;
+}
+
+Area Hwc2TestClientTargetSupport::getBufferArea() const
+{
+ return mBufferArea.get();
+}
+
+android_dataspace_t Hwc2TestClientTargetSupport::getDataspace() const
+{
+ return mDataspace.get();
+}
+
+const hwc_region_t Hwc2TestClientTargetSupport::getSurfaceDamage() const
+{
+ return mSurfaceDamage.get();
+}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.h b/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.h
new file mode 100644
index 0000000..3b47978
--- /dev/null
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _HWC2_TEST_CLIENT_TARGET_H
+#define _HWC2_TEST_CLIENT_TARGET_H
+
+#include <set>
+
+#define HWC2_INCLUDE_STRINGIFICATION
+#define HWC2_USE_CPP11
+#include <hardware/hwcomposer2.h>
+#undef HWC2_INCLUDE_STRINGIFICATION
+#undef HWC2_USE_CPP11
+
+#include "Hwc2TestProperties.h"
+#include "Hwc2TestLayers.h"
+
+/* Generates client target buffers from client composition layers */
+class Hwc2TestClientTarget {
+public:
+ int getBuffer(const Hwc2TestLayers& layers,
+ const std::set<hwc2_layer_t>& clientLayers,
+ const std::set<hwc2_layer_t>& clearLayers,
+ bool clearClientTarget, const Area& displayArea,
+ buffer_handle_t* outHandle, int32_t* outAcquireFence);
+
+private:
+ Hwc2TestClientTargetBuffer mBuffer;
+};
+
+/* Generates valid client targets to test which ones the device will support */
+class Hwc2TestClientTargetSupport {
+public:
+ Hwc2TestClientTargetSupport(Hwc2TestCoverage coverage,
+ const Area& displayArea);
+
+ std::string dump() const;
+
+ void reset();
+ bool advance();
+
+ Area getBufferArea() const;
+ android_dataspace_t getDataspace() const;
+ const hwc_region_t getSurfaceDamage() const;
+
+private:
+ std::array<Hwc2TestContainer*, 3> properties = {{
+ &mDataspace, &mSurfaceDamage, &mBufferArea
+ }};
+
+ Hwc2TestBufferArea mBufferArea;
+ Hwc2TestDataspace mDataspace;
+ Hwc2TestSurfaceDamage mSurfaceDamage;
+};
+
+#endif /* ifndef _HWC2_TEST_CLIENT_TARGET_H */
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp
new file mode 100644
index 0000000..937fce2
--- /dev/null
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sstream>
+
+#include "Hwc2TestLayer.h"
+
+Hwc2TestCoverage getCoverage(Hwc2TestPropertyName property,
+ Hwc2TestCoverage coverage, const std::unordered_map<Hwc2TestPropertyName,
+ Hwc2TestCoverage>& coverageExceptions) {
+ auto exception = coverageExceptions.find(property);
+ return (exception != coverageExceptions.end())? exception->second : coverage;
+}
+
+Hwc2TestLayer::Hwc2TestLayer(Hwc2TestCoverage coverage,
+ const Area& displayArea)
+ : Hwc2TestLayer(coverage, displayArea,
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage>()) { }
+
+Hwc2TestLayer::Hwc2TestLayer(Hwc2TestCoverage coverage,
+ const Area& displayArea, const std::unordered_map<Hwc2TestPropertyName,
+ Hwc2TestCoverage>& coverageExceptions)
+ : mBlendMode(getCoverage(Hwc2TestPropertyName::BlendMode, coverage,
+ coverageExceptions)),
+ mBufferArea(getCoverage(Hwc2TestPropertyName::BufferArea, coverage,
+ coverageExceptions), displayArea),
+ mColor(getCoverage(Hwc2TestPropertyName::Color, coverage,
+ coverageExceptions)),
+ mComposition(getCoverage(Hwc2TestPropertyName::Composition, coverage,
+ coverageExceptions)),
+ mDataspace(getCoverage(Hwc2TestPropertyName::Dataspace, coverage,
+ coverageExceptions)),
+ mDisplayFrame(getCoverage(Hwc2TestPropertyName::DisplayFrame, coverage,
+ coverageExceptions), displayArea),
+ mPlaneAlpha(getCoverage(Hwc2TestPropertyName::PlaneAlpha, coverage,
+ coverageExceptions)),
+ mSourceCrop(getCoverage(Hwc2TestPropertyName::SourceCrop, coverage,
+ coverageExceptions)),
+ mSurfaceDamage(getCoverage(Hwc2TestPropertyName::SurfaceDamage, coverage,
+ coverageExceptions)),
+ mTransform(getCoverage(Hwc2TestPropertyName::Transform, coverage,
+ coverageExceptions))
+{
+ mBufferArea.setDependent(&mBuffer);
+ mBufferArea.setDependent(&mSourceCrop);
+ mBufferArea.setDependent(&mSurfaceDamage);
+ mBlendMode.setDependent(&mColor);
+}
+
+std::string Hwc2TestLayer::dump() const
+{
+ std::stringstream dmp;
+
+ dmp << "layer: \n";
+
+ for (auto property : mProperties) {
+ dmp << property->dump();
+ }
+
+ dmp << mVisibleRegion.dump();
+ dmp << "\tz order: " << mZOrder << "\n";
+
+ return dmp.str();
+}
+
+int Hwc2TestLayer::getBuffer(buffer_handle_t* outHandle,
+ android::base::unique_fd* outAcquireFence)
+{
+ int32_t acquireFence;
+ int ret = mBuffer.get(outHandle, &acquireFence);
+ outAcquireFence->reset(acquireFence);
+ return ret;
+}
+
+int Hwc2TestLayer::getBuffer(buffer_handle_t* outHandle,
+ int32_t* outAcquireFence)
+{
+ return mBuffer.get(outHandle, outAcquireFence);
+}
+
+void Hwc2TestLayer::setZOrder(uint32_t zOrder)
+{
+ mZOrder = zOrder;
+}
+
+void Hwc2TestLayer::setVisibleRegion(const android::Region& region)
+{
+ return mVisibleRegion.set(region);
+}
+
+void Hwc2TestLayer::reset()
+{
+ mVisibleRegion.release();
+
+ for (auto property : mProperties) {
+ property->reset();
+ }
+}
+
+bool Hwc2TestLayer::advance()
+{
+ for (auto property : mProperties) {
+ if (property->isSupported(mComposition.get()))
+ if (property->advance())
+ return true;
+ }
+ return false;
+}
+
+hwc2_blend_mode_t Hwc2TestLayer::getBlendMode() const
+{
+ return mBlendMode.get();
+}
+
+Area Hwc2TestLayer::getBufferArea() const
+{
+ return mBufferArea.get();
+}
+
+hwc_color_t Hwc2TestLayer::getColor() const
+{
+ return mColor.get();
+}
+
+hwc2_composition_t Hwc2TestLayer::getComposition() const
+{
+ return mComposition.get();
+}
+
+/* The cursor position corresponds to {displayFrame.left, displayFrame.top} */
+hwc_rect_t Hwc2TestLayer::getCursorPosition() const
+{
+ return mDisplayFrame.get();
+}
+
+android_dataspace_t Hwc2TestLayer::getDataspace() const
+{
+ return mDataspace.get();
+}
+
+hwc_rect_t Hwc2TestLayer::getDisplayFrame() const
+{
+ return mDisplayFrame.get();
+}
+
+float Hwc2TestLayer::getPlaneAlpha() const
+{
+ return mPlaneAlpha.get();
+}
+
+hwc_frect_t Hwc2TestLayer::getSourceCrop() const
+{
+ return mSourceCrop.get();
+}
+
+hwc_region_t Hwc2TestLayer::getSurfaceDamage() const
+{
+ return mSurfaceDamage.get();
+}
+
+hwc_transform_t Hwc2TestLayer::getTransform() const
+{
+ return mTransform.get();
+}
+
+hwc_region_t Hwc2TestLayer::getVisibleRegion() const
+{
+ return mVisibleRegion.get();
+}
+
+uint32_t Hwc2TestLayer::getZOrder() const
+{
+ return mZOrder;
+}
+
+bool Hwc2TestLayer::advanceBlendMode()
+{
+ return mBlendMode.advance();
+}
+
+bool Hwc2TestLayer::advanceBufferArea()
+{
+ return mBufferArea.advance();
+}
+
+bool Hwc2TestLayer::advanceColor()
+{
+ return mColor.advance();
+}
+
+bool Hwc2TestLayer::advanceComposition()
+{
+ return mComposition.advance();
+}
+
+bool Hwc2TestLayer::advanceCursorPosition()
+{
+ return mDisplayFrame.advance();
+}
+
+bool Hwc2TestLayer::advanceDataspace()
+{
+ return mDataspace.advance();
+}
+
+bool Hwc2TestLayer::advanceDisplayFrame()
+{
+ return mDisplayFrame.advance();
+}
+
+bool Hwc2TestLayer::advancePlaneAlpha()
+{
+ return mPlaneAlpha.advance();
+}
+
+bool Hwc2TestLayer::advanceSourceCrop()
+{
+ return mSourceCrop.advance();
+}
+
+bool Hwc2TestLayer::advanceSurfaceDamage()
+{
+ return mSurfaceDamage.advance();
+}
+
+bool Hwc2TestLayer::advanceTransform()
+{
+ return mTransform.advance();
+}
+
+bool Hwc2TestLayer::advanceVisibleRegion()
+{
+ if (mPlaneAlpha.advance())
+ return true;
+ return mDisplayFrame.advance();
+}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h b/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h
new file mode 100644
index 0000000..0e7dd22
--- /dev/null
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _HWC2_TEST_LAYER_H
+#define _HWC2_TEST_LAYER_H
+
+#include <android-base/unique_fd.h>
+#include <unordered_map>
+
+#include "Hwc2TestBuffer.h"
+#include "Hwc2TestProperties.h"
+
+#define HWC2_INCLUDE_STRINGIFICATION
+#define HWC2_USE_CPP11
+#include <hardware/hwcomposer2.h>
+#undef HWC2_INCLUDE_STRINGIFICATION
+#undef HWC2_USE_CPP11
+
+class Hwc2TestLayer {
+public:
+ Hwc2TestLayer(Hwc2TestCoverage coverage, const Area& displayArea);
+
+ Hwc2TestLayer(Hwc2TestCoverage coverage, const Area& displayArea,
+ const std::unordered_map<Hwc2TestPropertyName,
+ Hwc2TestCoverage>& coverage_exceptions);
+
+ std::string dump() const;
+
+ int getBuffer(buffer_handle_t* outHandle,
+ android::base::unique_fd* outAcquireFence);
+ int getBuffer(buffer_handle_t* outHandle, int32_t* outAcquireFence);
+
+ void setZOrder(uint32_t zOrder);
+ void setVisibleRegion(const android::Region& region);
+
+ void reset();
+ bool advance();
+
+ hwc2_blend_mode_t getBlendMode() const;
+ Area getBufferArea() const;
+ hwc_color_t getColor() const;
+ hwc2_composition_t getComposition() const;
+ hwc_rect_t getCursorPosition() const;
+ android_dataspace_t getDataspace() const;
+ hwc_rect_t getDisplayFrame() const;
+ float getPlaneAlpha() const;
+ hwc_frect_t getSourceCrop() const;
+ hwc_region_t getSurfaceDamage() const;
+ hwc_transform_t getTransform() const;
+ hwc_region_t getVisibleRegion() const;
+ uint32_t getZOrder() const;
+
+ bool advanceBlendMode();
+ bool advanceBufferArea();
+ bool advanceColor();
+ bool advanceComposition();
+ bool advanceCursorPosition();
+ bool advanceDataspace();
+ bool advanceDisplayFrame();
+ bool advancePlaneAlpha();
+ bool advanceSourceCrop();
+ bool advanceSurfaceDamage();
+ bool advanceTransform();
+ bool advanceVisibleRegion();
+
+private:
+ std::array<Hwc2TestContainer*, 10> mProperties = {{
+ &mTransform, &mColor, &mDataspace, &mPlaneAlpha, &mSourceCrop,
+ &mSurfaceDamage, &mBlendMode, &mBufferArea, &mDisplayFrame,
+ &mComposition
+ }};
+
+ Hwc2TestBuffer mBuffer;
+
+ Hwc2TestBlendMode mBlendMode;
+ Hwc2TestBufferArea mBufferArea;
+ Hwc2TestColor mColor;
+ Hwc2TestComposition mComposition;
+ Hwc2TestDataspace mDataspace;
+ Hwc2TestDisplayFrame mDisplayFrame;
+ Hwc2TestPlaneAlpha mPlaneAlpha;
+ Hwc2TestSourceCrop mSourceCrop;
+ Hwc2TestSurfaceDamage mSurfaceDamage;
+ Hwc2TestTransform mTransform;
+ Hwc2TestVisibleRegion mVisibleRegion;
+
+ uint32_t mZOrder = UINT32_MAX;
+};
+
+#endif /* ifndef _HWC2_TEST_LAYER_H */
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp
new file mode 100644
index 0000000..495ef79
--- /dev/null
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp
@@ -0,0 +1,281 @@
+/* * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sstream>
+#include <gtest/gtest.h>
+
+#include "Hwc2TestLayers.h"
+
+Hwc2TestLayers::Hwc2TestLayers(const std::vector<hwc2_layer_t>& layers,
+ Hwc2TestCoverage coverage, const Area& displayArea)
+ : Hwc2TestLayers(layers, coverage, displayArea,
+ std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage>()) { }
+
+Hwc2TestLayers::Hwc2TestLayers(const std::vector<hwc2_layer_t>& layers,
+ Hwc2TestCoverage coverage, const Area& displayArea,
+ const std::unordered_map<Hwc2TestPropertyName,
+ Hwc2TestCoverage>& coverageExceptions)
+ : mDisplayArea(displayArea)
+{
+ for (auto layer : layers) {
+ mTestLayers.emplace(std::piecewise_construct,
+ std::forward_as_tuple(layer),
+ std::forward_as_tuple(coverage, displayArea, coverageExceptions));
+ }
+
+ /* Iterate over the layers in order and assign z orders in the same order.
+ * This allows us to iterate over z orders in the same way when computing
+ * visible regions */
+ uint32_t nextZOrder = layers.size();
+
+ for (auto& testLayer : mTestLayers) {
+ testLayer.second.setZOrder(nextZOrder--);
+ }
+
+ setVisibleRegions();
+}
+
+std::string Hwc2TestLayers::dump() const
+{
+ std::stringstream dmp;
+ for (auto& testLayer : mTestLayers) {
+ dmp << testLayer.second.dump();
+ }
+ return dmp.str();
+}
+
+void Hwc2TestLayers::reset()
+{
+ for (auto& testLayer : mTestLayers) {
+ testLayer.second.reset();
+ }
+
+ setVisibleRegions();
+}
+
+bool Hwc2TestLayers::advance()
+{
+ auto itr = mTestLayers.begin();
+ bool optimized;
+
+ while (itr != mTestLayers.end()) {
+ if (itr->second.advance()) {
+ optimized = setVisibleRegions();
+ if (!mOptimize || optimized)
+ return true;
+ itr = mTestLayers.begin();
+ } else {
+ itr->second.reset();
+ ++itr;
+ }
+ }
+ return false;
+}
+
+bool Hwc2TestLayers::advanceVisibleRegions()
+{
+ auto itr = mTestLayers.begin();
+ bool optimized;
+
+ while (itr != mTestLayers.end()) {
+ if (itr->second.advanceVisibleRegion()) {
+ optimized = setVisibleRegions();
+ if (!mOptimize || optimized)
+ return true;
+ itr = mTestLayers.begin();
+ } else {
+ itr->second.reset();
+ ++itr;
+ }
+ }
+ return false;
+}
+
+/* Removes layouts that do not cover the entire display.
+ * Also removes layouts where a layer is completely blocked from view.
+ */
+bool Hwc2TestLayers::optimizeLayouts()
+{
+ mOptimize = true;
+
+ if (setVisibleRegions())
+ return true;
+ return advance();
+}
+
+bool Hwc2TestLayers::contains(hwc2_layer_t layer) const
+{
+ return mTestLayers.count(layer) != 0;
+}
+
+int Hwc2TestLayers::getBuffer(hwc2_layer_t layer, buffer_handle_t* outHandle,
+ int32_t* outAcquireFence)
+{
+ if (mTestLayers.count(layer) == 0) {
+ []() { GTEST_FAIL(); }();
+ }
+ return mTestLayers.at(layer).getBuffer(outHandle, outAcquireFence);
+}
+
+hwc2_blend_mode_t Hwc2TestLayers::getBlendMode(hwc2_layer_t layer) const
+{
+ if (mTestLayers.count(layer) == 0) {
+ []() { GTEST_FAIL(); }();
+ }
+ return mTestLayers.at(layer).getBlendMode();
+}
+
+Area Hwc2TestLayers::getBufferArea(hwc2_layer_t layer) const
+{
+ auto testLayer = mTestLayers.find(layer);
+ if (testLayer == mTestLayers.end())
+ [] () { GTEST_FAIL(); }();
+ return testLayer->second.getBufferArea();
+}
+
+hwc_color_t Hwc2TestLayers::getColor(hwc2_layer_t layer) const
+{
+ if (mTestLayers.count(layer) == 0) {
+ []() { GTEST_FAIL(); }();
+ }
+ return mTestLayers.at(layer).getColor();
+}
+
+hwc2_composition_t Hwc2TestLayers::getComposition(hwc2_layer_t layer) const
+{
+ if (mTestLayers.count(layer) == 0) {
+ []() { GTEST_FAIL(); }();
+ }
+ return mTestLayers.at(layer).getComposition();
+}
+
+hwc_rect_t Hwc2TestLayers::getCursorPosition(hwc2_layer_t layer) const
+{
+ if (mTestLayers.count(layer) == 0) {
+ []() { GTEST_FAIL(); }();
+ }
+ return mTestLayers.at(layer).getCursorPosition();
+}
+
+android_dataspace_t Hwc2TestLayers::getDataspace(hwc2_layer_t layer) const
+{
+ if (mTestLayers.count(layer) == 0) {
+ []() { GTEST_FAIL(); }();
+ }
+ return mTestLayers.at(layer).getDataspace();
+}
+
+hwc_rect_t Hwc2TestLayers::getDisplayFrame(hwc2_layer_t layer) const
+{
+ if (mTestLayers.count(layer) == 0) {
+ []() { GTEST_FAIL(); }();
+ }
+ return mTestLayers.at(layer).getDisplayFrame();
+}
+
+float Hwc2TestLayers::getPlaneAlpha(hwc2_layer_t layer) const
+{
+ if (mTestLayers.count(layer) == 0) {
+ []() { GTEST_FAIL(); }();
+ }
+ return mTestLayers.at(layer).getPlaneAlpha();
+}
+
+hwc_frect_t Hwc2TestLayers::getSourceCrop(hwc2_layer_t layer) const
+{
+ if (mTestLayers.count(layer) == 0) {
+ []() { GTEST_FAIL(); }();
+ }
+ return mTestLayers.at(layer).getSourceCrop();
+}
+
+hwc_region_t Hwc2TestLayers::getSurfaceDamage(hwc2_layer_t layer) const
+{
+ if (mTestLayers.count(layer) == 0) {
+ []() { GTEST_FAIL(); }();
+ }
+ return mTestLayers.at(layer).getSurfaceDamage();
+}
+
+hwc_transform_t Hwc2TestLayers::getTransform(hwc2_layer_t layer) const
+{
+ if (mTestLayers.count(layer) == 0) {
+ []() { GTEST_FAIL(); }();
+ }
+ return mTestLayers.at(layer).getTransform();
+}
+
+hwc_region_t Hwc2TestLayers::getVisibleRegion(hwc2_layer_t layer) const
+{
+ if (mTestLayers.count(layer) == 0) {
+ []() { GTEST_FAIL(); }();
+ }
+ return mTestLayers.at(layer).getVisibleRegion();
+}
+
+uint32_t Hwc2TestLayers::getZOrder(hwc2_layer_t layer) const
+{
+ if (mTestLayers.count(layer) == 0) {
+ []() { GTEST_FAIL(); }();
+ }
+ return mTestLayers.at(layer).getZOrder();
+}
+
+/* Sets the visible regions for a display. Returns false if the layers do not
+ * cover the entire display or if a layer is not visible */
+bool Hwc2TestLayers::setVisibleRegions()
+{
+ /* The region of the display that is covered by layers above the current
+ * layer */
+ android::Region aboveOpaqueLayers;
+
+ bool optimized = true;
+
+ /* Iterate over test layers from max z order to min z order. */
+ for (auto& testLayer : mTestLayers) {
+ android::Region visibleRegion;
+
+ /* Set the visible region of this layer */
+ const hwc_rect_t displayFrame = testLayer.second.getDisplayFrame();
+
+ visibleRegion.set(android::Rect(displayFrame.left, displayFrame.top,
+ displayFrame.right, displayFrame.bottom));
+
+ /* Remove the area covered by opaque layers above this layer
+ * from this layer's visible region */
+ visibleRegion.subtractSelf(aboveOpaqueLayers);
+
+ testLayer.second.setVisibleRegion(visibleRegion);
+
+ /* If a layer is not visible, return false */
+ if (visibleRegion.isEmpty())
+ optimized = false;
+
+ /* If this layer is opaque, store the region it covers */
+ if (testLayer.second.getPlaneAlpha() == 1.0f)
+ aboveOpaqueLayers.orSelf(visibleRegion);
+ }
+
+ /* If the opaque region does not cover the entire display return false */
+ if (!aboveOpaqueLayers.isRect())
+ return false;
+
+ const auto rect = aboveOpaqueLayers.begin();
+ if (rect->left != 0 || rect->top != 0 || rect->right != mDisplayArea.width
+ || rect->bottom != mDisplayArea.height)
+ return false;
+
+ return optimized;
+}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.h b/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.h
new file mode 100644
index 0000000..d95a91f
--- /dev/null
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _HWC2_TEST_LAYERS_H
+#define _HWC2_TEST_LAYERS_H
+
+#include <map>
+
+#define HWC2_INCLUDE_STRINGIFICATION
+#define HWC2_USE_CPP11
+#include <hardware/hwcomposer2.h>
+#undef HWC2_INCLUDE_STRINGIFICATION
+#undef HWC2_USE_CPP11
+
+#include "Hwc2TestProperties.h"
+#include "Hwc2TestLayer.h"
+
+class Hwc2TestLayers {
+public:
+ Hwc2TestLayers(const std::vector<hwc2_layer_t>& layers,
+ Hwc2TestCoverage coverage, const Area& displayArea);
+
+ Hwc2TestLayers(const std::vector<hwc2_layer_t>& layers,
+ Hwc2TestCoverage coverage, const Area& displayArea,
+ const std::unordered_map<Hwc2TestPropertyName,
+ Hwc2TestCoverage>& coverageExceptions);
+
+ std::string dump() const;
+
+ void reset();
+
+ bool advance();
+ bool advanceVisibleRegions();
+
+ /* Test cases with multiple layers and property values can take quite some
+ * time to run. A significant amount of time can be spent on test cases
+ * where one layer is changing property values but is not visible. To
+ * decrease runtime, this function can be called. Removes layouts where a
+ * layer is completely blocked from view. It also removes layouts that do
+ * not cover the entire display.*/
+ bool optimizeLayouts();
+
+ bool contains(hwc2_layer_t layer) const;
+
+ int getBuffer(hwc2_layer_t layer, buffer_handle_t* outHandle,
+ int32_t* outAcquireFence);
+
+ hwc2_blend_mode_t getBlendMode(hwc2_layer_t layer) const;
+ Area getBufferArea(hwc2_layer_t layer) const;
+ hwc_color_t getColor(hwc2_layer_t layer) const;
+ hwc2_composition_t getComposition(hwc2_layer_t layer) const;
+ hwc_rect_t getCursorPosition(hwc2_layer_t layer) const;
+ android_dataspace_t getDataspace(hwc2_layer_t layer) const;
+ hwc_rect_t getDisplayFrame(hwc2_layer_t layer) const;
+ android_pixel_format_t getFormat(hwc2_layer_t layer) const;
+ float getPlaneAlpha(hwc2_layer_t layer) const;
+ hwc_frect_t getSourceCrop(hwc2_layer_t layer) const;
+ hwc_region_t getSurfaceDamage(hwc2_layer_t layer) const;
+ hwc_transform_t getTransform(hwc2_layer_t layer) const;
+ hwc_region_t getVisibleRegion(hwc2_layer_t layer) const;
+ uint32_t getZOrder(hwc2_layer_t layer) const;
+
+private:
+ bool setVisibleRegions();
+
+ std::map<hwc2_layer_t, Hwc2TestLayer> mTestLayers;
+
+ Area mDisplayArea;
+
+ bool mOptimize = false;
+};
+
+#endif /* ifndef _HWC2_TEST_LAYERS_H */
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp
new file mode 100644
index 0000000..b5522de
--- /dev/null
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp
@@ -0,0 +1,782 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sstream>
+#include <cutils/log.h>
+#include <ui/Rect.h>
+
+#define HWC2_INCLUDE_STRINGIFICATION
+#define HWC2_USE_CPP11
+#include <hardware/hwcomposer2.h>
+#undef HWC2_INCLUDE_STRINGIFICATION
+#undef HWC2_USE_CPP11
+
+#include "Hwc2TestBuffer.h"
+#include "Hwc2TestProperties.h"
+
+Hwc2TestBufferArea::Hwc2TestBufferArea(Hwc2TestCoverage coverage,
+ const Area& displayArea)
+ : Hwc2TestProperty(mBufferAreas, mCompositionSupport),
+ mScalars((coverage == Hwc2TestCoverage::Complete)? mCompleteScalars:
+ (coverage == Hwc2TestCoverage::Basic)? mBasicScalars:
+ mDefaultScalars),
+ mDisplayArea(displayArea)
+{
+ update();
+}
+
+std::string Hwc2TestBufferArea::dump() const
+{
+ std::stringstream dmp;
+ const Area& curr = get();
+ dmp << "\tbuffer area: width " << curr.width << ", height " << curr.height
+ << "\n";
+ return dmp.str();
+}
+
+void Hwc2TestBufferArea::setDependent(Hwc2TestBuffer* buffer)
+{
+ mBuffer = buffer;
+ if (buffer) {
+ buffer->updateBufferArea(get());
+ }
+}
+
+void Hwc2TestBufferArea::setDependent(Hwc2TestSourceCrop* sourceCrop)
+{
+ mSourceCrop = sourceCrop;
+ if (mSourceCrop) {
+ mSourceCrop->updateBufferArea(get());
+ }
+}
+
+void Hwc2TestBufferArea::setDependent(Hwc2TestSurfaceDamage* surfaceDamage)
+{
+ mSurfaceDamage = surfaceDamage;
+ if (mSurfaceDamage) {
+ mSurfaceDamage->updateBufferArea(get());
+ }
+}
+
+void Hwc2TestBufferArea::update()
+{
+ mBufferAreas.clear();
+
+ if (mDisplayArea.width == 0 && mDisplayArea.height == 0) {
+ mBufferAreas.push_back({0, 0});
+ return;
+ }
+
+ for (auto scalar : mScalars) {
+ mBufferAreas.push_back({static_cast<int32_t>(scalar * mDisplayArea.width),
+ static_cast<int32_t>(scalar * mDisplayArea.height)});
+ }
+
+ updateDependents();
+}
+
+void Hwc2TestBufferArea::updateDependents()
+{
+ const Area& curr = get();
+
+ if (mBuffer)
+ mBuffer->updateBufferArea(curr);
+ if (mSourceCrop)
+ mSourceCrop->updateBufferArea(curr);
+ if (mSurfaceDamage)
+ mSurfaceDamage->updateBufferArea(curr);
+}
+
+const std::vector<float> Hwc2TestBufferArea::mDefaultScalars = {
+ 1.0f,
+};
+
+const std::vector<float> Hwc2TestBufferArea::mBasicScalars = {
+ 1.0f, 0.5f,
+};
+
+const std::vector<float> Hwc2TestBufferArea::mCompleteScalars = {
+ 1.0f, 0.75f, 0.5f
+};
+
+
+Hwc2TestBlendMode::Hwc2TestBlendMode(Hwc2TestCoverage coverage)
+ : Hwc2TestProperty(coverage, mCompleteBlendModes, mBasicBlendModes,
+ mDefaultBlendModes, mCompositionSupport) { }
+
+std::string Hwc2TestBlendMode::dump() const
+{
+ std::stringstream dmp;
+ dmp << "\tblend mode: " << getBlendModeName(get()) << "\n";
+ return dmp.str();
+}
+
+void Hwc2TestBlendMode::setDependent(Hwc2TestColor* color)
+{
+ mColor = color;
+ updateDependents();
+}
+
+void Hwc2TestBlendMode::updateDependents()
+{
+ if (mColor)
+ mColor->updateBlendMode(get());
+}
+
+const std::vector<hwc2_blend_mode_t> Hwc2TestBlendMode::mDefaultBlendModes = {
+ HWC2_BLEND_MODE_NONE,
+};
+
+const std::vector<hwc2_blend_mode_t> Hwc2TestBlendMode::mBasicBlendModes = {
+ HWC2_BLEND_MODE_NONE,
+ HWC2_BLEND_MODE_PREMULTIPLIED,
+};
+
+const std::vector<hwc2_blend_mode_t> Hwc2TestBlendMode::mCompleteBlendModes = {
+ HWC2_BLEND_MODE_NONE,
+ HWC2_BLEND_MODE_PREMULTIPLIED,
+ HWC2_BLEND_MODE_COVERAGE,
+};
+
+
+Hwc2TestColor::Hwc2TestColor(Hwc2TestCoverage coverage,
+ hwc2_blend_mode_t blendMode)
+ : Hwc2TestProperty(mColors, mCompositionSupport),
+ mBaseColors((coverage == Hwc2TestCoverage::Complete)? mCompleteBaseColors:
+ (coverage == Hwc2TestCoverage::Basic)? mBasicBaseColors:
+ mDefaultBaseColors),
+ mBlendMode(blendMode)
+{
+ update();
+}
+
+std::string Hwc2TestColor::dump() const
+{
+ std::stringstream dmp;
+ const hwc_color_t& color = get();
+ dmp << "\tcolor: r " << std::to_string(color.r) << ", g "
+ << std::to_string(color.g) << ", b " << std::to_string(color.b)
+ << ", a " << std::to_string(color.a) << "\n";
+ return dmp.str();
+}
+
+void Hwc2TestColor::updateBlendMode(hwc2_blend_mode_t blendMode)
+{
+ mBlendMode = blendMode;
+ update();
+}
+
+void Hwc2TestColor::update()
+{
+ if (mBlendMode != HWC2_BLEND_MODE_PREMULTIPLIED) {
+ mColors = mBaseColors;
+ return;
+ }
+
+ mColors.clear();
+
+ for (const hwc_color_t& baseColor : mBaseColors) {
+ if (baseColor.a >= baseColor.r && baseColor.a >= baseColor.g
+ && baseColor.a >= baseColor.b) {
+ mColors.push_back(baseColor);
+ }
+ }
+
+}
+
+const std::vector<hwc_color_t> Hwc2TestColor::mDefaultBaseColors = {
+ {UINT8_MAX, UINT8_MAX, UINT8_MAX, UINT8_MAX},
+};
+
+const std::vector<hwc_color_t> Hwc2TestColor::mBasicBaseColors = {
+ {UINT8_MAX, UINT8_MAX, UINT8_MAX, UINT8_MAX},
+ { 0, 0, 0, 0},
+};
+
+const std::vector<hwc_color_t> Hwc2TestColor::mCompleteBaseColors = {
+ {UINT8_MAX, UINT8_MAX, UINT8_MAX, UINT8_MAX},
+ {UINT8_MAX, UINT8_MAX, UINT8_MAX, 0},
+ {UINT8_MAX, UINT8_MAX, 0, UINT8_MAX},
+ {UINT8_MAX, UINT8_MAX, 0, 0},
+ {UINT8_MAX, 0, UINT8_MAX, UINT8_MAX},
+ {UINT8_MAX, 0, UINT8_MAX, 0},
+ {UINT8_MAX, 0, 0, UINT8_MAX},
+ {UINT8_MAX, 0, 0, 0},
+ { 0, UINT8_MAX, UINT8_MAX, UINT8_MAX},
+ { 0, UINT8_MAX, UINT8_MAX, 0},
+ { 0, UINT8_MAX, 0, UINT8_MAX},
+ { 0, UINT8_MAX, 0, 0},
+ { 0, 0, UINT8_MAX, UINT8_MAX},
+ { 0, 0, UINT8_MAX, 0},
+ { 0, 0, 0, UINT8_MAX},
+ { 0, 0, 0, 0},
+};
+
+
+Hwc2TestComposition::Hwc2TestComposition(Hwc2TestCoverage coverage)
+ : Hwc2TestProperty(coverage, mCompleteCompositions, mBasicCompositions,
+ mDefaultCompositions, mCompositionSupport) { }
+
+std::string Hwc2TestComposition::dump() const
+{
+ std::stringstream dmp;
+ dmp << "\tcomposition: " << getCompositionName(get()) << "\n";
+ return dmp.str();
+}
+
+const std::vector<hwc2_composition_t> Hwc2TestComposition::mDefaultCompositions = {
+ HWC2_COMPOSITION_DEVICE,
+};
+
+const std::vector<hwc2_composition_t> Hwc2TestComposition::mBasicCompositions = {
+ HWC2_COMPOSITION_CLIENT,
+ HWC2_COMPOSITION_DEVICE,
+};
+
+const std::vector<hwc2_composition_t> Hwc2TestComposition::mCompleteCompositions = {
+ HWC2_COMPOSITION_CLIENT,
+ HWC2_COMPOSITION_DEVICE,
+ HWC2_COMPOSITION_SOLID_COLOR,
+ HWC2_COMPOSITION_CURSOR,
+ HWC2_COMPOSITION_SIDEBAND,
+};
+
+
+Hwc2TestDataspace::Hwc2TestDataspace(Hwc2TestCoverage coverage)
+ : Hwc2TestProperty(coverage, completeDataspaces, basicDataspaces,
+ defaultDataspaces, mCompositionSupport) { }
+
+std::string Hwc2TestDataspace::dump() const
+{
+ std::stringstream dmp;
+ dmp << "\tdataspace: " << get() << "\n";
+ return dmp.str();
+}
+
+const std::vector<android_dataspace_t> Hwc2TestDataspace::defaultDataspaces = {
+ HAL_DATASPACE_UNKNOWN,
+};
+
+const std::vector<android_dataspace_t> Hwc2TestDataspace::basicDataspaces = {
+ HAL_DATASPACE_UNKNOWN,
+ HAL_DATASPACE_V0_SRGB,
+};
+
+const std::vector<android_dataspace_t> Hwc2TestDataspace::completeDataspaces = {
+ HAL_DATASPACE_UNKNOWN,
+ HAL_DATASPACE_ARBITRARY,
+ HAL_DATASPACE_STANDARD_SHIFT,
+ HAL_DATASPACE_STANDARD_MASK,
+ HAL_DATASPACE_STANDARD_UNSPECIFIED,
+ HAL_DATASPACE_STANDARD_BT709,
+ HAL_DATASPACE_STANDARD_BT601_625,
+ HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED,
+ HAL_DATASPACE_STANDARD_BT601_525,
+ HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED,
+ HAL_DATASPACE_STANDARD_BT2020,
+ HAL_DATASPACE_STANDARD_BT2020_CONSTANT_LUMINANCE,
+ HAL_DATASPACE_STANDARD_BT470M,
+ HAL_DATASPACE_STANDARD_FILM,
+ HAL_DATASPACE_TRANSFER_SHIFT,
+ HAL_DATASPACE_TRANSFER_MASK,
+ HAL_DATASPACE_TRANSFER_UNSPECIFIED,
+ HAL_DATASPACE_TRANSFER_LINEAR,
+ HAL_DATASPACE_TRANSFER_SRGB,
+ HAL_DATASPACE_TRANSFER_SMPTE_170M,
+ HAL_DATASPACE_TRANSFER_GAMMA2_2,
+ HAL_DATASPACE_TRANSFER_GAMMA2_8,
+ HAL_DATASPACE_TRANSFER_ST2084,
+ HAL_DATASPACE_TRANSFER_HLG,
+ HAL_DATASPACE_RANGE_SHIFT,
+ HAL_DATASPACE_RANGE_MASK,
+ HAL_DATASPACE_RANGE_UNSPECIFIED,
+ HAL_DATASPACE_RANGE_FULL,
+ HAL_DATASPACE_RANGE_LIMITED,
+ HAL_DATASPACE_SRGB_LINEAR,
+ HAL_DATASPACE_V0_SRGB_LINEAR,
+ HAL_DATASPACE_SRGB,
+ HAL_DATASPACE_V0_SRGB,
+ HAL_DATASPACE_JFIF,
+ HAL_DATASPACE_V0_JFIF,
+ HAL_DATASPACE_BT601_625,
+ HAL_DATASPACE_V0_BT601_625,
+ HAL_DATASPACE_BT601_525,
+ HAL_DATASPACE_V0_BT601_525,
+ HAL_DATASPACE_BT709,
+ HAL_DATASPACE_V0_BT709,
+ HAL_DATASPACE_DEPTH,
+};
+
+
+Hwc2TestDisplayDimension::Hwc2TestDisplayDimension(Hwc2TestCoverage coverage)
+ : Hwc2TestProperty(
+ (coverage == Hwc2TestCoverage::Complete)? mCompleteDisplayDimensions:
+ (coverage == Hwc2TestCoverage::Basic)? mBasicDisplayDimensions:
+ mDefaultDisplayDimensions, mCompositionSupport) { }
+
+std::string Hwc2TestDisplayDimension::dump() const
+{
+ std::stringstream dmp;
+ const UnsignedArea& curr = get();
+ dmp << "\tdisplay dimension: " << curr.width<< " x " << curr.height<< "\n";
+ return dmp.str();
+}
+
+void Hwc2TestDisplayDimension::setDependent(Hwc2TestBuffer* buffer)
+{
+ mBuffer = buffer;
+ updateDependents();
+}
+
+void Hwc2TestDisplayDimension::updateDependents()
+{
+ const UnsignedArea& curr = get();
+
+ if (mBuffer)
+ mBuffer->updateBufferArea({static_cast<int32_t>(curr.width),
+ static_cast<int32_t>(curr.height)});
+}
+
+const std::vector<UnsignedArea>
+ Hwc2TestDisplayDimension::mDefaultDisplayDimensions = {
+ {1920, 1080},
+};
+
+const std::vector<UnsignedArea>
+ Hwc2TestDisplayDimension::mBasicDisplayDimensions = {
+ {640, 480},
+ {1280, 720},
+ {1920, 1080},
+ {1920, 1200},
+};
+
+const std::vector<UnsignedArea>
+ Hwc2TestDisplayDimension::mCompleteDisplayDimensions = {
+ {320, 240},
+ {480, 320},
+ {640, 480},
+ {1280, 720},
+ {1920, 1080},
+ {1920, 1200},
+ {2560, 1440},
+ {2560, 1600},
+ {3840, 2160},
+ {4096, 2160},
+};
+
+
+Hwc2TestDisplayFrame::Hwc2TestDisplayFrame(Hwc2TestCoverage coverage,
+ const Area& displayArea)
+ : Hwc2TestProperty(mDisplayFrames, mCompositionSupport),
+ mFrectScalars((coverage == Hwc2TestCoverage::Complete)? mCompleteFrectScalars:
+ (coverage == Hwc2TestCoverage::Basic)? mBasicFrectScalars:
+ mDefaultFrectScalars),
+ mDisplayArea(displayArea)
+{
+ update();
+}
+
+std::string Hwc2TestDisplayFrame::dump() const
+{
+ std::stringstream dmp;
+ const hwc_rect_t& displayFrame = get();
+ dmp << "\tdisplay frame: left " << displayFrame.left << ", top "
+ << displayFrame.top << ", right " << displayFrame.right
+ << ", bottom " << displayFrame.bottom << "\n";
+ return dmp.str();
+}
+
+void Hwc2TestDisplayFrame::update()
+{
+ mDisplayFrames.clear();
+
+ if (mDisplayArea.width == 0 && mDisplayArea.height == 0) {
+ mDisplayFrames.push_back({0, 0, 0, 0});
+ return;
+ }
+
+ for (const auto& frectScalar : mFrectScalars) {
+ mDisplayFrames.push_back({
+ static_cast<int>(frectScalar.left * mDisplayArea.width),
+ static_cast<int>(frectScalar.top * mDisplayArea.height),
+ static_cast<int>(frectScalar.right * mDisplayArea.width),
+ static_cast<int>(frectScalar.bottom * mDisplayArea.height)});
+ }
+}
+
+const std::vector<hwc_frect_t> Hwc2TestDisplayFrame::mDefaultFrectScalars = {
+ {0.0, 0.0, 1.0, 1.0},
+};
+
+const std::vector<hwc_frect_t> Hwc2TestDisplayFrame::mBasicFrectScalars = {
+ {0.0, 0.0, 1.0, 1.0},
+ {0.0, 0.0, 1.0, 0.05},
+ {0.0, 0.95, 1.0, 1.0},
+};
+
+const std::vector<hwc_frect_t> Hwc2TestDisplayFrame::mCompleteFrectScalars = {
+ {0.0, 0.0, 1.0, 1.0},
+ {0.0, 0.05, 1.0, 0.95},
+ {0.0, 0.05, 1.0, 1.0},
+ {0.0, 0.0, 1.0, 0.05},
+ {0.0, 0.95, 1.0, 1.0},
+ {0.25, 0.0, 0.75, 0.35},
+ {0.25, 0.25, 0.75, 0.75},
+};
+
+
+Hwc2TestPlaneAlpha::Hwc2TestPlaneAlpha(Hwc2TestCoverage coverage)
+ : Hwc2TestProperty(coverage, mCompletePlaneAlphas, mBasicPlaneAlphas,
+ mDefaultPlaneAlphas, mCompositionSupport) { }
+
+std::string Hwc2TestPlaneAlpha::dump() const
+{
+ std::stringstream dmp;
+ dmp << "\tplane alpha: " << get() << "\n";
+ return dmp.str();
+}
+
+const std::vector<float> Hwc2TestPlaneAlpha::mDefaultPlaneAlphas = {
+ 1.0f,
+};
+
+const std::vector<float> Hwc2TestPlaneAlpha::mBasicPlaneAlphas = {
+ 1.0f, 0.0f,
+};
+
+const std::vector<float> Hwc2TestPlaneAlpha::mCompletePlaneAlphas = {
+ 1.0f, 0.75f, 0.5f, 0.25f, 0.0f,
+};
+
+
+Hwc2TestSourceCrop::Hwc2TestSourceCrop(Hwc2TestCoverage coverage,
+ const Area& bufferArea)
+ : Hwc2TestProperty(mSourceCrops, mCompositionSupport),
+ mFrectScalars((coverage == Hwc2TestCoverage::Complete)? mCompleteFrectScalars:
+ (coverage == Hwc2TestCoverage::Basic)? mBasicFrectScalars:
+ mDefaultFrectScalars),
+ mBufferArea(bufferArea)
+{
+ update();
+}
+
+std::string Hwc2TestSourceCrop::dump() const
+{
+ std::stringstream dmp;
+ const hwc_frect_t& sourceCrop = get();
+ dmp << "\tsource crop: left " << sourceCrop.left << ", top "
+ << sourceCrop.top << ", right " << sourceCrop.right << ", bottom "
+ << sourceCrop.bottom << "\n";
+ return dmp.str();
+}
+
+void Hwc2TestSourceCrop::updateBufferArea(const Area& bufferArea)
+{
+ mBufferArea = bufferArea;
+ update();
+}
+
+void Hwc2TestSourceCrop::update()
+{
+ mSourceCrops.clear();
+
+ if (mBufferArea.width == 0 && mBufferArea.height == 0) {
+ mSourceCrops.push_back({0, 0, 0, 0});
+ return;
+ }
+
+ for (const auto& frectScalar : mFrectScalars) {
+ mSourceCrops.push_back({
+ frectScalar.left * mBufferArea.width,
+ frectScalar.top * mBufferArea.height,
+ frectScalar.right * mBufferArea.width,
+ frectScalar.bottom * mBufferArea.height});
+ }
+}
+
+const std::vector<hwc_frect_t> Hwc2TestSourceCrop::mDefaultFrectScalars = {
+ {0.0, 0.0, 1.0, 1.0},
+};
+
+const std::vector<hwc_frect_t> Hwc2TestSourceCrop::mBasicFrectScalars = {
+ {0.0, 0.0, 1.0, 1.0},
+ {0.0, 0.0, 0.5, 0.5},
+ {0.5, 0.5, 1.0, 1.0},
+};
+
+const std::vector<hwc_frect_t> Hwc2TestSourceCrop::mCompleteFrectScalars = {
+ {0.0, 0.0, 1.0, 1.0},
+ {0.0, 0.0, 0.5, 0.5},
+ {0.5, 0.5, 1.0, 1.0},
+ {0.0, 0.0, 0.25, 0.25},
+ {0.25, 0.25, 0.75, 0.75},
+};
+
+
+Hwc2TestSurfaceDamage::Hwc2TestSurfaceDamage(Hwc2TestCoverage coverage)
+ : Hwc2TestProperty(mSurfaceDamages, mCompositionSupport),
+ mRegionScalars((coverage == Hwc2TestCoverage::Complete)? mCompleteRegionScalars:
+ (coverage == Hwc2TestCoverage::Basic)? mBasicRegionScalars:
+ mDefaultRegionScalars)
+{
+ update();
+}
+
+Hwc2TestSurfaceDamage::~Hwc2TestSurfaceDamage()
+{
+ freeSurfaceDamages();
+}
+
+std::string Hwc2TestSurfaceDamage::dump() const
+{
+ std::stringstream dmp;
+
+ const hwc_region_t& curr = get();
+ dmp << "\tsurface damage: region count " << curr.numRects << "\n";
+ for (size_t i = 0; i < curr.numRects; i++) {
+ const hwc_rect_t& rect = curr.rects[i];
+ dmp << "\t\trect: left " << rect.left << ", top " << rect.top
+ << ", right " << rect.right << ", bottom " << rect.bottom << "\n";
+ }
+
+ return dmp.str();
+}
+
+void Hwc2TestSurfaceDamage::updateBufferArea(const Area& bufferArea)
+{
+ mBufferArea = bufferArea;
+ update();
+}
+
+void Hwc2TestSurfaceDamage::update()
+{
+ freeSurfaceDamages();
+
+ if (mBufferArea.width == 0 && mBufferArea.height == 0) {
+ mSurfaceDamages.push_back({0, nullptr});
+ return;
+ }
+
+ hwc_region_t damage;
+
+ for (const auto& regionScalar : mRegionScalars) {
+ damage.numRects = regionScalar.size();
+
+ if (damage.numRects > 0) {
+ hwc_rect_t* rects = new hwc_rect_t[damage.numRects];
+ if (!rects) {
+ ALOGW("failed to allocate new hwc_rect_t array");
+ continue;
+ }
+
+ for (size_t i = 0; i < damage.numRects; i++) {
+ rects[i].left = regionScalar[i].left * mBufferArea.width;
+ rects[i].top = regionScalar[i].top * mBufferArea.height;
+ rects[i].right = regionScalar[i].right * mBufferArea.width;
+ rects[i].bottom = regionScalar[i].bottom * mBufferArea.height;
+ }
+
+ damage.rects = static_cast<hwc_rect_t const*>(rects);
+ } else {
+ damage.rects = nullptr;
+ }
+
+ mSurfaceDamages.push_back(damage);
+ }
+}
+
+void Hwc2TestSurfaceDamage::freeSurfaceDamages()
+{
+ for (const auto& surfaceDamage : mSurfaceDamages) {
+ if (surfaceDamage.numRects > 0 && surfaceDamage.rects)
+ delete[] surfaceDamage.rects;
+ }
+ mSurfaceDamages.clear();
+}
+
+const std::vector<std::vector<hwc_frect_t>> Hwc2TestSurfaceDamage::mDefaultRegionScalars = {
+ {{}},
+};
+
+const std::vector<std::vector<hwc_frect_t>> Hwc2TestSurfaceDamage::mBasicRegionScalars = {
+ {{}},
+ {{0.0, 0.0, 1.0, 1.0}},
+};
+
+const std::vector<std::vector<hwc_frect_t>> Hwc2TestSurfaceDamage::mCompleteRegionScalars = {
+ {{}},
+ {{0.0, 0.0, 1.0, 1.0}},
+ {{0.0, 0.0, 0.5, 0.5}, {0.5, 0.5, 1.0, 1.0}},
+};
+
+
+Hwc2TestTransform::Hwc2TestTransform(Hwc2TestCoverage coverage)
+ : Hwc2TestProperty(coverage, mCompleteTransforms, mBasicTransforms,
+ mDefaultTransforms, mCompositionSupport) { }
+
+std::string Hwc2TestTransform::dump() const
+{
+ std::stringstream dmp;
+ dmp << "\ttransform: " << getTransformName(get()) << "\n";
+ return dmp.str();
+}
+
+const std::vector<hwc_transform_t> Hwc2TestTransform::mDefaultTransforms = {
+ static_cast<hwc_transform_t>(0),
+};
+
+const std::vector<hwc_transform_t> Hwc2TestTransform::mBasicTransforms = {
+ static_cast<hwc_transform_t>(0),
+ HWC_TRANSFORM_FLIP_H,
+ HWC_TRANSFORM_FLIP_V,
+ HWC_TRANSFORM_ROT_90,
+};
+
+const std::vector<hwc_transform_t> Hwc2TestTransform::mCompleteTransforms = {
+ static_cast<hwc_transform_t>(0),
+ HWC_TRANSFORM_FLIP_H,
+ HWC_TRANSFORM_FLIP_V,
+ HWC_TRANSFORM_ROT_90,
+ HWC_TRANSFORM_ROT_180,
+ HWC_TRANSFORM_ROT_270,
+ HWC_TRANSFORM_FLIP_H_ROT_90,
+ HWC_TRANSFORM_FLIP_V_ROT_90,
+};
+
+
+Hwc2TestVisibleRegion::~Hwc2TestVisibleRegion()
+{
+ release();
+}
+
+std::string Hwc2TestVisibleRegion::dump() const
+{
+ std::stringstream dmp;
+
+ const hwc_region_t& curr = get();
+ dmp << "\tvisible region: region count " << curr.numRects << "\n";
+ for (size_t i = 0; i < curr.numRects; i++) {
+ const hwc_rect_t& rect = curr.rects[i];
+ dmp << "\t\trect: left " << rect.left << ", top " << rect.top
+ << ", right " << rect.right << ", bottom " << rect.bottom << "\n";
+ }
+
+ return dmp.str();
+}
+
+void Hwc2TestVisibleRegion::set(const android::Region& visibleRegion)
+{
+ release();
+
+ size_t size = 0;
+ const android::Rect* rects = visibleRegion.getArray(&size);
+
+ mVisibleRegion.numRects = size;
+ mVisibleRegion.rects = nullptr;
+
+ if (size > 0) {
+ hwc_rect_t* hwcRects = new hwc_rect_t[size];
+ for (size_t i = 0; i < size; i++) {
+ hwcRects[i].left = rects[i].left;
+ hwcRects[i].top = rects[i].top;
+ hwcRects[i].right = rects[i].right;
+ hwcRects[i].bottom = rects[i].bottom;
+ }
+ mVisibleRegion.rects = hwcRects;
+ }
+}
+
+hwc_region_t Hwc2TestVisibleRegion::get() const
+{
+ return mVisibleRegion;
+}
+
+void Hwc2TestVisibleRegion::release()
+{
+ if (mVisibleRegion.numRects > 0 && mVisibleRegion.rects)
+ delete[] mVisibleRegion.rects;
+ mVisibleRegion.rects = nullptr;
+ mVisibleRegion.numRects = 0;
+}
+
+/* Identifies which layer properties are supported by each composition type.
+ * hwc2_composition_t values range from:
+ * HWC2_COMPOSITION_INVALID = 0,
+ * HWC2_COMPOSITION_CLIENT = 1,
+ * HWC2_COMPOSITION_DEVICE = 2,
+ * HWC2_COMPOSITION_SOLID_COLOR = 3,
+ * HWC2_COMPOSITION_CURSOR = 4,
+ * HWC2_COMPOSITION_SIDEBAND = 5,
+ *
+ * Each property array can be indexed by a hwc2_composition_t value.
+ * By using an array instead of a more complex data structure, runtimes for
+ * some test cases showed a noticeable improvement.
+ */
+
+/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */
+const std::array<bool, 6> Hwc2TestBufferArea::mCompositionSupport = {{
+ false, true, true, false, true, true,
+}};
+
+/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */
+const std::array<bool, 6> Hwc2TestBlendMode::mCompositionSupport = {{
+ false, true, true, false, true, true,
+}};
+
+/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */
+const std::array<bool, 6> Hwc2TestColor::mCompositionSupport = {{
+ false, false, false, true, false, false,
+}};
+
+/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */
+const std::array<bool, 6> Hwc2TestComposition::mCompositionSupport = {{
+ false, true, true, true, true, true,
+}};
+
+/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */
+const std::array<bool, 6> Hwc2TestDataspace::mCompositionSupport = {{
+ false, true, true, true, true, false,
+}};
+
+/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */
+const std::array<bool, 6> Hwc2TestDisplayDimension::mCompositionSupport = {{
+ false, true, true, true, true, true,
+}};
+
+/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */
+const std::array<bool, 6> Hwc2TestDisplayFrame::mCompositionSupport = {{
+ false, true, true, true, false, true,
+}};
+
+/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */
+const std::array<bool, 6> Hwc2TestPlaneAlpha::mCompositionSupport = {{
+ false, true, true, true, true, true,
+}};
+
+/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */
+const std::array<bool, 6> Hwc2TestSourceCrop::mCompositionSupport = {{
+ false, true, true, false, true, false,
+}};
+
+/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */
+const std::array<bool, 6> Hwc2TestSurfaceDamage::mCompositionSupport = {{
+ false, false, true, false, true, false,
+}};
+
+/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */
+const std::array<bool, 6> Hwc2TestTransform::mCompositionSupport = {{
+ false, true, true, false, true, true,
+}};
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h
new file mode 100644
index 0000000..c2029ab
--- /dev/null
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _HWC2_TEST_PROPERTIES_H
+#define _HWC2_TEST_PROPERTIES_H
+
+#include <array>
+#include <vector>
+
+#include <ui/Region.h>
+
+#define HWC2_INCLUDE_STRINGIFICATION
+#define HWC2_USE_CPP11
+#include <hardware/hwcomposer2.h>
+#undef HWC2_INCLUDE_STRINGIFICATION
+#undef HWC2_USE_CPP11
+
+enum class Hwc2TestCoverage {
+ Default = 0,
+ Basic,
+ Complete,
+};
+
+enum class Hwc2TestPropertyName {
+ BlendMode = 1,
+ BufferArea,
+ Color,
+ Composition,
+ CursorPosition,
+ Dataspace,
+ DisplayFrame,
+ PlaneAlpha,
+ SourceCrop,
+ SurfaceDamage,
+ Transform,
+};
+
+typedef struct {
+ int32_t width;
+ int32_t height;
+} Area;
+
+
+typedef struct {
+ uint32_t width;
+ uint32_t height;
+} UnsignedArea;
+
+
+class Hwc2TestContainer {
+public:
+ virtual ~Hwc2TestContainer() = default;
+
+ /* Resets the container */
+ virtual void reset() = 0;
+
+ /* Attempts to advance to the next valid value. Returns true if one can be
+ * found */
+ virtual bool advance() = 0;
+
+ virtual std::string dump() const = 0;
+
+ /* Returns true if the container supports the given composition type */
+ virtual bool isSupported(hwc2_composition_t composition) = 0;
+};
+
+
+template <class T>
+class Hwc2TestProperty : public Hwc2TestContainer {
+public:
+ Hwc2TestProperty(Hwc2TestCoverage coverage,
+ const std::vector<T>& completeList, const std::vector<T>& basicList,
+ const std::vector<T>& defaultList,
+ const std::array<bool, 6>& compositionSupport)
+ : Hwc2TestProperty((coverage == Hwc2TestCoverage::Complete)? completeList:
+ (coverage == Hwc2TestCoverage::Basic)? basicList : defaultList,
+ compositionSupport) { }
+
+ Hwc2TestProperty(const std::vector<T>& list,
+ const std::array<bool, 6>& compositionSupport)
+ : mList(list),
+ mCompositionSupport(compositionSupport) { }
+
+ void reset() override
+ {
+ mListIdx = 0;
+ }
+
+ bool advance() override
+ {
+ if (mListIdx + 1 < mList.size()) {
+ mListIdx++;
+ updateDependents();
+ return true;
+ }
+ reset();
+ updateDependents();
+ return false;
+ }
+
+ T get() const
+ {
+ return mList.at(mListIdx);
+ }
+
+ virtual bool isSupported(hwc2_composition_t composition)
+ {
+ return mCompositionSupport.at(composition);
+ }
+
+protected:
+ /* If a derived class has dependents, override this function */
+ virtual void updateDependents() { }
+
+ const std::vector<T>& mList;
+ size_t mListIdx = 0;
+
+ const std::array<bool, 6>& mCompositionSupport;
+};
+
+class Hwc2TestBuffer;
+class Hwc2TestSourceCrop;
+class Hwc2TestSurfaceDamage;
+
+class Hwc2TestBufferArea : public Hwc2TestProperty<Area> {
+public:
+ Hwc2TestBufferArea(Hwc2TestCoverage coverage, const Area& displayArea);
+
+ std::string dump() const override;
+
+ void setDependent(Hwc2TestBuffer* buffer);
+ void setDependent(Hwc2TestSourceCrop* sourceCrop);
+ void setDependent(Hwc2TestSurfaceDamage* surfaceDamage);
+
+protected:
+ void update();
+ void updateDependents() override;
+
+ const std::vector<float>& mScalars;
+ static const std::vector<float> mDefaultScalars;
+ static const std::vector<float> mBasicScalars;
+ static const std::vector<float> mCompleteScalars;
+
+ Area mDisplayArea;
+
+ Hwc2TestBuffer* mBuffer = nullptr;
+ Hwc2TestSourceCrop* mSourceCrop = nullptr;
+ Hwc2TestSurfaceDamage* mSurfaceDamage = nullptr;
+
+ std::vector<Area> mBufferAreas;
+
+ static const std::array<bool, 6> mCompositionSupport;
+};
+
+
+class Hwc2TestColor;
+
+class Hwc2TestBlendMode : public Hwc2TestProperty<hwc2_blend_mode_t> {
+public:
+ Hwc2TestBlendMode(Hwc2TestCoverage coverage);
+
+ std::string dump() const override;
+
+ void setDependent(Hwc2TestColor* color);
+
+protected:
+ void updateDependents() override;
+
+ Hwc2TestColor* mColor = nullptr;
+
+ static const std::vector<hwc2_blend_mode_t> mDefaultBlendModes;
+ static const std::vector<hwc2_blend_mode_t> mBasicBlendModes;
+ static const std::vector<hwc2_blend_mode_t> mCompleteBlendModes;
+
+ static const std::array<bool, 6> mCompositionSupport;
+};
+
+
+class Hwc2TestColor : public Hwc2TestProperty<hwc_color_t> {
+public:
+ Hwc2TestColor(Hwc2TestCoverage coverage,
+ hwc2_blend_mode_t blendMode = HWC2_BLEND_MODE_NONE);
+
+ std::string dump() const override;
+
+ void updateBlendMode(hwc2_blend_mode_t blendMode);
+
+protected:
+ void update();
+
+ std::vector<hwc_color_t> mBaseColors;
+ static const std::vector<hwc_color_t> mDefaultBaseColors;
+ static const std::vector<hwc_color_t> mBasicBaseColors;
+ static const std::vector<hwc_color_t> mCompleteBaseColors;
+
+ hwc2_blend_mode_t mBlendMode;
+
+ std::vector<hwc_color_t> mColors;
+
+ static const std::array<bool, 6> mCompositionSupport;
+};
+
+
+class Hwc2TestComposition : public Hwc2TestProperty<hwc2_composition_t> {
+public:
+ Hwc2TestComposition(Hwc2TestCoverage coverage);
+
+ std::string dump() const override;
+
+protected:
+ static const std::vector<hwc2_composition_t> mDefaultCompositions;
+ static const std::vector<hwc2_composition_t> mBasicCompositions;
+ static const std::vector<hwc2_composition_t> mCompleteCompositions;
+
+ static const std::array<bool, 6> mCompositionSupport;
+};
+
+
+class Hwc2TestDataspace : public Hwc2TestProperty<android_dataspace_t> {
+public:
+ Hwc2TestDataspace(Hwc2TestCoverage coverage);
+
+ std::string dump() const override;
+
+protected:
+ static const std::vector<android_dataspace_t> defaultDataspaces;
+ static const std::vector<android_dataspace_t> basicDataspaces;
+ static const std::vector<android_dataspace_t> completeDataspaces;
+
+ static const std::array<bool, 6> mCompositionSupport;
+};
+
+
+class Hwc2TestDisplayDimension : public Hwc2TestProperty<UnsignedArea> {
+public:
+ Hwc2TestDisplayDimension(Hwc2TestCoverage coverage);
+
+ std::string dump() const;
+
+ void setDependent(Hwc2TestBuffer* buffer);
+
+private:
+ void updateDependents();
+
+ Hwc2TestBuffer* mBuffer;
+
+ static const std::vector<UnsignedArea> mDefaultDisplayDimensions;
+ static const std::vector<UnsignedArea> mBasicDisplayDimensions;
+ static const std::vector<UnsignedArea> mCompleteDisplayDimensions;
+
+ static const std::array<bool, 6> mCompositionSupport;
+};
+
+
+class Hwc2TestDisplayFrame : public Hwc2TestProperty<hwc_rect_t> {
+public:
+ Hwc2TestDisplayFrame(Hwc2TestCoverage coverage, const Area& displayArea);
+
+ std::string dump() const override;
+
+protected:
+ void update();
+
+ const std::vector<hwc_frect_t>& mFrectScalars;
+ const static std::vector<hwc_frect_t> mDefaultFrectScalars;
+ const static std::vector<hwc_frect_t> mBasicFrectScalars;
+ const static std::vector<hwc_frect_t> mCompleteFrectScalars;
+
+ Area mDisplayArea;
+
+ std::vector<hwc_rect_t> mDisplayFrames;
+
+ static const std::array<bool, 6> mCompositionSupport;
+};
+
+
+class Hwc2TestPlaneAlpha : public Hwc2TestProperty<float> {
+public:
+ Hwc2TestPlaneAlpha(Hwc2TestCoverage coverage);
+
+ std::string dump() const override;
+
+protected:
+ static const std::vector<float> mDefaultPlaneAlphas;
+ static const std::vector<float> mBasicPlaneAlphas;
+ static const std::vector<float> mCompletePlaneAlphas;
+
+ static const std::array<bool, 6> mCompositionSupport;
+};
+
+
+class Hwc2TestSourceCrop : public Hwc2TestProperty<hwc_frect_t> {
+public:
+ Hwc2TestSourceCrop(Hwc2TestCoverage coverage, const Area& bufferArea = {0, 0});
+
+ std::string dump() const override;
+
+ void updateBufferArea(const Area& bufferArea);
+
+protected:
+ void update();
+
+ const std::vector<hwc_frect_t>& mFrectScalars;
+ const static std::vector<hwc_frect_t> mDefaultFrectScalars;
+ const static std::vector<hwc_frect_t> mBasicFrectScalars;
+ const static std::vector<hwc_frect_t> mCompleteFrectScalars;
+
+ Area mBufferArea;
+
+ std::vector<hwc_frect_t> mSourceCrops;
+
+ static const std::array<bool, 6> mCompositionSupport;
+};
+
+
+class Hwc2TestSurfaceDamage : public Hwc2TestProperty<hwc_region_t> {
+public:
+ Hwc2TestSurfaceDamage(Hwc2TestCoverage coverage);
+ ~Hwc2TestSurfaceDamage();
+
+ std::string dump() const override;
+
+ void updateBufferArea(const Area& bufferArea);
+
+protected:
+ void update();
+ void freeSurfaceDamages();
+
+ const std::vector<std::vector<hwc_frect_t>> &mRegionScalars;
+ const static std::vector<std::vector<hwc_frect_t>> mDefaultRegionScalars;
+ const static std::vector<std::vector<hwc_frect_t>> mBasicRegionScalars;
+ const static std::vector<std::vector<hwc_frect_t>> mCompleteRegionScalars;
+
+ Area mBufferArea = {0, 0};
+
+ std::vector<hwc_region_t> mSurfaceDamages;
+
+ static const std::array<bool, 6> mCompositionSupport;
+};
+
+
+class Hwc2TestTransform : public Hwc2TestProperty<hwc_transform_t> {
+public:
+ Hwc2TestTransform(Hwc2TestCoverage coverage);
+
+ std::string dump() const override;
+
+protected:
+ static const std::vector<hwc_transform_t> mDefaultTransforms;
+ static const std::vector<hwc_transform_t> mBasicTransforms;
+ static const std::vector<hwc_transform_t> mCompleteTransforms;
+
+ static const std::array<bool, 6> mCompositionSupport;
+};
+
+
+class Hwc2TestVisibleRegion {
+public:
+ ~Hwc2TestVisibleRegion();
+
+ std::string dump() const;
+
+ void set(const android::Region& visibleRegion);
+ hwc_region_t get() const;
+ void release();
+
+protected:
+ hwc_region_t mVisibleRegion = {0, nullptr};
+};
+
+#endif /* ifndef _HWC2_TEST_PROPERTIES_H */
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp
new file mode 100644
index 0000000..d0fbc0b
--- /dev/null
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sstream>
+
+#include "Hwc2TestVirtualDisplay.h"
+
+Hwc2TestVirtualDisplay::Hwc2TestVirtualDisplay(
+ Hwc2TestCoverage coverage)
+ : mDisplayDimension(coverage)
+{
+ mDisplayDimension.setDependent(&mBuffer);
+}
+
+std::string Hwc2TestVirtualDisplay::dump() const
+{
+ std::stringstream dmp;
+
+ dmp << "virtual display: \n";
+
+ mDisplayDimension.dump();
+
+ return dmp.str();
+}
+
+int Hwc2TestVirtualDisplay::getBuffer(buffer_handle_t* outHandle,
+ android::base::unique_fd* outAcquireFence)
+{
+ int32_t acquireFence;
+ int ret = mBuffer.get(outHandle, &acquireFence);
+ outAcquireFence->reset(acquireFence);
+ return ret;
+}
+
+void Hwc2TestVirtualDisplay::reset()
+{
+ return mDisplayDimension.reset();
+}
+
+bool Hwc2TestVirtualDisplay::advance()
+{
+ return mDisplayDimension.advance();
+}
+
+UnsignedArea Hwc2TestVirtualDisplay::getDisplayDimension() const
+{
+ return mDisplayDimension.get();
+}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h
new file mode 100644
index 0000000..09420ef
--- /dev/null
+++ b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _HWC2_TEST_VIRTUAL_DISPLAY_H
+#define _HWC2_TEST_VIRTUAL_DISPLAY_H
+
+#include "Hwc2TestBuffer.h"
+#include "Hwc2TestProperties.h"
+
+#define HWC2_INCLUDE_STRINGIFICATION
+#define HWC2_USE_CPP11
+#include <hardware/hwcomposer2.h>
+#undef HWC2_INCLUDE_STRINGIFICATION
+#undef HWC2_USE_CPP11
+
+class Hwc2TestVirtualDisplay {
+public:
+ Hwc2TestVirtualDisplay(Hwc2TestCoverage coverage);
+
+ std::string dump() const;
+
+ int getBuffer(buffer_handle_t* outHandle,
+ android::base::unique_fd* outAcquireFence);
+
+ void reset();
+ bool advance();
+
+ UnsignedArea getDisplayDimension() const;
+
+private:
+ Hwc2TestBuffer mBuffer;
+
+ Hwc2TestDisplayDimension mDisplayDimension;
+};
+
+#endif /* ifndef _HWC2_TEST_VIRTUAL_DISPLAY_H */
diff --git a/vulkan/Android.bp b/vulkan/Android.bp
new file mode 100644
index 0000000..f5be518
--- /dev/null
+++ b/vulkan/Android.bp
@@ -0,0 +1,36 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+ndk_headers {
+ name: "libvulkan_headers",
+ from: "include",
+ to: "",
+ srcs: [
+ "include/vulkan/vk_platform.h",
+ "include/vulkan/vulkan.h",
+ ],
+ license: "include/vulkan/NOTICE",
+}
+
+cc_library_static {
+ name: "vulkan_headers",
+ export_include_dirs: ["include"],
+ vendor_available: true,
+}
+
+subdirs = [
+ "nulldrv",
+ "libvulkan",
+ "tools",
+]
diff --git a/vulkan/Android.mk b/vulkan/Android.mk
deleted file mode 100644
index d125673..0000000
--- a/vulkan/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-named-subdir-makefiles, libvulkan nulldrv tools)
diff --git a/vulkan/api/platform.api b/vulkan/api/platform.api
index 7aa19e7..eb0124d 100644
--- a/vulkan/api/platform.api
+++ b/vulkan/api/platform.api
@@ -48,3 +48,10 @@
// VK_USE_PLATFORM_WIN32_KHR
@internal type void* HINSTANCE
@internal type void* HWND
+@internal type void* HANDLE
+@internal type u32 DWORD
+@internal type u16* LPCWSTR
+@internal class SECURITY_ATTRIBUTES {}
+
+// VK_USE_PLATFORM_XLIB_XRANDR_EXT
+@internal type u64 RROutput
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index 870f8eb..0616711 100644
--- a/vulkan/api/vulkan.api
+++ b/vulkan/api/vulkan.api
@@ -28,7 +28,7 @@
// API version (major.minor.patch)
define VERSION_MAJOR 1
define VERSION_MINOR 0
-define VERSION_PATCH 13
+define VERSION_PATCH 46
// API limits
define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256
@@ -37,6 +37,9 @@
define VK_MAX_DESCRIPTION_SIZE 256
define VK_MAX_MEMORY_TYPES 32
define VK_MAX_MEMORY_HEAPS 16 /// The maximum number of unique memory heaps, each of which supporting 1 or more memory types.
+define VK_MAX_DEVICE_GROUP_SIZE_KHX 32
+define VK_LUID_SIZE_KHX 8
+define VK_QUEUE_FAMILY_EXTERNAL_KHX -2
// API keywords
define VK_TRUE 1
@@ -45,57 +48,281 @@
// API keyword, but needs special handling by some templates
define NULL_HANDLE 0
+// 1
@extension("VK_KHR_surface") define VK_KHR_SURFACE_SPEC_VERSION 25
@extension("VK_KHR_surface") define VK_KHR_SURFACE_EXTENSION_NAME "VK_KHR_surface"
+// 2
@extension("VK_KHR_swapchain") define VK_KHR_SWAPCHAIN_SPEC_VERSION 68
@extension("VK_KHR_swapchain") define VK_KHR_SWAPCHAIN_EXTENSION_NAME "VK_KHR_swapchain"
+// 3
@extension("VK_KHR_display") define VK_KHR_DISPLAY_SPEC_VERSION 21
@extension("VK_KHR_display") define VK_KHR_DISPLAY_EXTENSION_NAME "VK_KHR_display"
+// 4
@extension("VK_KHR_display_swapchain") define VK_KHR_DISPLAY_SWAPCHAIN_SPEC_VERSION 9
@extension("VK_KHR_display_swapchain") define VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME "VK_KHR_display_swapchain"
+// 5
@extension("VK_KHR_xlib_surface") define VK_KHR_XLIB_SURFACE_SPEC_VERSION 6
@extension("VK_KHR_xlib_surface") define VK_KHR_XLIB_SURFACE_NAME "VK_KHR_xlib_surface"
+// 6
@extension("VK_KHR_xcb_surface") define VK_KHR_XCB_SURFACE_SPEC_VERSION 6
@extension("VK_KHR_xcb_surface") define VK_KHR_XCB_SURFACE_NAME "VK_KHR_xcb_surface"
-@extension("VK_KHR_wayland_surface") define VK_KHR_WAYLAND_SURFACE_SPEC_VERSION 5
+// 7
+@extension("VK_KHR_wayland_surface") define VK_KHR_WAYLAND_SURFACE_SPEC_VERSION 6
@extension("VK_KHR_wayland_surface") define VK_KHR_WAYLAND_SURFACE_NAME "VK_KHR_wayland_surface"
+// 8
@extension("VK_KHR_mir_surface") define VK_KHR_MIR_SURFACE_SPEC_VERSION 4
@extension("VK_KHR_mir_surface") define VK_KHR_MIR_SURFACE_NAME "VK_KHR_mir_surface"
+// 9
@extension("VK_KHR_android_surface") define VK_KHR_ANDROID_SURFACE_SPEC_VERSION 6
@extension("VK_KHR_android_surface") define VK_KHR_ANDROID_SURFACE_NAME "VK_KHR_android_surface"
+// 10
@extension("VK_KHR_win32_surface") define VK_KHR_WIN32_SURFACE_SPEC_VERSION 5
@extension("VK_KHR_win32_surface") define VK_KHR_WIN32_SURFACE_NAME "VK_KHR_win32_surface"
+// 11
@extension("VK_ANDROID_native_buffer") define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 5
@extension("VK_ANDROID_native_buffer") define VK_ANDROID_NATIVE_BUFFER_NAME "VK_ANDROID_native_buffer"
-@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_SPEC_VERSION 2
+// 12
+@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_SPEC_VERSION 6
@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_NAME "VK_EXT_debug_report"
+// 13
@extension("VK_NV_glsl_shader") define VK_NV_GLSL_SHADER_SPEC_VERSION 1
@extension("VK_NV_glsl_shader") define VK_NV_GLSL_SHADER_NAME "VK_NV_glsl_shader"
+// 15
@extension("VK_KHR_sampler_mirror_clamp_to_edge") define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_SPEC_VERSION 1
@extension("VK_KHR_sampler_mirror_clamp_to_edge") define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_NAME "VK_KHR_sampler_mirror_clamp_to_edge"
+// 16
@extension("VK_IMG_filter_cubic") define VK_IMG_FILTER_CUBIC_SPEC_VERSION 1
@extension("VK_IMG_filter_cubic") define VK_IMG_FILTER_CUBIC_NAME "VK_IMG_filter_cubic"
+// 19
@extension("VK_AMD_rasterization_order") define VK_AMD_RASTERIZATION_ORDER_SPEC_VERSION 1
@extension("VK_AMD_rasterization_order") define VK_AMD_RASTERIZATION_ORDER_NAME "VK_AMD_rasterization_order"
-@extension("VK_EXT_debug_marker") define VK_EXT_DEBUG_MARKER_SPEC_VERSION 3
+// 21
+@extension("VK_AMD_shader_trinary_minmax") define VK_AMD_SHADER_TRINARY_MINMAX_SPEC_VERSION 1
+@extension("VK_AMD_shader_trinary_minmax") define VK_AMD_SHADER_TRINARY_MINMAX_EXTENSION_NAME "VK_AMD_shader_trinary_minmax"
+
+// 22
+@extension("VK_AMD_shader_explicit_vertex_parameter") define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_SPEC_VERSION 1
+@extension("VK_AMD_shader_explicit_vertex_parameter") define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_EXTENSION_NAME "VK_AMD_shader_explicit_vertex_parameter"
+
+// 23
+@extension("VK_EXT_debug_marker") define VK_EXT_DEBUG_MARKER_SPEC_VERSION 4
@extension("VK_EXT_debug_marker") define VK_EXT_DEBUG_MARKER_NAME "VK_EXT_debug_marker"
+// 26
+@extension("VK_AMD_gcn_shader") define VK_AMD_GCN_SHADER_SPEC_VERSION 1
+@extension("VK_AMD_gcn_shader") define VK_AMD_GCN_SHADER_EXTENSION_NAME "VK_AMD_gcn_shader"
+
+// 27
+@extension("VK_NV_dedicated_allocation") define VK_NV_DEDICATED_ALLOCATION_SPEC_VERSION 1
+@extension("VK_NV_dedicated_allocation") define VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_NV_dedicated_allocation"
+
+// 28
+@extension("VK_IMG_format_pvrtc") define VK_IMG_FORMAT_PVRTC_SPEC_VERSION 1
+@extension("VK_IMG_format_pvrtc") define VK_IMG_FORMAT_PVRTC_EXTENSION_NAME "VK_IMG_format_pvrtc"
+
+// 34
+@extension("VK_AMD_draw_indirect_count") define VK_AMD_DRAW_INDIRECT_COUNT_SPEC_VERSION 1
+@extension("VK_AMD_draw_indirect_count") define VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_AMD_draw_indirect_count"
+
+// 36
+@extension("VK_AMD_negative_viewport_height") define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_SPEC_VERSION 1
+@extension("VK_AMD_negative_viewport_height") define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME "VK_AMD_negative_viewport_height"
+
+// 37
+@extension("VK_AMD_gpu_shader_half_float") define VK_AMD_GPU_SHADER_HALF_FLOAT_SPEC_VERSION 1
+@extension("VK_AMD_gpu_shader_half_float") define VK_AMD_GPU_SHADER_HALF_FLOAT_EXTENSION_NAME "VK_AMD_gpu_shader_half_float"
+
+// 38
+@extension("VK_AMD_shader_ballot") define VK_AMD_SHADER_BALLOT_SPEC_VERSION 1
+@extension("VK_AMD_shader_ballot") define VK_AMD_SHADER_BALLOT_EXTENSION_NAME "VK_AMD_shader_ballot"
+
+// 54
+@extension("VK_KHX_multiview") define VK_KHX_MULTIVIEW_SPEC_VERSION 1
+@extension("VK_KHX_multiview") define VK_KHX_MULTIVIEW_EXTENSION_NAME "VK_KHX_multiview"
+
+// 56
+@extension("VK_NV_external_memory_capabilities") define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1
+@extension("VK_NV_external_memory_capabilities") define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_NV_external_memory_capabilities"
+
+// 57
+@extension("VK_NV_external_memory") define VK_NV_EXTERNAL_MEMORY_SPEC_VERSION 1
+@extension("VK_NV_external_memory") define VK_NV_EXTERNAL_MEMORY_EXTENSION_NAME "VK_NV_external_memory"
+
+// 58
+@extension("VK_NV_external_memory_win32") define VK_NV_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1
+@extension("VK_NV_external_memory_win32") define VK_NV_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_NV_external_memory_win32"
+
+// 59
+@extension("VK_NV_win32_keyed_mutex") define VK_NV_WIN32_KEYED_MUTEX_SPEC_VERSION 1
+@extension("VK_NV_win32_keyed_mutex") define VK_NV_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_NV_win32_keyed_mutex"
+
+// 60
+@extension("VK_KHR_get_physical_device_properties2") define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION 1
+@extension("VK_KHR_get_physical_device_properties2") define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_physical_device_properties2"
+
+// 61
+@extension("VK_KHX_device_group") define VK_KHX_DEVICE_GROUP_SPEC_VERSION 1
+@extension("VK_KHX_device_group") define VK_KHX_DEVICE_GROUP_EXTENSION_NAME "VK_KHX_device_group"
+
+// 62
+@extension("VK_EXT_validation_flags") define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 1
+@extension("VK_EXT_validation_flags") define VK_EXT_VALIDATION_FLAGS_EXTENSION_NAME "VK_EXT_validation_flags"
+
+// 63
+@extension("VK_NN_vi_surface") define VK_NN_VI_SURFACE_SPEC_VERSION 1
+@extension("VK_NN_vi_surface") define VK_NN_VI_SURFACE_EXTENSION_NAME "VK_NN_vi_surface"
+
+// 64
+@extension("VK_KHR_shader_draw_parameters") define VK_KHR_SHADER_DRAW_PARAMETERS_SPEC_VERSION 1
+@extension("VK_KHR_shader_draw_parameters") define VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME "VK_KHR_shader_draw_parameters"
+
+// 65
+@extension("VK_EXT_shader_subgroup_ballot") define VK_EXT_SHADER_SUBGROUP_BALLOT_SPEC_VERSION 1
+@extension("VK_EXT_shader_subgroup_ballot") define VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME "VK_EXT_shader_subgroup_ballot"
+
+// 66
+@extension("VK_EXT_shader_subgroup_vote") define VK_EXT_SHADER_SUBGROUP_VOTE_SPEC_VERSION 1
+@extension("VK_EXT_shader_subgroup_vote") define VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME "VK_EXT_shader_subgroup_vote"
+
+// 70
+@extension("VK_KHR_maintenance1") define VK_KHR_MAINTENANCE1_SPEC_VERSION 1
+@extension("VK_KHR_maintenance1") define VK_KHR_MAINTENANCE1_EXTENSION_NAME "VK_KHR_maintenance1"
+
+// 71
+@extension("VK_KHX_device_group_creation") define VK_KHX_DEVICE_GROUP_CREATION_SPEC_VERSION 1
+@extension("VK_KHX_device_group_creation") define VK_KHX_DEVICE_GROUP_CREATION_EXTENSION_NAME "VK_KHX_device_group_creation"
+
+// 72
+@extension("VK_KHX_external_memory_capabilities") define VK_KHX_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1
+@extension("VK_KHX_external_memory_capabilities") define VK_KHX_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_KHX_external_memory_capabilities"
+
+// 73
+@extension("VK_KHX_external_memory") define VK_KHX_EXTERNAL_MEMORY_SPEC_VERSION 1
+@extension("VK_KHX_external_memory") define VK_KHX_EXTERNAL_MEMORY_EXTENSION_NAME "VK_KHX_external_memory"
+
+// 74
+@extension("VK_KHX_external_memory_win32") define VK_KHX_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1
+@extension("VK_KHX_external_memory_win32") define VK_KHX_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_KHX_external_memory_win32"
+
+// 75
+@extension("VK_KHX_external_memory_fd") define VK_KHX_EXTERNAL_MEMORY_FD_SPEC_VERSION 1
+@extension("VK_KHX_external_memory_fd") define VK_KHX_EXTERNAL_MEMORY_FD_EXTENSION_NAME "VK_KHX_external_memory_fd"
+
+// 76
+@extension("VK_KHX_win32_keyed_mutex") define VK_KHX_WIN32_KEYED_MUTEX_SPEC_VERSION 1
+@extension("VK_KHX_win32_keyed_mutex") define VK_KHX_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_KHX_win32_keyed_mutex"
+
+// 77
+@extension("VK_KHX_external_semaphore_capabilities") define VK_KHX_EXTERNAL_SEMAPHORE_CAPABILITIES_SPEC_VERSION 1
+@extension("VK_KHX_external_semaphore_capabilities") define VK_KHX_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME "VK_KHX_external_semaphore_capabilities"
+
+// 78
+@extension("VK_KHX_external_semaphore") define VK_KHX_EXTERNAL_SEMAPHORE_SPEC_VERSION 1
+@extension("VK_KHX_external_semaphore") define VK_KHX_EXTERNAL_SEMAPHORE_EXTENSION_NAME "VK_KHX_external_semaphore"
+
+// 79
+@extension("VK_KHX_external_semaphore_win32") define VK_KHX_EXTERNAL_SEMAPHORE_WIN32_SPEC_VERSION 1
+@extension("VK_KHX_external_semaphore_win32") define VK_KHX_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME "VK_KHX_external_semaphore_win32"
+
+// 80
+@extension("VK_KHX_external_semaphore_fd") define VK_KHX_EXTERNAL_SEMAPHORE_FD_SPEC_VERSION 1
+@extension("VK_KHX_external_semaphore_fd") define VK_KHX_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME "VK_KHX_external_semaphore_fd"
+
+// 81
+@extension("VK_KHR_push_descriptor") define VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION 1
+@extension("VK_KHR_push_descriptor") define VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME "VK_KHR_push_descriptor"
+
+// 85
+@extension("VK_KHR_incremental_present") define VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION 1
+@extension("VK_KHR_incremental_present") define VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME "VK_KHR_incremental_present"
+
+// 86
+@extension("VK_KHR_descriptor_update_template") define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_SPEC_VERSION 1
+@extension("VK_KHR_descriptor_update_template") define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME "VK_KHR_descriptor_update_template"
+
+// 87
+@extension("VK_NVX_device_generated_commands") define VK_NVX_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 1
+@extension("VK_NVX_device_generated_commands") define VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME "VK_NVX_device_generated_commands"
+
+// 88
+@extension("VK_NV_clip_space_w_scaling") define VK_NV_CLIP_SPACE_W_SCALING_SPEC_VERSION 1
+@extension("VK_NV_clip_space_w_scaling") define VK_NV_CLIP_SPACE_W_SCALING_EXTENSION_NAME "VK_NV_clip_space_w_scaling"
+
+// 89
+@extension("VK_EXT_direct_mode_display") define VK_EXT_DIRECT_MODE_DISPLAY_SPEC_VERSION 1
+@extension("VK_EXT_direct_mode_display") define VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME "VK_EXT_direct_mode_display"
+
+// 90
+@extension("VK_EXT_acquire_xlib_display") define VK_EXT_ACQUIRE_XLIB_DISPLAY_SPEC_VERSION 1
+@extension("VK_EXT_acquire_xlib_display") define VK_EXT_ACQUIRE_XLIB_DISPLAY_EXTENSION_NAME "VK_EXT_acquire_xlib_display"
+
+// 91
+@extension("VK_EXT_display_surface_counter") define VK_EXT_DISPLAY_SURFACE_COUNTER_SPEC_VERSION 1
+@extension("VK_EXT_display_surface_counter") define VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME "VK_EXT_display_surface_counter"
+
+// 92
+@extension("VK_EXT_display_control") define VK_EXT_DISPLAY_CONTROL_SPEC_VERSION 1
+@extension("VK_EXT_display_control") define VK_EXT_DISPLAY_CONTROL_COUNTER_EXTENSION_NAME "VK_EXT_display_control"
+
+// 93
+@extension("VK_GOOGLE_display_timing") define VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION 1
+@extension("VK_GOOGLE_display_timing") define VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME "VK_GOOGLE_display_timing"
+
+// 95
+@extension("VK_NV_sample_mask_override_coverage") define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_SPEC_VERSION 1
+@extension("VK_NV_sample_mask_override_coverage") define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_EXTENSION_NAME "VK_NV_sample_mask_override_coverage"
+
+// 96
+@extension("VK_NV_geometry_shader_passthrough") define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_SPEC_VERSION 1
+@extension("VK_NV_geometry_shader_passthrough") define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME "VK_NV_geometry_shader_passthrough"
+
+// 97
+@extension("VK_NV_viewport_array2") define VK_NV_VIEWPORT_ARRAY2_SPEC_VERSION 1
+@extension("VK_NV_viewport_array2") define VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME "VK_NV_viewport_array2"
+
+// 98
+@extension("VK_NVX_multiview_per_view_attributes") define VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_SPEC_VERSION 1
+@extension("VK_NVX_multiview_per_view_attributes") define VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_EXTENSION_NAME "VK_NVX_multiview_per_view_attributes"
+
+// 99
+@extension("VK_NV_viewport_swizzle") define VK_NV_VIEWPORT_SWIZZLE_SPEC_VERSION 1
+@extension("VK_NV_viewport_swizzle") define VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME "VK_NV_viewport_swizzle"
+
+// 100
+@extension("VK_EXT_discard_rectangles") define VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION 1
+@extension("VK_EXT_discard_rectangles") define VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME "VK_EXT_discard_rectangles"
+
+// 105
+@extension("VK_EXT_swapchain_colorspace") define VK_EXT_SWAPCHAIN_COLORSPACE_SPEC_VERSION 2
+@extension("VK_EXT_swapchain_colorspace") define VK_EXT_SWAPCHAIN_COLORSPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace"
+
+// 106
+@extension("VK_EXT_hdr_metadata") define VK_EXT_HDR_METADATA_SPEC_VERSION 1
+@extension("VK_EXT_hdr_metadata") define VK_EXT_HDR_METADATA_EXTENSION_NAME "VK_EXT_hdr_metadata"
+
+// 123
+@extension("VK_MVK_ios_surface") define VK_MVK_IOS_SURFACE_SPEC_VERSION 1
+@extension("VK_MVK_ios_surface") define VK_MVK_IOS_SURFACE_EXTENSION_NAME "VK_MVK_ios_surface"
+
+// 124
+@extension("VK_MVK_macos_surface") define VK_MVK_MACOS_SURFACE_SPEC_VERSION 1
+@extension("VK_MVK_macos_surface") define VK_MVK_MACOS_SURFACE_EXTENSION_NAME "VK_MVK_macos_surface"
/////////////
// Types //
@@ -135,15 +362,26 @@
@nonDispatchHandle type u64 VkRenderPass
@nonDispatchHandle type u64 VkPipelineCache
+// 1
@extension("VK_KHR_surface") @nonDispatchHandle type u64 VkSurfaceKHR
+// 2
@extension("VK_KHR_swapchain") @nonDispatchHandle type u64 VkSwapchainKHR
+// 3
@extension("VK_KHR_display") @nonDispatchHandle type u64 VkDisplayKHR
@extension("VK_KHR_display") @nonDispatchHandle type u64 VkDisplayModeKHR
+// 12
@extension("VK_EXT_debug_report") @nonDispatchHandle type u64 VkDebugReportCallbackEXT
+// 86
+@extension("VK_KHR_descriptor_update_template") @nonDispatchHandle type u64 VkDescriptorUpdateTemplateKHR
+
+// 87
+@extension("VK_NVX_device_generated_commands") @nonDispatchHandle type u64 VkObjectTableNVX
+@extension("VK_NVX_device_generated_commands") @nonDispatchHandle type u64 VkIndirectCommandsLayoutNVX
+
/////////////
// Enums //
@@ -160,7 +398,7 @@
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL = 0x00000007, /// Optimal layout when image is used only as destination of transfer operations
VK_IMAGE_LAYOUT_PREINITIALIZED = 0x00000008, /// Initial layout used when the data is populated by the CPU
- //@extension("VK_KHR_swapchain")
+ //@extension("VK_KHR_swapchain") // 2
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002,
}
@@ -273,7 +511,7 @@
VK_FILTER_NEAREST = 0x00000000,
VK_FILTER_LINEAR = 0x00000001,
- //@extension("VK_IMG_filter_cubic")
+ //@extension("VK_IMG_filter_cubic") // 16
VK_FILTER_CUBIC_IMG = 1000015000,
}
@@ -584,6 +822,16 @@
VK_FORMAT_ASTC_12x10_SRGB_BLOCK = 182,
VK_FORMAT_ASTC_12x12_UNORM_BLOCK = 183,
VK_FORMAT_ASTC_12x12_SRGB_BLOCK = 184,
+
+ //@extension("VK_IMG_format_pvrtc") // 28
+ VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000,
+ VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001,
+ VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002,
+ VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG = 1000054003,
+ VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG = 1000054004,
+ VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG = 1000054005,
+ VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006,
+ VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007,
}
/// Structure type enumerant
@@ -638,52 +886,198 @@
VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO = 47,
VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO = 48,
- //@extension("VK_KHR_swapchain")
+ //@extension("VK_KHR_swapchain") // 2
VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR = 1000001000,
VK_STRUCTURE_TYPE_PRESENT_INFO_KHR = 1000001001,
- //@extension("VK_KHR_display")
+ //@extension("VK_KHR_display") // 3
VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR = 1000002000,
VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR = 1000002001,
- //@extension("VK_KHR_display_swapchain")
+ //@extension("VK_KHR_display_swapchain") // 4
VK_STRUCTURE_TYPE_DISPLAY_DISPLAY_PRESENT_INFO_KHR = 1000003000,
- //@extension("VK_KHR_xlib_surface")
+ //@extension("VK_KHR_xlib_surface") // 5
VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000,
- //@extension("VK_KHR_xcb_surface")
+ //@extension("VK_KHR_xcb_surface") // 6
VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000,
- //@extension("VK_KHR_wayland_surface")
+ //@extension("VK_KHR_wayland_surface") // 7
VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000,
- //@extension("VK_KHR_mir_surface")
+ //@extension("VK_KHR_mir_surface") // 8
VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR = 1000007000,
- //@extension("VK_KHR_android_surface")
+ //@extension("VK_KHR_android_surface") // 9
VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000,
- //@extension("VK_KHR_win32_surface")
+ //@extension("VK_KHR_win32_surface") // 10
VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000,
- //@extension("VK_ANDROID_native_buffer")
+ //@extension("VK_ANDROID_native_buffer") // 11
VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID = 1000010000,
- //@extension("VK_EXT_debug_report")
+ //@extension("VK_EXT_debug_report") // 12
VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000,
- //@extension("VK_AMD_rasterization_order")
+ //@extension("VK_AMD_rasterization_order") // 19
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD = 1000018000,
- //@extension("VK_EXT_debug_marker")
+ //@extension("VK_EXT_debug_marker") // 23
VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT = 1000022000,
-
- //@extension("VK_EXT_debug_marker")
VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_TAG_INFO_EXT = 1000022001,
-
- //@extension("VK_EXT_debug_marker")
VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT = 1000022002,
+
+ //@extension("VK_NV_dedicated_allocation") // 27
+ VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000,
+ VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001,
+ VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002,
+
+ //@extension("VK_KHX_multiview") // 54
+ VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHX = 1000053000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHX = 1000053001,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHX = 1000053002,
+
+ //@extension("VK_NV_external_memory") // 57
+ VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000,
+ VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_NV = 1000056001,
+
+ //@extension("VK_NV_external_memory_win32") // 58
+ VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057000,
+ VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057001,
+
+ //@extension("VK_NV_win32_keyed_mutex") // 59
+ VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV = 1000058000,
+
+ //@extension("VK_KHR_get_physical_device_properties2") // 60
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR = 1000059000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR = 1000059001,
+ VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR = 1000059002,
+ VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059003,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR = 1000059004,
+ VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR = 1000059005,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR = 1000059006,
+ VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059007,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR = 1000059008,
+
+ //@extension("VK_KHX_device_group") // 61
+ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHX = 1000060000,
+ VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHX = 1000060001,
+ VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHX = 1000060002,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO_KHX = 1000060003,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO_KHX = 1000060004,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHX = 1000060005,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHX = 1000060006,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHX = 1000060007,
+ VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHX = 1000060008,
+ VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHX = 1000060009,
+ VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHX = 1000060010,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHX = 1000060011,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHX = 1000060012,
+
+ //@extension("VK_EXT_validation_flags") // 62
+ VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT = 1000061000,
+
+ //@extension("VK_NN_vi_surface") // 63
+ VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN = 1000062000,
+
+ //@extension("VK_KHX_device_group_creation") // 71
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHX = 1000070000,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHX = 1000070001,
+
+ //@extension("VK_KHX_external_memory_capabilities") // 72
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHX = 1000071000,
+ VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHX = 1000071001,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHX = 1000071002,
+ VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHX = 1000071003,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHX = 1000071004,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHX = 1000071005,
+ VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHX = 1000071006,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHX = 1000071007,
+
+ //@extension("VK_KHX_external_memory") // 73
+ VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHX = 1000072000,
+ VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHX = 1000072001,
+ VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHX = 1000072002,
+
+ //@extension("VK_KHX_external_memory_win32") // 74
+ VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHX = 1000073000,
+ VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHX = 1000073001,
+ VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHX = 1000073002,
+
+ //@extension("VK_KHX_external_memory_fd") // 75
+ VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHX = 1000074000,
+ VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHX = 1000074001,
+
+ //@extension("VK_KHX_win32_keyed_mutex") // 76
+ VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHX = 1000075000,
+
+ //@extension("VK_KHX_external_semaphore_capabilities") // 77
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO_KHX = 1000076000,
+ VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES_KHX = 1000076001,
+
+ //@extension("VK_KHX_external_semaphore") // 78
+ VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHX = 1000077000,
+
+ //@extension("VK_KHX_external_semaphore_win32") // 79
+ VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHX = 1000078000,
+ VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHX = 1000078001,
+ VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHX = 1000078002,
+
+ //@extension("VK_KHX_external_semaphore_fd") // 80
+ VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHX = 1000079000,
+
+ //@extension("VK_KHR_push_descriptor") // 81
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR = 1000080000,
+
+ //@extension("VK_KHR_incremental_present") // 85
+ VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR = 1000084000,
+
+ //@extension("VK_KHR_descriptor_update_template") // 86
+ VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR = 1000085000,
+
+ //@extension("VK_NVX_device_generated_commands") // 87
+ VK_STRUCTURE_TYPE_OBJECT_TABLE_CREATE_INFO_NVX = 1000086000,
+ VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NVX = 1000086001,
+ VK_STRUCTURE_TYPE_CMD_PROCESS_COMMANDS_INFO_NVX = 1000086002,
+ VK_STRUCTURE_TYPE_CMD_RESERVE_SPACE_FOR_COMMANDS_INFO_NVX = 1000086003,
+ VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_LIMITS_NVX = 1000086004,
+ VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_FEATURES_NVX = 1000086005,
+
+ //@extension("VK_NV_clip_space_w_scaling") // 88
+ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV = 1000087000,
+
+ //@extension("VK_EXT_display_surface_counter") // 91
+ VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES2_EXT = 1000090000,
+
+ //@extension("VK_EXT_display_control") // 92
+ VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT = 1000091000,
+ VK_STRUCTURE_TYPE_DEVICE_EVENT_INFO_EXT = 1000091001,
+ VK_STRUCTURE_TYPE_DISPLAY_EVENT_INFO_EXT = 1000091002,
+ VK_STRUCTURE_TYPE_SWAPCHAIN_COUNTER_CREATE_INFO_EXT = 1000091003,
+
+ //@extension("VK_GOOGLE_display_timing") // 93
+ VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE = 1000092000,
+
+ //@extension("VK_NVX_multiview_per_view_attributes") // 98
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_ATTRIBUTES_PROPERTIES_NVX = 1000097000,
+
+ //@extension("VK_NV_viewport_swizzle") // 99
+ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV = 1000098000,
+
+ //@extension("VK_EXT_discard_rectangles") // 100
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT = 1000099000,
+ VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT = 1000099001,
+
+ //@extension("VK_EXT_hdr_metadata") // 106
+ VK_STRUCTURE_TYPE_HDR_METADATA_EXT = 1000105000,
+
+ //@extension("VK_MVK_ios_surface") // 123
+ VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK = 1000122000,
+
+ //@extension("VK_MVK_macos_surface") // 124
+ VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000,
}
enum VkSubpassContents {
@@ -706,7 +1100,7 @@
VK_EVENT_RESET = 4,
VK_INCOMPLETE = 5,
- //@extension("VK_KHR_swapchain")
+ //@extension("VK_KHR_swapchain") // 2
VK_SUBOPTIMAL_KHR = 1000001003,
// Error codes (negative values)
@@ -721,24 +1115,29 @@
VK_ERROR_INCOMPATIBLE_DRIVER = 0xFFFFFFF7, // -9
VK_ERROR_TOO_MANY_OBJECTS = 0xFFFFFFF6, // -10
VK_ERROR_FORMAT_NOT_SUPPORTED = 0xFFFFFFF5, // -11
+ VK_ERROR_FRAGMENTED_POOL = 0xFFFFFFF4, // -12
- //@extension("VK_KHR_surface")
+ //@extension("VK_KHR_surface") // 1
VK_ERROR_SURFACE_LOST_KHR = 0xC4653600, // -1000000000
+ VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = 0xC46535FF, // -1000000001
- //@extension("VK_KHR_surface")
- VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = 0xC46535FF, // -1000008001
-
- //@extension("VK_KHR_swapchain")
+ //@extension("VK_KHR_swapchain") // 2
VK_ERROR_OUT_OF_DATE_KHR = 0xC4653214, // -1000001004
- //@extension("VK_KHR_display_swapchain")
+ //@extension("VK_KHR_display_swapchain") // 4
VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = 0xC4652A47, // -1000003001
- //@extension("VK_EXT_debug_report")
+ //@extension("VK_EXT_debug_report") // 12
VK_ERROR_VALIDATION_FAILED_EXT = 0xC4650B07, // -1000011001
- //@extension("VK_NV_glsl_shader")
+ //@extension("VK_NV_glsl_shader") // 13
VK_ERROR_INVALID_SHADER_NV = 0xC4650720, // -1000012000
+
+ //@extension("VK_KHR_maintenance1") // 70
+ VK_ERROR_OUT_OF_POOL_MEMORY_KHR = 0xC4642878, // -1000069000
+
+ //@extension("VK_KHX_external_memory") // 73
+ VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX = 0xC4641CBD, // -1000072003
}
enum VkDynamicState {
@@ -751,9 +1150,15 @@
VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK = 0x00000006,
VK_DYNAMIC_STATE_STENCIL_WRITE_MASK = 0x00000007,
VK_DYNAMIC_STATE_STENCIL_REFERENCE = 0x00000008,
+
+ //@extension("VK_NV_clip_space_w_scaling") // 88
+ VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV = 1000087000,
+
+ //@extension("VK_EXT_discard_rectangles") // 100
+ VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT = 1000099000,
}
-@extension("VK_KHR_surface")
+@extension("VK_KHR_surface") // 1
enum VkPresentModeKHR {
VK_PRESENT_MODE_IMMEDIATE_KHR = 0x00000000,
VK_PRESENT_MODE_MAILBOX_KHR = 0x00000001,
@@ -761,12 +1166,27 @@
VK_PRESENT_MODE_FIFO_RELAXED_KHR = 0x00000003,
}
-@extension("VK_KHR_surface")
+@extension("VK_KHR_surface") // 1
enum VkColorSpaceKHR {
VK_COLORSPACE_SRGB_NONLINEAR_KHR = 0x00000000,
+
+ //@extension("VK_EXT_swapchain_colorspace") // 105
+ VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT = 1000104001,
+ VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT = 1000104002,
+ VK_COLOR_SPACE_DCI_P3_LINEAR_EXT = 1000104003,
+ VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT = 1000104004,
+ VK_COLOR_SPACE_BT709_LINEAR_EXT = 1000104005,
+ VK_COLOR_SPACE_BT709_NONLINEAR_EXT = 1000104006,
+ VK_COLOR_SPACE_BT2020_LINEAR_EXT = 1000104007,
+ VK_COLOR_SPACE_HDR10_ST2084_EXT = 1000104008,
+ VK_COLOR_SPACE_DOLBYVISION_EXT = 1000104009,
+ VK_COLOR_SPACE_HDR10_HLG_EXT = 1000104010,
+ VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011,
+ VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012,
+ VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013,
}
-@extension("VK_EXT_debug_report")
+@extension("VK_EXT_debug_report") // 12
enum VkDebugReportObjectTypeEXT {
VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT = 0,
VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT = 1,
@@ -797,20 +1217,93 @@
VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT = 26,
VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT = 27,
VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = 28,
+ VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT = 29,
+ VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT = 30,
+ VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT = 31,
+ VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT = 32,
+
+ //extension("VK_KHR_descriptor_update_template") // 86
+ VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = 1000085000,
}
-@extension("VK_EXT_debug_report")
+@extension("VK_EXT_debug_report") // 12
enum VkDebugReportErrorEXT {
VK_DEBUG_REPORT_ERROR_NONE_EXT = 0,
VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT = 1,
}
-@extension("VK_AMD_rasterization_order")
+@extension("VK_AMD_rasterization_order") // 19
enum VkRasterizationOrderAMD {
VK_RASTERIZATION_ORDER_STRICT_AMD = 0,
VK_RASTERIZATION_ORDER_RELAXED_AMD = 1,
}
+@extension("VK_EXT_validation_flags") // 62
+enum VkValidationCheckEXT {
+ VK_VALIDATION_CHECK_ALL_EXT = 0,
+}
+
+@extension("VK_KHR_descriptor_update_template") // 86
+enum VkDescriptorUpdateTemplateTypeKHR {
+ VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR = 0,
+ VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR = 1,
+}
+
+@extension("VK_NVX_device_generated_commands") // 87
+enum VkIndirectCommandsTokenTypeNVX {
+ VK_INDIRECT_COMMANDS_TOKEN_PIPELINE_NVX = 0,
+ VK_INDIRECT_COMMANDS_TOKEN_DESCRIPTOR_SET_NVX = 1,
+ VK_INDIRECT_COMMANDS_TOKEN_INDEX_BUFFER_NVX = 2,
+ VK_INDIRECT_COMMANDS_TOKEN_VERTEX_BUFFER_NVX = 3,
+ VK_INDIRECT_COMMANDS_TOKEN_PUSH_CONSTANT_NVX = 4,
+ VK_INDIRECT_COMMANDS_TOKEN_DRAW_INDEXED_NVX = 5,
+ VK_INDIRECT_COMMANDS_TOKEN_DRAW_NVX = 6,
+ VK_INDIRECT_COMMANDS_TOKEN_DISPATCH_NVX = 7,
+}
+
+@extension("VK_NVX_device_generated_commands") // 87
+enum VkObjectEntryTypeNVX {
+ VK_OBJECT_ENTRY_DESCRIPTOR_SET_NVX = 0,
+ VK_OBJECT_ENTRY_PIPELINE_NVX = 1,
+ VK_OBJECT_ENTRY_INDEX_BUFFER_NVX = 2,
+ VK_OBJECT_ENTRY_VERTEX_BUFFER_NVX = 3,
+ VK_OBJECT_ENTRY_PUSH_CONSTANT_NVX = 4,
+}
+
+@extension("VK_EXT_display_control") // 92
+enum VkDisplayPowerStateEXT {
+ VK_DISPLAY_POWER_STATE_OFF_EXT = 0,
+ VK_DISPLAY_POWER_STATE_SUSPEND_EXT = 1,
+ VK_DISPLAY_POWER_STATE_ON_EXT = 2,
+}
+
+@extension("VK_EXT_display_control") // 92
+enum VkDeviceEventTypeEXT {
+ VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT = 0,
+}
+
+@extension("VK_EXT_display_control") // 92
+enum VkDisplayEventTypeEXT {
+ VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT = 0,
+}
+
+@extension("VK_NV_viewport_swizzle") // 99
+enum VkViewportCoordinateSwizzleNV {
+ VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV = 0,
+ VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_X_NV = 1,
+ VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV = 2,
+ VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Y_NV = 3,
+ VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV = 4,
+ VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Z_NV = 5,
+ VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV = 6,
+ VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV = 7,
+}
+
+@extension("VK_EXT_discard_rectangles") // 100
+enum VkDiscardRectangleModeEXT {
+ VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT = 0,
+ VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT = 1,
+}
/////////////////
// Bitfields //
@@ -839,6 +1332,9 @@
type VkFlags VkMemoryHeapFlags
bitfield VkMemoryHeapFlagBits {
VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 0x00000001,
+
+ //@extension("VK_KHX_device_group_creation") // 71
+ VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHX = 0x00000002,
}
/// Access flags
@@ -861,6 +1357,10 @@
VK_ACCESS_HOST_WRITE_BIT = 0x00004000,
VK_ACCESS_MEMORY_READ_BIT = 0x00008000,
VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000,
+
+ //@extension("VK_NVX_device_generated_commands") // 87
+ VK_ACCESS_COMMAND_PROCESS_READ_BIT_NVX = 0x00020000,
+ VK_ACCESS_COMMAND_PROCESS_WRITE_BIT_NVX = 0x00040000,
}
/// Buffer usage flags
@@ -931,6 +1431,12 @@
VK_IMAGE_CREATE_SPARSE_ALIASED_BIT = 0x00000004, /// Image should support constent data access to physical memory blocks mapped into multiple locations of sparse images
VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT = 0x00000008, /// Allows image views to have different format than the base image
VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT = 0x00000010, /// Allows creating image views with cube type from the created image
+
+ //@extension("VK_KHR_maintenance1") // 70
+ VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR = 0x00000020,
+
+ //@extension("VK_KHX_device_group") // 61
+ VK_IMAGE_CREATE_BIND_SFR_BIT_KHX = 0x00000040,
}
/// Image view creation flags
@@ -944,6 +1450,10 @@
VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT = 0x00000001,
VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 0x00000002,
VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004,
+
+ //@extension("VK_KHX_device_group") // 61
+ VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHX = 0x00000008,
+ VK_PIPELINE_CREATE_DISPATCH_BASE_KHX = 0x00000010,
}
/// Color component flags
@@ -983,8 +1493,12 @@
VK_FORMAT_FEATURE_BLIT_DST_BIT = 0x00000800, /// Format can be used as the destination image of blits with vkCommandBlitImage
VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 0x00001000,
- //@extension("VK_IMG_filter_cubic")
+ //@extension("VK_IMG_filter_cubic") // 16
VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = 0x00002000,
+
+ //@extension("VK_KHR_maintenance1") // 70
+ VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR = 0x00004000,
+ VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR = 0x00008000,
}
/// Query control flags
@@ -1085,6 +1599,9 @@
VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 0x00008000, /// All stages of the graphics pipeline
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 0x00010000, /// All graphics, compute, copy, and transition commands
+
+ //@extension("VK_NVX_device_generated_commands") // 87
+ VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX = 0x00020000,
}
/// Render pass attachment description flags
@@ -1096,6 +1613,9 @@
/// Subpass description flags
type VkFlags VkSubpassDescriptionFlags
bitfield VkSubpassDescriptionFlagBits {
+ //@extension("VK_NVX_multiview_per_view_attributes") // 98
+ VK_SUBPASS_DESCRIPTION_PER_VIEW_ATTRIBUTES_BIT_NVX = 0x00000001,
+ VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX = 0x00000002,
}
/// Command pool creation flags
@@ -1171,8 +1691,10 @@
/// Descriptor set layout creation flags
type VkFlags VkDescriptorSetLayoutCreateFlags
-//bitfield VkDescriptorSetLayoutCreateFlagBits {
-//}
+bitfield VkDescriptorSetLayoutCreateFlagBits {
+ //@extension("VK_KHR_push_descriptor") // 81
+ VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR = 0x00000001,
+}
/// Pipeline vertex input state creation flags
type VkFlags VkPipelineVertexInputStateCreateFlags
@@ -1243,6 +1765,12 @@
type VkFlags VkDependencyFlags
bitfield VkDependencyFlagBits {
VK_DEPENDENCY_BY_REGION_BIT = 0x00000001,
+
+ //@extension("VK_KHX_multiview") // 54
+ VK_DEPENDENCY_VIEW_LOCAL_BIT_KHX = 0x00000002,
+
+ //@extension("VK_KHX_device_group") // 61
+ VK_DEPENDENCY_DEVICE_GROUP_BIT_KHX = 0x00000004,
}
/// Cull mode flags
@@ -1254,9 +1782,9 @@
VK_CULL_MODE_FRONT_AND_BACK = 0x00000003,
}
-@extension("VK_KHR_surface")
+@extension("VK_KHR_surface") // 1
type VkFlags VkSurfaceTransformFlagsKHR
-@extension("VK_KHR_surface")
+@extension("VK_KHR_surface") // 1
bitfield VkSurfaceTransformFlagBitsKHR {
VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR = 0x00000001,
VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR = 0x00000002,
@@ -1269,9 +1797,9 @@
VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR = 0x00000100,
}
-@extension("VK_KHR_surface")
+@extension("VK_KHR_surface") // 1
type VkFlags VkCompositeAlphaFlagsKHR
-@extension("VK_KHR_surface")
+@extension("VK_KHR_surface") // 1
bitfield VkCompositeAlphaFlagBitsKHR {
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR = 0x00000001,
VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR = 0x00000002,
@@ -1279,15 +1807,17 @@
VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR = 0x00000008,
}
-@extension("VK_KHR_swapchain")
+@extension("VK_KHR_swapchain") // 2
type VkFlags VkSwapchainCreateFlagsKHR
-//@extension("VK_KHR_swapchain")
-//bitfield VkSwapchainCreateFlagBitsKHR {
-//}
+@extension("VK_KHR_swapchain") // 2
+bitfield VkSwapchainCreateFlagBitsKHR {
+ //@extension("VK_KHX_device_group") // 61
+ VK_SWAPCHAIN_CREATE_BIND_SFR_BIT_KHX = 0x00000001,
+}
-@extension("VK_KHR_display")
+@extension("VK_KHR_display") // 3
type VkFlags VkDisplayPlaneAlphaFlagsKHR
-@extension("VK_KHR_display")
+@extension("VK_KHR_display") // 3
bitfield VkDisplayPlaneAlphaFlagBitsKHR {
VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR = 0x00000001,
VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR = 0x00000002,
@@ -1295,57 +1825,57 @@
VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR = 0x00000008,
}
-@extension("VK_KHR_display")
+@extension("VK_KHR_display") // 3
type VkFlags VkDisplaySurfaceCreateFlagsKHR
-//@extension("VK_KHR_display")
+//@extension("VK_KHR_display") // 3
//bitfield VkDisplaySurfaceCreateFlagBitsKHR {
//}
-@extension("VK_KHR_display")
+@extension("VK_KHR_display") // 3
type VkFlags VkDisplayModeCreateFlagsKHR
-//@extension("VK_KHR_display")
+//@extension("VK_KHR_display") // 3
//bitfield VkDisplayModeCreateFlagBitsKHR {
//}
-@extension("VK_KHR_xlib_surface")
+@extension("VK_KHR_xlib_surface") // 5
type VkFlags VkXlibSurfaceCreateFlagsKHR
-//@extension("VK_KHR_xlib_surface")
+//@extension("VK_KHR_xlib_surface") // 5
//bitfield VkXlibSurfaceCreateFlagBitsKHR {
//}
-@extension("VK_KHR_xcb_surface")
+@extension("VK_KHR_xcb_surface") // 6
type VkFlags VkXcbSurfaceCreateFlagsKHR
-//@extension("VK_KHR_xcb_surface")
+//@extension("VK_KHR_xcb_surface") // 6
//bitfield VkXcbSurfaceCreateFlagBitsKHR {
//}
-@extension("VK_KHR_wayland_surface")
+@extension("VK_KHR_wayland_surface") // 7
type VkFlags VkWaylandSurfaceCreateFlagsKHR
-//@extension("VK_KHR_wayland_surface")
+//@extension("VK_KHR_wayland_surface") // 7
//bitfield VkWaylandSurfaceCreateFlagBitsKHR {
//}
-@extension("VK_KHR_mir_surface")
+@extension("VK_KHR_mir_surface") // 8
type VkFlags VkMirSurfaceCreateFlagsKHR
-//@extension("VK_KHR_mir_surface")
+//@extension("VK_KHR_mir_surface") // 8
//bitfield VkMirSurfaceCreateFlagBitsKHR {
//}
-@extension("VK_KHR_android_surface")
+@extension("VK_KHR_android_surface") // 9
type VkFlags VkAndroidSurfaceCreateFlagsKHR
-//@extension("VK_KHR_android_surface")
+//@extension("VK_KHR_android_surface") // 9
//bitfield VkAndroidSurfaceCreateFlagBitsKHR {
//}
-@extension("VK_KHR_win32_surface")
+@extension("VK_KHR_win32_surface") // 10
type VkFlags VkWin32SurfaceCreateFlagsKHR
-//@extension("VK_KHR_win32_surface")
+//@extension("VK_KHR_win32_surface") // 10
//bitfield VkWin32SurfaceCreateFlagBitsKHR {
//}
-@extension("VK_EXT_debug_report")
+@extension("VK_EXT_debug_report") // 12
type VkFlags VkDebugReportFlagsEXT
-@extension("VK_EXT_debug_report")
+@extension("VK_EXT_debug_report") // 12
bitfield VkDebugReportFlagBitsEXT {
VK_DEBUG_REPORT_INFORMATION_BIT_EXT = 0x00000001,
VK_DEBUG_REPORT_WARNING_BIT_EXT = 0x00000002,
@@ -1354,6 +1884,159 @@
VK_DEBUG_REPORT_DEBUG_BIT_EXT = 0x00000010,
}
+@extension("VK_NV_external_memory_capabilities") // 56
+type VkFlags VkExternalMemoryHandleTypeFlagsNV
+@extension("VK_NV_external_memory_capabilities") // 56
+bitfield VkExternalMemoryHandleTypeFlagBitsNV {
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_NV = 0x00000001,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_NV = 0x00000002,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_BIT_NV = 0x00000004,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_KMT_BIT_NV = 0x00000008,
+}
+
+@extension("VK_NV_external_memory_capabilities") // 56
+type VkFlags VkExternalMemoryFeatureFlagsNV
+@extension("VK_NV_external_memory_capabilities") // 56
+bitfield VkExternalMemoryFeatureFlagBitsNV {
+ VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_NV = 0x00000001,
+ VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_NV = 0x00000002,
+ VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_NV = 0x00000004,
+}
+
+@extension("VK_KHX_device_group") // 61
+type VkFlags VkPeerMemoryFeatureFlagsKHX
+@extension("VK_KHX_device_group") // 61
+bitfield VkPeerMemoryFeatureFlagBitsKHX {
+ VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT_KHX = 0x00000001,
+ VK_PEER_MEMORY_FEATURE_COPY_DST_BIT_KHX = 0x00000002,
+ VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT_KHX = 0x00000004,
+ VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHX = 0x00000008,
+}
+
+@extension("VK_KHX_device_group") // 61
+type VkFlags VkMemoryAllocateFlagsKHX
+@extension("VK_KHX_device_group") // 61
+bitfield VkMemoryAllocateFlagBitsKHX {
+ VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHX = 0x00000001,
+}
+
+@extension("VK_KHX_device_group") // 61
+type VkFlags VkDeviceGroupPresentModeFlagsKHX
+@extension("VK_KHX_device_group") // 61
+bitfield VkDeviceGroupPresentModeFlagBitsKHX {
+ VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHX = 0x00000001,
+ VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHX = 0x00000002,
+ VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHX = 0x00000004,
+ VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHX = 0x00000008,
+}
+
+@extension("VK_NN_vi_surface") // 63
+type VkFlags VkViSurfaceCreateFlagsNN
+//@extension("VK_NN_vi_surface") // 63
+//bitfield VkViSurfaceCreateFlagBitsNN {
+//}
+
+@extension("VK_KHR_maintenance1") // 70
+type VkFlags VkCommandPoolTrimFlagsKHR
+//@extension("VK_KHR_maintenance1") // 70
+//bitfield VkCommandPoolTrimFlagBitsKHR {
+//}
+
+@extension("VK_KHX_external_memory_capabilities") // 72
+type VkFlags VkExternalMemoryHandleTypeFlagsKHX
+@extension("VK_KHX_external_memory_capabilities") // 72
+bitfield VkExternalMemoryHandleTypeFlagBitsKHX {
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHX = 0x00000001,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHX = 0x00000002,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHX = 0x00000004,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT_KHX = 0x00000008,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT_KHX = 0x00000010,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT_KHX = 0x00000020,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT_KHX = 0x00000040,
+}
+
+@extension("VK_KHX_external_memory_capabilities") // 72
+type VkFlags VkExternalMemoryFeatureFlagsKHX
+@extension("VK_KHX_external_memory_capabilities") // 72
+bitfield VkExternalMemoryFeatureFlagBitsKHX {
+ VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHX = 0x00000001,
+ VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHX = 0x00000002,
+ VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHX = 0x00000004,
+}
+
+@extension("VK_KHX_external_semaphore_capabilities") // 77
+type VkFlags VkExternalSemaphoreHandleTypeFlagsKHX
+@extension("VK_KHX_external_semaphore_capabilities") // 77
+bitfield VkExternalSemaphoreHandleTypeFlagBitsKHX {
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHX = 0x00000001
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHX = 0x00000002
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHX = 0x00000004
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT_KHX = 0x00000008
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FENCE_FD_BIT_KHX = 0x00000010
+}
+
+@extension("VK_KHX_external_semaphore_capabilities") // 77
+type VkFlags VkExternalSemaphoreFeatureFlagsKHX
+@extension("VK_KHX_external_semaphore_capabilities") // 77
+bitfield VkExternalSemaphoreFeatureFlagBitsKHX {
+ VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHX = 0x00000001,
+ VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHX = 0x00000002,
+}
+
+@extension("VK_KHR_descriptor_update_template") // 86
+type VkFlags VkDescriptorUpdateTemplateCreateFlagsKHR
+//@extension("VK_KHR_descriptor_update_template") // 86
+//bitfield VkDescriptorUpdateTemplateCreateFlagBitsKHR {
+//}
+
+@extension("VK_NVX_device_generated_commands") // 87
+type VkFlags VkIndirectCommandsLayoutUsageFlagsNVX
+@extension("VK_NVX_device_generated_commands") // 87
+bitfield VkIndirectCommandsLayoutUsageFlagBitsNVX {
+ VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NVX = 0x00000001,
+ VK_INDIRECT_COMMANDS_LAYOUT_USAGE_SPARSE_SEQUENCES_BIT_NVX = 0x00000002,
+ VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EMPTY_EXECUTIONS_BIT_NVX = 0x00000004,
+ VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NVX = 0x00000008,
+}
+
+@extension("VK_NVX_device_generated_commands") // 87
+type VkFlags VkObjectEntryUsageFlagsNVX
+@extension("VK_NVX_device_generated_commands") // 87
+bitfield VkObjectEntryUsageFlagBitsNVX {
+ VK_OBJECT_ENTRY_USAGE_GRAPHICS_BIT_NVX = 0x00000001,
+ VK_OBJECT_ENTRY_USAGE_COMPUTE_BIT_NVX = 0x00000002,
+}
+
+@extension("VK_EXT_display_surface_counter") // 91
+type VkFlags VkSurfaceCounterFlagsEXT
+@extension("VK_EXT_display_surface_counter") // 91
+bitfield VkSurfaceCounterFlagBitsEXT {
+ VK_SURFACE_COUNTER_VBLANK_EXT = 0x00000001,
+}
+
+@extension("VK_NV_viewport_swizzle") // 99
+type VkFlags VkPipelineViewportSwizzleStateCreateFlagsNV
+//@extension("VK_NV_viewport_swizzle") // 99
+//bitfield VkPipelineViewportSwizzleStateCreateFlagBitsNV {
+//}
+
+@extension("VK_EXT_discard_rectangles") // 100
+type VkFlags VkPipelineDiscardRectangleStateCreateFlagsEXT
+//@extension("VK_EXT_discard_rectangles") // 100
+//bitfield VkPipelineDiscardRectangleStateCreateFlagBitsEXT {
+//}
+
+@extension("VK_MVK_ios_surface") // 123
+type VkFlags VkIOSSurfaceCreateFlagsMVK
+//@extension("VK_MVK_ios_surface") // 123
+//bitfield VkIOSSurfaceCreateFlagBitsMVK {
+//}
+
+@extension("VK_MVK_macos_surface") // 124
+type VkFlags VkMacOSSurfaceCreateFlagsMVK
+//@extension("VK_MVK_macos_surface") // 124
+//bitfield VkMacOSSurfaceCreateFlagBitsMVK {
+//}
//////////////////
// Structures //
@@ -2459,7 +3142,7 @@
u32 z
}
-@extension("VK_KHR_surface")
+@extension("VK_KHR_surface") // 1
class VkSurfaceCapabilitiesKHR {
u32 minImageCount
u32 maxImageCount
@@ -2473,13 +3156,13 @@
VkImageUsageFlags supportedUsageFlags
}
-@extension("VK_KHR_surface")
+@extension("VK_KHR_surface") // 1
class VkSurfaceFormatKHR {
VkFormat format
VkColorSpaceKHR colorSpace
}
-@extension("VK_KHR_swapchain")
+@extension("VK_KHR_swapchain") // 2
class VkSwapchainCreateInfoKHR {
VkStructureType sType
const void* pNext
@@ -2501,7 +3184,7 @@
VkSwapchainKHR oldSwapchain
}
-@extension("VK_KHR_swapchain")
+@extension("VK_KHR_swapchain") // 2
class VkPresentInfoKHR {
VkStructureType sType
const void* pNext
@@ -2513,7 +3196,7 @@
VkResult* pResults
}
-@extension("VK_KHR_display")
+@extension("VK_KHR_display") // 3
class VkDisplayPropertiesKHR {
VkDisplayKHR display
const char* displayName
@@ -2524,19 +3207,19 @@
VkBool32 persistentContent
}
-@extension("VK_KHR_display")
+@extension("VK_KHR_display") // 3
class VkDisplayModeParametersKHR {
VkExtent2D visibleRegion
u32 refreshRate
}
-@extension("VK_KHR_display")
+@extension("VK_KHR_display") // 3
class VkDisplayModePropertiesKHR {
VkDisplayModeKHR displayMode
VkDisplayModeParametersKHR parameters
}
-@extension("VK_KHR_display")
+@extension("VK_KHR_display") // 3
class VkDisplayModeCreateInfoKHR {
VkStructureType sType
const void* pNext
@@ -2544,13 +3227,13 @@
VkDisplayModeParametersKHR parameters
}
-@extension("VK_KHR_display")
+@extension("VK_KHR_display") // 3
class VkDisplayPlanePropertiesKHR {
VkDisplayKHR currentDisplay
u32 currentStackIndex
}
-@extension("VK_KHR_display")
+@extension("VK_KHR_display") // 3
class VkDisplayPlaneCapabilitiesKHR {
VkDisplayPlaneAlphaFlagsKHR supportedAlpha
VkOffset2D minSrcPosition
@@ -2563,7 +3246,7 @@
VkExtent2D maxDstExtent
}
-@extension("VK_KHR_display")
+@extension("VK_KHR_display") // 3
class VkDisplaySurfaceCreateInfoKHR {
VkStructureType sType
const void* pNext
@@ -2577,7 +3260,7 @@
VkExtent2D imageExtent
}
-@extension("VK_KHR_display_swapchain")
+@extension("VK_KHR_display_swapchain") // 4
class VkDisplayPresentInfoKHR {
VkStructureType sType
const void* pNext
@@ -2586,7 +3269,7 @@
VkBool32 persistent
}
-@extension("VK_KHR_xlib_surface")
+@extension("VK_KHR_xlib_surface") // 5
class VkXlibSurfaceCreateInfoKHR {
VkStructureType sType
const void* pNext
@@ -2595,7 +3278,7 @@
platform.Window window
}
-@extension("VK_KHR_xcb_surface")
+@extension("VK_KHR_xcb_surface") // 6
class VkXcbSurfaceCreateInfoKHR {
VkStructureType sType
const void* pNext
@@ -2604,7 +3287,7 @@
platform.xcb_window_t window
}
-@extension("VK_KHR_wayland_surface")
+@extension("VK_KHR_wayland_surface") // 7
class VkWaylandSurfaceCreateInfoKHR {
VkStructureType sType
const void* pNext
@@ -2613,7 +3296,7 @@
platform.wl_surface* surface
}
-@extension("VK_KHR_mir_surface")
+@extension("VK_KHR_mir_surface") // 8
class VkMirSurfaceCreateInfoKHR {
VkStructureType sType
const void* pNext
@@ -2622,7 +3305,7 @@
platform.MirSurface* mirSurface
}
-@extension("VK_KHR_android_surface")
+@extension("VK_KHR_android_surface") // 9
class VkAndroidSurfaceCreateInfoKHR {
VkStructureType sType
const void* pNext
@@ -2630,7 +3313,7 @@
platform.ANativeWindow* window
}
-@extension("VK_KHR_win32_surface")
+@extension("VK_KHR_win32_surface") // 10
class VkWin32SurfaceCreateInfoKHR {
VkStructureType sType
const void* pNext
@@ -2639,7 +3322,7 @@
platform.HWND hwnd
}
-@extension("VK_ANDROID_native_buffer")
+@extension("VK_ANDROID_native_buffer") // 11
class VkNativeBufferANDROID {
VkStructureType sType
const void* pNext
@@ -2649,7 +3332,7 @@
int usage
}
-@extension("VK_EXT_debug_report")
+@extension("VK_EXT_debug_report") // 12
class VkDebugReportCallbackCreateInfoEXT {
VkStructureType sType
const void* pNext
@@ -2658,14 +3341,14 @@
void* pUserData
}
-@extension("VK_AMD_rasterization_order")
+@extension("VK_AMD_rasterization_order") // 19
class VkPipelineRasterizationStateRasterizationOrderAMD {
VkStructureType sType
const void* pNext
VkRasterizationOrderAMD rasterizationOrder
}
-@extension("VK_EXT_debug_marker")
+@extension("VK_EXT_debug_marker") // 23
class VkDebugMarkerObjectNameInfoEXT {
VkStructureType sType
const void* pNext
@@ -2674,7 +3357,7 @@
const char* pObjectName
}
-@extension("VK_EXT_debug_marker")
+@extension("VK_EXT_debug_marker") // 23
class VkDebugMarkerObjectTagInfoEXT {
VkStructureType sType
const void* pNext
@@ -2685,7 +3368,7 @@
const void* pTag
}
-@extension("VK_EXT_debug_marker")
+@extension("VK_EXT_debug_marker") // 23
class VkDebugMarkerMarkerInfoEXT {
VkStructureType sType
const void* pNext
@@ -2693,6 +3376,853 @@
f32[4] color
}
+@extension("VK_NV_dedicated_allocation") // 27
+class VkDedicatedAllocationImageCreateInfoNV {
+ VkStructureType sType
+ const void* pNext
+ VkBool32 dedicatedAllocation
+}
+
+@extension("VK_NV_dedicated_allocation") // 27
+class VkDedicatedAllocationBufferCreateInfoNV {
+ VkStructureType sType
+ const void* pNext
+ VkBool32 dedicatedAllocation
+}
+
+@extension("VK_NV_dedicated_allocation") // 27
+class VkDedicatedAllocationMemoryAllocateInfoNV {
+ VkStructureType sType
+ const void* pNext
+ VkImage image
+ VkBuffer buffer
+}
+
+@extension("VK_KHX_multiview") // 54
+class VkRenderPassMultiviewCreateInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ u32 subpassCount
+ const u32* pViewMasks
+ u32 dependencyCount
+ const s32* pViewOffsets
+ u32 correlationMaskCount
+ const u32* pCorrelationMasks
+}
+
+@extension("VK_KHX_multiview") // 54
+class VkPhysicalDeviceMultiviewFeaturesKHX {
+ VkStructureType sType
+ void* pNext
+ VkBool32 multiview
+ VkBool32 multiviewGeometryShader
+ VkBool32 multiviewTessellationShader
+}
+
+@extension("VK_KHX_multiview") // 54
+class VkPhysicalDeviceMultiviewPropertiesKHX {
+ VkStructureType sType
+ void* pNext
+ u32 maxMultiviewViewCount
+ u32 maxMultiviewInstanceIndex
+}
+
+@extension("VK_NV_external_memory_capabilities") // 56
+class VkExternalImageFormatPropertiesNV {
+ VkImageFormatProperties imageFormatProperties
+ VkExternalMemoryFeatureFlagsNV externalMemoryFeatures
+ VkExternalMemoryHandleTypeFlagsNV exportFromImportedHandleTypes
+ VkExternalMemoryHandleTypeFlagsNV compatibleHandleTypes
+}
+
+@extension("VK_NV_external_memory") // 57
+class VkExternalMemoryImageCreateInfoNV {
+ VkStructureType sType
+ const void* pNext
+ VkExternalMemoryHandleTypeFlagsNV handleTypes
+}
+
+@extension("VK_NV_external_memory") // 57
+class VkExportMemoryAllocateInfoNV {
+ VkStructureType sType
+ const void* pNext
+ VkExternalMemoryHandleTypeFlagsNV handleTypes
+}
+
+@extension("VK_NV_external_memory_win32") // 58
+class VkImportMemoryWin32HandleInfoNV {
+ VkStructureType sType
+ const void* pNext
+ VkExternalMemoryHandleTypeFlagsNV handleType
+ platform.HANDLE handle
+}
+
+@extension("VK_NV_external_memory_win32") // 58
+class VkExportMemoryWin32HandleInfoNV {
+ VkStructureType sType
+ const void* pNext
+ const platform.SECURITY_ATTRIBUTES* pAttributes
+ platform.DWORD dwAccess
+}
+
+@extension("VK_NV_win32_keyed_mutex") // 59
+class VkWin32KeyedMutexAcquireReleaseInfoNV {
+ VkStructureType sType
+ const void* pNext
+ u32 acquireCount
+ const VkDeviceMemory* pAcquireSyncs
+ const u64* pAcquireKeys
+ const u32* pAcquireTimeoutMilliseconds
+ u32 releaseCount
+ const VkDeviceMemory* pReleaseSyncs
+ const u64* pReleaseKeys
+}
+
+@extension("VK_KHR_get_physical_device_properties2") // 60
+class VkPhysicalDeviceFeatures2KHR {
+ VkStructureType sType
+ void* pNext
+ VkPhysicalDeviceFeatures features
+}
+
+@extension("VK_KHR_get_physical_device_properties2") // 60
+class VkPhysicalDeviceProperties2KHR {
+ VkStructureType sType
+ void* pNext
+ VkPhysicalDeviceProperties properties
+}
+
+@extension("VK_KHR_get_physical_device_properties2") // 60
+class VkFormatProperties2KHR {
+ VkStructureType sType
+ void* pNext
+ VkFormatProperties formatProperties
+}
+
+@extension("VK_KHR_get_physical_device_properties2") // 60
+class VkImageFormatProperties2KHR {
+ VkStructureType sType
+ void* pNext
+ VkImageFormatProperties imageFormatProperties
+}
+
+@extension("VK_KHR_get_physical_device_properties2") // 60
+class VkPhysicalDeviceImageFormatInfo2KHR {
+ VkStructureType sType
+ const void* pNext
+ VkFormat format
+ VkImageType type
+ VkImageTiling tiling
+ VkImageUsageFlags usage
+ VkImageCreateFlags flags
+}
+
+@extension("VK_KHR_get_physical_device_properties2") // 60
+class VkQueueFamilyProperties2KHR {
+ VkStructureType sType
+ void* pNext
+ VkQueueFamilyProperties queueFamilyProperties
+}
+
+@extension("VK_KHR_get_physical_device_properties2") // 60
+class VkPhysicalDeviceMemoryProperties2KHR {
+ VkStructureType sType
+ void* pNext
+ VkPhysicalDeviceMemoryProperties memoryProperties
+}
+
+@extension("VK_KHR_get_physical_device_properties2") // 60
+class VkSparseImageFormatProperties2KHR {
+ VkStructureType sType
+ void* pNext
+ VkSparseImageFormatProperties properties
+}
+
+@extension("VK_KHR_get_physical_device_properties2") // 60
+class VkPhysicalDeviceSparseImageFormatInfo2KHR {
+ VkStructureType sType
+ const void* pNext
+ VkFormat format
+ VkImageType type
+ VkSampleCountFlagBits samples
+ VkImageUsageFlags usage
+ VkImageTiling tiling
+}
+
+@extension("VK_KHX_device_group") // 61
+class VkMemoryAllocateFlagsInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ VkMemoryAllocateFlagsKHX flags
+ u32 deviceMask
+}
+
+@extension("VK_KHX_device_group") // 61
+class VkBindBufferMemoryInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ VkBuffer buffer
+ VkDeviceMemory memory
+ VkDeviceSize memoryOffset
+ u32 deviceIndexCount
+ const u32* pDeviceIndices
+}
+
+@extension("VK_KHX_device_group") // 61
+class VkBindImageMemoryInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ VkImage image
+ VkDeviceMemory memory
+ VkDeviceSize memoryOffset
+ u32 deviceIndexCount
+ const u32* pDeviceIndices
+ u32 SFRRectCount
+ const VkRect2D* pSFRRects
+}
+
+@extension("VK_KHX_device_group") // 61
+class VkDeviceGroupRenderPassBeginInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ u32 deviceMask
+ u32 deviceRenderAreaCount
+ const VkRect2D* pDeviceRenderAreas
+}
+
+@extension("VK_KHX_device_group") // 61
+class VkDeviceGroupCommandBufferBeginInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ u32 deviceMask
+}
+
+@extension("VK_KHX_device_group") // 61
+class VkDeviceGroupSubmitInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ u32 waitSemaphoreCount
+ const u32* pWaitSemaphoreDeviceIndices
+ u32 commandBufferCount
+ const u32* pCommandBufferDeviceMasks
+ u32 signalSemaphoreCount
+ const u32* pSignalSemaphoreDeviceIndices
+}
+
+@extension("VK_KHX_device_group") // 61
+class VkDeviceGroupBindSparseInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ u32 resourceDeviceIndex
+ u32 memoryDeviceIndex
+}
+
+@extension("VK_KHX_device_group") // 61
+class VkDeviceGroupPresentCapabilitiesKHX {
+ VkStructureType sType
+ const void* pNext
+ u32[VK_MAX_DEVICE_GROUP_SIZE_KHX] presentMask
+ VkDeviceGroupPresentModeFlagsKHX modes
+}
+
+@extension("VK_KHX_device_group") // 61
+class VkImageSwapchainCreateInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ VkSwapchainKHR swapchain
+}
+
+@extension("VK_KHX_device_group") // 61
+class VkBindImageMemorySwapchainInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ VkSwapchainKHR swapchain
+ u32 imageIndex
+}
+
+@extension("VK_KHX_device_group") // 61
+class VkAcquireNextImageInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ VkSwapchainKHR swapchain
+ u64 timeout
+ VkSemaphore semaphore
+ VkFence fence
+ u32 deviceMask
+}
+
+@extension("VK_KHX_device_group") // 61
+class VkDeviceGroupPresentInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ u32 swapchainCount
+ const u32* pDeviceMasks
+ VkDeviceGroupPresentModeFlagBitsKHX mode
+}
+
+@extension("VK_KHX_device_group") // 61
+class VkDeviceGroupSwapchainCreateInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ VkDeviceGroupPresentModeFlagsKHX modes
+}
+
+@extension("VK_EXT_validation_flags") // 62
+class VkValidationFlagsEXT {
+ VkStructureType sType
+ const void* pNext
+ u32 disabledValidationCheckCount
+ VkValidationCheckEXT* pDisabledValidationChecks
+}
+
+@extension("VK_NN_vi_surface") // 63
+class VkViSurfaceCreateInfoNN {
+ VkStructureType sType
+ const void* pNext
+ VkViSurfaceCreateFlagsNN flags
+ void* window
+}
+
+@extension("VK_KHX_device_group_creation") // 71
+class VkPhysicalDeviceGroupPropertiesKHX {
+ VkStructureType sType
+ void* pNext
+ u32 physicalDeviceCount
+ VkPhysicalDevice[VK_MAX_DEVICE_GROUP_SIZE_KHX] physicalDevices
+ VkBool32 subsetAllocation
+}
+
+@extension("VK_KHX_device_group_creation") // 71
+class VkDeviceGroupDeviceCreateInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ u32 physicalDeviceCount
+ const VkPhysicalDevice* pPhysicalDevices
+}
+
+@extension("VK_KHX_external_memory_capabilities") // 72
+class VkExternalMemoryPropertiesKHX {
+ VkExternalMemoryFeatureFlagsKHX externalMemoryFeatures
+ VkExternalMemoryHandleTypeFlagsKHX exportFromImportedHandleTypes
+ VkExternalMemoryHandleTypeFlagsKHX compatibleHandleTypes
+}
+
+@extension("VK_KHX_external_memory_capabilities") // 72
+class VkPhysicalDeviceExternalImageFormatInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ VkExternalMemoryHandleTypeFlagBitsKHX handleType
+}
+
+@extension("VK_KHX_external_memory_capabilities") // 72
+class VkExternalImageFormatPropertiesKHX {
+ VkStructureType sType
+ void* pNext
+ VkExternalMemoryPropertiesKHX externalMemoryProperties
+}
+
+@extension("VK_KHX_external_memory_capabilities") // 72
+class VkPhysicalDeviceExternalBufferInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ VkBufferCreateFlags flags
+ VkBufferUsageFlags usage
+ VkExternalMemoryHandleTypeFlagBitsKHX handleType
+}
+
+@extension("VK_KHX_external_memory_capabilities") // 72
+class VkExternalBufferPropertiesKHX {
+ VkStructureType sType
+ void* pNext
+ VkExternalMemoryPropertiesKHX externalMemoryProperties
+}
+
+@extension("VK_KHX_external_memory_capabilities") // 72
+class VkPhysicalDeviceIDPropertiesKHX {
+ VkStructureType sType
+ void* pNext
+ u8[VK_UUID_SIZE] deviceUUID
+ u8[VK_UUID_SIZE] driverUUID
+ u8[VK_LUID_SIZE_KHX] deviceLUID
+ VkBool32 deviceLUIDValid
+}
+
+@extension("VK_KHX_external_memory") // 73
+class VkExternalMemoryImageCreateInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ VkExternalMemoryHandleTypeFlagsKHX handleTypes
+}
+
+@extension("VK_KHX_external_memory") // 73
+class VkExternalMemoryBufferCreateInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ VkExternalMemoryHandleTypeFlagsKHX handleTypes
+}
+
+@extension("VK_KHX_external_memory") // 73
+class VkExportMemoryAllocateInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ VkExternalMemoryHandleTypeFlagsKHX handleTypes
+}
+
+@extension("VK_KHX_external_memory_win32") // 74
+class VkImportMemoryWin32HandleInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ VkExternalMemoryHandleTypeFlagBitsKHX handleType
+ platform.HANDLE handle
+}
+
+@extension("VK_KHX_external_memory_win32") // 74
+class VkExportMemoryWin32HandleInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ const platform.SECURITY_ATTRIBUTES* pAttributes
+ platform.DWORD dwAccess
+ platform.LPCWSTR name
+}
+
+@extension("VK_KHX_external_memory_win32") // 74
+class VkMemoryWin32HandlePropertiesKHX {
+ VkStructureType sType
+ void* pNext
+ u32 memoryTypeBits
+}
+
+@extension("VK_KHX_external_memory_fd") // 75
+class VkImportMemoryFdInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ VkExternalMemoryHandleTypeFlagBitsKHX handleType
+ int fd
+}
+
+@extension("VK_KHX_external_memory_fd") // 75
+class VkMemoryFdPropertiesKHX {
+ VkStructureType sType
+ void* pNext
+ u32 memoryTypeBits
+}
+
+@extension("VK_KHX_win32_keyed_mutex") // 76
+class VkWin32KeyedMutexAcquireReleaseInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ u32 acquireCount
+ const VkDeviceMemory* pAcquireSyncs
+ const u64* pAcquireKeys
+ const u32* pAcquireTimeouts
+ u32 releaseCount
+ const VkDeviceMemory* pReleaseSyncs
+ const u64* pReleaseKeys
+}
+
+@extension("VK_KHX_external_semaphore_capabilities") // 77
+class VkPhysicalDeviceExternalSemaphoreInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ VkExternalSemaphoreHandleTypeFlagBitsKHX handleType
+}
+
+@extension("VK_KHX_external_semaphore_capabilities") // 77
+class VkExternalSemaphorePropertiesKHX {
+ VkStructureType sType
+ void* pNext
+ VkExternalSemaphoreHandleTypeFlagsKHX exportFromImportedHandleTypes
+ VkExternalSemaphoreHandleTypeFlagsKHX compatibleHandleTypes
+ VkExternalSemaphoreFeatureFlagsKHX externalSemaphoreFeatures
+}
+
+@extension("VK_KHX_external_semaphore") // 78
+class VkExportSemaphoreCreateInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ VkExternalSemaphoreHandleTypeFlagsKHX handleTypes
+}
+
+@extension("VK_KHX_external_semaphore_win32") // 79
+class VkImportSemaphoreWin32HandleInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ VkSemaphore semaphore
+ VkExternalSemaphoreHandleTypeFlagsKHX handleType
+ platform.HANDLE handle
+}
+
+@extension("VK_KHX_external_semaphore_win32") // 79
+class VkExportSemaphoreWin32HandleInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ const platform.SECURITY_ATTRIBUTES* pAttributes
+ platform.DWORD dwAccess
+ platform.LPCWSTR name
+}
+
+@extension("VK_KHX_external_semaphore_win32") // 79
+class VkD3D12FenceSubmitInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ u32 waitSemaphoreValuesCount
+ const u64* pWaitSemaphoreValues
+ u32 signalSemaphoreValuesCount
+ const u64* pSignalSemaphoreValues
+}
+
+@extension("VK_KHX_external_semaphore_fd") // 80
+class VkImportSemaphoreFdInfoKHX {
+ VkStructureType sType
+ const void* pNext
+ VkSemaphore semaphore
+ VkExternalSemaphoreHandleTypeFlagBitsKHX handleType
+ s32 fd
+}
+
+@extension("VK_KHR_push_descriptor") // 81
+class VkPhysicalDevicePushDescriptorPropertiesKHR {
+ VkStructureType sType
+ void* pNext
+ u32 maxPushDescriptors
+}
+
+@extension("VK_KHR_incremental_present") // 85
+class VkRectLayerKHR {
+ VkOffset2D offset
+ VkExtent2D extent
+ u32 layer
+}
+
+@extension("VK_KHR_incremental_present") // 85
+class VkPresentRegionKHR {
+ u32 rectangleCount
+ const VkRectLayerKHR* pRectangles
+}
+
+@extension("VK_KHR_incremental_present") // 85
+class VkPresentRegionsKHR {
+ VkStructureType sType
+ const void* pNext
+ u32 swapchainCount
+ const VkPresentRegionKHR* pRegions
+}
+
+@extension("VK_KHR_descriptor_update_template") // 86
+class VkDescriptorUpdateTemplateEntryKHR {
+ u32 dstBinding
+ u32 dstArrayElement
+ u32 descriptorCount
+ VkDescriptorType descriptorType
+ platform.size_t offset
+ platform.size_t stride
+}
+
+@extension("VK_KHR_descriptor_update_template") // 86
+class VkDescriptorUpdateTemplateCreateInfoKHR {
+ VkStructureType sType
+ void* pNext
+ VkDescriptorUpdateTemplateCreateFlagsKHR flags
+ u32 descriptorUpdateEntryCount
+ const VkDescriptorUpdateTemplateEntryKHR* pDescriptorUpdateEntries
+ VkDescriptorUpdateTemplateTypeKHR templateType
+ VkDescriptorSetLayout descriptorSetLayout
+ VkPipelineBindPoint pipelineBindPoint
+ VkPipelineLayout pipelineLayout
+ u32 set
+}
+
+@extension("VK_NVX_device_generated_commands") // 87
+class VkDeviceGeneratedCommandsFeaturesNVX {
+ VkStructureType sType
+ const void* pNext
+ VkBool32 computeBindingPointSupport
+}
+
+@extension("VK_NVX_device_generated_commands") // 87
+class VkDeviceGeneratedCommandsLimitsNVX {
+ VkStructureType sType
+ const void* pNext
+ u32 maxIndirectCommandsLayoutTokenCount
+ u32 maxObjectEntryCounts
+ u32 minSequenceCountBufferOffsetAlignment
+ u32 minSequenceIndexBufferOffsetAlignment
+ u32 minCommandsTokenBufferOffsetAlignment
+}
+
+@extension("VK_NVX_device_generated_commands") // 87
+class VkIndirectCommandsTokenNVX {
+ VkIndirectCommandsTokenTypeNVX tokenType
+ VkBuffer buffer
+ VkDeviceSize offset
+}
+
+@extension("VK_NVX_device_generated_commands") // 87
+class VkIndirectCommandsLayoutTokenNVX {
+ VkIndirectCommandsTokenTypeNVX tokenType
+ u32 bindingUnit
+ u32 dynamicCount
+ u32 divisor
+}
+
+@extension("VK_NVX_device_generated_commands") // 87
+class VkIndirectCommandsLayoutCreateInfoNVX {
+ VkStructureType sType
+ const void* pNext
+ VkPipelineBindPoint pipelineBindPoint
+ VkIndirectCommandsLayoutUsageFlagsNVX flags
+ u32 tokenCount
+ const VkIndirectCommandsLayoutTokenNVX* pTokens
+}
+
+@extension("VK_NVX_device_generated_commands") // 87
+class VkCmdProcessCommandsInfoNVX {
+ VkStructureType sType
+ const void* pNext
+ VkObjectTableNVX objectTable
+ VkIndirectCommandsLayoutNVX indirectCommandsLayout
+ u32 indirectCommandsTokenCount
+ const VkIndirectCommandsTokenNVX* pIndirectCommandsTokens
+ u32 maxSequencesCount
+ VkCommandBuffer targetCommandBuffer
+ VkBuffer sequencesCountBuffer
+ VkDeviceSize sequencesCountOffset
+ VkBuffer sequencesIndexBuffer
+ VkDeviceSize sequencesIndexOffset
+}
+
+@extension("VK_NVX_device_generated_commands") // 87
+class VkCmdReserveSpaceForCommandsInfoNVX {
+ VkStructureType sType
+ const void* pNext
+ VkObjectTableNVX objectTable
+ VkIndirectCommandsLayoutNVX indirectCommandsLayout
+ u32 maxSequencesCount
+}
+
+@extension("VK_NVX_device_generated_commands") // 87
+class VkObjectTableCreateInfoNVX {
+ VkStructureType sType
+ const void* pNext
+ u32 objectCount
+ const VkObjectEntryTypeNVX* pObjectEntryTypes
+ const u32* pObjectEntryCounts
+ const VkObjectEntryUsageFlagsNVX* pObjectEntryUsageFlags
+ u32 maxUniformBuffersPerDescriptor
+ u32 maxStorageBuffersPerDescriptor
+ u32 maxStorageImagesPerDescriptor
+ u32 maxSampledImagesPerDescriptor
+ u32 maxPipelineLayouts
+}
+
+@extension("VK_NVX_device_generated_commands") // 87
+class VkObjectTableEntryNVX {
+ VkObjectEntryTypeNVX type
+ VkObjectEntryUsageFlagsNVX flags
+}
+
+@extension("VK_NVX_device_generated_commands") // 87
+class VkObjectTablePipelineEntryNVX {
+ VkObjectEntryTypeNVX type
+ VkObjectEntryUsageFlagsNVX flags
+ VkPipeline pipeline
+}
+
+@extension("VK_NVX_device_generated_commands") // 87
+class VkObjectTableDescriptorSetEntryNVX {
+ VkObjectEntryTypeNVX type
+ VkObjectEntryUsageFlagsNVX flags
+ VkPipelineLayout pipelineLayout
+ VkDescriptorSet descriptorSet
+}
+
+@extension("VK_NVX_device_generated_commands") // 87
+class VkObjectTableVertexBufferEntryNVX {
+ VkObjectEntryTypeNVX type
+ VkObjectEntryUsageFlagsNVX flags
+ VkBuffer buffer
+}
+
+@extension("VK_NVX_device_generated_commands") // 87
+class VkObjectTableIndexBufferEntryNVX {
+ VkObjectEntryTypeNVX type
+ VkObjectEntryUsageFlagsNVX flags
+ VkBuffer buffer
+ VkIndexType indexType
+}
+
+@extension("VK_NVX_device_generated_commands") // 87
+class VkObjectTablePushConstantEntryNVX {
+ VkObjectEntryTypeNVX type
+ VkObjectEntryUsageFlagsNVX flags
+ VkPipelineLayout pipelineLayout
+ VkShaderStageFlags stageFlags
+}
+
+@extension("VK_NV_clip_space_w_scaling") // 88
+class VkViewportWScalingNV {
+ f32 xcoeff
+ f32 ycoeff
+}
+
+@extension("VK_NV_clip_space_w_scaling") // 88
+class VkPipelineViewportWScalingStateCreateInfoNV {
+ VkStructureType sType
+ const void* pNext
+ VkBool32 viewportWScalingEnable
+ u32 viewportCount
+ const VkViewportWScalingNV* pViewportWScalings
+}
+
+@extension("VK_EXT_display_surface_counter") // 91
+class VkSurfaceCapabilities2EXT {
+ VkStructureType sType
+ void* pNext
+ u32 minImageCount
+ u32 maxImageCount
+ VkExtent2D currentExtent
+ VkExtent2D minImageExtent
+ VkExtent2D maxImageExtent
+ u32 maxImageArrayLayers
+ VkSurfaceTransformFlagsKHR supportedTransforms
+ VkSurfaceTransformFlagBitsKHR currentTransform
+ VkCompositeAlphaFlagsKHR supportedCompositeAlpha
+ VkImageUsageFlags supportedUsageFlags
+ VkSurfaceCounterFlagsEXT supportedSurfaceCounters
+}
+
+@extension("VK_EXT_display_control") // 92
+class VkDisplayPowerInfoEXT {
+ VkStructureType sType
+ const void* pNext
+ VkDisplayPowerStateEXT powerState
+}
+
+@extension("VK_EXT_display_control") // 92
+class VkDeviceEventInfoEXT {
+ VkStructureType sType
+ const void* pNext
+ VkDeviceEventTypeEXT deviceEvent
+}
+
+@extension("VK_EXT_display_control") // 92
+class VkDisplayEventInfoEXT {
+ VkStructureType sType
+ const void* pNext
+ VkDisplayEventTypeEXT displayEvent
+}
+
+@extension("VK_EXT_display_control") // 92
+class VkSwapchainCounterCreateInfoEXT {
+ VkStructureType sType
+ const void* pNext
+ VkSurfaceCounterFlagsEXT surfaceCounters
+}
+
+@extension("VK_GOOGLE_display_timing") // 93
+class VkRefreshCycleDurationGOOGLE {
+ u64 refreshDuration
+}
+
+@extension("VK_GOOGLE_display_timing") // 93
+class VkPastPresentationTimingGOOGLE {
+ u32 presentID
+ u64 desiredPresentTime
+ u64 actualPresentTime
+ u64 earliestPresentTime
+ u64 presentMargin
+}
+
+@extension("VK_GOOGLE_display_timing") // 93
+class VkPresentTimeGOOGLE {
+ u32 presentID
+ u64 desiredPresentTime
+}
+
+@extension("VK_GOOGLE_display_timing") // 93
+class VkPresentTimesInfoGOOGLE {
+ VkStructureType sType
+ const void* pNext
+ u32 swapchainCount
+ const VkPresentTimeGOOGLE* pTimes
+}
+
+@extension("VK_NVX_multiview_per_view_attributes") // 98
+class VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX {
+ VkStructureType sType
+ void* pNext
+ VkBool32 perViewPositionAllComponents
+}
+
+@extension("VK_NV_viewport_swizzle") // 99
+class VkViewportSwizzleNV {
+ VkViewportCoordinateSwizzleNV x
+ VkViewportCoordinateSwizzleNV y
+ VkViewportCoordinateSwizzleNV z
+ VkViewportCoordinateSwizzleNV w
+}
+
+@extension("VK_NV_viewport_swizzle") // 99
+class VkPipelineViewportSwizzleStateCreateInfoNV {
+ VkStructureType sType
+ const void* pNext
+ VkPipelineViewportSwizzleStateCreateFlagsNV flags
+ u32 viewportCount
+ const VkViewportSwizzleNV* pViewportSwizzles
+}
+
+@extension("VK_EXT_discard_rectangles") // 100
+class VkPhysicalDeviceDiscardRectanglePropertiesEXT {
+ VkStructureType sType
+ void* pNext
+ u32 maxDiscardRectangles
+}
+
+@extension("VK_EXT_discard_rectangles") // 100
+class VkPipelineDiscardRectangleStateCreateInfoEXT {
+ VkStructureType sType
+ const void* pNext
+ VkPipelineDiscardRectangleStateCreateFlagsEXT flags
+ VkDiscardRectangleModeEXT discardRectangleMode
+ u32 discardRectangleCount
+ const VkRect2D* pDiscardRectangles
+}
+
+@extension("VK_EXT_hdr_metadata") // 106
+class VkXYColorEXT {
+ f32 x
+ f32 y
+}
+
+@extension("VK_EXT_hdr_metadata") // 106
+class VkHdrMetadataEXT {
+ VkStructureType sType
+ const void* pNext
+ VkXYColorEXT displayPrimaryRed
+ VkXYColorEXT displayPrimaryGreen
+ VkXYColorEXT displayPrimaryBlue
+ VkXYColorEXT whitePoint
+ f32 maxLuminance
+ f32 minLuminance
+ f32 maxContentLightLevel
+ f32 maxFrameAverageLightLevel
+}
+
+@extension("VK_MVK_ios_surface") // 123
+class VkIOSSurfaceCreateInfoMVK {
+ VkStructureType sType
+ const void* pNext
+ VkIOSSurfaceCreateFlagsMVK flags
+ const void* pView
+}
+
+@extension("VK_MVK_macos_surface") // 124
+class VkMacOSSurfaceCreateInfoMVK {
+ VkStructureType sType
+ const void* pNext
+ VkMacOSSurfaceCreateFlagsMVK flags
+ const void* pView
+}
////////////////
// Commands //
@@ -4415,9 +5945,9 @@
@threadSafety("app")
cmd void vkCmdDispatch(
VkCommandBuffer commandBuffer,
- u32 x,
- u32 y,
- u32 z) {
+ u32 groupCountX,
+ u32 groupCountY,
+ u32 groupCountZ) {
commandBufferObject := GetCommandBuffer(commandBuffer)
commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_COMPUTE_BIT)
@@ -4570,7 +6100,7 @@
VkBuffer dstBuffer,
VkDeviceSize dstOffset,
VkDeviceSize dataSize,
- const u32* pData) {
+ const void* pData) {
commandBufferObject := GetCommandBuffer(commandBuffer)
dstBufferObject := GetBuffer(dstBuffer)
assert(commandBufferObject.device == dstBufferObject.device)
@@ -4889,7 +6419,7 @@
}
}
-@extension("VK_KHR_surface")
+@extension("VK_KHR_surface") // 1
cmd void vkDestroySurfaceKHR(
VkInstance instance,
VkSurfaceKHR surface,
@@ -4901,7 +6431,7 @@
State.Surfaces[surface] = null
}
-@extension("VK_KHR_surface")
+@extension("VK_KHR_surface") // 1
cmd VkResult vkGetPhysicalDeviceSurfaceSupportKHR(
VkPhysicalDevice physicalDevice,
u32 queueFamilyIndex,
@@ -4912,7 +6442,7 @@
return ?
}
-@extension("VK_KHR_surface")
+@extension("VK_KHR_surface") // 1
cmd VkResult vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
VkPhysicalDevice physicalDevice,
VkSurfaceKHR surface,
@@ -4925,7 +6455,7 @@
return ?
}
-@extension("VK_KHR_surface")
+@extension("VK_KHR_surface") // 1
cmd VkResult vkGetPhysicalDeviceSurfaceFormatsKHR(
VkPhysicalDevice physicalDevice,
VkSurfaceKHR surface,
@@ -4945,7 +6475,7 @@
return ?
}
-@extension("VK_KHR_surface")
+@extension("VK_KHR_surface") // 1
cmd VkResult vkGetPhysicalDeviceSurfacePresentModesKHR(
VkPhysicalDevice physicalDevice,
VkSurfaceKHR surface,
@@ -4965,7 +6495,7 @@
return ?
}
-@extension("VK_KHR_swapchain")
+@extension("VK_KHR_swapchain") // 2
cmd VkResult vkCreateSwapchainKHR(
VkDevice device,
const VkSwapchainCreateInfoKHR* pCreateInfo,
@@ -4981,7 +6511,7 @@
return ?
}
-@extension("VK_KHR_swapchain")
+@extension("VK_KHR_swapchain") // 2
cmd void vkDestroySwapchainKHR(
VkDevice device,
VkSwapchainKHR swapchain,
@@ -4993,7 +6523,7 @@
State.Swapchains[swapchain] = null
}
-@extension("VK_KHR_swapchain")
+@extension("VK_KHR_swapchain") // 2
cmd VkResult vkGetSwapchainImagesKHR(
VkDevice device,
VkSwapchainKHR swapchain,
@@ -5014,7 +6544,7 @@
return ?
}
-@extension("VK_KHR_swapchain")
+@extension("VK_KHR_swapchain") // 2
cmd VkResult vkAcquireNextImageKHR(
VkDevice device,
VkSwapchainKHR swapchain,
@@ -5031,7 +6561,7 @@
return ?
}
-@extension("VK_KHR_swapchain")
+@extension("VK_KHR_swapchain") // 2
cmd VkResult vkQueuePresentKHR(
VkQueue queue,
const VkPresentInfoKHR* pPresentInfo) {
@@ -5043,7 +6573,7 @@
return ?
}
-@extension("VK_KHR_display")
+@extension("VK_KHR_display") // 3
cmd VkResult vkGetPhysicalDeviceDisplayPropertiesKHR(
VkPhysicalDevice physicalDevice,
u32* pPropertyCount,
@@ -5052,7 +6582,7 @@
return ?
}
-@extension("VK_KHR_display")
+@extension("VK_KHR_display") // 3
cmd VkResult vkGetPhysicalDeviceDisplayPlanePropertiesKHR(
VkPhysicalDevice physicalDevice,
u32* pPropertyCount,
@@ -5061,7 +6591,7 @@
return ?
}
-@extension("VK_KHR_display")
+@extension("VK_KHR_display") // 3
cmd VkResult vkGetDisplayPlaneSupportedDisplaysKHR(
VkPhysicalDevice physicalDevice,
u32 planeIndex,
@@ -5071,7 +6601,7 @@
return ?
}
-@extension("VK_KHR_display")
+@extension("VK_KHR_display") // 3
cmd VkResult vkGetDisplayModePropertiesKHR(
VkPhysicalDevice physicalDevice,
VkDisplayKHR display,
@@ -5081,7 +6611,7 @@
return ?
}
-@extension("VK_KHR_display")
+@extension("VK_KHR_display") // 3
cmd VkResult vkCreateDisplayModeKHR(
VkPhysicalDevice physicalDevice,
VkDisplayKHR display,
@@ -5092,7 +6622,7 @@
return ?
}
-@extension("VK_KHR_display")
+@extension("VK_KHR_display") // 3
cmd VkResult vkGetDisplayPlaneCapabilitiesKHR(
VkPhysicalDevice physicalDevice,
VkDisplayModeKHR mode,
@@ -5102,7 +6632,7 @@
return ?
}
-@extension("VK_KHR_display")
+@extension("VK_KHR_display") // 3
cmd VkResult vkCreateDisplayPlaneSurfaceKHR(
VkInstance instance,
const VkDisplaySurfaceCreateInfoKHR* pCreateInfo,
@@ -5111,7 +6641,7 @@
return ?
}
-@extension("VK_KHR_display_swapchain")
+@extension("VK_KHR_display_swapchain") // 4
cmd VkResult vkCreateSharedSwapchainsKHR(
VkDevice device,
u32 swapchainCount,
@@ -5121,7 +6651,7 @@
return ?
}
-@extension("VK_KHR_xlib_surface")
+@extension("VK_KHR_xlib_surface") // 5
cmd VkResult vkCreateXlibSurfaceKHR(
VkInstance instance,
const VkXlibSurfaceCreateInfoKHR* pCreateInfo,
@@ -5131,7 +6661,7 @@
return ?
}
-@extension("VK_KHR_xlib_surface")
+@extension("VK_KHR_xlib_surface") // 5
cmd VkBool32 vkGetPhysicalDeviceXlibPresentationSupportKHR(
VkPhysicalDevice physicalDevice,
u32 queueFamilyIndex,
@@ -5141,7 +6671,7 @@
return ?
}
-@extension("VK_KHR_xcb_surface")
+@extension("VK_KHR_xcb_surface") // 6
cmd VkResult vkCreateXcbSurfaceKHR(
VkInstance instance,
const VkXcbSurfaceCreateInfoKHR* pCreateInfo,
@@ -5151,7 +6681,7 @@
return ?
}
-@extension("VK_KHR_xcb_surface")
+@extension("VK_KHR_xcb_surface") // 6
cmd VkBool32 vkGetPhysicalDeviceXcbPresentationSupportKHR(
VkPhysicalDevice physicalDevice,
u32 queueFamilyIndex,
@@ -5161,7 +6691,7 @@
return ?
}
-@extension("VK_KHR_wayland_surface")
+@extension("VK_KHR_wayland_surface") // 7
cmd VkResult vkCreateWaylandSurfaceKHR(
VkInstance instance,
const VkWaylandSurfaceCreateInfoKHR* pCreateInfo,
@@ -5171,7 +6701,7 @@
return ?
}
-@extension("VK_KHR_wayland_surface")
+@extension("VK_KHR_wayland_surface") // 7
cmd VkBool32 vkGetPhysicalDeviceWaylandPresentationSupportKHR(
VkPhysicalDevice physicalDevice,
u32 queueFamilyIndex,
@@ -5180,7 +6710,7 @@
return ?
}
-@extension("VK_KHR_mir_surface")
+@extension("VK_KHR_mir_surface") // 8
cmd VkResult vkCreateMirSurfaceKHR(
VkInstance instance,
const VkMirSurfaceCreateInfoKHR* pCreateInfo,
@@ -5190,7 +6720,7 @@
return ?
}
-@extension("VK_KHR_mir_surface")
+@extension("VK_KHR_mir_surface") // 8
cmd VkBool32 vkGetPhysicalDeviceMirPresentationSupportKHR(
VkPhysicalDevice physicalDevice,
u32 queueFamilyIndex,
@@ -5199,7 +6729,7 @@
return ?
}
-@extension("VK_KHR_android_surface")
+@extension("VK_KHR_android_surface") // 9
cmd VkResult vkCreateAndroidSurfaceKHR(
VkInstance instance,
const VkAndroidSurfaceCreateInfoKHR* pCreateInfo,
@@ -5209,7 +6739,7 @@
return ?
}
-@extension("VK_KHR_win32_surface")
+@extension("VK_KHR_win32_surface") // 10
cmd VkResult vkCreateWin32SurfaceKHR(
VkInstance instance,
const VkWin32SurfaceCreateInfoKHR* pCreateInfo,
@@ -5219,7 +6749,7 @@
return ?
}
-@extension("VK_KHR_win32_surface")
+@extension("VK_KHR_win32_surface") // 10
cmd VkResult vkGetPhysicalDeviceWin32PresentationSupportKHR(
VkPhysicalDevice physicalDevice,
u32 queueFamilyIndex) {
@@ -5227,7 +6757,7 @@
return ?
}
-@extension("VK_ANDROID_native_buffer")
+@extension("VK_ANDROID_native_buffer") // 11
cmd VkResult vkGetSwapchainGrallocUsageANDROID(
VkDevice device,
VkFormat format,
@@ -5236,7 +6766,7 @@
return ?
}
-@extension("VK_ANDROID_native_buffer")
+@extension("VK_ANDROID_native_buffer") // 11
cmd VkResult vkAcquireImageANDROID(
VkDevice device,
VkImage image,
@@ -5246,7 +6776,7 @@
return ?
}
-@extension("VK_ANDROID_native_buffer")
+@extension("VK_ANDROID_native_buffer") // 11
cmd VkResult vkQueueSignalReleaseImageANDROID(
VkQueue queue,
u32 waitSemaphoreCount,
@@ -5256,9 +6786,9 @@
return ?
}
-@extension("VK_EXT_debug_report")
+@extension("VK_EXT_debug_report") // 12
@external type void* PFN_vkDebugReportCallbackEXT
-@extension("VK_EXT_debug_report")
+@extension("VK_EXT_debug_report") // 12
@pfn cmd VkBool32 vkDebugReportCallbackEXT(
VkDebugReportFlagsEXT flags,
VkDebugReportObjectTypeEXT objectType,
@@ -5271,7 +6801,7 @@
return ?
}
-@extension("VK_EXT_debug_report")
+@extension("VK_EXT_debug_report") // 12
cmd VkResult vkCreateDebugReportCallbackEXT(
VkInstance instance,
const VkDebugReportCallbackCreateInfoEXT* pCreateInfo,
@@ -5280,14 +6810,14 @@
return ?
}
-@extension("VK_EXT_debug_report")
+@extension("VK_EXT_debug_report") // 12
cmd void vkDestroyDebugReportCallbackEXT(
VkInstance instance,
VkDebugReportCallbackEXT callback,
const VkAllocationCallbacks* pAllocator) {
}
-@extension("VK_EXT_debug_report")
+@extension("VK_EXT_debug_report") // 12
cmd void vkDebugReportMessageEXT(
VkInstance instance,
VkDebugReportFlagsEXT flags,
@@ -5299,37 +6829,549 @@
const char* pMessage) {
}
-@extension("VK_EXT_debug_marker")
+@extension("VK_EXT_debug_marker") // 23
cmd VkResult vkDebugMarkerSetObjectTagEXT(
VkDevice device,
VkDebugMarkerObjectTagInfoEXT* pTagInfo) {
return ?
}
-@extension("VK_EXT_debug_marker")
+@extension("VK_EXT_debug_marker") // 23
cmd VkResult vkDebugMarkerSetObjectNameEXT(
VkDevice device,
VkDebugMarkerObjectNameInfoEXT* pNameInfo) {
return ?
}
-@extension("VK_EXT_debug_marker")
+@extension("VK_EXT_debug_marker") // 23
cmd void vkCmdDebugMarkerBeginEXT(
VkCommandBuffer commandBuffer,
VkDebugMarkerMarkerInfoEXT* pMarkerInfo) {
}
-@extension("VK_EXT_debug_marker")
+@extension("VK_EXT_debug_marker") // 23
cmd void vkCmdDebugMarkerEndEXT(
VkCommandBuffer commandBuffer) {
}
-@extension("VK_EXT_debug_marker")
+@extension("VK_EXT_debug_marker") // 23
cmd void vkCmdDebugMarkerInsertEXT(
VkCommandBuffer commandBuffer,
VkDebugMarkerMarkerInfoEXT* pMarkerInfo) {
}
+@extension("VK_AMD_draw_indirect_count") // 34
+cmd void vkCmdDrawIndirectCountAMD(
+ VkCommandBuffer commandBuffer,
+ VkBuffer buffer,
+ VkDeviceSize offset,
+ VkBuffer countBuffer,
+ VkDeviceSize countBufferOffset,
+ u32 maxDrawCount,
+ u32 stride) {
+}
+
+@extension("VK_AMD_draw_indirect_count") // 34
+cmd void vkCmdDrawIndexedIndirectCountAMD(
+ VkCommandBuffer commandBuffer,
+ VkBuffer buffer,
+ VkDeviceSize offset,
+ VkBuffer countBuffer,
+ VkDeviceSize countBufferOffset,
+ u32 maxDrawCount,
+ u32 stride) {
+}
+
+@extension("VK_NV_external_memory_capabilities") // 56
+cmd VkResult vkGetPhysicalDeviceExternalImageFormatPropertiesNV(
+ VkPhysicalDevice physicalDevice,
+ VkFormat format,
+ VkImageType type,
+ VkImageTiling tiling,
+ VkImageUsageFlags usage,
+ VkImageCreateFlags flags,
+ VkExternalMemoryHandleTypeFlagsNV externalHandleType,
+ VkExternalImageFormatPropertiesNV* pExternalImageFormatProperties) {
+ return ?
+}
+
+@extension("VK_NV_external_memory_win32") // 58
+cmd VkResult vkGetMemoryWin32HandleNV(
+ VkDevice device,
+ VkDeviceMemory memory,
+ VkExternalMemoryHandleTypeFlagsNV handleType,
+ platform.HANDLE* pHandle) {
+ return ?
+}
+
+@extension("VK_KHR_get_physical_device_properties2") // 60
+cmd void vkGetPhysicalDeviceFeatures2KHR(
+ VkPhysicalDevice physicalDevice,
+ VkPhysicalDeviceFeatures2KHR* pFeatures) {
+}
+
+@extension("VK_KHR_get_physical_device_properties2") // 60
+cmd void vkGetPhysicalDeviceProperties2KHR(
+ VkPhysicalDevice physicalDevice,
+ VkPhysicalDeviceProperties2KHR* pProperties) {
+}
+
+@extension("VK_KHR_get_physical_device_properties2") // 60
+cmd void vkGetPhysicalDeviceFormatProperties2KHR(
+ VkPhysicalDevice physicalDevice,
+ VkFormat format,
+ VkFormatProperties2KHR* pFormatProperties) {
+}
+
+@extension("VK_KHR_get_physical_device_properties2") // 60
+cmd VkResult vkGetPhysicalDeviceImageFormatProperties2KHR(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceImageFormatInfo2KHR* pImageFormatInfo,
+ VkImageFormatProperties2KHR* pImageFormatProperties) {
+ return ?
+}
+
+@extension("VK_KHR_get_physical_device_properties2") // 60
+cmd void vkGetPhysicalDeviceQueueFamilyProperties2KHR(
+ VkPhysicalDevice physicalDevice,
+ u32* pQueueFamilyPropertyCount,
+ VkQueueFamilyProperties2KHR* pQueueFamilyProperties) {
+}
+
+@extension("VK_KHR_get_physical_device_properties2") // 60
+cmd void vkGetPhysicalDeviceMemoryProperties2KHR(
+ VkPhysicalDevice physicalDevice,
+ VkPhysicalDeviceMemoryProperties2KHR* pMemoryProperties) {
+}
+
+@extension("VK_KHR_get_physical_device_properties2") // 60
+cmd void vkGetPhysicalDeviceSparseImageFormatProperties2KHR(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceSparseImageFormatInfo2KHR* pFormatInfo,
+ u32* pPropertyCount,
+ VkSparseImageFormatProperties2KHR* pProperties) {
+}
+
+@extension("VK_KHX_device_group") // 61
+cmd void vkGetDeviceGroupPeerMemoryFeaturesKHX(
+ VkDevice device,
+ u32 heapIndex,
+ u32 localDeviceIndex,
+ u32 remoteDeviceIndex,
+ VkPeerMemoryFeatureFlagsKHX* pPeerMemoryFeatures) {
+}
+
+@extension("VK_KHX_device_group") // 61
+cmd VkResult vkBindBufferMemory2KHX(
+ VkDevice device,
+ u32 bindInfoCount,
+ const VkBindBufferMemoryInfoKHX* pBindInfos) {
+ return ?
+}
+
+@extension("VK_KHX_device_group") // 61
+cmd VkResult vkBindImageMemory2KHX(
+ VkDevice device,
+ u32 bindInfoCount,
+ const VkBindImageMemoryInfoKHX* pBindInfos) {
+ return ?
+}
+
+@extension("VK_KHX_device_group") // 61
+cmd void vkCmdSetDeviceMaskKHX(
+ VkCommandBuffer commandBuffer,
+ u32 deviceMask) {
+}
+
+@extension("VK_KHX_device_group") // 61
+cmd VkResult vkGetDeviceGroupPresentCapabilitiesKHX(
+ VkDevice device,
+ VkDeviceGroupPresentCapabilitiesKHX* pDeviceGroupPresentCapabilities) {
+ return ?
+}
+
+@extension("VK_KHX_device_group") // 61
+cmd VkResult vkGetDeviceGroupSurfacePresentModesKHX(
+ VkDevice device,
+ VkSurfaceKHR surface,
+ VkDeviceGroupPresentModeFlagsKHX* pModes) {
+ return ?
+}
+
+@extension("VK_KHX_device_group") // 61
+cmd VkResult vkAcquireNextImage2KHX(
+ VkDevice device,
+ const VkAcquireNextImageInfoKHX* pAcquireInfo,
+ u32* pImageIndex) {
+ return ?
+}
+
+@extension("VK_KHX_device_group") // 61
+cmd void vkCmdDispatchBaseKHX(
+ VkCommandBuffer commandBuffer,
+ u32 baseGroupX,
+ u32 baseGroupY,
+ u32 baseGroupZ,
+ u32 groupCountX,
+ u32 groupCountY,
+ u32 groupCountZ) {
+}
+
+@extension("VK_KHX_device_group") // 61
+cmd VkResult vkGetPhysicalDevicePresentRectanglesKHX(
+ VkPhysicalDevice physicalDevice,
+ VkSurfaceKHR surface,
+ u32* pRectCount,
+ VkRect2D* pRects) {
+ return ?
+}
+
+@extension("VK_NN_vi_surface") // 63
+cmd VkResult vkCreateViSurfaceNN(
+ VkInstance instance,
+ const VkViSurfaceCreateInfoNN* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkSurfaceKHR* pSurface) {
+ return ?
+}
+
+@extension("VK_KHR_maintenance1") // 70
+cmd void vkTrimCommandPoolKHR(
+ VkDevice device,
+ VkCommandPool commandPool,
+ VkCommandPoolTrimFlagsKHR flags) {
+}
+
+@extension("VK_KHX_device_group_creation") // 71
+cmd VkResult vkEnumeratePhysicalDeviceGroupsKHX(
+ VkInstance instance,
+ u32* pPhysicalDeviceGroupCount,
+ VkPhysicalDeviceGroupPropertiesKHX* pPhysicalDeviceGroupProperties) {
+ return ?
+}
+
+@extension("VK_KHX_external_memory_capabilities") // 72
+cmd void vkGetPhysicalDeviceExternalBufferPropertiesKHX(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceExternalBufferInfoKHX* pExternalBufferInfo,
+ VkExternalBufferPropertiesKHX* pExternalBufferProperties) {
+}
+
+@extension("VK_KHX_external_memory_win32") // 74
+cmd VkResult vkGetMemoryWin32HandleKHX(
+ VkDevice device,
+ VkDeviceMemory memory,
+ VkExternalMemoryHandleTypeFlagBitsKHX handleType,
+ platform.HANDLE* pHandle) {
+ return ?
+}
+
+@extension("VK_KHX_external_memory_win32") // 74
+cmd VkResult vkGetMemoryWin32HandlePropertiesKHX(
+ VkDevice device,
+ VkExternalMemoryHandleTypeFlagBitsKHX handleType,
+ platform.HANDLE handle,
+ VkMemoryWin32HandlePropertiesKHX* pMemoryWin32HandleProperties) {
+ return ?
+}
+
+@extension("VK_KHX_external_memory_fd") // 75
+cmd VkResult vkGetMemoryFdKHX(
+ VkDevice device,
+ VkDeviceMemory memory,
+ VkExternalMemoryHandleTypeFlagBitsKHX handleType,
+ s32* pFd) {
+ return ?
+}
+
+@extension("VK_KHX_external_memory_fd") // 75
+cmd VkResult vkGetMemoryFdPropertiesKHX(
+ VkDevice device,
+ VkExternalMemoryHandleTypeFlagBitsKHX handleType,
+ s32 fd,
+ VkMemoryFdPropertiesKHX* pMemoryFdProperties) {
+ return ?
+}
+
+@extension("VK_KHX_external_semaphore_capabilities") // 77
+cmd void vkGetPhysicalDeviceExternalSemaphorePropertiesKHX(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceExternalSemaphoreInfoKHX* pExternalSemaphoreInfo,
+ VkExternalSemaphorePropertiesKHX* pExternalSemaphoreProperties) {
+}
+
+@extension("VK_KHX_external_semaphore_win32") // 79
+cmd VkResult vkImportSemaphoreWin32HandleKHX(
+ VkDevice device,
+ const VkImportSemaphoreWin32HandleInfoKHX* pImportSemaphoreWin32HandleInfo) {
+ return ?
+}
+
+@extension("VK_KHX_external_semaphore_win32") // 79
+cmd VkResult vkGetSemaphoreWin32HandleKHX(
+ VkDevice device,
+ VkSemaphore semaphore,
+ VkExternalSemaphoreHandleTypeFlagBitsKHX handleType,
+ platform.HANDLE* pHandle) {
+ return ?
+}
+
+@extension("VK_KHX_external_semaphore_fd") // 80
+cmd VkResult vkImportSemaphoreFdKHX(
+ VkDevice device,
+ const VkImportSemaphoreFdInfoKHX* pImportSemaphoreFdInfo) {
+ return ?
+}
+
+@extension("VK_KHX_external_semaphore_fd") // 80
+cmd VkResult vkGetSemaphoreFdKHX(
+ VkDevice device,
+ VkSemaphore semaphore,
+ VkExternalSemaphoreHandleTypeFlagBitsKHX handleType,
+ s32* pFd) {
+ return ?
+}
+
+@extension("VK_KHR_push_descriptor") // 81
+cmd void vkCmdPushDescriptorSetKHR(
+ VkCommandBuffer commandBuffer,
+ VkPipelineBindPoint pipelineBindPoint,
+ VkPipelineLayout layout,
+ u32 set,
+ u32 descriptorWriteCount,
+ const VkWriteDescriptorSet* pDescriptorWrites) {
+}
+
+@extension("VK_KHR_descriptor_update_template") // 86
+cmd VkResult vkCreateDescriptorUpdateTemplateKHR(
+ VkDevice device,
+ const VkDescriptorUpdateTemplateCreateInfoKHR* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkDescriptorUpdateTemplateKHR* pDescriptorUpdateTemplate) {
+ return ?
+}
+
+@extension("VK_KHR_descriptor_update_template") // 86
+cmd void vkDestroyDescriptorUpdateTemplateKHR(
+ VkDevice device,
+ VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+ const VkAllocationCallbacks* pAllocator) {
+}
+
+@extension("VK_KHR_descriptor_update_template") // 86
+cmd void vkUpdateDescriptorSetWithTemplateKHR(
+ VkDevice device,
+ VkDescriptorSet descriptorSet,
+ VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+ const void* pData) {
+}
+
+@extension("VK_KHR_descriptor_update_template") // 86
+cmd void vkCmdPushDescriptorSetWithTemplateKHR(
+ VkCommandBuffer commandBuffer,
+ VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+ VkPipelineLayout layout,
+ u32 set,
+ const void* pData) {
+}
+
+@extension("VK_NVX_device_generated_commands") // 87
+cmd void vkCmdProcessCommandsNVX(
+ VkCommandBuffer commandBuffer,
+ const VkCmdProcessCommandsInfoNVX* pProcessCommandsInfo) {
+}
+
+@extension("VK_NVX_device_generated_commands") // 87
+cmd void vkCmdReserveSpaceForCommandsNVX(
+ VkCommandBuffer commandBuffer,
+ const VkCmdReserveSpaceForCommandsInfoNVX* pReserveSpaceInfo) {
+}
+
+@extension("VK_NVX_device_generated_commands") // 87
+cmd VkResult vkCreateIndirectCommandsLayoutNVX(
+ VkDevice device,
+ const VkIndirectCommandsLayoutCreateInfoNVX* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkIndirectCommandsLayoutNVX* pIndirectCommandsLayout) {
+ return ?
+}
+
+@extension("VK_NVX_device_generated_commands") // 87
+cmd void vkDestroyIndirectCommandsLayoutNVX(
+ VkDevice device,
+ VkIndirectCommandsLayoutNVX indirectCommandsLayout,
+ const VkAllocationCallbacks* pAllocator) {
+}
+
+@extension("VK_NVX_device_generated_commands") // 87
+cmd VkResult vkCreateObjectTableNVX(
+ VkDevice device,
+ const VkObjectTableCreateInfoNVX* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkObjectTableNVX* pObjectTable) {
+ return ?
+}
+
+@extension("VK_NVX_device_generated_commands") // 87
+cmd void vkDestroyObjectTableNVX(
+ VkDevice device,
+ VkObjectTableNVX objectTable,
+ const VkAllocationCallbacks* pAllocator) {
+}
+
+@extension("VK_NVX_device_generated_commands") // 87
+cmd VkResult vkRegisterObjectsNVX(
+ VkDevice device,
+ VkObjectTableNVX objectTable,
+ u32 objectCount,
+ const VkObjectTableEntryNVX* const* ppObjectTableEntries,
+ const u32* pObjectIndices) {
+ return ?
+}
+
+@extension("VK_NVX_device_generated_commands") // 87
+cmd VkResult vkUnregisterObjectsNVX(
+ VkDevice device,
+ VkObjectTableNVX objectTable,
+ u32 objectCount,
+ const VkObjectEntryTypeNVX* pObjectEntryTypes,
+ const u32* pObjectIndices) {
+ return ?
+}
+
+@extension("VK_NVX_device_generated_commands") // 87
+cmd void vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX(
+ VkPhysicalDevice physicalDevice,
+ VkDeviceGeneratedCommandsFeaturesNVX* pFeatures,
+ VkDeviceGeneratedCommandsLimitsNVX* pLimits) {
+}
+
+@extension("VK_NV_clip_space_w_scaling") // 88
+cmd void vkCmdSetViewportWScalingNV(
+ VkCommandBuffer commandBuffer,
+ u32 firstViewport,
+ u32 viewportCount,
+ const VkViewportWScalingNV* pViewportWScalings) {
+}
+
+@extension("VK_EXT_direct_mode_display") // 89
+cmd VkResult vkReleaseDisplayEXT(
+ VkPhysicalDevice physicalDevice,
+ VkDisplayKHR display) {
+ return ?
+}
+
+@extension("VK_EXT_acquire_xlib_display") // 90
+cmd VkResult vkAcquireXlibDisplayEXT(
+ VkPhysicalDevice physicalDevice,
+ platform.Display* dpy,
+ VkDisplayKHR display) {
+ return ?
+}
+
+@extension("VK_EXT_acquire_xlib_display") // 90
+cmd VkResult vkGetRandROutputDisplayEXT(
+ VkPhysicalDevice physicalDevice,
+ platform.Display* dpy,
+ platform.RROutput rrOutput,
+ VkDisplayKHR* pDisplay) {
+ return ?
+}
+
+@extension("VK_EXT_display_surface_counter") // 91
+cmd VkResult vkGetPhysicalDeviceSurfaceCapabilities2EXT(
+ VkPhysicalDevice physicalDevice,
+ VkSurfaceKHR surface,
+ VkSurfaceCapabilities2EXT* pSurfaceCapabilities) {
+ return ?
+}
+
+@extension("VK_EXT_display_control") // 92
+cmd VkResult vkDisplayPowerControlEXT(
+ VkDevice device,
+ VkDisplayKHR display,
+ const VkDisplayPowerInfoEXT* pDisplayPowerInfo) {
+ return ?
+}
+
+@extension("VK_EXT_display_control") // 92
+cmd VkResult vkRegisterDeviceEventEXT(
+ VkDevice device,
+ const VkDeviceEventInfoEXT* pDeviceEventInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkFence* pFence) {
+ return ?
+}
+
+@extension("VK_EXT_display_control") // 92
+cmd VkResult vkRegisterDisplayEventEXT(
+ VkDevice device,
+ VkDisplayKHR display,
+ const VkDisplayEventInfoEXT* pDisplayEventInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkFence* pFence) {
+ return ?
+}
+
+@extension("VK_EXT_display_control") // 92
+cmd VkResult vkGetSwapchainCounterEXT(
+ VkDevice device,
+ VkSwapchainKHR swapchain,
+ VkSurfaceCounterFlagBitsEXT counter,
+ u64* pCounterValue) {
+ return ?
+}
+
+@extension("VK_GOOGLE_display_timing") // 93
+cmd VkResult vkGetRefreshCycleDurationGOOGLE(
+ VkDevice device,
+ VkSwapchainKHR swapchain,
+ VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties) {
+ return ?
+}
+
+@extension("VK_GOOGLE_display_timing") // 93
+cmd VkResult vkGetPastPresentationTimingGOOGLE(
+ VkDevice device,
+ VkSwapchainKHR swapchain,
+ u32* pPresentationTimingCount,
+ VkPastPresentationTimingGOOGLE* pPresentationTimings) {
+ return ?
+}
+
+@extension("VK_EXT_discard_rectangles") // 100
+cmd void vkCmdSetDiscardRectangleEXT(
+ VkCommandBuffer commandBuffer,
+ u32 firstDiscardRectangle,
+ u32 discardRectangleCount,
+ const VkRect2D* pDiscardRectangles) {
+}
+
+@extension("VK_EXT_hdr_metadata") // 106
+cmd void vkSetHdrMetadataEXT(
+ VkDevice device,
+ u32 swapchainCount,
+ const VkSwapchainKHR* pSwapchains,
+ const VkHdrMetadataEXT* pMetadata) {
+}
+
+@extension("VK_MVK_ios_surface") // 123
+cmd VkResult vkCreateIOSSurfaceMVK(
+ VkInstance instance,
+ const VkIOSSurfaceCreateInfoMVK* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkSurfaceKHR* pSurface) {
+ return ?
+}
+
+@extension("VK_MVK_macos_surface") // 124
+cmd VkResult vkCreateMacOSSurfaceMVK(
+ VkInstance instance,
+ const VkMacOSSurfaceCreateInfoMVK* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkSurfaceKHR* pSurface) {
+ return ?
+}
////////////////
// Validation //
diff --git a/vulkan/include/vulkan/NOTICE b/vulkan/include/vulkan/NOTICE
new file mode 100644
index 0000000..c958fba
--- /dev/null
+++ b/vulkan/include/vulkan/NOTICE
@@ -0,0 +1,13 @@
+Copyright (c) 2015-2016 The Khronos Group Inc.
+
+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.
diff --git a/vulkan/include/vulkan/vk_platform.h b/vulkan/include/vulkan/vk_platform.h
index 5d0fc76..72f8049 100644
--- a/vulkan/include/vulkan/vk_platform.h
+++ b/vulkan/include/vulkan/vk_platform.h
@@ -2,7 +2,7 @@
// File: vk_platform.h
//
/*
-** Copyright (c) 2014-2015 The Khronos Group Inc.
+** Copyright (c) 2014-2017 The Khronos Group Inc.
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -51,13 +51,13 @@
#define VKAPI_ATTR
#define VKAPI_CALL __stdcall
#define VKAPI_PTR VKAPI_CALL
-#elif defined(__ANDROID__) && defined(__ARM_EABI__) && !defined(__ARM_ARCH_7A__)
- // Android does not support Vulkan in native code using the "armeabi" ABI.
- #error "Vulkan requires the 'armeabi-v7a' or 'armeabi-v7a-hard' ABI on 32-bit ARM CPUs"
-#elif defined(__ANDROID__) && defined(__ARM_ARCH_7A__)
- // On Android/ARMv7a, Vulkan functions use the armeabi-v7a-hard calling
- // convention, even if the application's native code is compiled with the
- // armeabi-v7a calling convention.
+#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH < 7
+ #error "Vulkan isn't supported for the 'armeabi' NDK ABI"
+#elif defined(__ANDROID__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7 && defined(__ARM_32BIT_STATE)
+ // On Android 32-bit ARM targets, Vulkan functions use the "hardfloat"
+ // calling convention, i.e. float parameters are passed in registers. This
+ // is true even if the rest of the application passes floats on the stack,
+ // as it does by default when compiling for the armeabi-v7a NDK ABI.
#define VKAPI_ATTR __attribute__((pcs("aapcs-vfp")))
#define VKAPI_CALL
#define VKAPI_PTR VKAPI_ATTR
diff --git a/vulkan/include/vulkan/vulkan.h b/vulkan/include/vulkan/vulkan.h
index 2f18076..ef0c246 100644
--- a/vulkan/include/vulkan/vulkan.h
+++ b/vulkan/include/vulkan/vulkan.h
@@ -6,7 +6,7 @@
#endif
/*
-** Copyright (c) 2015-2016 The Khronos Group Inc.
+** Copyright (c) 2015-2017 The Khronos Group Inc.
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -43,7 +43,7 @@
#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)
#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)
// Version of this file
-#define VK_HEADER_VERSION 13
+#define VK_HEADER_VERSION 46
#define VK_NULL_HANDLE 0
@@ -53,11 +53,13 @@
#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;
-#if defined(__LP64__) || defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
+#if !defined(VK_DEFINE_NON_DISPATCHABLE_HANDLE)
+#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object;
#else
#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object;
#endif
+#endif
@@ -135,6 +137,7 @@
VK_ERROR_INCOMPATIBLE_DRIVER = -9,
VK_ERROR_TOO_MANY_OBJECTS = -10,
VK_ERROR_FORMAT_NOT_SUPPORTED = -11,
+ VK_ERROR_FRAGMENTED_POOL = -12,
VK_ERROR_SURFACE_LOST_KHR = -1000000000,
VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = -1000000001,
VK_SUBOPTIMAL_KHR = 1000001003,
@@ -142,9 +145,11 @@
VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = -1000003001,
VK_ERROR_VALIDATION_FAILED_EXT = -1000011001,
VK_ERROR_INVALID_SHADER_NV = -1000012000,
- VK_RESULT_BEGIN_RANGE = VK_ERROR_FORMAT_NOT_SUPPORTED,
+ VK_ERROR_OUT_OF_POOL_MEMORY_KHR = -1000069000,
+ VK_ERROR_INVALID_EXTERNAL_HANDLE_KHX = -1000072003,
+ VK_RESULT_BEGIN_RANGE = VK_ERROR_FRAGMENTED_POOL,
VK_RESULT_END_RANGE = VK_INCOMPLETE,
- VK_RESULT_RANGE_SIZE = (VK_INCOMPLETE - VK_ERROR_FORMAT_NOT_SUPPORTED + 1),
+ VK_RESULT_RANGE_SIZE = (VK_INCOMPLETE - VK_ERROR_FRAGMENTED_POOL + 1),
VK_RESULT_MAX_ENUM = 0x7FFFFFFF
} VkResult;
@@ -214,6 +219,90 @@
VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT = 1000022000,
VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_TAG_INFO_EXT = 1000022001,
VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT = 1000022002,
+ VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000,
+ VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001,
+ VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002,
+ VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHX = 1000053000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHX = 1000053001,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHX = 1000053002,
+ VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000,
+ VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_NV = 1000056001,
+ VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057000,
+ VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057001,
+ VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV = 1000058000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR = 1000059000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR = 1000059001,
+ VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR = 1000059002,
+ VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059003,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR = 1000059004,
+ VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR = 1000059005,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR = 1000059006,
+ VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059007,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR = 1000059008,
+ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHX = 1000060000,
+ VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHX = 1000060001,
+ VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHX = 1000060002,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO_KHX = 1000060003,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO_KHX = 1000060004,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHX = 1000060005,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHX = 1000060006,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHX = 1000060007,
+ VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHX = 1000060008,
+ VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHX = 1000060009,
+ VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHX = 1000060010,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHX = 1000060011,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHX = 1000060012,
+ VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT = 1000061000,
+ VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN = 1000062000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHX = 1000070000,
+ VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHX = 1000070001,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHX = 1000071000,
+ VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHX = 1000071001,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHX = 1000071002,
+ VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHX = 1000071003,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHX = 1000071004,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHX = 1000071005,
+ VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHX = 1000071006,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHX = 1000071007,
+ VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHX = 1000072000,
+ VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHX = 1000072001,
+ VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHX = 1000072002,
+ VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHX = 1000073000,
+ VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHX = 1000073001,
+ VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHX = 1000073002,
+ VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHX = 1000074000,
+ VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHX = 1000074001,
+ VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHX = 1000075000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO_KHX = 1000076000,
+ VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES_KHX = 1000076001,
+ VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHX = 1000077000,
+ VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHX = 1000078000,
+ VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHX = 1000078001,
+ VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHX = 1000078002,
+ VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHX = 1000079000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR = 1000080000,
+ VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR = 1000084000,
+ VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR = 1000085000,
+ VK_STRUCTURE_TYPE_OBJECT_TABLE_CREATE_INFO_NVX = 1000086000,
+ VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NVX = 1000086001,
+ VK_STRUCTURE_TYPE_CMD_PROCESS_COMMANDS_INFO_NVX = 1000086002,
+ VK_STRUCTURE_TYPE_CMD_RESERVE_SPACE_FOR_COMMANDS_INFO_NVX = 1000086003,
+ VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_LIMITS_NVX = 1000086004,
+ VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_FEATURES_NVX = 1000086005,
+ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV = 1000087000,
+ VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES2_EXT = 1000090000,
+ VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT = 1000091000,
+ VK_STRUCTURE_TYPE_DEVICE_EVENT_INFO_EXT = 1000091001,
+ VK_STRUCTURE_TYPE_DISPLAY_EVENT_INFO_EXT = 1000091002,
+ VK_STRUCTURE_TYPE_SWAPCHAIN_COUNTER_CREATE_INFO_EXT = 1000091003,
+ VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE = 1000092000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_ATTRIBUTES_PROPERTIES_NVX = 1000097000,
+ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV = 1000098000,
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT = 1000099000,
+ VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT = 1000099001,
+ VK_STRUCTURE_TYPE_HDR_METADATA_EXT = 1000105000,
+ VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK = 1000122000,
+ VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000,
VK_STRUCTURE_TYPE_BEGIN_RANGE = VK_STRUCTURE_TYPE_APPLICATION_INFO,
VK_STRUCTURE_TYPE_END_RANGE = VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO,
VK_STRUCTURE_TYPE_RANGE_SIZE = (VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO - VK_STRUCTURE_TYPE_APPLICATION_INFO + 1),
@@ -426,6 +515,14 @@
VK_FORMAT_ASTC_12x10_SRGB_BLOCK = 182,
VK_FORMAT_ASTC_12x12_UNORM_BLOCK = 183,
VK_FORMAT_ASTC_12x12_SRGB_BLOCK = 184,
+ VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000,
+ VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001,
+ VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002,
+ VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG = 1000054003,
+ VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG = 1000054004,
+ VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG = 1000054005,
+ VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006,
+ VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007,
VK_FORMAT_BEGIN_RANGE = VK_FORMAT_UNDEFINED,
VK_FORMAT_END_RANGE = VK_FORMAT_ASTC_12x12_SRGB_BLOCK,
VK_FORMAT_RANGE_SIZE = (VK_FORMAT_ASTC_12x12_SRGB_BLOCK - VK_FORMAT_UNDEFINED + 1),
@@ -674,6 +771,8 @@
VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK = 6,
VK_DYNAMIC_STATE_STENCIL_WRITE_MASK = 7,
VK_DYNAMIC_STATE_STENCIL_REFERENCE = 8,
+ VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV = 1000087000,
+ VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT = 1000099000,
VK_DYNAMIC_STATE_BEGIN_RANGE = VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_END_RANGE = VK_DYNAMIC_STATE_STENCIL_REFERENCE,
VK_DYNAMIC_STATE_RANGE_SIZE = (VK_DYNAMIC_STATE_STENCIL_REFERENCE - VK_DYNAMIC_STATE_VIEWPORT + 1),
@@ -814,6 +913,8 @@
VK_FORMAT_FEATURE_BLIT_DST_BIT = 0x00000800,
VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 0x00001000,
VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = 0x00002000,
+ VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR = 0x00004000,
+ VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR = 0x00008000,
VK_FORMAT_FEATURE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkFormatFeatureFlagBits;
typedef VkFlags VkFormatFeatureFlags;
@@ -837,6 +938,8 @@
VK_IMAGE_CREATE_SPARSE_ALIASED_BIT = 0x00000004,
VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT = 0x00000008,
VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT = 0x00000010,
+ VK_IMAGE_CREATE_BIND_SFR_BIT_KHX = 0x00000040,
+ VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR = 0x00000020,
VK_IMAGE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkImageCreateFlagBits;
typedef VkFlags VkImageCreateFlags;
@@ -874,6 +977,7 @@
typedef enum VkMemoryHeapFlagBits {
VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 0x00000001,
+ VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHX = 0x00000002,
VK_MEMORY_HEAP_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkMemoryHeapFlagBits;
typedef VkFlags VkMemoryHeapFlags;
@@ -898,6 +1002,7 @@
VK_PIPELINE_STAGE_HOST_BIT = 0x00004000,
VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 0x00008000,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 0x00010000,
+ VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX = 0x00020000,
VK_PIPELINE_STAGE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkPipelineStageFlagBits;
typedef VkFlags VkPipelineStageFlags;
@@ -990,6 +1095,8 @@
VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT = 0x00000001,
VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 0x00000002,
VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004,
+ VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHX = 0x00000008,
+ VK_PIPELINE_CREATE_DISPATCH_BASE_KHX = 0x00000010,
VK_PIPELINE_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkPipelineCreateFlagBits;
typedef VkFlags VkPipelineCreateFlags;
@@ -1036,6 +1143,11 @@
typedef VkFlags VkPipelineLayoutCreateFlags;
typedef VkFlags VkShaderStageFlags;
typedef VkFlags VkSamplerCreateFlags;
+
+typedef enum VkDescriptorSetLayoutCreateFlagBits {
+ VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR = 0x00000001,
+ VK_DESCRIPTOR_SET_LAYOUT_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkDescriptorSetLayoutCreateFlagBits;
typedef VkFlags VkDescriptorSetLayoutCreateFlags;
typedef enum VkDescriptorPoolCreateFlagBits {
@@ -1052,6 +1164,12 @@
VK_ATTACHMENT_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkAttachmentDescriptionFlagBits;
typedef VkFlags VkAttachmentDescriptionFlags;
+
+typedef enum VkSubpassDescriptionFlagBits {
+ VK_SUBPASS_DESCRIPTION_PER_VIEW_ATTRIBUTES_BIT_NVX = 0x00000001,
+ VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX = 0x00000002,
+ VK_SUBPASS_DESCRIPTION_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
+} VkSubpassDescriptionFlagBits;
typedef VkFlags VkSubpassDescriptionFlags;
typedef enum VkAccessFlagBits {
@@ -1072,12 +1190,16 @@
VK_ACCESS_HOST_WRITE_BIT = 0x00004000,
VK_ACCESS_MEMORY_READ_BIT = 0x00008000,
VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000,
+ VK_ACCESS_COMMAND_PROCESS_READ_BIT_NVX = 0x00020000,
+ VK_ACCESS_COMMAND_PROCESS_WRITE_BIT_NVX = 0x00040000,
VK_ACCESS_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkAccessFlagBits;
typedef VkFlags VkAccessFlags;
typedef enum VkDependencyFlagBits {
VK_DEPENDENCY_BY_REGION_BIT = 0x00000001,
+ VK_DEPENDENCY_VIEW_LOCAL_BIT_KHX = 0x00000002,
+ VK_DEPENDENCY_DEVICE_GROUP_BIT_KHX = 0x00000004,
VK_DEPENDENCY_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkDependencyFlagBits;
typedef VkFlags VkDependencyFlags;
@@ -2340,14 +2462,14 @@
typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexed)(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance);
typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride);
typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride);
-typedef void (VKAPI_PTR *PFN_vkCmdDispatch)(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z);
+typedef void (VKAPI_PTR *PFN_vkCmdDispatch)(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
typedef void (VKAPI_PTR *PFN_vkCmdDispatchIndirect)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset);
typedef void (VKAPI_PTR *PFN_vkCmdCopyBuffer)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy* pRegions);
typedef void (VKAPI_PTR *PFN_vkCmdCopyImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy* pRegions);
typedef void (VKAPI_PTR *PFN_vkCmdBlitImage)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter);
typedef void (VKAPI_PTR *PFN_vkCmdCopyBufferToImage)(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions);
typedef void (VKAPI_PTR *PFN_vkCmdCopyImageToBuffer)(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions);
-typedef void (VKAPI_PTR *PFN_vkCmdUpdateBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const uint32_t* pData);
+typedef void (VKAPI_PTR *PFN_vkCmdUpdateBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData);
typedef void (VKAPI_PTR *PFN_vkCmdFillBuffer)(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data);
typedef void (VKAPI_PTR *PFN_vkCmdClearColorImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges);
typedef void (VKAPI_PTR *PFN_vkCmdClearDepthStencilImage)(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange* pRanges);
@@ -2976,9 +3098,9 @@
VKAPI_ATTR void VKAPI_CALL vkCmdDispatch(
VkCommandBuffer commandBuffer,
- uint32_t x,
- uint32_t y,
- uint32_t z);
+ uint32_t groupCountX,
+ uint32_t groupCountY,
+ uint32_t groupCountZ);
VKAPI_ATTR void VKAPI_CALL vkCmdDispatchIndirect(
VkCommandBuffer commandBuffer,
@@ -3032,7 +3154,7 @@
VkBuffer dstBuffer,
VkDeviceSize dstOffset,
VkDeviceSize dataSize,
- const uint32_t* pData);
+ const void* pData);
VKAPI_ATTR void VKAPI_CALL vkCmdFillBuffer(
VkCommandBuffer commandBuffer,
@@ -3177,6 +3299,19 @@
typedef enum VkColorSpaceKHR {
VK_COLOR_SPACE_SRGB_NONLINEAR_KHR = 0,
+ VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT = 1000104001,
+ VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT = 1000104002,
+ VK_COLOR_SPACE_DCI_P3_LINEAR_EXT = 1000104003,
+ VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT = 1000104004,
+ VK_COLOR_SPACE_BT709_LINEAR_EXT = 1000104005,
+ VK_COLOR_SPACE_BT709_NONLINEAR_EXT = 1000104006,
+ VK_COLOR_SPACE_BT2020_LINEAR_EXT = 1000104007,
+ VK_COLOR_SPACE_HDR10_ST2084_EXT = 1000104008,
+ VK_COLOR_SPACE_DOLBYVISION_EXT = 1000104009,
+ VK_COLOR_SPACE_HDR10_HLG_EXT = 1000104010,
+ VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011,
+ VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012,
+ VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013,
VK_COLOR_SPACE_BEGIN_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
VK_COLOR_SPACE_END_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
VK_COLOR_SPACE_RANGE_SIZE_KHR = (VK_COLOR_SPACE_SRGB_NONLINEAR_KHR - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR + 1),
@@ -3279,6 +3414,11 @@
#define VK_KHR_SWAPCHAIN_SPEC_VERSION 68
#define VK_KHR_SWAPCHAIN_EXTENSION_NAME "VK_KHR_swapchain"
+
+typedef enum VkSwapchainCreateFlagBitsKHR {
+ VK_SWAPCHAIN_CREATE_BIND_SFR_BIT_KHX = 0x00000001,
+ VK_SWAPCHAIN_CREATE_FLAG_BITS_MAX_ENUM_KHR = 0x7FFFFFFF
+} VkSwapchainCreateFlagBitsKHR;
typedef VkFlags VkSwapchainCreateFlagsKHR;
typedef struct VkSwapchainCreateInfoKHR {
@@ -3579,7 +3719,7 @@
#define VK_KHR_wayland_surface 1
#include <wayland-client.h>
-#define VK_KHR_WAYLAND_SURFACE_SPEC_VERSION 5
+#define VK_KHR_WAYLAND_SURFACE_SPEC_VERSION 6
#define VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME "VK_KHR_wayland_surface"
typedef VkFlags VkWaylandSurfaceCreateFlagsKHR;
@@ -3712,10 +3852,259 @@
#define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME "VK_KHR_sampler_mirror_clamp_to_edge"
+#define VK_KHR_get_physical_device_properties2 1
+#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION 1
+#define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_physical_device_properties2"
+
+typedef struct VkPhysicalDeviceFeatures2KHR {
+ VkStructureType sType;
+ void* pNext;
+ VkPhysicalDeviceFeatures features;
+} VkPhysicalDeviceFeatures2KHR;
+
+typedef struct VkPhysicalDeviceProperties2KHR {
+ VkStructureType sType;
+ void* pNext;
+ VkPhysicalDeviceProperties properties;
+} VkPhysicalDeviceProperties2KHR;
+
+typedef struct VkFormatProperties2KHR {
+ VkStructureType sType;
+ void* pNext;
+ VkFormatProperties formatProperties;
+} VkFormatProperties2KHR;
+
+typedef struct VkImageFormatProperties2KHR {
+ VkStructureType sType;
+ void* pNext;
+ VkImageFormatProperties imageFormatProperties;
+} VkImageFormatProperties2KHR;
+
+typedef struct VkPhysicalDeviceImageFormatInfo2KHR {
+ VkStructureType sType;
+ const void* pNext;
+ VkFormat format;
+ VkImageType type;
+ VkImageTiling tiling;
+ VkImageUsageFlags usage;
+ VkImageCreateFlags flags;
+} VkPhysicalDeviceImageFormatInfo2KHR;
+
+typedef struct VkQueueFamilyProperties2KHR {
+ VkStructureType sType;
+ void* pNext;
+ VkQueueFamilyProperties queueFamilyProperties;
+} VkQueueFamilyProperties2KHR;
+
+typedef struct VkPhysicalDeviceMemoryProperties2KHR {
+ VkStructureType sType;
+ void* pNext;
+ VkPhysicalDeviceMemoryProperties memoryProperties;
+} VkPhysicalDeviceMemoryProperties2KHR;
+
+typedef struct VkSparseImageFormatProperties2KHR {
+ VkStructureType sType;
+ void* pNext;
+ VkSparseImageFormatProperties properties;
+} VkSparseImageFormatProperties2KHR;
+
+typedef struct VkPhysicalDeviceSparseImageFormatInfo2KHR {
+ VkStructureType sType;
+ const void* pNext;
+ VkFormat format;
+ VkImageType type;
+ VkSampleCountFlagBits samples;
+ VkImageUsageFlags usage;
+ VkImageTiling tiling;
+} VkPhysicalDeviceSparseImageFormatInfo2KHR;
+
+
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFeatures2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2KHR* pFeatures);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2KHR* pProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceFormatProperties2KHR)(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2KHR* pFormatProperties);
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2KHR* pImageFormatInfo, VkImageFormatProperties2KHR* pImageFormatProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR)(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2KHR* pQueueFamilyProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceMemoryProperties2KHR)(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2KHR* pMemoryProperties);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceSparseImageFormatProperties2KHR)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2KHR* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2KHR* pProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFeatures2KHR(
+ VkPhysicalDevice physicalDevice,
+ VkPhysicalDeviceFeatures2KHR* pFeatures);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceProperties2KHR(
+ VkPhysicalDevice physicalDevice,
+ VkPhysicalDeviceProperties2KHR* pProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceFormatProperties2KHR(
+ VkPhysicalDevice physicalDevice,
+ VkFormat format,
+ VkFormatProperties2KHR* pFormatProperties);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceImageFormatProperties2KHR(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceImageFormatInfo2KHR* pImageFormatInfo,
+ VkImageFormatProperties2KHR* pImageFormatProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties2KHR(
+ VkPhysicalDevice physicalDevice,
+ uint32_t* pQueueFamilyPropertyCount,
+ VkQueueFamilyProperties2KHR* pQueueFamilyProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceMemoryProperties2KHR(
+ VkPhysicalDevice physicalDevice,
+ VkPhysicalDeviceMemoryProperties2KHR* pMemoryProperties);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceSparseImageFormatProperties2KHR(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceSparseImageFormatInfo2KHR* pFormatInfo,
+ uint32_t* pPropertyCount,
+ VkSparseImageFormatProperties2KHR* pProperties);
+#endif
+
+#define VK_KHR_shader_draw_parameters 1
+#define VK_KHR_SHADER_DRAW_PARAMETERS_SPEC_VERSION 1
+#define VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME "VK_KHR_shader_draw_parameters"
+
+
+#define VK_KHR_maintenance1 1
+#define VK_KHR_MAINTENANCE1_SPEC_VERSION 1
+#define VK_KHR_MAINTENANCE1_EXTENSION_NAME "VK_KHR_maintenance1"
+
+typedef VkFlags VkCommandPoolTrimFlagsKHR;
+
+typedef void (VKAPI_PTR *PFN_vkTrimCommandPoolKHR)(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlagsKHR flags);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkTrimCommandPoolKHR(
+ VkDevice device,
+ VkCommandPool commandPool,
+ VkCommandPoolTrimFlagsKHR flags);
+#endif
+
+#define VK_KHR_push_descriptor 1
+#define VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION 1
+#define VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME "VK_KHR_push_descriptor"
+
+typedef struct VkPhysicalDevicePushDescriptorPropertiesKHR {
+ VkStructureType sType;
+ void* pNext;
+ uint32_t maxPushDescriptors;
+} VkPhysicalDevicePushDescriptorPropertiesKHR;
+
+
+typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetKHR)(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint, VkPipelineLayout layout, uint32_t set, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetKHR(
+ VkCommandBuffer commandBuffer,
+ VkPipelineBindPoint pipelineBindPoint,
+ VkPipelineLayout layout,
+ uint32_t set,
+ uint32_t descriptorWriteCount,
+ const VkWriteDescriptorSet* pDescriptorWrites);
+#endif
+
+#define VK_KHR_incremental_present 1
+#define VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION 1
+#define VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME "VK_KHR_incremental_present"
+
+typedef struct VkRectLayerKHR {
+ VkOffset2D offset;
+ VkExtent2D extent;
+ uint32_t layer;
+} VkRectLayerKHR;
+
+typedef struct VkPresentRegionKHR {
+ uint32_t rectangleCount;
+ const VkRectLayerKHR* pRectangles;
+} VkPresentRegionKHR;
+
+typedef struct VkPresentRegionsKHR {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t swapchainCount;
+ const VkPresentRegionKHR* pRegions;
+} VkPresentRegionsKHR;
+
+
+
+#define VK_KHR_descriptor_update_template 1
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorUpdateTemplateKHR)
+
+#define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_SPEC_VERSION 1
+#define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME "VK_KHR_descriptor_update_template"
+
+
+typedef enum VkDescriptorUpdateTemplateTypeKHR {
+ VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR = 0,
+ VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR = 1,
+ VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_BEGIN_RANGE_KHR = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR,
+ VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_END_RANGE_KHR = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR,
+ VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_RANGE_SIZE_KHR = (VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR - VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR + 1),
+ VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_MAX_ENUM_KHR = 0x7FFFFFFF
+} VkDescriptorUpdateTemplateTypeKHR;
+
+typedef VkFlags VkDescriptorUpdateTemplateCreateFlagsKHR;
+
+typedef struct VkDescriptorUpdateTemplateEntryKHR {
+ uint32_t dstBinding;
+ uint32_t dstArrayElement;
+ uint32_t descriptorCount;
+ VkDescriptorType descriptorType;
+ size_t offset;
+ size_t stride;
+} VkDescriptorUpdateTemplateEntryKHR;
+
+typedef struct VkDescriptorUpdateTemplateCreateInfoKHR {
+ VkStructureType sType;
+ void* pNext;
+ VkDescriptorUpdateTemplateCreateFlagsKHR flags;
+ uint32_t descriptorUpdateEntryCount;
+ const VkDescriptorUpdateTemplateEntryKHR* pDescriptorUpdateEntries;
+ VkDescriptorUpdateTemplateTypeKHR templateType;
+ VkDescriptorSetLayout descriptorSetLayout;
+ VkPipelineBindPoint pipelineBindPoint;
+ VkPipelineLayout pipelineLayout;
+ uint32_t set;
+} VkDescriptorUpdateTemplateCreateInfoKHR;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkCreateDescriptorUpdateTemplateKHR)(VkDevice device, const VkDescriptorUpdateTemplateCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplateKHR* pDescriptorUpdateTemplate);
+typedef void (VKAPI_PTR *PFN_vkDestroyDescriptorUpdateTemplateKHR)(VkDevice device, VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator);
+typedef void (VKAPI_PTR *PFN_vkUpdateDescriptorSetWithTemplateKHR)(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, const void* pData);
+typedef void (VKAPI_PTR *PFN_vkCmdPushDescriptorSetWithTemplateKHR)(VkCommandBuffer commandBuffer, VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, VkPipelineLayout layout, uint32_t set, const void* pData);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateDescriptorUpdateTemplateKHR(
+ VkDevice device,
+ const VkDescriptorUpdateTemplateCreateInfoKHR* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkDescriptorUpdateTemplateKHR* pDescriptorUpdateTemplate);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyDescriptorUpdateTemplateKHR(
+ VkDevice device,
+ VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+ const VkAllocationCallbacks* pAllocator);
+
+VKAPI_ATTR void VKAPI_CALL vkUpdateDescriptorSetWithTemplateKHR(
+ VkDevice device,
+ VkDescriptorSet descriptorSet,
+ VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+ const void* pData);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdPushDescriptorSetWithTemplateKHR(
+ VkCommandBuffer commandBuffer,
+ VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+ VkPipelineLayout layout,
+ uint32_t set,
+ const void* pData);
+#endif
+
#define VK_EXT_debug_report 1
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT)
-#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 2
+#define VK_EXT_DEBUG_REPORT_SPEC_VERSION 6
#define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report"
#define VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT
@@ -3750,9 +4139,14 @@
VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT = 26,
VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT = 27,
VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = 28,
+ VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT = 29,
+ VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT = 30,
+ VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT = 31,
+ VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT = 32,
+ VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = 1000085000,
VK_DEBUG_REPORT_OBJECT_TYPE_BEGIN_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
- VK_DEBUG_REPORT_OBJECT_TYPE_END_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT,
- VK_DEBUG_REPORT_OBJECT_TYPE_RANGE_SIZE_EXT = (VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT - VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT + 1),
+ VK_DEBUG_REPORT_OBJECT_TYPE_END_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT,
+ VK_DEBUG_REPORT_OBJECT_TYPE_RANGE_SIZE_EXT = (VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT - VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT + 1),
VK_DEBUG_REPORT_OBJECT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF
} VkDebugReportObjectTypeEXT;
@@ -3855,8 +4249,18 @@
+#define VK_AMD_shader_trinary_minmax 1
+#define VK_AMD_SHADER_TRINARY_MINMAX_SPEC_VERSION 1
+#define VK_AMD_SHADER_TRINARY_MINMAX_EXTENSION_NAME "VK_AMD_shader_trinary_minmax"
+
+
+#define VK_AMD_shader_explicit_vertex_parameter 1
+#define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_SPEC_VERSION 1
+#define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_EXTENSION_NAME "VK_AMD_shader_explicit_vertex_parameter"
+
+
#define VK_EXT_debug_marker 1
-#define VK_EXT_DEBUG_MARKER_SPEC_VERSION 3
+#define VK_EXT_DEBUG_MARKER_SPEC_VERSION 4
#define VK_EXT_DEBUG_MARKER_EXTENSION_NAME "VK_EXT_debug_marker"
typedef struct VkDebugMarkerObjectNameInfoEXT {
@@ -3912,6 +4316,1506 @@
VkDebugMarkerMarkerInfoEXT* pMarkerInfo);
#endif
+#define VK_AMD_gcn_shader 1
+#define VK_AMD_GCN_SHADER_SPEC_VERSION 1
+#define VK_AMD_GCN_SHADER_EXTENSION_NAME "VK_AMD_gcn_shader"
+
+
+#define VK_NV_dedicated_allocation 1
+#define VK_NV_DEDICATED_ALLOCATION_SPEC_VERSION 1
+#define VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_NV_dedicated_allocation"
+
+typedef struct VkDedicatedAllocationImageCreateInfoNV {
+ VkStructureType sType;
+ const void* pNext;
+ VkBool32 dedicatedAllocation;
+} VkDedicatedAllocationImageCreateInfoNV;
+
+typedef struct VkDedicatedAllocationBufferCreateInfoNV {
+ VkStructureType sType;
+ const void* pNext;
+ VkBool32 dedicatedAllocation;
+} VkDedicatedAllocationBufferCreateInfoNV;
+
+typedef struct VkDedicatedAllocationMemoryAllocateInfoNV {
+ VkStructureType sType;
+ const void* pNext;
+ VkImage image;
+ VkBuffer buffer;
+} VkDedicatedAllocationMemoryAllocateInfoNV;
+
+
+
+#define VK_AMD_draw_indirect_count 1
+#define VK_AMD_DRAW_INDIRECT_COUNT_SPEC_VERSION 1
+#define VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_AMD_draw_indirect_count"
+
+typedef void (VKAPI_PTR *PFN_vkCmdDrawIndirectCountAMD)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);
+typedef void (VKAPI_PTR *PFN_vkCmdDrawIndexedIndirectCountAMD)(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirectCountAMD(
+ VkCommandBuffer commandBuffer,
+ VkBuffer buffer,
+ VkDeviceSize offset,
+ VkBuffer countBuffer,
+ VkDeviceSize countBufferOffset,
+ uint32_t maxDrawCount,
+ uint32_t stride);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirectCountAMD(
+ VkCommandBuffer commandBuffer,
+ VkBuffer buffer,
+ VkDeviceSize offset,
+ VkBuffer countBuffer,
+ VkDeviceSize countBufferOffset,
+ uint32_t maxDrawCount,
+ uint32_t stride);
+#endif
+
+#define VK_AMD_negative_viewport_height 1
+#define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_SPEC_VERSION 1
+#define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME "VK_AMD_negative_viewport_height"
+
+
+#define VK_AMD_gpu_shader_half_float 1
+#define VK_AMD_GPU_SHADER_HALF_FLOAT_SPEC_VERSION 1
+#define VK_AMD_GPU_SHADER_HALF_FLOAT_EXTENSION_NAME "VK_AMD_gpu_shader_half_float"
+
+
+#define VK_AMD_shader_ballot 1
+#define VK_AMD_SHADER_BALLOT_SPEC_VERSION 1
+#define VK_AMD_SHADER_BALLOT_EXTENSION_NAME "VK_AMD_shader_ballot"
+
+
+#define VK_KHX_multiview 1
+#define VK_KHX_MULTIVIEW_SPEC_VERSION 1
+#define VK_KHX_MULTIVIEW_EXTENSION_NAME "VK_KHX_multiview"
+
+typedef struct VkRenderPassMultiviewCreateInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t subpassCount;
+ const uint32_t* pViewMasks;
+ uint32_t dependencyCount;
+ const int32_t* pViewOffsets;
+ uint32_t correlationMaskCount;
+ const uint32_t* pCorrelationMasks;
+} VkRenderPassMultiviewCreateInfoKHX;
+
+typedef struct VkPhysicalDeviceMultiviewFeaturesKHX {
+ VkStructureType sType;
+ void* pNext;
+ VkBool32 multiview;
+ VkBool32 multiviewGeometryShader;
+ VkBool32 multiviewTessellationShader;
+} VkPhysicalDeviceMultiviewFeaturesKHX;
+
+typedef struct VkPhysicalDeviceMultiviewPropertiesKHX {
+ VkStructureType sType;
+ void* pNext;
+ uint32_t maxMultiviewViewCount;
+ uint32_t maxMultiviewInstanceIndex;
+} VkPhysicalDeviceMultiviewPropertiesKHX;
+
+
+
+#define VK_IMG_format_pvrtc 1
+#define VK_IMG_FORMAT_PVRTC_SPEC_VERSION 1
+#define VK_IMG_FORMAT_PVRTC_EXTENSION_NAME "VK_IMG_format_pvrtc"
+
+
+#define VK_NV_external_memory_capabilities 1
+#define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1
+#define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_NV_external_memory_capabilities"
+
+
+typedef enum VkExternalMemoryHandleTypeFlagBitsNV {
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_NV = 0x00000001,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_NV = 0x00000002,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_BIT_NV = 0x00000004,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_KMT_BIT_NV = 0x00000008,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF
+} VkExternalMemoryHandleTypeFlagBitsNV;
+typedef VkFlags VkExternalMemoryHandleTypeFlagsNV;
+
+typedef enum VkExternalMemoryFeatureFlagBitsNV {
+ VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_NV = 0x00000001,
+ VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_NV = 0x00000002,
+ VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_NV = 0x00000004,
+ VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM_NV = 0x7FFFFFFF
+} VkExternalMemoryFeatureFlagBitsNV;
+typedef VkFlags VkExternalMemoryFeatureFlagsNV;
+
+typedef struct VkExternalImageFormatPropertiesNV {
+ VkImageFormatProperties imageFormatProperties;
+ VkExternalMemoryFeatureFlagsNV externalMemoryFeatures;
+ VkExternalMemoryHandleTypeFlagsNV exportFromImportedHandleTypes;
+ VkExternalMemoryHandleTypeFlagsNV compatibleHandleTypes;
+} VkExternalImageFormatPropertiesNV;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalImageFormatPropertiesNV)(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkExternalMemoryHandleTypeFlagsNV externalHandleType, VkExternalImageFormatPropertiesNV* pExternalImageFormatProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceExternalImageFormatPropertiesNV(
+ VkPhysicalDevice physicalDevice,
+ VkFormat format,
+ VkImageType type,
+ VkImageTiling tiling,
+ VkImageUsageFlags usage,
+ VkImageCreateFlags flags,
+ VkExternalMemoryHandleTypeFlagsNV externalHandleType,
+ VkExternalImageFormatPropertiesNV* pExternalImageFormatProperties);
+#endif
+
+#define VK_NV_external_memory 1
+#define VK_NV_EXTERNAL_MEMORY_SPEC_VERSION 1
+#define VK_NV_EXTERNAL_MEMORY_EXTENSION_NAME "VK_NV_external_memory"
+
+typedef struct VkExternalMemoryImageCreateInfoNV {
+ VkStructureType sType;
+ const void* pNext;
+ VkExternalMemoryHandleTypeFlagsNV handleTypes;
+} VkExternalMemoryImageCreateInfoNV;
+
+typedef struct VkExportMemoryAllocateInfoNV {
+ VkStructureType sType;
+ const void* pNext;
+ VkExternalMemoryHandleTypeFlagsNV handleTypes;
+} VkExportMemoryAllocateInfoNV;
+
+
+
+#ifdef VK_USE_PLATFORM_WIN32_KHR
+#define VK_NV_external_memory_win32 1
+#define VK_NV_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1
+#define VK_NV_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_NV_external_memory_win32"
+
+typedef struct VkImportMemoryWin32HandleInfoNV {
+ VkStructureType sType;
+ const void* pNext;
+ VkExternalMemoryHandleTypeFlagsNV handleType;
+ HANDLE handle;
+} VkImportMemoryWin32HandleInfoNV;
+
+typedef struct VkExportMemoryWin32HandleInfoNV {
+ VkStructureType sType;
+ const void* pNext;
+ const SECURITY_ATTRIBUTES* pAttributes;
+ DWORD dwAccess;
+} VkExportMemoryWin32HandleInfoNV;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandleNV)(VkDevice device, VkDeviceMemory memory, VkExternalMemoryHandleTypeFlagsNV handleType, HANDLE* pHandle);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandleNV(
+ VkDevice device,
+ VkDeviceMemory memory,
+ VkExternalMemoryHandleTypeFlagsNV handleType,
+ HANDLE* pHandle);
+#endif
+#endif /* VK_USE_PLATFORM_WIN32_KHR */
+
+#ifdef VK_USE_PLATFORM_WIN32_KHR
+#define VK_NV_win32_keyed_mutex 1
+#define VK_NV_WIN32_KEYED_MUTEX_SPEC_VERSION 1
+#define VK_NV_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_NV_win32_keyed_mutex"
+
+typedef struct VkWin32KeyedMutexAcquireReleaseInfoNV {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t acquireCount;
+ const VkDeviceMemory* pAcquireSyncs;
+ const uint64_t* pAcquireKeys;
+ const uint32_t* pAcquireTimeoutMilliseconds;
+ uint32_t releaseCount;
+ const VkDeviceMemory* pReleaseSyncs;
+ const uint64_t* pReleaseKeys;
+} VkWin32KeyedMutexAcquireReleaseInfoNV;
+
+
+#endif /* VK_USE_PLATFORM_WIN32_KHR */
+
+#define VK_KHX_device_group 1
+#define VK_MAX_DEVICE_GROUP_SIZE_KHX 32
+#define VK_KHX_DEVICE_GROUP_SPEC_VERSION 1
+#define VK_KHX_DEVICE_GROUP_EXTENSION_NAME "VK_KHX_device_group"
+
+
+typedef enum VkPeerMemoryFeatureFlagBitsKHX {
+ VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT_KHX = 0x00000001,
+ VK_PEER_MEMORY_FEATURE_COPY_DST_BIT_KHX = 0x00000002,
+ VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT_KHX = 0x00000004,
+ VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHX = 0x00000008,
+ VK_PEER_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM_KHX = 0x7FFFFFFF
+} VkPeerMemoryFeatureFlagBitsKHX;
+typedef VkFlags VkPeerMemoryFeatureFlagsKHX;
+
+typedef enum VkMemoryAllocateFlagBitsKHX {
+ VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHX = 0x00000001,
+ VK_MEMORY_ALLOCATE_FLAG_BITS_MAX_ENUM_KHX = 0x7FFFFFFF
+} VkMemoryAllocateFlagBitsKHX;
+typedef VkFlags VkMemoryAllocateFlagsKHX;
+
+typedef enum VkDeviceGroupPresentModeFlagBitsKHX {
+ VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHX = 0x00000001,
+ VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHX = 0x00000002,
+ VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHX = 0x00000004,
+ VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHX = 0x00000008,
+ VK_DEVICE_GROUP_PRESENT_MODE_FLAG_BITS_MAX_ENUM_KHX = 0x7FFFFFFF
+} VkDeviceGroupPresentModeFlagBitsKHX;
+typedef VkFlags VkDeviceGroupPresentModeFlagsKHX;
+
+typedef struct VkMemoryAllocateFlagsInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ VkMemoryAllocateFlagsKHX flags;
+ uint32_t deviceMask;
+} VkMemoryAllocateFlagsInfoKHX;
+
+typedef struct VkBindBufferMemoryInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ VkBuffer buffer;
+ VkDeviceMemory memory;
+ VkDeviceSize memoryOffset;
+ uint32_t deviceIndexCount;
+ const uint32_t* pDeviceIndices;
+} VkBindBufferMemoryInfoKHX;
+
+typedef struct VkBindImageMemoryInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ VkImage image;
+ VkDeviceMemory memory;
+ VkDeviceSize memoryOffset;
+ uint32_t deviceIndexCount;
+ const uint32_t* pDeviceIndices;
+ uint32_t SFRRectCount;
+ const VkRect2D* pSFRRects;
+} VkBindImageMemoryInfoKHX;
+
+typedef struct VkDeviceGroupRenderPassBeginInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t deviceMask;
+ uint32_t deviceRenderAreaCount;
+ const VkRect2D* pDeviceRenderAreas;
+} VkDeviceGroupRenderPassBeginInfoKHX;
+
+typedef struct VkDeviceGroupCommandBufferBeginInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t deviceMask;
+} VkDeviceGroupCommandBufferBeginInfoKHX;
+
+typedef struct VkDeviceGroupSubmitInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t waitSemaphoreCount;
+ const uint32_t* pWaitSemaphoreDeviceIndices;
+ uint32_t commandBufferCount;
+ const uint32_t* pCommandBufferDeviceMasks;
+ uint32_t signalSemaphoreCount;
+ const uint32_t* pSignalSemaphoreDeviceIndices;
+} VkDeviceGroupSubmitInfoKHX;
+
+typedef struct VkDeviceGroupBindSparseInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t resourceDeviceIndex;
+ uint32_t memoryDeviceIndex;
+} VkDeviceGroupBindSparseInfoKHX;
+
+typedef struct VkDeviceGroupPresentCapabilitiesKHX {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t presentMask[VK_MAX_DEVICE_GROUP_SIZE_KHX];
+ VkDeviceGroupPresentModeFlagsKHX modes;
+} VkDeviceGroupPresentCapabilitiesKHX;
+
+typedef struct VkImageSwapchainCreateInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ VkSwapchainKHR swapchain;
+} VkImageSwapchainCreateInfoKHX;
+
+typedef struct VkBindImageMemorySwapchainInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ VkSwapchainKHR swapchain;
+ uint32_t imageIndex;
+} VkBindImageMemorySwapchainInfoKHX;
+
+typedef struct VkAcquireNextImageInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ VkSwapchainKHR swapchain;
+ uint64_t timeout;
+ VkSemaphore semaphore;
+ VkFence fence;
+ uint32_t deviceMask;
+} VkAcquireNextImageInfoKHX;
+
+typedef struct VkDeviceGroupPresentInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t swapchainCount;
+ const uint32_t* pDeviceMasks;
+ VkDeviceGroupPresentModeFlagBitsKHX mode;
+} VkDeviceGroupPresentInfoKHX;
+
+typedef struct VkDeviceGroupSwapchainCreateInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ VkDeviceGroupPresentModeFlagsKHX modes;
+} VkDeviceGroupSwapchainCreateInfoKHX;
+
+
+typedef void (VKAPI_PTR *PFN_vkGetDeviceGroupPeerMemoryFeaturesKHX)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlagsKHX* pPeerMemoryFeatures);
+typedef VkResult (VKAPI_PTR *PFN_vkBindBufferMemory2KHX)(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfoKHX* pBindInfos);
+typedef VkResult (VKAPI_PTR *PFN_vkBindImageMemory2KHX)(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfoKHX* pBindInfos);
+typedef void (VKAPI_PTR *PFN_vkCmdSetDeviceMaskKHX)(VkCommandBuffer commandBuffer, uint32_t deviceMask);
+typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupPresentCapabilitiesKHX)(VkDevice device, VkDeviceGroupPresentCapabilitiesKHX* pDeviceGroupPresentCapabilities);
+typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupSurfacePresentModesKHX)(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHX* pModes);
+typedef VkResult (VKAPI_PTR *PFN_vkAcquireNextImage2KHX)(VkDevice device, const VkAcquireNextImageInfoKHX* pAcquireInfo, uint32_t* pImageIndex);
+typedef void (VKAPI_PTR *PFN_vkCmdDispatchBaseKHX)(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDevicePresentRectanglesKHX)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkGetDeviceGroupPeerMemoryFeaturesKHX(
+ VkDevice device,
+ uint32_t heapIndex,
+ uint32_t localDeviceIndex,
+ uint32_t remoteDeviceIndex,
+ VkPeerMemoryFeatureFlagsKHX* pPeerMemoryFeatures);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory2KHX(
+ VkDevice device,
+ uint32_t bindInfoCount,
+ const VkBindBufferMemoryInfoKHX* pBindInfos);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory2KHX(
+ VkDevice device,
+ uint32_t bindInfoCount,
+ const VkBindImageMemoryInfoKHX* pBindInfos);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdSetDeviceMaskKHX(
+ VkCommandBuffer commandBuffer,
+ uint32_t deviceMask);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupPresentCapabilitiesKHX(
+ VkDevice device,
+ VkDeviceGroupPresentCapabilitiesKHX* pDeviceGroupPresentCapabilities);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetDeviceGroupSurfacePresentModesKHX(
+ VkDevice device,
+ VkSurfaceKHR surface,
+ VkDeviceGroupPresentModeFlagsKHX* pModes);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkAcquireNextImage2KHX(
+ VkDevice device,
+ const VkAcquireNextImageInfoKHX* pAcquireInfo,
+ uint32_t* pImageIndex);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdDispatchBaseKHX(
+ VkCommandBuffer commandBuffer,
+ uint32_t baseGroupX,
+ uint32_t baseGroupY,
+ uint32_t baseGroupZ,
+ uint32_t groupCountX,
+ uint32_t groupCountY,
+ uint32_t groupCountZ);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDevicePresentRectanglesKHX(
+ VkPhysicalDevice physicalDevice,
+ VkSurfaceKHR surface,
+ uint32_t* pRectCount,
+ VkRect2D* pRects);
+#endif
+
+#define VK_EXT_validation_flags 1
+#define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 1
+#define VK_EXT_VALIDATION_FLAGS_EXTENSION_NAME "VK_EXT_validation_flags"
+
+
+typedef enum VkValidationCheckEXT {
+ VK_VALIDATION_CHECK_ALL_EXT = 0,
+ VK_VALIDATION_CHECK_BEGIN_RANGE_EXT = VK_VALIDATION_CHECK_ALL_EXT,
+ VK_VALIDATION_CHECK_END_RANGE_EXT = VK_VALIDATION_CHECK_ALL_EXT,
+ VK_VALIDATION_CHECK_RANGE_SIZE_EXT = (VK_VALIDATION_CHECK_ALL_EXT - VK_VALIDATION_CHECK_ALL_EXT + 1),
+ VK_VALIDATION_CHECK_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkValidationCheckEXT;
+
+typedef struct VkValidationFlagsEXT {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t disabledValidationCheckCount;
+ VkValidationCheckEXT* pDisabledValidationChecks;
+} VkValidationFlagsEXT;
+
+
+
+#ifdef VK_USE_PLATFORM_VI_NN
+#define VK_NN_vi_surface 1
+#define VK_NN_VI_SURFACE_SPEC_VERSION 1
+#define VK_NN_VI_SURFACE_EXTENSION_NAME "VK_NN_vi_surface"
+
+typedef VkFlags VkViSurfaceCreateFlagsNN;
+
+typedef struct VkViSurfaceCreateInfoNN {
+ VkStructureType sType;
+ const void* pNext;
+ VkViSurfaceCreateFlagsNN flags;
+ void* window;
+} VkViSurfaceCreateInfoNN;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkCreateViSurfaceNN)(VkInstance instance, const VkViSurfaceCreateInfoNN* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateViSurfaceNN(
+ VkInstance instance,
+ const VkViSurfaceCreateInfoNN* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkSurfaceKHR* pSurface);
+#endif
+#endif /* VK_USE_PLATFORM_VI_NN */
+
+#define VK_EXT_shader_subgroup_ballot 1
+#define VK_EXT_SHADER_SUBGROUP_BALLOT_SPEC_VERSION 1
+#define VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME "VK_EXT_shader_subgroup_ballot"
+
+
+#define VK_EXT_shader_subgroup_vote 1
+#define VK_EXT_SHADER_SUBGROUP_VOTE_SPEC_VERSION 1
+#define VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME "VK_EXT_shader_subgroup_vote"
+
+
+#define VK_KHX_device_group_creation 1
+#define VK_KHX_DEVICE_GROUP_CREATION_SPEC_VERSION 1
+#define VK_KHX_DEVICE_GROUP_CREATION_EXTENSION_NAME "VK_KHX_device_group_creation"
+
+typedef struct VkPhysicalDeviceGroupPropertiesKHX {
+ VkStructureType sType;
+ void* pNext;
+ uint32_t physicalDeviceCount;
+ VkPhysicalDevice physicalDevices[VK_MAX_DEVICE_GROUP_SIZE_KHX];
+ VkBool32 subsetAllocation;
+} VkPhysicalDeviceGroupPropertiesKHX;
+
+typedef struct VkDeviceGroupDeviceCreateInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t physicalDeviceCount;
+ const VkPhysicalDevice* pPhysicalDevices;
+} VkDeviceGroupDeviceCreateInfoKHX;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkEnumeratePhysicalDeviceGroupsKHX)(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupPropertiesKHX* pPhysicalDeviceGroupProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDeviceGroupsKHX(
+ VkInstance instance,
+ uint32_t* pPhysicalDeviceGroupCount,
+ VkPhysicalDeviceGroupPropertiesKHX* pPhysicalDeviceGroupProperties);
+#endif
+
+#define VK_KHX_external_memory_capabilities 1
+#define VK_LUID_SIZE_KHX 8
+#define VK_KHX_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1
+#define VK_KHX_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_KHX_external_memory_capabilities"
+
+
+typedef enum VkExternalMemoryHandleTypeFlagBitsKHX {
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHX = 0x00000001,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHX = 0x00000002,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHX = 0x00000004,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT_KHX = 0x00000008,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT_KHX = 0x00000010,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT_KHX = 0x00000020,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT_KHX = 0x00000040,
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM_KHX = 0x7FFFFFFF
+} VkExternalMemoryHandleTypeFlagBitsKHX;
+typedef VkFlags VkExternalMemoryHandleTypeFlagsKHX;
+
+typedef enum VkExternalMemoryFeatureFlagBitsKHX {
+ VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHX = 0x00000001,
+ VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHX = 0x00000002,
+ VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHX = 0x00000004,
+ VK_EXTERNAL_MEMORY_FEATURE_FLAG_BITS_MAX_ENUM_KHX = 0x7FFFFFFF
+} VkExternalMemoryFeatureFlagBitsKHX;
+typedef VkFlags VkExternalMemoryFeatureFlagsKHX;
+
+typedef struct VkExternalMemoryPropertiesKHX {
+ VkExternalMemoryFeatureFlagsKHX externalMemoryFeatures;
+ VkExternalMemoryHandleTypeFlagsKHX exportFromImportedHandleTypes;
+ VkExternalMemoryHandleTypeFlagsKHX compatibleHandleTypes;
+} VkExternalMemoryPropertiesKHX;
+
+typedef struct VkPhysicalDeviceExternalImageFormatInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ VkExternalMemoryHandleTypeFlagBitsKHX handleType;
+} VkPhysicalDeviceExternalImageFormatInfoKHX;
+
+typedef struct VkExternalImageFormatPropertiesKHX {
+ VkStructureType sType;
+ void* pNext;
+ VkExternalMemoryPropertiesKHX externalMemoryProperties;
+} VkExternalImageFormatPropertiesKHX;
+
+typedef struct VkPhysicalDeviceExternalBufferInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ VkBufferCreateFlags flags;
+ VkBufferUsageFlags usage;
+ VkExternalMemoryHandleTypeFlagBitsKHX handleType;
+} VkPhysicalDeviceExternalBufferInfoKHX;
+
+typedef struct VkExternalBufferPropertiesKHX {
+ VkStructureType sType;
+ void* pNext;
+ VkExternalMemoryPropertiesKHX externalMemoryProperties;
+} VkExternalBufferPropertiesKHX;
+
+typedef struct VkPhysicalDeviceIDPropertiesKHX {
+ VkStructureType sType;
+ void* pNext;
+ uint8_t deviceUUID[VK_UUID_SIZE];
+ uint8_t driverUUID[VK_UUID_SIZE];
+ uint8_t deviceLUID[VK_LUID_SIZE_KHX];
+ VkBool32 deviceLUIDValid;
+} VkPhysicalDeviceIDPropertiesKHX;
+
+
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalBufferPropertiesKHX)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfoKHX* pExternalBufferInfo, VkExternalBufferPropertiesKHX* pExternalBufferProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalBufferPropertiesKHX(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceExternalBufferInfoKHX* pExternalBufferInfo,
+ VkExternalBufferPropertiesKHX* pExternalBufferProperties);
+#endif
+
+#define VK_KHX_external_memory 1
+#define VK_KHX_EXTERNAL_MEMORY_SPEC_VERSION 1
+#define VK_KHX_EXTERNAL_MEMORY_EXTENSION_NAME "VK_KHX_external_memory"
+#define VK_QUEUE_FAMILY_EXTERNAL_KHX (~0U-1)
+
+typedef struct VkExternalMemoryImageCreateInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ VkExternalMemoryHandleTypeFlagsKHX handleTypes;
+} VkExternalMemoryImageCreateInfoKHX;
+
+typedef struct VkExternalMemoryBufferCreateInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ VkExternalMemoryHandleTypeFlagsKHX handleTypes;
+} VkExternalMemoryBufferCreateInfoKHX;
+
+typedef struct VkExportMemoryAllocateInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ VkExternalMemoryHandleTypeFlagsKHX handleTypes;
+} VkExportMemoryAllocateInfoKHX;
+
+
+
+#ifdef VK_USE_PLATFORM_WIN32_KHX
+#define VK_KHX_external_memory_win32 1
+#define VK_KHX_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1
+#define VK_KHX_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_KHX_external_memory_win32"
+
+typedef struct VkImportMemoryWin32HandleInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ VkExternalMemoryHandleTypeFlagBitsKHX handleType;
+ HANDLE handle;
+} VkImportMemoryWin32HandleInfoKHX;
+
+typedef struct VkExportMemoryWin32HandleInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ const SECURITY_ATTRIBUTES* pAttributes;
+ DWORD dwAccess;
+ LPCWSTR name;
+} VkExportMemoryWin32HandleInfoKHX;
+
+typedef struct VkMemoryWin32HandlePropertiesKHX {
+ VkStructureType sType;
+ void* pNext;
+ uint32_t memoryTypeBits;
+} VkMemoryWin32HandlePropertiesKHX;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandleKHX)(VkDevice device, VkDeviceMemory memory, VkExternalMemoryHandleTypeFlagBitsKHX handleType, HANDLE* pHandle);
+typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryWin32HandlePropertiesKHX)(VkDevice device, VkExternalMemoryHandleTypeFlagBitsKHX handleType, HANDLE handle, VkMemoryWin32HandlePropertiesKHX* pMemoryWin32HandleProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandleKHX(
+ VkDevice device,
+ VkDeviceMemory memory,
+ VkExternalMemoryHandleTypeFlagBitsKHX handleType,
+ HANDLE* pHandle);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryWin32HandlePropertiesKHX(
+ VkDevice device,
+ VkExternalMemoryHandleTypeFlagBitsKHX handleType,
+ HANDLE handle,
+ VkMemoryWin32HandlePropertiesKHX* pMemoryWin32HandleProperties);
+#endif
+#endif /* VK_USE_PLATFORM_WIN32_KHX */
+
+#define VK_KHX_external_memory_fd 1
+#define VK_KHX_EXTERNAL_MEMORY_FD_SPEC_VERSION 1
+#define VK_KHX_EXTERNAL_MEMORY_FD_EXTENSION_NAME "VK_KHX_external_memory_fd"
+
+typedef struct VkImportMemoryFdInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ VkExternalMemoryHandleTypeFlagBitsKHX handleType;
+ int fd;
+} VkImportMemoryFdInfoKHX;
+
+typedef struct VkMemoryFdPropertiesKHX {
+ VkStructureType sType;
+ void* pNext;
+ uint32_t memoryTypeBits;
+} VkMemoryFdPropertiesKHX;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryFdKHX)(VkDevice device, VkDeviceMemory memory, VkExternalMemoryHandleTypeFlagBitsKHX handleType, int* pFd);
+typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryFdPropertiesKHX)(VkDevice device, VkExternalMemoryHandleTypeFlagBitsKHX handleType, int fd, VkMemoryFdPropertiesKHX* pMemoryFdProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFdKHX(
+ VkDevice device,
+ VkDeviceMemory memory,
+ VkExternalMemoryHandleTypeFlagBitsKHX handleType,
+ int* pFd);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryFdPropertiesKHX(
+ VkDevice device,
+ VkExternalMemoryHandleTypeFlagBitsKHX handleType,
+ int fd,
+ VkMemoryFdPropertiesKHX* pMemoryFdProperties);
+#endif
+
+#ifdef VK_USE_PLATFORM_WIN32_KHR
+#define VK_KHX_win32_keyed_mutex 1
+#define VK_KHX_WIN32_KEYED_MUTEX_SPEC_VERSION 1
+#define VK_KHX_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_KHX_win32_keyed_mutex"
+
+typedef struct VkWin32KeyedMutexAcquireReleaseInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t acquireCount;
+ const VkDeviceMemory* pAcquireSyncs;
+ const uint64_t* pAcquireKeys;
+ const uint32_t* pAcquireTimeouts;
+ uint32_t releaseCount;
+ const VkDeviceMemory* pReleaseSyncs;
+ const uint64_t* pReleaseKeys;
+} VkWin32KeyedMutexAcquireReleaseInfoKHX;
+
+
+#endif /* VK_USE_PLATFORM_WIN32_KHR */
+
+#define VK_KHX_external_semaphore_capabilities 1
+#define VK_KHX_EXTERNAL_SEMAPHORE_CAPABILITIES_SPEC_VERSION 1
+#define VK_KHX_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME "VK_KHX_external_semaphore_capabilities"
+
+
+typedef enum VkExternalSemaphoreHandleTypeFlagBitsKHX {
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHX = 0x00000001,
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHX = 0x00000002,
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHX = 0x00000004,
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT_KHX = 0x00000008,
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FENCE_FD_BIT_KHX = 0x00000010,
+ VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM_KHX = 0x7FFFFFFF
+} VkExternalSemaphoreHandleTypeFlagBitsKHX;
+typedef VkFlags VkExternalSemaphoreHandleTypeFlagsKHX;
+
+typedef enum VkExternalSemaphoreFeatureFlagBitsKHX {
+ VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHX = 0x00000001,
+ VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHX = 0x00000002,
+ VK_EXTERNAL_SEMAPHORE_FEATURE_FLAG_BITS_MAX_ENUM_KHX = 0x7FFFFFFF
+} VkExternalSemaphoreFeatureFlagBitsKHX;
+typedef VkFlags VkExternalSemaphoreFeatureFlagsKHX;
+
+typedef struct VkPhysicalDeviceExternalSemaphoreInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ VkExternalSemaphoreHandleTypeFlagBitsKHX handleType;
+} VkPhysicalDeviceExternalSemaphoreInfoKHX;
+
+typedef struct VkExternalSemaphorePropertiesKHX {
+ VkStructureType sType;
+ void* pNext;
+ VkExternalSemaphoreHandleTypeFlagsKHX exportFromImportedHandleTypes;
+ VkExternalSemaphoreHandleTypeFlagsKHX compatibleHandleTypes;
+ VkExternalSemaphoreFeatureFlagsKHX externalSemaphoreFeatures;
+} VkExternalSemaphorePropertiesKHX;
+
+
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceExternalSemaphorePropertiesKHX)(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfoKHX* pExternalSemaphoreInfo, VkExternalSemaphorePropertiesKHX* pExternalSemaphoreProperties);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceExternalSemaphorePropertiesKHX(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceExternalSemaphoreInfoKHX* pExternalSemaphoreInfo,
+ VkExternalSemaphorePropertiesKHX* pExternalSemaphoreProperties);
+#endif
+
+#define VK_KHX_external_semaphore 1
+#define VK_KHX_EXTERNAL_SEMAPHORE_SPEC_VERSION 1
+#define VK_KHX_EXTERNAL_SEMAPHORE_EXTENSION_NAME "VK_KHX_external_semaphore"
+
+typedef struct VkExportSemaphoreCreateInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ VkExternalSemaphoreHandleTypeFlagsKHX handleTypes;
+} VkExportSemaphoreCreateInfoKHX;
+
+
+
+#ifdef VK_USE_PLATFORM_WIN32_KHX
+#define VK_KHX_external_semaphore_win32 1
+#define VK_KHX_EXTERNAL_SEMAPHORE_WIN32_SPEC_VERSION 1
+#define VK_KHX_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME "VK_KHX_external_semaphore_win32"
+
+typedef struct VkImportSemaphoreWin32HandleInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ VkSemaphore semaphore;
+ VkExternalSemaphoreHandleTypeFlagsKHX handleType;
+ HANDLE handle;
+} VkImportSemaphoreWin32HandleInfoKHX;
+
+typedef struct VkExportSemaphoreWin32HandleInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ const SECURITY_ATTRIBUTES* pAttributes;
+ DWORD dwAccess;
+ LPCWSTR name;
+} VkExportSemaphoreWin32HandleInfoKHX;
+
+typedef struct VkD3D12FenceSubmitInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t waitSemaphoreValuesCount;
+ const uint64_t* pWaitSemaphoreValues;
+ uint32_t signalSemaphoreValuesCount;
+ const uint64_t* pSignalSemaphoreValues;
+} VkD3D12FenceSubmitInfoKHX;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkImportSemaphoreWin32HandleKHX)(VkDevice device, const VkImportSemaphoreWin32HandleInfoKHX* pImportSemaphoreWin32HandleInfo);
+typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreWin32HandleKHX)(VkDevice device, VkSemaphore semaphore, VkExternalSemaphoreHandleTypeFlagBitsKHX handleType, HANDLE* pHandle);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkImportSemaphoreWin32HandleKHX(
+ VkDevice device,
+ const VkImportSemaphoreWin32HandleInfoKHX* pImportSemaphoreWin32HandleInfo);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreWin32HandleKHX(
+ VkDevice device,
+ VkSemaphore semaphore,
+ VkExternalSemaphoreHandleTypeFlagBitsKHX handleType,
+ HANDLE* pHandle);
+#endif
+#endif /* VK_USE_PLATFORM_WIN32_KHX */
+
+#define VK_KHX_external_semaphore_fd 1
+#define VK_KHX_EXTERNAL_SEMAPHORE_FD_SPEC_VERSION 1
+#define VK_KHX_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME "VK_KHX_external_semaphore_fd"
+
+typedef struct VkImportSemaphoreFdInfoKHX {
+ VkStructureType sType;
+ const void* pNext;
+ VkSemaphore semaphore;
+ VkExternalSemaphoreHandleTypeFlagBitsKHX handleType;
+ int fd;
+} VkImportSemaphoreFdInfoKHX;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkImportSemaphoreFdKHX)(VkDevice device, const VkImportSemaphoreFdInfoKHX* pImportSemaphoreFdInfo);
+typedef VkResult (VKAPI_PTR *PFN_vkGetSemaphoreFdKHX)(VkDevice device, VkSemaphore semaphore, VkExternalSemaphoreHandleTypeFlagBitsKHX handleType, int* pFd);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkImportSemaphoreFdKHX(
+ VkDevice device,
+ const VkImportSemaphoreFdInfoKHX* pImportSemaphoreFdInfo);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetSemaphoreFdKHX(
+ VkDevice device,
+ VkSemaphore semaphore,
+ VkExternalSemaphoreHandleTypeFlagBitsKHX handleType,
+ int* pFd);
+#endif
+
+#define VK_NVX_device_generated_commands 1
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkObjectTableNVX)
+VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutNVX)
+
+#define VK_NVX_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 1
+#define VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME "VK_NVX_device_generated_commands"
+
+
+typedef enum VkIndirectCommandsTokenTypeNVX {
+ VK_INDIRECT_COMMANDS_TOKEN_PIPELINE_NVX = 0,
+ VK_INDIRECT_COMMANDS_TOKEN_DESCRIPTOR_SET_NVX = 1,
+ VK_INDIRECT_COMMANDS_TOKEN_INDEX_BUFFER_NVX = 2,
+ VK_INDIRECT_COMMANDS_TOKEN_VERTEX_BUFFER_NVX = 3,
+ VK_INDIRECT_COMMANDS_TOKEN_PUSH_CONSTANT_NVX = 4,
+ VK_INDIRECT_COMMANDS_TOKEN_DRAW_INDEXED_NVX = 5,
+ VK_INDIRECT_COMMANDS_TOKEN_DRAW_NVX = 6,
+ VK_INDIRECT_COMMANDS_TOKEN_DISPATCH_NVX = 7,
+ VK_INDIRECT_COMMANDS_TOKEN_TYPE_BEGIN_RANGE_NVX = VK_INDIRECT_COMMANDS_TOKEN_PIPELINE_NVX,
+ VK_INDIRECT_COMMANDS_TOKEN_TYPE_END_RANGE_NVX = VK_INDIRECT_COMMANDS_TOKEN_DISPATCH_NVX,
+ VK_INDIRECT_COMMANDS_TOKEN_TYPE_RANGE_SIZE_NVX = (VK_INDIRECT_COMMANDS_TOKEN_DISPATCH_NVX - VK_INDIRECT_COMMANDS_TOKEN_PIPELINE_NVX + 1),
+ VK_INDIRECT_COMMANDS_TOKEN_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF
+} VkIndirectCommandsTokenTypeNVX;
+
+typedef enum VkObjectEntryTypeNVX {
+ VK_OBJECT_ENTRY_DESCRIPTOR_SET_NVX = 0,
+ VK_OBJECT_ENTRY_PIPELINE_NVX = 1,
+ VK_OBJECT_ENTRY_INDEX_BUFFER_NVX = 2,
+ VK_OBJECT_ENTRY_VERTEX_BUFFER_NVX = 3,
+ VK_OBJECT_ENTRY_PUSH_CONSTANT_NVX = 4,
+ VK_OBJECT_ENTRY_TYPE_BEGIN_RANGE_NVX = VK_OBJECT_ENTRY_DESCRIPTOR_SET_NVX,
+ VK_OBJECT_ENTRY_TYPE_END_RANGE_NVX = VK_OBJECT_ENTRY_PUSH_CONSTANT_NVX,
+ VK_OBJECT_ENTRY_TYPE_RANGE_SIZE_NVX = (VK_OBJECT_ENTRY_PUSH_CONSTANT_NVX - VK_OBJECT_ENTRY_DESCRIPTOR_SET_NVX + 1),
+ VK_OBJECT_ENTRY_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF
+} VkObjectEntryTypeNVX;
+
+
+typedef enum VkIndirectCommandsLayoutUsageFlagBitsNVX {
+ VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NVX = 0x00000001,
+ VK_INDIRECT_COMMANDS_LAYOUT_USAGE_SPARSE_SEQUENCES_BIT_NVX = 0x00000002,
+ VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EMPTY_EXECUTIONS_BIT_NVX = 0x00000004,
+ VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NVX = 0x00000008,
+ VK_INDIRECT_COMMANDS_LAYOUT_USAGE_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF
+} VkIndirectCommandsLayoutUsageFlagBitsNVX;
+typedef VkFlags VkIndirectCommandsLayoutUsageFlagsNVX;
+
+typedef enum VkObjectEntryUsageFlagBitsNVX {
+ VK_OBJECT_ENTRY_USAGE_GRAPHICS_BIT_NVX = 0x00000001,
+ VK_OBJECT_ENTRY_USAGE_COMPUTE_BIT_NVX = 0x00000002,
+ VK_OBJECT_ENTRY_USAGE_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF
+} VkObjectEntryUsageFlagBitsNVX;
+typedef VkFlags VkObjectEntryUsageFlagsNVX;
+
+typedef struct VkDeviceGeneratedCommandsFeaturesNVX {
+ VkStructureType sType;
+ const void* pNext;
+ VkBool32 computeBindingPointSupport;
+} VkDeviceGeneratedCommandsFeaturesNVX;
+
+typedef struct VkDeviceGeneratedCommandsLimitsNVX {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t maxIndirectCommandsLayoutTokenCount;
+ uint32_t maxObjectEntryCounts;
+ uint32_t minSequenceCountBufferOffsetAlignment;
+ uint32_t minSequenceIndexBufferOffsetAlignment;
+ uint32_t minCommandsTokenBufferOffsetAlignment;
+} VkDeviceGeneratedCommandsLimitsNVX;
+
+typedef struct VkIndirectCommandsTokenNVX {
+ VkIndirectCommandsTokenTypeNVX tokenType;
+ VkBuffer buffer;
+ VkDeviceSize offset;
+} VkIndirectCommandsTokenNVX;
+
+typedef struct VkIndirectCommandsLayoutTokenNVX {
+ VkIndirectCommandsTokenTypeNVX tokenType;
+ uint32_t bindingUnit;
+ uint32_t dynamicCount;
+ uint32_t divisor;
+} VkIndirectCommandsLayoutTokenNVX;
+
+typedef struct VkIndirectCommandsLayoutCreateInfoNVX {
+ VkStructureType sType;
+ const void* pNext;
+ VkPipelineBindPoint pipelineBindPoint;
+ VkIndirectCommandsLayoutUsageFlagsNVX flags;
+ uint32_t tokenCount;
+ const VkIndirectCommandsLayoutTokenNVX* pTokens;
+} VkIndirectCommandsLayoutCreateInfoNVX;
+
+typedef struct VkCmdProcessCommandsInfoNVX {
+ VkStructureType sType;
+ const void* pNext;
+ VkObjectTableNVX objectTable;
+ VkIndirectCommandsLayoutNVX indirectCommandsLayout;
+ uint32_t indirectCommandsTokenCount;
+ const VkIndirectCommandsTokenNVX* pIndirectCommandsTokens;
+ uint32_t maxSequencesCount;
+ VkCommandBuffer targetCommandBuffer;
+ VkBuffer sequencesCountBuffer;
+ VkDeviceSize sequencesCountOffset;
+ VkBuffer sequencesIndexBuffer;
+ VkDeviceSize sequencesIndexOffset;
+} VkCmdProcessCommandsInfoNVX;
+
+typedef struct VkCmdReserveSpaceForCommandsInfoNVX {
+ VkStructureType sType;
+ const void* pNext;
+ VkObjectTableNVX objectTable;
+ VkIndirectCommandsLayoutNVX indirectCommandsLayout;
+ uint32_t maxSequencesCount;
+} VkCmdReserveSpaceForCommandsInfoNVX;
+
+typedef struct VkObjectTableCreateInfoNVX {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t objectCount;
+ const VkObjectEntryTypeNVX* pObjectEntryTypes;
+ const uint32_t* pObjectEntryCounts;
+ const VkObjectEntryUsageFlagsNVX* pObjectEntryUsageFlags;
+ uint32_t maxUniformBuffersPerDescriptor;
+ uint32_t maxStorageBuffersPerDescriptor;
+ uint32_t maxStorageImagesPerDescriptor;
+ uint32_t maxSampledImagesPerDescriptor;
+ uint32_t maxPipelineLayouts;
+} VkObjectTableCreateInfoNVX;
+
+typedef struct VkObjectTableEntryNVX {
+ VkObjectEntryTypeNVX type;
+ VkObjectEntryUsageFlagsNVX flags;
+} VkObjectTableEntryNVX;
+
+typedef struct VkObjectTablePipelineEntryNVX {
+ VkObjectEntryTypeNVX type;
+ VkObjectEntryUsageFlagsNVX flags;
+ VkPipeline pipeline;
+} VkObjectTablePipelineEntryNVX;
+
+typedef struct VkObjectTableDescriptorSetEntryNVX {
+ VkObjectEntryTypeNVX type;
+ VkObjectEntryUsageFlagsNVX flags;
+ VkPipelineLayout pipelineLayout;
+ VkDescriptorSet descriptorSet;
+} VkObjectTableDescriptorSetEntryNVX;
+
+typedef struct VkObjectTableVertexBufferEntryNVX {
+ VkObjectEntryTypeNVX type;
+ VkObjectEntryUsageFlagsNVX flags;
+ VkBuffer buffer;
+} VkObjectTableVertexBufferEntryNVX;
+
+typedef struct VkObjectTableIndexBufferEntryNVX {
+ VkObjectEntryTypeNVX type;
+ VkObjectEntryUsageFlagsNVX flags;
+ VkBuffer buffer;
+ VkIndexType indexType;
+} VkObjectTableIndexBufferEntryNVX;
+
+typedef struct VkObjectTablePushConstantEntryNVX {
+ VkObjectEntryTypeNVX type;
+ VkObjectEntryUsageFlagsNVX flags;
+ VkPipelineLayout pipelineLayout;
+ VkShaderStageFlags stageFlags;
+} VkObjectTablePushConstantEntryNVX;
+
+
+typedef void (VKAPI_PTR *PFN_vkCmdProcessCommandsNVX)(VkCommandBuffer commandBuffer, const VkCmdProcessCommandsInfoNVX* pProcessCommandsInfo);
+typedef void (VKAPI_PTR *PFN_vkCmdReserveSpaceForCommandsNVX)(VkCommandBuffer commandBuffer, const VkCmdReserveSpaceForCommandsInfoNVX* pReserveSpaceInfo);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateIndirectCommandsLayoutNVX)(VkDevice device, const VkIndirectCommandsLayoutCreateInfoNVX* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkIndirectCommandsLayoutNVX* pIndirectCommandsLayout);
+typedef void (VKAPI_PTR *PFN_vkDestroyIndirectCommandsLayoutNVX)(VkDevice device, VkIndirectCommandsLayoutNVX indirectCommandsLayout, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkCreateObjectTableNVX)(VkDevice device, const VkObjectTableCreateInfoNVX* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkObjectTableNVX* pObjectTable);
+typedef void (VKAPI_PTR *PFN_vkDestroyObjectTableNVX)(VkDevice device, VkObjectTableNVX objectTable, const VkAllocationCallbacks* pAllocator);
+typedef VkResult (VKAPI_PTR *PFN_vkRegisterObjectsNVX)(VkDevice device, VkObjectTableNVX objectTable, uint32_t objectCount, const VkObjectTableEntryNVX* const* ppObjectTableEntries, const uint32_t* pObjectIndices);
+typedef VkResult (VKAPI_PTR *PFN_vkUnregisterObjectsNVX)(VkDevice device, VkObjectTableNVX objectTable, uint32_t objectCount, const VkObjectEntryTypeNVX* pObjectEntryTypes, const uint32_t* pObjectIndices);
+typedef void (VKAPI_PTR *PFN_vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX)(VkPhysicalDevice physicalDevice, VkDeviceGeneratedCommandsFeaturesNVX* pFeatures, VkDeviceGeneratedCommandsLimitsNVX* pLimits);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkCmdProcessCommandsNVX(
+ VkCommandBuffer commandBuffer,
+ const VkCmdProcessCommandsInfoNVX* pProcessCommandsInfo);
+
+VKAPI_ATTR void VKAPI_CALL vkCmdReserveSpaceForCommandsNVX(
+ VkCommandBuffer commandBuffer,
+ const VkCmdReserveSpaceForCommandsInfoNVX* pReserveSpaceInfo);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateIndirectCommandsLayoutNVX(
+ VkDevice device,
+ const VkIndirectCommandsLayoutCreateInfoNVX* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkIndirectCommandsLayoutNVX* pIndirectCommandsLayout);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyIndirectCommandsLayoutNVX(
+ VkDevice device,
+ VkIndirectCommandsLayoutNVX indirectCommandsLayout,
+ const VkAllocationCallbacks* pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateObjectTableNVX(
+ VkDevice device,
+ const VkObjectTableCreateInfoNVX* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkObjectTableNVX* pObjectTable);
+
+VKAPI_ATTR void VKAPI_CALL vkDestroyObjectTableNVX(
+ VkDevice device,
+ VkObjectTableNVX objectTable,
+ const VkAllocationCallbacks* pAllocator);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkRegisterObjectsNVX(
+ VkDevice device,
+ VkObjectTableNVX objectTable,
+ uint32_t objectCount,
+ const VkObjectTableEntryNVX* const* ppObjectTableEntries,
+ const uint32_t* pObjectIndices);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkUnregisterObjectsNVX(
+ VkDevice device,
+ VkObjectTableNVX objectTable,
+ uint32_t objectCount,
+ const VkObjectEntryTypeNVX* pObjectEntryTypes,
+ const uint32_t* pObjectIndices);
+
+VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX(
+ VkPhysicalDevice physicalDevice,
+ VkDeviceGeneratedCommandsFeaturesNVX* pFeatures,
+ VkDeviceGeneratedCommandsLimitsNVX* pLimits);
+#endif
+
+#define VK_NV_clip_space_w_scaling 1
+#define VK_NV_CLIP_SPACE_W_SCALING_SPEC_VERSION 1
+#define VK_NV_CLIP_SPACE_W_SCALING_EXTENSION_NAME "VK_NV_clip_space_w_scaling"
+
+typedef struct VkViewportWScalingNV {
+ float xcoeff;
+ float ycoeff;
+} VkViewportWScalingNV;
+
+typedef struct VkPipelineViewportWScalingStateCreateInfoNV {
+ VkStructureType sType;
+ const void* pNext;
+ VkBool32 viewportWScalingEnable;
+ uint32_t viewportCount;
+ const VkViewportWScalingNV* pViewportWScalings;
+} VkPipelineViewportWScalingStateCreateInfoNV;
+
+
+typedef void (VKAPI_PTR *PFN_vkCmdSetViewportWScalingNV)(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewportWScalingNV* pViewportWScalings);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkCmdSetViewportWScalingNV(
+ VkCommandBuffer commandBuffer,
+ uint32_t firstViewport,
+ uint32_t viewportCount,
+ const VkViewportWScalingNV* pViewportWScalings);
+#endif
+
+#define VK_EXT_direct_mode_display 1
+#define VK_EXT_DIRECT_MODE_DISPLAY_SPEC_VERSION 1
+#define VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME "VK_EXT_direct_mode_display"
+
+typedef VkResult (VKAPI_PTR *PFN_vkReleaseDisplayEXT)(VkPhysicalDevice physicalDevice, VkDisplayKHR display);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkReleaseDisplayEXT(
+ VkPhysicalDevice physicalDevice,
+ VkDisplayKHR display);
+#endif
+
+#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT
+#define VK_EXT_acquire_xlib_display 1
+#include <X11/extensions/Xrandr.h>
+
+#define VK_EXT_ACQUIRE_XLIB_DISPLAY_SPEC_VERSION 1
+#define VK_EXT_ACQUIRE_XLIB_DISPLAY_EXTENSION_NAME "VK_EXT_acquire_xlib_display"
+
+typedef VkResult (VKAPI_PTR *PFN_vkAcquireXlibDisplayEXT)(VkPhysicalDevice physicalDevice, Display* dpy, VkDisplayKHR display);
+typedef VkResult (VKAPI_PTR *PFN_vkGetRandROutputDisplayEXT)(VkPhysicalDevice physicalDevice, Display* dpy, RROutput rrOutput, VkDisplayKHR* pDisplay);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkAcquireXlibDisplayEXT(
+ VkPhysicalDevice physicalDevice,
+ Display* dpy,
+ VkDisplayKHR display);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetRandROutputDisplayEXT(
+ VkPhysicalDevice physicalDevice,
+ Display* dpy,
+ RROutput rrOutput,
+ VkDisplayKHR* pDisplay);
+#endif
+#endif /* VK_USE_PLATFORM_XLIB_XRANDR_EXT */
+
+#define VK_EXT_display_surface_counter 1
+#define VK_EXT_DISPLAY_SURFACE_COUNTER_SPEC_VERSION 1
+#define VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME "VK_EXT_display_surface_counter"
+
+
+typedef enum VkSurfaceCounterFlagBitsEXT {
+ VK_SURFACE_COUNTER_VBLANK_EXT = 0x00000001,
+ VK_SURFACE_COUNTER_FLAG_BITS_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkSurfaceCounterFlagBitsEXT;
+typedef VkFlags VkSurfaceCounterFlagsEXT;
+
+typedef struct VkSurfaceCapabilities2EXT {
+ VkStructureType sType;
+ void* pNext;
+ uint32_t minImageCount;
+ uint32_t maxImageCount;
+ VkExtent2D currentExtent;
+ VkExtent2D minImageExtent;
+ VkExtent2D maxImageExtent;
+ uint32_t maxImageArrayLayers;
+ VkSurfaceTransformFlagsKHR supportedTransforms;
+ VkSurfaceTransformFlagBitsKHR currentTransform;
+ VkCompositeAlphaFlagsKHR supportedCompositeAlpha;
+ VkImageUsageFlags supportedUsageFlags;
+ VkSurfaceCounterFlagsEXT supportedSurfaceCounters;
+} VkSurfaceCapabilities2EXT;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT)(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilities2EXT* pSurfaceCapabilities);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilities2EXT(
+ VkPhysicalDevice physicalDevice,
+ VkSurfaceKHR surface,
+ VkSurfaceCapabilities2EXT* pSurfaceCapabilities);
+#endif
+
+#define VK_EXT_display_control 1
+#define VK_EXT_DISPLAY_CONTROL_SPEC_VERSION 1
+#define VK_EXT_DISPLAY_CONTROL_EXTENSION_NAME "VK_EXT_display_control"
+
+
+typedef enum VkDisplayPowerStateEXT {
+ VK_DISPLAY_POWER_STATE_OFF_EXT = 0,
+ VK_DISPLAY_POWER_STATE_SUSPEND_EXT = 1,
+ VK_DISPLAY_POWER_STATE_ON_EXT = 2,
+ VK_DISPLAY_POWER_STATE_BEGIN_RANGE_EXT = VK_DISPLAY_POWER_STATE_OFF_EXT,
+ VK_DISPLAY_POWER_STATE_END_RANGE_EXT = VK_DISPLAY_POWER_STATE_ON_EXT,
+ VK_DISPLAY_POWER_STATE_RANGE_SIZE_EXT = (VK_DISPLAY_POWER_STATE_ON_EXT - VK_DISPLAY_POWER_STATE_OFF_EXT + 1),
+ VK_DISPLAY_POWER_STATE_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkDisplayPowerStateEXT;
+
+typedef enum VkDeviceEventTypeEXT {
+ VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT = 0,
+ VK_DEVICE_EVENT_TYPE_BEGIN_RANGE_EXT = VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT,
+ VK_DEVICE_EVENT_TYPE_END_RANGE_EXT = VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT,
+ VK_DEVICE_EVENT_TYPE_RANGE_SIZE_EXT = (VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT - VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT + 1),
+ VK_DEVICE_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkDeviceEventTypeEXT;
+
+typedef enum VkDisplayEventTypeEXT {
+ VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT = 0,
+ VK_DISPLAY_EVENT_TYPE_BEGIN_RANGE_EXT = VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT,
+ VK_DISPLAY_EVENT_TYPE_END_RANGE_EXT = VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT,
+ VK_DISPLAY_EVENT_TYPE_RANGE_SIZE_EXT = (VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT - VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT + 1),
+ VK_DISPLAY_EVENT_TYPE_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkDisplayEventTypeEXT;
+
+typedef struct VkDisplayPowerInfoEXT {
+ VkStructureType sType;
+ const void* pNext;
+ VkDisplayPowerStateEXT powerState;
+} VkDisplayPowerInfoEXT;
+
+typedef struct VkDeviceEventInfoEXT {
+ VkStructureType sType;
+ const void* pNext;
+ VkDeviceEventTypeEXT deviceEvent;
+} VkDeviceEventInfoEXT;
+
+typedef struct VkDisplayEventInfoEXT {
+ VkStructureType sType;
+ const void* pNext;
+ VkDisplayEventTypeEXT displayEvent;
+} VkDisplayEventInfoEXT;
+
+typedef struct VkSwapchainCounterCreateInfoEXT {
+ VkStructureType sType;
+ const void* pNext;
+ VkSurfaceCounterFlagsEXT surfaceCounters;
+} VkSwapchainCounterCreateInfoEXT;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkDisplayPowerControlEXT)(VkDevice device, VkDisplayKHR display, const VkDisplayPowerInfoEXT* pDisplayPowerInfo);
+typedef VkResult (VKAPI_PTR *PFN_vkRegisterDeviceEventEXT)(VkDevice device, const VkDeviceEventInfoEXT* pDeviceEventInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence);
+typedef VkResult (VKAPI_PTR *PFN_vkRegisterDisplayEventEXT)(VkDevice device, VkDisplayKHR display, const VkDisplayEventInfoEXT* pDisplayEventInfo, const VkAllocationCallbacks* pAllocator, VkFence* pFence);
+typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainCounterEXT)(VkDevice device, VkSwapchainKHR swapchain, VkSurfaceCounterFlagBitsEXT counter, uint64_t* pCounterValue);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkDisplayPowerControlEXT(
+ VkDevice device,
+ VkDisplayKHR display,
+ const VkDisplayPowerInfoEXT* pDisplayPowerInfo);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkRegisterDeviceEventEXT(
+ VkDevice device,
+ const VkDeviceEventInfoEXT* pDeviceEventInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkFence* pFence);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkRegisterDisplayEventEXT(
+ VkDevice device,
+ VkDisplayKHR display,
+ const VkDisplayEventInfoEXT* pDisplayEventInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkFence* pFence);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainCounterEXT(
+ VkDevice device,
+ VkSwapchainKHR swapchain,
+ VkSurfaceCounterFlagBitsEXT counter,
+ uint64_t* pCounterValue);
+#endif
+
+#define VK_GOOGLE_display_timing 1
+#define VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION 1
+#define VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME "VK_GOOGLE_display_timing"
+
+typedef struct VkRefreshCycleDurationGOOGLE {
+ uint64_t refreshDuration;
+} VkRefreshCycleDurationGOOGLE;
+
+typedef struct VkPastPresentationTimingGOOGLE {
+ uint32_t presentID;
+ uint64_t desiredPresentTime;
+ uint64_t actualPresentTime;
+ uint64_t earliestPresentTime;
+ uint64_t presentMargin;
+} VkPastPresentationTimingGOOGLE;
+
+typedef struct VkPresentTimeGOOGLE {
+ uint32_t presentID;
+ uint64_t desiredPresentTime;
+} VkPresentTimeGOOGLE;
+
+typedef struct VkPresentTimesInfoGOOGLE {
+ VkStructureType sType;
+ const void* pNext;
+ uint32_t swapchainCount;
+ const VkPresentTimeGOOGLE* pTimes;
+} VkPresentTimesInfoGOOGLE;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkGetRefreshCycleDurationGOOGLE)(VkDevice device, VkSwapchainKHR swapchain, VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties);
+typedef VkResult (VKAPI_PTR *PFN_vkGetPastPresentationTimingGOOGLE)(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pPresentationTimingCount, VkPastPresentationTimingGOOGLE* pPresentationTimings);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkGetRefreshCycleDurationGOOGLE(
+ VkDevice device,
+ VkSwapchainKHR swapchain,
+ VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties);
+
+VKAPI_ATTR VkResult VKAPI_CALL vkGetPastPresentationTimingGOOGLE(
+ VkDevice device,
+ VkSwapchainKHR swapchain,
+ uint32_t* pPresentationTimingCount,
+ VkPastPresentationTimingGOOGLE* pPresentationTimings);
+#endif
+
+#define VK_NV_sample_mask_override_coverage 1
+#define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_SPEC_VERSION 1
+#define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_EXTENSION_NAME "VK_NV_sample_mask_override_coverage"
+
+
+#define VK_NV_geometry_shader_passthrough 1
+#define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_SPEC_VERSION 1
+#define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME "VK_NV_geometry_shader_passthrough"
+
+
+#define VK_NV_viewport_array2 1
+#define VK_NV_VIEWPORT_ARRAY2_SPEC_VERSION 1
+#define VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME "VK_NV_viewport_array2"
+
+
+#define VK_NVX_multiview_per_view_attributes 1
+#define VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_SPEC_VERSION 1
+#define VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_EXTENSION_NAME "VK_NVX_multiview_per_view_attributes"
+
+typedef struct VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX {
+ VkStructureType sType;
+ void* pNext;
+ VkBool32 perViewPositionAllComponents;
+} VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX;
+
+
+
+#define VK_NV_viewport_swizzle 1
+#define VK_NV_VIEWPORT_SWIZZLE_SPEC_VERSION 1
+#define VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME "VK_NV_viewport_swizzle"
+
+
+typedef enum VkViewportCoordinateSwizzleNV {
+ VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV = 0,
+ VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_X_NV = 1,
+ VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV = 2,
+ VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Y_NV = 3,
+ VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV = 4,
+ VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Z_NV = 5,
+ VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV = 6,
+ VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV = 7,
+ VK_VIEWPORT_COORDINATE_SWIZZLE_BEGIN_RANGE_NV = VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV,
+ VK_VIEWPORT_COORDINATE_SWIZZLE_END_RANGE_NV = VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV,
+ VK_VIEWPORT_COORDINATE_SWIZZLE_RANGE_SIZE_NV = (VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV - VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV + 1),
+ VK_VIEWPORT_COORDINATE_SWIZZLE_MAX_ENUM_NV = 0x7FFFFFFF
+} VkViewportCoordinateSwizzleNV;
+
+typedef VkFlags VkPipelineViewportSwizzleStateCreateFlagsNV;
+
+typedef struct VkViewportSwizzleNV {
+ VkViewportCoordinateSwizzleNV x;
+ VkViewportCoordinateSwizzleNV y;
+ VkViewportCoordinateSwizzleNV z;
+ VkViewportCoordinateSwizzleNV w;
+} VkViewportSwizzleNV;
+
+typedef struct VkPipelineViewportSwizzleStateCreateInfoNV {
+ VkStructureType sType;
+ const void* pNext;
+ VkPipelineViewportSwizzleStateCreateFlagsNV flags;
+ uint32_t viewportCount;
+ const VkViewportSwizzleNV* pViewportSwizzles;
+} VkPipelineViewportSwizzleStateCreateInfoNV;
+
+
+
+#define VK_EXT_discard_rectangles 1
+#define VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION 1
+#define VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME "VK_EXT_discard_rectangles"
+
+
+typedef enum VkDiscardRectangleModeEXT {
+ VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT = 0,
+ VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT = 1,
+ VK_DISCARD_RECTANGLE_MODE_BEGIN_RANGE_EXT = VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT,
+ VK_DISCARD_RECTANGLE_MODE_END_RANGE_EXT = VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT,
+ VK_DISCARD_RECTANGLE_MODE_RANGE_SIZE_EXT = (VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT - VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT + 1),
+ VK_DISCARD_RECTANGLE_MODE_MAX_ENUM_EXT = 0x7FFFFFFF
+} VkDiscardRectangleModeEXT;
+
+typedef VkFlags VkPipelineDiscardRectangleStateCreateFlagsEXT;
+
+typedef struct VkPhysicalDeviceDiscardRectanglePropertiesEXT {
+ VkStructureType sType;
+ void* pNext;
+ uint32_t maxDiscardRectangles;
+} VkPhysicalDeviceDiscardRectanglePropertiesEXT;
+
+typedef struct VkPipelineDiscardRectangleStateCreateInfoEXT {
+ VkStructureType sType;
+ const void* pNext;
+ VkPipelineDiscardRectangleStateCreateFlagsEXT flags;
+ VkDiscardRectangleModeEXT discardRectangleMode;
+ uint32_t discardRectangleCount;
+ const VkRect2D* pDiscardRectangles;
+} VkPipelineDiscardRectangleStateCreateInfoEXT;
+
+
+typedef void (VKAPI_PTR *PFN_vkCmdSetDiscardRectangleEXT)(VkCommandBuffer commandBuffer, uint32_t firstDiscardRectangle, uint32_t discardRectangleCount, const VkRect2D* pDiscardRectangles);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkCmdSetDiscardRectangleEXT(
+ VkCommandBuffer commandBuffer,
+ uint32_t firstDiscardRectangle,
+ uint32_t discardRectangleCount,
+ const VkRect2D* pDiscardRectangles);
+#endif
+
+#define VK_EXT_swapchain_colorspace 1
+#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 2
+#define VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace"
+
+
+#define VK_EXT_hdr_metadata 1
+#define VK_EXT_HDR_METADATA_SPEC_VERSION 1
+#define VK_EXT_HDR_METADATA_EXTENSION_NAME "VK_EXT_hdr_metadata"
+
+typedef struct VkXYColorEXT {
+ float x;
+ float y;
+} VkXYColorEXT;
+
+typedef struct VkHdrMetadataEXT {
+ VkStructureType sType;
+ const void* pNext;
+ VkXYColorEXT displayPrimaryRed;
+ VkXYColorEXT displayPrimaryGreen;
+ VkXYColorEXT displayPrimaryBlue;
+ VkXYColorEXT whitePoint;
+ float maxLuminance;
+ float minLuminance;
+ float maxContentLightLevel;
+ float maxFrameAverageLightLevel;
+} VkHdrMetadataEXT;
+
+
+typedef void (VKAPI_PTR *PFN_vkSetHdrMetadataEXT)(VkDevice device, uint32_t swapchainCount, const VkSwapchainKHR* pSwapchains, const VkHdrMetadataEXT* pMetadata);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkSetHdrMetadataEXT(
+ VkDevice device,
+ uint32_t swapchainCount,
+ const VkSwapchainKHR* pSwapchains,
+ const VkHdrMetadataEXT* pMetadata);
+#endif
+
+#ifdef VK_USE_PLATFORM_IOS_MVK
+#define VK_MVK_ios_surface 1
+#define VK_MVK_IOS_SURFACE_SPEC_VERSION 2
+#define VK_MVK_IOS_SURFACE_EXTENSION_NAME "VK_MVK_ios_surface"
+
+typedef VkFlags VkIOSSurfaceCreateFlagsMVK;
+
+typedef struct VkIOSSurfaceCreateInfoMVK {
+ VkStructureType sType;
+ const void* pNext;
+ VkIOSSurfaceCreateFlagsMVK flags;
+ const void* pView;
+} VkIOSSurfaceCreateInfoMVK;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkCreateIOSSurfaceMVK)(VkInstance instance, const VkIOSSurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateIOSSurfaceMVK(
+ VkInstance instance,
+ const VkIOSSurfaceCreateInfoMVK* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkSurfaceKHR* pSurface);
+#endif
+#endif /* VK_USE_PLATFORM_IOS_MVK */
+
+#ifdef VK_USE_PLATFORM_MACOS_MVK
+#define VK_MVK_macos_surface 1
+#define VK_MVK_MACOS_SURFACE_SPEC_VERSION 2
+#define VK_MVK_MACOS_SURFACE_EXTENSION_NAME "VK_MVK_macos_surface"
+
+typedef VkFlags VkMacOSSurfaceCreateFlagsMVK;
+
+typedef struct VkMacOSSurfaceCreateInfoMVK {
+ VkStructureType sType;
+ const void* pNext;
+ VkMacOSSurfaceCreateFlagsMVK flags;
+ const void* pView;
+} VkMacOSSurfaceCreateInfoMVK;
+
+
+typedef VkResult (VKAPI_PTR *PFN_vkCreateMacOSSurfaceMVK)(VkInstance instance, const VkMacOSSurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR VkResult VKAPI_CALL vkCreateMacOSSurfaceMVK(
+ VkInstance instance,
+ const VkMacOSSurfaceCreateInfoMVK* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkSurfaceKHR* pSurface);
+#endif
+#endif /* VK_USE_PLATFORM_MACOS_MVK */
+
#ifdef __cplusplus
}
#endif
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
new file mode 100644
index 0000000..e1f164a
--- /dev/null
+++ b/vulkan/libvulkan/Android.bp
@@ -0,0 +1,81 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Headers module is in frameworks/native/vulkan/Android.bp.
+ndk_library {
+ name: "libvulkan",
+ symbol_file: "libvulkan.map.txt",
+ first_version: "24",
+ unversioned_until: "current",
+}
+
+cc_library_shared {
+ name: "libvulkan",
+ clang: true,
+ sanitize: {
+ misc_undefined: ["integer"],
+ },
+
+ cflags: [
+ "-DLOG_TAG=\"vulkan\"",
+ "-DVK_USE_PLATFORM_ANDROID_KHR",
+ "-DVK_NO_PROTOTYPES",
+ "-fvisibility=hidden",
+ "-fstrict-aliasing",
+ "-Weverything",
+ "-Werror",
+ "-Wno-padded",
+ "-Wno-switch-enum",
+ "-Wno-undef",
+
+ //"-DLOG_NDEBUG=0",
+ ],
+
+ cppflags: [
+ "-std=c++14",
+ "-Wno-c99-extensions",
+ "-Wno-c++98-compat-pedantic",
+ "-Wno-exit-time-destructors",
+ "-Wno-global-constructors",
+ "-Wno-zero-length-array",
+ ],
+
+ srcs: [
+ "api.cpp",
+ "api_gen.cpp",
+ "debug_report.cpp",
+ "driver.cpp",
+ "driver_gen.cpp",
+ "layers_extensions.cpp",
+ "stubhal.cpp",
+ "swapchain.cpp",
+ "vulkan_loader_data.cpp",
+ ],
+
+ export_static_lib_headers: ["vulkan_headers"],
+ static_libs: [
+ "vulkan_headers",
+ "libziparchive",
+ ],
+ shared_libs: [
+ "libgui",
+ "libhardware",
+ "libsync",
+ "libbase",
+ "liblog",
+ "libutils",
+ "libcutils",
+ "libz",
+ ],
+}
diff --git a/vulkan/libvulkan/Android.mk b/vulkan/libvulkan/Android.mk
deleted file mode 100644
index b7d6791..0000000
--- a/vulkan/libvulkan/Android.mk
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_CLANG := true
-LOCAL_SANITIZE := integer
-
-LOCAL_CFLAGS := -DLOG_TAG=\"vulkan\" \
- -DVK_USE_PLATFORM_ANDROID_KHR \
- -DVK_NO_PROTOTYPES \
- -std=c99 -fvisibility=hidden -fstrict-aliasing \
- -Weverything -Werror \
- -Wno-padded \
- -Wno-switch-enum \
- -Wno-undef
-#LOCAL_CFLAGS += -DLOG_NDEBUG=0
-LOCAL_CPPFLAGS := -std=c++14 \
- -Wno-c99-extensions \
- -Wno-c++98-compat-pedantic \
- -Wno-exit-time-destructors \
- -Wno-global-constructors \
- -Wno-zero-length-array
-
-LOCAL_C_INCLUDES := \
- frameworks/native/vulkan/include \
- system/core/libsync/include
-
-LOCAL_SRC_FILES := \
- api.cpp \
- api_gen.cpp \
- debug_report.cpp \
- driver.cpp \
- driver_gen.cpp \
- layers_extensions.cpp \
- stubhal.cpp \
- swapchain.cpp \
- vulkan_loader_data.cpp
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_STATIC_LIBRARIES := libziparchive
-LOCAL_SHARED_LIBRARIES := libgui libhardware libsync libbase liblog libutils libcutils libz
-
-LOCAL_MODULE := libvulkan
-include $(BUILD_SHARED_LIBRARY)
diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp
index b699fe9..36755a2 100644
--- a/vulkan/libvulkan/api.cpp
+++ b/vulkan/libvulkan/api.cpp
@@ -23,10 +23,12 @@
#include <stdlib.h>
#include <string.h>
+
#include <algorithm>
#include <mutex>
#include <new>
#include <utility>
+
#include <cutils/properties.h>
#include <log/log.h>
diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp
index 0a1dda2..ea6fadc 100644
--- a/vulkan/libvulkan/api_gen.cpp
+++ b/vulkan/libvulkan/api_gen.cpp
@@ -17,7 +17,9 @@
// WARNING: This file is generated. See ../README.md for instructions.
#include <string.h>
+
#include <algorithm>
+
#include <log/log.h>
// to catch mismatches between vulkan.h and this file
@@ -108,7 +110,7 @@
// clang-format on
-} // anonymous
+} // namespace
bool InitDispatchTable(
VkInstance instance,
@@ -387,14 +389,14 @@
VKAPI_ATTR void CmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance);
VKAPI_ATTR void CmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride);
VKAPI_ATTR void CmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride);
-VKAPI_ATTR void CmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z);
+VKAPI_ATTR void CmdDispatch(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
VKAPI_ATTR void CmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset);
VKAPI_ATTR void CmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy* pRegions);
VKAPI_ATTR void CmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy* pRegions);
VKAPI_ATTR void CmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter);
VKAPI_ATTR void CmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions);
VKAPI_ATTR void CmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions);
-VKAPI_ATTR void CmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const uint32_t* pData);
+VKAPI_ATTR void CmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData);
VKAPI_ATTR void CmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data);
VKAPI_ATTR void CmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges);
VKAPI_ATTR void CmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange* pRanges);
@@ -449,15 +451,28 @@
"vkEnumerateDeviceLayerProperties",
"vkEnumerateInstanceExtensionProperties",
"vkEnumerateInstanceLayerProperties",
+ "vkEnumeratePhysicalDeviceGroupsKHX",
"vkEnumeratePhysicalDevices",
"vkGetInstanceProcAddr",
+ "vkGetPhysicalDeviceExternalBufferPropertiesKHX",
+ "vkGetPhysicalDeviceExternalImageFormatPropertiesNV",
+ "vkGetPhysicalDeviceExternalSemaphorePropertiesKHX",
"vkGetPhysicalDeviceFeatures",
+ "vkGetPhysicalDeviceFeatures2KHR",
"vkGetPhysicalDeviceFormatProperties",
+ "vkGetPhysicalDeviceFormatProperties2KHR",
+ "vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX",
"vkGetPhysicalDeviceImageFormatProperties",
+ "vkGetPhysicalDeviceImageFormatProperties2KHR",
"vkGetPhysicalDeviceMemoryProperties",
+ "vkGetPhysicalDeviceMemoryProperties2KHR",
+ "vkGetPhysicalDevicePresentRectanglesKHX",
"vkGetPhysicalDeviceProperties",
+ "vkGetPhysicalDeviceProperties2KHR",
"vkGetPhysicalDeviceQueueFamilyProperties",
+ "vkGetPhysicalDeviceQueueFamilyProperties2KHR",
"vkGetPhysicalDeviceSparseImageFormatProperties",
+ "vkGetPhysicalDeviceSparseImageFormatProperties2KHR",
"vkGetPhysicalDeviceSurfaceCapabilitiesKHR",
"vkGetPhysicalDeviceSurfaceFormatsKHR",
"vkGetPhysicalDeviceSurfacePresentModesKHR",
@@ -1047,8 +1062,8 @@
GetData(commandBuffer).dispatch.CmdDrawIndexedIndirect(commandBuffer, buffer, offset, drawCount, stride);
}
-VKAPI_ATTR void CmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z) {
- GetData(commandBuffer).dispatch.CmdDispatch(commandBuffer, x, y, z);
+VKAPI_ATTR void CmdDispatch(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) {
+ GetData(commandBuffer).dispatch.CmdDispatch(commandBuffer, groupCountX, groupCountY, groupCountZ);
}
VKAPI_ATTR void CmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset) {
@@ -1075,7 +1090,7 @@
GetData(commandBuffer).dispatch.CmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions);
}
-VKAPI_ATTR void CmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const uint32_t* pData) {
+VKAPI_ATTR void CmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData) {
GetData(commandBuffer).dispatch.CmdUpdateBuffer(commandBuffer, dstBuffer, dstOffset, dataSize, pData);
}
@@ -1760,8 +1775,8 @@
}
__attribute__((visibility("default")))
-VKAPI_ATTR void vkCmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z) {
- vulkan::api::CmdDispatch(commandBuffer, x, y, z);
+VKAPI_ATTR void vkCmdDispatch(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) {
+ vulkan::api::CmdDispatch(commandBuffer, groupCountX, groupCountY, groupCountZ);
}
__attribute__((visibility("default")))
@@ -1795,7 +1810,7 @@
}
__attribute__((visibility("default")))
-VKAPI_ATTR void vkCmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const uint32_t* pData) {
+VKAPI_ATTR void vkCmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData) {
vulkan::api::CmdUpdateBuffer(commandBuffer, dstBuffer, dstOffset, dataSize, pData);
}
diff --git a/vulkan/libvulkan/api_gen.h b/vulkan/libvulkan/api_gen.h
index 7f8d274..3e50fda 100644
--- a/vulkan/libvulkan/api_gen.h
+++ b/vulkan/libvulkan/api_gen.h
@@ -19,8 +19,8 @@
#ifndef LIBVULKAN_API_GEN_H
#define LIBVULKAN_API_GEN_H
-#include <bitset>
#include <vulkan/vulkan.h>
+#include <bitset>
#include "driver_gen.h"
namespace vulkan {
diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl
index f9a4670..b5d51c6 100644
--- a/vulkan/libvulkan/code-generator.tmpl
+++ b/vulkan/libvulkan/code-generator.tmpl
@@ -91,7 +91,9 @@
// WARNING: This file is generated. See ../README.md for instructions.
¶
#include <string.h>
+¶
#include <algorithm>
+¶
#include <log/log.h>
¶
// to catch mismatches between vulkan.h and this file
@@ -270,7 +272,9 @@
// WARNING: This file is generated. See ../README.md for instructions.
¶
#include <string.h>
+¶
#include <algorithm>
+¶
#include <log/log.h>
¶
#include "driver.h"
@@ -1105,11 +1109,23 @@
{{$ext := index $.Arguments 0}}
{{ if eq $ext "VK_KHR_display"}}true
{{else if eq $ext "VK_KHR_display_swapchain"}}true
- {{else if eq $ext "VK_KHR_xlib_surface"}}true
- {{else if eq $ext "VK_KHR_xcb_surface"}}true
- {{else if eq $ext "VK_KHR_wayland_surface"}}true
{{else if eq $ext "VK_KHR_mir_surface"}}true
+ {{else if eq $ext "VK_KHR_xcb_surface"}}true
+ {{else if eq $ext "VK_KHR_xlib_surface"}}true
+ {{else if eq $ext "VK_KHR_wayland_surface"}}true
{{else if eq $ext "VK_KHR_win32_surface"}}true
+ {{else if eq $ext "VK_KHX_external_memory_win32"}}true
+ {{else if eq $ext "VK_KHX_win32_keyed_mutex"}}true
+ {{else if eq $ext "VK_KHX_external_semaphore_win32"}}true
+ {{else if eq $ext "VK_EXT_acquire_xlib_display"}}true
+ {{else if eq $ext "VK_EXT_direct_mode_display"}}true
+ {{else if eq $ext "VK_EXT_display_surface_counter"}}true
+ {{else if eq $ext "VK_EXT_display_control"}}true
+ {{else if eq $ext "VK_MVK_ios_surface"}}true
+ {{else if eq $ext "VK_MVK_macos_surface"}}true
+ {{else if eq $ext "VK_NN_vi_surface"}}true
+ {{else if eq $ext "VK_NV_external_memory_win32"}}true
+ {{else if eq $ext "VK_NV_win32_keyed_mutex"}}true
{{end}}
{{end}}
diff --git a/vulkan/libvulkan/debug_report.h b/vulkan/libvulkan/debug_report.h
index be9b645..3d8bd50 100644
--- a/vulkan/libvulkan/debug_report.h
+++ b/vulkan/libvulkan/debug_report.h
@@ -85,9 +85,9 @@
class DebugReportLogger {
public:
- DebugReportLogger(const VkInstanceCreateInfo& info)
+ explicit DebugReportLogger(const VkInstanceCreateInfo& info)
: instance_pnext_(info.pNext), callbacks_(nullptr) {}
- DebugReportLogger(const DebugReportCallbackList& callbacks)
+ explicit DebugReportLogger(const DebugReportCallbackList& callbacks)
: instance_pnext_(nullptr), callbacks_(&callbacks) {}
void Message(VkDebugReportFlagsEXT flags,
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 741a0ce..f9d3de1 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -14,14 +14,17 @@
* limitations under the License.
*/
+#include <malloc.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/prctl.h>
+
#include <algorithm>
#include <array>
#include <dlfcn.h>
#include <new>
-#include <malloc.h>
-#include <sys/prctl.h>
+
+#include <log/log.h>
#include <android/dlext.h>
#include <cutils/properties.h>
diff --git a/vulkan/libvulkan/driver.h b/vulkan/libvulkan/driver.h
index a02ebd7..e058439 100644
--- a/vulkan/libvulkan/driver.h
+++ b/vulkan/libvulkan/driver.h
@@ -18,8 +18,10 @@
#define LIBVULKAN_DRIVER_H 1
#include <inttypes.h>
+
#include <bitset>
#include <type_traits>
+
#include <log/log.h>
#include <vulkan/vulkan.h>
@@ -61,7 +63,7 @@
VK_DEFINE_HANDLE(DeviceDispatchable)
struct InstanceData {
- InstanceData(const VkAllocationCallbacks& alloc)
+ explicit InstanceData(const VkAllocationCallbacks& alloc)
: opaque_api_data(),
allocator(alloc),
driver(),
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
index d979a34..e9cbceb 100644
--- a/vulkan/libvulkan/driver_gen.cpp
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -17,7 +17,9 @@
// WARNING: This file is generated. See ../README.md for instructions.
#include <string.h>
+
#include <algorithm>
+
#include <log/log.h>
#include "driver.h"
@@ -276,7 +278,7 @@
// clang-format on
};
-} // anonymous
+} // namespace
const ProcHook* GetProcHook(const char* name) {
const auto& begin = g_proc_hooks;
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index a60b2fe..a54e89d 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -19,9 +19,9 @@
#ifndef LIBVULKAN_DRIVER_GEN_H
#define LIBVULKAN_DRIVER_GEN_H
-#include <bitset>
-#include <vulkan/vulkan.h>
#include <vulkan/vk_android_native_buffer.h>
+#include <vulkan/vulkan.h>
+#include <bitset>
namespace vulkan {
namespace driver {
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index 82169ff..6e44126 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -19,14 +19,15 @@
#include <alloca.h>
#include <dirent.h>
#include <dlfcn.h>
-#include <mutex>
-#include <sys/prctl.h>
-#include <string>
#include <string.h>
+#include <sys/prctl.h>
+
+#include <mutex>
+#include <string>
#include <vector>
-#include <android-base/strings.h>
#include <android/dlext.h>
+#include <android-base/strings.h>
#include <cutils/properties.h>
#include <log/log.h>
#include <ziparchive/zip_archive.h>
diff --git a/vulkan/libvulkan/layers_extensions.h b/vulkan/libvulkan/layers_extensions.h
index 79fe59d..07ac1a3 100644
--- a/vulkan/libvulkan/layers_extensions.h
+++ b/vulkan/libvulkan/layers_extensions.h
@@ -26,7 +26,7 @@
class LayerRef {
public:
- LayerRef(const Layer* layer);
+ explicit LayerRef(const Layer* layer);
LayerRef(LayerRef&& other);
~LayerRef();
LayerRef(const LayerRef&) = delete;
diff --git a/vulkan/libvulkan/libvulkan.map.txt b/vulkan/libvulkan/libvulkan.map.txt
new file mode 100644
index 0000000..1745925
--- /dev/null
+++ b/vulkan/libvulkan/libvulkan.map.txt
@@ -0,0 +1,153 @@
+LIBVULKAN {
+ global:
+ vkAcquireNextImageKHR;
+ vkAllocateCommandBuffers;
+ vkAllocateDescriptorSets;
+ vkAllocateMemory;
+ vkBeginCommandBuffer;
+ vkBindBufferMemory;
+ vkBindImageMemory;
+ vkCmdBeginQuery;
+ vkCmdBeginRenderPass;
+ vkCmdBindDescriptorSets;
+ vkCmdBindIndexBuffer;
+ vkCmdBindPipeline;
+ vkCmdBindVertexBuffers;
+ vkCmdBlitImage;
+ vkCmdClearAttachments;
+ vkCmdClearColorImage;
+ vkCmdClearDepthStencilImage;
+ vkCmdCopyBuffer;
+ vkCmdCopyBufferToImage;
+ vkCmdCopyImage;
+ vkCmdCopyImageToBuffer;
+ vkCmdCopyQueryPoolResults;
+ vkCmdDispatch;
+ vkCmdDispatchIndirect;
+ vkCmdDraw;
+ vkCmdDrawIndexed;
+ vkCmdDrawIndexedIndirect;
+ vkCmdDrawIndirect;
+ vkCmdEndQuery;
+ vkCmdEndRenderPass;
+ vkCmdExecuteCommands;
+ vkCmdFillBuffer;
+ vkCmdNextSubpass;
+ vkCmdPipelineBarrier;
+ vkCmdPushConstants;
+ vkCmdResetEvent;
+ vkCmdResetQueryPool;
+ vkCmdResolveImage;
+ vkCmdSetBlendConstants;
+ vkCmdSetDepthBias;
+ vkCmdSetDepthBounds;
+ vkCmdSetEvent;
+ vkCmdSetLineWidth;
+ vkCmdSetScissor;
+ vkCmdSetStencilCompareMask;
+ vkCmdSetStencilReference;
+ vkCmdSetStencilWriteMask;
+ vkCmdSetViewport;
+ vkCmdUpdateBuffer;
+ vkCmdWaitEvents;
+ vkCmdWriteTimestamp;
+ vkCreateAndroidSurfaceKHR;
+ vkCreateBuffer;
+ vkCreateBufferView;
+ vkCreateCommandPool;
+ vkCreateComputePipelines;
+ vkCreateDescriptorPool;
+ vkCreateDescriptorSetLayout;
+ vkCreateDevice;
+ vkCreateEvent;
+ vkCreateFence;
+ vkCreateFramebuffer;
+ vkCreateGraphicsPipelines;
+ vkCreateImage;
+ vkCreateImageView;
+ vkCreateInstance;
+ vkCreatePipelineCache;
+ vkCreatePipelineLayout;
+ vkCreateQueryPool;
+ vkCreateRenderPass;
+ vkCreateSampler;
+ vkCreateSemaphore;
+ vkCreateShaderModule;
+ vkCreateSwapchainKHR;
+ vkDestroyBuffer;
+ vkDestroyBufferView;
+ vkDestroyCommandPool;
+ vkDestroyDescriptorPool;
+ vkDestroyDescriptorSetLayout;
+ vkDestroyDevice;
+ vkDestroyEvent;
+ vkDestroyFence;
+ vkDestroyFramebuffer;
+ vkDestroyImage;
+ vkDestroyImageView;
+ vkDestroyInstance;
+ vkDestroyPipeline;
+ vkDestroyPipelineCache;
+ vkDestroyPipelineLayout;
+ vkDestroyQueryPool;
+ vkDestroyRenderPass;
+ vkDestroySampler;
+ vkDestroySemaphore;
+ vkDestroyShaderModule;
+ vkDestroySurfaceKHR;
+ vkDestroySwapchainKHR;
+ vkDeviceWaitIdle;
+ vkEndCommandBuffer;
+ vkEnumerateDeviceExtensionProperties;
+ vkEnumerateDeviceLayerProperties;
+ vkEnumerateInstanceExtensionProperties;
+ vkEnumerateInstanceLayerProperties;
+ vkEnumeratePhysicalDevices;
+ vkFlushMappedMemoryRanges;
+ vkFreeCommandBuffers;
+ vkFreeDescriptorSets;
+ vkFreeMemory;
+ vkGetBufferMemoryRequirements;
+ vkGetDeviceMemoryCommitment;
+ vkGetDeviceProcAddr;
+ vkGetDeviceQueue;
+ vkGetEventStatus;
+ vkGetFenceStatus;
+ vkGetImageMemoryRequirements;
+ vkGetImageSparseMemoryRequirements;
+ vkGetImageSubresourceLayout;
+ vkGetInstanceProcAddr;
+ vkGetPhysicalDeviceFeatures;
+ vkGetPhysicalDeviceFormatProperties;
+ vkGetPhysicalDeviceImageFormatProperties;
+ vkGetPhysicalDeviceMemoryProperties;
+ vkGetPhysicalDeviceProperties;
+ vkGetPhysicalDeviceQueueFamilyProperties;
+ vkGetPhysicalDeviceSparseImageFormatProperties;
+ vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
+ vkGetPhysicalDeviceSurfaceFormatsKHR;
+ vkGetPhysicalDeviceSurfacePresentModesKHR;
+ vkGetPhysicalDeviceSurfaceSupportKHR;
+ vkGetPipelineCacheData;
+ vkGetQueryPoolResults;
+ vkGetRenderAreaGranularity;
+ vkGetSwapchainImagesKHR;
+ vkInvalidateMappedMemoryRanges;
+ vkMapMemory;
+ vkMergePipelineCaches;
+ vkQueueBindSparse;
+ vkQueuePresentKHR;
+ vkQueueSubmit;
+ vkQueueWaitIdle;
+ vkResetCommandBuffer;
+ vkResetCommandPool;
+ vkResetDescriptorPool;
+ vkResetEvent;
+ vkResetFences;
+ vkSetEvent;
+ vkUnmapMemory;
+ vkUpdateDescriptorSets;
+ vkWaitForFences;
+ local:
+ *;
+};
diff --git a/vulkan/libvulkan/stubhal.cpp b/vulkan/libvulkan/stubhal.cpp
index a74d370..2926268 100644
--- a/vulkan/libvulkan/stubhal.cpp
+++ b/vulkan/libvulkan/stubhal.cpp
@@ -29,8 +29,10 @@
#include <array>
#include <bitset>
#include <mutex>
-#include <hardware/hwvulkan.h>
+
#include <log/log.h>
+#include <hardware/hwvulkan.h>
+
#include "stubhal.h"
namespace vulkan {
@@ -43,7 +45,7 @@
static std::bitset<kMaxInstances> g_instance_used(false);
static std::array<hwvulkan_dispatch_t, kMaxInstances> g_instances;
-[[noreturn]] void NoOp() {
+[[noreturn]] VKAPI_ATTR void NoOp() {
LOG_ALWAYS_FATAL("invalid stub function called");
}
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 03d37fa..bfe7aa7 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -16,8 +16,8 @@
#include <algorithm>
-#include <gui/BufferQueue.h>
#include <log/log.h>
+#include <gui/BufferQueue.h>
#include <sync/sync.h>
#include <utils/StrongPointer.h>
@@ -361,9 +361,11 @@
if (formats) {
if (*count < kNumFormats)
result = VK_INCOMPLETE;
- std::copy(kFormats, kFormats + std::min(*count, kNumFormats), formats);
+ *count = std::min(*count, kNumFormats);
+ std::copy(kFormats, kFormats + *count, formats);
+ } else {
+ *count = kNumFormats;
}
- *count = kNumFormats;
return result;
}
@@ -381,9 +383,11 @@
if (modes) {
if (*count < kNumModes)
result = VK_INCOMPLETE;
- std::copy(kModes, kModes + std::min(*count, kNumModes), modes);
+ *count = std::min(*count, kNumModes);
+ std::copy(kModes, kModes + *count, modes);
+ } else {
+ *count = kNumModes;
}
- *count = kNumModes;
return result;
}
@@ -753,8 +757,10 @@
}
for (uint32_t i = 0; i < n; i++)
images[i] = swapchain.images[i].image;
+ *count = n;
+ } else {
+ *count = swapchain.num_images;
}
- *count = swapchain.num_images;
return result;
}
diff --git a/vulkan/nulldrv/Android.bp b/vulkan/nulldrv/Android.bp
new file mode 100644
index 0000000..ea3b781
--- /dev/null
+++ b/vulkan/nulldrv/Android.bp
@@ -0,0 +1,47 @@
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+ // Real drivers would set this to vulkan.$(TARGET_BOARD_PLATFORM)
+ name: "vulkan.default",
+ proprietary: true,
+ relative_install_path: "hw",
+
+ clang: true,
+ cflags: [
+ "-fvisibility=hidden",
+ "-fstrict-aliasing",
+ "-DLOG_TAG=\"vknulldrv\"",
+ "-Weverything",
+ "-Werror",
+ "-Wno-padded",
+ "-Wno-undef",
+ "-Wno-zero-length-array",
+
+ "-DLOG_NDEBUG=0",
+ ],
+ cppflags: [
+ "-std=c++1y",
+ "-Wno-c++98-compat-pedantic",
+ "-Wno-c99-extensions",
+ ],
+
+ srcs: [
+ "null_driver.cpp",
+ "null_driver_gen.cpp",
+ ],
+
+ static_libs: ["vulkan_headers"],
+ shared_libs: ["liblog"],
+}
diff --git a/vulkan/nulldrv/Android.mk b/vulkan/nulldrv/Android.mk
deleted file mode 100644
index 77d4746..0000000
--- a/vulkan/nulldrv/Android.mk
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_CLANG := true
-LOCAL_CFLAGS := -std=c99 -fvisibility=hidden -fstrict-aliasing \
- -DLOG_TAG=\"vknulldrv\" \
- -Weverything -Werror \
- -Wno-padded \
- -Wno-undef \
- -Wno-zero-length-array
-#LOCAL_CFLAGS += -DLOG_NDEBUG=0
-LOCAL_CPPFLAGS := -std=c++1y \
- -Wno-c++98-compat-pedantic \
- -Wno-c99-extensions
-
-LOCAL_C_INCLUDES := \
- frameworks/native/vulkan/include
-
-LOCAL_SRC_FILES := \
- null_driver.cpp \
- null_driver_gen.cpp
-
-LOCAL_SHARED_LIBRARIES := liblog
-
-# Real drivers would set this to vulkan.$(TARGET_BOARD_PLATFORM)
-LOCAL_MODULE := vulkan.default
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/vulkan/nulldrv/null_driver.cpp b/vulkan/nulldrv/null_driver.cpp
index 3bf3ff7..e966c06 100644
--- a/vulkan/nulldrv/null_driver.cpp
+++ b/vulkan/nulldrv/null_driver.cpp
@@ -16,12 +16,13 @@
#include <hardware/hwvulkan.h>
-#include <algorithm>
-#include <array>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
+#include <algorithm>
+#include <array>
+
#include <log/log.h>
#include <utils/Errors.h>
@@ -1334,7 +1335,7 @@
void CmdCopyImageToBuffer(VkCommandBuffer cmdBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer destBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions) {
}
-void CmdUpdateBuffer(VkCommandBuffer cmdBuffer, VkBuffer destBuffer, VkDeviceSize destOffset, VkDeviceSize dataSize, const uint32_t* pData) {
+void CmdUpdateBuffer(VkCommandBuffer cmdBuffer, VkBuffer destBuffer, VkDeviceSize destOffset, VkDeviceSize dataSize, const void* pData) {
}
void CmdFillBuffer(VkCommandBuffer cmdBuffer, VkBuffer destBuffer, VkDeviceSize destOffset, VkDeviceSize fillSize, uint32_t data) {
diff --git a/vulkan/nulldrv/null_driver.tmpl b/vulkan/nulldrv/null_driver.tmpl
index 3a84971..209d61d 100644
--- a/vulkan/nulldrv/null_driver.tmpl
+++ b/vulkan/nulldrv/null_driver.tmpl
@@ -158,16 +158,7 @@
}
¶
PFN_vkVoidFunction GetInstanceProcAddr(const char* name) {«
- PFN_vkVoidFunction pfn;
- if ((pfn = Lookup(name, kInstanceProcs)))
- return pfn;
- if (strcmp(name, "vkGetSwapchainGrallocUsageANDROID") == 0)
- return reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSwapchainGrallocUsageANDROID>(GetSwapchainGrallocUsageANDROID));
- if (strcmp(name, "vkAcquireImageANDROID") == 0)
- return reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkAcquireImageANDROID>(AcquireImageANDROID));
- if (strcmp(name, "vkQueueSignalReleaseImageANDROID") == 0)
- return reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkQueueSignalReleaseImageANDROID>(QueueSignalReleaseImageANDROID));
- return nullptr;
+ return Lookup(name, kInstanceProcs);
»}
¶
} // namespace null_driver
diff --git a/vulkan/nulldrv/null_driver_gen.cpp b/vulkan/nulldrv/null_driver_gen.cpp
index 10da993..fd87161 100644
--- a/vulkan/nulldrv/null_driver_gen.cpp
+++ b/vulkan/nulldrv/null_driver_gen.cpp
@@ -16,8 +16,8 @@
// WARNING: This file is generated. See ../README.md for instructions.
-#include "null_driver_gen.h"
#include <algorithm>
+#include "null_driver_gen.h"
using namespace null_driver;
@@ -54,6 +54,7 @@
const NameProc kInstanceProcs[] = {
// clang-format off
+ {"vkAcquireImageANDROID", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkAcquireImageANDROID>(AcquireImageANDROID))},
{"vkAllocateCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkAllocateCommandBuffers>(AllocateCommandBuffers))},
{"vkAllocateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkAllocateDescriptorSets>(AllocateDescriptorSets))},
{"vkAllocateMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkAllocateMemory>(AllocateMemory))},
@@ -179,10 +180,12 @@
{"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))},
+ {"vkGetSwapchainGrallocUsageANDROID", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSwapchainGrallocUsageANDROID>(GetSwapchainGrallocUsageANDROID))},
{"vkInvalidateMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkInvalidateMappedMemoryRanges>(InvalidateMappedMemoryRanges))},
{"vkMapMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkMapMemory>(MapMemory))},
{"vkMergePipelineCaches", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkMergePipelineCaches>(MergePipelineCaches))},
{"vkQueueBindSparse", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkQueueBindSparse>(QueueBindSparse))},
+ {"vkQueueSignalReleaseImageANDROID", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkQueueSignalReleaseImageANDROID>(QueueSignalReleaseImageANDROID))},
{"vkQueueSubmit", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkQueueSubmit>(QueueSubmit))},
{"vkQueueWaitIdle", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkQueueWaitIdle>(QueueWaitIdle))},
{"vkResetCommandBuffer", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkResetCommandBuffer>(ResetCommandBuffer))},
@@ -206,21 +209,7 @@
}
PFN_vkVoidFunction GetInstanceProcAddr(const char* name) {
- PFN_vkVoidFunction pfn;
- if ((pfn = Lookup(name, kInstanceProcs)))
- return pfn;
- if (strcmp(name, "vkGetSwapchainGrallocUsageANDROID") == 0)
- return reinterpret_cast<PFN_vkVoidFunction>(
- static_cast<PFN_vkGetSwapchainGrallocUsageANDROID>(
- GetSwapchainGrallocUsageANDROID));
- if (strcmp(name, "vkAcquireImageANDROID") == 0)
- return reinterpret_cast<PFN_vkVoidFunction>(
- static_cast<PFN_vkAcquireImageANDROID>(AcquireImageANDROID));
- if (strcmp(name, "vkQueueSignalReleaseImageANDROID") == 0)
- return reinterpret_cast<PFN_vkVoidFunction>(
- static_cast<PFN_vkQueueSignalReleaseImageANDROID>(
- QueueSignalReleaseImageANDROID));
- return nullptr;
+ return Lookup(name, kInstanceProcs);
}
} // namespace null_driver
diff --git a/vulkan/nulldrv/null_driver_gen.h b/vulkan/nulldrv/null_driver_gen.h
index 98952b8..43cd45e 100644
--- a/vulkan/nulldrv/null_driver_gen.h
+++ b/vulkan/nulldrv/null_driver_gen.h
@@ -138,14 +138,14 @@
VKAPI_ATTR void CmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance);
VKAPI_ATTR void CmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride);
VKAPI_ATTR void CmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride);
-VKAPI_ATTR void CmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z);
+VKAPI_ATTR void CmdDispatch(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
VKAPI_ATTR void CmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset);
VKAPI_ATTR void CmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferCopy* pRegions);
VKAPI_ATTR void CmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageCopy* pRegions);
VKAPI_ATTR void CmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkImageBlit* pRegions, VkFilter filter);
VKAPI_ATTR void CmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, const VkBufferImageCopy* pRegions);
VKAPI_ATTR void CmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout, VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy* pRegions);
-VKAPI_ATTR void CmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const uint32_t* pData);
+VKAPI_ATTR void CmdUpdateBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize dataSize, const void* pData);
VKAPI_ATTR void CmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data);
VKAPI_ATTR void CmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue* pColor, uint32_t rangeCount, const VkImageSubresourceRange* pRanges);
VKAPI_ATTR void CmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearDepthStencilValue* pDepthStencil, uint32_t rangeCount, const VkImageSubresourceRange* pRanges);
@@ -165,6 +165,9 @@
VKAPI_ATTR void CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents);
VKAPI_ATTR void CmdEndRenderPass(VkCommandBuffer commandBuffer);
VKAPI_ATTR void CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers);
+VKAPI_ATTR VkResult GetSwapchainGrallocUsageANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int* grallocUsage);
+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 CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback);
VKAPI_ATTR void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator);
VKAPI_ATTR void DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage);
diff --git a/vulkan/tools/Android.bp b/vulkan/tools/Android.bp
new file mode 100644
index 0000000..d81d9ec
--- /dev/null
+++ b/vulkan/tools/Android.bp
@@ -0,0 +1,44 @@
+// Copyright 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_binary {
+ name: "vkinfo",
+
+ clang: true,
+ cflags: [
+ "-fvisibility=hidden",
+ "-fstrict-aliasing",
+
+ "-DLOG_TAG=\"vkinfo\"",
+
+ "-Weverything",
+ "-Werror",
+ "-Wno-padded",
+ "-Wno-undef",
+ "-Wno-switch-enum",
+ ],
+ cppflags: [
+ "-std=c++1y",
+ "-Wno-c++98-compat-pedantic",
+ "-Wno-c99-extensions",
+ "-Wno-old-style-cast",
+ ],
+
+ srcs: ["vkinfo.cpp"],
+
+ shared_libs: [
+ "libvulkan",
+ "liblog",
+ ],
+}
diff --git a/vulkan/tools/Android.mk b/vulkan/tools/Android.mk
deleted file mode 100644
index 337e683..0000000
--- a/vulkan/tools/Android.mk
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_CLANG := true
-LOCAL_CFLAGS := -std=c99 -fvisibility=hidden -fstrict-aliasing
-LOCAL_CFLAGS += -DLOG_TAG=\"vkinfo\"
-LOCAL_CFLAGS += -Weverything -Werror -Wno-padded -Wno-undef -Wno-switch-enum
-LOCAL_CPPFLAGS := -std=c++1y \
- -Wno-c++98-compat-pedantic \
- -Wno-c99-extensions \
- -Wno-old-style-cast
-
-LOCAL_C_INCLUDES := \
- frameworks/native/vulkan/include
-
-LOCAL_SRC_FILES := vkinfo.cpp
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_SHARED_LIBRARIES := libvulkan liblog
-
-LOCAL_MODULE := vkinfo
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_EXECUTABLE)
diff --git a/vulkan/tools/vkinfo.cpp b/vulkan/tools/vkinfo.cpp
index 7cf85e6..801eca8 100644
--- a/vulkan/tools/vkinfo.cpp
+++ b/vulkan/tools/vkinfo.cpp
@@ -14,18 +14,17 @@
* limitations under the License.
*/
-#include <algorithm>
-#include <array>
#include <inttypes.h>
#include <stdlib.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <array>
#include <sstream>
#include <vector>
#include <vulkan/vulkan.h>
-#define LOG_TAG "vkinfo"
-#include <log/log.h>
-
namespace {
struct Options {