Merge "Add the missing Parcel.writeInterfaceToken call."
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
index 7ef4f96..ce97c78 100644
--- a/include/binder/HalToken.h
+++ b/include/binder/HalToken.h
@@ -21,8 +21,16 @@
#include <hidl/HidlSupport.h>
/**
- * It is possible to pass a hidl interface via as a binder interface by
- * providing an appropriate "wrapper" class.
+ * 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
@@ -31,7 +39,8 @@
* 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 similar to `HALINTERFACE`.
+ * `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:
@@ -41,14 +50,14 @@
* 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 constructors in `H2BFoo` that call the corresponding
+ * 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 `CBase`, so the above line can be copied verbatim
- * into `H2BFoo`.
- * 4. Add conversion functions inside `H2BFoo`. `H2BConverter` provides a
- * protected `mBase` of type `sp<HFoo>` that can be used to access the 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
@@ -60,7 +69,7 @@
* 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
- * `getHalToken` and `getHalInterface` to the protected member `mBase`,
+ * `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`.)
@@ -97,7 +106,7 @@
uint32_t GETTOKEN = '_GTK'>
class H2BConverter : public BNINTERFACE {
public:
- typedef H2BConverter<HINTERFACE, INTERFACE, BNINTERFACE, GETTOKEN> CBase;
+ typedef H2BConverter<HINTERFACE, INTERFACE, BNINTERFACE, GETTOKEN> CBase; // Converter Base
typedef INTERFACE BaseInterface;
typedef HINTERFACE HalInterface;
static constexpr uint32_t GET_HAL_TOKEN = GETTOKEN;
@@ -112,8 +121,11 @@
sp<HalInterface> mBase;
};
-template <typename BPINTERFACE, typename CONVERTER, uint32_t GETTOKEN = '_GTK'>
-class HpInterface : public BPINTERFACE {
+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;
@@ -125,8 +137,10 @@
BaseInterface* getBaseInterface() { return mBase.get(); }
protected:
+ sp<IBinder> mImpl;
sp<BaseInterface> mBase;
sp<HalInterface> mHal;
+ IBinder* onAsBinder() override { return mImpl.get(); }
};
// ----------------------------------------------------------------------
@@ -191,18 +205,15 @@
template <typename BPINTERFACE, typename CONVERTER, uint32_t GETTOKEN>
HpInterface<BPINTERFACE, CONVERTER, GETTOKEN>::HpInterface(
- const sp<IBinder>& impl):
- BPINTERFACE(impl),
- mBase(nullptr) {
-
+ const sp<IBinder>& impl) : mImpl(impl) {
Parcel data, reply;
data.writeInterfaceToken(BaseInterface::getInterfaceDescriptor());
- if (this->remote()->transact(GET_HAL_TOKEN, data, &reply) == NO_ERROR) {
+ 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 = this;
+ mBase = new BPINTERFACE(impl);
} else {
sp<HInterface> hInterface = retrieveHalInterface(token);
deleteHalToken(token);
@@ -211,11 +222,11 @@
mBase = new CONVERTER(mHal);
} else {
ALOGE("HpInterface: Cannot retrieve HAL interface from token.");
- mBase = this;
+ mBase = new BPINTERFACE(impl);
}
}
} else {
- mBase = this;
+ mBase = new BPINTERFACE(impl);
}
}
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/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 4acdb82..4040374 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 &&
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/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 f34aaf9..be56856 100644
--- a/services/vr/vr_window_manager/hwc_callback.h
+++ b/services/vr/vr_window_manager/hwc_callback.h
@@ -51,6 +51,18 @@
}
}
+ // 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:
+ return false;
+ }
+ }
+
sp<Fence> fence;
sp<GraphicBuffer> buffer;
Rectf crop;
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.