Merge "Mark libui as vendor_available" into oc-dev
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 6cfbed9..d3e0cd4 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -31,6 +31,7 @@
#include <unistd.h>
#include <zlib.h>
+#include <fstream>
#include <memory>
#include <binder/IBinder.h>
@@ -436,56 +437,31 @@
return writeStr(k_traceBufferSizePath, str);
}
-// Read the trace_clock sysfs file and return true if it matches the requested
-// value. The trace_clock file format is:
-// local [global] counter uptime perf
-static bool isTraceClock(const char *mode)
-{
- int fd = open((g_traceFolder + k_traceClockPath).c_str(), O_RDONLY);
- if (fd == -1) {
- fprintf(stderr, "error opening %s: %s (%d)\n", k_traceClockPath,
- strerror(errno), errno);
- return false;
- }
-
- char buf[4097];
- ssize_t n = read(fd, buf, 4096);
- close(fd);
- if (n == -1) {
- fprintf(stderr, "error reading %s: %s (%d)\n", k_traceClockPath,
- strerror(errno), errno);
- return false;
- }
- buf[n] = '\0';
-
- char *start = strchr(buf, '[');
- if (start == NULL) {
- return false;
- }
- start++;
-
- char *end = strchr(start, ']');
- if (end == NULL) {
- return false;
- }
- *end = '\0';
-
- return strcmp(mode, start) == 0;
-}
-
-// Enable or disable the kernel's use of the global clock. Disabling the global
-// clock will result in the kernel using a per-CPU local clock.
+// Set the clock to the best available option while tracing. Use 'boot' if it's
+// available; otherwise, use 'mono'. If neither are available use 'global'.
// Any write to the trace_clock sysfs file will reset the buffer, so only
// update it if the requested value is not the current value.
-static bool setGlobalClockEnable(bool enable)
+static bool setClock()
{
- const char *clock = enable ? "global" : "local";
+ std::ifstream clockFile((g_traceFolder + k_traceClockPath).c_str(), O_RDONLY);
+ std::string clockStr((std::istreambuf_iterator<char>(clockFile)),
+ std::istreambuf_iterator<char>());
- if (isTraceClock(clock)) {
- return true;
+ std::string newClock;
+ if (clockStr.find("boot") != std::string::npos) {
+ newClock = "boot";
+ } else if (clockStr.find("mono") != std::string::npos) {
+ newClock = "mono";
+ } else {
+ newClock = "global";
}
- return writeStr(k_traceClockPath, clock);
+ size_t begin = clockStr.find("[") + 1;
+ size_t end = clockStr.find("]");
+ if (newClock.compare(0, std::string::npos, clockStr, begin, end-begin) == 0) {
+ return true;
+ }
+ return writeStr(k_traceClockPath, newClock.c_str());
}
static bool setPrintTgidEnableIfPresent(bool enable)
@@ -781,7 +757,7 @@
ok &= setCategoriesEnableFromFile(g_categoriesFile);
ok &= setTraceOverwriteEnable(g_traceOverwrite);
ok &= setTraceBufferSizeKB(g_traceBufferSizeKB);
- ok &= setGlobalClockEnable(true);
+ ok &= setClock();
ok &= setPrintTgidEnableIfPresent(true);
ok &= setKernelTraceFuncs(g_kernelTraceFuncs);
@@ -855,7 +831,6 @@
// Set the options back to their defaults.
setTraceOverwriteEnable(true);
setTraceBufferSizeKB(1);
- setGlobalClockEnable(false);
setPrintTgidEnableIfPresent(false);
setKernelTraceFuncs(NULL);
}
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index a0d987d..509dd92 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -78,6 +78,7 @@
static constexpr const char* CACHE_DIR_POSTFIX = "/cache";
static constexpr const char* CODE_CACHE_DIR_POSTFIX = "/code_cache";
+static constexpr const char *kIdMapPath = "/system/bin/idmap";
static constexpr const char* IDMAP_PREFIX = "/data/resource-cache/";
static constexpr const char* IDMAP_SUFFIX = "@idmap";
@@ -1941,14 +1942,58 @@
static void run_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd)
{
- static const char *IDMAP_BIN = "/system/bin/idmap";
- static const size_t MAX_INT_LEN = 32;
- char idmap_str[MAX_INT_LEN];
+ execl(kIdMapPath, kIdMapPath, "--fd", target_apk, overlay_apk,
+ StringPrintf("%d", idmap_fd).c_str(), (char*)NULL);
+ PLOG(ERROR) << "execl (" << kIdMapPath << ") failed";
+}
- snprintf(idmap_str, sizeof(idmap_str), "%d", idmap_fd);
+static void run_verify_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd)
+{
+ execl(kIdMapPath, kIdMapPath, "--verify", target_apk, overlay_apk,
+ StringPrintf("%d", idmap_fd).c_str(), (char*)NULL);
+ PLOG(ERROR) << "execl (" << kIdMapPath << ") failed";
+}
- execl(IDMAP_BIN, IDMAP_BIN, "--fd", target_apk, overlay_apk, idmap_str, (char*)NULL);
- ALOGE("execl(%s) failed: %s\n", IDMAP_BIN, strerror(errno));
+static bool delete_stale_idmap(const char* target_apk, const char* overlay_apk,
+ const char* idmap_path, int32_t uid) {
+ int idmap_fd = open(idmap_path, O_RDWR);
+ if (idmap_fd < 0) {
+ PLOG(ERROR) << "idmap open failed: " << idmap_path;
+ unlink(idmap_path);
+ return true;
+ }
+
+ pid_t pid;
+ pid = fork();
+ if (pid == 0) {
+ /* child -- drop privileges before continuing */
+ if (setgid(uid) != 0) {
+ LOG(ERROR) << "setgid(" << uid << ") failed during idmap";
+ exit(1);
+ }
+ if (setuid(uid) != 0) {
+ LOG(ERROR) << "setuid(" << uid << ") failed during idmap";
+ exit(1);
+ }
+ if (flock(idmap_fd, LOCK_EX | LOCK_NB) != 0) {
+ PLOG(ERROR) << "flock(" << idmap_path << ") failed during idmap";
+ exit(1);
+ }
+
+ run_verify_idmap(target_apk, overlay_apk, idmap_fd);
+ exit(1); /* only if exec call to deleting stale idmap failed */
+ } else {
+ int status = wait_child(pid);
+ close(idmap_fd);
+
+ if (status != 0) {
+ // Failed on verifying if idmap is made from target_apk and overlay_apk.
+ LOG(DEBUG) << "delete stale idmap: " << idmap_path;
+ unlink(idmap_path);
+ return true;
+ }
+ }
+ return false;
}
// Transform string /a/b/c.apk to (prefix)/a@b@c.apk@(suffix)
@@ -1997,7 +2042,7 @@
int idmap_fd = -1;
char idmap_path[PATH_MAX];
- struct stat target_apk_stat, overlay_apk_stat, idmap_stat;
+ struct stat idmap_stat;
bool outdated = false;
if (flatten_path(IDMAP_PREFIX, IDMAP_SUFFIX, overlay_apk,
@@ -2006,17 +2051,13 @@
goto fail;
}
- if (stat(idmap_path, &idmap_stat) < 0 ||
- stat(target_apk, &target_apk_stat) < 0 ||
- stat(overlay_apk, &overlay_apk_stat) < 0) {
+ if (stat(idmap_path, &idmap_stat) < 0) {
outdated = true;
- } else if (idmap_stat.st_mtime < target_apk_stat.st_mtime ||
- idmap_stat.st_mtime < overlay_apk_stat.st_mtime) {
- outdated = true;
+ } else {
+ outdated = delete_stale_idmap(target_apk, overlay_apk, idmap_path, uid);
}
if (outdated) {
- unlink(idmap_path);
idmap_fd = open(idmap_path, O_RDWR | O_CREAT | O_EXCL, 0644);
} else {
idmap_fd = open(idmap_path, O_RDWR);
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 3bbe3a1..b20a807 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -1703,10 +1703,20 @@
result = false;
continue;
}
+
+ // Delete oat/vdex/art files.
result = unlink_if_exists(oat_path) && result;
result = unlink_if_exists(create_vdex_filename(oat_path)) && result;
result = unlink_if_exists(create_image_filename(oat_path)) && result;
+ // Delete profiles.
+ std::string current_profile = create_current_profile_path(
+ multiuser_get_user_id(uid), dex_path, /*is_secondary*/true);
+ std::string reference_profile = create_reference_profile_path(
+ dex_path, /*is_secondary*/true);
+ result = unlink_if_exists(current_profile) && result;
+ result = unlink_if_exists(reference_profile) && result;
+
// Try removing the directories as well, they might be empty.
result = rmdir_if_empty(oat_isa_dir) && result;
result = rmdir_if_empty(oat_dir) && result;
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 43d0780..68cb0d7 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -64,6 +64,25 @@
namespace android {
namespace installd {
+// Check expected values for dexopt flags. If you need to change this:
+//
+// RUN AN A/B OTA TO MAKE SURE THINGS STILL WORK!
+//
+// You most likely need to increase the protocol version and all that entails!
+
+static_assert(DEXOPT_PUBLIC == 1 << 1, "DEXOPT_PUBLIC unexpected.");
+static_assert(DEXOPT_DEBUGGABLE == 1 << 2, "DEXOPT_DEBUGGABLE unexpected.");
+static_assert(DEXOPT_BOOTCOMPLETE == 1 << 3, "DEXOPT_BOOTCOMPLETE unexpected.");
+static_assert(DEXOPT_PROFILE_GUIDED == 1 << 4, "DEXOPT_PROFILE_GUIDED unexpected.");
+static_assert(DEXOPT_SECONDARY_DEX == 1 << 5, "DEXOPT_SECONDARY_DEX unexpected.");
+static_assert(DEXOPT_FORCE == 1 << 6, "DEXOPT_FORCE unexpected.");
+static_assert(DEXOPT_STORAGE_CE == 1 << 7, "DEXOPT_STORAGE_CE unexpected.");
+static_assert(DEXOPT_STORAGE_DE == 1 << 8, "DEXOPT_STORAGE_DE unexpected.");
+
+static_assert(DEXOPT_MASK == 0x1fe, "DEXOPT_MASK unexpected.");
+
+
+
template<typename T>
static constexpr T RoundDown(T x, typename std::decay<T>::type n) {
return DCHECK_CONSTEXPR(IsPowerOfTwo(n), , T(0))(x & -n);
diff --git a/cmds/lshal/Android.bp b/cmds/lshal/Android.bp
index 4740202..38647eb 100644
--- a/cmds/lshal/Android.bp
+++ b/cmds/lshal/Android.bp
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-cc_binary {
- name: "lshal",
+cc_library_shared {
+ name: "liblshal",
shared_libs: [
"libbase",
"libcutils",
@@ -25,7 +25,44 @@
"android.hidl.manager@1.0",
],
srcs: [
+ "DebugCommand.cpp",
"Lshal.cpp",
- "PipeRelay.cpp"
+ "ListCommand.cpp",
+ "PipeRelay.cpp",
+ "utils.cpp",
],
}
+
+cc_defaults {
+ name: "lshal_defaults",
+ shared_libs: [
+ "libbase",
+ "libhidlbase",
+ "libhidltransport",
+ "liblshal",
+ "libutils",
+ ]
+}
+
+cc_binary {
+ name: "lshal",
+ defaults: ["lshal_defaults"],
+ srcs: [
+ "main.cpp"
+ ]
+}
+
+cc_test {
+ name: "lshal_test",
+ defaults: ["lshal_defaults"],
+ gtest: true,
+ static_libs: [
+ "libgmock"
+ ],
+ shared_libs: [
+ "android.hardware.tests.baz@1.0"
+ ],
+ srcs: [
+ "test.cpp"
+ ]
+}
diff --git a/cmds/lshal/DebugCommand.cpp b/cmds/lshal/DebugCommand.cpp
new file mode 100644
index 0000000..672cad6
--- /dev/null
+++ b/cmds/lshal/DebugCommand.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#include "DebugCommand.h"
+
+#include "Lshal.h"
+
+namespace android {
+namespace lshal {
+
+DebugCommand::DebugCommand(Lshal &lshal) : mLshal(lshal) {
+}
+
+Status DebugCommand::parseArgs(const std::string &command, const Arg &arg) {
+ if (optind >= arg.argc) {
+ mLshal.usage(command);
+ return USAGE;
+ }
+ mInterfaceName = arg.argv[optind];
+ ++optind;
+ for (; optind < arg.argc; ++optind) {
+ mOptions.push_back(arg.argv[optind]);
+ }
+ return OK;
+}
+
+Status DebugCommand::main(const std::string &command, const Arg &arg) {
+ Status status = parseArgs(command, arg);
+ if (status != OK) {
+ return status;
+ }
+ auto pair = splitFirst(mInterfaceName, '/');
+ return mLshal.emitDebugInfo(
+ pair.first, pair.second.empty() ? "default" : pair.second, mOptions,
+ mLshal.out().buf(),
+ mLshal.err());
+}
+
+} // namespace lshal
+} // namespace android
+
diff --git a/cmds/lshal/DebugCommand.h b/cmds/lshal/DebugCommand.h
new file mode 100644
index 0000000..fa0f0fa
--- /dev/null
+++ b/cmds/lshal/DebugCommand.h
@@ -0,0 +1,49 @@
+/*
+ * 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 FRAMEWORK_NATIVE_CMDS_LSHAL_DEBUG_COMMAND_H_
+#define FRAMEWORK_NATIVE_CMDS_LSHAL_DEBUG_COMMAND_H_
+
+#include <string>
+
+#include <android-base/macros.h>
+
+#include "utils.h"
+
+namespace android {
+namespace lshal {
+
+class Lshal;
+
+class DebugCommand {
+public:
+ DebugCommand(Lshal &lshal);
+ Status main(const std::string &command, const Arg &arg);
+private:
+ Status parseArgs(const std::string &command, const Arg &arg);
+
+ Lshal &mLshal;
+ std::string mInterfaceName;
+ std::vector<std::string> mOptions;
+
+ DISALLOW_COPY_AND_ASSIGN(DebugCommand);
+};
+
+
+} // namespace lshal
+} // namespace android
+
+#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_DEBUG_COMMAND_H_
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
new file mode 100644
index 0000000..710b6e4
--- /dev/null
+++ b/cmds/lshal/ListCommand.cpp
@@ -0,0 +1,705 @@
+/*
+ * 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.
+ */
+
+#include "ListCommand.h"
+
+#include <getopt.h>
+
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <map>
+#include <sstream>
+#include <regex>
+
+#include <android-base/parseint.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <hidl-util/FQName.h>
+#include <private/android_filesystem_config.h>
+#include <sys/stat.h>
+#include <vintf/HalManifest.h>
+#include <vintf/parse_xml.h>
+
+#include "Lshal.h"
+#include "PipeRelay.h"
+#include "Timeout.h"
+#include "utils.h"
+
+using ::android::hardware::hidl_string;
+using ::android::hidl::manager::V1_0::IServiceManager;
+
+namespace android {
+namespace lshal {
+
+ListCommand::ListCommand(Lshal &lshal) : mLshal(lshal), mErr(lshal.err()), mOut(lshal.out()) {
+}
+
+std::string getCmdline(pid_t pid) {
+ std::ifstream ifs("/proc/" + std::to_string(pid) + "/cmdline");
+ std::string cmdline;
+ if (!ifs.is_open()) {
+ return "";
+ }
+ ifs >> cmdline;
+ return cmdline;
+}
+
+const std::string &ListCommand::getCmdline(pid_t pid) {
+ auto pair = mCmdlines.find(pid);
+ if (pair != mCmdlines.end()) {
+ return pair->second;
+ }
+ mCmdlines[pid] = ::android::lshal::getCmdline(pid);
+ return mCmdlines[pid];
+}
+
+void ListCommand::removeDeadProcesses(Pids *pids) {
+ static const pid_t myPid = getpid();
+ pids->erase(std::remove_if(pids->begin(), pids->end(), [this](auto pid) {
+ return pid == myPid || this->getCmdline(pid).empty();
+ }), pids->end());
+}
+
+bool ListCommand::getReferencedPids(
+ pid_t serverPid, std::map<uint64_t, Pids> *objects) const {
+
+ std::ifstream ifs("/d/binder/proc/" + std::to_string(serverPid));
+ if (!ifs.is_open()) {
+ return false;
+ }
+
+ static const std::regex prefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+");
+
+ std::string line;
+ std::smatch match;
+ while(getline(ifs, line)) {
+ if (!std::regex_search(line, match, prefix)) {
+ // the line doesn't start with the correct prefix
+ continue;
+ }
+ std::string ptrString = "0x" + match.str(2); // use number after c
+ uint64_t ptr;
+ if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
+ // Should not reach here, but just be tolerant.
+ mErr << "Could not parse number " << ptrString << std::endl;
+ continue;
+ }
+ const std::string proc = " proc ";
+ auto pos = line.rfind(proc);
+ if (pos != std::string::npos) {
+ for (const std::string &pidStr : split(line.substr(pos + proc.size()), ' ')) {
+ int32_t pid;
+ if (!::android::base::ParseInt(pidStr, &pid)) {
+ mErr << "Could not parse number " << pidStr << std::endl;
+ continue;
+ }
+ (*objects)[ptr].push_back(pid);
+ }
+ }
+ }
+ return true;
+}
+
+// Must process hwbinder services first, then passthrough services.
+void ListCommand::forEachTable(const std::function<void(Table &)> &f) {
+ f(mServicesTable);
+ f(mPassthroughRefTable);
+ f(mImplementationsTable);
+}
+void ListCommand::forEachTable(const std::function<void(const Table &)> &f) const {
+ f(mServicesTable);
+ f(mPassthroughRefTable);
+ f(mImplementationsTable);
+}
+
+void ListCommand::postprocess() {
+ 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));
+ }
+ }
+ });
+ // use a double for loop here because lshal doesn't care about efficiency.
+ for (TableEntry &packageEntry : mImplementationsTable) {
+ std::string packageName = packageEntry.interfaceName;
+ FQName fqPackageName{packageName.substr(0, packageName.find("::"))};
+ if (!fqPackageName.isValid()) {
+ continue;
+ }
+ for (TableEntry &interfaceEntry : mPassthroughRefTable) {
+ if (interfaceEntry.arch != ARCH_UNKNOWN) {
+ continue;
+ }
+ FQName interfaceName{splitFirst(interfaceEntry.interfaceName, '/').first};
+ if (!interfaceName.isValid()) {
+ continue;
+ }
+ if (interfaceName.getPackageAndVersion() == fqPackageName) {
+ interfaceEntry.arch = packageEntry.arch;
+ }
+ }
+ }
+}
+
+void ListCommand::printLine(
+ const std::string &interfaceName,
+ 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 {
+ if (mSelectedColumns & ENABLE_INTERFACE_NAME)
+ 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";
+ } else {
+ mOut << std::setw(5) << server << "\t";
+ }
+ }
+ if (mSelectedColumns & ENABLE_SERVER_ADDR)
+ mOut << std::setw(16) << address << "\t";
+ if (mSelectedColumns & ENABLE_CLIENT_PIDS) {
+ if (mEnableCmdlines) {
+ mOut << std::setw(0) << clientCmdlines;
+ } else {
+ mOut << std::setw(0) << clients;
+ }
+ }
+ mOut << std::endl;
+}
+
+void ListCommand::dumpVintf() const {
+ mOut << "<!-- " << std::endl
+ << " This is a skeleton device manifest. Notes: " << std::endl
+ << " 1. android.hidl.*, android.frameworks.*, android.system.* are not included." << std::endl
+ << " 2. If a HAL is supported in both hwbinder and passthrough transport, " << std::endl
+ << " only hwbinder is shown." << std::endl
+ << " 3. It is likely that HALs in passthrough transport does not have" << std::endl
+ << " <interface> declared; users will have to write them by hand." << std::endl
+ << " 4. sepolicy version is set to 0.0. It is recommended that the entry" << std::endl
+ << " is removed from the manifest file and written by assemble_vintf" << std::endl
+ << " at build time." << std::endl
+ << "-->" << std::endl;
+
+ vintf::HalManifest manifest;
+ forEachTable([this, &manifest] (const Table &table) {
+ for (const TableEntry &entry : table) {
+
+ std::string fqInstanceName = entry.interfaceName;
+
+ 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;
+ }
+ // Strip out system libs.
+ if (fqName.inPackage("android.hidl") ||
+ fqName.inPackage("android.frameworks") ||
+ fqName.inPackage("android.system")) {
+ continue;
+ }
+ std::string interfaceName =
+ &table == &mImplementationsTable ? "" : fqName.name();
+ std::string instanceName =
+ &table == &mImplementationsTable ? "" : splittedFqInstanceName.second;
+
+ vintf::Version version{fqName.getPackageMajorVersion(),
+ fqName.getPackageMinorVersion()};
+ vintf::Transport transport;
+ vintf::Arch arch;
+ if (entry.transport == "hwbinder") {
+ transport = vintf::Transport::HWBINDER;
+ arch = vintf::Arch::ARCH_EMPTY;
+ } else if (entry.transport == "passthrough") {
+ transport = vintf::Transport::PASSTHROUGH;
+ switch (entry.arch) {
+ case lshal::ARCH32:
+ arch = vintf::Arch::ARCH_32; break;
+ case lshal::ARCH64:
+ arch = vintf::Arch::ARCH_64; break;
+ case lshal::ARCH_BOTH:
+ arch = vintf::Arch::ARCH_32_64; break;
+ case lshal::ARCH_UNKNOWN: // fallthrough
+ default:
+ mErr << "Warning: '" << fqName.package()
+ << "' doesn't have bitness info, assuming 32+64." << std::endl;
+ arch = vintf::Arch::ARCH_32_64;
+ }
+ } else {
+ mErr << "Warning: '" << entry.transport << "' is not a valid transport." << std::endl;
+ continue;
+ }
+
+ bool done = false;
+ for (vintf::ManifestHal *hal : manifest.getHals(fqName.package())) {
+ if (hal->transport() != transport) {
+ if (transport != vintf::Transport::PASSTHROUGH) {
+ mErr << "Fatal: should not reach here. Generated result may be wrong."
+ << std::endl;
+ }
+ done = true;
+ break;
+ }
+ if (hal->hasVersion(version)) {
+ if (&table != &mImplementationsTable) {
+ hal->interfaces[interfaceName].name = interfaceName;
+ hal->interfaces[interfaceName].instances.insert(instanceName);
+ }
+ done = true;
+ break;
+ }
+ }
+ if (done) {
+ continue; // to next TableEntry
+ }
+ decltype(vintf::ManifestHal::interfaces) interfaces;
+ if (&table != &mImplementationsTable) {
+ interfaces[interfaceName].name = interfaceName;
+ interfaces[interfaceName].instances.insert(instanceName);
+ }
+ if (!manifest.add(vintf::ManifestHal{
+ .format = vintf::HalFormat::HIDL,
+ .name = fqName.package(),
+ .versions = {version},
+ .transportArch = {transport, arch},
+ .interfaces = interfaces})) {
+ mErr << "Warning: cannot add hal '" << fqInstanceName << "'" << std::endl;
+ }
+ }
+ });
+ mOut << vintf::gHalManifestConverter(manifest);
+}
+
+static const std::string &getArchString(Architecture arch) {
+ static const std::string sStr64 = "64";
+ static const std::string sStr32 = "32";
+ static const std::string sStrBoth = "32+64";
+ static const std::string sStrUnknown = "";
+ switch (arch) {
+ case ARCH64:
+ return sStr64;
+ case ARCH32:
+ return sStr32;
+ case ARCH_BOTH:
+ return sStrBoth;
+ case ARCH_UNKNOWN: // fall through
+ default:
+ return sStrUnknown;
+ }
+}
+
+static Architecture fromBaseArchitecture(::android::hidl::base::V1_0::DebugInfo::Architecture a) {
+ switch (a) {
+ case ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_64BIT:
+ return ARCH64;
+ case ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_32BIT:
+ return ARCH32;
+ case ::android::hidl::base::V1_0::DebugInfo::Architecture::UNKNOWN: // fallthrough
+ default:
+ return ARCH_UNKNOWN;
+ }
+}
+
+void ListCommand::dumpTable() {
+ mServicesTable.description =
+ "All binderized services (registered services through hwservicemanager)";
+ mPassthroughRefTable.description =
+ "All interfaces that getService() has ever return as a passthrough interface;\n"
+ "PIDs / processes shown below might be inaccurate because the process\n"
+ "might have relinquished the interface or might have died.\n"
+ "The Server / Server CMD column can be ignored.\n"
+ "The Clients / Clients CMD column shows all process that have ever dlopen'ed \n"
+ "the library and successfully fetched the passthrough implementation.";
+ mImplementationsTable.description =
+ "All available passthrough implementations (all -impl.so files)";
+ forEachTable([this] (const Table &table) {
+ mOut << table.description << std::endl;
+ mOut << std::left;
+ printLine("Interface", "Transport", "Arch", "Server", "Server CMD",
+ "PTR", "Clients", "Clients CMD");
+
+ for (const auto &entry : table) {
+ printLine(entry.interfaceName,
+ entry.transport,
+ getArchString(entry.arch),
+ entry.serverPid == NO_PID ? "N/A" : std::to_string(entry.serverPid),
+ entry.serverCmdline,
+ entry.serverObjectAddress == NO_PTR ? "N/A" : toHexString(entry.serverObjectAddress),
+ join(entry.clientPids, " "),
+ join(entry.clientCmdlines, ";"));
+
+ // We're only interested in dumping debug info for already
+ // instantiated services. There's little value in dumping the
+ // debug info for a service we create on the fly, so we only operate
+ // on the "mServicesTable".
+ if (mEmitDebugInfo && &table == &mServicesTable) {
+ auto pair = splitFirst(entry.interfaceName, '/');
+ mLshal.emitDebugInfo(pair.first, pair.second, {}, mOut.buf(),
+ NullableOStream<std::ostream>(nullptr));
+ }
+ }
+ mOut << std::endl;
+ });
+
+}
+
+void ListCommand::dump() {
+ if (mVintf) {
+ dumpVintf();
+ if (!!mFileOutput) {
+ mFileOutput.buf().close();
+ delete &mFileOutput.buf();
+ mFileOutput = nullptr;
+ }
+ mOut = std::cout;
+ } else {
+ dumpTable();
+ }
+}
+
+void ListCommand::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 ListCommand::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::debugDump, [&] (const auto &infos) {
+ std::map<std::string, TableEntry> entries;
+ for (const auto &info : infos) {
+ std::string interfaceName = std::string{info.interfaceName.c_str()} + "/" +
+ std::string{info.instanceName.c_str()};
+ entries.emplace(interfaceName, TableEntry{
+ .interfaceName = interfaceName,
+ .transport = "passthrough",
+ .serverPid = NO_PID,
+ .serverObjectAddress = NO_PTR,
+ .clientPids = {},
+ .arch = ARCH_UNKNOWN
+ }).first->second.arch |= fromBaseArchitecture(info.arch);
+ }
+ for (auto &&pair : entries) {
+ putEntry(LIST_DLLIB, std::move(pair.second));
+ }
+ });
+ if (!ret.isOk()) {
+ mErr << "Error: Failed to call list on getPassthroughServiceManager(): "
+ << ret.description() << std::endl;
+ return DUMP_ALL_LIBS_ERROR;
+ }
+ return OK;
+}
+
+Status ListCommand::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) {
+ if (info.clientPids.size() <= 0) {
+ continue;
+ }
+ putEntry(PTSERVICEMANAGER_REG_CLIENT, {
+ .interfaceName =
+ std::string{info.interfaceName.c_str()} + "/" +
+ 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)
+ });
+ }
+ });
+ if (!ret.isOk()) {
+ mErr << "Error: Failed to call debugDump on defaultServiceManager(): "
+ << ret.description() << std::endl;
+ return DUMP_PASSTHROUGH_ERROR;
+ }
+ return OK;
+}
+
+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;
+ // copying out for timeoutIPC
+ auto listRet = timeoutIPC(manager, &IServiceManager::list, [&] (const auto &names) {
+ fqInstanceNames = names;
+ });
+ if (!listRet.isOk()) {
+ mErr << "Error: Failed to list services for " << mode << ": "
+ << listRet.description() << std::endl;
+ return DUMP_BINDERIZED_ERROR;
+ }
+
+ Status status = OK;
+ // server pid, .ptr value of binder object, child pids
+ std::map<std::string, DebugInfo> allDebugInfos;
+ std::map<pid_t, std::map<uint64_t, Pids>> allPids;
+ 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()) {
+ mErr << "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) {
+ mErr << "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)].clear();
+ }
+ });
+ if (!debugRet.isOk()) {
+ mErr << "Warning: Skipping \"" << fqInstanceName << "\": "
+ << "debugging information cannot be retrieved:"
+ << debugRet.description() << std::endl;
+ status |= DUMP_BINDERIZED_ERROR;
+ }
+ }
+ for (auto &pair : allPids) {
+ pid_t serverPid = pair.first;
+ if (!getReferencedPids(serverPid, &allPids[serverPid])) {
+ mErr << "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 = {},
+ .arch = ARCH_UNKNOWN
+ });
+ continue;
+ }
+ const DebugInfo &info = it->second;
+ 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],
+ .arch = fromBaseArchitecture(info.arch),
+ });
+ }
+ return status;
+}
+
+Status ListCommand::fetch() {
+ Status status = OK;
+ auto bManager = mLshal.serviceManager();
+ if (bManager == nullptr) {
+ mErr << "Failed to get defaultServiceManager()!" << std::endl;
+ status |= NO_BINDERIZED_MANAGER;
+ } else {
+ status |= fetchBinderized(bManager);
+ // Passthrough PIDs are registered to the binderized manager as well.
+ status |= fetchPassthrough(bManager);
+ }
+
+ auto pManager = mLshal.passthroughManager();
+ if (pManager == nullptr) {
+ mErr << "Failed to get getPassthroughServiceManager()!" << std::endl;
+ status |= NO_PASSTHROUGH_MANAGER;
+ } else {
+ status |= fetchAllLibraries(pManager);
+ }
+ return status;
+}
+
+Status ListCommand::parseArgs(const std::string &command, const Arg &arg) {
+ static struct option longOptions[] = {
+ // long options with short alternatives
+ {"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' },
+ {"cmdline", no_argument, 0, 'm' },
+ {"debug", optional_argument, 0, 'd' },
+
+ // long options without short alternatives
+ {"sort", required_argument, 0, 's' },
+ {"init-vintf",optional_argument, 0, 'v' },
+ { 0, 0, 0, 0 }
+ };
+
+ int optionIndex;
+ int c;
+ // Lshal::parseArgs has set optind to the next option to parse
+ for (;;) {
+ // using getopt_long in case we want to add other options in the future
+ c = getopt_long(arg.argc, arg.argv,
+ "hitrpacmd", longOptions, &optionIndex);
+ if (c == -1) {
+ break;
+ }
+ switch (c) {
+ case 's': {
+ if (strcmp(optarg, "interface") == 0 || strcmp(optarg, "i") == 0) {
+ mSortColumn = TableEntry::sortByInterfaceName;
+ } else if (strcmp(optarg, "pid") == 0 || strcmp(optarg, "p") == 0) {
+ mSortColumn = TableEntry::sortByServerPid;
+ } else {
+ mErr << "Unrecognized sorting column: " << optarg << std::endl;
+ mLshal.usage(command);
+ return USAGE;
+ }
+ break;
+ }
+ case 'v': {
+ if (optarg) {
+ mFileOutput = new std::ofstream{optarg};
+ mOut = mFileOutput;
+ if (!mFileOutput.buf().is_open()) {
+ mErr << "Could not open file '" << optarg << "'." << std::endl;
+ return IO_ERROR;
+ }
+ }
+ mVintf = true;
+ }
+ case 'i': {
+ mSelectedColumns |= ENABLE_INTERFACE_NAME;
+ break;
+ }
+ case 't': {
+ mSelectedColumns |= ENABLE_TRANSPORT;
+ break;
+ }
+ case 'r': {
+ mSelectedColumns |= ENABLE_ARCH;
+ break;
+ }
+ case 'p': {
+ mSelectedColumns |= ENABLE_SERVER_PID;
+ break;
+ }
+ case 'a': {
+ mSelectedColumns |= ENABLE_SERVER_ADDR;
+ break;
+ }
+ case 'c': {
+ mSelectedColumns |= ENABLE_CLIENT_PIDS;
+ break;
+ }
+ case 'm': {
+ mEnableCmdlines = true;
+ break;
+ }
+ case 'd': {
+ mEmitDebugInfo = true;
+
+ if (optarg) {
+ mFileOutput = new std::ofstream{optarg};
+ mOut = mFileOutput;
+ if (!mFileOutput.buf().is_open()) {
+ mErr << "Could not open file '" << optarg << "'." << std::endl;
+ return IO_ERROR;
+ }
+ chown(optarg, AID_SHELL, AID_SHELL);
+ }
+ break;
+ }
+ case 'h': // falls through
+ default: // see unrecognized options
+ mLshal.usage(command);
+ return USAGE;
+ }
+ }
+ if (optind < arg.argc) {
+ // see non option
+ mErr << "Unrecognized option `" << arg.argv[optind] << "`" << std::endl;
+ }
+
+ if (mSelectedColumns == 0) {
+ mSelectedColumns = ENABLE_INTERFACE_NAME | ENABLE_SERVER_PID | ENABLE_CLIENT_PIDS;
+ }
+ return OK;
+}
+
+Status ListCommand::main(const std::string &command, const Arg &arg) {
+ Status status = parseArgs(command, arg);
+ if (status != OK) {
+ return status;
+ }
+ status = fetch();
+ postprocess();
+ dump();
+ return status;
+}
+
+} // namespace lshal
+} // namespace android
+
diff --git a/cmds/lshal/ListCommand.h b/cmds/lshal/ListCommand.h
new file mode 100644
index 0000000..42c965f
--- /dev/null
+++ b/cmds/lshal/ListCommand.h
@@ -0,0 +1,101 @@
+/*
+ * 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 FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_
+#define FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_
+
+#include <stdint.h>
+
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include <android-base/macros.h>
+#include <android/hidl/manager/1.0/IServiceManager.h>
+
+#include "NullableOStream.h"
+#include "TableEntry.h"
+#include "utils.h"
+
+namespace android {
+namespace lshal {
+
+class Lshal;
+
+class ListCommand {
+public:
+ ListCommand(Lshal &lshal);
+ Status main(const std::string &command, const Arg &arg);
+private:
+ Status parseArgs(const std::string &command, const Arg &arg);
+ Status fetch();
+ void postprocess();
+ void 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);
+ bool getReferencedPids(
+ pid_t serverPid, std::map<uint64_t, Pids> *objects) const;
+ void dumpTable();
+ void dumpVintf() const;
+ void printLine(
+ const std::string &interfaceName,
+ 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 ;
+ // Return /proc/{pid}/cmdline if it exists, else empty string.
+ const std::string &getCmdline(pid_t pid);
+ // 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;
+
+ Lshal &mLshal;
+
+ Table mServicesTable{};
+ Table mPassthroughRefTable{};
+ Table mImplementationsTable{};
+
+ NullableOStream<std::ostream> mErr;
+ NullableOStream<std::ostream> mOut;
+ NullableOStream<std::ofstream> mFileOutput = nullptr;
+ TableEntryCompare mSortColumn = nullptr;
+ TableEntrySelect mSelectedColumns = 0;
+ // If true, cmdlines will be printed instead of pid.
+ bool mEnableCmdlines = false;
+
+ // If true, calls IBase::debug(...) on each service.
+ bool mEmitDebugInfo = false;
+
+ bool mVintf = false;
+ // If an entry does not exist, need to ask /proc/{pid}/cmdline to get it.
+ // If an entry exist but is an empty string, process might have died.
+ // If an entry exist and not empty, it contains the cached content of /proc/{pid}/cmdline.
+ std::map<pid_t, std::string> mCmdlines;
+
+ DISALLOW_COPY_AND_ASSIGN(ListCommand);
+};
+
+
+} // namespace lshal
+} // namespace android
+
+#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index 85d8938..9db42f1 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -14,399 +14,155 @@
* limitations under the License.
*/
+#define LOG_TAG "lshal"
+#include <android-base/logging.h>
+
#include "Lshal.h"
-#include <getopt.h>
+#include <set>
+#include <string>
-#include <fstream>
-#include <iomanip>
-#include <iostream>
-#include <map>
-#include <sstream>
-#include <regex>
-
-#include <android-base/logging.h>
-#include <android-base/parseint.h>
-#include <android/hidl/manager/1.0/IServiceManager.h>
#include <hidl/ServiceManagement.h>
-#include <hidl-util/FQName.h>
-#include <private/android_filesystem_config.h>
-#include <sys/stat.h>
-#include <vintf/HalManifest.h>
-#include <vintf/parse_xml.h>
+#include "DebugCommand.h"
+#include "ListCommand.h"
#include "PipeRelay.h"
-#include "Timeout.h"
-
-using ::android::hardware::hidl_string;
-using ::android::hidl::manager::V1_0::IServiceManager;
namespace android {
namespace lshal {
-template <typename A>
-std::string join(const A &components, const std::string &separator) {
- std::stringstream out;
- bool first = true;
- for (const auto &component : components) {
- if (!first) {
- out << separator;
- }
- out << component;
+using ::android::hidl::manager::V1_0::IServiceManager;
- first = false;
+Lshal::Lshal()
+ : mOut(std::cout), mErr(std::cerr),
+ mServiceManager(::android::hardware::defaultServiceManager()),
+ mPassthroughManager(::android::hardware::getPassthroughServiceManager()) {
+}
+
+Lshal::Lshal(std::ostream &out, std::ostream &err,
+ sp<hidl::manager::V1_0::IServiceManager> serviceManager,
+ sp<hidl::manager::V1_0::IServiceManager> passthroughManager)
+ : mOut(out), mErr(err),
+ mServiceManager(serviceManager),
+ mPassthroughManager(passthroughManager) {
+
+}
+
+void Lshal::usage(const std::string &command) const {
+ static const std::string helpSummary =
+ "lshal: List and debug HALs.\n"
+ "\n"
+ "commands:\n"
+ " help Print help message\n"
+ " list list HALs\n"
+ " debug debug a specified HAL\n"
+ "\n"
+ "If no command is specified, `list` is the default.\n";
+
+ static const std::string list =
+ "list:\n"
+ " lshal\n"
+ " lshal list\n"
+ " List all hals with default ordering and columns (`lshal list -ipc`)\n"
+ " lshal list [-h|--help]\n"
+ " -h, --help: Print help message for list (`lshal help list`)\n"
+ " lshal [list] [--interface|-i] [--transport|-t] [-r|--arch]\n"
+ " [--pid|-p] [--address|-a] [--clients|-c] [--cmdline|-m]\n"
+ " [--sort={interface|i|pid|p}] [--init-vintf[=<output file>]]\n"
+ " [--debug|-d[=<output file>]]\n"
+ " -i, --interface: print the interface name column\n"
+ " -n, --instance: print the instance name column\n"
+ " -t, --transport: print the transport mode column\n"
+ " -r, --arch: print if the HAL is in 64-bit or 32-bit\n"
+ " -p, --pid: print the server PID, or server cmdline if -m is set\n"
+ " -a, --address: print the server object address column\n"
+ " -c, --clients: print the client PIDs, or client cmdlines if -m is set\n"
+ " -m, --cmdline: print cmdline instead of PIDs\n"
+ " -d[=<output file>], --debug[=<output file>]: emit debug info from \n"
+ " IBase::debug with empty options\n"
+ " --sort=i, --sort=interface: sort by interface name\n"
+ " --sort=p, --sort=pid: sort by server pid\n"
+ " --init-vintf=<output file>: form a skeleton HAL manifest to specified\n"
+ " file, or stdout if no file specified.\n";
+
+ static const std::string debug =
+ "debug:\n"
+ " lshal debug <interface> [options [options [...]]] \n"
+ " Print debug information of a specified interface.\n"
+ " <inteface>: Format is `android.hardware.foo@1.0::IFoo/default`.\n"
+ " If instance name is missing `default` is used.\n"
+ " options: space separated options to IBase::debug.\n";
+
+ static const std::string help =
+ "help:\n"
+ " lshal -h\n"
+ " lshal --help\n"
+ " lshal help\n"
+ " Print this help message\n"
+ " lshal help list\n"
+ " Print help message for list\n"
+ " lshal help debug\n"
+ " Print help message for debug\n";
+
+ if (command == "list") {
+ mErr << list;
+ return;
}
- return out.str();
-}
-
-static std::string toHexString(uint64_t t) {
- std::ostringstream os;
- os << std::hex << std::setfill('0') << std::setw(16) << t;
- return os.str();
-}
-
-template<typename String>
-static std::pair<String, String> splitFirst(const String &s, char c) {
- const char *pos = strchr(s.c_str(), c);
- if (pos == nullptr) {
- return {s, {}};
- }
- return {String(s.c_str(), pos - s.c_str()), String(pos + 1)};
-}
-
-static std::vector<std::string> split(const std::string &s, char c) {
- std::vector<std::string> components{};
- size_t startPos = 0;
- size_t matchPos;
- while ((matchPos = s.find(c, startPos)) != std::string::npos) {
- components.push_back(s.substr(startPos, matchPos - startPos));
- startPos = matchPos + 1;
+ if (command == "debug") {
+ mErr << debug;
+ return;
}
- if (startPos <= s.length()) {
- components.push_back(s.substr(startPos));
- }
- return components;
-}
-
-static void replaceAll(std::string *s, char from, char to) {
- for (size_t i = 0; i < s->size(); ++i) {
- if (s->at(i) == from) {
- s->at(i) = to;
- }
- }
-}
-
-std::string getCmdline(pid_t pid) {
- std::ifstream ifs("/proc/" + std::to_string(pid) + "/cmdline");
- std::string cmdline;
- if (!ifs.is_open()) {
- return "";
- }
- ifs >> cmdline;
- return cmdline;
-}
-
-const std::string &Lshal::getCmdline(pid_t pid) {
- auto pair = mCmdlines.find(pid);
- if (pair != mCmdlines.end()) {
- return pair->second;
- }
- mCmdlines[pid] = ::android::lshal::getCmdline(pid);
- return mCmdlines[pid];
-}
-
-void Lshal::removeDeadProcesses(Pids *pids) {
- static const pid_t myPid = getpid();
- std::remove_if(pids->begin(), pids->end(), [this](auto pid) {
- return pid == myPid || this->getCmdline(pid).empty();
- });
-}
-
-bool Lshal::getReferencedPids(
- pid_t serverPid, std::map<uint64_t, Pids> *objects) const {
-
- std::ifstream ifs("/d/binder/proc/" + std::to_string(serverPid));
- if (!ifs.is_open()) {
- return false;
- }
-
- static const std::regex prefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+");
-
- std::string line;
- std::smatch match;
- while(getline(ifs, line)) {
- if (!std::regex_search(line, match, prefix)) {
- // the line doesn't start with the correct prefix
- continue;
- }
- std::string ptrString = "0x" + match.str(2); // use number after c
- uint64_t ptr;
- if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
- // Should not reach here, but just be tolerant.
- mErr << "Could not parse number " << ptrString << std::endl;
- continue;
- }
- const std::string proc = " proc ";
- auto pos = line.rfind(proc);
- if (pos != std::string::npos) {
- for (const std::string &pidStr : split(line.substr(pos + proc.size()), ' ')) {
- int32_t pid;
- if (!::android::base::ParseInt(pidStr, &pid)) {
- mErr << "Could not parse number " << pidStr << std::endl;
- continue;
- }
- (*objects)[ptr].push_back(pid);
- }
- }
- }
- return true;
-}
-
-// Must process hwbinder services first, then passthrough services.
-void Lshal::forEachTable(const std::function<void(Table &)> &f) {
- f(mServicesTable);
- f(mPassthroughRefTable);
- f(mImplementationsTable);
-}
-void Lshal::forEachTable(const std::function<void(const Table &)> &f) const {
- f(mServicesTable);
- f(mPassthroughRefTable);
- f(mImplementationsTable);
-}
-
-void Lshal::postprocess() {
- 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));
- }
- }
- });
- // use a double for loop here because lshal doesn't care about efficiency.
- for (TableEntry &packageEntry : mImplementationsTable) {
- std::string packageName = packageEntry.interfaceName;
- FQName fqPackageName{packageName.substr(0, packageName.find("::"))};
- if (!fqPackageName.isValid()) {
- continue;
- }
- for (TableEntry &interfaceEntry : mPassthroughRefTable) {
- if (interfaceEntry.arch != ARCH_UNKNOWN) {
- continue;
- }
- FQName interfaceName{splitFirst(interfaceEntry.interfaceName, '/').first};
- if (!interfaceName.isValid()) {
- continue;
- }
- if (interfaceName.getPackageAndVersion() == fqPackageName) {
- interfaceEntry.arch = packageEntry.arch;
- }
- }
- }
-}
-
-void Lshal::printLine(
- const std::string &interfaceName,
- 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 {
- if (mSelectedColumns & ENABLE_INTERFACE_NAME)
- 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";
- } else {
- mOut << std::setw(5) << server << "\t";
- }
- }
- if (mSelectedColumns & ENABLE_SERVER_ADDR)
- mOut << std::setw(16) << address << "\t";
- if (mSelectedColumns & ENABLE_CLIENT_PIDS) {
- if (mEnableCmdlines) {
- mOut << std::setw(0) << clientCmdlines;
- } else {
- mOut << std::setw(0) << clients;
- }
- }
- mOut << std::endl;
-}
-
-void Lshal::dumpVintf() const {
- mOut << "<!-- " << std::endl
- << " This is a skeleton device manifest. Notes: " << std::endl
- << " 1. android.hidl.*, android.frameworks.*, android.system.* are not included." << std::endl
- << " 2. If a HAL is supported in both hwbinder and passthrough transport, " << std::endl
- << " only hwbinder is shown." << std::endl
- << " 3. It is likely that HALs in passthrough transport does not have" << std::endl
- << " <interface> declared; users will have to write them by hand." << std::endl
- << " 4. sepolicy version is set to 0.0. It is recommended that the entry" << std::endl
- << " is removed from the manifest file and written by assemble_vintf" << std::endl
- << " at build time." << std::endl
- << "-->" << std::endl;
-
- vintf::HalManifest manifest;
- forEachTable([this, &manifest] (const Table &table) {
- for (const TableEntry &entry : table) {
-
- std::string fqInstanceName = entry.interfaceName;
-
- 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;
- }
- // Strip out system libs.
- if (fqName.inPackage("android.hidl") ||
- fqName.inPackage("android.frameworks") ||
- fqName.inPackage("android.system")) {
- continue;
- }
- std::string interfaceName =
- &table == &mImplementationsTable ? "" : fqName.name();
- std::string instanceName =
- &table == &mImplementationsTable ? "" : splittedFqInstanceName.second;
-
- vintf::Version version{fqName.getPackageMajorVersion(),
- fqName.getPackageMinorVersion()};
- vintf::Transport transport;
- vintf::Arch arch;
- if (entry.transport == "hwbinder") {
- transport = vintf::Transport::HWBINDER;
- arch = vintf::Arch::ARCH_EMPTY;
- } else if (entry.transport == "passthrough") {
- transport = vintf::Transport::PASSTHROUGH;
- switch (entry.arch) {
- case lshal::ARCH32:
- arch = vintf::Arch::ARCH_32; break;
- case lshal::ARCH64:
- arch = vintf::Arch::ARCH_64; break;
- case lshal::ARCH_BOTH:
- arch = vintf::Arch::ARCH_32_64; break;
- case lshal::ARCH_UNKNOWN: // fallthrough
- default:
- mErr << "Warning: '" << fqName.package()
- << "' doesn't have bitness info, assuming 32+64." << std::endl;
- arch = vintf::Arch::ARCH_32_64;
- }
- } else {
- mErr << "Warning: '" << entry.transport << "' is not a valid transport." << std::endl;
- continue;
- }
-
- bool done = false;
- for (vintf::ManifestHal *hal : manifest.getHals(fqName.package())) {
- if (hal->transport() != transport) {
- if (transport != vintf::Transport::PASSTHROUGH) {
- mErr << "Fatal: should not reach here. Generated result may be wrong."
- << std::endl;
- }
- done = true;
- break;
- }
- if (hal->hasVersion(version)) {
- if (&table != &mImplementationsTable) {
- hal->interfaces[interfaceName].name = interfaceName;
- hal->interfaces[interfaceName].instances.insert(instanceName);
- }
- done = true;
- break;
- }
- }
- if (done) {
- continue; // to next TableEntry
- }
- decltype(vintf::ManifestHal::interfaces) interfaces;
- if (&table != &mImplementationsTable) {
- interfaces[interfaceName].name = interfaceName;
- interfaces[interfaceName].instances.insert(instanceName);
- }
- if (!manifest.add(vintf::ManifestHal{
- .format = vintf::HalFormat::HIDL,
- .name = fqName.package(),
- .versions = {version},
- .transportArch = {transport, arch},
- .interfaces = interfaces})) {
- mErr << "Warning: cannot add hal '" << fqInstanceName << "'" << std::endl;
- }
- }
- });
- mOut << vintf::gHalManifestConverter(manifest);
-}
-
-static const std::string &getArchString(Architecture arch) {
- static const std::string sStr64 = "64";
- static const std::string sStr32 = "32";
- static const std::string sStrBoth = "32+64";
- static const std::string sStrUnknown = "";
- switch (arch) {
- case ARCH64:
- return sStr64;
- case ARCH32:
- return sStr32;
- case ARCH_BOTH:
- return sStrBoth;
- case ARCH_UNKNOWN: // fall through
- default:
- return sStrUnknown;
- }
-}
-
-static Architecture fromBaseArchitecture(::android::hidl::base::V1_0::DebugInfo::Architecture a) {
- switch (a) {
- case ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_64BIT:
- return ARCH64;
- case ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_32BIT:
- return ARCH32;
- case ::android::hidl::base::V1_0::DebugInfo::Architecture::UNKNOWN: // fallthrough
- default:
- return ARCH_UNKNOWN;
- }
+ mErr << helpSummary << "\n" << list << "\n" << debug << "\n" << help;
}
// A unique_ptr type using a custom deleter function.
template<typename T>
using deleted_unique_ptr = std::unique_ptr<T, std::function<void(T *)> >;
-void Lshal::emitDebugInfo(
- const sp<IServiceManager> &serviceManager,
+static hardware::hidl_vec<hardware::hidl_string> convert(const std::vector<std::string> &v) {
+ hardware::hidl_vec<hardware::hidl_string> hv;
+ hv.resize(v.size());
+ for (size_t i = 0; i < v.size(); ++i) {
+ hv[i].setToExternal(v[i].c_str(), v[i].size());
+ }
+ return hv;
+}
+
+Status Lshal::emitDebugInfo(
const std::string &interfaceName,
- const std::string &instanceName) const {
+ const std::string &instanceName,
+ const std::vector<std::string> &options,
+ std::ostream &out,
+ NullableOStream<std::ostream> err) const {
using android::hidl::base::V1_0::IBase;
- hardware::Return<sp<IBase>> retBase =
- serviceManager->get(interfaceName, instanceName);
+ hardware::Return<sp<IBase>> retBase = serviceManager()->get(interfaceName, instanceName);
- sp<IBase> base;
- if (!retBase.isOk() || (base = retBase) == nullptr) {
- // There's a small race, where a service instantiated while collecting
- // the list of services has by now terminated, so this isn't anything
- // to be concerned about.
- return;
+ if (!retBase.isOk()) {
+ std::string msg = "Cannot get " + interfaceName + "/" + instanceName + ": "
+ + retBase.description();
+ err << msg << std::endl;
+ LOG(ERROR) << msg;
+ return TRANSACTION_ERROR;
}
- PipeRelay relay(mOut.buf());
+ sp<IBase> base = retBase;
+ if (base == nullptr) {
+ std::string msg = interfaceName + "/" + instanceName + " does not exist, or "
+ + "no permission to connect.";
+ err << msg << std::endl;
+ LOG(ERROR) << msg;
+ return NO_INTERFACE;
+ }
+
+ PipeRelay relay(out);
if (relay.initCheck() != OK) {
- LOG(ERROR) << "PipeRelay::initCheck() FAILED w/ " << relay.initCheck();
- return;
+ std::string msg = "PipeRelay::initCheck() FAILED w/ " + std::to_string(relay.initCheck());
+ err << msg << std::endl;
+ LOG(ERROR) << msg;
+ return IO_ERROR;
}
deleted_unique_ptr<native_handle_t> fdHandle(
@@ -415,407 +171,40 @@
fdHandle->data[0] = relay.fd();
- hardware::hidl_vec<hardware::hidl_string> options;
- hardware::Return<void> ret = base->debug(fdHandle.get(), options);
+ hardware::Return<void> ret = base->debug(fdHandle.get(), convert(options));
if (!ret.isOk()) {
- LOG(ERROR)
- << interfaceName
- << "::debug(...) FAILED. (instance "
- << instanceName
- << ")";
- }
-}
-
-void Lshal::dumpTable() {
- mServicesTable.description =
- "All binderized services (registered services through hwservicemanager)";
- mPassthroughRefTable.description =
- "All interfaces that getService() has ever return as a passthrough interface;\n"
- "PIDs / processes shown below might be inaccurate because the process\n"
- "might have relinquished the interface or might have died.\n"
- "The Server / Server CMD column can be ignored.\n"
- "The Clients / Clients CMD column shows all process that have ever dlopen'ed \n"
- "the library and successfully fetched the passthrough implementation.";
- mImplementationsTable.description =
- "All available passthrough implementations (all -impl.so files)";
- forEachTable([this] (const Table &table) {
- mOut << table.description << std::endl;
- mOut << std::left;
- printLine("Interface", "Transport", "Arch", "Server", "Server CMD",
- "PTR", "Clients", "Clients CMD");
-
- // We're only interested in dumping debug info for already
- // instantiated services. There's little value in dumping the
- // debug info for a service we create on the fly, so we only operate
- // on the "mServicesTable".
- sp<IServiceManager> serviceManager;
- if (mEmitDebugInfo && &table == &mServicesTable) {
- serviceManager = ::android::hardware::defaultServiceManager();
- }
-
- 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, ";"));
-
- if (serviceManager != nullptr) {
- auto pair = splitFirst(entry.interfaceName, '/');
- emitDebugInfo(serviceManager, pair.first, pair.second);
- }
- }
- mOut << std::endl;
- });
-
-}
-
-void Lshal::dump() {
- if (mVintf) {
- dumpVintf();
- if (!!mFileOutput) {
- mFileOutput.buf().close();
- delete &mFileOutput.buf();
- mFileOutput = nullptr;
- }
- mOut = std::cout;
- } else {
- dumpTable();
- }
-}
-
-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::debugDump, [&] (const auto &infos) {
- std::map<std::string, TableEntry> entries;
- for (const auto &info : infos) {
- std::string interfaceName = std::string{info.interfaceName.c_str()} + "/" +
- std::string{info.instanceName.c_str()};
- entries.emplace(interfaceName, TableEntry{
- .interfaceName = interfaceName,
- .transport = "passthrough",
- .serverPid = NO_PID,
- .serverObjectAddress = NO_PTR,
- .clientPids = {},
- .arch = ARCH_UNKNOWN
- }).first->second.arch |= fromBaseArchitecture(info.arch);
- }
- for (auto &&pair : entries) {
- putEntry(LIST_DLLIB, std::move(pair.second));
- }
- });
- if (!ret.isOk()) {
- mErr << "Error: Failed to call list on getPassthroughServiceManager(): "
- << ret.description() << std::endl;
- return DUMP_ALL_LIBS_ERROR;
+ std::string msg = "debug() FAILED on " + interfaceName + "/" + instanceName + ": "
+ + ret.description();
+ err << msg << std::endl;
+ LOG(ERROR) << msg;
+ return TRANSACTION_ERROR;
}
return OK;
}
-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) {
- if (info.clientPids.size() <= 0) {
- continue;
- }
- putEntry(PTSERVICEMANAGER_REG_CLIENT, {
- .interfaceName =
- std::string{info.interfaceName.c_str()} + "/" +
- 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)
- });
- }
- });
- if (!ret.isOk()) {
- mErr << "Error: Failed to call debugDump on defaultServiceManager(): "
- << ret.description() << std::endl;
- return DUMP_PASSTHROUGH_ERROR;
- }
- return OK;
-}
-
-Status Lshal::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;
- // copying out for timeoutIPC
- auto listRet = timeoutIPC(manager, &IServiceManager::list, [&] (const auto &names) {
- fqInstanceNames = names;
- });
- if (!listRet.isOk()) {
- mErr << "Error: Failed to list services for " << mode << ": "
- << listRet.description() << std::endl;
- return DUMP_BINDERIZED_ERROR;
- }
-
- Status status = OK;
- // server pid, .ptr value of binder object, child pids
- std::map<std::string, DebugInfo> allDebugInfos;
- std::map<pid_t, std::map<uint64_t, Pids>> allPids;
- 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()) {
- mErr << "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) {
- mErr << "Warning: Skipping \"" << fqInstanceName << "\": "
- << "cannot be fetched from service manager (null)";
- 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)].clear();
- }
- });
- if (!debugRet.isOk()) {
- mErr << "Warning: Skipping \"" << fqInstanceName << "\": "
- << "debugging information cannot be retrieved:"
- << debugRet.description() << std::endl;
- status |= DUMP_BINDERIZED_ERROR;
- }
- }
- for (auto &pair : allPids) {
- pid_t serverPid = pair.first;
- if (!getReferencedPids(serverPid, &allPids[serverPid])) {
- mErr << "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 = {},
- .arch = ARCH_UNKNOWN
- });
- continue;
- }
- const DebugInfo &info = it->second;
- 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],
- .arch = fromBaseArchitecture(info.arch),
- });
- }
- return status;
-}
-
-Status Lshal::fetch() {
- Status status = OK;
- auto bManager = ::android::hardware::defaultServiceManager();
- if (bManager == nullptr) {
- mErr << "Failed to get defaultServiceManager()!" << std::endl;
- status |= NO_BINDERIZED_MANAGER;
- } else {
- status |= fetchBinderized(bManager);
- // Passthrough PIDs are registered to the binderized manager as well.
- status |= fetchPassthrough(bManager);
- }
-
- auto pManager = ::android::hardware::getPassthroughServiceManager();
- if (pManager == nullptr) {
- mErr << "Failed to get getPassthroughServiceManager()!" << std::endl;
- status |= NO_PASSTHROUGH_MANAGER;
- } else {
- status |= fetchAllLibraries(pManager);
- }
- return status;
-}
-
-void Lshal::usage() const {
- mErr
- << "usage: lshal" << 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"
- << std::endl
- << " -m, --cmdline: print cmdline instead of PIDs" << std::endl
- << " --sort=i, --sort=interface: sort by interface name" << std::endl
- << " --sort=p, --sort=pid: sort by server pid" << std::endl
- << " --init-vintf=path: form a skeleton HAL manifest to specified file " << std::endl
- << " (stdout if no file specified)" << std::endl
- << " lshal [-h|--help]" << std::endl
- << " -h, --help: show this help information." << std::endl;
-}
-
-Status Lshal::parseArgs(int argc, char **argv) {
- static struct option longOptions[] = {
- // long options with short alternatives
- {"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' },
- {"cmdline", no_argument, 0, 'm' },
- {"debug", optional_argument, 0, 'd' },
-
- // long options without short alternatives
- {"sort", required_argument, 0, 's' },
- {"init-vintf",optional_argument, 0, 'v' },
- { 0, 0, 0, 0 }
- };
-
- int optionIndex;
- int c;
+Status Lshal::parseArgs(const Arg &arg) {
+ static std::set<std::string> sAllCommands{"list", "debug", "help"};
optind = 1;
- for (;;) {
- // using getopt_long in case we want to add other options in the future
- c = getopt_long(argc, argv, "hitrpacmd", longOptions, &optionIndex);
- if (c == -1) {
- break;
- }
- switch (c) {
- case 's': {
- if (strcmp(optarg, "interface") == 0 || strcmp(optarg, "i") == 0) {
- mSortColumn = TableEntry::sortByInterfaceName;
- } else if (strcmp(optarg, "pid") == 0 || strcmp(optarg, "p") == 0) {
- mSortColumn = TableEntry::sortByServerPid;
- } else {
- mErr << "Unrecognized sorting column: " << optarg << std::endl;
- usage();
- return USAGE;
- }
- break;
- }
- case 'v': {
- if (optarg) {
- mFileOutput = new std::ofstream{optarg};
- mOut = mFileOutput;
- if (!mFileOutput.buf().is_open()) {
- mErr << "Could not open file '" << optarg << "'." << std::endl;
- return IO_ERROR;
- }
- }
- mVintf = true;
- }
- case 'i': {
- mSelectedColumns |= ENABLE_INTERFACE_NAME;
- break;
- }
- case 't': {
- mSelectedColumns |= ENABLE_TRANSPORT;
- break;
- }
- case 'r': {
- mSelectedColumns |= ENABLE_ARCH;
- break;
- }
- case 'p': {
- mSelectedColumns |= ENABLE_SERVER_PID;
- break;
- }
- case 'a': {
- mSelectedColumns |= ENABLE_SERVER_ADDR;
- break;
- }
- case 'c': {
- mSelectedColumns |= ENABLE_CLIENT_PIDS;
- break;
- }
- case 'm': {
- mEnableCmdlines = true;
- break;
- }
- case 'd': {
- mEmitDebugInfo = true;
-
- if (optarg) {
- mFileOutput = new std::ofstream{optarg};
- mOut = mFileOutput;
- if (!mFileOutput.buf().is_open()) {
- mErr << "Could not open file '" << optarg << "'." << std::endl;
- return IO_ERROR;
- }
- chown(optarg, AID_SHELL, AID_SHELL);
- }
- break;
- }
- case 'h': // falls through
- default: // see unrecognized options
- usage();
- return USAGE;
- }
+ if (optind >= arg.argc) {
+ // no options at all.
+ return OK;
+ }
+ mCommand = arg.argv[optind];
+ if (sAllCommands.find(mCommand) != sAllCommands.end()) {
+ ++optind;
+ return OK; // mCommand is set correctly
}
- if (mSelectedColumns == 0) {
- mSelectedColumns = ENABLE_INTERFACE_NAME | ENABLE_SERVER_PID | ENABLE_CLIENT_PIDS;
+ if (mCommand.size() > 0 && mCommand[0] == '-') {
+ // first argument is an option, set command to "" (which is recognized as "list")
+ mCommand = "";
+ return OK;
}
- return OK;
-}
-int Lshal::main(int argc, char **argv) {
- Status status = parseArgs(argc, argv);
- if (status != OK) {
- return status;
- }
- status = fetch();
- postprocess();
- dump();
- return status;
+ mErr << arg.argv[0] << ": unrecognized option `" << arg.argv[optind] << "`" << std::endl;
+ usage();
+ return USAGE;
}
void signalHandler(int sig) {
@@ -825,10 +214,43 @@
}
}
+Status Lshal::main(const Arg &arg) {
+ // Allow SIGINT to terminate all threads.
+ signal(SIGINT, signalHandler);
+
+ Status status = parseArgs(arg);
+ if (status != OK) {
+ return status;
+ }
+ if (mCommand == "help") {
+ usage(optind < arg.argc ? arg.argv[optind] : "");
+ return USAGE;
+ }
+ // Default command is list
+ if (mCommand == "list" || mCommand == "") {
+ return ListCommand{*this}.main(mCommand, arg);
+ }
+ if (mCommand == "debug") {
+ return DebugCommand{*this}.main(mCommand, arg);
+ }
+ usage();
+ return USAGE;
+}
+
+NullableOStream<std::ostream> Lshal::err() const {
+ return mErr;
+}
+NullableOStream<std::ostream> Lshal::out() const {
+ return mOut;
+}
+
+const sp<IServiceManager> &Lshal::serviceManager() const {
+ return mServiceManager;
+}
+
+const sp<IServiceManager> &Lshal::passthroughManager() const {
+ return mPassthroughManager;
+}
+
} // namespace lshal
} // namespace android
-
-int main(int argc, char **argv) {
- signal(SIGINT, ::android::lshal::signalHandler);
- return ::android::lshal::Lshal{}.main(argc, argv);
-}
diff --git a/cmds/lshal/Lshal.h b/cmds/lshal/Lshal.h
index a21e86c..00db5d0 100644
--- a/cmds/lshal/Lshal.h
+++ b/cmds/lshal/Lshal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -17,94 +17,51 @@
#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_LSHAL_H_
#define FRAMEWORK_NATIVE_CMDS_LSHAL_LSHAL_H_
-#include <stdint.h>
-
-#include <fstream>
+#include <iostream>
#include <string>
-#include <vector>
+#include <android-base/macros.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <utils/StrongPointer.h>
#include "NullableOStream.h"
-#include "TableEntry.h"
+#include "utils.h"
namespace android {
namespace lshal {
-enum : unsigned int {
- OK = 0,
- USAGE = 1 << 0,
- NO_BINDERIZED_MANAGER = 1 << 1,
- NO_PASSTHROUGH_MANAGER = 1 << 2,
- DUMP_BINDERIZED_ERROR = 1 << 3,
- DUMP_PASSTHROUGH_ERROR = 1 << 4,
- DUMP_ALL_LIBS_ERROR = 1 << 5,
- IO_ERROR = 1 << 6,
-};
-using Status = unsigned int;
-
class Lshal {
public:
- int main(int argc, char **argv);
+ Lshal();
+ Lshal(std::ostream &out, std::ostream &err,
+ sp<hidl::manager::V1_0::IServiceManager> serviceManager,
+ sp<hidl::manager::V1_0::IServiceManager> passthroughManager);
+ Status main(const Arg &arg);
+ void usage(const std::string &command = "") const;
+ NullableOStream<std::ostream> err() const;
+ NullableOStream<std::ostream> out() const;
+ const sp<hidl::manager::V1_0::IServiceManager> &serviceManager() const;
+ const sp<hidl::manager::V1_0::IServiceManager> &passthroughManager() const;
+ Status emitDebugInfo(
+ const std::string &interfaceName,
+ const std::string &instanceName,
+ const std::vector<std::string> &options,
+ std::ostream &out,
+ NullableOStream<std::ostream> err) const;
private:
- Status parseArgs(int argc, char **argv);
- Status fetch();
- void postprocess();
- void dump();
- void usage() const;
- 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();
- void dumpVintf() const;
- void printLine(
- const std::string &interfaceName,
- 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 ;
- // Return /proc/{pid}/cmdline if it exists, else empty string.
- const std::string &getCmdline(pid_t pid);
- // 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;
+ Status parseArgs(const Arg &arg);
+ std::string mCommand;
+ Arg mCmdArgs;
+ NullableOStream<std::ostream> mOut;
+ NullableOStream<std::ostream> mErr;
- void emitDebugInfo(
- const sp<hidl::manager::V1_0::IServiceManager> &serviceManager,
- const std::string &interfaceName,
- const std::string &instanceName) const;
+ sp<hidl::manager::V1_0::IServiceManager> mServiceManager;
+ sp<hidl::manager::V1_0::IServiceManager> mPassthroughManager;
- Table mServicesTable{};
- Table mPassthroughRefTable{};
- Table mImplementationsTable{};
-
- NullableOStream<std::ostream> mErr = std::cerr;
- NullableOStream<std::ostream> mOut = std::cout;
- NullableOStream<std::ofstream> mFileOutput = nullptr;
- TableEntryCompare mSortColumn = nullptr;
- TableEntrySelect mSelectedColumns = 0;
- // If true, cmdlines will be printed instead of pid.
- bool mEnableCmdlines = false;
-
- // If true, calls IBase::debug(...) on each service.
- bool mEmitDebugInfo = false;
-
- bool mVintf = false;
- // If an entry does not exist, need to ask /proc/{pid}/cmdline to get it.
- // If an entry exist but is an empty string, process might have died.
- // If an entry exist and not empty, it contains the cached content of /proc/{pid}/cmdline.
- std::map<pid_t, std::string> mCmdlines;
+ DISALLOW_COPY_AND_ASSIGN(Lshal);
};
-
} // namespace lshal
} // namespace android
diff --git a/cmds/lshal/PipeRelay.cpp b/cmds/lshal/PipeRelay.cpp
index c7b29df..54d19f6 100644
--- a/cmds/lshal/PipeRelay.cpp
+++ b/cmds/lshal/PipeRelay.cpp
@@ -70,7 +70,6 @@
mInitCheck = mThread->run("RelayThread");
}
-// static
void PipeRelay::CloseFd(int *fd) {
if (*fd >= 0) {
close(*fd);
diff --git a/cmds/lshal/main.cpp b/cmds/lshal/main.cpp
new file mode 100644
index 0000000..366c938
--- /dev/null
+++ b/cmds/lshal/main.cpp
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+#include "Lshal.h"
+
+int main(int argc, char **argv) {
+ using namespace ::android::lshal;
+ return Lshal{}.main(Arg{argc, argv});
+}
diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp
new file mode 100644
index 0000000..972d508
--- /dev/null
+++ b/cmds/lshal/test.cpp
@@ -0,0 +1,168 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "Lshal"
+#include <android-base/logging.h>
+
+#include <sstream>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+#include <android/hardware/tests/baz/1.0/IQuux.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "Lshal.h"
+
+#define NELEMS(array) static_cast<int>(sizeof(array) / sizeof(array[0]))
+
+using namespace testing;
+
+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_death_recipient;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+
+namespace android {
+namespace hardware {
+namespace tests {
+namespace baz {
+namespace V1_0 {
+namespace implementation {
+struct Quux : android::hardware::tests::baz::V1_0::IQuux {
+ ::android::hardware::Return<void> debug(const hidl_handle& hh, const hidl_vec<hidl_string>& options) override {
+ const native_handle_t *handle = hh.getNativeHandle();
+ if (handle->numFds < 1) {
+ return Void();
+ }
+ int fd = handle->data[0];
+ std::string content{descriptor};
+ for (const auto &option : options) {
+ content += "\n";
+ content += option.c_str();
+ }
+ ssize_t written = write(fd, content.c_str(), content.size());
+ if (written != (ssize_t)content.size()) {
+ LOG(WARNING) << "SERVER(Quux) debug writes " << written << " bytes < "
+ << content.size() << " bytes, errno = " << errno;
+ }
+ return Void();
+ }
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace baz
+} // namespace tests
+} // namespace hardware
+
+namespace lshal {
+
+
+class MockServiceManager : public IServiceManager {
+public:
+ template<typename T>
+ using R = ::android::hardware::Return<T>;
+ using String = const hidl_string&;
+ ~MockServiceManager() = default;
+
+#define MOCK_METHOD_CB(name) MOCK_METHOD1(name, R<void>(IServiceManager::name##_cb))
+
+ MOCK_METHOD2(get, R<sp<IBase>>(String, String));
+ MOCK_METHOD2(add, R<bool>(String, const sp<IBase>&));
+ MOCK_METHOD2(getTransport, R<IServiceManager::Transport>(String, String));
+ MOCK_METHOD_CB(list);
+ MOCK_METHOD2(listByInterface, R<void>(String, listByInterface_cb));
+ MOCK_METHOD3(registerForNotifications, R<bool>(String, String, const sp<IServiceNotification>&));
+ MOCK_METHOD_CB(debugDump);
+ MOCK_METHOD2(registerPassthroughClient, R<void>(String, String));
+ MOCK_METHOD_CB(interfaceChain);
+ MOCK_METHOD2(debug, R<void>(const hidl_handle&, const hidl_vec<hidl_string>&));
+ MOCK_METHOD_CB(interfaceDescriptor);
+ MOCK_METHOD_CB(getHashChain);
+ MOCK_METHOD0(setHalInstrumentation, R<void>());
+ MOCK_METHOD2(linkToDeath, R<bool>(const sp<hidl_death_recipient>&, uint64_t));
+ MOCK_METHOD0(ping, R<void>());
+ MOCK_METHOD_CB(getDebugInfo);
+ MOCK_METHOD0(notifySyspropsChanged, R<void>());
+ MOCK_METHOD1(unlinkToDeath, R<bool>(const sp<hidl_death_recipient>&));
+
+};
+
+class LshalTest : public ::testing::Test {
+public:
+ void SetUp() override {
+ using ::android::hardware::tests::baz::V1_0::IQuux;
+ using ::android::hardware::tests::baz::V1_0::implementation::Quux;
+
+ err.str("");
+ out.str("");
+ serviceManager = new testing::NiceMock<MockServiceManager>();
+ ON_CALL(*serviceManager, get(_, _)).WillByDefault(Invoke(
+ [](const auto &iface, const auto &inst) -> ::android::hardware::Return<sp<IBase>> {
+ if (iface == IQuux::descriptor && inst == "default")
+ return new Quux();
+ return nullptr;
+ }));
+ }
+ void TearDown() override {}
+
+ std::stringstream err;
+ std::stringstream out;
+ sp<MockServiceManager> serviceManager;
+};
+
+TEST_F(LshalTest, Debug) {
+ const char *args[] = {
+ "lshal", "debug", "android.hardware.tests.baz@1.0::IQuux/default", "foo", "bar"
+ };
+ EXPECT_EQ(0u, Lshal(out, err, serviceManager, serviceManager)
+ .main({NELEMS(args), const_cast<char **>(args)}));
+ EXPECT_THAT(out.str(), StrEq("android.hardware.tests.baz@1.0::IQuux\nfoo\nbar"));
+ EXPECT_THAT(err.str(), IsEmpty());
+}
+
+TEST_F(LshalTest, Debug2) {
+ const char *args[] = {
+ "lshal", "debug", "android.hardware.tests.baz@1.0::IQuux", "baz", "quux"
+ };
+ EXPECT_EQ(0u, Lshal(out, err, serviceManager, serviceManager)
+ .main({NELEMS(args), const_cast<char **>(args)}));
+ EXPECT_THAT(out.str(), StrEq("android.hardware.tests.baz@1.0::IQuux\nbaz\nquux"));
+ EXPECT_THAT(err.str(), IsEmpty());
+}
+
+TEST_F(LshalTest, Debug3) {
+ const char *args[] = {
+ "lshal", "debug", "android.hardware.tests.doesnotexist@1.0::IDoesNotExist",
+ };
+ EXPECT_NE(0u, Lshal(out, err, serviceManager, serviceManager)
+ .main({NELEMS(args), const_cast<char **>(args)}));
+ EXPECT_THAT(err.str(), HasSubstr("does not exist"));
+}
+
+} // namespace lshal
+} // namespace android
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleMock(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/cmds/lshal/utils.cpp b/cmds/lshal/utils.cpp
new file mode 100644
index 0000000..5550721
--- /dev/null
+++ b/cmds/lshal/utils.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#include "utils.h"
+
+namespace android {
+namespace lshal {
+
+std::string toHexString(uint64_t t) {
+ std::ostringstream os;
+ os << std::hex << std::setfill('0') << std::setw(16) << t;
+ return os.str();
+}
+
+std::vector<std::string> split(const std::string &s, char c) {
+ std::vector<std::string> components{};
+ size_t startPos = 0;
+ size_t matchPos;
+ while ((matchPos = s.find(c, startPos)) != std::string::npos) {
+ components.push_back(s.substr(startPos, matchPos - startPos));
+ startPos = matchPos + 1;
+ }
+
+ if (startPos <= s.length()) {
+ components.push_back(s.substr(startPos));
+ }
+ return components;
+}
+
+void replaceAll(std::string *s, char from, char to) {
+ for (size_t i = 0; i < s->size(); ++i) {
+ if (s->at(i) == from) {
+ s->at(i) = to;
+ }
+ }
+}
+
+} // namespace lshal
+} // namespace android
+
diff --git a/cmds/lshal/utils.h b/cmds/lshal/utils.h
new file mode 100644
index 0000000..45b922c
--- /dev/null
+++ b/cmds/lshal/utils.h
@@ -0,0 +1,82 @@
+/*
+ * 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 FRAMEWORK_NATIVE_CMDS_LSHAL_UTILS_H_
+#define FRAMEWORK_NATIVE_CMDS_LSHAL_UTILS_H_
+
+#include <iomanip>
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <utility>
+#include <vector>
+
+namespace android {
+namespace lshal {
+
+enum : unsigned int {
+ OK = 0,
+ USAGE = 1 << 0,
+ NO_BINDERIZED_MANAGER = 1 << 1,
+ NO_PASSTHROUGH_MANAGER = 1 << 2,
+ DUMP_BINDERIZED_ERROR = 1 << 3,
+ DUMP_PASSTHROUGH_ERROR = 1 << 4,
+ DUMP_ALL_LIBS_ERROR = 1 << 5,
+ IO_ERROR = 1 << 6,
+ NO_INTERFACE = 1 << 7,
+ TRANSACTION_ERROR = 1 << 8,
+};
+using Status = unsigned int;
+
+struct Arg {
+ int argc;
+ char **argv;
+};
+
+template <typename A>
+std::string join(const A &components, const std::string &separator) {
+ std::stringstream out;
+ bool first = true;
+ for (const auto &component : components) {
+ if (!first) {
+ out << separator;
+ }
+ out << component;
+
+ first = false;
+ }
+ return out.str();
+}
+
+std::string toHexString(uint64_t t);
+
+template<typename String>
+std::pair<String, String> splitFirst(const String &s, char c) {
+ const char *pos = strchr(s.c_str(), c);
+ if (pos == nullptr) {
+ return {s, {}};
+ }
+ return {String(s.c_str(), pos - s.c_str()), String(pos + 1)};
+}
+
+std::vector<std::string> split(const std::string &s, char c);
+
+void replaceAll(std::string *s, char from, char to);
+
+} // namespace lshal
+} // namespace android
+
+#endif // FRAMEWORK_NATIVE_CMDS_LSHAL_UTILS_H_
diff --git a/include/audiomanager/AudioManager.h b/include/audiomanager/AudioManager.h
index 834dcbd..009dc52 100644
--- a/include/audiomanager/AudioManager.h
+++ b/include/audiomanager/AudioManager.h
@@ -26,6 +26,9 @@
typedef enum {
PLAYER_TYPE_SLES_AUDIOPLAYER_BUFFERQUEUE = 11,
PLAYER_TYPE_SLES_AUDIOPLAYER_URI_FD = 12,
+ PLAYER_TYPE_AAUDIO = 13,
+ PLAYER_TYPE_HW_SOURCE = 14,
+ PLAYER_TYPE_EXTERNAL_PROXY = 15,
} player_type_t;
typedef enum {
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 6fefb38..aec8f10 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -2547,16 +2547,8 @@
objectsSize = 0;
} else {
while (objectsSize > 0) {
- if (mObjects[objectsSize-1] < desired) {
- // Check for an object being sliced
- if (desired < mObjects[objectsSize-1] + sizeof(flat_binder_object)) {
- ALOGE("Attempt to shrink Parcel would slice an objects allocated memory");
- return UNKNOWN_ERROR + 0xBADF10;
- }
+ if (mObjects[objectsSize-1] < desired)
break;
- }
- // STOPSHIP: Above code to be replaced with following commented code:
- // if (mObjects[objectsSize-1] + sizeof(flat_binder_object) <= desired) break;
objectsSize--;
}
}
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 8159aef..3d57769 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -511,7 +511,7 @@
{ // Autolock scope
Mutex::Autolock lock(mCore->mMutex);
- if (graphicBuffer != NULL && !mCore->mIsAbandoned) {
+ if (error == NO_ERROR && !mCore->mIsAbandoned) {
graphicBuffer->setGenerationNumber(mCore->mGenerationNumber);
mSlots[*outSlot].mGraphicBuffer = graphicBuffer;
}
@@ -519,7 +519,7 @@
mCore->mIsAllocating = false;
mCore->mIsAllocatingCondition.broadcast();
- if (graphicBuffer == NULL) {
+ if (error != NO_ERROR) {
mCore->mFreeSlots.insert(*outSlot);
mCore->clearBufferSlotLocked(*outSlot);
BQ_LOGE("dequeueBuffer: createGraphicBuffer failed");
@@ -732,6 +732,7 @@
mSlots[*outSlot].mFence = Fence::NO_FENCE;
mSlots[*outSlot].mRequestBufferCalled = true;
mSlots[*outSlot].mAcquireCalled = false;
+ mSlots[*outSlot].mNeedsReallocation = false;
mCore->mActiveBuffers.insert(found);
VALIDATE_CONSISTENCY();
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 74117c8..bca645f 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -27,6 +27,7 @@
#include <binder/Parcel.h>
#include <binder/IInterface.h>
+#include <gui/BufferQueueDefs.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/IProducerListener.h>
@@ -220,8 +221,16 @@
if (result != NO_ERROR) {
return result;
}
+
*slot = reply.readInt32();
result = reply.readInt32();
+ if (result == NO_ERROR &&
+ (*slot < 0 || *slot >= BufferQueueDefs::NUM_BUFFER_SLOTS)) {
+ ALOGE("attachBuffer returned invalid slot %d", *slot);
+ android_errorWriteLog(0x534e4554, "37478824");
+ return UNKNOWN_ERROR;
+ }
+
return result;
}
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index a6d9e66..6583a62 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -476,6 +476,9 @@
{
Mutex::Autolock lock(mMutex);
+ if (mReportRemovedBuffers) {
+ mRemovedBuffers.clear();
+ }
reqWidth = mReqWidth ? mReqWidth : mUserWidth;
reqHeight = mReqHeight ? mReqHeight : mUserHeight;
@@ -513,6 +516,12 @@
return result;
}
+ if (buf < 0 || buf >= NUM_BUFFER_SLOTS) {
+ ALOGE("dequeueBuffer: IGraphicBufferProducer returned invalid slot number %d", buf);
+ android_errorWriteLog(0x534e4554, "36991414"); // SafetyNet logging
+ return FAILED_TRANSACTION;
+ }
+
Mutex::Autolock lock(mMutex);
sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
@@ -530,7 +539,6 @@
if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == nullptr) {
if (mReportRemovedBuffers && (gbuf != nullptr)) {
- mRemovedBuffers.clear();
mRemovedBuffers.push_back(gbuf);
}
result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
@@ -1202,6 +1210,9 @@
}
Mutex::Autolock lock(mMutex);
+ if (mReportRemovedBuffers) {
+ mRemovedBuffers.clear();
+ }
sp<GraphicBuffer> buffer(NULL);
sp<Fence> fence(NULL);
@@ -1218,13 +1229,9 @@
*outFence = Fence::NO_FENCE;
}
- if (mReportRemovedBuffers) {
- mRemovedBuffers.clear();
- }
-
for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
if (mSlots[i].buffer != NULL &&
- mSlots[i].buffer->handle == buffer->handle) {
+ mSlots[i].buffer->getId() == buffer->getId()) {
if (mReportRemovedBuffers) {
mRemovedBuffers.push_back(mSlots[i].buffer);
}
@@ -1241,6 +1248,9 @@
ALOGV("Surface::attachBuffer");
Mutex::Autolock lock(mMutex);
+ if (mReportRemovedBuffers) {
+ mRemovedBuffers.clear();
+ }
sp<GraphicBuffer> graphicBuffer(static_cast<GraphicBuffer*>(buffer));
uint32_t priorGeneration = graphicBuffer->mGenerationNumber;
@@ -1254,7 +1264,6 @@
return result;
}
if (mReportRemovedBuffers && (mSlots[attachedSlot].buffer != nullptr)) {
- mRemovedBuffers.clear();
mRemovedBuffers.push_back(mSlots[attachedSlot].buffer);
}
mSlots[attachedSlot].buffer = graphicBuffer;
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 192bfc8..7efdb14 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -14,6 +14,7 @@
"FillBuffer.cpp",
"GLTest.cpp",
"IGraphicBufferProducer_test.cpp",
+ "Malicious.cpp",
"MultiTextureConsumer_test.cpp",
"StreamSplitter_test.cpp",
"SurfaceTextureClient_test.cpp",
diff --git a/libs/gui/tests/Malicious.cpp b/libs/gui/tests/Malicious.cpp
new file mode 100644
index 0000000..7ecf08c
--- /dev/null
+++ b/libs/gui/tests/Malicious.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright 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.
+ */
+
+#include <gui/BufferQueue.h>
+#include <gui/IProducerListener.h>
+#include <gui/Surface.h>
+
+#include <android/native_window.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace test {
+
+class ProxyBQP : public BnGraphicBufferProducer {
+public:
+ ProxyBQP(const sp<IGraphicBufferProducer>& producer) : mProducer(producer) {}
+
+ // Pass through calls to mProducer
+ status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override {
+ return mProducer->requestBuffer(slot, buf);
+ }
+ status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) override {
+ return mProducer->setMaxDequeuedBufferCount(maxDequeuedBuffers);
+ }
+ status_t setAsyncMode(bool async) override { return mProducer->setAsyncMode(async); }
+ status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h, PixelFormat format,
+ uint32_t usage, FrameEventHistoryDelta* outTimestamps) override {
+ return mProducer->dequeueBuffer(slot, fence, w, h, format, usage, outTimestamps);
+ }
+ status_t detachBuffer(int slot) override { return mProducer->detachBuffer(slot); }
+ status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) override {
+ return mProducer->detachNextBuffer(outBuffer, outFence);
+ }
+ status_t attachBuffer(int* outSlot, const sp<GraphicBuffer>& buffer) override {
+ return mProducer->attachBuffer(outSlot, buffer);
+ }
+ status_t queueBuffer(int slot, const QueueBufferInput& input,
+ QueueBufferOutput* output) override {
+ return mProducer->queueBuffer(slot, input, output);
+ }
+ status_t cancelBuffer(int slot, const sp<Fence>& fence) override {
+ return mProducer->cancelBuffer(slot, fence);
+ }
+ int query(int what, int* value) override { return mProducer->query(what, value); }
+ status_t connect(const sp<IProducerListener>& listener, int api, bool producerControlledByApp,
+ QueueBufferOutput* output) override {
+ return mProducer->connect(listener, api, producerControlledByApp, output);
+ }
+ status_t disconnect(int api, DisconnectMode mode) override {
+ return mProducer->disconnect(api, mode);
+ }
+ status_t setSidebandStream(const sp<NativeHandle>& stream) override {
+ return mProducer->setSidebandStream(stream);
+ }
+ void allocateBuffers(uint32_t width, uint32_t height, PixelFormat format,
+ uint32_t usage) override {
+ mProducer->allocateBuffers(width, height, format, usage);
+ }
+ status_t allowAllocation(bool allow) override { return mProducer->allowAllocation(allow); }
+ status_t setGenerationNumber(uint32_t generationNumber) override {
+ return mProducer->setGenerationNumber(generationNumber);
+ }
+ String8 getConsumerName() const override { return mProducer->getConsumerName(); }
+ status_t setSharedBufferMode(bool sharedBufferMode) override {
+ return mProducer->setSharedBufferMode(sharedBufferMode);
+ }
+ status_t setAutoRefresh(bool autoRefresh) override {
+ return mProducer->setAutoRefresh(autoRefresh);
+ }
+ status_t setDequeueTimeout(nsecs_t timeout) override {
+ return mProducer->setDequeueTimeout(timeout);
+ }
+ status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence,
+ float outTransformMatrix[16]) override {
+ return mProducer->getLastQueuedBuffer(outBuffer, outFence, outTransformMatrix);
+ }
+ void getFrameTimestamps(FrameEventHistoryDelta*) override {}
+ status_t getUniqueId(uint64_t* outId) const override { return mProducer->getUniqueId(outId); }
+
+protected:
+ sp<IGraphicBufferProducer> mProducer;
+};
+
+class MaliciousBQP : public ProxyBQP {
+public:
+ MaliciousBQP(const sp<IGraphicBufferProducer>& producer) : ProxyBQP(producer) {}
+
+ void beMalicious(int32_t value) { mMaliciousValue = value; }
+
+ void setExpectedSlot(int32_t slot) { mExpectedSlot = slot; }
+
+ // Override dequeueBuffer, optionally corrupting the returned slot number
+ status_t dequeueBuffer(int* buf, sp<Fence>* fence, uint32_t width, uint32_t height,
+ PixelFormat format, uint32_t usage,
+ FrameEventHistoryDelta* outTimestamps) override {
+ EXPECT_EQ(BUFFER_NEEDS_REALLOCATION,
+ mProducer->dequeueBuffer(buf, fence, width, height, format, usage,
+ outTimestamps));
+ EXPECT_EQ(mExpectedSlot, *buf);
+ if (mMaliciousValue != 0) {
+ *buf = mMaliciousValue;
+ return NO_ERROR;
+ } else {
+ return BUFFER_NEEDS_REALLOCATION;
+ }
+ }
+
+private:
+ int32_t mMaliciousValue = 0;
+ int32_t mExpectedSlot = 0;
+};
+
+class DummyListener : public BnConsumerListener {
+public:
+ void onFrameAvailable(const BufferItem&) override {}
+ void onBuffersReleased() override {}
+ void onSidebandStreamChanged() override {}
+};
+
+sp<MaliciousBQP> getMaliciousBQP() {
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ sp<IConsumerListener> listener = new DummyListener;
+ consumer->consumerConnect(listener, false);
+
+ sp<MaliciousBQP> malicious = new MaliciousBQP(producer);
+ return malicious;
+}
+
+TEST(Malicious, Bug36991414Max) {
+ sp<MaliciousBQP> malicious = getMaliciousBQP();
+ sp<Surface> surface = new Surface(malicious);
+
+ ASSERT_EQ(NO_ERROR, surface->connect(NATIVE_WINDOW_API_CPU, nullptr, false));
+ ANativeWindow_Buffer buffer;
+ ASSERT_EQ(NO_ERROR, surface->lock(&buffer, nullptr));
+ ASSERT_EQ(NO_ERROR, surface->unlockAndPost());
+
+ malicious->setExpectedSlot(1);
+ malicious->beMalicious(std::numeric_limits<int32_t>::max());
+ ASSERT_EQ(FAILED_TRANSACTION, surface->lock(&buffer, nullptr));
+}
+
+TEST(Malicious, Bug36991414Min) {
+ sp<MaliciousBQP> malicious = getMaliciousBQP();
+ sp<Surface> surface = new Surface(malicious);
+
+ ASSERT_EQ(NO_ERROR, surface->connect(NATIVE_WINDOW_API_CPU, nullptr, false));
+ ANativeWindow_Buffer buffer;
+ ASSERT_EQ(NO_ERROR, surface->lock(&buffer, nullptr));
+ ASSERT_EQ(NO_ERROR, surface->unlockAndPost());
+
+ malicious->setExpectedSlot(1);
+ malicious->beMalicious(std::numeric_limits<int32_t>::min());
+ ASSERT_EQ(FAILED_TRANSACTION, surface->lock(&buffer, nullptr));
+}
+
+TEST(Malicious, Bug36991414NegativeOne) {
+ sp<MaliciousBQP> malicious = getMaliciousBQP();
+ sp<Surface> surface = new Surface(malicious);
+
+ ASSERT_EQ(NO_ERROR, surface->connect(NATIVE_WINDOW_API_CPU, nullptr, false));
+ ANativeWindow_Buffer buffer;
+ ASSERT_EQ(NO_ERROR, surface->lock(&buffer, nullptr));
+ ASSERT_EQ(NO_ERROR, surface->unlockAndPost());
+
+ malicious->setExpectedSlot(1);
+ malicious->beMalicious(-1);
+ ASSERT_EQ(FAILED_TRANSACTION, surface->lock(&buffer, nullptr));
+}
+
+TEST(Malicious, Bug36991414NumSlots) {
+ sp<MaliciousBQP> malicious = getMaliciousBQP();
+ sp<Surface> surface = new Surface(malicious);
+
+ ASSERT_EQ(NO_ERROR, surface->connect(NATIVE_WINDOW_API_CPU, nullptr, false));
+ ANativeWindow_Buffer buffer;
+ ASSERT_EQ(NO_ERROR, surface->lock(&buffer, nullptr));
+ ASSERT_EQ(NO_ERROR, surface->unlockAndPost());
+
+ malicious->setExpectedSlot(1);
+ malicious->beMalicious(BufferQueueDefs::NUM_BUFFER_SLOTS);
+ ASSERT_EQ(FAILED_TRANSACTION, surface->lock(&buffer, nullptr));
+}
+
+} // namespace test
+} // namespace android
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 08d6715..fcaa23a 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -24,6 +24,7 @@
#include <cutils/properties.h>
#include <gui/BufferItemConsumer.h>
#include <gui/IDisplayEventConnection.h>
+#include <gui/IProducerListener.h>
#include <gui/ISurfaceComposer.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
@@ -320,6 +321,77 @@
ASSERT_EQ(NO_ERROR, window->queueBuffer(window.get(), buffer, fence));
}
+TEST_F(SurfaceTest, GetAndFlushRemovedBuffers) {
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+
+ sp<DummyConsumer> dummyConsumer(new DummyConsumer);
+ consumer->consumerConnect(dummyConsumer, false);
+ consumer->setConsumerName(String8("TestConsumer"));
+
+ sp<Surface> surface = new Surface(producer);
+ sp<ANativeWindow> window(surface);
+ sp<DummyProducerListener> listener = new DummyProducerListener();
+ ASSERT_EQ(OK, surface->connect(
+ NATIVE_WINDOW_API_CPU,
+ /*listener*/listener,
+ /*reportBufferRemoval*/true));
+ const int BUFFER_COUNT = 4;
+ ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(window.get(), BUFFER_COUNT));
+
+ sp<GraphicBuffer> detachedBuffer;
+ sp<Fence> outFence;
+ int fences[BUFFER_COUNT];
+ ANativeWindowBuffer* buffers[BUFFER_COUNT];
+ // Allocate buffers because detachNextBuffer requires allocated buffers
+ for (int i = 0; i < BUFFER_COUNT; i++) {
+ ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffers[i], &fences[i]));
+ }
+ for (int i = 0; i < BUFFER_COUNT; i++) {
+ ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffers[i], fences[i]));
+ }
+
+ // Test detached buffer is correctly reported
+ ASSERT_EQ(NO_ERROR, surface->detachNextBuffer(&detachedBuffer, &outFence));
+ std::vector<sp<GraphicBuffer>> removedBuffers;
+ ASSERT_EQ(OK, surface->getAndFlushRemovedBuffers(&removedBuffers));
+ ASSERT_EQ(1u, removedBuffers.size());
+ ASSERT_EQ(detachedBuffer->handle, removedBuffers.at(0)->handle);
+ // Test the list is flushed one getAndFlushRemovedBuffers returns
+ ASSERT_EQ(OK, surface->getAndFlushRemovedBuffers(&removedBuffers));
+ ASSERT_EQ(0u, removedBuffers.size());
+
+
+ // Test removed buffer list is cleanup after next dequeueBuffer call
+ ASSERT_EQ(NO_ERROR, surface->detachNextBuffer(&detachedBuffer, &outFence));
+ ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffers[0], &fences[0]));
+ ASSERT_EQ(OK, surface->getAndFlushRemovedBuffers(&removedBuffers));
+ ASSERT_EQ(0u, removedBuffers.size());
+ ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffers[0], fences[0]));
+
+ // Test removed buffer list is cleanup after next detachNextBuffer call
+ ASSERT_EQ(NO_ERROR, surface->detachNextBuffer(&detachedBuffer, &outFence));
+ ASSERT_EQ(NO_ERROR, surface->detachNextBuffer(&detachedBuffer, &outFence));
+ ASSERT_EQ(OK, surface->getAndFlushRemovedBuffers(&removedBuffers));
+ ASSERT_EQ(1u, removedBuffers.size());
+ ASSERT_EQ(detachedBuffer->handle, removedBuffers.at(0)->handle);
+
+ // Re-allocate buffers since all buffers are detached up to now
+ for (int i = 0; i < BUFFER_COUNT; i++) {
+ ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffers[i], &fences[i]));
+ }
+ for (int i = 0; i < BUFFER_COUNT; i++) {
+ ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffers[i], fences[i]));
+ }
+
+ ASSERT_EQ(NO_ERROR, surface->detachNextBuffer(&detachedBuffer, &outFence));
+ ASSERT_EQ(NO_ERROR, surface->attachBuffer(detachedBuffer.get()));
+ ASSERT_EQ(OK, surface->getAndFlushRemovedBuffers(&removedBuffers));
+ // Depends on which slot GraphicBufferProducer impl pick, the attach call might
+ // get 0 or 1 buffer removed.
+ ASSERT_LE(removedBuffers.size(), 1u);
+}
class FakeConsumer : public BnConsumerListener {
public:
diff --git a/libs/hwc2on1adapter/Android.bp b/libs/hwc2on1adapter/Android.bp
index 5d7f660..ec9cbf8 100644
--- a/libs/hwc2on1adapter/Android.bp
+++ b/libs/hwc2on1adapter/Android.bp
@@ -14,7 +14,7 @@
cc_library_shared {
name: "libhwc2on1adapter",
- vendor_available: true,
+ vendor: true,
clang: true,
cppflags: [
diff --git a/libs/hwc2on1adapter/CleanSpec.mk b/libs/hwc2on1adapter/CleanSpec.mk
new file mode 100644
index 0000000..7fc2216
--- /dev/null
+++ b/libs/hwc2on1adapter/CleanSpec.mk
@@ -0,0 +1,52 @@
+# 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.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list. These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list. E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libhwc2on1adapter_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libhwc2on1adapter.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/libhwc2on1adapter.so)
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index cdcdc0e..5edd664 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -77,6 +77,7 @@
"libhardware",
"libhidlbase",
"libhidltransport",
+ "libhwbinder",
"libsync",
"libutils",
"liblog",
diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp
index 02d4137..b67f4d9 100644
--- a/libs/ui/Fence.cpp
+++ b/libs/ui/Fence.cpp
@@ -165,7 +165,7 @@
return INVALID_OPERATION;
}
- if (size < 1) {
+ if (size < getFlattenedSize()) {
return NO_MEMORY;
}
diff --git a/libs/ui/Gralloc2.cpp b/libs/ui/Gralloc2.cpp
index f8d9401..87dbaf4 100644
--- a/libs/ui/Gralloc2.cpp
+++ b/libs/ui/Gralloc2.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "Gralloc2"
+#include <hwbinder/IPCThreadState.h>
#include <ui/Gralloc2.h>
#include <log/log.h>
@@ -241,6 +242,9 @@
*outStride = tmpStride;
});
+ // make sure the kernel driver sees BC_FREE_BUFFER and closes the fds now
+ hardware::IPCThreadState::self()->flushCommands();
+
return (ret.isOk()) ? error : kTransactionError;
}
diff --git a/libs/vr/libpdx/Android.bp b/libs/vr/libpdx/Android.bp
index 69300d6..f55e994 100644
--- a/libs/vr/libpdx/Android.bp
+++ b/libs/vr/libpdx/Android.bp
@@ -37,6 +37,7 @@
"libpdx",
"liblog",
"libutils",
+ "libvndksupport",
],
}
diff --git a/services/displayservice/Android.bp b/services/displayservice/Android.bp
new file mode 100644
index 0000000..3442cb2
--- /dev/null
+++ b/services/displayservice/Android.bp
@@ -0,0 +1,46 @@
+//
+// 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.
+//
+
+cc_library_shared {
+ name: "libdisplayservicehidl",
+
+ srcs: [
+ "DisplayService.cpp",
+ "DisplayEventReceiver.cpp",
+ ],
+
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libgui",
+ "libhidlbase",
+ "libhidltransport",
+ "libutils",
+ "android.frameworks.displayservice@1.0",
+ ],
+
+ export_include_dirs: ["include"],
+ export_shared_lib_headers: [
+ "android.frameworks.displayservice@1.0",
+ "libgui",
+ "libutils",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ]
+}
diff --git a/services/displayservice/DisplayEventReceiver.cpp b/services/displayservice/DisplayEventReceiver.cpp
new file mode 100644
index 0000000..5993e44
--- /dev/null
+++ b/services/displayservice/DisplayEventReceiver.cpp
@@ -0,0 +1,170 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "libdisplayservicehidl"
+
+#include <displayservice/DisplayEventReceiver.h>
+
+#include <android-base/logging.h>
+#include <android/frameworks/displayservice/1.0/BpHwEventCallback.h>
+
+#include <thread>
+
+namespace android {
+namespace frameworks {
+namespace displayservice {
+namespace V1_0 {
+namespace implementation {
+
+sp<Looper> getLooper() {
+ static sp<Looper> looper = []() {
+ sp<Looper> looper = new Looper(false /* allowNonCallbacks */);
+
+ std::thread{[&](){
+ int pollResult = looper->pollAll(-1 /* timeout */);
+ LOG(ERROR) << "Looper::pollAll returns unexpected " << pollResult;
+ }}.detach();
+
+ return looper;
+ }();
+
+ return looper;
+}
+
+DisplayEventReceiver::AttachedEvent::AttachedEvent(const sp<IEventCallback> &callback)
+ : mCallback(callback)
+{
+ mLooperAttached = getLooper()->addFd(mFwkReceiver.getFd(),
+ Looper::POLL_CALLBACK,
+ Looper::EVENT_INPUT,
+ this,
+ nullptr);
+}
+
+DisplayEventReceiver::AttachedEvent::~AttachedEvent() {
+ if (!detach()) {
+ LOG(ERROR) << "Could not remove fd from looper.";
+ }
+}
+
+bool DisplayEventReceiver::AttachedEvent::detach() {
+ if (!valid()) {
+ return true;
+ }
+
+ return getLooper()->removeFd(mFwkReceiver.getFd());
+}
+
+bool DisplayEventReceiver::AttachedEvent::valid() const {
+ return mFwkReceiver.initCheck() == OK && mLooperAttached;
+}
+
+DisplayEventReceiver::FwkReceiver &DisplayEventReceiver::AttachedEvent::receiver() {
+ return mFwkReceiver;
+}
+
+int DisplayEventReceiver::AttachedEvent::handleEvent(int fd, int events, void* /* data */) {
+ CHECK(fd == mFwkReceiver.getFd());
+
+ if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
+ LOG(ERROR) << "AttachedEvent handleEvent received error or hangup:" << events;
+ return 0; // remove the callback
+ }
+
+ if (!(events & Looper::EVENT_INPUT)) {
+ LOG(ERROR) << "AttachedEvent handleEvent unhandled poll event:" << events;
+ return 1; // keep the callback
+ }
+
+ constexpr size_t SIZE = 1;
+
+ ssize_t n;
+ FwkReceiver::Event buf[SIZE];
+ while ((n = mFwkReceiver.getEvents(buf, SIZE)) > 0) {
+ for (size_t i = 0; i < static_cast<size_t>(n); ++i) {
+ const FwkReceiver::Event &event = buf[i];
+
+ uint32_t type = event.header.type;
+ uint64_t timestamp = event.header.timestamp;
+
+ switch(buf[i].header.type) {
+ case FwkReceiver::DISPLAY_EVENT_VSYNC: {
+ mCallback->onVsync(timestamp, event.vsync.count);
+ } break;
+ case FwkReceiver::DISPLAY_EVENT_HOTPLUG: {
+ mCallback->onHotplug(timestamp, event.hotplug.connected);
+ } break;
+ default: {
+ LOG(ERROR) << "AttachedEvent handleEvent unknown type: " << type;
+ }
+ }
+ }
+ }
+
+ return 1; // keep on going
+}
+
+Return<Status> DisplayEventReceiver::init(const sp<IEventCallback>& callback) {
+ std::unique_lock<std::mutex> lock(mMutex);
+
+ if (mAttached != nullptr || callback == nullptr) {
+ return Status::BAD_VALUE;
+ }
+
+ mAttached = new AttachedEvent(callback);
+
+ return mAttached->valid() ? Status::SUCCESS : Status::UNKNOWN;
+}
+
+Return<Status> DisplayEventReceiver::setVsyncRate(int32_t count) {
+ std::unique_lock<std::mutex> lock(mMutex);
+
+ if (mAttached == nullptr || count < 0) {
+ return Status::BAD_VALUE;
+ }
+
+ bool success = OK == mAttached->receiver().setVsyncRate(count);
+ return success ? Status::SUCCESS : Status::UNKNOWN;
+}
+
+Return<Status> DisplayEventReceiver::requestNextVsync() {
+ std::unique_lock<std::mutex> lock(mMutex);
+
+ if (mAttached == nullptr) {
+ return Status::BAD_VALUE;
+ }
+
+ bool success = OK == mAttached->receiver().requestNextVsync();
+ return success ? Status::SUCCESS : Status::UNKNOWN;
+}
+
+Return<Status> DisplayEventReceiver::close() {
+ std::unique_lock<std::mutex> lock(mMutex);
+ if (mAttached == nullptr) {
+ return Status::BAD_VALUE;
+ }
+
+ bool success = mAttached->detach();
+ mAttached = nullptr;
+
+ return success ? Status::SUCCESS : Status::UNKNOWN;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace displayservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/displayservice/DisplayService.cpp b/services/displayservice/DisplayService.cpp
new file mode 100644
index 0000000..18418fd
--- /dev/null
+++ b/services/displayservice/DisplayService.cpp
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#include <displayservice/DisplayService.h>
+#include <displayservice/DisplayEventReceiver.h>
+
+namespace android {
+namespace frameworks {
+namespace displayservice {
+namespace V1_0 {
+namespace implementation {
+
+Return<sp<IDisplayEventReceiver>> DisplayService::getEventReceiver() {
+ return new DisplayEventReceiver();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace displayservice
+} // namespace frameworks
+} // namespace android
diff --git a/services/displayservice/include/displayservice/DisplayEventReceiver.h b/services/displayservice/include/displayservice/DisplayEventReceiver.h
new file mode 100644
index 0000000..5d569b6
--- /dev/null
+++ b/services/displayservice/include/displayservice/DisplayEventReceiver.h
@@ -0,0 +1,72 @@
+/*
+ * 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_FRAMEWORKS_DISPLAYSERVICE_V1_0_DISPLAYEVENTRECEIVER_H
+#define ANDROID_FRAMEWORKS_DISPLAYSERVICE_V1_0_DISPLAYEVENTRECEIVER_H
+
+#include <android/frameworks/displayservice/1.0/IDisplayEventReceiver.h>
+#include <gui/DisplayEventReceiver.h>
+#include <hidl/Status.h>
+#include <gui/DisplayEventReceiver.h>
+#include <utils/Looper.h>
+
+#include <mutex>
+
+namespace android {
+namespace frameworks {
+namespace displayservice {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+class DisplayEventReceiver : public IDisplayEventReceiver {
+public:
+ Return<Status> init(const sp<IEventCallback>& callback) override;
+ Return<Status> setVsyncRate(int32_t count) override;
+ Return<Status> requestNextVsync() override;
+ Return<Status> close() override;
+
+private:
+ using FwkReceiver = ::android::DisplayEventReceiver;
+
+ struct AttachedEvent : LooperCallback {
+ AttachedEvent(const sp<IEventCallback> &callback);
+ ~AttachedEvent();
+
+ bool detach();
+ bool valid() const;
+ FwkReceiver &receiver();
+ virtual int handleEvent(int fd, int events, void* /* data */) override;
+
+ private:
+ FwkReceiver mFwkReceiver;
+ sp<IEventCallback> mCallback;
+ bool mLooperAttached;
+ };
+
+ sp<AttachedEvent> mAttached;
+ std::mutex mMutex;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace displayservice
+} // namespace frameworks
+} // namespace android
+
+#endif // ANDROID_FRAMEWORKS_DISPLAYSERVICE_V1_0_DISPLAYEVENTRECEIVER_H
diff --git a/services/displayservice/include/displayservice/DisplayService.h b/services/displayservice/include/displayservice/DisplayService.h
new file mode 100644
index 0000000..9722e71
--- /dev/null
+++ b/services/displayservice/include/displayservice/DisplayService.h
@@ -0,0 +1,42 @@
+/*
+ * 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_FRAMEWORKS_DISPLAYSERVICE_V1_0_DISPLAYSERVICE_H
+#define ANDROID_FRAMEWORKS_DISPLAYSERVICE_V1_0_DISPLAYSERVICE_H
+
+#include <android/frameworks/displayservice/1.0/IDisplayService.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace frameworks {
+namespace displayservice {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+struct DisplayService : public IDisplayService {
+ Return<sp<IDisplayEventReceiver>> getEventReceiver() override;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace displayservice
+} // namespace frameworks
+} // namespace android
+
+#endif // ANDROID_FRAMEWORKS_DISPLAYSERVICE_V1_0_DISPLAYSERVICE_H
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 7bb20ba..95a522d 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -54,11 +54,7 @@
LOCAL_SRC_FILES += \
SurfaceFlinger.cpp \
DisplayHardware/HWComposer.cpp
- ifeq ($(TARGET_USES_HWC2ON1ADAPTER), true)
- LOCAL_CFLAGS += -DBYPASS_IHWC
- endif
else
- LOCAL_CFLAGS += -DBYPASS_IHWC
LOCAL_SRC_FILES += \
SurfaceFlinger_hwc1.cpp \
DisplayHardware/HWComposer_hwc1.cpp
@@ -84,7 +80,6 @@
libdl \
libfmq \
libhardware \
- libhwc2on1adapter \
libhidlbase \
libhidltransport \
libhwbinder \
@@ -133,11 +128,13 @@
main_surfaceflinger.cpp
LOCAL_SHARED_LIBRARIES := \
+ android.frameworks.displayservice@1.0 \
android.hardware.configstore@1.0 \
android.hardware.configstore-utils \
android.hardware.graphics.allocator@2.0 \
libsurfaceflinger \
libcutils \
+ libdisplayservicehidl \
liblog \
libbinder \
libhidlbase \
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 8270c39..0366630 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -88,55 +88,8 @@
// Device methods
-#ifdef BYPASS_IHWC
-Device::Device(hwc2_device_t* device)
- : mHwcDevice(device),
- mCreateVirtualDisplay(nullptr),
- mDestroyVirtualDisplay(nullptr),
- mDump(nullptr),
- mGetMaxVirtualDisplayCount(nullptr),
- mRegisterCallback(nullptr),
- mAcceptDisplayChanges(nullptr),
- mCreateLayer(nullptr),
- mDestroyLayer(nullptr),
- mGetActiveConfig(nullptr),
- mGetChangedCompositionTypes(nullptr),
- mGetColorModes(nullptr),
- mGetDisplayAttribute(nullptr),
- mGetDisplayConfigs(nullptr),
- mGetDisplayName(nullptr),
- mGetDisplayRequests(nullptr),
- mGetDisplayType(nullptr),
- mGetDozeSupport(nullptr),
- mGetHdrCapabilities(nullptr),
- mGetReleaseFences(nullptr),
- mPresentDisplay(nullptr),
- mSetActiveConfig(nullptr),
- mSetClientTarget(nullptr),
- mSetColorMode(nullptr),
- mSetColorTransform(nullptr),
- mSetOutputBuffer(nullptr),
- mSetPowerMode(nullptr),
- mSetVsyncEnabled(nullptr),
- mValidateDisplay(nullptr),
- mSetCursorPosition(nullptr),
- mSetLayerBuffer(nullptr),
- mSetLayerSurfaceDamage(nullptr),
- mSetLayerBlendMode(nullptr),
- mSetLayerColor(nullptr),
- mSetLayerCompositionType(nullptr),
- mSetLayerDataspace(nullptr),
- mSetLayerDisplayFrame(nullptr),
- mSetLayerPlaneAlpha(nullptr),
- mSetLayerSidebandStream(nullptr),
- mSetLayerSourceCrop(nullptr),
- mSetLayerTransform(nullptr),
- mSetLayerVisibleRegion(nullptr),
- mSetLayerZOrder(nullptr),
-#else
Device::Device(bool useVrComposer)
: mComposer(std::make_unique<Hwc2::Composer>(useVrComposer)),
-#endif // BYPASS_IHWC
mCapabilities(),
mDisplays(),
mHotplug(),
@@ -147,18 +100,11 @@
mPendingVsyncs()
{
loadCapabilities();
- loadFunctionPointers();
registerCallbacks();
}
Device::~Device()
{
-#ifdef BYPASS_IHWC
- if (mHwcDevice == nullptr) {
- return;
- }
-#endif
-
for (auto element : mDisplays) {
auto display = element.second.lock();
if (!display) {
@@ -185,36 +131,18 @@
}
}
}
-
-#ifdef BYPASS_IHWC
- hwc2_close(mHwcDevice);
-#endif
}
// Required by HWC2 device
std::string Device::dump() const
{
-#ifdef BYPASS_IHWC
- uint32_t numBytes = 0;
- mDump(mHwcDevice, &numBytes, nullptr);
-
- std::vector<char> buffer(numBytes);
- mDump(mHwcDevice, &numBytes, buffer.data());
-
- return std::string(buffer.data(), buffer.size());
-#else
return mComposer->dumpDebugInfo();
-#endif
}
uint32_t Device::getMaxVirtualDisplayCount() const
{
-#ifdef BYPASS_IHWC
- return mGetMaxVirtualDisplayCount(mHwcDevice);
-#else
return mComposer->getMaxVirtualDisplayCount();
-#endif
}
Error Device::createVirtualDisplay(uint32_t width, uint32_t height,
@@ -223,15 +151,9 @@
ALOGI("Creating virtual display");
hwc2_display_t displayId = 0;
-#ifdef BYPASS_IHWC
- int32_t intFormat = static_cast<int32_t>(*format);
- int32_t intError = mCreateVirtualDisplay(mHwcDevice, width, height,
- &intFormat, &displayId);
-#else
auto intFormat = static_cast<Hwc2::PixelFormat>(*format);
auto intError = mComposer->createVirtualDisplay(width, height,
&intFormat, &displayId);
-#endif
auto error = static_cast<Error>(intError);
if (error != Error::None) {
return error;
@@ -285,9 +207,7 @@
{
if (connected == Connection::Connected) {
if (!display->isConnected()) {
-#ifndef BYPASS_IHWC
mComposer->setClientTargetSlotCount(display->getId());
-#endif
display->loadConfigs();
display->setConnected(true);
}
@@ -345,21 +265,10 @@
{
static_assert(sizeof(Capability) == sizeof(int32_t),
"Capability size has changed");
-#ifdef BYPASS_IHWC
- uint32_t numCapabilities = 0;
- mHwcDevice->getCapabilities(mHwcDevice, &numCapabilities, nullptr);
- std::vector<Capability> capabilities(numCapabilities);
- auto asInt = reinterpret_cast<int32_t*>(capabilities.data());
- mHwcDevice->getCapabilities(mHwcDevice, &numCapabilities, asInt);
- for (auto capability : capabilities) {
- mCapabilities.emplace(capability);
- }
-#else
auto capabilities = mComposer->getCapabilities();
for (auto capability : capabilities) {
mCapabilities.emplace(static_cast<Capability>(capability));
}
-#endif
}
bool Device::hasCapability(HWC2::Capability capability) const
@@ -368,105 +277,6 @@
capability) != mCapabilities.cend();
}
-void Device::loadFunctionPointers()
-{
-#ifdef BYPASS_IHWC
- // For all of these early returns, we log an error message inside
- // loadFunctionPointer specifying which function failed to load
-
- // Display function pointers
- if (!loadFunctionPointer(FunctionDescriptor::CreateVirtualDisplay,
- mCreateVirtualDisplay)) return;
- if (!loadFunctionPointer(FunctionDescriptor::DestroyVirtualDisplay,
- mDestroyVirtualDisplay)) return;
- if (!loadFunctionPointer(FunctionDescriptor::Dump, mDump)) return;
- if (!loadFunctionPointer(FunctionDescriptor::GetMaxVirtualDisplayCount,
- mGetMaxVirtualDisplayCount)) return;
- if (!loadFunctionPointer(FunctionDescriptor::RegisterCallback,
- mRegisterCallback)) return;
-
- // Device function pointers
- if (!loadFunctionPointer(FunctionDescriptor::AcceptDisplayChanges,
- mAcceptDisplayChanges)) return;
- if (!loadFunctionPointer(FunctionDescriptor::CreateLayer,
- mCreateLayer)) return;
- if (!loadFunctionPointer(FunctionDescriptor::DestroyLayer,
- mDestroyLayer)) return;
- if (!loadFunctionPointer(FunctionDescriptor::GetActiveConfig,
- mGetActiveConfig)) return;
- if (!loadFunctionPointer(FunctionDescriptor::GetChangedCompositionTypes,
- mGetChangedCompositionTypes)) return;
- if (!loadFunctionPointer(FunctionDescriptor::GetColorModes,
- mGetColorModes)) return;
- if (!loadFunctionPointer(FunctionDescriptor::GetDisplayAttribute,
- mGetDisplayAttribute)) return;
- if (!loadFunctionPointer(FunctionDescriptor::GetDisplayConfigs,
- mGetDisplayConfigs)) return;
- if (!loadFunctionPointer(FunctionDescriptor::GetDisplayName,
- mGetDisplayName)) return;
- if (!loadFunctionPointer(FunctionDescriptor::GetDisplayRequests,
- mGetDisplayRequests)) return;
- if (!loadFunctionPointer(FunctionDescriptor::GetDisplayType,
- mGetDisplayType)) return;
- if (!loadFunctionPointer(FunctionDescriptor::GetDozeSupport,
- mGetDozeSupport)) return;
- if (!loadFunctionPointer(FunctionDescriptor::GetHdrCapabilities,
- mGetHdrCapabilities)) return;
- if (!loadFunctionPointer(FunctionDescriptor::GetReleaseFences,
- mGetReleaseFences)) return;
- if (!loadFunctionPointer(FunctionDescriptor::PresentDisplay,
- mPresentDisplay)) return;
- if (!loadFunctionPointer(FunctionDescriptor::SetActiveConfig,
- mSetActiveConfig)) return;
- if (!loadFunctionPointer(FunctionDescriptor::SetClientTarget,
- mSetClientTarget)) return;
- if (!loadFunctionPointer(FunctionDescriptor::SetColorMode,
- mSetColorMode)) return;
- if (!loadFunctionPointer(FunctionDescriptor::SetColorTransform,
- mSetColorTransform)) return;
- if (!loadFunctionPointer(FunctionDescriptor::SetOutputBuffer,
- mSetOutputBuffer)) return;
- if (!loadFunctionPointer(FunctionDescriptor::SetPowerMode,
- mSetPowerMode)) return;
- if (!loadFunctionPointer(FunctionDescriptor::SetVsyncEnabled,
- mSetVsyncEnabled)) return;
- if (!loadFunctionPointer(FunctionDescriptor::ValidateDisplay,
- mValidateDisplay)) return;
-
- // Layer function pointers
- if (!loadFunctionPointer(FunctionDescriptor::SetCursorPosition,
- mSetCursorPosition)) return;
- if (!loadFunctionPointer(FunctionDescriptor::SetLayerBuffer,
- mSetLayerBuffer)) return;
- if (!loadFunctionPointer(FunctionDescriptor::SetLayerSurfaceDamage,
- mSetLayerSurfaceDamage)) return;
- if (!loadFunctionPointer(FunctionDescriptor::SetLayerBlendMode,
- mSetLayerBlendMode)) return;
- if (!loadFunctionPointer(FunctionDescriptor::SetLayerColor,
- mSetLayerColor)) return;
- if (!loadFunctionPointer(FunctionDescriptor::SetLayerCompositionType,
- mSetLayerCompositionType)) return;
- if (!loadFunctionPointer(FunctionDescriptor::SetLayerDataspace,
- mSetLayerDataspace)) return;
- if (!loadFunctionPointer(FunctionDescriptor::SetLayerDisplayFrame,
- mSetLayerDisplayFrame)) return;
- if (!loadFunctionPointer(FunctionDescriptor::SetLayerPlaneAlpha,
- mSetLayerPlaneAlpha)) return;
- if (hasCapability(Capability::SidebandStream)) {
- if (!loadFunctionPointer(FunctionDescriptor::SetLayerSidebandStream,
- mSetLayerSidebandStream)) return;
- }
- if (!loadFunctionPointer(FunctionDescriptor::SetLayerSourceCrop,
- mSetLayerSourceCrop)) return;
- if (!loadFunctionPointer(FunctionDescriptor::SetLayerTransform,
- mSetLayerTransform)) return;
- if (!loadFunctionPointer(FunctionDescriptor::SetLayerVisibleRegion,
- mSetLayerVisibleRegion)) return;
- if (!loadFunctionPointer(FunctionDescriptor::SetLayerZOrder,
- mSetLayerZOrder)) return;
-#endif // BYPASS_IHWC
-}
-
namespace {
class ComposerCallback : public Hwc2::IComposerCallback {
public:
@@ -498,14 +308,8 @@
void Device::registerCallbacks()
{
-#ifdef BYPASS_IHWC
- registerCallback<HWC2_PFN_HOTPLUG>(Callback::Hotplug, hotplug_hook);
- registerCallback<HWC2_PFN_REFRESH>(Callback::Refresh, refresh_hook);
- registerCallback<HWC2_PFN_VSYNC>(Callback::Vsync, vsync_hook);
-#else
sp<ComposerCallback> callback = new ComposerCallback(this);
mComposer->registerCallback(callback);
-#endif
}
@@ -514,11 +318,7 @@
void Device::destroyVirtualDisplay(hwc2_display_t display)
{
ALOGI("Destroying virtual display");
-#ifdef BYPASS_IHWC
- int32_t intError = mDestroyVirtualDisplay(mHwcDevice, display);
-#else
auto intError = mComposer->destroyVirtualDisplay(display);
-#endif
auto error = static_cast<Error>(intError);
ALOGE_IF(error != Error::None, "destroyVirtualDisplay(%" PRIu64 ") failed:"
" %s (%d)", display, to_string(error).c_str(), intError);
@@ -535,13 +335,8 @@
{
ALOGV("Created display %" PRIu64, id);
-#ifdef BYPASS_IHWC
- int32_t intError = mDevice.mGetDisplayType(mDevice.mHwcDevice, mId,
- reinterpret_cast<int32_t *>(&mType));
-#else
auto intError = mDevice.mComposer->getDisplayType(mId,
reinterpret_cast<Hwc2::IComposerClient::DisplayType *>(&mType));
-#endif
auto error = static_cast<Error>(intError);
if (error != Error::None) {
ALOGE("getDisplayType(%" PRIu64 ") failed: %s (%d)",
@@ -588,22 +383,14 @@
Error Display::acceptChanges()
{
-#ifdef BYPASS_IHWC
- int32_t intError = mDevice.mAcceptDisplayChanges(mDevice.mHwcDevice, mId);
-#else
auto intError = mDevice.mComposer->acceptDisplayChanges(mId);
-#endif
return static_cast<Error>(intError);
}
Error Display::createLayer(std::shared_ptr<Layer>* outLayer)
{
hwc2_layer_t layerId = 0;
-#ifdef BYPASS_IHWC
- int32_t intError = mDevice.mCreateLayer(mDevice.mHwcDevice, mId, &layerId);
-#else
auto intError = mDevice.mComposer->createLayer(mId, &layerId);
-#endif
auto error = static_cast<Error>(intError);
if (error != Error::None) {
return error;
@@ -620,12 +407,7 @@
{
ALOGV("[%" PRIu64 "] getActiveConfig", mId);
hwc2_config_t configId = 0;
-#ifdef BYPASS_IHWC
- int32_t intError = mDevice.mGetActiveConfig(mDevice.mHwcDevice, mId,
- &configId);
-#else
auto intError = mDevice.mComposer->getActiveConfig(mId, &configId);
-#endif
auto error = static_cast<Error>(intError);
if (error != Error::None) {
@@ -650,27 +432,12 @@
Error Display::getChangedCompositionTypes(
std::unordered_map<std::shared_ptr<Layer>, Composition>* outTypes)
{
-#ifdef BYPASS_IHWC
- uint32_t numElements = 0;
- int32_t intError = mDevice.mGetChangedCompositionTypes(mDevice.mHwcDevice,
- mId, &numElements, nullptr, nullptr);
- auto error = static_cast<Error>(intError);
- if (error != Error::None) {
- return error;
- }
-
- std::vector<hwc2_layer_t> layerIds(numElements);
- std::vector<int32_t> types(numElements);
- intError = mDevice.mGetChangedCompositionTypes(mDevice.mHwcDevice, mId,
- &numElements, layerIds.data(), types.data());
-#else
std::vector<Hwc2::Layer> layerIds;
std::vector<Hwc2::IComposerClient::Composition> types;
auto intError = mDevice.mComposer->getChangedCompositionTypes(mId,
&layerIds, &types);
uint32_t numElements = layerIds.size();
auto error = static_cast<Error>(intError);
-#endif
error = static_cast<Error>(intError);
if (error != Error::None) {
return error;
@@ -696,25 +463,10 @@
Error Display::getColorModes(std::vector<android_color_mode_t>* outModes) const
{
-#ifdef BYPASS_IHWC
- uint32_t numModes = 0;
- int32_t intError = mDevice.mGetColorModes(mDevice.mHwcDevice, mId,
- &numModes, nullptr);
- auto error = static_cast<Error>(intError);
- if (error != Error::None) {
- return error;
- }
-
- std::vector<int32_t> modes(numModes);
- intError = mDevice.mGetColorModes(mDevice.mHwcDevice, mId, &numModes,
- modes.data());
- error = static_cast<Error>(intError);
-#else
std::vector<Hwc2::ColorMode> modes;
auto intError = mDevice.mComposer->getColorModes(mId, &modes);
uint32_t numModes = modes.size();
auto error = static_cast<Error>(intError);
-#endif
if (error != Error::None) {
return error;
}
@@ -737,52 +489,14 @@
Error Display::getName(std::string* outName) const
{
-#ifdef BYPASS_IHWC
- uint32_t size;
- int32_t intError = mDevice.mGetDisplayName(mDevice.mHwcDevice, mId, &size,
- nullptr);
- auto error = static_cast<Error>(intError);
- if (error != Error::None) {
- return error;
- }
-
- std::vector<char> rawName(size);
- intError = mDevice.mGetDisplayName(mDevice.mHwcDevice, mId, &size,
- rawName.data());
- error = static_cast<Error>(intError);
- if (error != Error::None) {
- return error;
- }
-
- *outName = std::string(rawName.cbegin(), rawName.cend());
- return Error::None;
-#else
auto intError = mDevice.mComposer->getDisplayName(mId, outName);
return static_cast<Error>(intError);
-#endif
}
Error Display::getRequests(HWC2::DisplayRequest* outDisplayRequests,
std::unordered_map<std::shared_ptr<Layer>, LayerRequest>*
outLayerRequests)
{
-#ifdef BYPASS_IHWC
- int32_t intDisplayRequests = 0;
- uint32_t numElements = 0;
- int32_t intError = mDevice.mGetDisplayRequests(mDevice.mHwcDevice, mId,
- &intDisplayRequests, &numElements, nullptr, nullptr);
- auto error = static_cast<Error>(intError);
- if (error != Error::None) {
- return error;
- }
-
- std::vector<hwc2_layer_t> layerIds(numElements);
- std::vector<int32_t> layerRequests(numElements);
- intError = mDevice.mGetDisplayRequests(mDevice.mHwcDevice, mId,
- &intDisplayRequests, &numElements, layerIds.data(),
- layerRequests.data());
- error = static_cast<Error>(intError);
-#else
uint32_t intDisplayRequests;
std::vector<Hwc2::Layer> layerIds;
std::vector<uint32_t> layerRequests;
@@ -790,7 +504,6 @@
&intDisplayRequests, &layerIds, &layerRequests);
uint32_t numElements = layerIds.size();
auto error = static_cast<Error>(intError);
-#endif
if (error != Error::None) {
return error;
}
@@ -821,14 +534,8 @@
Error Display::supportsDoze(bool* outSupport) const
{
-#ifdef BYPASS_IHWC
- int32_t intSupport = 0;
- int32_t intError = mDevice.mGetDozeSupport(mDevice.mHwcDevice, mId,
- &intSupport);
-#else
bool intSupport = false;
auto intError = mDevice.mComposer->getDozeSupport(mId, &intSupport);
-#endif
auto error = static_cast<Error>(intError);
if (error != Error::None) {
return error;
@@ -844,20 +551,6 @@
float maxLuminance = -1.0f;
float maxAverageLuminance = -1.0f;
float minLuminance = -1.0f;
-#ifdef BYPASS_IHWC
- int32_t intError = mDevice.mGetHdrCapabilities(mDevice.mHwcDevice, mId,
- &numTypes, nullptr, &maxLuminance, &maxAverageLuminance,
- &minLuminance);
- auto error = static_cast<HWC2::Error>(intError);
- if (error != Error::None) {
- return error;
- }
-
- std::vector<int32_t> types(numTypes);
- intError = mDevice.mGetHdrCapabilities(mDevice.mHwcDevice, mId, &numTypes,
- types.data(), &maxLuminance, &maxAverageLuminance, &minLuminance);
- error = static_cast<HWC2::Error>(intError);
-#else
std::vector<Hwc2::Hdr> intTypes;
auto intError = mDevice.mComposer->getHdrCapabilities(mId, &intTypes,
&maxLuminance, &maxAverageLuminance, &minLuminance);
@@ -868,7 +561,6 @@
types.push_back(static_cast<int32_t>(type));
}
numTypes = types.size();
-#endif
if (error != Error::None) {
return error;
}
@@ -881,28 +573,12 @@
Error Display::getReleaseFences(
std::unordered_map<std::shared_ptr<Layer>, sp<Fence>>* outFences) const
{
-#ifdef BYPASS_IHWC
- uint32_t numElements = 0;
- int32_t intError = mDevice.mGetReleaseFences(mDevice.mHwcDevice, mId,
- &numElements, nullptr, nullptr);
- auto error = static_cast<Error>(intError);
- if (error != Error::None) {
- return error;
- }
-
- std::vector<hwc2_layer_t> layerIds(numElements);
- std::vector<int32_t> fenceFds(numElements);
- intError = mDevice.mGetReleaseFences(mDevice.mHwcDevice, mId, &numElements,
- layerIds.data(), fenceFds.data());
- error = static_cast<Error>(intError);
-#else
std::vector<Hwc2::Layer> layerIds;
std::vector<int> fenceFds;
auto intError = mDevice.mComposer->getReleaseFences(mId,
&layerIds, &fenceFds);
auto error = static_cast<Error>(intError);
uint32_t numElements = layerIds.size();
-#endif
if (error != Error::None) {
return error;
}
@@ -917,6 +593,9 @@
} else {
ALOGE("getReleaseFences: invalid layer %" PRIu64
" found on display %" PRIu64, layerIds[element], mId);
+ for (; element < numElements; ++element) {
+ close(fenceFds[element]);
+ }
return Error::BadLayer;
}
}
@@ -928,12 +607,7 @@
Error Display::present(sp<Fence>* outPresentFence)
{
int32_t presentFenceFd = -1;
-#ifdef BYPASS_IHWC
- int32_t intError = mDevice.mPresentDisplay(mDevice.mHwcDevice, mId,
- &presentFenceFd);
-#else
auto intError = mDevice.mComposer->presentDisplay(mId, &presentFenceFd);
-#endif
auto error = static_cast<Error>(intError);
if (error != Error::None) {
return error;
@@ -951,12 +625,7 @@
config->getDisplayId(), mId);
return Error::BadConfig;
}
-#ifdef BYPASS_IHWC
- int32_t intError = mDevice.mSetActiveConfig(mDevice.mHwcDevice, mId,
- config->getId());
-#else
auto intError = mDevice.mComposer->setActiveConfig(mId, config->getId());
-#endif
return static_cast<Error>(intError);
}
@@ -965,44 +634,24 @@
{
// TODO: Properly encode client target surface damage
int32_t fenceFd = acquireFence->dup();
-#ifdef BYPASS_IHWC
- (void) slot;
- buffer_handle_t handle = nullptr;
- if (target.get() && target->getNativeBuffer()) {
- handle = target->getNativeBuffer()->handle;
- }
-
- int32_t intError = mDevice.mSetClientTarget(mDevice.mHwcDevice, mId, handle,
- fenceFd, static_cast<int32_t>(dataspace), {0, nullptr});
-#else
auto intError = mDevice.mComposer->setClientTarget(mId, slot, target,
fenceFd, static_cast<Hwc2::Dataspace>(dataspace),
std::vector<Hwc2::IComposerClient::Rect>());
-#endif
return static_cast<Error>(intError);
}
Error Display::setColorMode(android_color_mode_t mode)
{
-#ifdef BYPASS_IHWC
- int32_t intError = mDevice.mSetColorMode(mDevice.mHwcDevice, mId, mode);
-#else
auto intError = mDevice.mComposer->setColorMode(mId,
static_cast<Hwc2::ColorMode>(mode));
-#endif
return static_cast<Error>(intError);
}
Error Display::setColorTransform(const android::mat4& matrix,
android_color_transform_t hint)
{
-#ifdef BYPASS_IHWC
- int32_t intError = mDevice.mSetColorTransform(mDevice.mHwcDevice, mId,
- matrix.asArray(), static_cast<int32_t>(hint));
-#else
auto intError = mDevice.mComposer->setColorTransform(mId,
matrix.asArray(), static_cast<Hwc2::ColorTransform>(hint));
-#endif
return static_cast<Error>(intError);
}
@@ -1011,38 +660,22 @@
{
int32_t fenceFd = releaseFence->dup();
auto handle = buffer->getNativeBuffer()->handle;
-#ifdef BYPASS_IHWC
- int32_t intError = mDevice.mSetOutputBuffer(mDevice.mHwcDevice, mId, handle,
- fenceFd);
-#else
auto intError = mDevice.mComposer->setOutputBuffer(mId, handle, fenceFd);
-#endif
close(fenceFd);
return static_cast<Error>(intError);
}
Error Display::setPowerMode(PowerMode mode)
{
-#ifdef BYPASS_IHWC
- auto intMode = static_cast<int32_t>(mode);
- int32_t intError = mDevice.mSetPowerMode(mDevice.mHwcDevice, mId, intMode);
-#else
auto intMode = static_cast<Hwc2::IComposerClient::PowerMode>(mode);
auto intError = mDevice.mComposer->setPowerMode(mId, intMode);
-#endif
return static_cast<Error>(intError);
}
Error Display::setVsyncEnabled(Vsync enabled)
{
-#ifdef BYPASS_IHWC
- auto intEnabled = static_cast<int32_t>(enabled);
- int32_t intError = mDevice.mSetVsyncEnabled(mDevice.mHwcDevice, mId,
- intEnabled);
-#else
auto intEnabled = static_cast<Hwc2::IComposerClient::Vsync>(enabled);
auto intError = mDevice.mComposer->setVsyncEnabled(mId, intEnabled);
-#endif
return static_cast<Error>(intError);
}
@@ -1050,13 +683,8 @@
{
uint32_t numTypes = 0;
uint32_t numRequests = 0;
-#ifdef BYPASS_IHWC
- int32_t intError = mDevice.mValidateDisplay(mDevice.mHwcDevice, mId,
- &numTypes, &numRequests);
-#else
auto intError = mDevice.mComposer->validateDisplay(mId,
&numTypes, &numRequests);
-#endif
auto error = static_cast<Error>(intError);
if (error != Error::None && error != Error::HasChanges) {
return error;
@@ -1072,14 +700,9 @@
int32_t Display::getAttribute(hwc2_config_t configId, Attribute attribute)
{
int32_t value = 0;
-#ifdef BYPASS_IHWC
- int32_t intError = mDevice.mGetDisplayAttribute(mDevice.mHwcDevice, mId,
- configId, static_cast<int32_t>(attribute), &value);
-#else
auto intError = mDevice.mComposer->getDisplayAttribute(mId, configId,
static_cast<Hwc2::IComposerClient::Attribute>(attribute),
&value);
-#endif
auto error = static_cast<Error>(intError);
if (error != Error::None) {
ALOGE("getDisplayAttribute(%" PRIu64 ", %u, %s) failed: %s (%d)", mId,
@@ -1108,26 +731,9 @@
{
ALOGV("[%" PRIu64 "] loadConfigs", mId);
-#ifdef BYPASS_IHWC
- uint32_t numConfigs = 0;
- int32_t intError = mDevice.mGetDisplayConfigs(mDevice.mHwcDevice, mId,
- &numConfigs, nullptr);
- auto error = static_cast<Error>(intError);
- if (error != Error::None) {
- ALOGE("[%" PRIu64 "] getDisplayConfigs [1] failed: %s (%d)", mId,
- to_string(error).c_str(), intError);
- return;
- }
-
- std::vector<hwc2_config_t> configIds(numConfigs);
- intError = mDevice.mGetDisplayConfigs(mDevice.mHwcDevice, mId, &numConfigs,
- configIds.data());
- error = static_cast<Error>(intError);
-#else
std::vector<Hwc2::Config> configIds;
auto intError = mDevice.mComposer->getDisplayConfigs(mId, &configIds);
auto error = static_cast<Error>(intError);
-#endif
if (error != Error::None) {
ALOGE("[%" PRIu64 "] getDisplayConfigs [2] failed: %s (%d)", mId,
to_string(error).c_str(), intError);
@@ -1143,11 +749,7 @@
void Display::destroyLayer(hwc2_layer_t layerId)
{
-#ifdef BYPASS_IHWC
- int32_t intError = mDevice.mDestroyLayer(mDevice.mHwcDevice, mId, layerId);
-#else
auto intError =mDevice.mComposer->destroyLayer(mId, layerId);
-#endif
auto error = static_cast<Error>(intError);
ALOGE_IF(error != Error::None, "destroyLayer(%" PRIu64 ", %" PRIu64 ")"
" failed: %s (%d)", mId, layerId, to_string(error).c_str(),
@@ -1189,13 +791,8 @@
Error Layer::setCursorPosition(int32_t x, int32_t y)
{
-#ifdef BYPASS_IHWC
- int32_t intError = mDevice.mSetCursorPosition(mDevice.mHwcDevice,
- mDisplayId, mId, x, y);
-#else
auto intError = mDevice.mComposer->setCursorPosition(mDisplayId,
mId, x, y);
-#endif
return static_cast<Error>(intError);
}
@@ -1203,19 +800,8 @@
const sp<Fence>& acquireFence)
{
int32_t fenceFd = acquireFence->dup();
-#ifdef BYPASS_IHWC
- (void) slot;
- buffer_handle_t handle = nullptr;
- if (buffer.get() && buffer->getNativeBuffer()) {
- handle = buffer->getNativeBuffer()->handle;
- }
-
- int32_t intError = mDevice.mSetLayerBuffer(mDevice.mHwcDevice, mDisplayId,
- mId, handle, fenceFd);
-#else
auto intError = mDevice.mComposer->setLayerBuffer(mDisplayId,
mId, slot, buffer, fenceFd);
-#endif
return static_cast<Error>(intError);
}
@@ -1223,44 +809,22 @@
{
// We encode default full-screen damage as INVALID_RECT upstream, but as 0
// rects for HWC
-#ifdef BYPASS_IHWC
- int32_t intError = 0;
-#else
Hwc2::Error intError = Hwc2::Error::NONE;
-#endif
if (damage.isRect() && damage.getBounds() == Rect::INVALID_RECT) {
-#ifdef BYPASS_IHWC
- intError = mDevice.mSetLayerSurfaceDamage(mDevice.mHwcDevice,
- mDisplayId, mId, {0, nullptr});
-#else
intError = mDevice.mComposer->setLayerSurfaceDamage(mDisplayId,
mId, std::vector<Hwc2::IComposerClient::Rect>());
-#endif
} else {
size_t rectCount = 0;
auto rectArray = damage.getArray(&rectCount);
-#ifdef BYPASS_IHWC
- std::vector<hwc_rect_t> hwcRects;
-#else
std::vector<Hwc2::IComposerClient::Rect> hwcRects;
-#endif
for (size_t rect = 0; rect < rectCount; ++rect) {
hwcRects.push_back({rectArray[rect].left, rectArray[rect].top,
rectArray[rect].right, rectArray[rect].bottom});
}
-#ifdef BYPASS_IHWC
- hwc_region_t hwcRegion = {};
- hwcRegion.numRects = rectCount;
- hwcRegion.rects = hwcRects.data();
-
- intError = mDevice.mSetLayerSurfaceDamage(mDevice.mHwcDevice,
- mDisplayId, mId, hwcRegion);
-#else
intError = mDevice.mComposer->setLayerSurfaceDamage(mDisplayId,
mId, hwcRects);
-#endif
}
return static_cast<Error>(intError);
@@ -1268,83 +832,49 @@
Error Layer::setBlendMode(BlendMode mode)
{
-#ifdef BYPASS_IHWC
- auto intMode = static_cast<int32_t>(mode);
- int32_t intError = mDevice.mSetLayerBlendMode(mDevice.mHwcDevice,
- mDisplayId, mId, intMode);
-#else
auto intMode = static_cast<Hwc2::IComposerClient::BlendMode>(mode);
auto intError = mDevice.mComposer->setLayerBlendMode(mDisplayId,
mId, intMode);
-#endif
return static_cast<Error>(intError);
}
Error Layer::setColor(hwc_color_t color)
{
-#ifdef BYPASS_IHWC
- int32_t intError = mDevice.mSetLayerColor(mDevice.mHwcDevice, mDisplayId,
- mId, color);
-#else
Hwc2::IComposerClient::Color hwcColor{color.r, color.g, color.b, color.a};
auto intError = mDevice.mComposer->setLayerColor(mDisplayId,
mId, hwcColor);
-#endif
return static_cast<Error>(intError);
}
Error Layer::setCompositionType(Composition type)
{
-#ifdef BYPASS_IHWC
- auto intType = static_cast<int32_t>(type);
- int32_t intError = mDevice.mSetLayerCompositionType(mDevice.mHwcDevice,
- mDisplayId, mId, intType);
-#else
auto intType = static_cast<Hwc2::IComposerClient::Composition>(type);
auto intError = mDevice.mComposer->setLayerCompositionType(mDisplayId,
mId, intType);
-#endif
return static_cast<Error>(intError);
}
Error Layer::setDataspace(android_dataspace_t dataspace)
{
-#ifdef BYPASS_IHWC
- auto intDataspace = static_cast<int32_t>(dataspace);
- int32_t intError = mDevice.mSetLayerDataspace(mDevice.mHwcDevice,
- mDisplayId, mId, intDataspace);
-#else
auto intDataspace = static_cast<Hwc2::Dataspace>(dataspace);
auto intError = mDevice.mComposer->setLayerDataspace(mDisplayId,
mId, intDataspace);
-#endif
return static_cast<Error>(intError);
}
Error Layer::setDisplayFrame(const Rect& frame)
{
-#ifdef BYPASS_IHWC
- hwc_rect_t hwcRect{frame.left, frame.top, frame.right, frame.bottom};
- int32_t intError = mDevice.mSetLayerDisplayFrame(mDevice.mHwcDevice,
- mDisplayId, mId, hwcRect);
-#else
Hwc2::IComposerClient::Rect hwcRect{frame.left, frame.top,
frame.right, frame.bottom};
auto intError = mDevice.mComposer->setLayerDisplayFrame(mDisplayId,
mId, hwcRect);
-#endif
return static_cast<Error>(intError);
}
Error Layer::setPlaneAlpha(float alpha)
{
-#ifdef BYPASS_IHWC
- int32_t intError = mDevice.mSetLayerPlaneAlpha(mDevice.mHwcDevice,
- mDisplayId, mId, alpha);
-#else
auto intError = mDevice.mComposer->setLayerPlaneAlpha(mDisplayId,
mId, alpha);
-#endif
return static_cast<Error>(intError);
}
@@ -1355,42 +885,25 @@
"device supports sideband streams");
return Error::Unsupported;
}
-#ifdef BYPASS_IHWC
- int32_t intError = mDevice.mSetLayerSidebandStream(mDevice.mHwcDevice,
- mDisplayId, mId, stream);
-#else
auto intError = mDevice.mComposer->setLayerSidebandStream(mDisplayId,
mId, stream);
-#endif
return static_cast<Error>(intError);
}
Error Layer::setSourceCrop(const FloatRect& crop)
{
-#ifdef BYPASS_IHWC
- hwc_frect_t hwcRect{crop.left, crop.top, crop.right, crop.bottom};
- int32_t intError = mDevice.mSetLayerSourceCrop(mDevice.mHwcDevice,
- mDisplayId, mId, hwcRect);
-#else
Hwc2::IComposerClient::FRect hwcRect{
crop.left, crop.top, crop.right, crop.bottom};
auto intError = mDevice.mComposer->setLayerSourceCrop(mDisplayId,
mId, hwcRect);
-#endif
return static_cast<Error>(intError);
}
Error Layer::setTransform(Transform transform)
{
-#ifdef BYPASS_IHWC
- auto intTransform = static_cast<int32_t>(transform);
- int32_t intError = mDevice.mSetLayerTransform(mDevice.mHwcDevice,
- mDisplayId, mId, intTransform);
-#else
auto intTransform = static_cast<Hwc2::Transform>(transform);
auto intError = mDevice.mComposer->setLayerTransform(mDisplayId,
mId, intTransform);
-#endif
return static_cast<Error>(intError);
}
@@ -1399,50 +912,26 @@
size_t rectCount = 0;
auto rectArray = region.getArray(&rectCount);
-#ifdef BYPASS_IHWC
- std::vector<hwc_rect_t> hwcRects;
-#else
std::vector<Hwc2::IComposerClient::Rect> hwcRects;
-#endif
for (size_t rect = 0; rect < rectCount; ++rect) {
hwcRects.push_back({rectArray[rect].left, rectArray[rect].top,
rectArray[rect].right, rectArray[rect].bottom});
}
-#ifdef BYPASS_IHWC
- hwc_region_t hwcRegion = {};
- hwcRegion.numRects = rectCount;
- hwcRegion.rects = hwcRects.data();
-
- int32_t intError = mDevice.mSetLayerVisibleRegion(mDevice.mHwcDevice,
- mDisplayId, mId, hwcRegion);
-#else
auto intError = mDevice.mComposer->setLayerVisibleRegion(mDisplayId,
mId, hwcRects);
-#endif
return static_cast<Error>(intError);
}
Error Layer::setZOrder(uint32_t z)
{
-#ifdef BYPASS_IHWC
- int32_t intError = mDevice.mSetLayerZOrder(mDevice.mHwcDevice, mDisplayId,
- mId, z);
-#else
auto intError = mDevice.mComposer->setLayerZOrder(mDisplayId, mId, z);
-#endif
return static_cast<Error>(intError);
}
Error Layer::setInfo(uint32_t type, uint32_t appId)
{
-#ifdef BYPASS_IHWC
- (void)type;
- (void)appId;
- int32_t intError = 0;
-#else
auto intError = mDevice.mComposer->setLayerInfo(mDisplayId, mId, type, appId);
-#endif
return static_cast<Error>(intError);
}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 643b1e0..97582a7 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -62,14 +62,10 @@
class Device
{
public:
-#ifdef BYPASS_IHWC
- explicit Device(hwc2_device_t* device);
-#else
// useVrComposer is passed to the composer HAL. When true, the composer HAL
// will use the vr composer service, otherwise it uses the real hardware
// composer.
Device(bool useVrComposer);
-#endif
~Device();
friend class HWC2::Display;
@@ -107,43 +103,12 @@
bool hasCapability(HWC2::Capability capability) const;
-#ifdef BYPASS_IHWC
- android::Hwc2::Composer* getComposer() { return nullptr; }
-#else
android::Hwc2::Composer* getComposer() { return mComposer.get(); }
-#endif
private:
// Initialization methods
-#ifdef BYPASS_IHWC
- template <typename PFN>
- [[clang::warn_unused_result]] bool loadFunctionPointer(
- FunctionDescriptor desc, PFN& outPFN) {
- auto intDesc = static_cast<int32_t>(desc);
- auto pfn = mHwcDevice->getFunction(mHwcDevice, intDesc);
- if (pfn != nullptr) {
- outPFN = reinterpret_cast<PFN>(pfn);
- return true;
- } else {
- ALOGE("Failed to load function %s", to_string(desc).c_str());
- return false;
- }
- }
-
- template <typename PFN, typename HOOK>
- void registerCallback(Callback callback, HOOK hook) {
- static_assert(std::is_same<PFN, HOOK>::value,
- "Incompatible function pointer");
- auto intCallback = static_cast<int32_t>(callback);
- auto callbackData = static_cast<hwc2_callback_data_t>(this);
- auto pfn = reinterpret_cast<hwc2_function_pointer_t>(hook);
- mRegisterCallback(mHwcDevice, intCallback, callbackData, pfn);
- }
-#endif
-
void loadCapabilities();
- void loadFunctionPointers();
void registerCallbacks();
// For use by Display
@@ -151,60 +116,7 @@
void destroyVirtualDisplay(hwc2_display_t display);
// Member variables
-
-#ifdef BYPASS_IHWC
- hwc2_device_t* mHwcDevice;
-
- // Device function pointers
- HWC2_PFN_CREATE_VIRTUAL_DISPLAY mCreateVirtualDisplay;
- HWC2_PFN_DESTROY_VIRTUAL_DISPLAY mDestroyVirtualDisplay;
- HWC2_PFN_DUMP mDump;
- HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT mGetMaxVirtualDisplayCount;
- HWC2_PFN_REGISTER_CALLBACK mRegisterCallback;
-
- // Display function pointers
- HWC2_PFN_ACCEPT_DISPLAY_CHANGES mAcceptDisplayChanges;
- HWC2_PFN_CREATE_LAYER mCreateLayer;
- HWC2_PFN_DESTROY_LAYER mDestroyLayer;
- HWC2_PFN_GET_ACTIVE_CONFIG mGetActiveConfig;
- HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES mGetChangedCompositionTypes;
- HWC2_PFN_GET_COLOR_MODES mGetColorModes;
- HWC2_PFN_GET_DISPLAY_ATTRIBUTE mGetDisplayAttribute;
- HWC2_PFN_GET_DISPLAY_CONFIGS mGetDisplayConfigs;
- HWC2_PFN_GET_DISPLAY_NAME mGetDisplayName;
- HWC2_PFN_GET_DISPLAY_REQUESTS mGetDisplayRequests;
- HWC2_PFN_GET_DISPLAY_TYPE mGetDisplayType;
- HWC2_PFN_GET_DOZE_SUPPORT mGetDozeSupport;
- HWC2_PFN_GET_HDR_CAPABILITIES mGetHdrCapabilities;
- HWC2_PFN_GET_RELEASE_FENCES mGetReleaseFences;
- HWC2_PFN_PRESENT_DISPLAY mPresentDisplay;
- HWC2_PFN_SET_ACTIVE_CONFIG mSetActiveConfig;
- HWC2_PFN_SET_CLIENT_TARGET mSetClientTarget;
- HWC2_PFN_SET_COLOR_MODE mSetColorMode;
- HWC2_PFN_SET_COLOR_TRANSFORM mSetColorTransform;
- HWC2_PFN_SET_OUTPUT_BUFFER mSetOutputBuffer;
- HWC2_PFN_SET_POWER_MODE mSetPowerMode;
- HWC2_PFN_SET_VSYNC_ENABLED mSetVsyncEnabled;
- HWC2_PFN_VALIDATE_DISPLAY mValidateDisplay;
-
- // Layer function pointers
- HWC2_PFN_SET_CURSOR_POSITION mSetCursorPosition;
- HWC2_PFN_SET_LAYER_BUFFER mSetLayerBuffer;
- HWC2_PFN_SET_LAYER_SURFACE_DAMAGE mSetLayerSurfaceDamage;
- HWC2_PFN_SET_LAYER_BLEND_MODE mSetLayerBlendMode;
- HWC2_PFN_SET_LAYER_COLOR mSetLayerColor;
- HWC2_PFN_SET_LAYER_COMPOSITION_TYPE mSetLayerCompositionType;
- HWC2_PFN_SET_LAYER_DATASPACE mSetLayerDataspace;
- HWC2_PFN_SET_LAYER_DISPLAY_FRAME mSetLayerDisplayFrame;
- HWC2_PFN_SET_LAYER_PLANE_ALPHA mSetLayerPlaneAlpha;
- HWC2_PFN_SET_LAYER_SIDEBAND_STREAM mSetLayerSidebandStream;
- HWC2_PFN_SET_LAYER_SOURCE_CROP mSetLayerSourceCrop;
- HWC2_PFN_SET_LAYER_TRANSFORM mSetLayerTransform;
- HWC2_PFN_SET_LAYER_VISIBLE_REGION mSetLayerVisibleRegion;
- HWC2_PFN_SET_LAYER_Z_ORDER mSetLayerZOrder;
-#else
std::unique_ptr<android::Hwc2::Composer> mComposer;
-#endif // BYPASS_IHWC
std::unordered_set<Capability> mCapabilities;
std::unordered_map<hwc2_display_t, std::weak_ptr<Display>> mDisplays;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 04ab78f..42be935 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -47,7 +47,6 @@
#include <log/log.h>
#include "HWComposer.h"
-#include "hwc2on1adapter/HWC2On1Adapter.h"
#include "HWC2.h"
#include "ComposerHal.h"
@@ -61,8 +60,7 @@
// ---------------------------------------------------------------------------
HWComposer::HWComposer(bool useVrComposer)
- : mAdapter(),
- mHwcDevice(),
+ : mHwcDevice(),
mDisplayData(2),
mFreeDisplaySlots(),
mHwcDisplaySlots(),
@@ -108,45 +106,7 @@
void HWComposer::loadHwcModule(bool useVrComposer)
{
ALOGV("loadHwcModule");
-
-#ifdef BYPASS_IHWC
- (void)useVrComposer; // Silence unused parameter warning.
-
- hw_module_t const* module;
-
- if (hw_get_module(HWC_HARDWARE_MODULE_ID, &module) != 0) {
- ALOGE("%s module not found, aborting", HWC_HARDWARE_MODULE_ID);
- abort();
- }
-
- hw_device_t* device = nullptr;
- int error = module->methods->open(module, HWC_HARDWARE_COMPOSER, &device);
- if (error != 0) {
- ALOGE("Failed to open HWC device (%s), aborting", strerror(-error));
- abort();
- }
-
- uint32_t majorVersion = (device->version >> 24) & 0xF;
- if (majorVersion == 2) {
- mHwcDevice = std::make_unique<HWC2::Device>(
- reinterpret_cast<hwc2_device_t*>(device));
- } else {
- mAdapter = std::make_unique<HWC2On1Adapter>(
- reinterpret_cast<hwc_composer_device_1_t*>(device));
- uint8_t minorVersion = mAdapter->getHwc1MinorVersion();
- if (minorVersion < 1) {
- ALOGE("Cannot adapt to HWC version %d.%d",
- static_cast<int32_t>((minorVersion >> 8) & 0xF),
- static_cast<int32_t>(minorVersion & 0xF));
- abort();
- }
- mHwcDevice = std::make_unique<HWC2::Device>(
- static_cast<hwc2_device_t*>(mAdapter.get()));
- }
-#else
mHwcDevice = std::make_unique<HWC2::Device>(useVrComposer);
-#endif
-
mRemainingHwcVirtualDisplays = mHwcDevice->getMaxVirtualDisplayCount();
}
@@ -870,11 +830,7 @@
*/
bool HWComposer::isUsingVrComposer() const {
-#ifdef BYPASS_IHWC
- return false;
-#else
return getComposer()->isUsingVrComposer();
-#endif
}
void HWComposer::dump(String8& result) const {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 631af14..3eb968d 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -58,7 +58,6 @@
class Fence;
class FloatRect;
class GraphicBuffer;
-class HWC2On1Adapter;
class NativeHandle;
class Region;
class String8;
@@ -205,7 +204,6 @@
HWC2::Vsync vsyncEnabled;
};
- std::unique_ptr<HWC2On1Adapter> mAdapter;
std::unique_ptr<HWC2::Device> mHwcDevice;
std::vector<DisplayData> mDisplayData;
std::set<size_t> mFreeDisplaySlots;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposerBufferCache.cpp b/services/surfaceflinger/DisplayHardware/HWComposerBufferCache.cpp
index 6b91224..a234b63 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposerBufferCache.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposerBufferCache.cpp
@@ -29,10 +29,6 @@
const sp<GraphicBuffer>& buffer,
uint32_t* outSlot, sp<GraphicBuffer>* outBuffer)
{
-#ifdef BYPASS_IHWC
- *outSlot = slot;
- *outBuffer = buffer;
-#else
if (slot == BufferQueue::INVALID_BUFFER_SLOT || slot < 0) {
// default to slot 0
slot = 0;
@@ -53,7 +49,6 @@
// update cache
mBuffers[slot] = buffer;
}
-#endif
}
} // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 50d8998..d5498ed 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -298,6 +298,11 @@
}
mSurfaceFlingerConsumer->abandon();
+
+#ifdef USE_HWC2
+ clearHwcLayers();
+#endif
+
for (const auto& child : mCurrentChildren) {
child->onRemoved();
}
@@ -1665,14 +1670,6 @@
} else {
editCurrentState.active = editCurrentState.requested;
c.active = c.requested;
- if (c.crop != c.requestedCrop ||
- c.finalCrop != c.requestedFinalCrop) {
- c.sequence++;
- c.crop = c.requestedCrop;
- c.finalCrop = c.requestedFinalCrop;
- editCurrentState.crop = c.crop;
- editCurrentState.finalCrop = c.finalCrop;
- }
}
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 513ddff..05c367d 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -207,7 +207,7 @@
// immediate. If setGeometryAppliesWithResize is specified
// while a resize is pending, then update of these attributes will
// be delayed until the resize completes.
-
+
// setPosition operates in parent buffer space (pre parent-transform) or display
// space for top-level layers.
bool setPosition(float x, float y, bool immediate);
diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp
index b2424d0..6e37b45 100644
--- a/services/surfaceflinger/LayerRejecter.cpp
+++ b/services/surfaceflinger/LayerRejecter.cpp
@@ -73,6 +73,19 @@
// recompute visible region
mRecomputeVisibleRegions = true;
+
+ mFreezeGeometryUpdates = false;
+
+ if (mFront.crop != mFront.requestedCrop) {
+ mFront.crop = mFront.requestedCrop;
+ mCurrent.crop = mFront.requestedCrop;
+ mRecomputeVisibleRegions = true;
+ }
+ if (mFront.finalCrop != mFront.requestedFinalCrop) {
+ mFront.finalCrop = mFront.requestedFinalCrop;
+ mCurrent.finalCrop = mFront.requestedFinalCrop;
+ mRecomputeVisibleRegions = true;
+ }
}
ALOGD_IF(DEBUG_RESIZE,
@@ -100,6 +113,10 @@
// conservative, but that's fine, worst case we're doing
// a bit of extra work), we latch the new one and we
// trigger a visible-region recompute.
+ //
+ // We latch the transparent region here, instead of above where we latch
+ // the rest of the geometry because it is only content but not necessarily
+ // resize dependent.
if (!mFront.activeTransparentRegion.isTriviallyEqual(mFront.requestedTransparentRegion)) {
mFront.activeTransparentRegion = mFront.requestedTransparentRegion;
@@ -115,8 +132,6 @@
mRecomputeVisibleRegions = true;
}
- mFreezeGeometryUpdates = false;
-
return false;
}
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index d15376e..e50f3ce 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -18,6 +18,7 @@
#include <sched.h>
+#include <android/frameworks/displayservice/1.0/IDisplayService.h>
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
#include <cutils/sched_policy.h>
@@ -25,6 +26,7 @@
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
+#include <displayservice/DisplayService.h>
#include <hidl/LegacySupport.h>
#include <configstore/Utils.h>
#include "GpuService.h"
@@ -32,14 +34,9 @@
using namespace android;
-using android::hardware::graphics::allocator::V2_0::IAllocator;
-using android::hardware::configstore::V1_0::ISurfaceFlingerConfigs;
-using android::hardware::configstore::getBool;
-using android::hardware::configstore::getBool;
-
static status_t startGraphicsAllocatorService() {
- hardware::configureRpcThreadpool( 1 /* maxThreads */,
- false /* callerWillJoin */);
+ using android::hardware::graphics::allocator::V2_0::IAllocator;
+
status_t result =
hardware::registerPassthroughServiceImplementation<IAllocator>();
if (result != OK) {
@@ -50,12 +47,38 @@
return OK;
}
-int main(int, char**) {
+static status_t startHidlServices() {
+ using android::frameworks::displayservice::V1_0::implementation::DisplayService;
+ using android::frameworks::displayservice::V1_0::IDisplayService;
+ using android::hardware::configstore::getBool;
+ using android::hardware::configstore::getBool;
+ using android::hardware::configstore::V1_0::ISurfaceFlingerConfigs;
+ hardware::configureRpcThreadpool(1 /* maxThreads */,
+ false /* callerWillJoin */);
+
+ status_t err;
+
if (getBool<ISurfaceFlingerConfigs,
&ISurfaceFlingerConfigs::startGraphicsAllocatorService>(false)) {
- startGraphicsAllocatorService();
+ err = startGraphicsAllocatorService();
+ if (err != OK) {
+ return err;
+ }
}
+ sp<IDisplayService> displayservice = new DisplayService();
+ err = displayservice->registerAsService();
+
+ if (err != OK) {
+ ALOGE("Could not register IDisplayService service.");
+ }
+
+ return err;
+}
+
+int main(int, char**) {
+ startHidlServices();
+
signal(SIGPIPE, SIG_IGN);
// When SF is launched in its own process, limit the number of
// binder threads to 4.
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index eaf082d..68519a1 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -33,7 +33,7 @@
// Fill an RGBA_8888 formatted surface with a single color.
static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc,
- uint8_t r, uint8_t g, uint8_t b) {
+ uint8_t r, uint8_t g, uint8_t b, bool unlock=true) {
ANativeWindow_Buffer outBuffer;
sp<Surface> s = sc->getSurface();
ASSERT_TRUE(s != NULL);
@@ -48,7 +48,9 @@
pixel[3] = 255;
}
}
- ASSERT_EQ(NO_ERROR, s->unlockAndPost());
+ if (unlock) {
+ ASSERT_EQ(NO_ERROR, s->unlockAndPost());
+ }
}
// A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check
@@ -479,6 +481,17 @@
sc->expectFGColor(127, 127);
sc->expectBGColor(128, 128);
}
+
+ void lockAndFillFGBuffer() {
+ fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63, false);
+ }
+
+ void unlockFGBuffer() {
+ sp<Surface> s = mFGSurfaceControl->getSurface();
+ ASSERT_EQ(NO_ERROR, s->unlockAndPost());
+ waitForPostedBuffers();
+ }
+
void completeFGResize() {
fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
waitForPostedBuffers();
@@ -605,10 +618,48 @@
EXPECT_CROPPED_STATE("after the resize finishes");
}
+// In this test we ensure that setGeometryAppliesWithResize actually demands
+// a buffer of the new size, and not just any size.
+TEST_F(CropLatchingTest, FinalCropLatchingBufferOldSize) {
+ EXPECT_INITIAL_STATE("before anything");
+ // Normally the crop applies immediately even while a resize is pending.
+ SurfaceComposerClient::openGlobalTransaction();
+ mFGSurfaceControl->setSize(128, 128);
+ mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
+ SurfaceComposerClient::closeGlobalTransaction(true);
+
+ EXPECT_CROPPED_STATE("after setting crop (without geometryAppliesWithResize)");
+
+ restoreInitialState();
+
+ // In order to prepare to submit a buffer at the wrong size, we acquire it prior to
+ // initiating the resize.
+ lockAndFillFGBuffer();
+
+ SurfaceComposerClient::openGlobalTransaction();
+ mFGSurfaceControl->setSize(128, 128);
+ mFGSurfaceControl->setGeometryAppliesWithResize();
+ mFGSurfaceControl->setFinalCrop(Rect(64, 64, 127, 127));
+ SurfaceComposerClient::closeGlobalTransaction(true);
+
+ EXPECT_INITIAL_STATE("after setting crop (with geometryAppliesWithResize)");
+
+ // We now submit our old buffer, at the old size, and ensure it doesn't
+ // trigger geometry latching.
+ unlockFGBuffer();
+
+ EXPECT_INITIAL_STATE("after unlocking FG buffer (with geometryAppliesWithResize)");
+
+ completeFGResize();
+
+ EXPECT_CROPPED_STATE("after the resize finishes");
+}
+
TEST_F(CropLatchingTest, FinalCropLatchingRegressionForb37531386) {
EXPECT_INITIAL_STATE("before anything");
// In this scenario, we attempt to set the final crop a second time while the resize
- // is still pending, and ensure we are successful.
+ // is still pending, and ensure we are successful. Success meaning the second crop
+ // is the one which eventually latches and not the first.
SurfaceComposerClient::openGlobalTransaction();
mFGSurfaceControl->setSize(128, 128);
mFGSurfaceControl->setGeometryAppliesWithResize();
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 0005a90..6f425f5 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -39,9 +39,6 @@
android_namespace_t* android_get_exported_namespace(const char*);
}
-// Set to true to enable exposing unratified extensions for development
-static const bool kEnableUnratifiedExtensions = false;
-
// #define ENABLE_ALLOC_CALLSTACKS 1
#if ENABLE_ALLOC_CALLSTACKS
#include <utils/CallStack.h>
@@ -717,12 +714,9 @@
loader_extensions.push_back({
VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME,
VK_EXT_SWAPCHAIN_COLOR_SPACE_SPEC_VERSION});
-
- if (kEnableUnratifiedExtensions) {
- loader_extensions.push_back({
- VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME,
- VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION});
- }
+ loader_extensions.push_back({
+ VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME,
+ VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION});
static const VkExtensionProperties loader_debug_report_extension = {
VK_EXT_DEBUG_REPORT_EXTENSION_NAME, VK_EXT_DEBUG_REPORT_SPEC_VERSION,
@@ -818,15 +812,12 @@
VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME,
VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION});
- if (kEnableUnratifiedExtensions) {
- // conditionally add shared_presentable_image if supportable
- VkPhysicalDevicePresentationPropertiesANDROID presentation_properties;
- if (QueryPresentationProperties(physicalDevice, &presentation_properties) &&
- presentation_properties.sharedImage) {
- loader_extensions.push_back({
- VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME,
- VK_KHR_SHARED_PRESENTABLE_IMAGE_SPEC_VERSION});
- }
+ VkPhysicalDevicePresentationPropertiesANDROID presentation_properties;
+ if (QueryPresentationProperties(physicalDevice, &presentation_properties) &&
+ presentation_properties.sharedImage) {
+ loader_extensions.push_back({
+ VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME,
+ VK_KHR_SHARED_PRESENTABLE_IMAGE_SPEC_VERSION});
}
// conditionally add VK_GOOGLE_display_timing if present timestamps are
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index caa2674..e2c8c06 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -1092,12 +1092,9 @@
image_native_buffer.stride = img.buffer->stride;
image_native_buffer.format = img.buffer->format;
image_native_buffer.usage = img.buffer->usage;
- // TODO: Adjust once ANativeWindowBuffer supports gralloc1-style usage.
- // For now, this is the same translation Gralloc1On0Adapter does.
- image_native_buffer.usage2.consumer =
- static_cast<uint64_t>(img.buffer->usage);
- image_native_buffer.usage2.producer =
- static_cast<uint64_t>(img.buffer->usage);
+ android_convertGralloc0To1Usage(img.buffer->usage,
+ &image_native_buffer.usage2.producer,
+ &image_native_buffer.usage2.consumer);
result =
dispatch.CreateImage(device, &image_create, nullptr, &img.image);