Merge "Validate the size of all dex paths eagerly" into oc-dr1-dev
diff --git a/cmds/atrace/Android.bp b/cmds/atrace/Android.bp
index 5548699..abf7b06 100644
--- a/cmds/atrace/Android.bp
+++ b/cmds/atrace/Android.bp
@@ -14,6 +14,9 @@
"libz",
"libbase",
],
+ static_libs: [
+ "libpdx_default_transport",
+ ],
init_rc: ["atrace.rc"],
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index d61cbc9..2d9a98c 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -40,6 +40,7 @@
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <hidl/ServiceManagement.h>
+#include <pdx/default_transport/service_utility.h>
#include <utils/String8.h>
#include <utils/Timers.h>
#include <utils/Tokenizer.h>
@@ -50,6 +51,7 @@
#include <android-base/stringprintf.h>
using namespace android;
+using pdx::default_transport::ServiceUtility;
using std::string;
@@ -61,6 +63,7 @@
const char* k_traceAppsNumberProperty = "debug.atrace.app_number";
const char* k_traceAppsPropertyTemplate = "debug.atrace.app_%d";
const char* k_coreServiceCategory = "core_services";
+const char* k_pdxServiceCategory = "pdx";
const char* k_coreServicesProp = "ro.atrace.core.services";
typedef enum { OPT, REQ } requiredness ;
@@ -114,6 +117,7 @@
{ "network", "Network", ATRACE_TAG_NETWORK, { } },
{ "adb", "ADB", ATRACE_TAG_ADB, { } },
{ k_coreServiceCategory, "Core services", 0, { } },
+ { k_pdxServiceCategory, "PDX services", 0, { } },
{ "sched", "CPU Scheduling", 0, {
{ REQ, "events/sched/sched_switch/enable" },
{ REQ, "events/sched/sched_wakeup/enable" },
@@ -209,6 +213,7 @@
static const char* g_outputFile = nullptr;
/* Global state */
+static bool g_tracePdx = false;
static bool g_traceAborted = false;
static bool g_categoryEnables[arraysize(k_categories)] = {};
static std::string g_traceFolder;
@@ -368,6 +373,10 @@
return !android::base::GetProperty(k_coreServicesProp, "").empty();
}
+ if (strcmp(category.name, k_pdxServiceCategory) == 0) {
+ return true;
+ }
+
bool ok = category.tags != 0;
for (int i = 0; i < MAX_SYS_FILES; i++) {
const char* path = category.sysfiles[i].path;
@@ -769,7 +778,8 @@
ok &= setCategoriesEnableFromFile(g_categoriesFile);
ok &= setTraceOverwriteEnable(g_traceOverwrite);
ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
- ok &= setCmdlineSize();
+ // TODO: Re-enable after stabilization
+ //ok &= setCmdlineSize();
ok &= setClock();
ok &= setPrintTgidEnableIfPresent(true);
ok &= setKernelTraceFuncs(g_kernelTraceFuncs);
@@ -789,6 +799,11 @@
if (strcmp(k_categories[i].name, k_coreServiceCategory) == 0) {
coreServicesTagEnabled = g_categoryEnables[i];
}
+
+ // Set whether to poke PDX services in this session.
+ if (strcmp(k_categories[i].name, k_pdxServiceCategory) == 0) {
+ g_tracePdx = g_categoryEnables[i];
+ }
}
std::string packageList(g_debugAppCmdLine);
@@ -802,6 +817,10 @@
ok &= pokeBinderServices();
pokeHalServices();
+ if (g_tracePdx) {
+ ok &= ServiceUtility::PokeServices();
+ }
+
// 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();
@@ -839,6 +858,10 @@
clearAppProperties();
pokeBinderServices();
+ if (g_tracePdx) {
+ ServiceUtility::PokeServices();
+ }
+
// Set the options back to their defaults.
setTraceOverwriteEnable(true);
setTraceBufferSizeKB(1);
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 95dc8dd..4161bd7 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -123,7 +123,14 @@
static const std::string ZIP_ROOT_DIR = "FS";
// Must be hardcoded because dumpstate HAL implementation need SELinux access to it
-static const std::string kDumpstateBoardPath = "/bugreports/dumpstate_board.txt";
+static const std::string kDumpstateBoardPath = "/bugreports/";
+static const std::string kDumpstateBoardFiles[] = {
+ "dumpstate_board.txt",
+ // TODO: rename to dumpstate_board.bin once vendors can handle it
+ "modem_log_all.tar"
+};
+static const int NUM_OF_DUMPS = arraysize(kDumpstateBoardFiles);
+
static const std::string kLsHalDebugPath = "/bugreports/dumpstate_lshal.txt";
static constexpr char PROPERTY_EXTRA_OPTIONS[] = "dumpstate.options";
@@ -445,88 +452,6 @@
}
}
-/**
- * Finds the last modified file in the directory dir whose name starts with file_prefix.
- *
- * Function returns empty string when it does not find a file
- */
-static std::string GetLastModifiedFileWithPrefix(const std::string& dir,
- const std::string& file_prefix) {
- std::unique_ptr<DIR, decltype(&closedir)> d(opendir(dir.c_str()), closedir);
- if (d == nullptr) {
- MYLOGD("Error %d opening %s\n", errno, dir.c_str());
- return "";
- }
-
- // Find the newest file matching the file_prefix in dir
- struct dirent *de;
- time_t last_modified_time = 0;
- std::string last_modified_file = "";
- struct stat s;
-
- while ((de = readdir(d.get()))) {
- std::string file = std::string(de->d_name);
- if (!file_prefix.empty()) {
- if (!android::base::StartsWith(file, file_prefix.c_str())) continue;
- }
- file = dir + "/" + file;
- int ret = stat(file.c_str(), &s);
-
- if ((ret == 0) && (s.st_mtime > last_modified_time)) {
- last_modified_file = file;
- last_modified_time = s.st_mtime;
- }
- }
-
- return last_modified_file;
-}
-
-static void DumpModemLogs() {
- DurationReporter durationReporter("DUMP MODEM LOGS");
- if (PropertiesHelper::IsUserBuild()) {
- return;
- }
-
- if (!ds.IsZipping()) {
- MYLOGD("Not dumping modem logs. dumpstate is not generating a zipping bugreport\n");
- return;
- }
-
- std::string file_prefix = android::base::GetProperty("ro.radio.log_prefix", "");
-
- if(file_prefix.empty()) {
- MYLOGD("No modem log : file_prefix is empty\n");
- return;
- }
-
- // TODO: b/33820081 we need to provide a right way to dump modem logs.
- std::string radio_bugreport_dir = android::base::GetProperty("ro.radio.log_loc", "");
- if (radio_bugreport_dir.empty()) {
- radio_bugreport_dir = dirname(ds.GetPath("").c_str());
- }
-
- MYLOGD("DumpModemLogs: directory is %s and file_prefix is %s\n",
- radio_bugreport_dir.c_str(), file_prefix.c_str());
-
- std::string modem_log_file = GetLastModifiedFileWithPrefix(radio_bugreport_dir, file_prefix);
-
- struct stat s;
- if (modem_log_file.empty() || stat(modem_log_file.c_str(), &s) != 0) {
- MYLOGD("Modem log %s does not exist\n", modem_log_file.c_str());
- return;
- }
-
- std::string filename = basename(modem_log_file.c_str());
- if (!ds.AddZipEntry(filename, modem_log_file)) {
- MYLOGE("Unable to add modem log %s to zip file\n", modem_log_file.c_str());
- } else {
- MYLOGD("Modem Log %s is added to zip\n", modem_log_file.c_str());
- if (remove(modem_log_file.c_str())) {
- MYLOGE("Error removing modem log %s\n", modem_log_file.c_str());
- }
- }
-}
-
static bool skip_not_stat(const char *path) {
static const char stat[] = "/stat";
size_t len = strlen(path);
@@ -918,7 +843,7 @@
"-d", "*:v"});
}
-static void DumpIpTables() {
+static void DumpIpTablesAsRoot() {
RunCommand("IPTABLES", {"iptables", "-L", "-nvx"});
RunCommand("IP6TABLES", {"ip6tables", "-L", "-nvx"});
RunCommand("IPTABLES NAT", {"iptables", "-t", "nat", "-L", "-nvx"});
@@ -1088,6 +1013,24 @@
}
return;
}
+
+static void DumpPacketStats() {
+ DumpFile("NETWORK DEV INFO", "/proc/net/dev");
+ DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
+ DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
+ DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
+ DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
+}
+
+static void DumpIpAddrAndRules() {
+ /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
+ RunCommand("NETWORK INTERFACES", {"ip", "link"});
+ RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
+ RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
+ RunCommand("IP RULES", {"ip", "rule", "show"});
+ RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
+}
+
static void dumpstate() {
DurationReporter duration_reporter("DUMPSTATE");
@@ -1165,23 +1108,11 @@
printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR.c_str());
}
- DumpFile("NETWORK DEV INFO", "/proc/net/dev");
- DumpFile("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
- DumpFile("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
- DumpFile("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
- DumpFile("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
+ DumpPacketStats();
DoKmsg();
- /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
-
- RunCommand("NETWORK INTERFACES", {"ip", "link"});
-
- RunCommand("IPv4 ADDRESSES", {"ip", "-4", "addr", "show"});
- RunCommand("IPv6 ADDRESSES", {"ip", "-6", "addr", "show"});
-
- RunCommand("IP RULES", {"ip", "rule", "show"});
- RunCommand("IP RULES v6", {"ip", "-6", "rule", "show"});
+ DumpIpAddrAndRules();
dump_route_tables();
@@ -1282,11 +1213,6 @@
RunDumpsys("DROPBOX SYSTEM SERVER CRASHES", {"dropbox", "-p", "system_server_crash"});
RunDumpsys("DROPBOX SYSTEM APP CRASHES", {"dropbox", "-p", "system_app_crash"});
- // DumpModemLogs adds the modem logs if available to the bugreport.
- // Do this at the end to allow for sufficient time for the modem logs to be
- // collected.
- DumpModemLogs();
-
printf("========================================================\n");
printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(),
ds.progress_->GetMax(), ds.progress_->GetInitialMax());
@@ -1295,6 +1221,46 @@
printf("========================================================\n");
}
+// This method collects dumpsys for telephony debugging only
+static void DumpstateTelephonyOnly() {
+ DurationReporter duration_reporter("DUMPSTATE");
+
+ DumpIpTablesAsRoot();
+
+ if (!DropRootUser()) {
+ return;
+ }
+
+ do_dmesg();
+ DoLogcat();
+ DumpPacketStats();
+ DoKmsg();
+ DumpIpAddrAndRules();
+ dump_route_tables();
+
+ RunDumpsys("NETWORK DIAGNOSTICS", {"connectivity", "--diag"},
+ CommandOptions::WithTimeout(10).Build());
+
+ RunCommand("SYSTEM PROPERTIES", {"getprop"});
+
+ printf("========================================================\n");
+ printf("== Android Framework Services\n");
+ printf("========================================================\n");
+
+ RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(), 10);
+ RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(), 10);
+
+ printf("========================================================\n");
+ printf("== Running Application Services\n");
+ printf("========================================================\n");
+
+ RunDumpsys("TELEPHONY SERVICES", {"activity", "service", "TelephonyDebugService"});
+
+ printf("========================================================\n");
+ printf("== dumpstate: done (id %d)\n", ds.id_);
+ printf("========================================================\n");
+}
+
void Dumpstate::DumpstateBoard() {
DurationReporter duration_reporter("dumpstate_board()");
printf("========================================================\n");
@@ -1312,23 +1278,35 @@
return;
}
- std::string path = kDumpstateBoardPath;
- MYLOGI("Calling IDumpstateDevice implementation using path %s\n", path.c_str());
+ std::string path[NUM_OF_DUMPS];
+ android::base::unique_fd fd[NUM_OF_DUMPS];
+ int numFds = 0;
- int fd =
- TEMP_FAILURE_RETRY(open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
- if (fd < 0) {
- MYLOGE("Could not open file %s: %s\n", path.c_str(), strerror(errno));
- return;
+ for (int i = 0; i < NUM_OF_DUMPS; i++) {
+ path[i] = kDumpstateBoardPath + kDumpstateBoardFiles[i];
+ MYLOGI("Calling IDumpstateDevice implementation using path %s\n", path[i].c_str());
+
+ fd[i] = android::base::unique_fd(
+ TEMP_FAILURE_RETRY(open(path[i].c_str(),
+ O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)));
+ if (fd[i] < 0) {
+ MYLOGE("Could not open file %s: %s\n", path[i].c_str(), strerror(errno));
+ return;
+ } else {
+ numFds++;
+ }
}
- native_handle_t* handle = native_handle_create(1, 0);
+ native_handle_t *handle = native_handle_create(numFds, 0);
if (handle == nullptr) {
MYLOGE("Could not create native_handle\n");
return;
}
- handle->data[0] = fd;
+
+ for (int i = 0; i < numFds; i++) {
+ handle->data[i] = fd[i].release();
+ }
// TODO: need a timeout mechanism so dumpstate does not hang on device implementation call.
android::hardware::Return<void> status = dumpstate_device->dumpstateBoard(handle);
@@ -1339,14 +1317,26 @@
return;
}
- AddZipEntry("dumpstate-board.txt", path);
+ for (int i = 0; i < numFds; i++) {
+ struct stat s;
+ if (fstat(handle->data[i], &s) == -1) {
+ MYLOGE("Failed to fstat %s: %d\n", kDumpstateBoardFiles[i].c_str(), errno);
+ } else if (s.st_size > 0) {
+ AddZipEntry(kDumpstateBoardFiles[i], path[i]);
+ } else {
+ MYLOGE("Ignoring empty %s\n", kDumpstateBoardFiles[i].c_str());
+ }
+ }
+
printf("*** See dumpstate-board.txt entry ***\n");
native_handle_close(handle);
native_handle_delete(handle);
- if (remove(path.c_str()) != 0) {
- MYLOGE("Could not remove(%s): %s\n", path.c_str(), strerror(errno));
+ for (int i = 0; i < numFds; i++) {
+ if (remove(path[i].c_str()) != 0) {
+ MYLOGE("Could not remove(%s): %s\n", path[i].c_str(), strerror(errno));
+ }
}
}
@@ -1808,15 +1798,8 @@
ds.PrintHeader();
if (telephony_only) {
- DumpIpTables();
- if (!DropRootUser()) {
- return -1;
- }
- do_dmesg();
- DoLogcat();
- DoKmsg();
+ DumpstateTelephonyOnly();
ds.DumpstateBoard();
- DumpModemLogs();
} else {
// Dumps systrace right away, otherwise it will be filled with unnecessary events.
// First try to dump anrd trace if the daemon is running. Otherwise, dump
@@ -1850,7 +1833,7 @@
ds.AddDir(PROFILE_DATA_DIR_REF, true);
}
add_mountinfo();
- DumpIpTables();
+ DumpIpTablesAsRoot();
// Capture any IPSec policies in play. No keys are exposed here.
RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"},
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index 87b9104..7c6cfd9 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -244,7 +244,18 @@
mOut << std::endl;
}
+static inline bool findAndBumpVersion(vintf::ManifestHal* hal, const vintf::Version& version) {
+ for (vintf::Version& v : hal->versions) {
+ if (v.majorVer == version.majorVer) {
+ v.minorVer = std::max(v.minorVer, version.minorVer);
+ return true;
+ }
+ }
+ return false;
+}
+
void ListCommand::dumpVintf() const {
+ using vintf::operator|=;
mOut << "<!-- " << std::endl
<< " This is a skeleton device manifest. Notes: " << std::endl
<< " 1. android.hidl.*, android.frameworks.*, android.system.* are not included." << std::endl
@@ -252,7 +263,9 @@
<< " 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
+ << " 4. A HAL with lower minor version can be overridden by a HAL with" << std::endl
+ << " higher minor version if they have the same name and major version." << std::endl
+ << " 5. 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;
@@ -316,17 +329,19 @@
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."
+ mErr << "Fatal: should not reach here. Generated result may be wrong for '"
+ << hal->name << "'."
<< std::endl;
}
done = true;
break;
}
- if (hal->hasVersion(version)) {
+ if (findAndBumpVersion(hal, version)) {
if (&table != &mImplementationsTable) {
hal->interfaces[interfaceName].name = interfaceName;
hal->interfaces[interfaceName].instances.insert(instanceName);
}
+ hal->transportArch.arch |= arch;
done = true;
break;
}
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index 45bb1d0..d5cfcaf 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -287,7 +287,11 @@
}
if (sehandle && selinux_status_updated() > 0) {
+#ifdef VENDORSERVICEMANAGER
+ struct selabel_handle *tmp_sehandle = selinux_android_vendor_service_context_handle();
+#else
struct selabel_handle *tmp_sehandle = selinux_android_service_context_handle();
+#endif
if (tmp_sehandle) {
selabel_close(sehandle);
sehandle = tmp_sehandle;
diff --git a/include/gui b/include/gui
new file mode 120000
index 0000000..3b796f3
--- /dev/null
+++ b/include/gui
@@ -0,0 +1 @@
+../libs/gui/include/gui
\ No newline at end of file
diff --git a/include/private/gui b/include/private/gui
new file mode 120000
index 0000000..99de2dc
--- /dev/null
+++ b/include/private/gui
@@ -0,0 +1 @@
+../../libs/gui/include/private/gui
\ No newline at end of file
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 204fdb5..3a353c2 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -15,6 +15,7 @@
cc_library_headers {
name: "libbinder_headers",
export_include_dirs: ["include"],
+ vendor_available: true,
}
cc_library {
@@ -74,13 +75,18 @@
"libcutils",
"libutils",
],
+
+ header_libs: [
+ "libbinder_headers",
+ ],
+
export_shared_lib_headers: [
"libbase",
"libutils",
],
- export_include_dirs: [
- "include",
+ export_header_lib_headers: [
+ "libbinder_headers",
],
clang: true,
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index c0ae3d7..4558fe8 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -11,9 +11,15 @@
// 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_headers {
+ name: "libgui_headers",
+ vendor_available: true,
+ export_include_dirs: ["include"],
+}
cc_library_shared {
name: "libgui",
+ vendor_available: true,
clang: true,
cppflags: [
@@ -57,7 +63,7 @@
brillo: {
cflags: ["-DHAVE_NO_SURFACE_FLINGER"],
},
- debuggable: {
+ eng: {
cppflags: [
"-UDEBUG_ONLY_CODE",
"-DDEBUG_ONLY_CODE=1",
@@ -119,16 +125,22 @@
header_libs: [
"libnativebase_headers",
+ "libgui_headers",
],
export_shared_lib_headers: [
"libbinder",
- "libui",
+ "libEGL",
"libnativewindow",
+ "libui",
"android.hidl.token@1.0-utils",
"android.hardware.graphics.bufferqueue@1.0",
],
+ export_header_lib_headers: [
+ "libgui_headers",
+ ],
+
export_include_dirs: [
"include",
],
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index c2b10a9..3d36376 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -106,7 +106,7 @@
sp<FrameAvailableListener> listener;
{ // scope for the lock
- Mutex::Autolock lock(mMutex);
+ Mutex::Autolock lock(mFrameAvailableMutex);
listener = mFrameAvailableListener.promote();
}
@@ -121,7 +121,7 @@
sp<FrameAvailableListener> listener;
{
- Mutex::Autolock lock(mMutex);
+ Mutex::Autolock lock(mFrameAvailableMutex);
listener = mFrameAvailableListener.promote();
}
@@ -185,7 +185,7 @@
void ConsumerBase::setFrameAvailableListener(
const wp<FrameAvailableListener>& listener) {
CB_LOGV("setFrameAvailableListener");
- Mutex::Autolock lock(mMutex);
+ Mutex::Autolock lock(mFrameAvailableMutex);
mFrameAvailableListener = listener;
}
diff --git a/include/gui/BufferItem.h b/libs/gui/include/gui/BufferItem.h
similarity index 100%
rename from include/gui/BufferItem.h
rename to libs/gui/include/gui/BufferItem.h
diff --git a/include/gui/BufferItemConsumer.h b/libs/gui/include/gui/BufferItemConsumer.h
similarity index 100%
rename from include/gui/BufferItemConsumer.h
rename to libs/gui/include/gui/BufferItemConsumer.h
diff --git a/include/gui/BufferQueue.h b/libs/gui/include/gui/BufferQueue.h
similarity index 100%
rename from include/gui/BufferQueue.h
rename to libs/gui/include/gui/BufferQueue.h
diff --git a/include/gui/BufferQueueConsumer.h b/libs/gui/include/gui/BufferQueueConsumer.h
similarity index 100%
rename from include/gui/BufferQueueConsumer.h
rename to libs/gui/include/gui/BufferQueueConsumer.h
diff --git a/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h
similarity index 100%
rename from include/gui/BufferQueueCore.h
rename to libs/gui/include/gui/BufferQueueCore.h
diff --git a/include/gui/BufferQueueDefs.h b/libs/gui/include/gui/BufferQueueDefs.h
similarity index 100%
rename from include/gui/BufferQueueDefs.h
rename to libs/gui/include/gui/BufferQueueDefs.h
diff --git a/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h
similarity index 100%
rename from include/gui/BufferQueueProducer.h
rename to libs/gui/include/gui/BufferQueueProducer.h
diff --git a/include/gui/BufferSlot.h b/libs/gui/include/gui/BufferSlot.h
similarity index 100%
rename from include/gui/BufferSlot.h
rename to libs/gui/include/gui/BufferSlot.h
diff --git a/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h
similarity index 98%
rename from include/gui/ConsumerBase.h
rename to libs/gui/include/gui/ConsumerBase.h
index d1a9b04..e9fc8fd 100644
--- a/include/gui/ConsumerBase.h
+++ b/libs/gui/include/gui/ConsumerBase.h
@@ -241,7 +241,9 @@
// mFrameAvailableListener is the listener object that will be called when a
// new frame becomes available. If it is not NULL it will be called from
- // queueBuffer.
+ // queueBuffer. The listener object is protected by mFrameAvailableMutex
+ // (not mMutex).
+ Mutex mFrameAvailableMutex;
wp<FrameAvailableListener> mFrameAvailableListener;
// The ConsumerBase has-a BufferQueue and is responsible for creating this object
diff --git a/include/gui/CpuConsumer.h b/libs/gui/include/gui/CpuConsumer.h
similarity index 100%
rename from include/gui/CpuConsumer.h
rename to libs/gui/include/gui/CpuConsumer.h
diff --git a/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
similarity index 100%
rename from include/gui/DisplayEventReceiver.h
rename to libs/gui/include/gui/DisplayEventReceiver.h
diff --git a/include/gui/FrameTimestamps.h b/libs/gui/include/gui/FrameTimestamps.h
similarity index 100%
rename from include/gui/FrameTimestamps.h
rename to libs/gui/include/gui/FrameTimestamps.h
diff --git a/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h
similarity index 100%
rename from include/gui/GLConsumer.h
rename to libs/gui/include/gui/GLConsumer.h
diff --git a/include/gui/GuiConfig.h b/libs/gui/include/gui/GuiConfig.h
similarity index 100%
rename from include/gui/GuiConfig.h
rename to libs/gui/include/gui/GuiConfig.h
diff --git a/include/gui/IConsumerListener.h b/libs/gui/include/gui/IConsumerListener.h
similarity index 100%
rename from include/gui/IConsumerListener.h
rename to libs/gui/include/gui/IConsumerListener.h
diff --git a/include/gui/IDisplayEventConnection.h b/libs/gui/include/gui/IDisplayEventConnection.h
similarity index 100%
rename from include/gui/IDisplayEventConnection.h
rename to libs/gui/include/gui/IDisplayEventConnection.h
diff --git a/include/gui/IGraphicBufferConsumer.h b/libs/gui/include/gui/IGraphicBufferConsumer.h
similarity index 100%
rename from include/gui/IGraphicBufferConsumer.h
rename to libs/gui/include/gui/IGraphicBufferConsumer.h
diff --git a/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h
similarity index 100%
rename from include/gui/IGraphicBufferProducer.h
rename to libs/gui/include/gui/IGraphicBufferProducer.h
diff --git a/include/gui/IProducerListener.h b/libs/gui/include/gui/IProducerListener.h
similarity index 100%
rename from include/gui/IProducerListener.h
rename to libs/gui/include/gui/IProducerListener.h
diff --git a/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
similarity index 100%
rename from include/gui/ISurfaceComposer.h
rename to libs/gui/include/gui/ISurfaceComposer.h
diff --git a/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h
similarity index 100%
rename from include/gui/ISurfaceComposerClient.h
rename to libs/gui/include/gui/ISurfaceComposerClient.h
diff --git a/include/gui/OccupancyTracker.h b/libs/gui/include/gui/OccupancyTracker.h
similarity index 100%
rename from include/gui/OccupancyTracker.h
rename to libs/gui/include/gui/OccupancyTracker.h
diff --git a/include/gui/StreamSplitter.h b/libs/gui/include/gui/StreamSplitter.h
similarity index 100%
rename from include/gui/StreamSplitter.h
rename to libs/gui/include/gui/StreamSplitter.h
diff --git a/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
similarity index 100%
rename from include/gui/Surface.h
rename to libs/gui/include/gui/Surface.h
diff --git a/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
similarity index 100%
rename from include/gui/SurfaceComposerClient.h
rename to libs/gui/include/gui/SurfaceComposerClient.h
diff --git a/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
similarity index 100%
rename from include/gui/SurfaceControl.h
rename to libs/gui/include/gui/SurfaceControl.h
diff --git a/include/gui/bufferqueue/1.0/B2HProducerListener.h b/libs/gui/include/gui/bufferqueue/1.0/B2HProducerListener.h
similarity index 100%
rename from include/gui/bufferqueue/1.0/B2HProducerListener.h
rename to libs/gui/include/gui/bufferqueue/1.0/B2HProducerListener.h
diff --git a/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
similarity index 100%
rename from include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
rename to libs/gui/include/gui/bufferqueue/1.0/H2BGraphicBufferProducer.h
diff --git a/include/gui/view/Surface.h b/libs/gui/include/gui/view/Surface.h
similarity index 100%
rename from include/gui/view/Surface.h
rename to libs/gui/include/gui/view/Surface.h
diff --git a/include/private/gui/ComposerService.h b/libs/gui/include/private/gui/ComposerService.h
similarity index 100%
rename from include/private/gui/ComposerService.h
rename to libs/gui/include/private/gui/ComposerService.h
diff --git a/include/private/gui/LayerState.h b/libs/gui/include/private/gui/LayerState.h
similarity index 100%
rename from include/private/gui/LayerState.h
rename to libs/gui/include/private/gui/LayerState.h
diff --git a/include/private/gui/SyncFeatures.h b/libs/gui/include/private/gui/SyncFeatures.h
similarity index 100%
rename from include/private/gui/SyncFeatures.h
rename to libs/gui/include/private/gui/SyncFeatures.h
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index d9cfed7..6630d90 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -89,6 +89,7 @@
header_libs: [
"libnativebase_headers",
+ "libhardware_headers",
],
export_include_dirs: ["include"],
@@ -100,6 +101,7 @@
export_header_lib_headers: [
"libnativebase_headers",
+ "libhardware_headers",
],
}
diff --git a/libs/ui/Gralloc2.cpp b/libs/ui/Gralloc2.cpp
index e149803..87dbaf4 100644
--- a/libs/ui/Gralloc2.cpp
+++ b/libs/ui/Gralloc2.cpp
@@ -16,7 +16,6 @@
#define LOG_TAG "Gralloc2"
-#include <hidl/ServiceManagement.h>
#include <hwbinder/IPCThreadState.h>
#include <ui/Gralloc2.h>
@@ -251,17 +250,4 @@
} // namespace Gralloc2
-namespace {
-// Load the IMapper implementation library when this shared library is loaded, rather than when
-// we (lazily) create the Gralloc2::Mapper instance. Since these libraries will all be needed by
-// nearly all apps, this allows us to load them in Zygote rather than on each app launch.
-class PreloadMapperImpl {
-public:
- PreloadMapperImpl() {
- android::hardware::preloadPassthroughService<hardware::graphics::mapper::V2_0::IMapper>();
- }
-};
-static PreloadMapperImpl preloadMapperImpl;
-} // namespace
-
} // namespace android
diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp
index 4041d6b..7fe9825 100644
--- a/libs/vr/libdvr/Android.bp
+++ b/libs/vr/libdvr/Android.bp
@@ -31,6 +31,7 @@
"dvr_configuration_data.cpp",
"dvr_display_manager.cpp",
"dvr_hardware_composer_client.cpp",
+ "dvr_performance.cpp",
"dvr_surface.cpp",
"dvr_vsync.cpp",
]
@@ -45,6 +46,7 @@
"libvr_hwc-impl",
"libvr_hwc-binder",
"libgrallocusage",
+ "libperformance",
"libpdx_default_transport",
]
diff --git a/libs/vr/libdvr/dvr_api.cpp b/libs/vr/libdvr/dvr_api.cpp
index dc31917..7d4e2d1 100644
--- a/libs/vr/libdvr/dvr_api.cpp
+++ b/libs/vr/libdvr/dvr_api.cpp
@@ -10,6 +10,7 @@
#include <dvr/dvr_buffer_queue.h>
#include <dvr/dvr_configuration_data.h>
#include <dvr/dvr_display_manager.h>
+#include <dvr/dvr_performance.h>
#include <dvr/dvr_surface.h>
#include <dvr/dvr_vsync.h>
diff --git a/libs/vr/libdvr/dvr_buffer_queue.cpp b/libs/vr/libdvr/dvr_buffer_queue.cpp
index aa2ed94..2e1655f 100644
--- a/libs/vr/libdvr/dvr_buffer_queue.cpp
+++ b/libs/vr/libdvr/dvr_buffer_queue.cpp
@@ -313,7 +313,10 @@
int dvrReadBufferQueueDequeue(DvrReadBufferQueue* read_queue, int timeout,
DvrReadBuffer* read_buffer, int* out_fence_fd,
void* out_meta, size_t meta_size_bytes) {
- if (!read_queue || !read_buffer || !out_fence_fd || !out_meta)
+ if (!read_queue || !read_buffer || !out_fence_fd)
+ return -EINVAL;
+
+ if (meta_size_bytes != 0 && !out_meta)
return -EINVAL;
return read_queue->Dequeue(timeout, read_buffer, out_fence_fd, out_meta,
diff --git a/libs/vr/libdvr/dvr_hardware_composer_client.cpp b/libs/vr/libdvr/dvr_hardware_composer_client.cpp
index d3ae299..46d72ca 100644
--- a/libs/vr/libdvr/dvr_hardware_composer_client.cpp
+++ b/libs/vr/libdvr/dvr_hardware_composer_client.cpp
@@ -6,7 +6,9 @@
#include <binder/IServiceManager.h>
#include <private/android/AHardwareBufferHelpers.h>
+#include <functional>
#include <memory>
+#include <mutex>
struct DvrHwcFrame {
android::dvr::ComposerView::Frame frame;
@@ -16,10 +18,15 @@
class HwcCallback : public android::dvr::BnVrComposerCallback {
public:
- explicit HwcCallback(DvrHwcOnFrameCallback callback,
- void* client_state);
+ using CallbackFunction = std::function<int(DvrHwcFrame*)>;
+
+ explicit HwcCallback(const CallbackFunction& callback);
~HwcCallback() override;
+ // Reset the callback. This needs to be done early to avoid use after free
+ // accesses from binder thread callbacks.
+ void Shutdown();
+
std::unique_ptr<DvrHwcFrame> DequeueFrame();
private:
@@ -28,26 +35,41 @@
const android::dvr::ParcelableComposerFrame& frame,
android::dvr::ParcelableUniqueFd* fence) override;
- DvrHwcOnFrameCallback callback_;
- void* client_state_;
+ // Protects the |callback_| from uses from multiple threads. During shutdown
+ // there may be in-flight frame update events. In those cases the callback
+ // access needs to be protected otherwise binder threads may access an invalid
+ // callback.
+ std::mutex mutex_;
+ CallbackFunction callback_;
HwcCallback(const HwcCallback&) = delete;
void operator=(const HwcCallback&) = delete;
};
-HwcCallback::HwcCallback(DvrHwcOnFrameCallback callback, void* client_state)
- : callback_(callback), client_state_(client_state) {}
+HwcCallback::HwcCallback(const CallbackFunction& callback)
+ : callback_(callback) {}
HwcCallback::~HwcCallback() {}
+void HwcCallback::Shutdown() {
+ std::lock_guard<std::mutex> guard(mutex_);
+ callback_ = nullptr;
+}
+
android::binder::Status HwcCallback::onNewFrame(
const android::dvr::ParcelableComposerFrame& frame,
android::dvr::ParcelableUniqueFd* fence) {
+ std::lock_guard<std::mutex> guard(mutex_);
+
+ if (!callback_) {
+ fence->set_fence(android::base::unique_fd());
+ return android::binder::Status::ok();
+ }
+
std::unique_ptr<DvrHwcFrame> dvr_frame(new DvrHwcFrame());
dvr_frame->frame = frame.frame();
- fence->set_fence(android::base::unique_fd(callback_(client_state_,
- dvr_frame.release())));
+ fence->set_fence(android::base::unique_fd(callback_(dvr_frame.release())));
return android::binder::Status::ok();
}
@@ -67,7 +89,8 @@
if (!client->composer.get())
return nullptr;
- client->callback = new HwcCallback(callback, data);
+ client->callback = new HwcCallback(std::bind(callback, data,
+ std::placeholders::_1));
android::binder::Status status = client->composer->registerObserver(
client->callback);
if (!status.isOk())
@@ -77,6 +100,10 @@
}
void dvrHwcClientDestroy(DvrHwcClient* client) {
+ // NOTE: Deleting DvrHwcClient* isn't enough since DvrHwcClient::callback is a
+ // shared pointer that could be referenced from a binder thread. But the
+ // client callback isn't valid past this calls so that needs to be reset.
+ client->callback->Shutdown();
delete client;
}
diff --git a/libs/vr/libdvr/dvr_performance.cpp b/libs/vr/libdvr/dvr_performance.cpp
new file mode 100644
index 0000000..599101f
--- /dev/null
+++ b/libs/vr/libdvr/dvr_performance.cpp
@@ -0,0 +1,18 @@
+#include "include/dvr/dvr_performance.h"
+
+#include <private/dvr/performance_client.h>
+
+using android::dvr::PerformanceClient;
+
+extern "C" {
+
+int dvrPerformanceSetSchedulerPolicy(pid_t task_id,
+ const char* scheduler_policy) {
+ int error;
+ if (auto client = PerformanceClient::Create(&error))
+ return client->SetSchedulerPolicy(task_id, scheduler_policy);
+ else
+ return error;
+}
+
+} // extern "C"
diff --git a/libs/vr/libdvr/dvr_surface.cpp b/libs/vr/libdvr/dvr_surface.cpp
index 8602206..a3a47f1 100644
--- a/libs/vr/libdvr/dvr_surface.cpp
+++ b/libs/vr/libdvr/dvr_surface.cpp
@@ -2,6 +2,7 @@
#include <inttypes.h>
+#include <pdx/rpc/variant.h>
#include <private/android/AHardwareBufferHelpers.h>
#include <private/dvr/display_client.h>
@@ -14,9 +15,20 @@
using android::dvr::display::SurfaceAttributes;
using android::dvr::display::SurfaceAttributeValue;
using android::dvr::CreateDvrReadBufferFromBufferConsumer;
+using android::pdx::rpc::EmptyVariant;
namespace {
+// Sets the Variant |destination| to the target std::array type and copies the C
+// array into it. Unsupported std::array configurations will fail to compile.
+template <typename T, std::size_t N>
+void ArrayCopy(SurfaceAttributeValue* destination, const T (&source)[N]) {
+ using ArrayType = std::array<T, N>;
+ *destination = ArrayType{};
+ std::copy(std::begin(source), std::end(source),
+ std::get<ArrayType>(*destination).begin());
+}
+
bool ConvertSurfaceAttributes(const DvrSurfaceAttribute* attributes,
size_t attribute_count,
SurfaceAttributes* surface_attributes,
@@ -31,25 +43,31 @@
value = attributes[i].value.int64_value;
break;
case DVR_SURFACE_ATTRIBUTE_TYPE_BOOL:
- value = attributes[i].value.bool_value;
+ // bool_value is defined in an extern "C" block, which makes it look
+ // like an int to C++. Use a cast to assign the correct type to the
+ // Variant type SurfaceAttributeValue.
+ value = static_cast<bool>(attributes[i].value.bool_value);
break;
case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT:
value = attributes[i].value.float_value;
break;
case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT2:
- value = attributes[i].value.float2_value;
+ ArrayCopy(&value, attributes[i].value.float2_value);
break;
case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT3:
- value = attributes[i].value.float3_value;
+ ArrayCopy(&value, attributes[i].value.float3_value);
break;
case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT4:
- value = attributes[i].value.float4_value;
+ ArrayCopy(&value, attributes[i].value.float4_value);
break;
case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT8:
- value = attributes[i].value.float8_value;
+ ArrayCopy(&value, attributes[i].value.float8_value);
break;
case DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT16:
- value = attributes[i].value.float16_value;
+ ArrayCopy(&value, attributes[i].value.float16_value);
+ break;
+ case DVR_SURFACE_ATTRIBUTE_TYPE_NONE:
+ value = EmptyVariant{};
break;
default:
*error_index = i;
@@ -223,4 +241,38 @@
return 0;
}
+int dvrGetNativeDisplayMetrics(size_t sizeof_metrics,
+ DvrNativeDisplayMetrics* metrics) {
+ ALOGE_IF(sizeof_metrics != sizeof(DvrNativeDisplayMetrics),
+ "dvrGetNativeDisplayMetrics: metrics struct mismatch, your dvr api "
+ "header is out of date.");
+
+ auto client = DisplayClient::Create();
+ if (!client) {
+ ALOGE("dvrGetNativeDisplayMetrics: Failed to create display client!");
+ return -ECOMM;
+ }
+
+ if (metrics == nullptr) {
+ ALOGE("dvrGetNativeDisplayMetrics: output metrics buffer must be non-null");
+ return -EINVAL;
+ }
+
+ auto status = client->GetDisplayMetrics();
+
+ if (!status) {
+ return -status.error();
+ }
+
+ if (sizeof_metrics >= 20) {
+ metrics->display_width = status.get().display_width;
+ metrics->display_height = status.get().display_height;
+ metrics->display_x_dpi = status.get().display_x_dpi;
+ metrics->display_y_dpi = status.get().display_y_dpi;
+ metrics->vsync_period_ns = status.get().vsync_period_ns;
+ }
+
+ return 0;
+}
+
} // extern "C"
diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h
index 5d5e2f0..ceb6cf2 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api.h
@@ -4,6 +4,7 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
+#include <unistd.h>
#include <cstdio>
#include <dvr/dvr_display_types.h>
@@ -41,6 +42,19 @@
typedef struct DvrSurfaceAttributeValue DvrSurfaceAttributeValue;
typedef struct DvrSurfaceAttribute DvrSurfaceAttribute;
+// Note: To avoid breaking others during active development, only modify this
+// struct by appending elements to the end.
+// If you do feel we should to re-arrange or remove elements, please make a
+// note of it, and wait until we're about to finalize for an API release to do
+// so.
+typedef struct DvrNativeDisplayMetrics {
+ uint32_t display_width;
+ uint32_t display_height;
+ uint32_t display_x_dpi;
+ uint32_t display_y_dpi;
+ uint32_t vsync_period_ns;
+} DvrNativeDisplayMetrics;
+
// native_handle contains the fds for the underlying ION allocations inside
// the gralloc buffer. This is needed temporarily while GPU vendors work on
// better support for AHardwareBuffer via glBindSharedBuffer APIs. See
@@ -200,6 +214,8 @@
DvrSurface* surface, uint32_t width, uint32_t height, uint32_t format,
uint32_t layer_count, uint64_t usage, size_t capacity, size_t metadata_size,
DvrWriteBufferQueue** queue_out);
+typedef int (*DvrGetNativeDisplayMetricsPtr)(size_t sizeof_metrics,
+ DvrNativeDisplayMetrics* metrics);
// dvr_vsync.h
typedef int (*DvrVSyncClientCreatePtr)(DvrVSyncClient** client_out);
@@ -219,6 +235,8 @@
int32_t controller_id,
uint32_t vsync_count,
DvrPoseAsync* out_pose);
+typedef int (*DvrPoseClientSensorsEnablePtr)(DvrPoseClient* client,
+ bool enabled);
// services/vr/virtual_touchpad/include/dvr/virtual_touchpad_client.h
@@ -305,6 +323,10 @@
size_t layer_index,
size_t index);
+// dvr_performance.h
+typedef int (*DvrPerformanceSetSchedulerPolicyPtr)(
+ pid_t task_id, const char* scheduler_policy);
+
// The buffer metadata that an Android Surface (a.k.a. ANativeWindow)
// will populate. A DvrWriteBufferQueue must be created with this metadata iff
// ANativeWindow access is needed. Please do not remove, modify, or reorder
diff --git a/libs/vr/libdvr/include/dvr/dvr_api_entries.h b/libs/vr/libdvr/include/dvr/dvr_api_entries.h
index a30a6c3..914901e 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api_entries.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api_entries.h
@@ -148,3 +148,12 @@
// Virtual touchpad client
DVR_V1_API_ENTRY(VirtualTouchpadScroll);
+
+// Read the native display metrics from the hardware composer
+DVR_V1_API_ENTRY(GetNativeDisplayMetrics);
+
+// Performance
+DVR_V1_API_ENTRY(PerformanceSetSchedulerPolicy);
+
+// Pose client
+DVR_V1_API_ENTRY(PoseClientSensorsEnable);
diff --git a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
index caf208d..95c04f1 100644
--- a/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
+++ b/libs/vr/libdvr/include/dvr/dvr_buffer_queue.h
@@ -124,6 +124,8 @@
// signals the release of underlying buffer. The consumer should wait until
// this fence clears before reading data from it.
// @param out_meta The memory area where a metadata object will be filled.
+// Can be nullptr iff |meta_size_bytes| is zero (i.e., there is no
+// metadata).
// @param meta_size_bytes Size of the metadata object caller expects. If it
// doesn't match the size of actually metadata transported by the buffer
// queue, the method returns -EINVAL.
diff --git a/libs/vr/libdvr/include/dvr/dvr_performance.h b/libs/vr/libdvr/include/dvr/dvr_performance.h
new file mode 100644
index 0000000..5df35ad
--- /dev/null
+++ b/libs/vr/libdvr/include/dvr/dvr_performance.h
@@ -0,0 +1,26 @@
+#ifndef ANDROID_DVR_PERFORMANCE_H_
+#define ANDROID_DVR_PERFORMANCE_H_
+
+#include <stddef.h>
+#include <unistd.h>
+
+__BEGIN_DECLS
+
+/// Sets the scheduler policy for a task.
+///
+/// Sets the scheduler policy for a task to the class described by a semantic
+/// string.
+///
+/// Supported policies are device-specific.
+///
+/// @param task_id The task id of task to set the policy for. When task_id is 0
+/// the current task id is substituted.
+/// @param scheduler_policy NULL-terminated ASCII string containing the desired
+/// scheduler policy.
+/// @returns Returns 0 on success or a negative errno error code on error.
+int dvrPerformanceSetSchedulerPolicy(pid_t task_id, const char* scheduler_policy);
+
+__END_DECLS
+
+#endif // ANDROID_DVR_PERFORMANCE_H_
+
diff --git a/libs/vr/libdvr/include/dvr/dvr_pose.h b/libs/vr/libdvr/include/dvr/dvr_pose.h
index 4256cf9..b3df028 100644
--- a/libs/vr/libdvr/include/dvr/dvr_pose.h
+++ b/libs/vr/libdvr/include/dvr/dvr_pose.h
@@ -43,16 +43,24 @@
} DvrPoseAsync;
enum {
- DVR_POSE_FLAG_INVALID = (1UL << 0), // This pose is invalid.
- DVR_POSE_FLAG_INITIALIZING = (1UL << 1), // The pose delivered during
- // initialization and it may not be
- // correct.
+ DVR_POSE_FLAG_INVALID = (1ULL << 0), // This pose is invalid.
+ DVR_POSE_FLAG_INITIALIZING = (1ULL << 1), // The pose delivered during
+ // initialization and it may not be
+ // correct.
DVR_POSE_FLAG_3DOF =
- (1UL << 2), // This pose is derived from 3Dof sensors. If
- // this is not set, pose is derived using
- // 3Dof and 6Dof sensors.
+ (1ULL << 2), // This pose is derived from 3Dof sensors. If
+ // this is not set, pose is derived using
+ // 3Dof and 6Dof sensors.
DVR_POSE_FLAG_FLOOR_HEIGHT_INVALID =
- (1UL << 3), // If set the floor height is invalid.
+ (1ULL << 3), // If set the floor height is invalid.
+
+ // Bits that indicate the tracking system state.
+ DVR_POSE_FLAG_SERVICE_EXCEPTION = (1ULL << 32),
+ DVR_POSE_FLAG_FISHEYE_OVER_EXPOSED = (1ULL << 33),
+ DVR_POSE_FLAG_FISHEYE_UNDER_EXPOSED = (1ULL << 34),
+ DVR_POSE_FLAG_COLOR_OVER_EXPOSED = (1ULL << 35),
+ DVR_POSE_FLAG_COLOR_UNDER_EXPOSED = (1ULL << 36),
+ DVR_POSE_FLAG_TOO_FEW_FEATURES_TRACKED = (1ULL << 37)
};
// Represents a sensor pose sample.
diff --git a/libs/vr/libdvr/include/dvr/dvr_surface.h b/libs/vr/libdvr/include/dvr/dvr_surface.h
index 7b8dfa8..74a68a1 100644
--- a/libs/vr/libdvr/include/dvr/dvr_surface.h
+++ b/libs/vr/libdvr/include/dvr/dvr_surface.h
@@ -97,6 +97,17 @@
// @return 0 on success. Otherwise returns a negative error value.
int dvrGetGlobalBuffer(DvrGlobalBufferKey key, DvrBuffer** out_buffer);
+// Read the native device display metrics as reported by the hardware composer.
+// This is useful as otherwise the device metrics are only reported as
+// relative to the current device orientation.
+// @param sizeof_metrics the size of the passed in metrics struct. This is used
+// to ensure we don't break each other during active development.
+// @param metrics on success holds the retrieved device metrics.
+// @return 0 on success. Otherwise returns a negative error value (typically
+// this means the display service is not available).
+int dvrGetNativeDisplayMetrics(size_t metrics_struct_size,
+ DvrNativeDisplayMetrics* metrics);
+
__END_DECLS
#endif // ANDROID_DVR_SURFACE_H_
diff --git a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
index 5158612..497b1cb 100644
--- a/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_buffer_queue-test.cpp
@@ -37,15 +37,11 @@
protected:
void SetUp() override {
- auto config = ProducerQueueConfigBuilder()
- .SetDefaultWidth(kBufferWidth)
- .SetDefaultHeight(kBufferHeight)
- .SetDefaultFormat(kBufferFormat)
- .SetMetadata<TestMeta>()
- .Build();
- write_queue_ =
- new DvrWriteBufferQueue(ProducerQueue::Create(config, UsagePolicy{}));
- ASSERT_NE(nullptr, write_queue_);
+ config_builder_ = ProducerQueueConfigBuilder()
+ .SetDefaultWidth(kBufferWidth)
+ .SetDefaultHeight(kBufferHeight)
+ .SetDefaultFormat(kBufferFormat)
+ .SetMetadata<TestMeta>();
}
void TearDown() override {
@@ -55,6 +51,12 @@
}
}
+ void CreateWriteBufferQueue() {
+ write_queue_ = new DvrWriteBufferQueue(
+ ProducerQueue::Create(config_builder_.Build(), UsagePolicy{}));
+ ASSERT_NE(nullptr, write_queue_);
+ }
+
void AllocateBuffers(size_t buffer_count) {
auto status = write_queue_->producer_queue()->AllocateBuffers(
kBufferWidth, kBufferHeight, kLayerCount, kBufferFormat, kBufferUsage,
@@ -73,18 +75,23 @@
buffer_removed_count_);
}
+ ProducerQueueConfigBuilder config_builder_;
DvrWriteBufferQueue* write_queue_{nullptr};
int buffer_available_count_{0};
int buffer_removed_count_{0};
};
-TEST_F(DvrBufferQueueTest, TestWrite_QueueDestroy) {
+TEST_F(DvrBufferQueueTest, TestWrite_QueueCreateDestroy) {
+ ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+
dvrWriteBufferQueueDestroy(write_queue_);
write_queue_ = nullptr;
}
TEST_F(DvrBufferQueueTest, TestWrite_QueueGetCapacity) {
- AllocateBuffers(kQueueCapacity);
+ ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+ ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity));
+
size_t capacity = dvrWriteBufferQueueGetCapacity(write_queue_);
ALOGD_IF(TRACE, "TestWrite_QueueGetCapacity, capacity=%zu", capacity);
@@ -92,6 +99,8 @@
}
TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromWriteQueue) {
+ ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+
DvrReadBufferQueue* read_queue = nullptr;
int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue);
@@ -102,6 +111,8 @@
}
TEST_F(DvrBufferQueueTest, TestCreateReadQueueFromReadQueue) {
+ ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+
DvrReadBufferQueue* read_queue1 = nullptr;
DvrReadBufferQueue* read_queue2 = nullptr;
int ret = dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue1);
@@ -119,7 +130,8 @@
}
TEST_F(DvrBufferQueueTest, CreateEmptyBuffer) {
- AllocateBuffers(3);
+ ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+ ASSERT_NO_FATAL_FAILURE(AllocateBuffers(3));
DvrReadBuffer* read_buffer = nullptr;
DvrWriteBuffer* write_buffer = nullptr;
@@ -152,6 +164,9 @@
}
TEST_F(DvrBufferQueueTest, TestDequeuePostDequeueRelease) {
+ ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+ ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity));
+
static constexpr int kTimeout = 0;
DvrReadBufferQueue* read_queue = nullptr;
DvrReadBuffer* rb = nullptr;
@@ -172,8 +187,6 @@
dvrReadBufferCreateEmpty(&rb);
ASSERT_NE(nullptr, rb);
- AllocateBuffers(kQueueCapacity);
-
// Gain buffer for writing.
ret = dvrWriteBufferQueueDequeue(write_queue_, kTimeout, wb, &fence_fd);
ASSERT_EQ(0, ret);
@@ -221,6 +234,8 @@
}
TEST_F(DvrBufferQueueTest, TestGetExternalSurface) {
+ ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+
ANativeWindow* window = nullptr;
// The |write_queue_| doesn't have proper metadata (must be
@@ -251,6 +266,9 @@
// Before each dequeue operation, we resize the buffer queue and expect the
// queue always return buffer with desired dimension.
TEST_F(DvrBufferQueueTest, TestResizeBuffer) {
+ ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+ ASSERT_NO_FATAL_FAILURE(AllocateBuffers(kQueueCapacity));
+
static constexpr int kTimeout = 0;
int fence_fd = -1;
@@ -278,8 +296,6 @@
dvrWriteBufferCreateEmpty(&wb3);
ASSERT_NE(nullptr, wb3);
- AllocateBuffers(kQueueCapacity);
-
// Handle all pending events on the read queue.
ret = dvrReadBufferQueueHandleEvents(read_queue);
ASSERT_EQ(0, ret);
@@ -369,6 +385,71 @@
dvrReadBufferQueueDestroy(read_queue);
}
+TEST_F(DvrBufferQueueTest, DequeueEmptyMetadata) {
+ // Overrides default queue parameters: Empty metadata.
+ config_builder_.SetMetadata<void>();
+ ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+ ASSERT_NO_FATAL_FAILURE(AllocateBuffers(1));
+
+ DvrReadBuffer* rb = nullptr;
+ DvrWriteBuffer* wb = nullptr;
+ dvrReadBufferCreateEmpty(&rb);
+ dvrWriteBufferCreateEmpty(&wb);
+
+ DvrReadBufferQueue* read_queue = nullptr;
+ EXPECT_EQ(0, dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue));
+
+ const int kTimeoutMs = 0;
+ int fence_fd = -1;
+ EXPECT_EQ(0, dvrWriteBufferQueueDequeue(write_queue_, 0, wb, &fence_fd));
+
+ EXPECT_EQ(0, dvrWriteBufferPost(wb, /*fence=*/-1, nullptr, 0));
+ EXPECT_EQ(0, dvrWriteBufferClear(wb));
+ dvrWriteBufferDestroy(wb);
+ wb = nullptr;
+
+ // When acquire buffer, it's legit to pass nullptr as out_meta iff metadata
+ // size is Zero.
+ EXPECT_EQ(0, dvrReadBufferQueueDequeue(read_queue, kTimeoutMs, rb, &fence_fd,
+ nullptr, 0));
+ EXPECT_TRUE(dvrReadBufferIsValid(rb));
+}
+
+TEST_F(DvrBufferQueueTest, DequeueMismatchMetadata) {
+ ASSERT_NO_FATAL_FAILURE(CreateWriteBufferQueue());
+ ASSERT_NO_FATAL_FAILURE(AllocateBuffers(1));
+
+ DvrReadBuffer* rb = nullptr;
+ DvrWriteBuffer* wb = nullptr;
+ dvrReadBufferCreateEmpty(&rb);
+ dvrWriteBufferCreateEmpty(&wb);
+
+ DvrReadBufferQueue* read_queue = nullptr;
+ EXPECT_EQ(0, dvrWriteBufferQueueCreateReadQueue(write_queue_, &read_queue));
+
+ const int kTimeoutMs = 0;
+ int fence_fd = -1;
+ EXPECT_EQ(0, dvrWriteBufferQueueDequeue(write_queue_, 0, wb, &fence_fd));
+
+ TestMeta seq = 42U;
+ EXPECT_EQ(0, dvrWriteBufferPost(wb, /*fence=*/-1, &seq, sizeof(seq)));
+ EXPECT_EQ(0, dvrWriteBufferClear(wb));
+ dvrWriteBufferDestroy(wb);
+ wb = nullptr;
+
+ // Dequeue with wrong metadata will cause EINVAL.
+ int8_t wrong_metadata;
+ EXPECT_EQ(-EINVAL,
+ dvrReadBufferQueueDequeue(read_queue, kTimeoutMs, rb, &fence_fd,
+ &wrong_metadata, sizeof(wrong_metadata)));
+ EXPECT_FALSE(dvrReadBufferIsValid(rb));
+
+ // Dequeue with empty metadata will cause EINVAL.
+ EXPECT_EQ(-EINVAL, dvrReadBufferQueueDequeue(read_queue, kTimeoutMs, rb,
+ &fence_fd, nullptr, 0));
+ EXPECT_FALSE(dvrReadBufferIsValid(rb));
+}
+
} // namespace
} // namespace dvr
diff --git a/libs/vr/libdvr/tests/dvr_display_manager-test.cpp b/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
index 726949d..f83b26e 100644
--- a/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
@@ -1,11 +1,13 @@
#include <android-base/properties.h>
#include <base/logging.h>
#include <gtest/gtest.h>
+#include <log/log.h>
#include <poll.h>
#include <android/hardware_buffer.h>
#include <algorithm>
+#include <array>
#include <set>
#include <thread>
#include <vector>
@@ -25,7 +27,30 @@
namespace {
-DvrSurfaceAttribute GetAttribute(DvrSurfaceAttributeKey key, bool value) {
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, nullptr_t) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_NONE;
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, int32_t value) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32;
+ attribute.value.int32_value = value;
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, int64_t value) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT64;
+ attribute.value.int64_value = value;
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, bool value) {
DvrSurfaceAttribute attribute;
attribute.key = key;
attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_BOOL;
@@ -33,11 +58,56 @@
return attribute;
}
-DvrSurfaceAttribute GetAttribute(DvrSurfaceAttributeKey key, int32_t value) {
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, float value) {
DvrSurfaceAttribute attribute;
attribute.key = key;
- attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_INT32;
- attribute.value.bool_value = value;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT;
+ attribute.value.float_value = value;
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
+ const std::array<float, 2>& value) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT2;
+ std::copy(value.begin(), value.end(), attribute.value.float2_value);
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
+ const std::array<float, 3>& value) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT3;
+ std::copy(value.begin(), value.end(), attribute.value.float3_value);
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
+ const std::array<float, 4>& value) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT4;
+ std::copy(value.begin(), value.end(), attribute.value.float4_value);
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
+ const std::array<float, 8>& value) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT8;
+ std::copy(value.begin(), value.end(), attribute.value.float8_value);
+ return attribute;
+}
+
+DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key,
+ const std::array<float, 16>& value) {
+ DvrSurfaceAttribute attribute;
+ attribute.key = key;
+ attribute.value.type = DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT16;
+ std::copy(value.begin(), value.end(), attribute.value.float16_value);
return attribute;
}
@@ -45,8 +115,8 @@
int32_t z_order = 0) {
DvrSurface* surface = nullptr;
DvrSurfaceAttribute attributes[] = {
- GetAttribute(DVR_SURFACE_ATTRIBUTE_Z_ORDER, z_order),
- GetAttribute(DVR_SURFACE_ATTRIBUTE_VISIBLE, visible)};
+ MakeAttribute(DVR_SURFACE_ATTRIBUTE_Z_ORDER, z_order),
+ MakeAttribute(DVR_SURFACE_ATTRIBUTE_VISIBLE, visible)};
const int ret = dvrSurfaceCreate(
attributes, std::extent<decltype(attributes)>::value, &surface);
@@ -101,13 +171,14 @@
return {};
}
- Status<void> WaitForUpdate() {
+ enum : int { kTimeoutMs = 10000 }; // 10s
+
+ Status<void> WaitForUpdate(int timeout_ms = kTimeoutMs) {
if (display_manager_event_fd_ < 0)
return ErrorStatus(-display_manager_event_fd_);
- const int kTimeoutMs = 10000; // 10s
pollfd pfd = {display_manager_event_fd_, POLLIN, 0};
- const int count = poll(&pfd, 1, kTimeoutMs);
+ const int count = poll(&pfd, 1, timeout_ms);
if (count < 0)
return ErrorStatus(errno);
else if (count == 0)
@@ -471,20 +542,218 @@
auto attributes = attribute_status.take();
EXPECT_GE(attributes.size(), 2u);
- const std::set<int32_t> expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER,
- DVR_SURFACE_ATTRIBUTE_VISIBLE};
+ std::set<int32_t> actual_keys;
+ std::set<int32_t> expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+ DVR_SURFACE_ATTRIBUTE_VISIBLE};
// Collect all the keys in attributes that match the expected keys.
- std::set<int32_t> actual_keys;
- std::for_each(attributes.begin(), attributes.end(),
- [&expected_keys, &actual_keys](const auto& attribute) {
- if (expected_keys.find(attribute.key) != expected_keys.end())
- actual_keys.emplace(attribute.key);
- });
+ auto compare_keys = [](const auto& attributes, const auto& expected_keys) {
+ std::set<int32_t> keys;
+ for (const auto& attribute : attributes) {
+ if (expected_keys.find(attribute.key) != expected_keys.end())
+ keys.emplace(attribute.key);
+ }
+ return keys;
+ };
// If the sets match then attributes contained at least the expected keys,
// even if other keys were also present.
+ actual_keys = compare_keys(attributes, expected_keys);
EXPECT_EQ(expected_keys, actual_keys);
+
+ std::vector<DvrSurfaceAttribute> attributes_to_set = {
+ MakeAttribute(DVR_SURFACE_ATTRIBUTE_Z_ORDER, 0)};
+
+ // Test invalid args.
+ EXPECT_EQ(-EINVAL, dvrSurfaceSetAttributes(nullptr, attributes_to_set.data(),
+ attributes_to_set.size()));
+ EXPECT_EQ(-EINVAL, dvrSurfaceSetAttributes(surface.get(), nullptr,
+ attributes_to_set.size()));
+
+ // Test attribute change events.
+ ASSERT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
+ attributes_to_set.size()));
+ ASSERT_STATUS_OK(manager_->WaitForUpdate());
+
+ // Verify the attributes changed flag is set.
+ auto check_flags = [](const auto& value) {
+ return value & DVR_SURFACE_UPDATE_FLAGS_ATTRIBUTES_CHANGED;
+ };
+ EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0));
+
+ attribute_status = manager_->GetAttributes(0);
+ ASSERT_STATUS_OK(attribute_status);
+ attributes = attribute_status.take();
+ EXPECT_GE(attributes.size(), 2u);
+
+ expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+ DVR_SURFACE_ATTRIBUTE_VISIBLE};
+
+ actual_keys.clear();
+ actual_keys = compare_keys(attributes, expected_keys);
+ EXPECT_EQ(expected_keys, actual_keys);
+
+ // Test setting and then deleting an attribute.
+ const DvrSurfaceAttributeKey kUserKey = 1;
+ attributes_to_set = {MakeAttribute(kUserKey, 1024)};
+
+ ASSERT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
+ attributes_to_set.size()));
+ ASSERT_STATUS_OK(manager_->WaitForUpdate());
+ EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0));
+
+ attribute_status = manager_->GetAttributes(0);
+ ASSERT_STATUS_OK(attribute_status);
+ attributes = attribute_status.take();
+ EXPECT_GE(attributes.size(), 2u);
+
+ expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER, DVR_SURFACE_ATTRIBUTE_VISIBLE,
+ kUserKey};
+
+ actual_keys.clear();
+ actual_keys = compare_keys(attributes, expected_keys);
+ EXPECT_EQ(expected_keys, actual_keys);
+
+ // Delete the attribute.
+ attributes_to_set = {MakeAttribute(kUserKey, nullptr)};
+
+ ASSERT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
+ attributes_to_set.size()));
+ ASSERT_STATUS_OK(manager_->WaitForUpdate());
+ EXPECT_STATUS_PRED(check_flags, manager_->GetUpdateFlags(0));
+
+ attribute_status = manager_->GetAttributes(0);
+ ASSERT_STATUS_OK(attribute_status);
+ attributes = attribute_status.take();
+ EXPECT_GE(attributes.size(), 2u);
+
+ expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER, DVR_SURFACE_ATTRIBUTE_VISIBLE,
+ kUserKey};
+
+ actual_keys.clear();
+ actual_keys = compare_keys(attributes, expected_keys);
+ EXPECT_NE(expected_keys, actual_keys);
+
+ // Test deleting a reserved attribute.
+ attributes_to_set = {MakeAttribute(DVR_SURFACE_ATTRIBUTE_VISIBLE, nullptr)};
+
+ EXPECT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
+ attributes_to_set.size()));
+
+ // Failed attribute operations should not trigger update events.
+ const int kTimeoutMs = 100; // 0.1s
+ EXPECT_STATUS_ERROR_VALUE(ETIMEDOUT, manager_->WaitForUpdate(kTimeoutMs));
+
+ attribute_status = manager_->GetAttributes(0);
+ ASSERT_STATUS_OK(attribute_status);
+ attributes = attribute_status.take();
+ EXPECT_GE(attributes.size(), 2u);
+
+ expected_keys = {DVR_SURFACE_ATTRIBUTE_Z_ORDER,
+ DVR_SURFACE_ATTRIBUTE_VISIBLE};
+
+ actual_keys.clear();
+ actual_keys = compare_keys(attributes, expected_keys);
+ EXPECT_EQ(expected_keys, actual_keys);
+}
+
+TEST_F(DvrDisplayManagerTest, SurfaceAttributeTypes) {
+ // Create an application surface.
+ auto surface_status = CreateApplicationSurface();
+ ASSERT_STATUS_OK(surface_status);
+ UniqueDvrSurface surface = surface_status.take();
+ ASSERT_NE(nullptr, surface.get());
+
+ enum : std::int32_t {
+ kInt32Key = 1,
+ kInt64Key,
+ kBoolKey,
+ kFloatKey,
+ kFloat2Key,
+ kFloat3Key,
+ kFloat4Key,
+ kFloat8Key,
+ kFloat16Key,
+ };
+
+ const std::vector<DvrSurfaceAttribute> attributes_to_set = {
+ MakeAttribute(kInt32Key, int32_t{0}),
+ MakeAttribute(kInt64Key, int64_t{0}),
+ MakeAttribute(kBoolKey, false),
+ MakeAttribute(kFloatKey, 0.0f),
+ MakeAttribute(kFloat2Key, std::array<float, 2>{{1.0f, 2.0f}}),
+ MakeAttribute(kFloat3Key, std::array<float, 3>{{3.0f, 4.0f, 5.0f}}),
+ MakeAttribute(kFloat4Key, std::array<float, 4>{{6.0f, 7.0f, 8.0f, 9.0f}}),
+ MakeAttribute(kFloat8Key,
+ std::array<float, 8>{{10.0f, 11.0f, 12.0f, 13.0f, 14.0f,
+ 15.0f, 16.0f, 17.0f}}),
+ MakeAttribute(kFloat16Key, std::array<float, 16>{
+ {18.0f, 19.0f, 20.0f, 21.0f, 22.0f, 23.0f,
+ 24.0f, 25.0f, 26.0f, 27.0f, 28.0f, 29.0f,
+ 30.0f, 31.0f, 32.0f, 33.0f}})};
+
+ EXPECT_EQ(0, dvrSurfaceSetAttributes(surface.get(), attributes_to_set.data(),
+ attributes_to_set.size()));
+
+ ASSERT_STATUS_OK(manager_->WaitForUpdate());
+ auto attribute_status = manager_->GetAttributes(0);
+ ASSERT_STATUS_OK(attribute_status);
+ auto attributes = attribute_status.take();
+ EXPECT_GE(attributes.size(), attributes_to_set.size());
+
+ auto HasAttribute = [](const auto& attributes,
+ DvrSurfaceAttributeKey key) -> bool {
+ for (const auto& attribute : attributes) {
+ if (attribute.key == key)
+ return true;
+ }
+ return false;
+ };
+ auto AttributeType =
+ [](const auto& attributes,
+ DvrSurfaceAttributeKey key) -> DvrSurfaceAttributeType {
+ for (const auto& attribute : attributes) {
+ if (attribute.key == key)
+ return attribute.value.type;
+ }
+ return DVR_SURFACE_ATTRIBUTE_TYPE_NONE;
+ };
+
+ ASSERT_TRUE(HasAttribute(attributes, kInt32Key));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_INT32,
+ AttributeType(attributes, kInt32Key));
+
+ ASSERT_TRUE(HasAttribute(attributes, kInt64Key));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_INT64,
+ AttributeType(attributes, kInt64Key));
+
+ ASSERT_TRUE(HasAttribute(attributes, kBoolKey));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_BOOL,
+ AttributeType(attributes, kBoolKey));
+
+ ASSERT_TRUE(HasAttribute(attributes, kFloatKey));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT,
+ AttributeType(attributes, kFloatKey));
+
+ ASSERT_TRUE(HasAttribute(attributes, kFloat2Key));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT2,
+ AttributeType(attributes, kFloat2Key));
+
+ ASSERT_TRUE(HasAttribute(attributes, kFloat3Key));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT3,
+ AttributeType(attributes, kFloat3Key));
+
+ ASSERT_TRUE(HasAttribute(attributes, kFloat4Key));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT4,
+ AttributeType(attributes, kFloat4Key));
+
+ ASSERT_TRUE(HasAttribute(attributes, kFloat8Key));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT8,
+ AttributeType(attributes, kFloat8Key));
+
+ ASSERT_TRUE(HasAttribute(attributes, kFloat16Key));
+ EXPECT_EQ(DVR_SURFACE_ATTRIBUTE_TYPE_FLOAT16,
+ AttributeType(attributes, kFloat16Key));
}
TEST_F(DvrDisplayManagerTest, SurfaceQueueEvent) {
@@ -500,7 +769,8 @@
ASSERT_STATUS_OK(manager_->WaitForUpdate());
ASSERT_STATUS_EQ(1u, manager_->GetSurfaceCount());
- // Verify there are no queues for the surface recorded in the state snapshot.
+ // Verify there are no queues for the surface recorded in the state
+ // snapshot.
EXPECT_STATUS_EQ(std::vector<int>{}, manager_->GetQueueIds(0));
// Create a new queue in the surface.
diff --git a/libs/vr/libpdx/private/pdx/rpc/variant.h b/libs/vr/libpdx/private/pdx/rpc/variant.h
index dc321fa..80b1769 100644
--- a/libs/vr/libpdx/private/pdx/rpc/variant.h
+++ b/libs/vr/libpdx/private/pdx/rpc/variant.h
@@ -26,14 +26,35 @@
template <std::size_t I, typename... Types>
using TypeTagForIndex = TypeTag<TypeForIndex<I, Types...>>;
+// Similar to std::is_constructible except that it evaluates to false for bool
+// construction from pointer types: this helps prevent subtle to bugs caused by
+// assigning values that decay to pointers to Variants with bool elements.
+//
+// Here is an example of the problematic situation this trait avoids:
+//
+// Variant<int, bool> v;
+// const int array[3] = {1, 2, 3};
+// v = array; // This is allowed by regular std::is_constructible.
+//
+template <typename...>
+struct IsConstructible;
+template <typename T, typename U>
+struct IsConstructible<T, U>
+ : std::integral_constant<bool,
+ std::is_constructible<T, U>::value &&
+ !(std::is_same<std::decay_t<T>, bool>::value &&
+ std::is_pointer<std::decay_t<U>>::value)> {};
+template <typename T, typename... Args>
+struct IsConstructible<T, Args...> : std::is_constructible<T, Args...> {};
+
// Enable if T(Args...) is well formed.
template <typename R, typename T, typename... Args>
using EnableIfConstructible =
- typename std::enable_if<std::is_constructible<T, Args...>::value, R>::type;
+ typename std::enable_if<IsConstructible<T, Args...>::value, R>::type;
// Enable if T(Args...) is not well formed.
template <typename R, typename T, typename... Args>
using EnableIfNotConstructible =
- typename std::enable_if<!std::is_constructible<T, Args...>::value, R>::type;
+ typename std::enable_if<!IsConstructible<T, Args...>::value, R>::type;
// Determines whether T is an element of Types...;
template <typename... Types>
@@ -65,12 +86,11 @@
struct ConstructibleCount;
template <typename From, typename To>
struct ConstructibleCount<From, To>
- : std::integral_constant<std::size_t,
- std::is_constructible<To, From>::value> {};
+ : std::integral_constant<std::size_t, IsConstructible<To, From>::value> {};
template <typename From, typename First, typename... Rest>
struct ConstructibleCount<From, First, Rest...>
: std::integral_constant<std::size_t,
- std::is_constructible<First, From>::value +
+ IsConstructible<First, From>::value +
ConstructibleCount<From, Rest...>::value> {};
// Enable if T is an element of Types...
@@ -126,6 +146,18 @@
: first_(std::forward<T>(value)) {
*index_out = index;
}
+ Union(const Union& other, std::int32_t index) {
+ if (index == 0)
+ new (&first_) Type(other.first_);
+ }
+ Union(Union&& other, std::int32_t index) {
+ if (index == 0)
+ new (&first_) Type(std::move(other.first_));
+ }
+ Union(const Union&) = delete;
+ Union(Union&&) = delete;
+ void operator=(const Union&) = delete;
+ void operator=(Union&&) = delete;
Type& get(TypeTag<Type>) { return first_; }
const Type& get(TypeTag<Type>) const { return first_; }
@@ -217,6 +249,22 @@
template <typename T, typename U>
Union(std::int32_t index, std::int32_t* index_out, TypeTag<T>, U&& value)
: rest_(index + 1, index_out, TypeTag<T>{}, std::forward<U>(value)) {}
+ Union(const Union& other, std::int32_t index) {
+ if (index == 0)
+ new (&first_) First(other.first_);
+ else
+ new (&rest_) Union<Rest...>(other.rest_, index - 1);
+ }
+ Union(Union&& other, std::int32_t index) {
+ if (index == 0)
+ new (&first_) First(std::move(other.first_));
+ else
+ new (&rest_) Union<Rest...>(std::move(other.rest_), index - 1);
+ }
+ Union(const Union&) = delete;
+ Union(Union&&) = delete;
+ void operator=(const Union&) = delete;
+ void operator=(Union&&) = delete;
struct FirstType {};
struct RestType {};
@@ -351,6 +399,10 @@
} // namespace detail
+// Variant is a type safe union that can store values of any of its element
+// types. A Variant is different than std::tuple in that it only stores one type
+// at a time or a special empty type. Variants are always default constructible
+// to empty, even when none of the element types are default constructible.
template <typename... Types>
class Variant {
private:
@@ -393,6 +445,11 @@
explicit Variant(EmptyVariant) {}
~Variant() { Destruct(); }
+ Variant(const Variant& other)
+ : index_{other.index_}, value_{other.value_, other.index_} {}
+ Variant(Variant&& other)
+ : index_{other.index_}, value_{std::move(other.value_), other.index_} {}
+
// Copy and move construction from Variant types. Each element of OtherTypes
// must be convertible to an element of Types.
template <typename... OtherTypes>
@@ -404,6 +461,15 @@
other.Visit([this](auto&& value) { Construct(std::move(value)); });
}
+ Variant& operator=(const Variant& other) {
+ other.Visit([this](const auto& value) { *this = value; });
+ return *this;
+ }
+ Variant& operator=(Variant&& other) {
+ other.Visit([this](auto&& value) { *this = std::move(value); });
+ return *this;
+ }
+
// Construction from non-Variant types.
template <typename T, typename = EnableIfAssignable<void, T>>
explicit Variant(T&& value)
diff --git a/libs/vr/libpdx/variant_tests.cpp b/libs/vr/libpdx/variant_tests.cpp
index b1ebc9b..e3520f5 100644
--- a/libs/vr/libpdx/variant_tests.cpp
+++ b/libs/vr/libpdx/variant_tests.cpp
@@ -1,3 +1,4 @@
+#include <array>
#include <cstdint>
#include <functional>
#include <memory>
@@ -1097,6 +1098,29 @@
EXPECT_FALSE((detail::HasType<char&, int, float, bool>::value));
}
+TEST(Variant, IsConstructible) {
+ using ArrayType = const float[3];
+ struct ImplicitBool {
+ operator bool() const { return true; }
+ };
+ struct ExplicitBool {
+ explicit operator bool() const { return true; }
+ };
+ struct NonBool {};
+ struct TwoArgs {
+ TwoArgs(int, bool) {}
+ };
+
+ EXPECT_FALSE((detail::IsConstructible<bool, ArrayType>::value));
+ EXPECT_TRUE((detail::IsConstructible<bool, int>::value));
+ EXPECT_TRUE((detail::IsConstructible<bool, ImplicitBool>::value));
+ EXPECT_TRUE((detail::IsConstructible<bool, ExplicitBool>::value));
+ EXPECT_FALSE((detail::IsConstructible<bool, NonBool>::value));
+ EXPECT_TRUE((detail::IsConstructible<TwoArgs, int, bool>::value));
+ EXPECT_FALSE((detail::IsConstructible<TwoArgs, int, std::string>::value));
+ EXPECT_FALSE((detail::IsConstructible<TwoArgs, int>::value));
+}
+
TEST(Variant, Set) {
EXPECT_TRUE((detail::Set<int, bool, float>::template IsSubset<int, bool,
float>::value));
diff --git a/libs/vr/libpdx_uds/channel_event_set.cpp b/libs/vr/libpdx_uds/channel_event_set.cpp
index ac4dea9..ebe7cea 100644
--- a/libs/vr/libpdx_uds/channel_event_set.cpp
+++ b/libs/vr/libpdx_uds/channel_event_set.cpp
@@ -100,6 +100,9 @@
ALOGE("ChannelEventReceiver::GetPendingEvents: Failed to get events: %s",
status.GetErrorMessage().c_str());
return status;
+ } else if (count == 0) {
+ status.SetError(ETIMEDOUT);
+ return status;
}
const int mask_out = event.data.u32;
diff --git a/libs/vr/libperformance/include/dvr/performance_client_api.h b/libs/vr/libperformance/include/dvr/performance_client_api.h
index 2216e38..9d617cb 100644
--- a/libs/vr/libperformance/include/dvr/performance_client_api.h
+++ b/libs/vr/libperformance/include/dvr/performance_client_api.h
@@ -8,6 +8,20 @@
extern "C" {
#endif
+/// Sets the scheduler policy for a task.
+///
+/// Sets the scheduler policy for a task to the class described by a semantic
+/// string.
+///
+/// Supported policies are device-specific.
+///
+/// @param task_id The task id of task to set the policy for. When task_id is 0
+/// the current task id is substituted.
+/// @param scheduler_policy NULL-terminated ASCII string containing the desired
+/// scheduler policy.
+/// @returns Returns 0 on success or a negative errno error code on error.
+int dvrSetSchedulerPolicy(pid_t task_id, const char* scheduler_policy);
+
/// Sets the CPU partition for a task.
///
/// Sets the CPU partition for a task to the partition described by a CPU
diff --git a/libs/vr/libperformance/include/private/dvr/performance_client.h b/libs/vr/libperformance/include/private/dvr/performance_client.h
index a61c6b2..3bd90dc 100644
--- a/libs/vr/libperformance/include/private/dvr/performance_client.h
+++ b/libs/vr/libperformance/include/private/dvr/performance_client.h
@@ -14,6 +14,10 @@
class PerformanceClient : public pdx::ClientBase<PerformanceClient> {
public:
+ int SetSchedulerPolicy(pid_t task_id, const std::string& scheduler_policy);
+ int SetSchedulerPolicy(pid_t task_id, const char* scheduler_policy);
+
+ // TODO(eieio): Consider deprecating this API.
int SetCpuPartition(pid_t task_id, const std::string& partition);
int SetCpuPartition(pid_t task_id, const char* partition);
int SetSchedulerClass(pid_t task_id, const std::string& scheduler_class);
diff --git a/libs/vr/libperformance/include/private/dvr/performance_rpc.h b/libs/vr/libperformance/include/private/dvr/performance_rpc.h
index 73bdaa7..d57bbe8 100644
--- a/libs/vr/libperformance/include/private/dvr/performance_rpc.h
+++ b/libs/vr/libperformance/include/private/dvr/performance_rpc.h
@@ -21,14 +21,17 @@
kOpSetCpuPartition = 0,
kOpSetSchedulerClass,
kOpGetCpuPartition,
+ kOpSetSchedulerPolicy,
};
// Methods.
PDX_REMOTE_METHOD(SetCpuPartition, kOpSetCpuPartition,
- int(pid_t, const std::string&));
+ void(pid_t, const std::string&));
PDX_REMOTE_METHOD(SetSchedulerClass, kOpSetSchedulerClass,
- int(pid_t, const std::string&));
+ void(pid_t, const std::string&));
PDX_REMOTE_METHOD(GetCpuPartition, kOpGetCpuPartition, std::string(pid_t));
+ PDX_REMOTE_METHOD(SetSchedulerPolicy, kOpSetSchedulerPolicy,
+ void(pid_t, const std::string&));
};
} // namespace dvr
diff --git a/libs/vr/libperformance/performance_client.cpp b/libs/vr/libperformance/performance_client.cpp
index 2124162..bf3726e 100644
--- a/libs/vr/libperformance/performance_client.cpp
+++ b/libs/vr/libperformance/performance_client.cpp
@@ -37,6 +37,26 @@
task_id, WrapString(partition)));
}
+int PerformanceClient::SetSchedulerPolicy(pid_t task_id,
+ const std::string& scheduler_policy) {
+ if (task_id == 0)
+ task_id = gettid();
+
+ return ReturnStatusOrError(
+ InvokeRemoteMethod<PerformanceRPC::SetSchedulerPolicy>(task_id,
+ scheduler_policy));
+}
+
+int PerformanceClient::SetSchedulerPolicy(pid_t task_id,
+ const char* scheduler_policy) {
+ if (task_id == 0)
+ task_id = gettid();
+
+ return ReturnStatusOrError(
+ InvokeRemoteMethod<PerformanceRPC::SetSchedulerPolicy>(
+ task_id, WrapString(scheduler_policy)));
+}
+
int PerformanceClient::SetSchedulerClass(pid_t task_id,
const std::string& scheduler_class) {
if (task_id == 0)
@@ -101,6 +121,15 @@
return error;
}
+extern "C" int dvrSetSchedulerPolicy(pid_t task_id,
+ const char* scheduler_policy) {
+ int error;
+ if (auto client = android::dvr::PerformanceClient::Create(&error))
+ return client->SetSchedulerPolicy(task_id, scheduler_policy);
+ else
+ return error;
+}
+
extern "C" int dvrSetSchedulerClass(pid_t task_id,
const char* scheduler_class) {
int error;
diff --git a/libs/vr/libvrflinger/display_surface.cpp b/libs/vr/libvrflinger/display_surface.cpp
index 330b455..6e18781 100644
--- a/libs/vr/libvrflinger/display_surface.cpp
+++ b/libs/vr/libvrflinger/display_surface.cpp
@@ -68,7 +68,7 @@
display::SurfaceUpdateFlags update_flags;
for (const auto& attribute : attributes) {
- const auto& key = attribute.first;
+ const auto key = attribute.first;
const auto* variant = &attribute.second;
bool invalid_value = false;
bool visibility_changed = false;
@@ -95,14 +95,23 @@
break;
}
+ // Only update the attribute map with valid values. This check also has the
+ // effect of preventing special attributes handled above from being deleted
+ // by an empty value.
if (invalid_value) {
ALOGW(
"DisplaySurface::OnClientSetAttributes: Failed to set display "
"surface attribute '%d' because of incompatible type: %d",
key, variant->index());
} else {
- // Only update the attribute map with valid values.
- attributes_[attribute.first] = attribute.second;
+ // An empty value indicates the attribute should be deleted.
+ if (variant->empty()) {
+ auto search = attributes_.find(key);
+ if (search != attributes_.end())
+ attributes_.erase(search);
+ } else {
+ attributes_[key] = *variant;
+ }
// All attribute changes generate a notification, even if the value
// doesn't change. Visibility attributes set a flag only if the value
diff --git a/libs/vr/libvrflinger/include/dvr/vr_flinger.h b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
index 145852e..f41da87 100644
--- a/libs/vr/libvrflinger/include/dvr/vr_flinger.h
+++ b/libs/vr/libvrflinger/include/dvr/vr_flinger.h
@@ -32,6 +32,9 @@
// Called on a binder thread.
void OnHardwareComposerRefresh();
+ // dump all vr flinger state.
+ std::string Dump();
+
private:
VrFlinger();
bool Init(Hwc2::Composer* hidl,
diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp
index b2dc1d8..3a0ca4a 100644
--- a/libs/vr/libvrflinger/vr_flinger.cpp
+++ b/libs/vr/libvrflinger/vr_flinger.cpp
@@ -139,6 +139,11 @@
display_service_->OnHardwareComposerRefresh();
}
+std::string VrFlinger::Dump() {
+ // TODO(karthikrs): Add more state information here.
+ return display_service_->DumpState(0/*unused*/);
+}
+
void VrFlinger::PersistentVrStateCallback::onPersistentVrStateChanged(
bool enabled) {
ALOGV("Notified persistent vr mode is %s", enabled ? "on" : "off");
@@ -146,6 +151,5 @@
// Persistent VR mode is not enough.
// request_display_callback_(enabled);
}
-
} // namespace dvr
} // namespace android
diff --git a/opengl/Android.bp b/opengl/Android.bp
index c520bda..aec5a95 100644
--- a/opengl/Android.bp
+++ b/opengl/Android.bp
@@ -52,6 +52,12 @@
license: "include/KHR/NOTICE",
}
+cc_library_headers {
+ name: "gl_headers",
+ vendor_available: true,
+ export_include_dirs: ["include"],
+}
+
subdirs = [
"*",
]
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index 4e275db..a344636 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -64,6 +64,16 @@
"liblog",
"libdl",
],
+ static_libs: [
+ "libarect",
+ ],
+ header_libs: [
+ "gl_headers",
+ "libsystem_headers",
+ "libhardware_headers",
+ "libnativebase_headers",
+ ],
+ export_header_lib_headers: ["gl_headers"],
// we need to access the private Bionic header <bionic_tls.h>
include_dirs: ["bionic/libc/private"],
@@ -75,6 +85,7 @@
cc_defaults {
name: "egl_libs_defaults",
defaults: ["gl_libs_defaults"],
+ vendor_available: true,
cflags: [
"-DLOG_TAG=\"libEGL\"",
],
@@ -85,6 +96,11 @@
"libnativewindow",
"libbacktrace",
],
+ target: {
+ vendor: {
+ exclude_shared_libs: ["libgraphicsenv"],
+ },
+ },
}
cc_library_static {
@@ -129,6 +145,7 @@
cc_defaults {
name: "gles_libs_defaults",
defaults: ["gl_libs_defaults"],
+ vendor_available: true,
arch: {
arm: {
instruction_set: "arm",
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 6e5c510..32f8caa 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -28,7 +28,9 @@
#include <cutils/properties.h>
#include <log/log.h>
+#ifndef __ANDROID_VNDK__
#include <graphicsenv/GraphicsEnv.h>
+#endif
#include <vndksupport/linker.h>
#include "egl_trace.h"
@@ -477,10 +479,12 @@
ATRACE_CALL();
void* dso = nullptr;
+#ifndef __ANDROID_VNDK__
android_namespace_t* ns = android_getDriverNamespace();
if (ns) {
dso = load_updated_driver(kind, ns);
}
+#endif
if (!dso) {
dso = load_system_driver(kind);
if (!dso)
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 835e72b..c5feb89 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -457,8 +457,8 @@
// 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
// the modification isn't possible, the original dataSpace is returned.
-static android_dataspace modifyBufferDataspace( android_dataspace dataSpace,
- EGLint colorspace) {
+static android_dataspace modifyBufferDataspace(android_dataspace dataSpace,
+ EGLint colorspace) {
if (colorspace == EGL_GL_COLORSPACE_LINEAR_KHR) {
return HAL_DATASPACE_SRGB_LINEAR;
} else if (colorspace == EGL_GL_COLORSPACE_SRGB_KHR) {
@@ -473,6 +473,59 @@
return dataSpace;
}
+// Return true if we stripped any EGL_GL_COLORSPACE_KHR attributes.
+static EGLBoolean stripColorSpaceAttribute(egl_display_ptr dp, const EGLint* attrib_list,
+ EGLint format,
+ std::vector<EGLint>& stripped_attrib_list) {
+ std::vector<EGLint> allowedColorSpaces;
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_RGB_565:
+ // driver okay with linear & sRGB for 8888, but can't handle
+ // Display-P3 or other spaces.
+ allowedColorSpaces.push_back(EGL_GL_COLORSPACE_SRGB_KHR);
+ allowedColorSpaces.push_back(EGL_GL_COLORSPACE_LINEAR_KHR);
+ break;
+
+ case HAL_PIXEL_FORMAT_RGBA_FP16:
+ case HAL_PIXEL_FORMAT_RGBA_1010102:
+ default:
+ // driver does not want to see colorspace attributes for 1010102 or fp16.
+ // Future: if driver supports XXXX extension, we can pass down that colorspace
+ break;
+ }
+
+ bool stripped = false;
+ if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) {
+ for (const EGLint* attr = attrib_list; attr[0] != EGL_NONE; attr += 2) {
+ if (attr[0] == EGL_GL_COLORSPACE_KHR) {
+ EGLint colorSpace = attr[1];
+ bool found = false;
+ // Verify that color space is allowed
+ for (auto it : allowedColorSpaces) {
+ if (colorSpace == it) {
+ found = true;
+ }
+ }
+ if (!found) {
+ stripped = true;
+ } else {
+ stripped_attrib_list.push_back(attr[0]);
+ stripped_attrib_list.push_back(attr[1]);
+ }
+ } else {
+ stripped_attrib_list.push_back(attr[0]);
+ stripped_attrib_list.push_back(attr[1]);
+ }
+ }
+ }
+ if (stripped) {
+ stripped_attrib_list.push_back(EGL_NONE);
+ stripped_attrib_list.push_back(EGL_NONE);
+ }
+ return stripped;
+}
+
static EGLBoolean getColorSpaceAttribute(egl_display_ptr dp, const EGLint* attrib_list,
EGLint& colorSpace, android_dataspace& dataSpace) {
colorSpace = EGL_GL_COLORSPACE_LINEAR_KHR;
@@ -514,6 +567,65 @@
return true;
}
+void getNativePixelFormat(EGLDisplay dpy, egl_connection_t* cnx, EGLConfig config, EGLint& format) {
+ // Set the native window's buffers format to match what this config requests.
+ // Whether to use sRGB gamma is not part of the EGLconfig, but is part
+ // of our native format. So if sRGB gamma is requested, we have to
+ // modify the EGLconfig's format before setting the native window's
+ // format.
+
+ EGLint componentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
+ cnx->egl.eglGetConfigAttrib(dpy, config, EGL_COLOR_COMPONENT_TYPE_EXT, &componentType);
+
+ EGLint a = 0;
+ EGLint r, g, b;
+ r = g = b = 0;
+ cnx->egl.eglGetConfigAttrib(dpy, config, EGL_RED_SIZE, &r);
+ cnx->egl.eglGetConfigAttrib(dpy, config, EGL_GREEN_SIZE, &g);
+ cnx->egl.eglGetConfigAttrib(dpy, config, EGL_BLUE_SIZE, &b);
+ cnx->egl.eglGetConfigAttrib(dpy, config, EGL_ALPHA_SIZE, &a);
+ EGLint colorDepth = r + g + b;
+
+ // Today, the driver only understands sRGB and linear on 888X
+ // formats. Strip other colorspaces from the attribute list and
+ // only use them to set the dataspace via
+ // native_window_set_buffers_dataspace
+ // if pixel format is RGBX 8888
+ // TBD: Can test for future extensions that indicate that driver
+ // handles requested color space and we can let it through.
+ // allow SRGB and LINEAR. All others need to be stripped.
+ // else if 565, 4444
+ // TBD: Can we assume these are supported if 8888 is?
+ // else if FP16 or 1010102
+ // strip colorspace from attribs.
+ // endif
+ if (a == 0) {
+ if (colorDepth <= 16) {
+ format = HAL_PIXEL_FORMAT_RGB_565;
+ } else {
+ if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
+ if (colorDepth > 24) {
+ format = HAL_PIXEL_FORMAT_RGBA_1010102;
+ } else {
+ format = HAL_PIXEL_FORMAT_RGBX_8888;
+ }
+ } else {
+ format = HAL_PIXEL_FORMAT_RGBA_FP16;
+ }
+ }
+ } else {
+ if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
+ if (colorDepth > 24) {
+ format = HAL_PIXEL_FORMAT_RGBA_1010102;
+ } else {
+ format = HAL_PIXEL_FORMAT_RGBA_8888;
+ }
+ } else {
+ format = HAL_PIXEL_FORMAT_RGBA_FP16;
+ }
+ }
+}
+
EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
NativeWindowType window,
const EGLint *attrib_list)
@@ -543,60 +655,24 @@
return setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
}
- // Set the native window's buffers format to match what this config requests.
- // Whether to use sRGB gamma is not part of the EGLconfig, but is part
- // of our native format. So if sRGB gamma is requested, we have to
- // modify the EGLconfig's format before setting the native window's
- // format.
-
- EGLint componentType = EGL_COLOR_COMPONENT_TYPE_FIXED_EXT;
- cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_COLOR_COMPONENT_TYPE_EXT,
- &componentType);
-
EGLint format;
+ getNativePixelFormat(iDpy, cnx, config, format);
+
+ // now select correct colorspace and dataspace based on user's attribute list
EGLint colorSpace;
android_dataspace dataSpace;
- EGLint a = 0;
- EGLint r, g, b;
- r = g = b = 0;
- cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_RED_SIZE, &r);
- cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_GREEN_SIZE, &g);
- cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_BLUE_SIZE, &b);
- cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_ALPHA_SIZE, &a);
- EGLint colorDepth = r + g + b;
-
- if (a == 0) {
- if (colorDepth <= 16) {
- format = HAL_PIXEL_FORMAT_RGB_565;
- } else {
- if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
- if (colorDepth > 24) {
- format = HAL_PIXEL_FORMAT_RGBA_1010102;
- } else {
- format = HAL_PIXEL_FORMAT_RGBX_8888;
- }
- } else {
- format = HAL_PIXEL_FORMAT_RGBA_FP16;
- }
- }
- } else {
- if (componentType == EGL_COLOR_COMPONENT_TYPE_FIXED_EXT) {
- if (colorDepth > 24) {
- format = HAL_PIXEL_FORMAT_RGBA_1010102;
- } else {
- format = HAL_PIXEL_FORMAT_RGBA_8888;
- }
- } else {
- format = HAL_PIXEL_FORMAT_RGBA_FP16;
- }
- }
-
- // now select a corresponding sRGB format if needed
if (!getColorSpaceAttribute(dp, attrib_list, colorSpace, dataSpace)) {
ALOGE("error invalid colorspace: %d", colorSpace);
return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
}
+ std::vector<EGLint> strippedAttribList;
+ if (stripColorSpaceAttribute(dp, attrib_list, format, strippedAttribList)) {
+ // Had to modify the attribute list due to use of color space.
+ // Use modified list from here on.
+ attrib_list = strippedAttribList.data();
+ }
+
if (format != 0) {
int err = native_window_set_buffers_format(window, format);
if (err != 0) {
@@ -671,15 +747,29 @@
egl_connection_t* cnx = NULL;
egl_display_ptr dp = validate_display_connection(dpy, cnx);
- EGLint colorSpace;
- android_dataspace dataSpace;
if (dp) {
- // now select a corresponding sRGB format if needed
+ EGLDisplay iDpy = dp->disp.dpy;
+ EGLint format;
+ getNativePixelFormat(iDpy, cnx, config, format);
+
+ // now select correct colorspace and dataspace based on user's attribute list
+ EGLint colorSpace;
+ android_dataspace dataSpace;
if (!getColorSpaceAttribute(dp, attrib_list, colorSpace, dataSpace)) {
ALOGE("error invalid colorspace: %d", colorSpace);
return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
}
+ // Pbuffers are not displayed so we don't need to store the
+ // colorspace. We do need to filter out color spaces the
+ // driver doesn't know how to process.
+ std::vector<EGLint> strippedAttribList;
+ if (stripColorSpaceAttribute(dp, attrib_list, format, strippedAttribList)) {
+ // Had to modify the attribute list due to use of color space.
+ // Use modified list from here on.
+ attrib_list = strippedAttribList.data();
+ }
+
EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
dp->disp.dpy, config, attrib_list);
if (surface != EGL_NO_SURFACE) {
@@ -1963,8 +2053,15 @@
EGLClientBuffer eglGetNativeClientBufferANDROID(const AHardwareBuffer *buffer) {
clearError();
+ // AHardwareBuffer_to_ANativeWindowBuffer is a platform-only symbol and thus
+ // this function cannot be implemented when this libEGL is built for
+ // vendors.
+#ifndef __ANDROID_VNDK__
if (!buffer) return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0);
return const_cast<ANativeWindowBuffer *>(AHardwareBuffer_to_ANativeWindowBuffer(buffer));
+#else
+ return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0);
+#endif
}
// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp
index dc1a4af..579e422 100644
--- a/opengl/libs/EGL/egl_cache.cpp
+++ b/opengl/libs/EGL/egl_cache.cpp
@@ -26,6 +26,7 @@
#include <inttypes.h>
#include <sys/mman.h>
#include <sys/stat.h>
+#include <unistd.h>
#include <thread>
diff --git a/services/inputflinger/InputWindow.cpp b/services/inputflinger/InputWindow.cpp
index 5e82d75..b54752b 100644
--- a/services/inputflinger/InputWindow.cpp
+++ b/services/inputflinger/InputWindow.cpp
@@ -46,8 +46,10 @@
|| layoutParamsType == TYPE_MAGNIFICATION_OVERLAY
|| layoutParamsType == TYPE_STATUS_BAR
|| layoutParamsType == TYPE_NAVIGATION_BAR
+ || layoutParamsType == TYPE_NAVIGATION_BAR_PANEL
|| layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY
- || layoutParamsType == TYPE_DOCK_DIVIDER;
+ || layoutParamsType == TYPE_DOCK_DIVIDER
+ || layoutParamsType == TYPE_ACCESSIBILITY_OVERLAY;
}
bool InputWindowInfo::supportsSplitTouch() const {
diff --git a/services/inputflinger/InputWindow.h b/services/inputflinger/InputWindow.h
index 0ac868b..610290b 100644
--- a/services/inputflinger/InputWindow.h
+++ b/services/inputflinger/InputWindow.h
@@ -101,7 +101,9 @@
TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19,
TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20,
TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21,
+ TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24,
TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27,
+ TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32,
TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW+34,
LAST_SYSTEM_WINDOW = 2999,
};
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index fad046c..bfe4c09 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -477,7 +477,14 @@
// separately before the next batch of events.
for (int j = 0; j < numEventsDropped; ++j) {
if (scratch[j].type == SENSOR_TYPE_META_DATA) {
- FlushInfo& flushInfo = mSensorInfo.editValueFor(scratch[j].meta_data.sensor);
+ ssize_t index = mSensorInfo.indexOfKey(scratch[j].meta_data.sensor);
+ if (index < 0) {
+ ALOGW("%s: sensor 0x%x is not found in connection",
+ __func__, scratch[j].meta_data.sensor);
+ continue;
+ }
+
+ FlushInfo& flushInfo = mSensorInfo.editValueAt(index);
flushInfo.mPendingFlushEventsToSend++;
ALOGD_IF(DEBUG_CONNECTIONS, "increment pendingFlushCount %d",
flushInfo.mPendingFlushEventsToSend);
diff --git a/services/sensorservice/hidl/SensorManager.cpp b/services/sensorservice/hidl/SensorManager.cpp
index 25a3dc5..cf5ab05 100644
--- a/services/sensorservice/hidl/SensorManager.cpp
+++ b/services/sensorservice/hidl/SensorManager.cpp
@@ -24,7 +24,6 @@
#include <sched.h>
-#include <thread>
#include "EventQueue.h"
#include "DirectReportChannel.h"
@@ -40,20 +39,24 @@
using ::android::hardware::sensors::V1_0::SensorsEventFormatOffset;
using ::android::hardware::hidl_vec;
using ::android::hardware::Void;
-using ::android::sp;
static const char* POLL_THREAD_NAME = "hidl_ssvc_poll";
SensorManager::SensorManager(JavaVM* vm)
- : mJavaVm(vm) {
+ : mLooper(new Looper(false /*allowNonCallbacks*/)), mStopThread(true), mJavaVm(vm) {
}
SensorManager::~SensorManager() {
// Stops pollAll inside the thread.
- std::unique_lock<std::mutex> lock(mLooperMutex);
+ std::lock_guard<std::mutex> lock(mThreadMutex);
+
+ mStopThread = true;
if (mLooper != nullptr) {
mLooper->wake();
}
+ if (mPollThread.joinable()) {
+ mPollThread.join();
+ }
}
// Methods from ::android::frameworks::sensorservice::V1_0::ISensorManager follow.
@@ -128,12 +131,13 @@
}
/* One global looper for all event queues created from this SensorManager. */
-sp<::android::Looper> SensorManager::getLooper() {
- std::unique_lock<std::mutex> lock(mLooperMutex);
- if (mLooper == nullptr) {
- std::condition_variable looperSet;
+sp<Looper> SensorManager::getLooper() {
+ std::lock_guard<std::mutex> lock(mThreadMutex);
- std::thread{[&mutex = mLooperMutex, &looper = mLooper, &looperSet, javaVm = mJavaVm] {
+ if (!mPollThread.joinable()) {
+ // if thread not initialized, start thread
+ mStopThread = false;
+ std::thread pollThread{[&stopThread = mStopThread, looper = mLooper, javaVm = mJavaVm] {
struct sched_param p = {0};
p.sched_priority = 10;
@@ -142,16 +146,11 @@
<< strerror(errno);
}
- std::unique_lock<std::mutex> lock(mutex);
- if (looper != nullptr) {
- LOG(INFO) << "Another thread has already set the looper, exiting this one.";
- return;
- }
- looper = Looper::prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS /* opts */);
- lock.unlock();
+ // set looper
+ Looper::setForThread(looper);
- // Attach the thread to JavaVM so that pollAll do not crash if the event
- // is from Java.
+ // Attach the thread to JavaVM so that pollAll do not crash if the thread
+ // eventually calls into Java.
JavaVMAttachArgs args{
.version = JNI_VERSION_1_2,
.name = POLL_THREAD_NAME,
@@ -162,19 +161,30 @@
LOG(FATAL) << "Cannot attach SensorManager looper thread to Java VM.";
}
- looperSet.notify_one();
- int pollResult = looper->pollAll(-1 /* timeout */);
- if (pollResult != ALOOPER_POLL_WAKE) {
- LOG(ERROR) << "Looper::pollAll returns unexpected " << pollResult;
+ LOG(INFO) << POLL_THREAD_NAME << " started.";
+ for (;;) {
+ int pollResult = looper->pollAll(-1 /* timeout */);
+ if (pollResult == Looper::POLL_WAKE) {
+ if (stopThread == true) {
+ LOG(INFO) << POLL_THREAD_NAME << ": requested to stop";
+ break;
+ } else {
+ LOG(INFO) << POLL_THREAD_NAME << ": spurious wake up, back to work";
+ }
+ } else {
+ LOG(ERROR) << POLL_THREAD_NAME << ": Looper::pollAll returns unexpected "
+ << pollResult;
+ break;
+ }
}
if (javaVm->DetachCurrentThread() != JNI_OK) {
LOG(ERROR) << "Cannot detach SensorManager looper thread from Java VM.";
}
- LOG(INFO) << "Looper thread is terminated.";
- }}.detach();
- looperSet.wait(lock, [this]{ return this->mLooper != nullptr; });
+ LOG(INFO) << POLL_THREAD_NAME << " is terminated.";
+ }};
+ mPollThread = std::move(pollThread);
}
return mLooper;
}
@@ -196,6 +206,12 @@
}
sp<::android::Looper> looper = getLooper();
+ if (looper == nullptr) {
+ LOG(ERROR) << "::android::SensorManager::createEventQueue cannot initialize looper";
+ _hidl_cb(nullptr, Result::UNKNOWN_ERROR);
+ return Void();
+ }
+
sp<::android::SensorEventQueue> internalQueue = getInternalManager().createEventQueue();
if (internalQueue == nullptr) {
LOG(WARNING) << "::android::SensorManager::createEventQueue returns nullptr.";
diff --git a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
index e66c8e5..ddcee28 100644
--- a/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
+++ b/services/sensorservice/hidl/include/sensorservicehidl/SensorManager.h
@@ -20,6 +20,7 @@
#include <jni.h>
#include <mutex>
+#include <thread>
#include <android/frameworks/sensorservice/1.0/ISensorManager.h>
#include <android/frameworks/sensorservice/1.0/types.h>
@@ -38,6 +39,7 @@
using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_memory;
using ::android::hardware::Return;
+using ::android::sp;
struct SensorManager final : public ISensorManager {
@@ -54,13 +56,15 @@
private:
// Block until ::android::SensorManager is initialized.
::android::SensorManager& getInternalManager();
- sp<::android::Looper> getLooper();
+ sp<Looper> getLooper();
std::mutex mInternalManagerMutex;
::android::SensorManager* mInternalManager = nullptr; // does not own
+ sp<Looper> mLooper;
- std::mutex mLooperMutex;
- sp<::android::Looper> mLooper;
+ volatile bool mStopThread;
+ std::mutex mThreadMutex; //protects mPollThread
+ std::thread mPollThread;
JavaVM* mJavaVm;
};
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index ae628e1..e34fa16 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -553,6 +553,29 @@
return Error::NONE;
}
+Error Composer::presentOrValidateDisplay(Display display, uint32_t* outNumTypes,
+ uint32_t* outNumRequests, int* outPresentFence, uint32_t* state) {
+ mWriter.selectDisplay(display);
+ mWriter.presentOrvalidateDisplay();
+
+ Error error = execute();
+ if (error != Error::NONE) {
+ return error;
+ }
+
+ mReader.takePresentOrValidateStage(display, state);
+
+ if (*state == 1) { // Present succeeded
+ mReader.takePresentFence(display, outPresentFence);
+ }
+
+ if (*state == 0) { // Validate succeeded.
+ mReader.hasChanges(display, outNumTypes, outNumRequests);
+ }
+
+ return Error::NONE;
+}
+
Error Composer::setCursorPosition(Display display, Layer layer,
int32_t x, int32_t y)
{
@@ -770,7 +793,8 @@
auto command = mWriter.getCommand(cmdErr.location);
if (command == IComposerClient::Command::VALIDATE_DISPLAY ||
- command == IComposerClient::Command::PRESENT_DISPLAY) {
+ command == IComposerClient::Command::PRESENT_DISPLAY ||
+ command == IComposerClient::Command::PRESENT_OR_VALIDATE_DISPLAY) {
error = cmdErr.error;
} else {
ALOGW("command 0x%x generated error %d",
@@ -821,6 +845,9 @@
case IComposerClient::Command::SET_RELEASE_FENCES:
parsed = parseSetReleaseFences(length);
break;
+ case IComposerClient::Command ::SET_PRESENT_OR_VALIDATE_DISPLAY_RESULT:
+ parsed = parseSetPresentOrValidateDisplayResult(length);
+ break;
default:
parsed = false;
break;
@@ -949,6 +976,15 @@
return true;
}
+bool CommandReader::parseSetPresentOrValidateDisplayResult(uint16_t length)
+{
+ if (length != CommandWriterBase::kPresentOrValidateDisplayResultLength || !mCurrentReturnData) {
+ return false;
+ }
+ mCurrentReturnData->presentOrValidateState = read();
+ return true;
+}
+
void CommandReader::resetData()
{
mErrors.clear();
@@ -1058,6 +1094,16 @@
data.presentFence = -1;
}
+void CommandReader::takePresentOrValidateStage(Display display, uint32_t* state) {
+ auto found = mReturnData.find(display);
+ if (found == mReturnData.end()) {
+ *state= -1;
+ return;
+ }
+ ReturnData& data = found->second;
+ *state = data.presentOrValidateState;
+}
+
} // namespace Hwc2
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 68d6e6f..96dd833 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -93,6 +93,9 @@
// Get and clear saved present fence.
void takePresentFence(Display display, int* outPresentFence);
+ // Get what stage succeeded during PresentOrValidate: Present or Validate
+ void takePresentOrValidateStage(Display display, uint32_t * state);
+
private:
void resetData();
@@ -102,6 +105,7 @@
bool parseSetDisplayRequests(uint16_t length);
bool parseSetPresentFence(uint16_t length);
bool parseSetReleaseFences(uint16_t length);
+ bool parseSetPresentOrValidateDisplayResult(uint16_t length);
struct ReturnData {
uint32_t displayRequests = 0;
@@ -116,6 +120,8 @@
std::vector<Layer> releasedLayers;
std::vector<int> releaseFences;
+
+ uint32_t presentOrValidateState;
};
std::vector<CommandError> mErrors;
@@ -202,6 +208,11 @@
Error validateDisplay(Display display, uint32_t* outNumTypes,
uint32_t* outNumRequests);
+ Error presentOrValidateDisplay(Display display, uint32_t* outNumTypes,
+ uint32_t* outNumRequests,
+ int* outPresentFence,
+ uint32_t* state);
+
Error setCursorPosition(Display display, Layer layer,
int32_t x, int32_t y);
/* see setClientTarget for the purpose of slot */
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 263ff00..270a732 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -695,6 +695,34 @@
return error;
}
+Error Display::presentOrValidate(uint32_t* outNumTypes, uint32_t* outNumRequests,
+ sp<android::Fence>* outPresentFence, uint32_t* state) {
+
+ uint32_t numTypes = 0;
+ uint32_t numRequests = 0;
+ int32_t presentFenceFd = -1;
+ auto intError = mDevice.mComposer->presentOrValidateDisplay(mId, &numTypes, &numRequests, &presentFenceFd, state);
+ auto error = static_cast<Error>(intError);
+ if (error != Error::None && error != Error::HasChanges) {
+ return error;
+ }
+
+ if (*state == 1) {
+ *outPresentFence = new Fence(presentFenceFd);
+ }
+
+ if (*state == 0) {
+ *outNumTypes = numTypes;
+ *outNumRequests = numRequests;
+ }
+ return error;
+}
+
+void Display::discardCommands()
+{
+ mDevice.mComposer->resetCommands();
+}
+
// For use by Device
int32_t Display::getAttribute(hwc2_config_t configId, Attribute attribute)
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index b7376d0..404bb28 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -255,6 +255,15 @@
[[clang::warn_unused_result]] Error setVsyncEnabled(Vsync enabled);
[[clang::warn_unused_result]] Error validate(uint32_t* outNumTypes,
uint32_t* outNumRequests);
+ [[clang::warn_unused_result]] Error presentOrValidate(uint32_t* outNumTypes,
+ uint32_t* outNumRequests,
+ android::sp<android::Fence>* outPresentFence, uint32_t* state);
+
+ // Most methods in this class write a command to a command buffer. The
+ // command buffer is implicitly submitted in validate, present, and
+ // presentOrValidate. This method provides a way to discard the commands,
+ // which can be used to discard stale commands.
+ void discardCommands();
// Other Display methods
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 42be935..ac2dde2 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -455,7 +455,34 @@
uint32_t numTypes = 0;
uint32_t numRequests = 0;
- auto error = hwcDisplay->validate(&numTypes, &numRequests);
+
+ HWC2::Error error = HWC2::Error::None;
+
+ // First try to skip validate altogether if the HWC supports it.
+ displayData.validateWasSkipped = false;
+ if (hasCapability(HWC2::Capability::SkipValidate) &&
+ !displayData.hasClientComposition) {
+ sp<android::Fence> outPresentFence;
+ uint32_t state = UINT32_MAX;
+ error = hwcDisplay->presentOrValidate(&numTypes, &numRequests, &outPresentFence , &state);
+ if (error != HWC2::Error::None && error != HWC2::Error::HasChanges) {
+ ALOGV("skipValidate: Failed to Present or Validate");
+ return UNKNOWN_ERROR;
+ }
+ if (state == 1) { //Present Succeeded.
+ std::unordered_map<std::shared_ptr<HWC2::Layer>, sp<Fence>> releaseFences;
+ error = hwcDisplay->getReleaseFences(&releaseFences);
+ displayData.releaseFences = std::move(releaseFences);
+ displayData.lastPresentFence = outPresentFence;
+ displayData.validateWasSkipped = true;
+ displayData.presentError = error;
+ return NO_ERROR;
+ }
+ // Present failed but Validate ran.
+ } else {
+ error = hwcDisplay->validate(&numTypes, &numRequests);
+ }
+ ALOGV("SkipValidate failed, Falling back to SLOW validate/present");
if (error != HWC2::Error::None && error != HWC2::Error::HasChanges) {
ALOGE("prepare: validate failed for display %d: %s (%d)", displayId,
to_string(error).c_str(), static_cast<int32_t>(error));
@@ -592,6 +619,18 @@
auto& displayData = mDisplayData[displayId];
auto& hwcDisplay = displayData.hwcDisplay;
+
+ if (displayData.validateWasSkipped) {
+ hwcDisplay->discardCommands();
+ auto error = displayData.presentError;
+ if (error != HWC2::Error::None) {
+ ALOGE("skipValidate: failed for display %d: %s (%d)",
+ displayId, to_string(error).c_str(), static_cast<int32_t>(error));
+ return UNKNOWN_ERROR;
+ }
+ return NO_ERROR;
+ }
+
auto error = hwcDisplay->present(&displayData.lastPresentFence);
if (error != HWC2::Error::None) {
ALOGE("presentAndGetReleaseFences: failed for display %d: %s (%d)",
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 3eb968d..7463362 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -202,6 +202,9 @@
// protected by mVsyncLock
HWC2::Vsync vsyncEnabled;
+
+ bool validateWasSkipped;
+ HWC2::Error presentError;
};
std::unique_ptr<HWC2::Device> mHwcDevice;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 5aed896..273f194 100755
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1952,7 +1952,6 @@
mCurrentState.barrierLayer = nullptr;
mCurrentState.frameNumber = 0;
mCurrentState.modified = false;
- ALOGE("Deferred transaction");
}
void Layer::deferTransactionUntil(const sp<IBinder>& barrierHandle,
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 6ed372c..392479f 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -408,6 +408,7 @@
* to figure out if the content or size of a surface has changed.
*/
Region latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime);
+ bool isBufferLatched() const { return mRefreshPending; }
bool isPotentialCursor() const { return mPotentialCursor;}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index c6ce82c..c10493b 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2457,7 +2457,7 @@
const Region dirty(layer->latchBuffer(visibleRegions, latchTime));
layer->useSurfaceDamage();
invalidateLayerStack(layer->getLayerStack(), dirty);
- if (!dirty.isEmpty()) {
+ if (layer->isBufferLatched()) {
newDataLatched = true;
}
}
@@ -2467,7 +2467,7 @@
// If we will need to wake up at some time in the future to deal with a
// queued frame that shouldn't be displayed during this vsync period, wake
// up during the next vsync period to check again.
- if (frameQueued && mLayersWithQueuedFrames.empty()) {
+ if (frameQueued && (mLayersWithQueuedFrames.empty() || !newDataLatched)) {
signalLayerUpdate();
}
@@ -2730,8 +2730,6 @@
return NO_ERROR;
}
- index = p->removeChild(layer);
-
sp<Layer> ancestor = p;
while (ancestor->getParent() != nullptr) {
ancestor = ancestor->getParent();
@@ -2740,6 +2738,8 @@
ALOGE("removeLayer called with a layer whose parent has been removed");
return NAME_NOT_FOUND;
}
+
+ index = p->removeChild(layer);
} else {
index = mCurrentState.layersSortedByZ.remove(layer);
}
@@ -3770,6 +3770,15 @@
*/
const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
alloc.dump(result);
+
+ /*
+ * Dump VrFlinger state if in use.
+ */
+ if (mVrFlingerRequestsDisplay && mVrFlinger) {
+ result.append("VrFlinger state:\n");
+ result.append(mVrFlinger->Dump().c_str());
+ result.append("\n");
+ }
}
const Vector< sp<Layer> >&
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
index 9babeef..abc8fde 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
@@ -240,10 +240,15 @@
}
void SurfaceFlingerConsumer::onSidebandStreamChanged() {
+ FrameAvailableListener* unsafeFrameAvailableListener = nullptr;
+ {
+ Mutex::Autolock lock(mFrameAvailableMutex);
+ unsafeFrameAvailableListener = mFrameAvailableListener.unsafe_get();
+ }
sp<ContentsChangedListener> listener;
{ // scope for the lock
Mutex::Autolock lock(mMutex);
- ALOG_ASSERT(mFrameAvailableListener.unsafe_get() == mContentsChangedListener.unsafe_get());
+ ALOG_ASSERT(unsafeFrameAvailableListener == mContentsChangedListener.unsafe_get());
listener = mContentsChangedListener.promote();
}
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 7856114..f8d1bb0 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -2327,8 +2327,13 @@
if (parent == nullptr) {
mCurrentState.layersSortedByZ.add(lbc);
} else {
+ if (mCurrentState.layersSortedByZ.indexOf(parent) < 0) {
+ ALOGE("addClientLayer called with a removed parent");
+ return NAME_NOT_FOUND;
+ }
parent->addChild(lbc);
}
+
mGraphicBufferProducerList.add(IInterface::asBinder(gbc));
mLayersAdded = true;
mNumLayers++;
@@ -2350,6 +2355,15 @@
return NO_ERROR;
}
+ sp<Layer> ancestor = p;
+ while (ancestor->getParent() != nullptr) {
+ ancestor = ancestor->getParent();
+ }
+ if (mCurrentState.layersSortedByZ.indexOf(ancestor) < 0) {
+ ALOGE("removeLayer called with a layer whose parent has been removed");
+ return NAME_NOT_FOUND;
+ }
+
index = p->removeChild(layer);
} else {
index = mCurrentState.layersSortedByZ.remove(layer);
@@ -2371,7 +2385,7 @@
mLayersPendingRemoval.add(layer);
mLayersRemoved = true;
- mNumLayers--;
+ mNumLayers -= 1 + layer->getChildrenCount();
setTransactionFlags(eTransactionNeeded);
return NO_ERROR;
}
diff --git a/services/vr/hardware_composer/impl/vr_hwc.cpp b/services/vr/hardware_composer/impl/vr_hwc.cpp
index 9bbb7f3..861114d 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.cpp
+++ b/services/vr/hardware_composer/impl/vr_hwc.cpp
@@ -15,6 +15,7 @@
*/
#include "impl/vr_hwc.h"
+#include <cutils/properties.h>
#include <private/dvr/display_client.h>
#include <ui/Fence.h>
@@ -352,7 +353,14 @@
break;
case IComposerClient::Attribute::DPI_X:
case IComposerClient::Attribute::DPI_Y:
- *outValue = 300 * 1000; // 300dpi
+ {
+ constexpr int32_t kDefaultDPI = 300;
+ int32_t dpi = property_get_int32("ro.vr.hwc.dpi", kDefaultDPI);
+ if (dpi <= 0) {
+ dpi = kDefaultDPI;
+ }
+ *outValue = 1000 * dpi;
+ }
break;
default:
return Error::BAD_PARAMETER;
diff --git a/services/vr/performanced/Android.mk b/services/vr/performanced/Android.mk
index 6256e90..dbc66f1 100644
--- a/services/vr/performanced/Android.mk
+++ b/services/vr/performanced/Android.mk
@@ -23,8 +23,10 @@
staticLibraries := \
libperformance \
libpdx_default_transport \
+ libvr_manager
sharedLibraries := \
+ libbinder \
libbase \
libcutils \
liblog \
diff --git a/services/vr/performanced/cpu_set.cpp b/services/vr/performanced/cpu_set.cpp
index 1a3723f..1a7264c 100644
--- a/services/vr/performanced/cpu_set.cpp
+++ b/services/vr/performanced/cpu_set.cpp
@@ -15,6 +15,9 @@
#include "task.h"
#include "unique_file.h"
+using android::pdx::ErrorStatus;
+using android::pdx::Status;
+
namespace {
constexpr int kDirectoryFlags = O_RDONLY | O_DIRECTORY | O_CLOEXEC;
@@ -176,11 +179,11 @@
task_id, task.name().c_str(), target_set.c_str(),
task.thread_group_id(), task.parent_process_id());
- const int ret = target->AttachTask(task_id);
- ALOGW_IF(ret < 0 && ret != -EINVAL,
+ auto status = target->AttachTask(task_id);
+ ALOGW_IF(!status && status.error() != EINVAL,
"CpuSetManager::MoveUnboundTasks: Failed to attach task_id=%d "
"to cpuset=%s: %s",
- task_id, target_set.c_str(), strerror(-ret));
+ task_id, target_set.c_str(), status.GetErrorMessage().c_str());
} else {
ALOGD_IF(TRACE,
"CpuSet::MoveUnboundTasks: Skipping task_id=%d name=%s cpus=%s.",
@@ -233,7 +236,7 @@
return fp;
}
-int CpuSet::AttachTask(pid_t task_id) const {
+Status<void> CpuSet::AttachTask(pid_t task_id) const {
auto file = OpenFile("tasks", O_RDWR);
if (file.get() >= 0) {
std::ostringstream stream;
@@ -241,11 +244,15 @@
std::string value = stream.str();
const bool ret = base::WriteStringToFd(value, file.get());
- return !ret ? -errno : 0;
+ if (!ret)
+ return ErrorStatus(errno);
+ else
+ return {};
} else {
+ const int error = errno;
ALOGE("CpuSet::AttachTask: Failed to open %s/tasks: %s", path_.c_str(),
- strerror(errno));
- return -errno;
+ strerror(error));
+ return ErrorStatus(error);
}
}
diff --git a/services/vr/performanced/cpu_set.h b/services/vr/performanced/cpu_set.h
index fcf280a..6879272 100644
--- a/services/vr/performanced/cpu_set.h
+++ b/services/vr/performanced/cpu_set.h
@@ -11,6 +11,8 @@
#include <android-base/unique_fd.h>
+#include <pdx/status.h>
+
#include "unique_file.h"
namespace android {
@@ -28,7 +30,7 @@
std::string GetCpuList() const;
- int AttachTask(pid_t task_id) const;
+ pdx::Status<void> AttachTask(pid_t task_id) const;
std::vector<pid_t> GetTasks() const;
private:
diff --git a/services/vr/performanced/performance_service.cpp b/services/vr/performanced/performance_service.cpp
index 955c661..3f7009a 100644
--- a/services/vr/performanced/performance_service.cpp
+++ b/services/vr/performanced/performance_service.cpp
@@ -8,14 +8,20 @@
#include <pdx/rpc/argument_encoder.h>
#include <pdx/rpc/message_buffer.h>
#include <pdx/rpc/remote_method.h>
+#include <private/android_filesystem_config.h>
#include <private/dvr/performance_rpc.h>
+#include <private/dvr/trusted_uids.h>
#include "task.h"
// This prctl is only available in Android kernels.
#define PR_SET_TIMERSLACK_PID 41
+using android::dvr::IsTrustedUid;
+using android::dvr::Task;
+using android::pdx::ErrorStatus;
using android::pdx::Message;
+using android::pdx::Status;
using android::pdx::rpc::DispatchRemoteMethod;
using android::pdx::default_transport::Endpoint;
@@ -26,6 +32,68 @@
constexpr unsigned long kTimerSlackForegroundNs = 50000;
constexpr unsigned long kTimerSlackBackgroundNs = 40000000;
+// Expands the given parameter pack expression using an initializer list to
+// guarantee ordering and a comma expression to guarantee even void expressions
+// are valid elements of the initializer list.
+#define EXPAND_PACK(...) \
+ std::initializer_list<int> { (__VA_ARGS__, 0)... }
+
+// Returns true if the sender's euid matches any of the uids in |UIDs|.
+template <uid_t... UIDs>
+struct UserId {
+ static bool Check(const Message& sender, const Task&) {
+ const uid_t uid = sender.GetEffectiveUserId();
+ bool allow = false;
+ EXPAND_PACK(allow |= (uid == UIDs));
+ return allow;
+ }
+};
+
+// Returns true if the sender's egid matches any of the gids in |GIDs|.
+template <gid_t... GIDs>
+struct GroupId {
+ static bool Check(const Message& sender, const Task&) {
+ const gid_t gid = sender.GetEffectiveGroupId();
+ bool allow = false;
+ EXPAND_PACK(allow |= (gid == GIDs));
+ return allow;
+ }
+};
+
+// Returns true if the sender's euid is trusted according to VR manager service.
+struct Trusted {
+ static bool Check(const Message& sender, const Task&) {
+ return IsTrustedUid(sender.GetEffectiveUserId(), false);
+ }
+};
+
+// Returns returns true if the task belongs to the sending process.
+struct SameProcess {
+ static bool Check(const Message& sender, const Task& task) {
+ return sender.GetProcessId() == task.thread_group_id();
+ }
+};
+
+// Returns true if any of the checks in |Allows| pass, false otherwise.
+template <typename... Allows>
+struct CheckOr {
+ static bool Check(const Message& sender, const Task& task) {
+ bool allow = false;
+ EXPAND_PACK(allow |= Allows::Check(sender, task));
+ return allow;
+ }
+};
+
+// Returns true if all of the checks in |Allows| pass, false otherwise.
+template <typename... Allows>
+struct CheckAnd {
+ static bool Check(const Message& sender, const Task& task) {
+ bool allow = true;
+ EXPAND_PACK(allow &= Allows::Check(sender, task));
+ return allow;
+ }
+};
+
} // anonymous namespace
namespace android {
@@ -48,43 +116,79 @@
const int fifo_low = sched_fifo_min_priority_;
const int fifo_medium = sched_fifo_min_priority_ + fifo_range / 5;
- // TODO(eieio): Make this configurable on the command line.
+ // TODO(eieio): Make this configurable on the command line or config file.
cpuset_.MoveUnboundTasks("/kernel");
+ // TODO(eieio): Replace this witha device-specific config file. This is just a
+ // hack for now to put some form of permission logic in place while a longer
+ // term solution is developed.
+ using AllowRootSystem =
+ CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM>,
+ GroupId<AID_SYSTEM>>>;
+ using AllowRootSystemGraphics =
+ CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM, AID_GRAPHICS>,
+ GroupId<AID_SYSTEM, AID_GRAPHICS>>>;
+ using AllowRootSystemAudio =
+ CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM, AID_AUDIO>,
+ GroupId<AID_SYSTEM, AID_AUDIO>>>;
+ using AllowRootSystemTrusted = CheckOr<Trusted, UserId<AID_ROOT, AID_SYSTEM>,
+ GroupId<AID_SYSTEM>>;
+
+ partition_permission_check_ = AllowRootSystemTrusted::Check;
+
// Setup the scheduler classes.
+ // TODO(eieio): Replace this with a device-specific config file.
scheduler_classes_ = {
{"audio:low",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_medium}},
+ .priority = fifo_medium,
+ .permission_check = AllowRootSystemAudio::Check}},
{"audio:high",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_medium + 3}},
+ .priority = fifo_medium + 3,
+ .permission_check = AllowRootSystemAudio::Check}},
{"graphics",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_medium}},
+ .priority = fifo_medium,
+ .permission_check = AllowRootSystemGraphics::Check}},
{"graphics:low",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_medium}},
+ .priority = fifo_medium,
+ .permission_check = AllowRootSystemGraphics::Check}},
{"graphics:high",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_medium + 2}},
+ .priority = fifo_medium + 2,
+ .permission_check = AllowRootSystemGraphics::Check}},
{"sensors",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_low}},
+ .priority = fifo_low,
+ .permission_check = AllowRootSystem::Check}},
{"sensors:low",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_low}},
+ .priority = fifo_low,
+ .permission_check = AllowRootSystem::Check}},
{"sensors:high",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
- .priority = fifo_low + 1}},
+ .priority = fifo_low + 1,
+ .permission_check = AllowRootSystem::Check}},
+ {"vr:system:arp",
+ {.timer_slack = kTimerSlackForegroundNs,
+ .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
+ .priority = fifo_medium + 2,
+ .permission_check = AllowRootSystemTrusted::Check}},
+ {"vr:app:render",
+ {.timer_slack = kTimerSlackForegroundNs,
+ .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
+ .priority = fifo_medium + 1,
+ .permission_check = AllowRootSystemTrusted::Check}},
{"normal",
{.timer_slack = kTimerSlackForegroundNs,
.scheduler_policy = SCHED_NORMAL,
@@ -113,67 +217,94 @@
return cpuset_.DumpState();
}
-int PerformanceService::OnSetCpuPartition(Message& message, pid_t task_id,
- const std::string& partition) {
+Status<void> PerformanceService::OnSetSchedulerPolicy(
+ Message& message, pid_t task_id, const std::string& scheduler_policy) {
+ // Forward to scheduler class handler for now. In the future this method will
+ // subsume the others by unifying both scheduler class and cpu partiton into a
+ // single policy concept.
+ ALOGI(
+ "PerformanceService::OnSetSchedulerPolicy: task_id=%d "
+ "scheduler_policy=%s",
+ task_id, scheduler_policy.c_str());
+ return OnSetSchedulerClass(message, task_id, scheduler_policy);
+}
+
+Status<void> PerformanceService::OnSetCpuPartition(
+ Message& message, pid_t task_id, const std::string& partition) {
Task task(task_id);
if (!task || task.thread_group_id() != message.GetProcessId())
- return -EINVAL;
+ return ErrorStatus(EINVAL);
+
+ // Temporary permission check.
+ // TODO(eieio): Replace this with a configuration file.
+ if (partition_permission_check_ &&
+ !partition_permission_check_(message, task)) {
+ return ErrorStatus(EINVAL);
+ }
auto target_set = cpuset_.Lookup(partition);
if (!target_set)
- return -ENOENT;
+ return ErrorStatus(ENOENT);
- const auto attach_error = target_set->AttachTask(task_id);
- if (attach_error)
- return attach_error;
+ auto attach_status = target_set->AttachTask(task_id);
+ if (!attach_status)
+ return attach_status;
- return 0;
+ return {};
}
-int PerformanceService::OnSetSchedulerClass(
+Status<void> PerformanceService::OnSetSchedulerClass(
Message& message, pid_t task_id, const std::string& scheduler_class) {
- // Make sure the task id is valid and belongs to the sending process.
Task task(task_id);
- if (!task || task.thread_group_id() != message.GetProcessId())
- return -EINVAL;
+ if (!task)
+ return ErrorStatus(EINVAL);
- struct sched_param param;
-
- // TODO(eieio): Apply rules based on the requesting process. Applications are
- // only allowed one audio thread that runs at SCHED_FIFO. System services can
- // have more than one.
auto search = scheduler_classes_.find(scheduler_class);
if (search != scheduler_classes_.end()) {
auto config = search->second;
+
+ // Make sure the sending process is allowed to make the requested change to
+ // this task.
+ if (!config.IsAllowed(message, task))
+ return ErrorStatus(EINVAL);
+
+ struct sched_param param;
param.sched_priority = config.priority;
+
sched_setscheduler(task_id, config.scheduler_policy, ¶m);
prctl(PR_SET_TIMERSLACK_PID, config.timer_slack, task_id);
ALOGI("PerformanceService::OnSetSchedulerClass: Set task=%d to class=%s.",
task_id, scheduler_class.c_str());
- return 0;
+ return {};
} else {
ALOGE(
"PerformanceService::OnSetSchedulerClass: Invalid class=%s requested "
"by task=%d.",
scheduler_class.c_str(), task_id);
- return -EINVAL;
+ return ErrorStatus(EINVAL);
}
}
-std::string PerformanceService::OnGetCpuPartition(Message& message,
- pid_t task_id) {
+Status<std::string> PerformanceService::OnGetCpuPartition(Message& message,
+ pid_t task_id) {
// Make sure the task id is valid and belongs to the sending process.
Task task(task_id);
if (!task || task.thread_group_id() != message.GetProcessId())
- REPLY_ERROR_RETURN(message, EINVAL, "");
+ return ErrorStatus(EINVAL);
return task.GetCpuSetPath();
}
-pdx::Status<void> PerformanceService::HandleMessage(Message& message) {
+Status<void> PerformanceService::HandleMessage(Message& message) {
+ ALOGD_IF(TRACE, "PerformanceService::HandleMessage: op=%d", message.GetOp());
switch (message.GetOp()) {
+ case PerformanceRPC::SetSchedulerPolicy::Opcode:
+ DispatchRemoteMethod<PerformanceRPC::SetSchedulerPolicy>(
+ *this, &PerformanceService::OnSetSchedulerPolicy, message);
+ return {};
+
case PerformanceRPC::SetCpuPartition::Opcode:
- DispatchRemoteMethod<PerformanceRPC::SetSchedulerClass>(
+ DispatchRemoteMethod<PerformanceRPC::SetCpuPartition>(
*this, &PerformanceService::OnSetCpuPartition, message);
return {};
diff --git a/services/vr/performanced/performance_service.h b/services/vr/performanced/performance_service.h
index 34abba7..b812535 100644
--- a/services/vr/performanced/performance_service.h
+++ b/services/vr/performanced/performance_service.h
@@ -1,12 +1,14 @@
#ifndef ANDROID_DVR_PERFORMANCED_PERFORMANCE_SERVICE_H_
#define ANDROID_DVR_PERFORMANCED_PERFORMANCE_SERVICE_H_
+#include <functional>
#include <string>
#include <unordered_map>
#include <pdx/service.h>
#include "cpu_set.h"
+#include "task.h"
namespace android {
namespace dvr {
@@ -27,11 +29,15 @@
PerformanceService();
- int OnSetCpuPartition(pdx::Message& message, pid_t task_id,
- const std::string& partition);
- int OnSetSchedulerClass(pdx::Message& message, pid_t task_id,
- const std::string& scheduler_class);
- std::string OnGetCpuPartition(pdx::Message& message, pid_t task_id);
+ pdx::Status<void> OnSetSchedulerPolicy(pdx::Message& message, pid_t task_id,
+ const std::string& scheduler_class);
+
+ pdx::Status<void> OnSetCpuPartition(pdx::Message& message, pid_t task_id,
+ const std::string& partition);
+ pdx::Status<void> OnSetSchedulerClass(pdx::Message& message, pid_t task_id,
+ const std::string& scheduler_class);
+ pdx::Status<std::string> OnGetCpuPartition(pdx::Message& message,
+ pid_t task_id);
CpuSetManager cpuset_;
@@ -43,10 +49,24 @@
unsigned long timer_slack;
int scheduler_policy;
int priority;
+ std::function<bool(const pdx::Message& message, const Task& task)>
+ permission_check;
+
+ // Check the permisison of the given task to use this scheduler class. If a
+ // permission check function is not set then all tasks are allowed.
+ bool IsAllowed(const pdx::Message& message, const Task& task) const {
+ if (permission_check)
+ return permission_check(message, task);
+ else
+ return true;
+ }
};
std::unordered_map<std::string, SchedulerClassConfig> scheduler_classes_;
+ std::function<bool(const pdx::Message& message, const Task& task)>
+ partition_permission_check_;
+
PerformanceService(const PerformanceService&) = delete;
void operator=(const PerformanceService&) = delete;
};
diff --git a/services/vr/performanced/performance_service_tests.cpp b/services/vr/performanced/performance_service_tests.cpp
index b526082..7de1f08 100644
--- a/services/vr/performanced/performance_service_tests.cpp
+++ b/services/vr/performanced/performance_service_tests.cpp
@@ -1,12 +1,22 @@
#include <errno.h>
#include <sched.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <condition_variable>
+#include <cstdlib>
#include <mutex>
#include <thread>
#include <dvr/performance_client_api.h>
#include <gtest/gtest.h>
+#include <private/android_filesystem_config.h>
+
+namespace {
+
+const char kTrustedUidEnvironmentVariable[] = "GTEST_TRUSTED_UID";
+
+} // anonymous namespace
TEST(DISABLED_PerformanceTest, SetCpuPartition) {
int error;
@@ -86,6 +96,27 @@
EXPECT_EQ(-EINVAL, error);
}
+// This API mirrors SetSchedulerClass for now. Replace with with a more specific
+// test once the policy API is fully implemented.
+TEST(PerformanceTest, SetSchedulerPolicy) {
+ int error;
+
+ error = dvrSetSchedulerPolicy(0, "background");
+ EXPECT_EQ(0, error);
+ EXPECT_EQ(SCHED_BATCH, sched_getscheduler(0));
+
+ error = dvrSetSchedulerPolicy(0, "audio:low");
+ EXPECT_EQ(0, error);
+ EXPECT_EQ(SCHED_FIFO | SCHED_RESET_ON_FORK, sched_getscheduler(0));
+
+ error = dvrSetSchedulerPolicy(0, "normal");
+ EXPECT_EQ(0, error);
+ EXPECT_EQ(SCHED_NORMAL, sched_getscheduler(0));
+
+ error = dvrSetSchedulerPolicy(0, "foobar");
+ EXPECT_EQ(-EINVAL, error);
+}
+
TEST(PerformanceTest, SchedulerClassResetOnFork) {
int error;
@@ -135,3 +166,273 @@
error = dvrGetCpuPartition(0, nullptr, sizeof(partition));
EXPECT_EQ(-EINVAL, error);
}
+
+TEST(PerformanceTest, Permissions) {
+ int error;
+
+ const int original_uid = getuid();
+ const int original_gid = getgid();
+ int trusted_uid = -1;
+
+ // See if the environment variable GTEST_TRUSTED_UID is set. If it is enable
+ // testing the ActivityManager trusted uid permission checks using that uid.
+ const char* trusted_uid_env = std::getenv(kTrustedUidEnvironmentVariable);
+ if (trusted_uid_env)
+ trusted_uid = std::atoi(trusted_uid_env);
+
+ ASSERT_EQ(AID_ROOT, original_uid)
+ << "This test must run as root to function correctly!";
+
+ // Switch the uid/gid to an id that should not have permission to access any
+ // privileged actions.
+ ASSERT_EQ(0, setresgid(AID_NOBODY, AID_NOBODY, -1))
+ << "Failed to set gid: " << strerror(errno);
+ ASSERT_EQ(0, setresuid(AID_NOBODY, AID_NOBODY, -1))
+ << "Failed to set uid: " << strerror(errno);
+
+ // Unprivileged policies.
+ error = dvrSetSchedulerPolicy(0, "batch");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "background");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "foreground");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "normal");
+ EXPECT_EQ(0, error);
+
+ // Privileged policies.
+ error = dvrSetSchedulerPolicy(0, "audio:low");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "audio:high");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "graphics");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:low");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:high");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "sensors");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:low");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:high");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "vr:system:arp");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "vr:app:render");
+ EXPECT_EQ(-EINVAL, error);
+
+ // uid=AID_SYSTEM / gid=AID_NOBODY
+ ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
+ << "Failed to restore uid: " << strerror(errno);
+ ASSERT_EQ(0, setresuid(AID_SYSTEM, AID_SYSTEM, -1))
+ << "Failed to set uid: " << strerror(errno);
+
+ // Unprivileged policies.
+ error = dvrSetSchedulerPolicy(0, "batch");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "background");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "foreground");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "normal");
+ EXPECT_EQ(0, error);
+
+ // Privileged policies.
+ error = dvrSetSchedulerPolicy(0, "audio:low");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "audio:high");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:low");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:high");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "sensors");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:low");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:high");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "vr:system:arp");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "vr:app:render");
+ EXPECT_EQ(0, error);
+
+ // uid=AID_NOBODY / gid=AID_SYSTEM
+ ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
+ << "Failed to restore uid: " << strerror(errno);
+ ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
+ << "Failed to restore gid: " << strerror(errno);
+ ASSERT_EQ(0, setresgid(AID_SYSTEM, AID_SYSTEM, -1))
+ << "Failed to set gid: " << strerror(errno);
+ ASSERT_EQ(0, setresuid(AID_SYSTEM, AID_NOBODY, -1))
+ << "Failed to set uid: " << strerror(errno);
+
+ // Unprivileged policies.
+ error = dvrSetSchedulerPolicy(0, "batch");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "background");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "foreground");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "normal");
+ EXPECT_EQ(0, error);
+
+ // Privileged policies.
+ error = dvrSetSchedulerPolicy(0, "audio:low");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "audio:high");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:low");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:high");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "sensors");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:low");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:high");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "vr:system:arp");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "vr:app:render");
+ EXPECT_EQ(0, error);
+
+ // uid=AID_GRAPHICS / gid=AID_NOBODY
+ ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
+ << "Failed to restore uid: " << strerror(errno);
+ ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
+ << "Failed to restore gid: " << strerror(errno);
+ ASSERT_EQ(0, setresgid(AID_NOBODY, AID_NOBODY, -1))
+ << "Failed to set gid: " << strerror(errno);
+ ASSERT_EQ(0, setresuid(AID_GRAPHICS, AID_GRAPHICS, -1))
+ << "Failed to set uid: " << strerror(errno);
+
+ // Unprivileged policies.
+ error = dvrSetSchedulerPolicy(0, "batch");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "background");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "foreground");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "normal");
+ EXPECT_EQ(0, error);
+
+ // Privileged policies.
+ error = dvrSetSchedulerPolicy(0, "audio:low");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "audio:high");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "graphics");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:low");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:high");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "sensors");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:low");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:high");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "vr:system:arp");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "vr:app:render");
+ EXPECT_EQ(-EINVAL, error);
+
+ // uid=AID_NOBODY / gid=AID_GRAPHICS
+ ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
+ << "Failed to restore uid: " << strerror(errno);
+ ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
+ << "Failed to restore gid: " << strerror(errno);
+ ASSERT_EQ(0, setresgid(AID_GRAPHICS, AID_GRAPHICS, -1))
+ << "Failed to set gid: " << strerror(errno);
+ ASSERT_EQ(0, setresuid(AID_NOBODY, AID_NOBODY, -1))
+ << "Failed to set uid: " << strerror(errno);
+
+ // Unprivileged policies.
+ error = dvrSetSchedulerPolicy(0, "batch");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "background");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "foreground");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "normal");
+ EXPECT_EQ(0, error);
+
+ // Privileged policies.
+ error = dvrSetSchedulerPolicy(0, "audio:low");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "audio:high");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "graphics");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:low");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:high");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "sensors");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:low");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:high");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "vr:system:arp");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "vr:app:render");
+ EXPECT_EQ(-EINVAL, error);
+
+ if (trusted_uid != -1) {
+ // uid=<trusted uid> / gid=AID_NOBODY
+ ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
+ << "Failed to restore uid: " << strerror(errno);
+ ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
+ << "Failed to restore gid: " << strerror(errno);
+ ASSERT_EQ(0, setresgid(AID_NOBODY, AID_NOBODY, -1))
+ << "Failed to set gid: " << strerror(errno);
+ ASSERT_EQ(0, setresuid(trusted_uid, trusted_uid, -1))
+ << "Failed to set uid: " << strerror(errno);
+
+ // Unprivileged policies.
+ error = dvrSetSchedulerPolicy(0, "batch");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "background");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "foreground");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "normal");
+ EXPECT_EQ(0, error);
+
+ // Privileged policies.
+ error = dvrSetSchedulerPolicy(0, "audio:low");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "audio:high");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "graphics");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:low");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "graphics:high");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "sensors");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:low");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "sensors:high");
+ EXPECT_EQ(-EINVAL, error);
+ error = dvrSetSchedulerPolicy(0, "vr:system:arp");
+ EXPECT_EQ(0, error);
+ error = dvrSetSchedulerPolicy(0, "vr:app:render");
+ EXPECT_EQ(0, error);
+ }
+
+ // Restore original effective uid/gid.
+ ASSERT_EQ(0, setresgid(original_gid, original_gid, -1))
+ << "Failed to restore gid: " << strerror(errno);
+ ASSERT_EQ(0, setresuid(original_uid, original_uid, -1))
+ << "Failed to restore uid: " << strerror(errno);
+}