Merge "Use Layer.getAlpha instead of State.alpha to calculate occlusion"
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index dd32ac6..d83f601 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -1068,7 +1068,7 @@
} else {
// Mismatched GID/mode is recoverable; fall through to update
LOG(DEBUG) << "Mismatched cache GID/mode at " << path << ": found " << st.st_gid
- << " but expected " << gid;
+ << "/" << actual_mode << " but expected " << gid << "/" << target_mode;
}
// Directory is owned correctly, but GID or mode mismatch means it's
diff --git a/cmds/lshal/Android.bp b/cmds/lshal/Android.bp
index 5a87505..6cbe7e2 100644
--- a/cmds/lshal/Android.bp
+++ b/cmds/lshal/Android.bp
@@ -20,6 +20,7 @@
"libutils",
"libhidlbase",
"libhidltransport",
+ "libhidl-gen-hash",
"libhidl-gen-utils",
"libvintf",
],
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index 8b59fb8..7399692 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -27,6 +27,7 @@
#include <android-base/parseint.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <hidl-hash/Hash.h>
#include <hidl-util/FQName.h>
#include <private/android_filesystem_config.h>
#include <sys/stat.h>
@@ -39,6 +40,9 @@
#include "utils.h"
using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hidl::base::V1_0::DebugInfo;
+using ::android::hidl::base::V1_0::IBase;
using ::android::hidl::manager::V1_0::IServiceManager;
namespace android {
@@ -85,7 +89,7 @@
}), pids->end());
}
-bool scanBinderContext(pid_t pid,
+static bool scanBinderContext(pid_t pid,
const std::string &contextName,
std::function<void(const std::string&)> eachLine) {
std::ifstream ifs("/d/binder/proc/" + std::to_string(pid));
@@ -171,6 +175,16 @@
});
}
+const PidInfo* ListCommand::getPidInfoCached(pid_t serverPid) {
+ auto pair = mCachedPidInfos.insert({serverPid, PidInfo{}});
+ if (pair.second /* did insertion take place? */) {
+ if (!getPidInfo(serverPid, &pair.first->second)) {
+ return nullptr;
+ }
+ }
+ return &pair.first->second;
+}
+
// Must process hwbinder services first, then passthrough services.
void ListCommand::forEachTable(const std::function<void(Table &)> &f) {
f(mServicesTable);
@@ -445,10 +459,7 @@
entries.emplace(interfaceName, TableEntry{
.interfaceName = interfaceName,
.transport = "passthrough",
- .serverPid = NO_PID,
- .serverObjectAddress = NO_PTR,
.clientPids = info.clientPids,
- .arch = ARCH_UNKNOWN
}).first->second.arch |= fromBaseArchitecture(info.arch);
}
for (auto &&pair : entries) {
@@ -479,7 +490,6 @@
std::string{info.instanceName.c_str()},
.transport = "passthrough",
.serverPid = info.clientPids.size() == 1 ? info.clientPids[0] : NO_PID,
- .serverObjectAddress = NO_PTR,
.clientPids = info.clientPids,
.arch = fromBaseArchitecture(info.arch)
});
@@ -494,10 +504,6 @@
}
Status ListCommand::fetchBinderized(const sp<IServiceManager> &manager) {
- using namespace ::std;
- using namespace ::android::hardware;
- using namespace ::android::hidl::manager::V1_0;
- using namespace ::android::hidl::base::V1_0;
const std::string mode = "hwbinder";
hidl_vec<hidl_string> fqInstanceNames;
@@ -512,80 +518,117 @@
}
Status status = OK;
- // server pid, .ptr value of binder object, child pids
- std::map<std::string, DebugInfo> allDebugInfos;
- std::map<pid_t, PidInfo> allPids;
+ std::map<std::string, TableEntry> allTableEntries;
for (const auto &fqInstanceName : fqInstanceNames) {
- const auto pair = splitFirst(fqInstanceName, '/');
- const auto &serviceName = pair.first;
- const auto &instanceName = pair.second;
- auto getRet = timeoutIPC(manager, &IServiceManager::get, serviceName, instanceName);
- if (!getRet.isOk()) {
- err() << "Warning: Skipping \"" << fqInstanceName << "\": "
- << "cannot be fetched from service manager:"
- << getRet.description() << std::endl;
- status |= DUMP_BINDERIZED_ERROR;
- continue;
- }
- sp<IBase> service = getRet;
- if (service == nullptr) {
- err() << "Warning: Skipping \"" << fqInstanceName << "\": "
- << "cannot be fetched from service manager (null)"
- << std::endl;
- status |= DUMP_BINDERIZED_ERROR;
- continue;
- }
- auto debugRet = timeoutIPC(service, &IBase::getDebugInfo, [&] (const auto &debugInfo) {
- allDebugInfos[fqInstanceName] = debugInfo;
- if (debugInfo.pid >= 0) {
- allPids[static_cast<pid_t>(debugInfo.pid)] = PidInfo();
- }
+ // create entry and default assign all fields.
+ TableEntry& entry = allTableEntries[fqInstanceName];
+ entry.interfaceName = fqInstanceName;
+ entry.transport = mode;
+
+ status |= fetchBinderizedEntry(manager, &entry);
+ }
+
+ for (auto& pair : allTableEntries) {
+ putEntry(HWSERVICEMANAGER_LIST, std::move(pair.second));
+ }
+ return status;
+}
+
+Status ListCommand::fetchBinderizedEntry(const sp<IServiceManager> &manager,
+ TableEntry *entry) {
+ Status status = OK;
+ const auto handleError = [&](Status additionalError, const std::string& msg) {
+ err() << "Warning: Skipping \"" << entry->interfaceName << "\": " << msg << std::endl;
+ status |= DUMP_BINDERIZED_ERROR | additionalError;
+ };
+
+ const auto pair = splitFirst(entry->interfaceName, '/');
+ const auto &serviceName = pair.first;
+ const auto &instanceName = pair.second;
+ auto getRet = timeoutIPC(manager, &IServiceManager::get, serviceName, instanceName);
+ if (!getRet.isOk()) {
+ handleError(TRANSACTION_ERROR,
+ "cannot be fetched from service manager:" + getRet.description());
+ return status;
+ }
+ sp<IBase> service = getRet;
+ if (service == nullptr) {
+ handleError(NO_INTERFACE, "cannot be fetched from service manager (null)");
+ return status;
+ }
+
+ // getDebugInfo
+ do {
+ DebugInfo debugInfo;
+ auto debugRet = timeoutIPC(service, &IBase::getDebugInfo, [&] (const auto &received) {
+ debugInfo = received;
});
if (!debugRet.isOk()) {
- err() << "Warning: Skipping \"" << fqInstanceName << "\": "
- << "debugging information cannot be retrieved:"
- << debugRet.description() << std::endl;
- status |= DUMP_BINDERIZED_ERROR;
+ handleError(TRANSACTION_ERROR,
+ "debugging information cannot be retrieved: " + debugRet.description());
+ break; // skip getPidInfo
}
- }
- for (auto &pair : allPids) {
- pid_t serverPid = pair.first;
- if (!getPidInfo(serverPid, &allPids[serverPid])) {
- err() << "Warning: no information for PID " << serverPid
- << ", are you root?" << std::endl;
- status |= DUMP_BINDERIZED_ERROR;
- }
- }
- for (const auto &fqInstanceName : fqInstanceNames) {
- auto it = allDebugInfos.find(fqInstanceName);
- if (it == allDebugInfos.end()) {
- putEntry(HWSERVICEMANAGER_LIST, {
- .interfaceName = fqInstanceName,
- .transport = mode,
- .serverPid = NO_PID,
- .serverObjectAddress = NO_PTR,
- .clientPids = {},
- .threadUsage = 0,
- .threadCount = 0,
- .arch = ARCH_UNKNOWN
- });
- continue;
- }
- const DebugInfo &info = it->second;
- bool writePidInfo = info.pid != NO_PID && info.ptr != NO_PTR;
+ entry->serverPid = debugInfo.pid;
+ entry->serverObjectAddress = debugInfo.ptr;
+ entry->arch = fromBaseArchitecture(debugInfo.arch);
- putEntry(HWSERVICEMANAGER_LIST, {
- .interfaceName = fqInstanceName,
- .transport = mode,
- .serverPid = info.pid,
- .serverObjectAddress = info.ptr,
- .clientPids = writePidInfo ? allPids[info.pid].refPids[info.ptr] : Pids{},
- .threadUsage = writePidInfo ? allPids[info.pid].threadUsage : 0,
- .threadCount = writePidInfo ? allPids[info.pid].threadCount : 0,
- .arch = fromBaseArchitecture(info.arch),
+ if (debugInfo.pid != NO_PID) {
+ const PidInfo* pidInfo = getPidInfoCached(debugInfo.pid);
+ if (pidInfo == nullptr) {
+ handleError(IO_ERROR,
+ "no information for PID " + std::to_string(debugInfo.pid) +
+ ", are you root?");
+ break;
+ }
+ if (debugInfo.ptr != NO_PTR) {
+ auto it = pidInfo->refPids.find(debugInfo.ptr);
+ if (it != pidInfo->refPids.end()) {
+ entry->clientPids = it->second;
+ }
+ }
+ entry->threadUsage = pidInfo->threadUsage;
+ entry->threadCount = pidInfo->threadCount;
+ }
+ } while (0);
+
+ // hash
+ do {
+ ssize_t hashIndex = -1;
+ auto ifaceChainRet = timeoutIPC(service, &IBase::interfaceChain, [&] (const auto& c) {
+ for (size_t i = 0; i < c.size(); ++i) {
+ if (serviceName == c[i]) {
+ hashIndex = static_cast<ssize_t>(i);
+ break;
+ }
+ }
});
- }
+ if (!ifaceChainRet.isOk()) {
+ handleError(TRANSACTION_ERROR,
+ "interfaceChain fails: " + ifaceChainRet.description());
+ break; // skip getHashChain
+ }
+ if (hashIndex < 0) {
+ handleError(BAD_IMPL, "Interface name does not exist in interfaceChain.");
+ break; // skip getHashChain
+ }
+ auto hashRet = timeoutIPC(service, &IBase::getHashChain, [&] (const auto& hashChain) {
+ if (static_cast<size_t>(hashIndex) >= hashChain.size()) {
+ handleError(BAD_IMPL,
+ "interfaceChain indicates position " + std::to_string(hashIndex) +
+ " but getHashChain returns " + std::to_string(hashChain.size()) +
+ " hashes");
+ return;
+ }
+
+ auto&& hashArray = hashChain[hashIndex];
+ std::vector<uint8_t> hashVec{hashArray.data(), hashArray.data() + hashArray.size()};
+ entry->hash = Hash::hexString(hashVec);
+ });
+ if (!hashRet.isOk()) {
+ handleError(TRANSACTION_ERROR, "getHashChain failed: " + hashRet.description());
+ }
+ } while (0);
return status;
}
@@ -623,6 +666,10 @@
thiz->mSelectedColumns.push_back(TableColumnType::INTERFACE_NAME);
return OK;
}, "print the instance name column"});
+ mOptions.push_back({'l', "released", no_argument, v++, [](ListCommand* thiz, const char*) {
+ thiz->mSelectedColumns.push_back(TableColumnType::RELEASED);
+ return OK;
+ }, "print the 'is released?' column\n(Y=released, empty=unreleased or unknown)"});
mOptions.push_back({'t', "transport", no_argument, v++, [](ListCommand* thiz, const char*) {
thiz->mSelectedColumns.push_back(TableColumnType::TRANSPORT);
return OK;
@@ -631,6 +678,10 @@
thiz->mSelectedColumns.push_back(TableColumnType::ARCH);
return OK;
}, "print the bitness column"});
+ mOptions.push_back({'s', "hash", no_argument, v++, [](ListCommand* thiz, const char*) {
+ thiz->mSelectedColumns.push_back(TableColumnType::HASH);
+ return OK;
+ }, "print hash of the interface"});
mOptions.push_back({'p', "pid", no_argument, v++, [](ListCommand* thiz, const char*) {
thiz->mSelectedColumns.push_back(TableColumnType::SERVER_PID);
return OK;
@@ -773,7 +824,8 @@
}
if (mSelectedColumns.empty()) {
- mSelectedColumns = {TableColumnType::INTERFACE_NAME, TableColumnType::THREADS,
+ mSelectedColumns = {TableColumnType::RELEASED,
+ TableColumnType::INTERFACE_NAME, TableColumnType::THREADS,
TableColumnType::SERVER_PID, TableColumnType::CLIENT_PIDS};
}
@@ -841,7 +893,7 @@
err() << "list:" << std::endl
<< " lshal" << std::endl
<< " lshal list" << std::endl
- << " List all hals with default ordering and columns (`lshal list -iepc`)" << std::endl
+ << " List all hals with default ordering and columns (`lshal list -riepc`)" << std::endl
<< " lshal list [-h|--help]" << std::endl
<< " -h, --help: Print help message for list (`lshal help list`)" << std::endl
<< " lshal [list] [OPTIONS...]" << std::endl;
diff --git a/cmds/lshal/ListCommand.h b/cmds/lshal/ListCommand.h
index 5bc834c..7e252fc 100644
--- a/cmds/lshal/ListCommand.h
+++ b/cmds/lshal/ListCommand.h
@@ -78,14 +78,21 @@
protected:
Status parseArgs(const Arg &arg);
Status fetch();
- void postprocess();
+ virtual void postprocess();
Status dump();
void putEntry(TableEntrySource source, TableEntry &&entry);
Status fetchPassthrough(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
Status fetchBinderized(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
Status fetchAllLibraries(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
+ Status fetchBinderizedEntry(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager,
+ TableEntry *entry);
+
+ // Get relevant information for a PID by parsing files under /d/binder.
+ // It is a virtual member function so that it can be mocked.
virtual bool getPidInfo(pid_t serverPid, PidInfo *info) const;
+ // Retrieve from mCachedPidInfos and call getPidInfo if necessary.
+ const PidInfo* getPidInfoCached(pid_t serverPid);
void dumpTable(const NullableOStream<std::ostream>& out) const;
void dumpVintf(const NullableOStream<std::ostream>& out) const;
@@ -129,6 +136,9 @@
// If an entry exist and not empty, it contains the cached content of /proc/{pid}/cmdline.
std::map<pid_t, std::string> mCmdlines;
+ // Cache for getPidInfo.
+ std::map<pid_t, PidInfo> mCachedPidInfos;
+
RegisteredOptions mOptions;
// All selected columns
std::vector<TableColumnType> mSelectedColumns;
diff --git a/cmds/lshal/TableEntry.cpp b/cmds/lshal/TableEntry.cpp
index cbcf979..e8792a4 100644
--- a/cmds/lshal/TableEntry.cpp
+++ b/cmds/lshal/TableEntry.cpp
@@ -16,6 +16,8 @@
#define LOG_TAG "lshal"
#include <android-base/logging.h>
+#include <hidl-hash/Hash.h>
+
#include "TableEntry.h"
#include "TextTable.h"
@@ -53,8 +55,10 @@
case TableColumnType::CLIENT_CMDS: return "Clients CMD";
case TableColumnType::ARCH: return "Arch";
case TableColumnType::THREADS: return "Thread Use";
+ case TableColumnType::RELEASED: return "R";
+ case TableColumnType::HASH: return "Hash";
default:
- LOG(FATAL) << "Should not reach here.";
+ LOG(FATAL) << __func__ << "Should not reach here. " << static_cast<int>(type);
return "";
}
}
@@ -79,12 +83,25 @@
return getArchString(arch);
case TableColumnType::THREADS:
return getThreadUsage();
+ case TableColumnType::RELEASED:
+ return isReleased();
+ case TableColumnType::HASH:
+ return hash;
default:
- LOG(FATAL) << "Should not reach here.";
+ LOG(FATAL) << __func__ << "Should not reach here. " << static_cast<int>(type);
return "";
}
}
+std::string TableEntry::isReleased() const {
+ static const std::string unreleased = Hash::hexString(Hash::kEmptyHash);
+
+ if (hash.empty() || hash == unreleased) {
+ return " "; // unknown or unreleased
+ }
+ return "Y"; // released
+}
+
TextTable Table::createTextTable(bool neat,
const std::function<std::string(const std::string&)>& emitDebugInfo) const {
diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h
index 7a3b22e..69206cc 100644
--- a/cmds/lshal/TableEntry.h
+++ b/cmds/lshal/TableEntry.h
@@ -55,19 +55,28 @@
CLIENT_CMDS,
ARCH,
THREADS,
+ RELEASED,
+ HASH,
+};
+
+enum {
+ NO_PID = -1,
+ NO_PTR = 0
};
struct TableEntry {
- std::string interfaceName;
- std::string transport;
- int32_t serverPid;
- uint32_t threadUsage;
- uint32_t threadCount;
- std::string serverCmdline;
- uint64_t serverObjectAddress;
- Pids clientPids;
- std::vector<std::string> clientCmdlines;
- Architecture arch;
+ std::string interfaceName{};
+ std::string transport{};
+ int32_t serverPid{NO_PID};
+ uint32_t threadUsage{0};
+ uint32_t threadCount{0};
+ std::string serverCmdline{};
+ uint64_t serverObjectAddress{NO_PTR};
+ Pids clientPids{};
+ std::vector<std::string> clientCmdlines{};
+ Architecture arch{ARCH_UNKNOWN};
+ // empty: unknown, all zeros: unreleased, otherwise: released
+ std::string hash{};
static bool sortByInterfaceName(const TableEntry &a, const TableEntry &b) {
return a.interfaceName < b.interfaceName;
@@ -84,6 +93,8 @@
return std::to_string(threadUsage) + "/" + std::to_string(threadCount);
}
+ std::string isReleased() const;
+
std::string getField(TableColumnType type) const;
bool operator==(const TableEntry& other) const;
@@ -129,11 +140,6 @@
std::vector<const Table*> mTables;
};
-enum {
- NO_PID = -1,
- NO_PTR = 0
-};
-
} // namespace lshal
} // namespace android
diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp
index 06b6819..9220fc0 100644
--- a/cmds/lshal/test.cpp
+++ b/cmds/lshal/test.cpp
@@ -39,6 +39,7 @@
using ::android::hidl::base::V1_0::IBase;
using ::android::hidl::manager::V1_0::IServiceManager;
using ::android::hidl::manager::V1_0::IServiceNotification;
+using ::android::hardware::hidl_array;
using ::android::hardware::hidl_death_recipient;
using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_string;
@@ -46,6 +47,8 @@
using InstanceDebugInfo = IServiceManager::InstanceDebugInfo;
+using hidl_hash = hidl_array<uint8_t, 32>;
+
namespace android {
namespace hardware {
namespace tests {
@@ -185,6 +188,9 @@
Status parseArgs(const Arg& arg) { return ListCommand::parseArgs(arg); }
Status main(const Arg& arg) { return ListCommand::main(arg); }
+ void forEachTable(const std::function<void(Table &)> &f) {
+ return ListCommand::forEachTable(f);
+ }
void forEachTable(const std::function<void(const Table &)> &f) const {
return ListCommand::forEachTable(f);
}
@@ -192,7 +198,12 @@
void dumpVintf(const NullableOStream<std::ostream>& out) {
return ListCommand::dumpVintf(out);
}
+ void internalPostprocess() { ListCommand::postprocess(); }
+ const PidInfo* getPidInfoCached(pid_t serverPid) {
+ return ListCommand::getPidInfoCached(serverPid);
+ }
+ MOCK_METHOD0(postprocess, void());
MOCK_CONST_METHOD2(getPidInfo, bool(pid_t, PidInfo*));
MOCK_CONST_METHOD1(parseCmdline, std::string(pid_t));
};
@@ -210,16 +221,6 @@
std::stringstream output;
};
-TEST_F(ListParseArgsTest, Default) {
- // default args
- EXPECT_EQ(0u, mockList->parseArgs(createArg({})));
- mockList->forEachTable([](const Table& table) {
- EXPECT_EQ(SelectedColumns({TableColumnType::INTERFACE_NAME, TableColumnType::THREADS,
- TableColumnType::SERVER_PID, TableColumnType::CLIENT_PIDS}),
- table.getSelectedColumns());
- });
-}
-
TEST_F(ListParseArgsTest, Args) {
EXPECT_EQ(0u, mockList->parseArgs(createArg({"lshal", "-p", "-i", "-a", "-c"})));
mockList->forEachTable([](const Table& table) {
@@ -232,9 +233,14 @@
TEST_F(ListParseArgsTest, Cmds) {
EXPECT_EQ(0u, mockList->parseArgs(createArg({"lshal", "-m"})));
mockList->forEachTable([](const Table& table) {
- EXPECT_EQ(SelectedColumns({TableColumnType::INTERFACE_NAME, TableColumnType::THREADS,
- TableColumnType::SERVER_CMD, TableColumnType::CLIENT_CMDS}),
- table.getSelectedColumns());
+ EXPECT_THAT(table.getSelectedColumns(), Not(Contains(TableColumnType::SERVER_PID)))
+ << "should not print server PID with -m";
+ EXPECT_THAT(table.getSelectedColumns(), Not(Contains(TableColumnType::CLIENT_PIDS)))
+ << "should not print client PIDs with -m";
+ EXPECT_THAT(table.getSelectedColumns(), Contains(TableColumnType::SERVER_CMD))
+ << "should print server cmd with -m";
+ EXPECT_THAT(table.getSelectedColumns(), Contains(TableColumnType::CLIENT_CMDS))
+ << "should print client cmds with -m";
});
}
@@ -274,17 +280,34 @@
if (serverId == NO_PID) return "";
return "command_line_" + std::to_string(serverId);
}
+static bool getIsReleasedFromId(pid_t p) { return p % 2 == 0; }
+static hidl_hash getHashFromId(pid_t serverId) {
+ hidl_hash hash;
+ bool isReleased = getIsReleasedFromId(serverId);
+ for (size_t i = 0; i < hash.size(); ++i) {
+ hash[i] = isReleased ? static_cast<uint8_t>(serverId) : 0u;
+ }
+ return hash;
+}
// Fake service returned by mocked IServiceManager::get.
class TestService : public IBase {
public:
- TestService(DebugInfo&& info) : mInfo(std::move(info)) {}
+ TestService(pid_t id) : mId(id) {}
hardware::Return<void> getDebugInfo(getDebugInfo_cb cb) override {
- cb(mInfo);
+ cb({ mId /* pid */, getPtr(mId), DebugInfo::Architecture::IS_64BIT });
+ return hardware::Void();
+ }
+ hardware::Return<void> interfaceChain(interfaceChain_cb cb) override {
+ cb({getInterfaceName(mId), IBase::descriptor});
+ return hardware::Void();
+ }
+ hardware::Return<void> getHashChain(getHashChain_cb cb) override {
+ cb({getHashFromId(mId), getHashFromId(0xff)});
return hardware::Void();
}
private:
- DebugInfo mInfo;
+ pid_t mId;
};
class ListTest : public ::testing::Test {
@@ -303,6 +326,13 @@
return true;
}));
ON_CALL(*mockList, parseCmdline(_)).WillByDefault(Invoke(&getCmdlineFromId));
+ ON_CALL(*mockList, postprocess()).WillByDefault(Invoke([&]() {
+ mockList->internalPostprocess();
+ size_t i = 0;
+ mockList->forEachTable([&](Table& table) {
+ table.setDescription("[fake description " + std::to_string(i++) + "]");
+ });
+ }));
}
void initMockServiceManager() {
@@ -318,7 +348,7 @@
ON_CALL(*serviceManager, get(_, _)).WillByDefault(Invoke(
[&](const hidl_string&, const hidl_string& instance) {
int id = getIdFromInstanceName(instance);
- return sp<IBase>(new TestService({ id /* pid */, getPtr(id), A::IS_64BIT }));
+ return sp<IBase>(new TestService(id));
}));
ON_CALL(*serviceManager, debugDump(_)).WillByDefault(Invoke(
@@ -348,6 +378,13 @@
sp<MockServiceManager> passthruManager;
};
+TEST_F(ListTest, GetPidInfoCached) {
+ EXPECT_CALL(*mockList, getPidInfo(5, _)).Times(1);
+
+ EXPECT_NE(nullptr, mockList->getPidInfoCached(5));
+ EXPECT_NE(nullptr, mockList->getPidInfoCached(5));
+}
+
TEST_F(ListTest, Fetch) {
EXPECT_EQ(0u, mockList->fetch());
std::array<std::string, 6> transports{{"hwbinder", "hwbinder", "passthrough",
@@ -456,24 +493,68 @@
<< vintf::gHalManifestConverter.lastError();
}
+// test default columns
+TEST_F(ListTest, DumpDefault) {
+ const std::string expected =
+ "[fake description 0]\n"
+ "R Interface Thread Use Server Clients\n"
+ " a.h.foo1@1.0::IFoo/1 11/21 1 2 4\n"
+ "Y a.h.foo2@2.0::IFoo/2 12/22 2 3 5\n"
+ "\n"
+ "[fake description 1]\n"
+ "R Interface Thread Use Server Clients\n"
+ " a.h.foo3@3.0::IFoo/3 N/A N/A 4 6\n"
+ " a.h.foo4@4.0::IFoo/4 N/A N/A 5 7\n"
+ "\n"
+ "[fake description 2]\n"
+ "R Interface Thread Use Server Clients\n"
+ " a.h.foo5@5.0::IFoo/5 N/A N/A 6 8\n"
+ " a.h.foo6@6.0::IFoo/6 N/A N/A 7 9\n"
+ "\n";
+
+ optind = 1; // mimic Lshal::parseArg()
+ EXPECT_EQ(0u, mockList->main(createArg({"lshal"})));
+ EXPECT_EQ(expected, out.str());
+ EXPECT_EQ("", err.str());
+}
+
+TEST_F(ListTest, DumpHash) {
+ const std::string expected =
+ "[fake description 0]\n"
+ "Interface R Hash\n"
+ "a.h.foo1@1.0::IFoo/1 0000000000000000000000000000000000000000000000000000000000000000\n"
+ "a.h.foo2@2.0::IFoo/2 Y 0202020202020202020202020202020202020202020202020202020202020202\n"
+ "\n"
+ "[fake description 1]\n"
+ "Interface R Hash\n"
+ "a.h.foo3@3.0::IFoo/3 \n"
+ "a.h.foo4@4.0::IFoo/4 \n"
+ "\n"
+ "[fake description 2]\n"
+ "Interface R Hash\n"
+ "a.h.foo5@5.0::IFoo/5 \n"
+ "a.h.foo6@6.0::IFoo/6 \n"
+ "\n";
+
+ optind = 1; // mimic Lshal::parseArg()
+ EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-ils"})));
+ EXPECT_EQ(expected, out.str());
+ EXPECT_EQ("", err.str());
+}
+
TEST_F(ListTest, Dump) {
const std::string expected =
- "All binderized services (registered services through hwservicemanager)\n"
+ "[fake description 0]\n"
"Interface Transport Arch Thread Use Server PTR Clients\n"
"a.h.foo1@1.0::IFoo/1 hwbinder 64 11/21 1 0000000000002711 2 4\n"
"a.h.foo2@2.0::IFoo/2 hwbinder 64 12/22 2 0000000000002712 3 5\n"
"\n"
- "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.\n"
+ "[fake description 1]\n"
"Interface Transport Arch Thread Use Server PTR Clients\n"
"a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A N/A 4 6\n"
"a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A N/A 5 7\n"
"\n"
- "All available passthrough implementations (all -impl.so files)\n"
+ "[fake description 2]\n"
"Interface Transport Arch Thread Use Server PTR Clients\n"
"a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A N/A 6 8\n"
"a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A N/A 7 9\n"
@@ -487,22 +568,17 @@
TEST_F(ListTest, DumpCmdline) {
const std::string expected =
- "All binderized services (registered services through hwservicemanager)\n"
+ "[fake description 0]\n"
"Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
"a.h.foo1@1.0::IFoo/1 hwbinder 64 11/21 command_line_1 0000000000002711 command_line_2;command_line_4\n"
"a.h.foo2@2.0::IFoo/2 hwbinder 64 12/22 command_line_2 0000000000002712 command_line_3;command_line_5\n"
"\n"
- "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.\n"
+ "[fake description 1]\n"
"Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
"a.h.foo3@3.0::IFoo/3 passthrough 32 N/A N/A command_line_4;command_line_6\n"
"a.h.foo4@4.0::IFoo/4 passthrough 32 N/A N/A command_line_5;command_line_7\n"
"\n"
- "All available passthrough implementations (all -impl.so files)\n"
+ "[fake description 2]\n"
"Interface Transport Arch Thread Use Server CMD PTR Clients CMD\n"
"a.h.foo5@5.0::IFoo/5 passthrough 32 N/A N/A command_line_6;command_line_8\n"
"a.h.foo6@6.0::IFoo/6 passthrough 32 N/A N/A command_line_7;command_line_9\n"
@@ -524,7 +600,7 @@
"a.h.foo6@6.0::IFoo/6 N/A N/A 7 9\n";
optind = 1; // mimic Lshal::parseArg()
- EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--neat"})));
+ EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iepc", "--neat"})));
EXPECT_EQ(expected, out.str());
EXPECT_EQ("", err.str());
}
diff --git a/cmds/lshal/utils.h b/cmds/lshal/utils.h
index 7eca14e..c09e8b1 100644
--- a/cmds/lshal/utils.h
+++ b/cmds/lshal/utils.h
@@ -44,6 +44,8 @@
NO_INTERFACE = 1 << 7,
// Transaction error from hwbinder transactions
TRANSACTION_ERROR = 1 << 8,
+ // No transaction error, but return value is unexpected.
+ BAD_IMPL = 1 << 9,
};
using Status = unsigned int;
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index 6b7254c..3264666 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -38,4 +38,20 @@
* strings.
*/
@utf8InCpp String[] getNamesForUids(in int[] uids);
+
+ /**
+ * Returns the name of the installer (a package) which installed the named
+ * package. Preloaded packages return the string "preload". Sideloaded packages
+ * return an empty string. Unknown or unknowable are returned as empty strings.
+ */
+
+ @utf8InCpp String getInstallerForPackage(in String packageName);
+
+ /**
+ * Returns the version code of the named package.
+ * Unknown or unknowable versions are returned as 0.
+ */
+
+ int getVersionCodeForPackage(in String packageName);
+
}
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 573f685..3418a49 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -46,7 +46,6 @@
output.writeStrongBinder(IInterface::asBinder(barrierGbp));
output.writeStrongBinder(relativeLayerHandle);
output.writeStrongBinder(parentHandleForChild);
- output.writeStrongBinder(childHandle);
output.write(transparentRegion);
return NO_ERROR;
}
@@ -80,7 +79,6 @@
interface_cast<IGraphicBufferProducer>(input.readStrongBinder());
relativeLayerHandle = input.readStrongBinder();
parentHandleForChild = input.readStrongBinder();
- childHandle = input.readStrongBinder();
input.read(transparentRegion);
return NO_ERROR;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index b0ae7e0..be7b1d2 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -176,9 +176,8 @@
status_t reparentChildren(const sp<SurfaceComposerClient>& client,
const sp<IBinder>& id,
const sp<IBinder>& newParentHandle);
- status_t reparentChild(const sp<SurfaceComposerClient>& client,
- const sp<IBinder>& id, const sp<IBinder>& newParentHandle,
- const sp<IBinder>& childHandle);
+ status_t reparent(const sp<SurfaceComposerClient>& client,
+ const sp<IBinder>& id, const sp<IBinder>& newParentHandle);
status_t detachChildren(const sp<SurfaceComposerClient>& client,
const sp<IBinder>& id);
status_t setOverrideScalingMode(const sp<SurfaceComposerClient>& client,
@@ -496,18 +495,16 @@
return NO_ERROR;
}
-status_t Composer::reparentChild(const sp<SurfaceComposerClient>& client,
+status_t Composer::reparent(const sp<SurfaceComposerClient>& client,
const sp<IBinder>& id,
- const sp<IBinder>& newParentHandle,
- const sp<IBinder>& childHandle) {
+ const sp<IBinder>& newParentHandle) {
Mutex::Autolock lock(mLock);
layer_state_t* s = getLayerStateLocked(client, id);
if (!s) {
return BAD_INDEX;
}
- s->what |= layer_state_t::eReparentChild;
+ s->what |= layer_state_t::eReparent;
s->parentHandleForChild = newParentHandle;
- s->childHandle = childHandle;
return NO_ERROR;
}
@@ -849,9 +846,9 @@
return getComposer().reparentChildren(this, id, newParentHandle);
}
-status_t SurfaceComposerClient::reparentChild(const sp<IBinder>& id,
- const sp<IBinder>& newParentHandle, const sp<IBinder>& childHandle) {
- return getComposer().reparentChild(this, id, newParentHandle, childHandle);
+status_t SurfaceComposerClient::reparent(const sp<IBinder>& id,
+ const sp<IBinder>& newParentHandle) {
+ return getComposer().reparent(this, id, newParentHandle);
}
status_t SurfaceComposerClient::detachChildren(const sp<IBinder>& id) {
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index b9c5ef9..d801d12 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -191,11 +191,10 @@
return mClient->reparentChildren(mHandle, newParentHandle);
}
-status_t SurfaceControl::reparentChild(const sp<IBinder>& newParentHandle,
- const sp<IBinder>& childHandle) {
+status_t SurfaceControl::reparent(const sp<IBinder>& newParentHandle) {
status_t err = validate();
if (err < 0) return err;
- return mClient->reparentChild(mHandle, newParentHandle, childHandle);
+ return mClient->reparent(mHandle, newParentHandle);
}
status_t SurfaceControl::detachChildren() {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 6e2cb83..cf2ff5b 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -161,8 +161,7 @@
const sp<Surface>& handle, uint64_t frameNumber);
status_t reparentChildren(const sp<IBinder>& id,
const sp<IBinder>& newParentHandle);
- status_t reparentChild(const sp<IBinder>& id, const sp<IBinder>& newParentHandle,
- const sp<IBinder>& childHandle);
+ status_t reparent(const sp<IBinder>& id, const sp<IBinder>& newParentHandle);
status_t detachChildren(const sp<IBinder>& id);
status_t setOverrideScalingMode(const sp<IBinder>& id,
int32_t overrideScalingMode);
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index d8b67ef..b506e00 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -124,11 +124,10 @@
// Reparents all children of this layer to the new parent handle.
status_t reparentChildren(const sp<IBinder>& newParentHandle);
- // Reparents a specified child from this layer to the new parent handle.
- // The child, parent, and new parent must all have the same client.
+ // Reparents the current layer to the new parent handle. The new parent must not be null.
// This can be used instead of reparentChildren if the caller wants to
- // only re-parent specific children.
- status_t reparentChild(const sp<IBinder>& newParentHandle, const sp<IBinder>& childHandle);
+ // only re-parent a specific child.
+ status_t reparent(const sp<IBinder>& newParentHandle);
// Detaches all child surfaces (and their children recursively)
// from their SurfaceControl.
diff --git a/libs/gui/include/private/gui/LayerState.h b/libs/gui/include/private/gui/LayerState.h
index 4f73e04..4ff2e5e 100644
--- a/libs/gui/include/private/gui/LayerState.h
+++ b/libs/gui/include/private/gui/LayerState.h
@@ -60,7 +60,7 @@
eReparentChildren = 0x00002000,
eDetachChildren = 0x00004000,
eRelativeLayerChanged = 0x00008000,
- eReparentChild = 0x00010000
+ eReparent = 0x00010000
};
layer_state_t()
@@ -109,7 +109,6 @@
sp<IBinder> relativeLayerHandle;
sp<IBinder> parentHandleForChild;
- sp<IBinder> childHandle;
// non POD must be last. see write/read
Region transparentRegion;
diff --git a/libs/hwc2on1adapter/HWC2On1Adapter.cpp b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
index 8c6ef69..e1b9a8a 100644
--- a/libs/hwc2on1adapter/HWC2On1Adapter.cpp
+++ b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
@@ -2005,10 +2005,21 @@
return Error::None;
}
+static bool compareRects(const hwc_rect_t& rect1, const hwc_rect_t& rect2) {
+ return rect1.left == rect2.left &&
+ rect1.right == rect2.right &&
+ rect1.top == rect2.top &&
+ rect1.bottom == rect2.bottom;
+}
+
Error HWC2On1Adapter::Layer::setVisibleRegion(hwc_region_t visible) {
- mVisibleRegion.resize(visible.numRects);
- std::copy_n(visible.rects, visible.numRects, mVisibleRegion.begin());
- mDisplay.markGeometryChanged();
+ if ((getNumVisibleRegions() != visible.numRects) ||
+ !std::equal(mVisibleRegion.begin(), mVisibleRegion.end(), visible.rects,
+ compareRects)) {
+ mVisibleRegion.resize(visible.numRects);
+ std::copy_n(visible.rects, visible.numRects, mVisibleRegion.begin());
+ mDisplay.markGeometryChanged();
+ }
return Error::None;
}
diff --git a/libs/vr/libvrflinger/display_manager_service.cpp b/libs/vr/libvrflinger/display_manager_service.cpp
index 40396b9..ef8cca3 100644
--- a/libs/vr/libvrflinger/display_manager_service.cpp
+++ b/libs/vr/libvrflinger/display_manager_service.cpp
@@ -65,6 +65,7 @@
}
pdx::Status<void> DisplayManagerService::HandleMessage(pdx::Message& message) {
+ ATRACE_NAME("DisplayManagerService::HandleMessage");
auto channel = std::static_pointer_cast<DisplayManager>(message.GetChannel());
switch (message.GetOp()) {
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index 10abc5e..ac68a5e 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -124,6 +124,8 @@
// surface-specific messages to the per-instance handlers.
Status<void> DisplayService::HandleMessage(pdx::Message& message) {
ALOGD_IF(TRACE, "DisplayService::HandleMessage: opcode=%d", message.GetOp());
+ ATRACE_NAME("DisplayService::HandleMessage");
+
switch (message.GetOp()) {
case DisplayProtocol::GetMetrics::Opcode:
DispatchRemoteMethod<DisplayProtocol::GetMetrics>(
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index 9c4278c..1039fc5 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -5,12 +5,14 @@
#include <fcntl.h>
#include <log/log.h>
#include <poll.h>
+#include <stdint.h>
#include <sync/sync.h>
#include <sys/eventfd.h>
#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/system_properties.h>
#include <sys/timerfd.h>
+#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <utils/Trace.h>
@@ -30,7 +32,9 @@
using android::hardware::Return;
using android::hardware::Void;
+using android::pdx::ErrorStatus;
using android::pdx::LocalHandle;
+using android::pdx::Status;
using android::pdx::rpc::EmptyVariant;
using android::pdx::rpc::IfAnyOf;
@@ -82,6 +86,29 @@
return true;
}
+// Utility to generate scoped tracers with arguments.
+// TODO(eieio): Move/merge this into utils/Trace.h?
+class TraceArgs {
+ public:
+ template <typename... Args>
+ TraceArgs(const char* format, Args&&... args) {
+ std::array<char, 1024> buffer;
+ snprintf(buffer.data(), buffer.size(), format, std::forward<Args>(args)...);
+ atrace_begin(ATRACE_TAG, buffer.data());
+ }
+
+ ~TraceArgs() { atrace_end(ATRACE_TAG); }
+
+ private:
+ TraceArgs(const TraceArgs&) = delete;
+ void operator=(const TraceArgs&) = delete;
+};
+
+// Macro to define a scoped tracer with arguments. Uses PASTE(x, y) macro
+// defined in utils/Trace.h.
+#define TRACE_FORMAT(format, ...) \
+ TraceArgs PASTE(__tracer, __LINE__) { format, ##__VA_ARGS__ }
+
} // anonymous namespace
HardwareComposer::HardwareComposer()
@@ -411,14 +438,12 @@
retire_fence_fds_.erase(retire_fence_fds_.begin());
}
- const bool is_frame_pending = IsFramePendingInDriver();
const bool is_fence_pending = static_cast<int32_t>(retire_fence_fds_.size()) >
post_thread_config_.allowed_pending_fence_count;
- if (is_fence_pending || is_frame_pending) {
+ if (is_fence_pending) {
ATRACE_INT("frame_skip_count", ++frame_skip_count_);
- ALOGW_IF(is_frame_pending, "Warning: frame already queued, dropping frame");
ALOGW_IF(is_fence_pending,
"Warning: dropping a frame to catch up with HWC (pending = %zd)",
retire_fence_fds_.size());
@@ -587,18 +612,28 @@
}
}
+Status<int64_t> HardwareComposer::GetVSyncTime() {
+ auto status = composer_callback_->GetVsyncTime(HWC_DISPLAY_PRIMARY);
+ ALOGE_IF(!status,
+ "HardwareComposer::GetVSyncTime: Failed to get vsync timestamp: %s",
+ status.GetErrorMessage().c_str());
+ return status;
+}
+
// Waits for the next vsync and returns the timestamp of the vsync event. If
// vsync already passed since the last call, returns the latest vsync timestamp
// instead of blocking.
-int HardwareComposer::WaitForVSync(int64_t* timestamp) {
- int error = PostThreadPollInterruptible(composer_callback_->GetVsyncEventFd(),
- POLLIN, /*timeout_ms*/ 1000);
- if (error == kPostThreadInterrupted || error < 0) {
+Status<int64_t> HardwareComposer::WaitForVSync() {
+ const int64_t predicted_vsync_time =
+ last_vsync_timestamp_ +
+ display_metrics_.vsync_period_ns * vsync_prediction_interval_;
+ const int error = SleepUntil(predicted_vsync_time);
+ if (error < 0) {
+ ALOGE("HardwareComposer::WaifForVSync:: Failed to sleep: %s",
+ strerror(-error));
return error;
- } else {
- *timestamp = composer_callback_->GetVsyncTime();
- return 0;
}
+ return {predicted_vsync_time};
}
int HardwareComposer::SleepUntil(int64_t wakeup_timestamp) {
@@ -704,26 +739,41 @@
thread_policy_setup =
SetThreadPolicy("graphics:high", "/system/performance");
}
+
+ // Initialize the last vsync timestamp with the current time. The
+ // predictor below uses this time + the vsync interval in absolute time
+ // units for the initial delay. Once the driver starts reporting vsync the
+ // predictor will sync up with the real vsync.
+ last_vsync_timestamp_ = GetSystemClockNs();
}
int64_t vsync_timestamp = 0;
{
- std::array<char, 128> buf;
- snprintf(buf.data(), buf.size(), "wait_vsync|vsync=%d|",
- vsync_count_ + 1);
- ATRACE_NAME(buf.data());
+ TRACE_FORMAT("wait_vsync|vsync=%u;last_timestamp=%" PRId64
+ ";prediction_interval=%d|",
+ vsync_count_ + 1, last_vsync_timestamp_,
+ vsync_prediction_interval_);
- const int error = WaitForVSync(&vsync_timestamp);
+ auto status = WaitForVSync();
ALOGE_IF(
- error < 0,
+ !status,
"HardwareComposer::PostThread: Failed to wait for vsync event: %s",
- strerror(-error));
- // Don't bother processing this frame if a pause was requested
- if (error == kPostThreadInterrupted)
+ status.GetErrorMessage().c_str());
+
+ // If there was an error either sleeping was interrupted due to pausing or
+ // there was an error getting the latest timestamp.
+ if (!status)
continue;
+
+ // Predicted vsync timestamp for this interval. This is stable because we
+ // use absolute time for the wakeup timer.
+ vsync_timestamp = status.get();
}
- ++vsync_count_;
+ // Advance the vsync counter only if the system is keeping up with hardware
+ // vsync to give clients an indication of the delays.
+ if (vsync_prediction_interval_ == 1)
+ ++vsync_count_;
const bool layer_config_changed = UpdateLayerConfig();
@@ -773,6 +823,38 @@
}
}
+ {
+ auto status = GetVSyncTime();
+ if (!status) {
+ ALOGE("HardwareComposer::PostThread: Failed to get VSYNC time: %s",
+ status.GetErrorMessage().c_str());
+ }
+
+ // If we failed to read vsync there might be a problem with the driver.
+ // Since there's nothing we can do just behave as though we didn't get an
+ // updated vsync time and let the prediction continue.
+ const int64_t current_vsync_timestamp =
+ status ? status.get() : last_vsync_timestamp_;
+
+ const bool vsync_delayed =
+ last_vsync_timestamp_ == current_vsync_timestamp;
+ ATRACE_INT("vsync_delayed", vsync_delayed);
+
+ // If vsync was delayed advance the prediction interval and allow the
+ // fence logic in PostLayers() to skip the frame.
+ if (vsync_delayed) {
+ ALOGW(
+ "HardwareComposer::PostThread: VSYNC timestamp did not advance "
+ "since last frame: timestamp=%" PRId64 " prediction_interval=%d",
+ current_vsync_timestamp, vsync_prediction_interval_);
+ vsync_prediction_interval_++;
+ } else {
+ // We have an updated vsync timestamp, reset the prediction interval.
+ last_vsync_timestamp_ = current_vsync_timestamp;
+ vsync_prediction_interval_ = 1;
+ }
+ }
+
PostLayers();
}
}
@@ -860,14 +942,28 @@
}
}
-HardwareComposer::ComposerCallback::ComposerCallback() {
- vsync_event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
- LOG_ALWAYS_FATAL_IF(!vsync_event_fd_, "Failed to create vsync event fd : %s",
- strerror(errno));
-}
-
Return<void> HardwareComposer::ComposerCallback::onHotplug(
- Hwc2::Display /*display*/, IComposerCallback::Connection /*conn*/) {
+ Hwc2::Display display, IComposerCallback::Connection /*conn*/) {
+ // See if the driver supports the vsync_event node in sysfs.
+ if (display < HWC_NUM_PHYSICAL_DISPLAY_TYPES &&
+ !displays_[display].driver_vsync_event_fd) {
+ std::array<char, 1024> buffer;
+ snprintf(buffer.data(), buffer.size(),
+ "/sys/class/graphics/fb%" PRIu64 "/vsync_event", display);
+ if (LocalHandle handle{buffer.data(), O_RDONLY}) {
+ ALOGI(
+ "HardwareComposer::ComposerCallback::onHotplug: Driver supports "
+ "vsync_event node for display %" PRIu64,
+ display);
+ displays_[display].driver_vsync_event_fd = std::move(handle);
+ } else {
+ ALOGI(
+ "HardwareComposer::ComposerCallback::onHotplug: Driver does not "
+ "support vsync_event node for display %" PRIu64,
+ display);
+ }
+ }
+
return Void();
}
@@ -878,29 +974,81 @@
Return<void> HardwareComposer::ComposerCallback::onVsync(Hwc2::Display display,
int64_t timestamp) {
- if (display == HWC_DISPLAY_PRIMARY) {
- std::lock_guard<std::mutex> lock(vsync_mutex_);
- vsync_time_ = timestamp;
- int error = eventfd_write(vsync_event_fd_.Get(), 1);
- LOG_ALWAYS_FATAL_IF(error != 0, "Failed writing to vsync event fd");
+ TRACE_FORMAT("vsync_callback|display=%" PRIu64 ";timestamp=%" PRId64 "|",
+ display, timestamp);
+ if (display < HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
+ displays_[display].callback_vsync_timestamp = timestamp;
+ } else {
+ ALOGW(
+ "HardwareComposer::ComposerCallback::onVsync: Received vsync on "
+ "non-physical display: display=%" PRId64,
+ display);
}
return Void();
}
-const pdx::LocalHandle& HardwareComposer::ComposerCallback::GetVsyncEventFd()
- const {
- return vsync_event_fd_;
-}
+Status<int64_t> HardwareComposer::ComposerCallback::GetVsyncTime(
+ Hwc2::Display display) {
+ if (display >= HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
+ ALOGE(
+ "HardwareComposer::ComposerCallback::GetVsyncTime: Invalid physical "
+ "display requested: display=%" PRIu64,
+ display);
+ return ErrorStatus(EINVAL);
+ }
-int64_t HardwareComposer::ComposerCallback::GetVsyncTime() {
- std::lock_guard<std::mutex> lock(vsync_mutex_);
- eventfd_t event;
- eventfd_read(vsync_event_fd_.Get(), &event);
- LOG_ALWAYS_FATAL_IF(vsync_time_ < 0,
- "Attempt to read vsync time before vsync event");
- int64_t return_val = vsync_time_;
- vsync_time_ = -1;
- return return_val;
+ // See if the driver supports direct vsync events.
+ LocalHandle& event_fd = displays_[display].driver_vsync_event_fd;
+ if (!event_fd) {
+ // Fall back to returning the last timestamp returned by the vsync
+ // callback.
+ std::lock_guard<std::mutex> autolock(vsync_mutex_);
+ return displays_[display].callback_vsync_timestamp;
+ }
+
+ // When the driver supports the vsync_event sysfs node we can use it to
+ // determine the latest vsync timestamp, even if the HWC callback has been
+ // delayed.
+
+ // The driver returns data in the form "VSYNC=<timestamp ns>".
+ std::array<char, 32> data;
+ data.fill('\0');
+
+ // Seek back to the beginning of the event file.
+ int ret = lseek(event_fd.Get(), 0, SEEK_SET);
+ if (ret < 0) {
+ const int error = errno;
+ ALOGE(
+ "HardwareComposer::ComposerCallback::GetVsyncTime: Failed to seek "
+ "vsync event fd: %s",
+ strerror(error));
+ return ErrorStatus(error);
+ }
+
+ // Read the vsync event timestamp.
+ ret = read(event_fd.Get(), data.data(), data.size());
+ if (ret < 0) {
+ const int error = errno;
+ ALOGE_IF(error != EAGAIN,
+ "HardwareComposer::ComposerCallback::GetVsyncTime: Error "
+ "while reading timestamp: %s",
+ strerror(error));
+ return ErrorStatus(error);
+ }
+
+ int64_t timestamp;
+ ret = sscanf(data.data(), "VSYNC=%" PRIu64,
+ reinterpret_cast<uint64_t*>(×tamp));
+ if (ret < 0) {
+ const int error = errno;
+ ALOGE(
+ "HardwareComposer::ComposerCallback::GetVsyncTime: Error while "
+ "parsing timestamp: %s",
+ strerror(error));
+ return ErrorStatus(error);
+ }
+
+ return {timestamp};
}
Hwc2::Composer* Layer::composer_{nullptr};
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index 793c3e8..8131e50 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -142,9 +142,7 @@
bool operator<(const Layer& other) const {
return GetSurfaceId() < other.GetSurfaceId();
}
- bool operator<(int surface_id) const {
- return GetSurfaceId() < surface_id;
- }
+ bool operator<(int surface_id) const { return GetSurfaceId() < surface_id; }
// Sets the composer instance used by all Layer instances.
static void SetComposer(Hwc2::Composer* composer) { composer_ = composer; }
@@ -340,19 +338,23 @@
class ComposerCallback : public Hwc2::IComposerCallback {
public:
- ComposerCallback();
+ ComposerCallback() = default;
hardware::Return<void> onHotplug(Hwc2::Display display,
Connection conn) override;
hardware::Return<void> onRefresh(Hwc2::Display display) override;
hardware::Return<void> onVsync(Hwc2::Display display,
int64_t timestamp) override;
- const pdx::LocalHandle& GetVsyncEventFd() const;
- int64_t GetVsyncTime();
+
+ pdx::Status<int64_t> GetVsyncTime(Hwc2::Display display);
private:
std::mutex vsync_mutex_;
- pdx::LocalHandle vsync_event_fd_;
- int64_t vsync_time_ = -1;
+
+ struct Display {
+ pdx::LocalHandle driver_vsync_event_fd;
+ int64_t callback_vsync_timestamp{0};
+ };
+ std::array<Display, HWC_NUM_PHYSICAL_DISPLAY_TYPES> displays_;
};
HWC::Error Validate(hwc2_display_t display);
@@ -392,11 +394,10 @@
// can be interrupted by a control thread. If interrupted, these calls return
// kPostThreadInterrupted.
int ReadWaitPPState();
- int WaitForVSync(int64_t* timestamp);
+ pdx::Status<int64_t> WaitForVSync();
+ pdx::Status<int64_t> GetVSyncTime();
int SleepUntil(int64_t wakeup_timestamp);
- bool IsFramePendingInDriver() { return false; }
-
// Reconfigures the layer stack if the display surfaces changed since the last
// frame. Called only from the post thread.
bool UpdateLayerConfig();
@@ -463,6 +464,9 @@
// The timestamp of the last vsync.
int64_t last_vsync_timestamp_ = 0;
+ // The number of vsync intervals to predict since the last vsync.
+ int vsync_prediction_interval_ = 1;
+
// Vsync count since display on.
uint32_t vsync_count_ = 0;
diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp
index fcf94f0..85dc586 100644
--- a/libs/vr/libvrflinger/vr_flinger.cpp
+++ b/libs/vr/libvrflinger/vr_flinger.cpp
@@ -64,9 +64,6 @@
ALOGI("Starting up VrFlinger...");
- setpriority(PRIO_PROCESS, 0, android::PRIORITY_URGENT_DISPLAY);
- set_sched_policy(0, SP_FOREGROUND);
-
// We need to be able to create endpoints with full perms.
umask(0000);
@@ -100,6 +97,9 @@
prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("VrDispatch"), 0, 0, 0);
ALOGI("Entering message loop.");
+ setpriority(PRIO_PROCESS, 0, android::PRIORITY_URGENT_DISPLAY);
+ set_sched_policy(0, SP_FOREGROUND);
+
int ret = dispatcher_->EnterDispatchLoop();
if (ret < 0) {
ALOGE("Dispatch loop exited because: %s\n", strerror(-ret));
diff --git a/libs/vr/libvrflinger/vsync_service.cpp b/libs/vr/libvrflinger/vsync_service.cpp
index 3098b43..fdeb899 100644
--- a/libs/vr/libvrflinger/vsync_service.cpp
+++ b/libs/vr/libvrflinger/vsync_service.cpp
@@ -110,6 +110,7 @@
}
pdx::Status<void> VSyncService::HandleMessage(pdx::Message& message) {
+ ATRACE_NAME("VSyncService::HandleMessage");
switch (message.GetOp()) {
case VSyncProtocol::Wait::Opcode:
AddWaiter(message);
diff --git a/services/inputflinger/InputWindow.cpp b/services/inputflinger/InputWindow.cpp
index b54752b..3ae7972 100644
--- a/services/inputflinger/InputWindow.cpp
+++ b/services/inputflinger/InputWindow.cpp
@@ -49,7 +49,8 @@
|| layoutParamsType == TYPE_NAVIGATION_BAR_PANEL
|| layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY
|| layoutParamsType == TYPE_DOCK_DIVIDER
- || layoutParamsType == TYPE_ACCESSIBILITY_OVERLAY;
+ || layoutParamsType == TYPE_ACCESSIBILITY_OVERLAY
+ || layoutParamsType == TYPE_INPUT_CONSUMER;
}
bool InputWindowInfo::supportsSplitTouch() const {
diff --git a/services/inputflinger/InputWindow.h b/services/inputflinger/InputWindow.h
index 610290b..9eb2798 100644
--- a/services/inputflinger/InputWindow.h
+++ b/services/inputflinger/InputWindow.h
@@ -101,6 +101,7 @@
TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19,
TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20,
TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21,
+ TYPE_INPUT_CONSUMER = FIRST_SYSTEM_WINDOW+22,
TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24,
TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27,
TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32,
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 9435a18..fd30e16 100755
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2625,8 +2625,8 @@
return true;
}
-bool Layer::reparentChild(const sp<IBinder>& newParentHandle, const sp<IBinder>& childHandle) {
- if (newParentHandle == nullptr || childHandle == nullptr) {
+bool Layer::reparent(const sp<IBinder>& newParentHandle) {
+ if (newParentHandle == nullptr) {
return false;
}
@@ -2637,29 +2637,19 @@
return false;
}
- handle = static_cast<Handle*>(childHandle.get());
- sp<Layer> child = handle->owner.promote();
- if (child == nullptr) {
- ALOGE("Unable to promote child Layer handle");
- return false;
+ sp<Layer> parent = getParent();
+ if (parent != nullptr) {
+ parent->removeChild(this);
}
+ newParent->addChild(this);
- if (mCurrentChildren.indexOf(child) < 0) {
- ALOGE("Child layer is not child of current layer");
- return false;
- }
-
- sp<Client> parentClient(mClientRef.promote());
- sp<Client> childClient(child->mClientRef.promote());
+ sp<Client> client(mClientRef.promote());
sp<Client> newParentClient(newParent->mClientRef.promote());
- if (parentClient != childClient || childClient != newParentClient) {
- ALOGE("Current layer, child layer, and new parent layer must have the same client");
- return false;
+ if (client != newParentClient) {
+ client->setParentLayer(newParent);
}
- newParent->addChild(child);
- mCurrentChildren.remove(child);
return true;
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index f94833b..e7ece45 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -241,7 +241,7 @@
bool setOverrideScalingMode(int32_t overrideScalingMode);
void setInfo(uint32_t type, uint32_t appId);
bool reparentChildren(const sp<IBinder>& layer);
- bool reparentChild(const sp<IBinder>& newParentHandle, const sp<IBinder>& childHandle);
+ bool reparent(const sp<IBinder>& newParentHandle);
bool detachChildren();
// If we have received a new buffer this frame, we will pass its surface
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index eb574eb..e21379c 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3121,10 +3121,8 @@
// We don't trigger a traversal here because if no other state is
// changed, we don't want this to cause any more work
}
- // Always re-parent the children that explicitly requested to get
- // re-parented before the general re-parent of all children.
- if (what & layer_state_t::eReparentChild) {
- if (layer->reparentChild(s.parentHandleForChild, s.childHandle)) {
+ if (what & layer_state_t::eReparent) {
+ if (layer->reparent(s.parentHandleForChild)) {
flags |= eTransactionNeeded|eTraversalNeeded;
}
}
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 71aa52d..b1c8c0a 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -179,6 +179,8 @@
maxFrameBufferAcquiredBuffers = getInt64< ISurfaceFlingerConfigs,
&ISurfaceFlingerConfigs::maxFrameBufferAcquiredBuffers>(2);
+ mPrimaryDispSync.init(hasSyncFramework, dispSyncPresentTimeOffset);
+
char value[PROPERTY_VALUE_MAX];
property_get("ro.bq.gpu_to_cpu_unsupported", value, "0");
@@ -2679,10 +2681,8 @@
// We don't trigger a traversal here because if no other state is
// changed, we don't want this to cause any more work
}
- // Always re-parent the children that explicitly requested to get
- // re-parented before the general re-parent of all children.
- if (what & layer_state_t::eReparentChild) {
- if (layer->reparentChild(s.parentHandleForChild, s.childHandle)) {
+ if (what & layer_state_t::eReparent) {
+ if (layer->reparent(s.parentHandleForChild)) {
flags |= eTransactionNeeded|eTraversalNeeded;
}
}
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index dea6503..2119492 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -1169,7 +1169,7 @@
fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0);
}
-TEST_F(ChildLayerTest, ReparentChild) {
+TEST_F(ChildLayerTest, Reparent) {
SurfaceComposerClient::openGlobalTransaction();
mChild->show();
mChild->setPosition(10, 10);
@@ -1185,7 +1185,7 @@
// And 10 more pixels we should be back to the foreground surface
mCapture->expectFGColor(84, 84);
}
- mFGSurfaceControl->reparentChild(mBGSurfaceControl->getHandle(), mChild->getHandle());
+ mChild->reparent(mBGSurfaceControl->getHandle());
{
ScreenCapture::captureScreen(&mCapture);
mCapture->expectFGColor(64, 64);
@@ -1198,6 +1198,69 @@
}
}
+TEST_F(ChildLayerTest, ReparentToNoParent) {
+ SurfaceComposerClient::openGlobalTransaction();
+ mChild->show();
+ mChild->setPosition(10, 10);
+ mFGSurfaceControl->setPosition(64, 64);
+ SurfaceComposerClient::closeGlobalTransaction(true);
+
+ {
+ ScreenCapture::captureScreen(&mCapture);
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // But 10 pixels in we should see the child surface
+ mCapture->expectChildColor(74, 74);
+ // And 10 more pixels we should be back to the foreground surface
+ mCapture->expectFGColor(84, 84);
+ }
+ mChild->reparent(nullptr);
+ {
+ ScreenCapture::captureScreen(&mCapture);
+ // Nothing should have changed.
+ mCapture->expectFGColor(64, 64);
+ mCapture->expectChildColor(74, 74);
+ mCapture->expectFGColor(84, 84);
+ }
+}
+
+TEST_F(ChildLayerTest, ReparentFromNoParent) {
+ sp<SurfaceControl> newSurface = mComposerClient->createSurface(
+ String8("New Surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, 0);
+ ASSERT_TRUE(newSurface != NULL);
+ ASSERT_TRUE(newSurface->isValid());
+
+ fillSurfaceRGBA8(newSurface, 63, 195, 63);
+ SurfaceComposerClient::openGlobalTransaction();
+ mChild->hide();
+ newSurface->show();
+ newSurface->setPosition(10, 10);
+ newSurface->setLayer(INT32_MAX-2);
+ mFGSurfaceControl->setPosition(64, 64);
+ SurfaceComposerClient::closeGlobalTransaction(true);
+
+ {
+ ScreenCapture::captureScreen(&mCapture);
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // At 10, 10 we should see the new surface
+ mCapture->checkPixel(10, 10, 63, 195, 63);
+ }
+
+ SurfaceComposerClient::openGlobalTransaction();
+ newSurface->reparent(mFGSurfaceControl->getHandle());
+ SurfaceComposerClient::closeGlobalTransaction(true);
+
+ {
+ ScreenCapture::captureScreen(&mCapture);
+ // newSurface will now be a child of mFGSurface so it will be 10, 10 offset from
+ // mFGSurface, putting it at 74, 74.
+ mCapture->expectFGColor(64, 64);
+ mCapture->checkPixel(74, 74, 63, 195, 63);
+ mCapture->expectFGColor(84, 84);
+ }
+}
+
TEST_F(ChildLayerTest, NestedChildren) {
sp<SurfaceControl> grandchild = mComposerClient->createSurface(
String8("Grandchild surface"),