Merge "Double check hidl service at init + meaningful abort when hidl crash"
diff --git a/cmds/bugreportz/readme.md b/cmds/bugreportz/readme.md
index 2697f09..eb0d898 100644
--- a/cmds/bugreportz/readme.md
+++ b/cmds/bugreportz/readme.md
@@ -17,3 +17,4 @@
- `OK:<path_to_bugreport_file>` in case of success.
- `FAIL:<error message>` in case of failure.
+
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index e953ded..9e60461 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -159,22 +159,37 @@
return true;
}
+void Lshal::forEachTable(const std::function<void(Table &)> &f) {
+ for (const Table &table : {mServicesTable, mPassthroughRefTable, mImplementationsTable}) {
+ f(const_cast<Table &>(table));
+ }
+}
+void Lshal::forEachTable(const std::function<void(const Table &)> &f) const {
+ for (const Table &table : {mServicesTable, mPassthroughRefTable, mImplementationsTable}) {
+ f(table);
+ }
+}
+
void Lshal::postprocess() {
- if (mSortColumn) {
- std::sort(mTable.begin(), mTable.end(), mSortColumn);
- }
- for (TableEntry &entry : mTable) {
- entry.serverCmdline = getCmdline(entry.serverPid);
- removeDeadProcesses(&entry.clientPids);
- for (auto pid : entry.clientPids) {
- entry.clientCmdlines.push_back(this->getCmdline(pid));
+ forEachTable([this](Table &table) {
+ if (mSortColumn) {
+ std::sort(table.begin(), table.end(), mSortColumn);
}
- }
+ for (TableEntry &entry : table) {
+ entry.serverCmdline = getCmdline(entry.serverPid);
+ removeDeadProcesses(&entry.clientPids);
+ for (auto pid : entry.clientPids) {
+ entry.clientCmdlines.push_back(this->getCmdline(pid));
+ }
+ }
+ });
}
void Lshal::printLine(
const std::string &interfaceName,
- const std::string &transport, const std::string &server,
+ const std::string &transport,
+ const std::string &arch,
+ const std::string &server,
const std::string &serverCmdline,
const std::string &address, const std::string &clients,
const std::string &clientCmdlines) const {
@@ -182,6 +197,8 @@
mOut << std::setw(80) << interfaceName << "\t";
if (mSelectedColumns & ENABLE_TRANSPORT)
mOut << std::setw(10) << transport << "\t";
+ if (mSelectedColumns & ENABLE_ARCH)
+ mOut << std::setw(5) << arch << "\t";
if (mSelectedColumns & ENABLE_SERVER_PID) {
if (mEnableCmdlines) {
mOut << std::setw(15) << serverCmdline << "\t";
@@ -203,90 +220,139 @@
void Lshal::dumpVintf() const {
vintf::HalManifest manifest;
- for (const TableEntry &entry : mTable) {
+ forEachTable([this, &manifest] (const Table &table) {
+ for (const TableEntry &entry : table) {
- std::string fqInstanceName = entry.interfaceName;
+ std::string fqInstanceName = entry.interfaceName;
- if (entry.source == LIST_DLLIB) {
- // Quick hack to work around *'s
- replaceAll(&fqInstanceName, '*', 'D');
- }
- auto splittedFqInstanceName = splitFirst(fqInstanceName, '/');
- FQName fqName(splittedFqInstanceName.first);
- if (!fqName.isValid()) {
- mErr << "Warning: '" << splittedFqInstanceName.first
- << "' is not a valid FQName." << std::endl;
- continue;
- }
- // Strip out system libs.
- // TODO(b/34772739): might want to add other framework HAL packages
- if (fqName.inPackage("android.hidl")) {
- continue;
- }
- std::string interfaceName =
- entry.source == LIST_DLLIB ? "" : fqName.name();
- std::string instanceName =
- entry.source == LIST_DLLIB ? "" : splittedFqInstanceName.second;
-
- vintf::Transport transport;
- if (entry.transport == "hwbinder") {
- transport = vintf::Transport::HWBINDER;
- } else if (entry.transport == "passthrough") {
- transport = vintf::Transport::PASSTHROUGH;
- } else {
- mErr << "Warning: '" << entry.transport << "' is not a valid transport." << std::endl;
- continue;
- }
-
- vintf::ManifestHal *hal = manifest.getHal(fqName.package());
- if (hal == nullptr) {
- if (!manifest.add(vintf::ManifestHal{
- .format = vintf::HalFormat::HIDL,
- .name = fqName.package(),
- .impl = {.implLevel = vintf::ImplLevel::GENERIC, .impl = ""},
- .transport = transport
- })) {
- mErr << "Warning: cannot add hal '" << fqInstanceName << "'" << std::endl;
+ if (&table == &mImplementationsTable) {
+ // Quick hack to work around *'s
+ replaceAll(&fqInstanceName, '*', 'D');
+ }
+ auto splittedFqInstanceName = splitFirst(fqInstanceName, '/');
+ FQName fqName(splittedFqInstanceName.first);
+ if (!fqName.isValid()) {
+ mErr << "Warning: '" << splittedFqInstanceName.first
+ << "' is not a valid FQName." << std::endl;
continue;
}
- hal = manifest.getHal(fqName.package());
- }
- if (hal == nullptr) {
- mErr << "Warning: cannot get hal '" << fqInstanceName
- << "' after adding it" << std::endl;
- continue;
- }
- vintf::Version version{fqName.getPackageMajorVersion(), fqName.getPackageMinorVersion()};
- if (std::find(hal->versions.begin(), hal->versions.end(), version) == hal->versions.end()) {
- hal->versions.push_back(version);
- }
- if (entry.source != LIST_DLLIB) {
- auto it = hal->interfaces.find(interfaceName);
- if (it == hal->interfaces.end()) {
- hal->interfaces.insert({interfaceName, {interfaceName, {{instanceName}}}});
+ // Strip out system libs.
+ // TODO(b/34772739): might want to add other framework HAL packages
+ if (fqName.inPackage("android.hidl")) {
+ continue;
+ }
+ std::string interfaceName =
+ &table == &mImplementationsTable ? "" : fqName.name();
+ std::string instanceName =
+ &table == &mImplementationsTable ? "" : splittedFqInstanceName.second;
+
+ vintf::Transport transport;
+ if (entry.transport == "hwbinder") {
+ transport = vintf::Transport::HWBINDER;
+ } else if (entry.transport == "passthrough") {
+ transport = vintf::Transport::PASSTHROUGH;
} else {
- it->second.instances.insert(instanceName);
+ mErr << "Warning: '" << entry.transport << "' is not a valid transport." << std::endl;
+ continue;
+ }
+
+ vintf::ManifestHal *hal = manifest.getHal(fqName.package());
+ if (hal == nullptr) {
+ if (!manifest.add(vintf::ManifestHal{
+ .format = vintf::HalFormat::HIDL,
+ .name = fqName.package(),
+ .impl = {.implLevel = vintf::ImplLevel::GENERIC, .impl = ""},
+ .transport = transport
+ })) {
+ mErr << "Warning: cannot add hal '" << fqInstanceName << "'" << std::endl;
+ continue;
+ }
+ hal = manifest.getHal(fqName.package());
+ }
+ if (hal == nullptr) {
+ mErr << "Warning: cannot get hal '" << fqInstanceName
+ << "' after adding it" << std::endl;
+ continue;
+ }
+ vintf::Version version{fqName.getPackageMajorVersion(), fqName.getPackageMinorVersion()};
+ if (std::find(hal->versions.begin(), hal->versions.end(), version) == hal->versions.end()) {
+ hal->versions.push_back(version);
+ }
+ if (&table != &mImplementationsTable) {
+ auto it = hal->interfaces.find(interfaceName);
+ if (it == hal->interfaces.end()) {
+ hal->interfaces.insert({interfaceName, {interfaceName, {{instanceName}}}});
+ } else {
+ it->second.instances.insert(instanceName);
+ }
}
}
- }
+ });
mOut << vintf::gHalManifestConverter(manifest);
}
-void Lshal::dumpTable() const {
- mOut << "All services:" << std::endl;
- mOut << std::left;
- printLine("Interface", "Transport", "Server", "Server CMD", "PTR", "Clients", "Clients CMD");
- for (const auto &entry : mTable) {
- printLine(entry.interfaceName,
- entry.transport,
- entry.serverPid == NO_PID ? "N/A" : std::to_string(entry.serverPid),
- entry.serverCmdline,
- entry.serverObjectAddress == NO_PTR ? "N/A" : toHexString(entry.serverObjectAddress),
- join(entry.clientPids, " "),
- join(entry.clientCmdlines, ";"));
+static const std::string &getArchString(Architecture arch) {
+ static const std::string sStr64 = "64";
+ static const std::string sStr32 = "32";
+ static const std::string sStrBoth = "32+64";
+ static const std::string sStrUnknown = "";
+ switch (arch) {
+ case ARCH64:
+ return sStr64;
+ case ARCH32:
+ return sStr32;
+ case ARCH_BOTH:
+ return sStrBoth;
+ case ARCH_UNKNOWN: // fall through
+ default:
+ return sStrUnknown;
}
}
+static Architecture fromBaseArchitecture(::android::hidl::base::V1_0::DebugInfo::Architecture a) {
+ switch (a) {
+ case ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_64BIT:
+ return ARCH64;
+ case ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_32BIT:
+ return ARCH32;
+ case ::android::hidl::base::V1_0::DebugInfo::Architecture::UNKNOWN: // fallthrough
+ default:
+ return ARCH_UNKNOWN;
+ }
+}
+
+void Lshal::dumpTable() {
+ mServicesTable.description =
+ "All binderized services (registered services through hwservicemanager)";
+ mPassthroughRefTable.description =
+ "All interfaces that getService() has ever return as a passthrough interface;\n"
+ "PIDs / processes shown below might be inaccurate because the process\n"
+ "might have relinquished the interface or might have died.\n"
+ "The Server / Server CMD column can be ignored.\n"
+ "The Clients / Clients CMD column shows all process that have ever dlopen'ed \n"
+ "the library and successfully fetched the passthrough implementation.";
+ mImplementationsTable.description =
+ "All available passthrough implementations (all -impl.so files)";
+ forEachTable([this] (const Table &table) {
+ mOut << table.description << std::endl;
+ mOut << std::left;
+ printLine("Interface", "Transport", "Arch", "Server", "Server CMD",
+ "PTR", "Clients", "Clients CMD");
+ for (const auto &entry : table) {
+ printLine(entry.interfaceName,
+ entry.transport,
+ getArchString(entry.arch),
+ entry.serverPid == NO_PID ? "N/A" : std::to_string(entry.serverPid),
+ entry.serverCmdline,
+ entry.serverObjectAddress == NO_PTR ? "N/A" : toHexString(entry.serverObjectAddress),
+ join(entry.clientPids, " "),
+ join(entry.clientCmdlines, ";"));
+ }
+ mOut << std::endl;
+ });
+
+}
+
void Lshal::dump() {
if (mVintf) {
dumpVintf();
@@ -301,24 +367,43 @@
}
}
-void Lshal::putEntry(TableEntry &&entry) {
- mTable.push_back(std::forward<TableEntry>(entry));
+void Lshal::putEntry(TableEntrySource source, TableEntry &&entry) {
+ Table *table = nullptr;
+ switch (source) {
+ case HWSERVICEMANAGER_LIST :
+ table = &mServicesTable; break;
+ case PTSERVICEMANAGER_REG_CLIENT :
+ table = &mPassthroughRefTable; break;
+ case LIST_DLLIB :
+ table = &mImplementationsTable; break;
+ default:
+ mErr << "Error: Unknown source of entry " << source << std::endl;
+ }
+ if (table) {
+ table->entries.push_back(std::forward<TableEntry>(entry));
+ }
}
Status Lshal::fetchAllLibraries(const sp<IServiceManager> &manager) {
using namespace ::android::hardware;
using namespace ::android::hidl::manager::V1_0;
using namespace ::android::hidl::base::V1_0;
- auto ret = timeoutIPC(manager, &IServiceManager::list, [&] (const auto &fqInstanceNames) {
- for (const auto &fqInstanceName : fqInstanceNames) {
- putEntry({
- .interfaceName = fqInstanceName,
+ auto ret = timeoutIPC(manager, &IServiceManager::debugDump, [&] (const auto &infos) {
+ std::map<std::string, TableEntry> entries;
+ for (const auto &info : infos) {
+ std::string interfaceName = std::string{info.interfaceName.c_str()} + "/" +
+ std::string{info.instanceName.c_str()};
+ entries.emplace(interfaceName, TableEntry{
+ .interfaceName = interfaceName,
.transport = "passthrough",
.serverPid = NO_PID,
.serverObjectAddress = NO_PTR,
.clientPids = {},
- .source = LIST_DLLIB
- });
+ .arch = ARCH_UNKNOWN
+ }).first->second.arch |= fromBaseArchitecture(info.arch);
+ }
+ for (auto &&pair : entries) {
+ putEntry(LIST_DLLIB, std::move(pair.second));
}
});
if (!ret.isOk()) {
@@ -331,11 +416,12 @@
Status Lshal::fetchPassthrough(const sp<IServiceManager> &manager) {
using namespace ::android::hardware;
+ using namespace ::android::hardware::details;
using namespace ::android::hidl::manager::V1_0;
using namespace ::android::hidl::base::V1_0;
auto ret = timeoutIPC(manager, &IServiceManager::debugDump, [&] (const auto &infos) {
for (const auto &info : infos) {
- putEntry({
+ putEntry(PTSERVICEMANAGER_REG_CLIENT, {
.interfaceName =
std::string{info.interfaceName.c_str()} + "/" +
std::string{info.instanceName.c_str()},
@@ -343,7 +429,7 @@
.serverPid = info.clientPids.size() == 1 ? info.clientPids[0] : NO_PID,
.serverObjectAddress = NO_PTR,
.clientPids = info.clientPids,
- .source = PTSERVICEMANAGER_REG_CLIENT
+ .arch = fromBaseArchitecture(info.arch)
});
}
});
@@ -420,25 +506,25 @@
for (const auto &fqInstanceName : fqInstanceNames) {
auto it = allDebugInfos.find(fqInstanceName);
if (it == allDebugInfos.end()) {
- putEntry({
+ putEntry(HWSERVICEMANAGER_LIST, {
.interfaceName = fqInstanceName,
.transport = mode,
.serverPid = NO_PID,
.serverObjectAddress = NO_PTR,
.clientPids = {},
- .source = HWSERVICEMANAGER_LIST
+ .arch = ARCH_UNKNOWN
});
continue;
}
const DebugInfo &info = it->second;
- putEntry({
+ putEntry(HWSERVICEMANAGER_LIST, {
.interfaceName = fqInstanceName,
.transport = mode,
.serverPid = info.pid,
.serverObjectAddress = info.ptr,
.clientPids = info.pid == NO_PID || info.ptr == NO_PTR
? Pids{} : allPids[info.pid][info.ptr],
- .source = HWSERVICEMANAGER_LIST
+ .arch = fromBaseArchitecture(info.arch),
});
}
return status;
@@ -469,13 +555,14 @@
void Lshal::usage() const {
mErr
<< "usage: lshal" << std::endl
- << " Dump all hals with default ordering and columns [-itpc]." << std::endl
- << " lshal [--interface|-i] [--transport|-t]" << std::endl
+ << " Dump all hals with default ordering and columns [-ipc]." << std::endl
+ << " lshal [--interface|-i] [--transport|-t] [-r|--arch]" << std::endl
<< " [--pid|-p] [--address|-a] [--clients|-c] [--cmdline|-m]" << std::endl
<< " [--sort={interface|i|pid|p}] [--init-vintf[=path]]" << std::endl
<< " -i, --interface: print the interface name column" << std::endl
<< " -n, --instance: print the instance name column" << std::endl
<< " -t, --transport: print the transport mode column" << std::endl
+ << " -r, --arch: print if the HAL is in 64-bit or 32-bit" << std::endl
<< " -p, --pid: print the server PID, or server cmdline if -m is set" << std::endl
<< " -a, --address: print the server object address column" << std::endl
<< " -c, --clients: print the client PIDs, or client cmdlines if -m is set"
@@ -495,6 +582,7 @@
{"help", no_argument, 0, 'h' },
{"interface", no_argument, 0, 'i' },
{"transport", no_argument, 0, 't' },
+ {"arch", no_argument, 0, 'r' },
{"pid", no_argument, 0, 'p' },
{"address", no_argument, 0, 'a' },
{"clients", no_argument, 0, 'c' },
@@ -511,7 +599,7 @@
optind = 1;
for (;;) {
// using getopt_long in case we want to add other options in the future
- c = getopt_long(argc, argv, "hitpacm", longOptions, &optionIndex);
+ c = getopt_long(argc, argv, "hitrpacm", longOptions, &optionIndex);
if (c == -1) {
break;
}
@@ -547,6 +635,10 @@
mSelectedColumns |= ENABLE_TRANSPORT;
break;
}
+ case 'r': {
+ mSelectedColumns |= ENABLE_ARCH;
+ break;
+ }
case 'p': {
mSelectedColumns |= ENABLE_SERVER_PID;
break;
@@ -571,8 +663,7 @@
}
if (mSelectedColumns == 0) {
- mSelectedColumns = ENABLE_INTERFACE_NAME
- | ENABLE_TRANSPORT | ENABLE_SERVER_PID | ENABLE_CLIENT_PIDS;
+ mSelectedColumns = ENABLE_INTERFACE_NAME | ENABLE_SERVER_PID | ENABLE_CLIENT_PIDS;
}
return OK;
}
diff --git a/cmds/lshal/Lshal.h b/cmds/lshal/Lshal.h
index 1c30908..c9c6660 100644
--- a/cmds/lshal/Lshal.h
+++ b/cmds/lshal/Lshal.h
@@ -53,17 +53,19 @@
void postprocess();
void dump();
void usage() const;
- void putEntry(TableEntry &&entry);
+ void putEntry(TableEntrySource source, TableEntry &&entry);
Status fetchPassthrough(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
Status fetchBinderized(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
Status fetchAllLibraries(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
bool getReferencedPids(
pid_t serverPid, std::map<uint64_t, Pids> *objects) const;
- void dumpTable() const;
+ void dumpTable();
void dumpVintf() const;
void printLine(
const std::string &interfaceName,
- const std::string &transport, const std::string &server,
+ const std::string &transport,
+ const std::string &arch,
+ const std::string &server,
const std::string &serverCmdline,
const std::string &address, const std::string &clients,
const std::string &clientCmdlines) const ;
@@ -72,8 +74,13 @@
// Call getCmdline on all pid in pids. If it returns empty string, the process might
// have died, and the pid is removed from pids.
void removeDeadProcesses(Pids *pids);
+ void forEachTable(const std::function<void(Table &)> &f);
+ void forEachTable(const std::function<void(const Table &)> &f) const;
- Table mTable{};
+ Table mServicesTable{};
+ Table mPassthroughRefTable{};
+ Table mImplementationsTable{};
+
NullableOStream<std::ostream> mErr = std::cerr;
NullableOStream<std::ostream> mOut = std::cout;
NullableOStream<std::ofstream> mFileOutput = nullptr;
diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h
index e55806e..2407b42 100644
--- a/cmds/lshal/TableEntry.h
+++ b/cmds/lshal/TableEntry.h
@@ -35,6 +35,14 @@
};
using TableEntrySource = unsigned int;
+enum : unsigned int {
+ ARCH_UNKNOWN = 0,
+ ARCH64 = 1 << 0,
+ ARCH32 = 1 << 1,
+ ARCH_BOTH = ARCH32 | ARCH64
+};
+using Architecture = unsigned int;
+
struct TableEntry {
std::string interfaceName;
std::string transport;
@@ -43,7 +51,7 @@
uint64_t serverObjectAddress;
Pids clientPids;
std::vector<std::string> clientCmdlines;
- TableEntrySource source;
+ Architecture arch;
static bool sortByInterfaceName(const TableEntry &a, const TableEntry &b) {
return a.interfaceName < b.interfaceName;
@@ -53,7 +61,17 @@
};
};
-using Table = std::vector<TableEntry>;
+struct Table {
+ using Entries = std::vector<TableEntry>;
+ std::string description;
+ Entries entries;
+
+ Entries::iterator begin() { return entries.begin(); }
+ Entries::const_iterator begin() const { return entries.begin(); }
+ Entries::iterator end() { return entries.end(); }
+ Entries::const_iterator end() const { return entries.end(); }
+};
+
using TableEntryCompare = std::function<bool(const TableEntry &, const TableEntry &)>;
enum : unsigned int {
@@ -61,7 +79,8 @@
ENABLE_TRANSPORT = 1 << 1,
ENABLE_SERVER_PID = 1 << 2,
ENABLE_SERVER_ADDR = 1 << 3,
- ENABLE_CLIENT_PIDS = 1 << 4
+ ENABLE_CLIENT_PIDS = 1 << 4,
+ ENABLE_ARCH = 1 << 5
};
using TableEntrySelect = unsigned int;
diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h
index f757fc3..f36c9fd 100644
--- a/cmds/surfacereplayer/replayer/Replayer.h
+++ b/cmds/surfacereplayer/replayer/Replayer.h
@@ -29,6 +29,7 @@
#include <utils/Errors.h>
#include <utils/StrongPointer.h>
+#include <stdatomic.h>
#include <condition_variable>
#include <memory>
#include <mutex>
diff --git a/include/binder/HalToken.h b/include/binder/HalToken.h
new file mode 100644
index 0000000..ce97c78
--- /dev/null
+++ b/include/binder/HalToken.h
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HALTOKEN_H
+#define ANDROID_HALTOKEN_H
+
+#include <binder/Parcel.h>
+#include <hidl/HidlSupport.h>
+
+/**
+ * Hybrid Interfaces
+ * =================
+ *
+ * A hybrid interface is a binder interface that
+ * 1. is implemented both traditionally and as a wrapper around a hidl
+ * interface, and allows querying whether the underlying instance comes from
+ * a hidl interface or not; and
+ * 2. allows efficient calls to a hidl interface (if the underlying instance
+ * comes from a hidl interface) by automatically creating the wrapper in the
+ * process that calls it.
+ *
+ * Terminology:
+ * - `HalToken`: The type for a "token" of a hidl interface. This is defined to
+ * be compatible with `ITokenManager.hal`.
+ * - `HInterface`: The base type for a hidl interface. Currently, it is defined
+ * as `::android::hidl::base::V1_0::IBase`.
+ * - `HALINTERFACE`: The hidl interface that will be sent through binders.
+ * - `INTERFACE`: The binder interface that will be the wrapper of
+ * `HALINTERFACE`. `INTERFACE` is supposed to be somewhat similar to
+ * `HALINTERFACE`.
+ *
+ * To demonstrate how this is done, here is an example. Suppose `INTERFACE` is
+ * `IFoo` and `HALINTERFACE` is `HFoo`. The required steps are:
+ * 1. Use DECLARE_HYBRID_META_INTERFACE instead of DECLARE_META_INTERFACE in the
+ * definition of `IFoo`. The usage is
+ * DECLARE_HYBRID_META_INTERFACE(IFoo, HFoo)
+ * inside the body of `IFoo`.
+ * 2. Create a converter class that derives from
+ * `H2BConverter<HFoo, IFoo, BnFoo>`. Let us call this `H2BFoo`.
+ * 3. Add the following constructor in `H2BFoo` that call the corresponding
+ * constructors in `H2BConverter`:
+ * H2BFoo(const sp<HalInterface>& base) : CBase(base) {}
+ * Note: `CBase = H2BConverter<HFoo, IFoo, BnFoo>` and `HalInterface = HFoo`
+ * are member typedefs of `H2BConverter<HFoo, IFoo, BnFoo>`, so the above
+ * line can be copied into `H2BFoo`.
+ * 4. Implement `IFoo` in `H2BFoo` on top of `HFoo`. `H2BConverter` provides a
+ * protected `mBase` of type `sp<HFoo>` that can be used to access the `HFoo`
+ * instance. (There is also a public function named `getHalInterface()` that
+ * returns `mBase`.)
+ * 5. Create a hardware proxy class that derives from
+ * `HpInterface<BpFoo, H2BFoo>`. Name this class `HpFoo`. (This name cannot
+ * deviate. See step 8 below.)
+ * 6. Add the following constructor to `HpFoo`:
+ * HpFoo(const sp<IBinder>& base): PBase(base) {}
+ * Note: `PBase` a member typedef of `HpInterface<BpFoo, H2BFoo>` that is
+ * equal to `HpInterface<BpFoo, H2BFoo>` itself, so the above line can be
+ * copied verbatim into `HpFoo`.
+ * 7. Delegate all functions in `HpFoo` that come from `IFoo` except
+ * `getHalInterface` to the protected member `mBase`,
+ * which is defined in `HpInterface<BpFoo, H2BFoo>` (hence in `HpFoo`) with
+ * type `IFoo`. (There is also a public function named `getBaseInterface()`
+ * that returns `mBase`.)
+ * 8. Replace the existing `IMPLEMENT_META_INTERFACE` for INTERFACE by
+ * `IMPLEMENT_HYBRID_META_INTERFACE`. Note that this macro relies on the
+ * exact naming of `HpFoo`, where `Foo` comes from the interface name `IFoo`.
+ * An example usage is
+ * IMPLEMENT_HYBRID_META_INTERFACE(IFoo, HFoo, "example.interface.foo");
+ *
+ * `GETTOKEN` Template Argument
+ * ============================
+ *
+ * Following the instructions above, `H2BConverter` and `HpInterface` would use
+ * `transact()` to send over tokens, with `code` (the first argument of
+ * `transact()`) equal to a 4-byte value of '_GTK'. If this value clashes with
+ * other values already in use in the `Bp` class, it can be changed by supplying
+ * the last optional template argument to `H2BConverter` and `HpInterface`.
+ *
+ */
+
+namespace android {
+
+typedef uint64_t HalToken;
+typedef ::android::hidl::base::V1_0::IBase HInterface;
+
+sp<HInterface> retrieveHalInterface(const HalToken& token);
+bool createHalToken(const sp<HInterface>& interface, HalToken* token);
+bool deleteHalToken(const HalToken& token);
+
+template <
+ typename HINTERFACE,
+ typename INTERFACE,
+ typename BNINTERFACE,
+ uint32_t GETTOKEN = '_GTK'>
+class H2BConverter : public BNINTERFACE {
+public:
+ typedef H2BConverter<HINTERFACE, INTERFACE, BNINTERFACE, GETTOKEN> CBase; // Converter Base
+ typedef INTERFACE BaseInterface;
+ typedef HINTERFACE HalInterface;
+ static constexpr uint32_t GET_HAL_TOKEN = GETTOKEN;
+
+ H2BConverter(const sp<HalInterface>& base) : mBase(base) {}
+ virtual status_t onTransact(uint32_t code,
+ const Parcel& data, Parcel* reply, uint32_t flags = 0);
+ sp<HalInterface> getHalInterface() override { return mBase; }
+ HalInterface* getBaseInterface() { return mBase.get(); }
+
+protected:
+ sp<HalInterface> mBase;
+};
+
+template <
+ typename BPINTERFACE,
+ typename CONVERTER,
+ uint32_t GETTOKEN = '_GTK'>
+class HpInterface : public CONVERTER::BaseInterface {
+public:
+ typedef HpInterface<BPINTERFACE, CONVERTER, GETTOKEN> PBase; // Proxy Base
+ typedef typename CONVERTER::BaseInterface BaseInterface;
+ typedef typename CONVERTER::HalInterface HalInterface;
+ static constexpr uint32_t GET_HAL_TOKEN = GETTOKEN;
+
+ explicit HpInterface(const sp<IBinder>& impl);
+ sp<HalInterface> getHalInterface() override { return mHal; }
+ BaseInterface* getBaseInterface() { return mBase.get(); }
+
+protected:
+ sp<IBinder> mImpl;
+ sp<BaseInterface> mBase;
+ sp<HalInterface> mHal;
+ IBinder* onAsBinder() override { return mImpl.get(); }
+};
+
+// ----------------------------------------------------------------------
+
+#define DECLARE_HYBRID_META_INTERFACE(INTERFACE, HAL) \
+ static const ::android::String16 descriptor; \
+ static ::android::sp<I##INTERFACE> asInterface( \
+ const ::android::sp<::android::IBinder>& obj); \
+ virtual const ::android::String16& getInterfaceDescriptor() const; \
+ I##INTERFACE(); \
+ virtual ~I##INTERFACE(); \
+ virtual sp<HAL> getHalInterface(); \
+
+
+#define IMPLEMENT_HYBRID_META_INTERFACE(INTERFACE, HAL, NAME) \
+ const ::android::String16 I##INTERFACE::descriptor(NAME); \
+ const ::android::String16& \
+ I##INTERFACE::getInterfaceDescriptor() const { \
+ return I##INTERFACE::descriptor; \
+ } \
+ ::android::sp<I##INTERFACE> I##INTERFACE::asInterface( \
+ const ::android::sp<::android::IBinder>& obj) \
+ { \
+ ::android::sp<I##INTERFACE> intr; \
+ if (obj != NULL) { \
+ intr = static_cast<I##INTERFACE*>( \
+ obj->queryLocalInterface( \
+ I##INTERFACE::descriptor).get()); \
+ if (intr == NULL) { \
+ intr = new Hp##INTERFACE(obj); \
+ } \
+ } \
+ return intr; \
+ } \
+ I##INTERFACE::I##INTERFACE() { } \
+ I##INTERFACE::~I##INTERFACE() { } \
+ sp<HAL> I##INTERFACE::getHalInterface() { return nullptr; } \
+
+// ----------------------------------------------------------------------
+
+template <
+ typename HINTERFACE,
+ typename INTERFACE,
+ typename BNINTERFACE,
+ uint32_t GETTOKEN>
+status_t H2BConverter<HINTERFACE, INTERFACE, BNINTERFACE, GETTOKEN>::
+ onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+ if (code == GET_HAL_TOKEN) {
+ HalToken token;
+ bool result;
+ result = createHalToken(mBase, &token);
+ if (!result) {
+ ALOGE("H2BConverter: Failed to create HAL token.");
+ }
+ reply->writeBool(result);
+ reply->writeUint64(token);
+ return NO_ERROR;
+ }
+ return BNINTERFACE::onTransact(code, data, reply, flags);
+}
+
+template <typename BPINTERFACE, typename CONVERTER, uint32_t GETTOKEN>
+HpInterface<BPINTERFACE, CONVERTER, GETTOKEN>::HpInterface(
+ const sp<IBinder>& impl) : mImpl(impl) {
+ Parcel data, reply;
+ data.writeInterfaceToken(BaseInterface::getInterfaceDescriptor());
+ if (impl->transact(GET_HAL_TOKEN, data, &reply) == NO_ERROR) {
+ bool tokenCreated = reply.readBool();
+ HalToken token = reply.readUint64();
+ if (!tokenCreated) {
+ ALOGE("HpInterface: Sender failed to create HAL token.");
+ mBase = new BPINTERFACE(impl);
+ } else {
+ sp<HInterface> hInterface = retrieveHalInterface(token);
+ deleteHalToken(token);
+ if (hInterface != nullptr) {
+ mHal = static_cast<HalInterface*>(hInterface.get());
+ mBase = new CONVERTER(mHal);
+ } else {
+ ALOGE("HpInterface: Cannot retrieve HAL interface from token.");
+ mBase = new BPINTERFACE(impl);
+ }
+ }
+ } else {
+ mBase = new BPINTERFACE(impl);
+ }
+}
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_HALTOKEN_H
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index a3c2bfa..cfc68c6 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -155,6 +155,9 @@
nsecs_t* outDisplayPresentTime, nsecs_t* outDisplayRetireTime,
nsecs_t* outDequeueReadyTime, nsecs_t* outReleaseTime);
+ status_t getWideColorSupport(bool* supported);
+ status_t getHdrSupport(bool* supported);
+
status_t getUniqueId(uint64_t* outId) const;
protected:
@@ -215,6 +218,8 @@
int dispatchEnableFrameTimestamps(va_list args);
int dispatchGetCompositorTiming(va_list args);
int dispatchGetFrameTimestamps(va_list args);
+ int dispatchGetWideColorSupport(va_list args);
+ int dispatchGetHdrSupport(va_list args);
protected:
virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 93b8684..2cb44eb 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -34,6 +34,7 @@
"IResultReceiver.cpp",
"IServiceManager.cpp",
"IShellCallback.cpp",
+ "HalToken.cpp",
"MemoryBase.cpp",
"MemoryDealer.cpp",
"MemoryHeapBase.cpp",
@@ -65,6 +66,8 @@
"liblog",
"libcutils",
"libutils",
+ "libhidlbase",
+ "android.hidl.token@1.0",
],
export_shared_lib_headers: [
"libbase",
diff --git a/libs/binder/HalToken.cpp b/libs/binder/HalToken.cpp
new file mode 100644
index 0000000..6e71a52
--- /dev/null
+++ b/libs/binder/HalToken.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "HalToken"
+
+#include <utils/Log.h>
+#include <binder/HalToken.h>
+
+#include <android/hidl/token/1.0/ITokenManager.h>
+
+namespace android {
+
+using ::android::hidl::token::V1_0::ITokenManager;
+
+sp<ITokenManager> gTokenManager = nullptr;
+
+ITokenManager* getTokenManager() {
+ if (gTokenManager != nullptr) {
+ return gTokenManager.get();
+ }
+ gTokenManager = ITokenManager::getService();
+ if (gTokenManager == nullptr) {
+ ALOGE("Cannot retrieve TokenManager.");
+ }
+ return gTokenManager.get();
+}
+
+sp<HInterface> retrieveHalInterface(const HalToken& token) {
+ auto transaction = getTokenManager()->get(token);
+ if (!transaction.isOk()) {
+ ALOGE("getHalInterface: Cannot obtain interface from token.");
+ return nullptr;
+ }
+ return static_cast<sp<HInterface> >(transaction);
+}
+
+bool createHalToken(const sp<HInterface>& interface, HalToken* token) {
+ auto transaction = getTokenManager()->createToken(interface);
+ if (!transaction.isOk()) {
+ ALOGE("createHalToken: Cannot create token from interface.");
+ return false;
+ }
+ *token = static_cast<HalToken>(transaction);
+ return true;
+}
+
+bool deleteHalToken(const HalToken& token) {
+ auto transaction = getTokenManager()->unregister(token);
+ if (!transaction.isOk()) {
+ ALOGE("deleteHalToken: Cannot unregister hal token.");
+ return false;
+ }
+ return true;
+}
+
+}; // namespace android
+
diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp
index 87b295a..50a8b28 100644
--- a/libs/binder/IActivityManager.cpp
+++ b/libs/binder/IActivityManager.cpp
@@ -36,6 +36,7 @@
virtual int openContentUri(const String16& stringUri)
{
Parcel data, reply;
+ data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor());
data.writeString16(stringUri);
status_t ret = remote()->transact(OPEN_CONTENT_URI_TRANSACTION, data, & reply);
int fd = -1;
diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp
index f4e0a60..5c1a4f4 100644
--- a/libs/binder/IMemory.cpp
+++ b/libs/binder/IMemory.cpp
@@ -17,6 +17,8 @@
#define LOG_TAG "IMemory"
#include <atomic>
+#include <stdatomic.h>
+
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
@@ -28,6 +30,7 @@
#include <binder/IMemory.h>
#include <binder/Parcel.h>
#include <log/log.h>
+
#include <utils/CallStack.h>
#include <utils/KeyedVector.h>
#include <utils/threads.h>
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 6e6cce2..9e3fecb 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -29,6 +29,7 @@
#include <inttypes.h>
#include <cutils/properties.h>
+#include <cutils/atomic.h>
#include <gui/BufferItem.h>
#include <gui/BufferQueueCore.h>
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index c26de66..8acdfed 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -27,6 +27,8 @@
#include <hardware/hardware.h>
+#include <cutils/atomic.h>
+
#include <gui/BufferItem.h>
#include <gui/IGraphicBufferAlloc.h>
#include <gui/ISurfaceComposer.h>
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index efb1524..ad1984a 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -26,9 +26,10 @@
#include <utils/Trace.h>
#include <utils/NativeHandle.h>
-#include <ui/Fence.h>
-#include <ui/Region.h>
#include <ui/DisplayStatInfo.h>
+#include <ui/Fence.h>
+#include <ui/HdrCapabilities.h>
+#include <ui/Region.h>
#include <gui/BufferItem.h>
#include <gui/IProducerListener.h>
@@ -305,6 +306,51 @@
return NO_ERROR;
}
+status_t Surface::getWideColorSupport(bool* supported) {
+ ATRACE_CALL();
+
+ sp<IBinder> display(
+ composerService()->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ Vector<android_color_mode_t> colorModes;
+ status_t err =
+ composerService()->getDisplayColorModes(display, &colorModes);
+
+ if (err)
+ return err;
+
+ *supported = false;
+ for (android_color_mode_t colorMode : colorModes) {
+ switch (colorMode) {
+ case HAL_COLOR_MODE_DISPLAY_P3:
+ case HAL_COLOR_MODE_ADOBE_RGB:
+ case HAL_COLOR_MODE_DCI_P3:
+ *supported = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+status_t Surface::getHdrSupport(bool* supported) {
+ ATRACE_CALL();
+
+ sp<IBinder> display(
+ composerService()->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+ HdrCapabilities hdrCapabilities;
+ status_t err =
+ composerService()->getHdrCapabilities(display, &hdrCapabilities);
+
+ if (err)
+ return err;
+
+ *supported = !hdrCapabilities.getSupportedHdrTypes().empty();
+
+ return NO_ERROR;
+}
+
int Surface::hook_setSwapInterval(ANativeWindow* window, int interval) {
Surface* c = getSelf(window);
return c->setSwapInterval(interval);
@@ -880,6 +926,12 @@
case NATIVE_WINDOW_GET_FRAME_TIMESTAMPS:
res = dispatchGetFrameTimestamps(args);
break;
+ case NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT:
+ res = dispatchGetWideColorSupport(args);
+ break;
+ case NATIVE_WINDOW_GET_HDR_SUPPORT:
+ res = dispatchGetHdrSupport(args);
+ break;
default:
res = NAME_NOT_FOUND;
break;
@@ -1044,6 +1096,16 @@
outDisplayRetireTime, outDequeueReadyTime, outReleaseTime);
}
+int Surface::dispatchGetWideColorSupport(va_list args) {
+ bool* outSupport = va_arg(args, bool*);
+ return getWideColorSupport(outSupport);
+}
+
+int Surface::dispatchGetHdrSupport(va_list args) {
+ bool* outSupport = va_arg(args, bool*);
+ return getHdrSupport(outSupport);
+}
+
int Surface::connect(int api) {
static sp<IProducerListener> listener = new DummyProducerListener();
return connect(api, listener);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 012dbe7..da6f13d 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -19,11 +19,12 @@
#include <gtest/gtest.h>
#include <binder/ProcessState.h>
+#include <cutils/properties.h>
+#include <gui/BufferItemConsumer.h>
#include <gui/IDisplayEventConnection.h>
#include <gui/ISurfaceComposer.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
-#include <gui/BufferItemConsumer.h>
#include <private/gui/ComposerService.h>
#include <ui/Rect.h>
#include <utils/String8.h>
@@ -252,6 +253,35 @@
EXPECT_STREQ("TestConsumer", surface->getConsumerName().string());
}
+TEST_F(SurfaceTest, GetWideColorSupport) {
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+
+ sp<DummyConsumer> dummyConsumer(new DummyConsumer);
+ consumer->consumerConnect(dummyConsumer, false);
+ consumer->setConsumerName(String8("TestConsumer"));
+
+ sp<Surface> surface = new Surface(producer);
+ sp<ANativeWindow> window(surface);
+ native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU);
+
+ bool supported;
+ surface->getWideColorSupport(&supported);
+
+ // TODO(courtneygo): How can we know what device we are on to
+ // verify that this is correct?
+ char product[PROPERTY_VALUE_MAX] = "0";
+ property_get("ro.build.product", product, "0");
+ std::cerr << "[ ] product = " << product << std::endl;
+
+ if (strcmp("marlin", product) == 0 || strcmp("sailfish", product) == 0) {
+ ASSERT_EQ(true, supported);
+ } else {
+ ASSERT_EQ(false, supported);
+ }
+}
+
TEST_F(SurfaceTest, DynamicSetBufferCount) {
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index c4d8f76..9006178 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -16,6 +16,8 @@
#define LOG_TAG "GraphicBuffer"
+#include <cutils/atomic.h>
+
#include <ui/GraphicBuffer.h>
#include <cutils/atomic.h>
diff --git a/libs/vr/libsensor/Android.mk b/libs/vr/libsensor/Android.mk
index 89abcb0..8c7ad43 100644
--- a/libs/vr/libsensor/Android.mk
+++ b/libs/vr/libsensor/Android.mk
@@ -32,7 +32,6 @@
libhardware \
liblog \
libutils \
- libandroid \
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(sourceFiles)
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 0ac74db..740ead3 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -623,9 +623,9 @@
#define EGL_ANDROID_get_native_client_buffer 1
struct AHardwareBuffer;
#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLClientBuffer eglGetNativeClientBufferANDROID (const AHardwareBuffer *buffer);
+EGLAPI EGLClientBuffer eglGetNativeClientBufferANDROID (const struct AHardwareBuffer *buffer);
#else
-typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLGETNATIVECLIENTBUFFERANDROID) (const AHardwareBuffer *buffer);
+typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLGETNATIVECLIENTBUFFERANDROID) (const struct AHardwareBuffer *buffer);
#endif
#endif
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 3359c64..e52713f 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -126,6 +126,7 @@
"EGL_EXT_yuv_surface "
"EGL_EXT_protected_content "
"EGL_IMG_context_priority "
+ "EGL_KHR_no_config_context "
;
// extensions not exposed to applications but used by the ANDROID system
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 24ebac7..c3f8665 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -604,14 +604,15 @@
// this gives us only the "orientation" component of the transform
const State& s(getDrawingState());
#ifdef USE_HWC2
+ auto blendMode = HWC2::BlendMode::None;
if (!isOpaque(s) || s.alpha != 1.0f) {
- auto blendMode = mPremultipliedAlpha ?
+ blendMode = mPremultipliedAlpha ?
HWC2::BlendMode::Premultiplied : HWC2::BlendMode::Coverage;
- auto error = hwcLayer->setBlendMode(blendMode);
- ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set blend mode %s:"
- " %s (%d)", mName.string(), to_string(blendMode).c_str(),
- to_string(error).c_str(), static_cast<int32_t>(error));
}
+ auto error = hwcLayer->setBlendMode(blendMode);
+ ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set blend mode %s:"
+ " %s (%d)", mName.string(), to_string(blendMode).c_str(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
#else
if (!isOpaque(s) || s.alpha != 0xFF) {
layer.setBlending(mPremultipliedAlpha ?
@@ -666,7 +667,7 @@
}
const Transform& tr(displayDevice->getTransform());
Rect transformedFrame = tr.transform(frame);
- auto error = hwcLayer->setDisplayFrame(transformedFrame);
+ error = hwcLayer->setDisplayFrame(transformedFrame);
if (error != HWC2::Error::None) {
ALOGE("[%s] Failed to set display frame [%d, %d, %d, %d]: %s (%d)",
mName.string(), transformedFrame.left, transformedFrame.top,
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 4acdb82..daeac27 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -156,6 +156,7 @@
mVisibleRegionsDirty(false),
mGeometryInvalid(false),
mAnimCompositionPending(false),
+ mVrModeSupported(0),
mDebugRegion(0),
mDebugDDMS(0),
mDebugDisableHWC(0),
@@ -185,6 +186,10 @@
// debugging stuff...
char value[PROPERTY_VALUE_MAX];
+ // TODO (urbanus): remove once b/35319396 is fixed.
+ property_get("ro.boot.vr", value, "0");
+ mVrModeSupported = atoi(value);
+
property_get("ro.bq.gpu_to_cpu_unsupported", value, "0");
mGpuToCpuSupported = !atoi(value);
@@ -1262,8 +1267,11 @@
ATRACE_CALL();
switch (what) {
case MessageQueue::INVALIDATE: {
- // TODO(eieio): Disabled until SELinux issues are resolved.
- //updateVrMode();
+ // TODO(eieio): Tied to a conditional until SELinux issues
+ // are resolved.
+ if (mVrModeSupported) {
+ updateVrMode();
+ }
bool frameMissed = !mHadClientComposition &&
mPreviousPresentFence != Fence::NO_FENCE &&
@@ -1586,6 +1594,9 @@
layer->setHwcLayer(displayDevice->getHwcDisplayId(),
nullptr);
}
+ } else {
+ layer->setHwcLayer(displayDevice->getHwcDisplayId(),
+ nullptr);
}
});
}
@@ -1640,7 +1651,6 @@
if (hwcId >= 0) {
const Vector<sp<Layer>>& currentLayers(
displayDevice->getVisibleLayersSortedByZ());
- bool foundLayerWithoutHwc = false;
for (size_t i = 0; i < currentLayers.size(); i++) {
const auto& layer = currentLayers[i];
if (!layer->hasHwcLayer(hwcId)) {
@@ -1649,7 +1659,6 @@
layer->setHwcLayer(hwcId, std::move(hwcLayer));
} else {
layer->forceClientComposition(hwcId);
- foundLayerWithoutHwc = true;
continue;
}
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 0b3deef..d63c0bb 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -557,6 +557,7 @@
DefaultKeyedVector< wp<IBinder>, sp<DisplayDevice> > mDisplays;
// don't use a lock for these, we don't care
+ int mVrModeSupported;
int mDebugRegion;
int mDebugDDMS;
int mDebugDisableHWC;
diff --git a/services/vr/virtual_touchpad/Android.mk b/services/vr/virtual_touchpad/Android.mk
index 4224aaa..b78eb99 100644
--- a/services/vr/virtual_touchpad/Android.mk
+++ b/services/vr/virtual_touchpad/Android.mk
@@ -6,13 +6,14 @@
src := \
EvdevInjector.cpp \
- VirtualTouchpad.cpp
+ VirtualTouchpadEvdev.cpp
shared_libs := \
libbase
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(src)
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_SHARED_LIBRARIES := $(shared_libs)
LOCAL_CPPFLAGS += -std=c++11
LOCAL_CFLAGS += -DLOG_TAG=\"VrVirtualTouchpad\"
@@ -29,11 +30,13 @@
static_libs := \
libbase \
libcutils \
+ libutils \
libvirtualtouchpad
$(foreach file,$(test_src_files), \
$(eval include $(CLEAR_VARS)) \
$(eval LOCAL_SRC_FILES := $(file)) \
+ $(eval LOCAL_C_INCLUDES := $(LOCAL_PATH)/include) \
$(eval LOCAL_STATIC_LIBRARIES := $(static_libs)) \
$(eval LOCAL_SHARED_LIBRARIES := $(shared_libs)) \
$(eval LOCAL_CPPFLAGS += -std=c++11) \
@@ -63,6 +66,7 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(src)
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_STATIC_LIBRARIES := $(static_libs)
LOCAL_SHARED_LIBRARIES := $(shared_libs)
LOCAL_CPPFLAGS += -std=c++11
@@ -74,3 +78,27 @@
LOCAL_MULTILIB := 64
LOCAL_CXX_STL := libc++_static
include $(BUILD_EXECUTABLE)
+
+
+# Touchpad client library.
+
+src := \
+ VirtualTouchpadClient.cpp \
+ aidl/android/dvr/VirtualTouchpadService.aidl
+
+shared_libs := \
+ libbase \
+ libbinder \
+ libutils
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(src)
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_SHARED_LIBRARIES := $(shared_libs)
+LOCAL_CPPFLAGS += -std=c++11
+LOCAL_CFLAGS += -DLOG_TAG=\"VirtualTouchpadClient\"
+LOCAL_LDLIBS := -llog
+LOCAL_MODULE := libvirtualtouchpadclient
+LOCAL_MODULE_TAGS := optional
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+include $(BUILD_STATIC_LIBRARY)
diff --git a/services/vr/virtual_touchpad/VirtualTouchpad.h b/services/vr/virtual_touchpad/VirtualTouchpad.h
deleted file mode 100644
index 17aeb35..0000000
--- a/services/vr/virtual_touchpad/VirtualTouchpad.h
+++ /dev/null
@@ -1,77 +0,0 @@
-#ifndef ANDROID_DVR_VIRTUAL_TOUCHPAD_H
-#define ANDROID_DVR_VIRTUAL_TOUCHPAD_H
-
-#include <memory>
-
-#include "EvdevInjector.h"
-
-namespace android {
-namespace dvr {
-
-class EvdevInjector;
-
-// Provides a virtual touchpad for injecting events into the input system.
-//
-class VirtualTouchpad {
- public:
- VirtualTouchpad() {}
- ~VirtualTouchpad() {}
-
- // |Intialize()| must be called once on a VirtualTouchpad before
- // and other public method. Returns zero on success.
- int Initialize();
-
- // Generate a simulated touch event.
- //
- // @param x Horizontal touch position.
- // @param y Vertical touch position.
- // Values must be in the range [0.0, 1.0).
- // @param pressure Touch pressure.
- // Positive values represent contact; use 1.0f if contact
- // is binary. Use 0.0f for no contact.
- // @returns Zero on success.
- //
- int Touch(float x, float y, float pressure);
-
- // Generate a simulated touchpad button state.
- //
- // @param buttons A union of MotionEvent BUTTON_* values.
- // @returns Zero on success.
- //
- // Currently only BUTTON_BACK is supported, as the implementation
- // restricts itself to operations actually required by VrWindowManager.
- //
- int ButtonState(int buttons);
-
- protected:
- // Must be called only between construction and Initialize().
- inline void SetEvdevInjectorForTesting(EvdevInjector* injector) {
- injector_ = injector;
- }
-
- private:
- // Except for testing, the |EvdevInjector| used to inject evdev events.
- std::unique_ptr<EvdevInjector> owned_injector_;
-
- // Active pointer to |owned_injector_| or to a testing injector.
- EvdevInjector* injector_ = nullptr;
-
- // Previous (x, y) position in device space, to suppress redundant events.
- int32_t last_device_x_ = INT32_MIN;
- int32_t last_device_y_ = INT32_MIN;
-
- // Records current touch state (0=up 1=down) in bit 0, and previous state
- // in bit 1, to track transitions.
- int touches_ = 0;
-
- // Previous injected button state, to detect changes.
- int32_t last_motion_event_buttons_ = 0;
-
- VirtualTouchpad(const VirtualTouchpad&) = delete;
- void operator=(const VirtualTouchpad&) = delete;
-};
-
-} // namespace dvr
-} // namespace android
-
-#endif // ANDROID_DVR_VIRTUAL_TOUCHPAD_H
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp b/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
new file mode 100644
index 0000000..23a2e31
--- /dev/null
+++ b/services/vr/virtual_touchpad/VirtualTouchpadClient.cpp
@@ -0,0 +1,52 @@
+#include "VirtualTouchpadClient.h"
+
+#include <android/dvr/IVirtualTouchpadService.h>
+#include <binder/IServiceManager.h>
+
+namespace android {
+namespace dvr {
+
+namespace {
+
+class VirtualTouchpadClientImpl : public VirtualTouchpadClient {
+ public:
+ VirtualTouchpadClientImpl(sp<IVirtualTouchpadService> service)
+ : service_(service) {}
+ ~VirtualTouchpadClientImpl() {}
+
+ status_t Touch(float x, float y, float pressure) override {
+ if (service_ == nullptr) {
+ return NO_INIT;
+ }
+ return service_->touch(x, y, pressure).transactionError();
+ }
+ status_t ButtonState(int buttons) override {
+ if (service_ == nullptr) {
+ return NO_INIT;
+ }
+ return service_->buttonState(buttons).transactionError();
+ }
+
+ private:
+ sp<IVirtualTouchpadService> service_;
+};
+
+} // anonymous namespace
+
+sp<VirtualTouchpad> VirtualTouchpadClient::Create() {
+ sp<IServiceManager> sm = defaultServiceManager();
+ if (sm == nullptr) {
+ ALOGE("no service manager");
+ return sp<VirtualTouchpad>();
+ }
+ sp<IVirtualTouchpadService> service = interface_cast<IVirtualTouchpadService>(
+ sm->getService(IVirtualTouchpadService::SERVICE_NAME()));
+ if (service == nullptr) {
+ ALOGE("failed to get service");
+ return sp<VirtualTouchpad>();
+ }
+ return new VirtualTouchpadClientImpl(service);
+}
+
+} // namespace dvr
+} // namespace android
diff --git a/services/vr/virtual_touchpad/VirtualTouchpad.cpp b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
similarity index 87%
rename from services/vr/virtual_touchpad/VirtualTouchpad.cpp
rename to services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
index 4793058..ae31156 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpad.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.cpp
@@ -1,4 +1,4 @@
-#include "VirtualTouchpad.h"
+#include "VirtualTouchpadEvdev.h"
#include <android/input.h>
#include <inttypes.h>
@@ -30,7 +30,17 @@
} // anonymous namespace
-int VirtualTouchpad::Initialize() {
+sp<VirtualTouchpad> VirtualTouchpadEvdev::Create() {
+ VirtualTouchpadEvdev* const touchpad = new VirtualTouchpadEvdev();
+ const status_t status = touchpad->Initialize();
+ if (status) {
+ ALOGE("initialization failed: %d", status);
+ return sp<VirtualTouchpad>();
+ }
+ return sp<VirtualTouchpad>(touchpad);
+}
+
+int VirtualTouchpadEvdev::Initialize() {
if (!injector_) {
owned_injector_.reset(new EvdevInjector());
injector_ = owned_injector_.get();
@@ -46,7 +56,7 @@
return injector_->GetError();
}
-int VirtualTouchpad::Touch(float x, float y, float pressure) {
+int VirtualTouchpadEvdev::Touch(float x, float y, float pressure) {
if ((x < 0.0f) || (x >= 1.0f) || (y < 0.0f) || (y >= 1.0f)) {
return EINVAL;
}
@@ -91,7 +101,7 @@
return injector_->GetError();
}
-int VirtualTouchpad::ButtonState(int buttons) {
+int VirtualTouchpadEvdev::ButtonState(int buttons) {
const int changes = last_motion_event_buttons_ ^ buttons;
if (!changes) {
return 0;
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
new file mode 100644
index 0000000..c763529
--- /dev/null
+++ b/services/vr/virtual_touchpad/VirtualTouchpadEvdev.h
@@ -0,0 +1,59 @@
+#ifndef ANDROID_DVR_VIRTUAL_TOUCHPAD_EVDEV_H
+#define ANDROID_DVR_VIRTUAL_TOUCHPAD_EVDEV_H
+
+#include <memory>
+
+#include "VirtualTouchpad.h"
+#include "EvdevInjector.h"
+
+namespace android {
+namespace dvr {
+
+class EvdevInjector;
+
+// VirtualTouchpadEvdev implements a VirtualTouchpad by injecting evdev events.
+//
+class VirtualTouchpadEvdev : public VirtualTouchpad {
+ public:
+ static sp<VirtualTouchpad> Create();
+
+ // VirtualTouchpad implementation:
+ status_t Touch(float x, float y, float pressure) override;
+ status_t ButtonState(int buttons) override;
+
+ protected:
+ VirtualTouchpadEvdev() {}
+ ~VirtualTouchpadEvdev() {}
+ status_t Initialize();
+
+ // Must be called only between construction and Initialize().
+ inline void SetEvdevInjectorForTesting(EvdevInjector* injector) {
+ injector_ = injector;
+ }
+
+ private:
+ // Except for testing, the |EvdevInjector| used to inject evdev events.
+ std::unique_ptr<EvdevInjector> owned_injector_;
+
+ // Active pointer to |owned_injector_| or to a testing injector.
+ EvdevInjector* injector_ = nullptr;
+
+ // Previous (x, y) position in device space, to suppress redundant events.
+ int32_t last_device_x_ = INT32_MIN;
+ int32_t last_device_y_ = INT32_MIN;
+
+ // Records current touch state (0=up 1=down) in bit 0, and previous state
+ // in bit 1, to track transitions.
+ int touches_ = 0;
+
+ // Previous injected button state, to detect changes.
+ int32_t last_motion_event_buttons_ = 0;
+
+ VirtualTouchpadEvdev(const VirtualTouchpadEvdev&) = delete;
+ void operator=(const VirtualTouchpadEvdev&) = delete;
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_VIRTUAL_TOUCHPAD_EVDEV_H
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
index 25c1a4f..3fcb8fc 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
+++ b/services/vr/virtual_touchpad/VirtualTouchpadService.cpp
@@ -8,19 +8,15 @@
namespace android {
namespace dvr {
-int VirtualTouchpadService::Initialize() {
- return touchpad_.Initialize();
-}
-
binder::Status VirtualTouchpadService::touch(float x, float y, float pressure) {
- const int error = touchpad_.Touch(x, y, pressure);
- return error ? binder::Status::fromServiceSpecificError(error)
+ const status_t error = touchpad_->Touch(x, y, pressure);
+ return error ? binder::Status::fromStatusT(error)
: binder::Status::ok();
}
binder::Status VirtualTouchpadService::buttonState(int buttons) {
- const int error = touchpad_.ButtonState(buttons);
- return error ? binder::Status::fromServiceSpecificError(error)
+ const status_t error = touchpad_->ButtonState(buttons);
+ return error ? binder::Status::fromStatusT(error)
: binder::Status::ok();
}
diff --git a/services/vr/virtual_touchpad/VirtualTouchpadService.h b/services/vr/virtual_touchpad/VirtualTouchpadService.h
index e2426e3..b832c8f 100644
--- a/services/vr/virtual_touchpad/VirtualTouchpadService.h
+++ b/services/vr/virtual_touchpad/VirtualTouchpadService.h
@@ -13,22 +13,16 @@
//
class VirtualTouchpadService : public BnVirtualTouchpadService {
public:
- VirtualTouchpadService(VirtualTouchpad& touchpad)
+ VirtualTouchpadService(sp<VirtualTouchpad> touchpad)
: touchpad_(touchpad) {}
- // Must be called before clients can connect.
- // Returns 0 if initialization is successful.
- int Initialize();
-
- static char const* getServiceName() { return "virtual_touchpad"; }
-
protected:
// Implements IVirtualTouchpadService.
- ::android::binder::Status touch(float x, float y, float pressure) override;
- ::android::binder::Status buttonState(int buttons) override;
+ binder::Status touch(float x, float y, float pressure) override;
+ binder::Status buttonState(int buttons) override;
private:
- VirtualTouchpad& touchpad_;
+ sp<VirtualTouchpad> touchpad_;
VirtualTouchpadService(const VirtualTouchpadService&) = delete;
void operator=(const VirtualTouchpadService&) = delete;
diff --git a/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl b/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
index e048837..c2044da 100644
--- a/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
+++ b/services/vr/virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl
@@ -3,6 +3,8 @@
/** @hide */
interface VirtualTouchpadService
{
+ const String SERVICE_NAME = "virtual_touchpad";
+
/**
* Generate a simulated touch event.
*
diff --git a/services/vr/virtual_touchpad/include/VirtualTouchpad.h b/services/vr/virtual_touchpad/include/VirtualTouchpad.h
new file mode 100644
index 0000000..bbaf69b
--- /dev/null
+++ b/services/vr/virtual_touchpad/include/VirtualTouchpad.h
@@ -0,0 +1,57 @@
+#ifndef ANDROID_DVR_VIRTUAL_TOUCHPAD_INTERFACE_H
+#define ANDROID_DVR_VIRTUAL_TOUCHPAD_INTERFACE_H
+
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace dvr {
+
+// Provides a virtual touchpad for injecting events into the input system.
+//
+class VirtualTouchpad : public RefBase {
+ public:
+ // Create a virtual touchpad.
+ // Implementations should provide this, and hide their constructors.
+ // For the user, switching implementations should be as simple as changing
+ // the class whose |Create()| is called.
+ static sp<VirtualTouchpad> Create() {
+ return sp<VirtualTouchpad>();
+ }
+
+ // Generate a simulated touch event.
+ //
+ // @param x Horizontal touch position.
+ // @param y Vertical touch position.
+ // Values must be in the range [0.0, 1.0).
+ // @param pressure Touch pressure.
+ // Positive values represent contact; use 1.0f if contact
+ // is binary. Use 0.0f for no contact.
+ // @returns OK on success.
+ //
+ virtual status_t Touch(float x, float y, float pressure) = 0;
+
+ // Generate a simulated touchpad button state.
+ //
+ // @param buttons A union of MotionEvent BUTTON_* values.
+ // @returns OK on success.
+ //
+ // Currently only BUTTON_BACK is supported, as the implementation
+ // restricts itself to operations actually required by VrWindowManager.
+ //
+ virtual status_t ButtonState(int buttons) = 0;
+
+ protected:
+ VirtualTouchpad() {}
+ virtual ~VirtualTouchpad() {}
+
+ private:
+ VirtualTouchpad(const VirtualTouchpad&) = delete;
+ void operator=(const VirtualTouchpad&) = delete;
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_VIRTUAL_TOUCHPAD_INTERFACE_H
diff --git a/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h b/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
new file mode 100644
index 0000000..46bec0e
--- /dev/null
+++ b/services/vr/virtual_touchpad/include/VirtualTouchpadClient.h
@@ -0,0 +1,31 @@
+#ifndef ANDROID_DVR_VIRTUAL_TOUCHPAD_CLIENT_H
+#define ANDROID_DVR_VIRTUAL_TOUCHPAD_CLIENT_H
+
+#include "VirtualTouchpad.h"
+
+namespace android {
+namespace dvr {
+
+// VirtualTouchpadClient implements a VirtualTouchpad by connecting to
+// a VirtualTouchpadService over Binder.
+//
+class VirtualTouchpadClient : public VirtualTouchpad {
+ public:
+ // VirtualTouchpad implementation:
+ static sp<VirtualTouchpad> Create();
+ status_t Touch(float x, float y, float pressure) override;
+ status_t ButtonState(int buttons) override;
+
+ protected:
+ VirtualTouchpadClient() {}
+ virtual ~VirtualTouchpadClient() {}
+
+ private:
+ VirtualTouchpadClient(const VirtualTouchpadClient&) = delete;
+ void operator=(const VirtualTouchpadClient&) = delete;
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_VIRTUAL_TOUCHPAD_CLIENT_H
diff --git a/services/vr/virtual_touchpad/main.cpp b/services/vr/virtual_touchpad/main.cpp
index 1debe9f..e73f8b9 100644
--- a/services/vr/virtual_touchpad/main.cpp
+++ b/services/vr/virtual_touchpad/main.cpp
@@ -3,17 +3,13 @@
#include <binder/ProcessState.h>
#include <log/log.h>
+#include "VirtualTouchpadEvdev.h"
#include "VirtualTouchpadService.h"
int main() {
ALOGI("Starting");
- android::dvr::VirtualTouchpad touchpad;
- android::dvr::VirtualTouchpadService touchpad_service(touchpad);
- const int touchpad_status = touchpad_service.Initialize();
- if (touchpad_status) {
- ALOGE("virtual touchpad initialization failed: %d", touchpad_status);
- exit(1);
- }
+ android::dvr::VirtualTouchpadService touchpad_service(
+ android::dvr::VirtualTouchpadEvdev::Create());
signal(SIGPIPE, SIG_IGN);
android::sp<android::ProcessState> ps(android::ProcessState::self());
@@ -23,7 +19,7 @@
android::sp<android::IServiceManager> sm(android::defaultServiceManager());
const android::status_t service_status =
- sm->addService(android::String16(touchpad_service.getServiceName()),
+ sm->addService(android::String16(touchpad_service.SERVICE_NAME()),
&touchpad_service, false /*allowIsolated*/);
if (service_status != android::OK) {
ALOGE("virtual touchpad service not added: %d",
diff --git a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
index 256c6bc..b448fd1 100644
--- a/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
+++ b/services/vr/virtual_touchpad/tests/VirtualTouchpad_test.cpp
@@ -1,12 +1,12 @@
#include <android/input.h>
+#include <gtest/gtest.h>
+#include <linux/input.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
-#include <gtest/gtest.h>
-#include <linux/input.h>
#include "EvdevInjector.h"
-#include "VirtualTouchpad.h"
+#include "VirtualTouchpadEvdev.h"
namespace android {
namespace dvr {
@@ -21,7 +21,7 @@
event.type = type;
event.code = code;
event.value = value;
- Write(&event, sizeof (event));
+ Write(&event, sizeof(event));
}
};
@@ -87,16 +87,17 @@
class EvdevInjectorForTesting : public EvdevInjector {
public:
- EvdevInjectorForTesting(UInput& uinput) {
- SetUInputForTesting(&uinput);
- }
+ EvdevInjectorForTesting(UInput& uinput) { SetUInputForTesting(&uinput); }
const uinput_user_dev* GetUiDev() const { return GetUiDevForTesting(); }
};
-class VirtualTouchpadForTesting : public VirtualTouchpad {
+class VirtualTouchpadForTesting : public VirtualTouchpadEvdev {
public:
- VirtualTouchpadForTesting(EvdevInjector& injector) {
- SetEvdevInjectorForTesting(&injector);
+ static sp<VirtualTouchpad> Create(EvdevInjectorForTesting& injector) {
+ VirtualTouchpadForTesting* const touchpad = new VirtualTouchpadForTesting();
+ touchpad->SetEvdevInjectorForTesting(&injector);
+ touchpad->Initialize();
+ return sp<VirtualTouchpad>(touchpad);
}
};
@@ -113,17 +114,13 @@
} // anonymous namespace
-class VirtualTouchpadTest : public testing::Test {
-};
+class VirtualTouchpadTest : public testing::Test {};
TEST_F(VirtualTouchpadTest, Goodness) {
UInputRecorder expect;
UInputRecorder record;
EvdevInjectorForTesting injector(record);
- VirtualTouchpadForTesting touchpad(injector);
-
- const int initialization_status = touchpad.Initialize();
- EXPECT_EQ(0, initialization_status);
+ sp<VirtualTouchpad> touchpad(VirtualTouchpadForTesting::Create(injector));
// Check some aspects of uinput_user_dev.
const uinput_user_dev* uidev = injector.GetUiDev();
@@ -154,13 +151,13 @@
expect.IoctlSetInt(UI_SET_EVBIT, EV_KEY);
expect.IoctlSetInt(UI_SET_KEYBIT, BTN_TOUCH);
// From ConfigureEnd():
- expect.Write(uidev, sizeof (uinput_user_dev));
+ expect.Write(uidev, sizeof(uinput_user_dev));
expect.IoctlVoid(UI_DEV_CREATE);
EXPECT_EQ(expect.GetString(), record.GetString());
expect.Reset();
record.Reset();
- int touch_status = touchpad.Touch(0, 0, 0);
+ int touch_status = touchpad->Touch(0, 0, 0);
EXPECT_EQ(0, touch_status);
expect.WriteInputEvent(EV_ABS, ABS_MT_SLOT, 0);
expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
@@ -171,7 +168,7 @@
expect.Reset();
record.Reset();
- touch_status = touchpad.Touch(0.25f, 0.75f, 0.5f);
+ touch_status = touchpad->Touch(0.25f, 0.75f, 0.5f);
EXPECT_EQ(0, touch_status);
expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, 0.25f * width);
@@ -182,7 +179,7 @@
expect.Reset();
record.Reset();
- touch_status = touchpad.Touch(1.0f, 1.0f, 1.0f);
+ touch_status = touchpad->Touch(1.0f, 1.0f, 1.0f);
EXPECT_EQ(0, touch_status);
expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, 0);
expect.WriteInputEvent(EV_ABS, ABS_MT_POSITION_X, width);
@@ -192,7 +189,7 @@
expect.Reset();
record.Reset();
- touch_status = touchpad.Touch(0.25f, 0.75f, -0.01f);
+ touch_status = touchpad->Touch(0.25f, 0.75f, -0.01f);
EXPECT_EQ(0, touch_status);
expect.WriteInputEvent(EV_KEY, BTN_TOUCH, EvdevInjector::KEY_RELEASE);
expect.WriteInputEvent(EV_ABS, ABS_MT_TRACKING_ID, -1);
@@ -201,7 +198,7 @@
expect.Reset();
record.Reset();
- touch_status = touchpad.ButtonState(AMOTION_EVENT_BUTTON_BACK);
+ touch_status = touchpad->ButtonState(AMOTION_EVENT_BUTTON_BACK);
EXPECT_EQ(0, touch_status);
expect.WriteInputEvent(EV_KEY, BTN_BACK, EvdevInjector::KEY_PRESS);
expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
@@ -209,13 +206,13 @@
expect.Reset();
record.Reset();
- touch_status = touchpad.ButtonState(AMOTION_EVENT_BUTTON_BACK);
+ touch_status = touchpad->ButtonState(AMOTION_EVENT_BUTTON_BACK);
EXPECT_EQ(0, touch_status);
EXPECT_EQ(expect.GetString(), record.GetString());
expect.Reset();
record.Reset();
- touch_status = touchpad.ButtonState(0);
+ touch_status = touchpad->ButtonState(0);
EXPECT_EQ(0, touch_status);
expect.WriteInputEvent(EV_KEY, BTN_BACK, EvdevInjector::KEY_RELEASE);
expect.WriteInputEvent(EV_SYN, SYN_REPORT, 0);
@@ -229,56 +226,29 @@
UInputRecorder expect;
UInputRecorder record;
EvdevInjectorForTesting injector(record);
- VirtualTouchpadForTesting touchpad(injector);
-
- // Touch before initialization should return an error,
- // and should not result in any system calls.
- expect.Reset();
- record.Reset();
- int touch_status = touchpad.Touch(0.25f, 0.75f, -0.01f);
- EXPECT_NE(0, touch_status);
- EXPECT_EQ(expect.GetString(), record.GetString());
-
- // Button change before initialization should return an error,
- // and should not result in any system calls.
- expect.Reset();
- record.Reset();
- touch_status = touchpad.ButtonState(AMOTION_EVENT_BUTTON_BACK);
- EXPECT_NE(0, touch_status);
- EXPECT_EQ(expect.GetString(), record.GetString());
-
- expect.Reset();
- record.Reset();
- touchpad.Initialize();
-
- // Repeated initialization should return an error,
- // and should not result in any system calls.
- expect.Reset();
- record.Reset();
- const int initialization_status = touchpad.Initialize();
- EXPECT_NE(0, initialization_status);
- EXPECT_EQ(expect.GetString(), record.GetString());
+ sp<VirtualTouchpad> touchpad(
+ VirtualTouchpadForTesting::Create(injector));
// Touch off-screen should return an error,
// and should not result in any system calls.
expect.Reset();
record.Reset();
- touch_status = touchpad.Touch(-0.25f, 0.75f, 1.0f);
- EXPECT_NE(0, touch_status);
- touch_status = touchpad.Touch(0.25f, -0.75f, 1.0f);
- EXPECT_NE(0, touch_status);
- touch_status = touchpad.Touch(1.25f, 0.75f, 1.0f);
- EXPECT_NE(0, touch_status);
- touch_status = touchpad.Touch(0.25f, 1.75f, 1.0f);
- EXPECT_NE(0, touch_status);
+ status_t touch_status = touchpad->Touch(-0.25f, 0.75f, 1.0f);
+ EXPECT_NE(OK, touch_status);
+ touch_status = touchpad->Touch(0.25f, -0.75f, 1.0f);
+ EXPECT_NE(OK, touch_status);
+ touch_status = touchpad->Touch(1.25f, 0.75f, 1.0f);
+ EXPECT_NE(OK, touch_status);
+ touch_status = touchpad->Touch(0.25f, 1.75f, 1.0f);
+ EXPECT_NE(OK, touch_status);
EXPECT_EQ(expect.GetString(), record.GetString());
// Unsupported button should return an error,
// and should not result in any system calls.
expect.Reset();
record.Reset();
- touch_status = touchpad.ButtonState(AMOTION_EVENT_BUTTON_FORWARD);
- EXPECT_NE(0, touch_status);
+ touch_status = touchpad->ButtonState(AMOTION_EVENT_BUTTON_FORWARD);
+ EXPECT_NE(OK, touch_status);
EXPECT_EQ(expect.GetString(), record.GetString());
}
diff --git a/services/vr/vr_window_manager/Android.mk b/services/vr/vr_window_manager/Android.mk
index e9552bc..ddb58e9 100644
--- a/services/vr/vr_window_manager/Android.mk
+++ b/services/vr/vr_window_manager/Android.mk
@@ -14,29 +14,6 @@
LOCAL_PATH := $(call my-dir)
-binder_src := \
- vr_window_manager_binder.cpp \
- aidl/android/service/vr/IVrWindowManager.aidl
-
-static_libs := \
- libcutils
-
-shared_libs := \
- libbase \
- libbinder \
- libutils
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(binder_src)
-LOCAL_STATIC_LIBRARIES := $(static_libs)
-LOCAL_SHARED_LIBRARIES := $(shared_libs)
-LOCAL_CPPFLAGS += -std=c++11
-LOCAL_CFLAGS += -DLOG_TAG=\"VrWindowManager\"
-LOCAL_LDLIBS := -llog
-LOCAL_MODULE := libvrwm_binder
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_STATIC_LIBRARY)
-
native_src := \
application.cpp \
controller_mesh.cpp \
@@ -47,7 +24,8 @@
surface_flinger_view.cpp \
texture.cpp \
vr_window_manager.cpp \
- ../virtual_touchpad/aidl/android/dvr/VirtualTouchpadService.aidl \
+ vr_window_manager_binder.cpp \
+ aidl/android/service/vr/IVrWindowManager.aidl
static_libs := \
libdisplay \
@@ -61,12 +39,13 @@
libperformance \
libpdx_default_transport \
libcutils \
+ libvr_manager \
+ libvirtualtouchpadclient
shared_libs := \
android.dvr.composer@1.0 \
android.hardware.graphics.composer@2.1 \
libvrhwc \
- libandroid \
libbase \
libbinder \
libinput \
@@ -85,7 +64,7 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(native_src)
-LOCAL_STATIC_LIBRARIES := $(static_libs) libvrwm_binder
+LOCAL_STATIC_LIBRARIES := $(static_libs)
LOCAL_SHARED_LIBRARIES := $(shared_libs)
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES
LOCAL_CFLAGS += -DEGL_EGLEXT_PROTOTYPES
diff --git a/services/vr/vr_window_manager/application.cpp b/services/vr/vr_window_manager/application.cpp
index 467e95e..dba797f 100644
--- a/services/vr/vr_window_manager/application.cpp
+++ b/services/vr/vr_window_manager/application.cpp
@@ -17,9 +17,16 @@
namespace android {
namespace dvr {
-Application::Application() {}
+Application::Application() {
+ vr_mode_listener_ = new VrModeListener(this);
+}
Application::~Application() {
+ sp<IVrManager> vrManagerService = interface_cast<IVrManager>(
+ defaultServiceManager()->getService(String16("vrmanager")));
+ if (vrManagerService.get()) {
+ vrManagerService->unregisterListener(vr_mode_listener_);
+ }
}
int Application::Initialize() {
@@ -29,6 +36,11 @@
elbow_model_.Enable(ElbowModel::kDefaultNeckPosition, is_right_handed);
last_frame_time_ = std::chrono::system_clock::now();
+ sp<IVrManager> vrManagerService = interface_cast<IVrManager>(
+ defaultServiceManager()->getService(String16("vrmanager")));
+ if (vrManagerService.get()) {
+ vrManagerService->registerListener(vr_mode_listener_);
+ }
return 0;
}
@@ -274,6 +286,11 @@
}
void Application::SetVisibility(bool visible) {
+ if (visible && !initialized_) {
+ if (AllocateResources())
+ ALOGE("Failed to allocate resources");
+ }
+
bool changed = is_visible_ != visible;
if (changed) {
is_visible_ = visible;
@@ -296,5 +313,10 @@
wake_up_init_and_render_.notify_one();
}
+void Application::VrModeListener::onVrStateChanged(bool enabled) {
+ if (!enabled)
+ app_->QueueTask(MainThreadTask::ExitingVrMode);
+}
+
} // namespace dvr
} // namespace android
diff --git a/services/vr/vr_window_manager/application.h b/services/vr/vr_window_manager/application.h
index c7aa4dd..2c60e0a 100644
--- a/services/vr/vr_window_manager/application.h
+++ b/services/vr/vr_window_manager/application.h
@@ -4,6 +4,7 @@
#include <memory>
#include <private/dvr/types.h>
#include <stdint.h>
+#include <vr/vr_manager/vr_manager.h>
#include <chrono>
#include <mutex>
@@ -43,6 +44,16 @@
Show,
};
+ class VrModeListener : public BnVrStateCallbacks {
+ public:
+ VrModeListener(Application *app) : app_(app) {}
+ void onVrStateChanged(bool enabled) override;
+
+ private:
+ Application *app_;
+ };
+
+ sp<VrModeListener> vr_mode_listener_;
virtual void OnDrawFrame() = 0;
virtual void DrawEye(EyeType eye, const mat4& perspective,
const mat4& eye_matrix, const mat4& head_matrix) = 0;
diff --git a/services/vr/vr_window_manager/hwc_callback.h b/services/vr/vr_window_manager/hwc_callback.h
index bcfeb97..be56856 100644
--- a/services/vr/vr_window_manager/hwc_callback.h
+++ b/services/vr/vr_window_manager/hwc_callback.h
@@ -25,7 +25,8 @@
struct HwcLayer {
enum LayerType : uint32_t {
// These are from frameworks/base/core/java/android/view/WindowManager.java
- kUndefinedWindow = 0,
+ kSurfaceFlingerLayer = 0,
+ kUndefinedWindow = ~0U,
kFirstApplicationWindow = 1,
kLastApplicationWindow = 99,
kFirstSubWindow = 1000,
@@ -42,6 +43,19 @@
// Always skip the following layer types
case kNavigationBar:
case kStatusBar:
+ case kSurfaceFlingerLayer:
+ case kUndefinedWindow:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ // This is a layer that provides some other functionality, eg dim layer.
+ // We use this to determine the point at which layers are "on top".
+ bool is_extra_layer() const {
+ switch(type) {
+ case kSurfaceFlingerLayer:
case kUndefinedWindow:
return true;
default:
diff --git a/services/vr/vr_window_manager/shell_view.cpp b/services/vr/vr_window_manager/shell_view.cpp
index 9d0aaad..7321ed0 100644
--- a/services/vr/vr_window_manager/shell_view.cpp
+++ b/services/vr/vr_window_manager/shell_view.cpp
@@ -195,7 +195,8 @@
uint32_t vr_app) {
auto& layers = frame.layers();
- // We assume the first two layers are the VR app.
+ // We assume the first two layers are the VR app. In the case of a 2D app,
+ // there will be the app + at least one system layer so this is still safe.
if (layers.size() < kVRAppLayerCount)
return ViewMode::Hidden;
@@ -203,19 +204,23 @@
layers[1].appid != layers[0].appid) {
if (layers[1].appid != layers[0].appid && layers[0].appid) {
// This might be a 2D app.
+ // If a dim layer exists afterwards it is much more likely that this is
+ // actually an app launch artifact.
+ for (size_t i = 2; i < layers.size(); i++) {
+ if (layers[i].is_extra_layer())
+ return ViewMode::Hidden;
+ }
return ViewMode::App;
}
return ViewMode::Hidden;
}
- // If a non-VR-app, non-skipped layer appears, show.
size_t index = kVRAppLayerCount;
// Now, find a dim layer if it exists.
// If it does, ignore any layers behind it for visibility determination.
for (size_t i = index; i < layers.size(); i++) {
- if (layers[i].appid == 0) {
+ if (layers[i].appid == HwcCallback::HwcLayer::kSurfaceFlingerLayer) {
index = i + 1;
- break;
}
}
@@ -419,7 +424,6 @@
// so give it a kick.
if (visibility != ViewMode::Hidden &&
current_frame_.visibility == ViewMode::Hidden) {
- QueueTask(MainThreadTask::EnteringVrMode);
QueueTask(MainThreadTask::Show);
}
@@ -699,10 +703,7 @@
}
bool ShellView::InitializeTouch() {
- virtual_touchpad_ =
- android::interface_cast<android::dvr::IVirtualTouchpadService>(
- android::defaultServiceManager()->getService(
- android::String16("virtual_touchpad")));
+ virtual_touchpad_ = VirtualTouchpadClient::Create();
if (!virtual_touchpad_.get()) {
ALOGE("Failed to connect to virtual touchpad");
return false;
@@ -719,12 +720,12 @@
}
}
- const android::binder::Status status = virtual_touchpad_->touch(
+ const android::status_t status = virtual_touchpad_->Touch(
hit_location_in_window_coord_.x() / size_.x(),
hit_location_in_window_coord_.y() / size_.y(),
is_touching_ ? 1.0f : 0.0f);
- if (!status.isOk()) {
- ALOGE("touch failed: %s", status.toString8().string());
+ if (status != OK) {
+ ALOGE("touch failed: %d", status);
}
}
@@ -746,11 +747,10 @@
return false;
}
- const android::binder::Status status =
- virtual_touchpad_->buttonState(touchpad_buttons_);
- if (!status.isOk()) {
- ALOGE("touchpad button failed: %d %s", touchpad_buttons_,
- status.toString8().string());
+ const android::status_t status =
+ virtual_touchpad_->ButtonState(touchpad_buttons_);
+ if (status != OK) {
+ ALOGE("touchpad button failed: %d %d", touchpad_buttons_, status);
}
return true;
}
diff --git a/services/vr/vr_window_manager/shell_view.h b/services/vr/vr_window_manager/shell_view.h
index 1e061bb..c477669 100644
--- a/services/vr/vr_window_manager/shell_view.h
+++ b/services/vr/vr_window_manager/shell_view.h
@@ -3,10 +3,10 @@
#include <private/dvr/graphics/mesh.h>
#include <private/dvr/graphics/shader_program.h>
-#include <android/dvr/IVirtualTouchpadService.h>
#include <deque>
+#include "VirtualTouchpadClient.h"
#include "application.h"
#include "reticle.h"
#include "shell_view_binder_interface.h"
@@ -90,7 +90,7 @@
std::unique_ptr<SurfaceFlingerView> surface_flinger_view_;
std::unique_ptr<Reticle> reticle_;
- sp<IVirtualTouchpadService> virtual_touchpad_;
+ sp<VirtualTouchpad> virtual_touchpad_;
std::vector<TextureLayer> textures_;
TextureLayer ime_texture_;
diff --git a/vulkan/include/vulkan/vulkan.h b/vulkan/include/vulkan/vulkan.h
index 45b574a..3c8ee1c 100644
--- a/vulkan/include/vulkan/vulkan.h
+++ b/vulkan/include/vulkan/vulkan.h
@@ -3218,18 +3218,19 @@
typedef enum VkColorSpaceKHR {
VK_COLOR_SPACE_SRGB_NONLINEAR_KHR = 0,
- VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT = 1000104001,
- VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT = 1000104002,
- VK_COLOR_SPACE_SCRGB_LINEAR_EXT = 1000104003,
- VK_COLOR_SPACE_SCRGB_NONLINEAR_EXT = 1000104004,
- VK_COLOR_SPACE_DCI_P3_LINEAR_EXT = 1000104005,
- VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT = 1000104006,
- VK_COLOR_SPACE_BT709_LINEAR_EXT = 1000104007,
- VK_COLOR_SPACE_BT709_NONLINEAR_EXT = 1000104008,
- VK_COLOR_SPACE_BT2020_LINEAR_EXT = 1000104009,
- VK_COLOR_SPACE_BT2020_NONLINEAR_EXT = 1000104010,
+ VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT = 1000104001,
+ VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT = 1000104002,
+ VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT = 1000104003,
+ VK_COLOR_SPACE_DCI_P3_LINEAR_EXT = 1000104004,
+ VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT = 1000104005,
+ VK_COLOR_SPACE_BT709_LINEAR_EXT = 1000104006,
+ VK_COLOR_SPACE_BT709_NONLINEAR_EXT = 1000104007,
+ VK_COLOR_SPACE_BT2020_LINEAR_EXT = 1000104008,
+ VK_COLOR_SPACE_BT2020_170M_EXT = 1000104009,
+ VK_COLOR_SPACE_BT2020_ST2084_EXT = 1000104010,
VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011,
VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012,
+ VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013,
VK_COLOR_SPACE_BEGIN_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
VK_COLOR_SPACE_END_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
VK_COLOR_SPACE_RANGE_SIZE_KHR = (VK_COLOR_SPACE_SRGB_NONLINEAR_KHR - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR + 1),
@@ -4606,6 +4607,10 @@
VkPastPresentationTimingGOOGLE* pPresentationTimings);
#endif
+#define VK_EXT_swapchain_colorspace 1
+#define VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION 1
+#define VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace"
+
#define VK_EXT_hdr_metadata 1
#define VK_EXT_HDR_METADATA_SPEC_VERSION 0
#define VK_EXT_HDR_METADATA_EXTENSION_NAME "VK_EXT_hdr_metadata"
diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl
index 4835a56..992c5d1 100644
--- a/vulkan/libvulkan/code-generator.tmpl
+++ b/vulkan/libvulkan/code-generator.tmpl
@@ -683,12 +683,13 @@
VK_ANDROID_native_buffer
VK_EXT_debug_report
VK_EXT_hdr_metadata
+VK_EXT_swapchain_colorspace
VK_GOOGLE_display_timing
VK_KHR_android_surface
VK_KHR_incremental_present
+VK_KHR_shared_presentable_image
VK_KHR_surface
VK_KHR_swapchain
-VK_KHR_shared_presentable_image
{{end}}
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 76aa176..351caeb 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -447,6 +447,7 @@
switch (ext_bit) {
case ProcHook::KHR_android_surface:
case ProcHook::KHR_surface:
+ case ProcHook::EXT_swapchain_colorspace:
hook_extensions_.set(ext_bit);
// return now as these extensions do not require HAL support
return;
@@ -673,11 +674,13 @@
const char* pLayerName,
uint32_t* pPropertyCount,
VkExtensionProperties* pProperties) {
- static const std::array<VkExtensionProperties, 2> loader_extensions = {{
+ static const std::array<VkExtensionProperties, 3> loader_extensions = {{
// WSI extensions
{VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_SURFACE_SPEC_VERSION},
{VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
VK_KHR_ANDROID_SURFACE_SPEC_VERSION},
+ {VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME,
+ VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION},
}};
static const VkExtensionProperties loader_debug_report_extension = {
VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION,
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
index c4cb544..fc3f87a 100644
--- a/vulkan/libvulkan/driver_gen.cpp
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -365,12 +365,13 @@
if (strcmp(name, "VK_ANDROID_native_buffer") == 0) return ProcHook::ANDROID_native_buffer;
if (strcmp(name, "VK_EXT_debug_report") == 0) return ProcHook::EXT_debug_report;
if (strcmp(name, "VK_EXT_hdr_metadata") == 0) return ProcHook::EXT_hdr_metadata;
+ if (strcmp(name, "VK_EXT_swapchain_colorspace") == 0) return ProcHook::EXT_swapchain_colorspace;
if (strcmp(name, "VK_GOOGLE_display_timing") == 0) return ProcHook::GOOGLE_display_timing;
if (strcmp(name, "VK_KHR_android_surface") == 0) return ProcHook::KHR_android_surface;
if (strcmp(name, "VK_KHR_incremental_present") == 0) return ProcHook::KHR_incremental_present;
+ if (strcmp(name, "VK_KHR_shared_presentable_image") == 0) return ProcHook::KHR_shared_presentable_image;
if (strcmp(name, "VK_KHR_surface") == 0) return ProcHook::KHR_surface;
if (strcmp(name, "VK_KHR_swapchain") == 0) return ProcHook::KHR_swapchain;
- if (strcmp(name, "VK_KHR_shared_presentable_image") == 0) return ProcHook::KHR_shared_presentable_image;
if (strcmp(name, "VK_KHR_get_physical_device_properties2") == 0) return ProcHook::KHR_get_physical_device_properties2;
// clang-format on
return ProcHook::EXTENSION_UNKNOWN;
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index c9dba78..738da5b 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -36,12 +36,13 @@
ANDROID_native_buffer,
EXT_debug_report,
EXT_hdr_metadata,
+ EXT_swapchain_colorspace,
GOOGLE_display_timing,
KHR_android_surface,
KHR_incremental_present,
+ KHR_shared_presentable_image,
KHR_surface,
KHR_swapchain,
- KHR_shared_presentable_image,
KHR_get_physical_device_properties2,
EXTENSION_CORE, // valid bit
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index e105922..a0ae1f3 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -380,6 +380,75 @@
*count = num_copied;
}
+android_pixel_format GetNativePixelFormat(VkFormat format) {
+ android_pixel_format native_format = HAL_PIXEL_FORMAT_RGBA_8888;
+ switch (format) {
+ case VK_FORMAT_R8G8B8A8_UNORM:
+ case VK_FORMAT_R8G8B8A8_SRGB:
+ native_format = HAL_PIXEL_FORMAT_RGBA_8888;
+ break;
+ case VK_FORMAT_R5G6B5_UNORM_PACK16:
+ native_format = HAL_PIXEL_FORMAT_RGB_565;
+ break;
+ case VK_FORMAT_R16G16B16A16_SFLOAT:
+ native_format = HAL_PIXEL_FORMAT_RGBA_FP16;
+ break;
+ case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
+ native_format = HAL_PIXEL_FORMAT_RGBA_1010102;
+ break;
+ default:
+ ALOGV("unsupported swapchain format %d", format);
+ break;
+ }
+ return native_format;
+}
+
+android_dataspace GetNativeDataspace(VkColorSpaceKHR colorspace) {
+ switch (colorspace) {
+ case VK_COLOR_SPACE_SRGB_NONLINEAR_KHR:
+ return HAL_DATASPACE_V0_SRGB;
+ case VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT:
+ return HAL_DATASPACE_DISPLAY_P3;
+ case VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT:
+ return HAL_DATASPACE_V0_SCRGB_LINEAR;
+ case VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT:
+ return HAL_DATASPACE_V0_SCRGB;
+ case VK_COLOR_SPACE_DCI_P3_LINEAR_EXT:
+ return HAL_DATASPACE_DCI_P3_LINEAR;
+ case VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT:
+ return HAL_DATASPACE_DCI_P3;
+ case VK_COLOR_SPACE_BT709_LINEAR_EXT:
+ return HAL_DATASPACE_V0_SRGB_LINEAR;
+ case VK_COLOR_SPACE_BT709_NONLINEAR_EXT:
+ return HAL_DATASPACE_V0_SRGB;
+ case VK_COLOR_SPACE_BT2020_170M_EXT:
+ return static_cast<android_dataspace>(
+ HAL_DATASPACE_STANDARD_BT2020 |
+ HAL_DATASPACE_TRANSFER_SMPTE_170M | HAL_DATASPACE_RANGE_FULL);
+ case VK_COLOR_SPACE_BT2020_ST2084_EXT:
+ return static_cast<android_dataspace>(
+ HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_TRANSFER_ST2084 |
+ HAL_DATASPACE_RANGE_FULL);
+ case VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT:
+ return static_cast<android_dataspace>(
+ HAL_DATASPACE_STANDARD_ADOBE_RGB |
+ HAL_DATASPACE_TRANSFER_LINEAR | HAL_DATASPACE_RANGE_FULL);
+ case VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT:
+ return HAL_DATASPACE_ADOBE_RGB;
+
+ // Pass through is intended to allow app to provide data that is passed
+ // to the display system without modification.
+ case VK_COLOR_SPACE_PASS_THROUGH_EXT:
+ return HAL_DATASPACE_ARBITRARY;
+
+ default:
+ // This indicates that we don't know about the
+ // dataspace specified and we should indicate that
+ // it's unsupported
+ return HAL_DATASPACE_UNKNOWN;
+ }
+}
+
} // anonymous namespace
VKAPI_ATTR
@@ -410,7 +479,7 @@
err);
surface->~Surface();
allocator->pfnFree(allocator->pUserData, surface);
- return VK_ERROR_INITIALIZATION_FAILED;
+ return VK_ERROR_NATIVE_WINDOW_IN_USE_KHR;
}
*out_surface = HandleFromSurface(surface);
@@ -458,13 +527,13 @@
if (err != 0) {
ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
strerror(-err), err);
- return VK_ERROR_INITIALIZATION_FAILED;
+ return VK_ERROR_SURFACE_LOST_KHR;
}
err = window->query(window, NATIVE_WINDOW_DEFAULT_HEIGHT, &height);
if (err != 0) {
ALOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: %s (%d)",
strerror(-err), err);
- return VK_ERROR_INITIALIZATION_FAILED;
+ return VK_ERROR_SURFACE_LOST_KHR;
}
int transform_hint;
@@ -472,7 +541,7 @@
if (err != 0) {
ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)",
strerror(-err), err);
- return VK_ERROR_INITIALIZATION_FAILED;
+ return VK_ERROR_SURFACE_LOST_KHR;
}
// TODO(jessehall): Figure out what the min/max values should be.
@@ -512,10 +581,12 @@
}
VKAPI_ATTR
-VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice /*pdev*/,
- VkSurfaceKHR /*surface*/,
+VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev,
+ VkSurfaceKHR surface_handle,
uint32_t* count,
VkSurfaceFormatKHR* formats) {
+ const InstanceData& instance_data = GetData(pdev);
+
// TODO(jessehall): Fill out the set of supported formats. Longer term, add
// a new gralloc method to query whether a (format, usage) pair is
// supported, and check that for each gralloc format that corresponds to a
@@ -528,15 +599,51 @@
{VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
};
const uint32_t kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
+ uint32_t total_num_formats = kNumFormats;
+
+ bool wide_color_support = false;
+ Surface& surface = *SurfaceFromHandle(surface_handle);
+ int err = native_window_get_wide_color_support(surface.window.get(),
+ &wide_color_support);
+ if (err) {
+ // Not allowed to return a more sensible error code, so do this
+ return VK_ERROR_OUT_OF_HOST_MEMORY;
+ }
+ ALOGV("wide_color_support is: %d", wide_color_support);
+ wide_color_support =
+ wide_color_support &&
+ instance_data.hook_extensions.test(ProcHook::EXT_swapchain_colorspace);
+
+ const VkSurfaceFormatKHR kWideColorFormats[] = {
+ {VK_FORMAT_R16G16B16A16_SFLOAT,
+ VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT},
+ {VK_FORMAT_A2R10G10B10_UNORM_PACK32,
+ VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT},
+ };
+ const uint32_t kNumWideColorFormats =
+ sizeof(kWideColorFormats) / sizeof(kWideColorFormats[0]);
+ if (wide_color_support) {
+ total_num_formats += kNumWideColorFormats;
+ }
VkResult result = VK_SUCCESS;
if (formats) {
- if (*count < kNumFormats)
+ uint32_t out_count = 0;
+ uint32_t transfer_count = 0;
+ if (*count < total_num_formats)
result = VK_INCOMPLETE;
- *count = std::min(*count, kNumFormats);
- std::copy(kFormats, kFormats + *count, formats);
+ transfer_count = std::min(*count, kNumFormats);
+ std::copy(kFormats, kFormats + transfer_count, formats);
+ out_count += transfer_count;
+ if (wide_color_support) {
+ transfer_count = std::min(*count - out_count, kNumWideColorFormats);
+ std::copy(kWideColorFormats, kWideColorFormats + transfer_count,
+ formats + out_count);
+ out_count += transfer_count;
+ }
+ *count = out_count;
} else {
- *count = kNumFormats;
+ *count = total_num_formats;
}
return result;
}
@@ -594,12 +701,21 @@
if (!allocator)
allocator = &GetData(device).allocator;
+ android_pixel_format native_pixel_format =
+ GetNativePixelFormat(create_info->imageFormat);
+ android_dataspace native_dataspace =
+ GetNativeDataspace(create_info->imageColorSpace);
+ if (native_dataspace == HAL_DATASPACE_UNKNOWN) {
+ ALOGE(
+ "CreateSwapchainKHR(VkSwapchainCreateInfoKHR.imageColorSpace = %d) "
+ "failed: Unsupported color space",
+ create_info->imageColorSpace);
+ return VK_ERROR_INITIALIZATION_FAILED;
+ }
+
ALOGV_IF(create_info->imageArrayLayers != 1,
"swapchain imageArrayLayers=%u not supported",
create_info->imageArrayLayers);
- ALOGV_IF(create_info->imageColorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
- "swapchain imageColorSpace=%u not supported",
- create_info->imageColorSpace);
ALOGV_IF((create_info->preTransform & ~kSupportedTransforms) != 0,
"swapchain preTransform=%#x not supported",
create_info->preTransform);
@@ -648,65 +764,55 @@
if (err != 0) {
ALOGE("native_window_set_buffer_count(0) failed: %s (%d)",
strerror(-err), err);
- return VK_ERROR_INITIALIZATION_FAILED;
+ return VK_ERROR_SURFACE_LOST_KHR;
}
- err = surface.window->setSwapInterval(surface.window.get(), 1);
+ int swap_interval =
+ create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR ? 0 : 1;
+ err = surface.window->setSwapInterval(surface.window.get(), swap_interval);
if (err != 0) {
// TODO(jessehall): Improve error reporting. Can we enumerate possible
// errors and translate them to valid Vulkan result codes?
ALOGE("native_window->setSwapInterval(1) failed: %s (%d)",
strerror(-err), err);
- return VK_ERROR_INITIALIZATION_FAILED;
+ return VK_ERROR_SURFACE_LOST_KHR;
}
err = native_window_set_shared_buffer_mode(surface.window.get(), false);
if (err != 0) {
ALOGE("native_window_set_shared_buffer_mode(false) failed: %s (%d)",
strerror(-err), err);
- return VK_ERROR_INITIALIZATION_FAILED;
+ return VK_ERROR_SURFACE_LOST_KHR;
}
err = native_window_set_auto_refresh(surface.window.get(), false);
if (err != 0) {
ALOGE("native_window_set_auto_refresh(false) failed: %s (%d)",
strerror(-err), err);
- return VK_ERROR_INITIALIZATION_FAILED;
+ return VK_ERROR_SURFACE_LOST_KHR;
}
// -- Configure the native window --
const auto& dispatch = GetData(device).driver;
- int native_format = HAL_PIXEL_FORMAT_RGBA_8888;
- switch (create_info->imageFormat) {
- case VK_FORMAT_R8G8B8A8_UNORM:
- case VK_FORMAT_R8G8B8A8_SRGB:
- native_format = HAL_PIXEL_FORMAT_RGBA_8888;
- break;
- case VK_FORMAT_R5G6B5_UNORM_PACK16:
- native_format = HAL_PIXEL_FORMAT_RGB_565;
- break;
- default:
- ALOGV("unsupported swapchain format %d", create_info->imageFormat);
- break;
- }
- err = native_window_set_buffers_format(surface.window.get(), native_format);
+ err = native_window_set_buffers_format(surface.window.get(),
+ native_pixel_format);
if (err != 0) {
// TODO(jessehall): Improve error reporting. Can we enumerate possible
// errors and translate them to valid Vulkan result codes?
ALOGE("native_window_set_buffers_format(%d) failed: %s (%d)",
- native_format, strerror(-err), err);
- return VK_ERROR_INITIALIZATION_FAILED;
+ native_pixel_format, strerror(-err), err);
+ return VK_ERROR_SURFACE_LOST_KHR;
}
err = native_window_set_buffers_data_space(surface.window.get(),
- HAL_DATASPACE_SRGB_LINEAR);
+ native_dataspace);
if (err != 0) {
// TODO(jessehall): Improve error reporting. Can we enumerate possible
// errors and translate them to valid Vulkan result codes?
ALOGE("native_window_set_buffers_data_space(%d) failed: %s (%d)",
- HAL_DATASPACE_SRGB_LINEAR, strerror(-err), err);
- return VK_ERROR_INITIALIZATION_FAILED;
+ native_dataspace, strerror(-err), err);
+ return VK_ERROR_SURFACE_LOST_KHR;
}
err = native_window_set_buffers_dimensions(
@@ -718,7 +824,7 @@
ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)",
create_info->imageExtent.width, create_info->imageExtent.height,
strerror(-err), err);
- return VK_ERROR_INITIALIZATION_FAILED;
+ return VK_ERROR_SURFACE_LOST_KHR;
}
// VkSwapchainCreateInfo::preTransform indicates the transformation the app
@@ -738,7 +844,7 @@
ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)",
InvertTransformToNative(create_info->preTransform),
strerror(-err), err);
- return VK_ERROR_INITIALIZATION_FAILED;
+ return VK_ERROR_SURFACE_LOST_KHR;
}
err = native_window_set_scaling_mode(
@@ -748,7 +854,7 @@
// errors and translate them to valid Vulkan result codes?
ALOGE("native_window_set_scaling_mode(SCALE_TO_WINDOW) failed: %s (%d)",
strerror(-err), err);
- return VK_ERROR_INITIALIZATION_FAILED;
+ return VK_ERROR_SURFACE_LOST_KHR;
}
int query_value;
@@ -760,16 +866,9 @@
// errors and translate them to valid Vulkan result codes?
ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err,
query_value);
- return VK_ERROR_INITIALIZATION_FAILED;
+ return VK_ERROR_SURFACE_LOST_KHR;
}
uint32_t min_undequeued_buffers = static_cast<uint32_t>(query_value);
- // The MIN_UNDEQUEUED_BUFFERS query doesn't know whether we'll be using
- // async mode or not, and assumes not. But in async mode, the BufferQueue
- // requires an extra undequeued buffer.
- // See BufferQueueCore::getMinUndequeuedBufferCountLocked().
- if (create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR)
- min_undequeued_buffers += 1;
-
uint32_t num_images =
(create_info->minImageCount - 1) + min_undequeued_buffers;
err = native_window_set_buffer_count(surface.window.get(), num_images);
@@ -778,7 +877,7 @@
// errors and translate them to valid Vulkan result codes?
ALOGE("native_window_set_buffer_count(%d) failed: %s (%d)", num_images,
strerror(-err), err);
- return VK_ERROR_INITIALIZATION_FAILED;
+ return VK_ERROR_SURFACE_LOST_KHR;
}
VkSwapchainImageUsageFlagsANDROID swapchain_image_usage = 0;
@@ -789,7 +888,7 @@
err = native_window_set_shared_buffer_mode(surface.window.get(), true);
if (err != 0) {
ALOGE("native_window_set_shared_buffer_mode failed: %s (%d)", strerror(-err), err);
- return VK_ERROR_INITIALIZATION_FAILED;
+ return VK_ERROR_SURFACE_LOST_KHR;
}
}
@@ -797,7 +896,7 @@
err = native_window_set_auto_refresh(surface.window.get(), true);
if (err != 0) {
ALOGE("native_window_set_auto_refresh failed: %s (%d)", strerror(-err), err);
- return VK_ERROR_INITIALIZATION_FAILED;
+ return VK_ERROR_SURFACE_LOST_KHR;
}
}
@@ -826,7 +925,7 @@
}
if (result != VK_SUCCESS) {
ALOGE("vkGetSwapchainGrallocUsage2ANDROID failed: %d", result);
- return VK_ERROR_INITIALIZATION_FAILED;
+ return VK_ERROR_SURFACE_LOST_KHR;
}
// TODO: This is the same translation done by Gralloc1On0Adapter.
// Remove it once ANativeWindow has been updated to take gralloc1-style
@@ -839,7 +938,7 @@
&gralloc_usage);
if (result != VK_SUCCESS) {
ALOGE("vkGetSwapchainGrallocUsageANDROID failed: %d", result);
- return VK_ERROR_INITIALIZATION_FAILED;
+ return VK_ERROR_SURFACE_LOST_KHR;
}
}
err = native_window_set_usage(surface.window.get(), gralloc_usage);
@@ -847,18 +946,7 @@
// TODO(jessehall): Improve error reporting. Can we enumerate possible
// errors and translate them to valid Vulkan result codes?
ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), err);
- return VK_ERROR_INITIALIZATION_FAILED;
- }
-
- int swap_interval =
- create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR ? 0 : 1;
- err = surface.window->setSwapInterval(surface.window.get(), swap_interval);
- if (err != 0) {
- // TODO(jessehall): Improve error reporting. Can we enumerate possible
- // errors and translate them to valid Vulkan result codes?
- ALOGE("native_window->setSwapInterval(%d) failed: %s (%d)",
- swap_interval, strerror(-err), err);
- return VK_ERROR_INITIALIZATION_FAILED;
+ return VK_ERROR_SURFACE_LOST_KHR;
}
// -- Allocate our Swapchain object --
@@ -917,7 +1005,7 @@
// TODO(jessehall): Improve error reporting. Can we enumerate
// possible errors and translate them to valid Vulkan result codes?
ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err);
- result = VK_ERROR_INITIALIZATION_FAILED;
+ result = VK_ERROR_SURFACE_LOST_KHR;
break;
}
img.buffer = buffer;
@@ -1053,7 +1141,7 @@
// TODO(jessehall): Improve error reporting. Can we enumerate possible
// errors and translate them to valid Vulkan result codes?
ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
- return VK_ERROR_INITIALIZATION_FAILED;
+ return VK_ERROR_SURFACE_LOST_KHR;
}
uint32_t idx;
diff --git a/vulkan/libvulkan/swapchain.h b/vulkan/libvulkan/swapchain.h
index 4d9f18f..976c995 100644
--- a/vulkan/libvulkan/swapchain.h
+++ b/vulkan/libvulkan/swapchain.h
@@ -27,7 +27,7 @@
VKAPI_ATTR void DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* allocator);
VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice pdev, uint32_t queue_family, VkSurfaceKHR surface, VkBool32* pSupported);
VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice pdev, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* capabilities);
-VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, VkSurfaceKHR surface, uint32_t* count, VkSurfaceFormatKHR* formats);
+VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, VkSurfaceKHR surface_handle, uint32_t* count, VkSurfaceFormatKHR* formats);
VKAPI_ATTR VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev, VkSurfaceKHR surface, uint32_t* count, VkPresentModeKHR* modes);
VKAPI_ATTR VkResult CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* create_info, const VkAllocationCallbacks* allocator, VkSwapchainKHR* swapchain_handle);
VKAPI_ATTR void DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain_handle, const VkAllocationCallbacks* allocator);