Merge "Tie VR mode support to a property"
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index e953ded..7646feb 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 = "64&32";
+ 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 a passthrough interface;\n"
+ "PIDs / processes shown below might be inaccurate because the process\n"
+ "might have relinquish 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 the library\n"
+ "and successfully fetch 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(std::string{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/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/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/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index d755ed3..9d761fd 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -21,6 +21,7 @@
#include <ctype.h>
#include <input/InputDevice.h>
+#include <input/InputEventLabels.h>
namespace android {
@@ -87,17 +88,23 @@
const String8& name, InputDeviceConfigurationFileType type) {
// Search system repository.
String8 path;
- path.setTo(getenv("ANDROID_ROOT"));
- path.append("/usr/");
- appendInputDeviceConfigurationFileRelativePath(path, name, type);
+
+ // Treblized input device config files will be located /odm/usr or /vendor/usr.
+ char *rootsForPartition[] {"/odm", "/vendor", getenv("ANDROID_ROOT")};
+ for (size_t i = 0; i < size(rootsForPartition); i++) {
+ path.setTo(rootsForPartition[i]);
+ path.append("/usr/");
+ appendInputDeviceConfigurationFileRelativePath(path, name, type);
#if DEBUG_PROBE
- ALOGD("Probing for system provided input device configuration file: path='%s'", path.string());
+ ALOGD("Probing for system provided input device configuration file: path='%s'",
+ path.string());
#endif
- if (!access(path.string(), R_OK)) {
+ if (!access(path.string(), R_OK)) {
#if DEBUG_PROBE
- ALOGD("Found");
+ ALOGD("Found");
#endif
- return path;
+ return path;
+ }
}
// Search user repository.
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/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 4a281d4..f03491f 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -69,7 +69,8 @@
mCBContext(),
mEventHandler(nullptr),
mVSyncCounts(),
- mRemainingHwcVirtualDisplays(0)
+ mRemainingHwcVirtualDisplays(0),
+ mDumpMayLockUp(false)
{
for (size_t i=0 ; i<HWC_NUM_PHYSICAL_DISPLAY_TYPES ; i++) {
mLastHwVSync[i] = 0;
@@ -489,6 +490,8 @@
return NO_ERROR;
}
+ mDumpMayLockUp = true;
+
uint32_t numTypes = 0;
uint32_t numRequests = 0;
auto error = hwcDisplay->validate(&numTypes, &numRequests);
@@ -633,6 +636,9 @@
auto& displayData = mDisplayData[displayId];
auto& hwcDisplay = displayData.hwcDisplay;
auto error = hwcDisplay->present(&displayData.lastPresentFence);
+
+ mDumpMayLockUp = false;
+
if (error != HWC2::Error::None) {
ALOGE("presentAndGetReleaseFences: failed for display %d: %s (%d)",
displayId, to_string(error).c_str(), static_cast<int32_t>(error));
@@ -878,6 +884,11 @@
}
void HWComposer::dump(String8& result) const {
+ if (mDumpMayLockUp) {
+ result.append("HWComposer dump skipped because present in progress");
+ return;
+ }
+
// TODO: In order to provide a dump equivalent to HWC1, we need to shadow
// all the state going into the layers. This is probably better done in
// Layer itself, but it's going to take a bit of work to get there.
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 0713709..20cca39 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -231,6 +231,9 @@
// thread-safe
mutable Mutex mVsyncLock;
+
+ // XXX temporary workaround for b/35806047
+ mutable std::atomic<bool> mDumpMayLockUp;
};
class HWComposerBufferCache {
diff --git a/services/vr/vr_window_manager/Android.mk b/services/vr/vr_window_manager/Android.mk
index e9552bc..706efe5 100644
--- a/services/vr/vr_window_manager/Android.mk
+++ b/services/vr/vr_window_manager/Android.mk
@@ -61,12 +61,12 @@
libperformance \
libpdx_default_transport \
libcutils \
+ libvr_manager \
shared_libs := \
android.dvr.composer@1.0 \
android.hardware.graphics.composer@2.1 \
libvrhwc \
- libandroid \
libbase \
libbinder \
libinput \
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..6cbd88d 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);
}
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index e105922..b35e534 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -651,7 +651,9 @@
return VK_ERROR_INITIALIZATION_FAILED;
}
- 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?
@@ -763,13 +765,6 @@
return VK_ERROR_INITIALIZATION_FAILED;
}
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);
@@ -850,17 +845,6 @@
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;
- }
-
// -- Allocate our Swapchain object --
// After this point, we must deallocate the swapchain on error.