package android.view;
-parcelable Surface cpp_header "gui/Surface.h";
+parcelable Surface cpp_header "gui/view/Surface.h";
"libz",
"libbase",
],
+ static_libs: [
+ "libpdx_default_transport",
+ ],
init_rc: ["atrace.rc"],
}
#include <errno.h>
#include <fcntl.h>
+#include <ftw.h>
#include <getopt.h>
#include <inttypes.h>
#include <signal.h>
#include <hidl/ServiceManagement.h>
#include <cutils/properties.h>
+#include <pdx/default_transport/service_utility.h>
#include <utils/String8.h>
#include <utils/Timers.h>
#include <utils/Tokenizer.h>
#include <android-base/file.h>
using namespace android;
+using pdx::default_transport::ServiceUtility;
using std::string;
#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
}
}
+// Sends the sysprop_change message to the service at fpath, so it re-reads its
+// system properties. Returns 0 on success or a negated errno code on failure.
+static int pokeOnePDXService(const char *fpath, const struct stat * /*sb*/,
+ int typeflag, struct FTW * /*ftwbuf*/)
+{
+ const bool kIgnoreErrors = true;
+
+ if (typeflag == FTW_F) {
+ int error;
+ auto utility = ServiceUtility::Create(fpath, &error);
+ if (!utility) {
+ if (error != -ECONNREFUSED) {
+ ALOGE("pokeOnePDXService: Failed to open %s, %s.", fpath,
+ strerror(-error));
+ }
+ return kIgnoreErrors ? 0 : error;
+ }
+
+ auto status = utility->ReloadSystemProperties();
+ if (!status) {
+ ALOGE("pokeOnePDXService: Failed to send sysprop change to %s, "
+ "error %d, %s.", fpath, status.error(),
+ status.GetErrorMessage().c_str());
+ return kIgnoreErrors ? 0 : -status.error();
+ }
+ }
+
+ return 0;
+}
+
+// Pokes all the PDX processes in the system to get them to re-read
+// their system properties. Returns true on success, false on failure.
+static bool pokePDXServices()
+{
+ const int kMaxDepth = 16;
+ const int result = nftw(ServiceUtility::GetRootEndpointPath().c_str(),
+ pokeOnePDXService, kMaxDepth, FTW_PHYS);
+ return result == 0 ? true : false;
+}
+
// Set the trace tags that userland tracing uses, and poke the running
// processes to pick up the new value.
static bool setTagsProperty(uint64_t tags)
ok &= setAppCmdlineProperty(&packageList[0]);
ok &= pokeBinderServices();
pokeHalServices();
+ ok &= pokePDXServices();
// Disable all the sysfs enables. This is done as a separate loop from
// the enables to allow the same enable to exist in multiple categories.
setTagsProperty(0);
clearAppProperties();
pokeBinderServices();
+ pokePDXServices();
// Set the options back to their defaults.
setTraceOverwriteEnable(true);
LOCAL_MODULE := dumpstate
-LOCAL_SHARED_LIBRARIES := $(COMMON_SHARED_LIBRARIES) \
- android.hardware.vibrator@1.0
+LOCAL_SHARED_LIBRARIES := $(COMMON_SHARED_LIBRARIES)
LOCAL_STATIC_LIBRARIES := $(COMMON_STATIC_LIBRARIES)
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <android/hardware/dumpstate/1.0/IDumpstateDevice.h>
-#include <android/hardware/vibrator/1.0/IVibrator.h>
#include <cutils/native_handle.h>
#include <cutils/properties.h>
#include <openssl/sha.h>
#include "dumpstate.h"
using ::android::hardware::dumpstate::V1_0::IDumpstateDevice;
-using ::android::hardware::vibrator::V1_0::IVibrator;
-using VibratorStatus = ::android::hardware::vibrator::V1_0::Status;
// TODO: remove once moved to namespace
using android::os::dumpstate::CommandOptions;
return std::string(hash_buffer);
}
+static void SendShellBroadcast(const std::string& action, const std::vector<std::string>& args) {
+ std::vector<std::string> am = {
+ "/system/bin/cmd", "activity", "broadcast", "--user", "0", "-a", action};
+
+ am.insert(am.end(), args.begin(), args.end());
+
+ // TODO: explicity setting Shell's component to allow broadcast to launch it.
+ // That might break other components that are listening to the bugreport notifications
+ // (android.intent.action.BUGREPORT_STARTED and android.intent.action.BUGREPORT_STOPED), but
+ // those should be just handled by Shell anyways.
+ // A more generic alternative would be passing the -f 0x01000000 flag (or whatever
+ // value is defined by FLAG_RECEIVER_INCLUDE_BACKGROUND), but that would reset the
+ // --receiver-foreground option
+ am.push_back("com.android.shell");
+
+ RunCommand("", am,
+ CommandOptions::WithTimeout(20)
+ .Log("Sending broadcast: '%s'\n")
+ .Always()
+ .DropRoot()
+ .RedirectStderr()
+ .Build());
+}
+
+static void Vibrate(int duration_ms) {
+ // clang-format off
+ RunCommand("", {"cmd", "vibrator", "vibrate", std::to_string(duration_ms), "dumpstate"},
+ CommandOptions::WithTimeout(10)
+ .Log("Vibrate: '%s'\n")
+ .Always()
+ .Build());
+ // clang-format on
+}
+
int main(int argc, char *argv[]) {
int do_add_date = 0;
int do_zip_file = 0;
if (do_broadcast) {
// clang-format off
- // NOTE: flag must be kept in sync when the value of
- // FLAG_RECEIVER_INCLUDE_BACKGROUND is changed.
std::vector<std::string> am_args = {
"--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
- "-f", "0x01000000",
"--es", "android.intent.extra.NAME", ds.name_,
"--ei", "android.intent.extra.ID", std::to_string(ds.id_),
"--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
"--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
};
// clang-format on
- send_broadcast("android.intent.action.BUGREPORT_STARTED", am_args);
+ SendShellBroadcast("android.intent.action.BUGREPORT_STARTED", am_args);
}
if (use_control_socket) {
dprintf(ds.control_socket_fd_, "BEGIN:%s\n", ds.path_.c_str());
fclose(cmdline);
}
- ::android::sp<IVibrator> vibrator = nullptr;
if (do_vibrate) {
- vibrator = IVibrator::getService();
-
- if (vibrator != nullptr) {
- // cancel previous vibration if any
- ::android::hardware::Return<VibratorStatus> offStatus = vibrator->off();
- if (!offStatus.isOk() || offStatus != VibratorStatus::OK) {
- MYLOGE("Vibrator off failed.");
- } else {
- ::android::hardware::Return<VibratorStatus> onStatus = vibrator->on(150);
- if (!onStatus.isOk() || onStatus != VibratorStatus::OK) {
- MYLOGE("Vibrator on failed.");
- }
- }
- }
+ Vibrate(150);
}
if (do_fb && ds.do_early_screenshot_) {
}
/* vibrate a few but shortly times to let user know it's finished */
- if (vibrator != nullptr) {
- // in case dumpstate magically completes before the above vibration
- ::android::hardware::Return<VibratorStatus> offStatus = vibrator->off();
- if (!offStatus.isOk() || offStatus != VibratorStatus::OK) {
- MYLOGE("Vibrator off failed.");
- } else {
- for (int i = 0; i < 3; i++) {
- ::android::hardware::Return<VibratorStatus> onStatus = vibrator->on(75);
- if (!onStatus.isOk() || onStatus != VibratorStatus::OK) {
- MYLOGE("Vibrator on failed.");
- break;
- }
- usleep((75 + 50) * 1000);
- }
- }
+ for (int i = 0; i < 3; i++) {
+ Vibrate(75);
+ usleep((75 + 50) * 1000);
}
/* tell activity manager we're done */
MYLOGI("Final bugreport path: %s\n", ds.path_.c_str());
// clang-format off
- // NOTE: flag must be kept in sync when the value of
- // FLAG_RECEIVER_INCLUDE_BACKGROUND is changed.
std::vector<std::string> am_args = {
"--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
- "-f", "0x01000000",
"--ei", "android.intent.extra.ID", std::to_string(ds.id_),
"--ei", "android.intent.extra.PID", std::to_string(ds.pid_),
"--ei", "android.intent.extra.MAX", std::to_string(ds.progress_->GetMax()),
am_args.push_back("--es");
am_args.push_back("android.intent.extra.REMOTE_BUGREPORT_HASH");
am_args.push_back(SHA256_file_hash(ds.path_));
- send_broadcast("android.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
+ SendShellBroadcast("android.intent.action.REMOTE_BUGREPORT_FINISHED", am_args);
} else {
- send_broadcast("android.intent.action.BUGREPORT_FINISHED", am_args);
+ SendShellBroadcast("android.intent.action.BUGREPORT_FINISHED", am_args);
}
} else {
MYLOGE("Skipping finished broadcast because bugreport could not be generated\n");
int dump_files(const std::string& title, const char* dir, bool (*skip)(const char* path),
int (*dump_from_fd)(const char* title, const char* path, int fd));
-/* sends a broadcast using Activity Manager */
-void send_broadcast(const std::string& action, const std::vector<std::string>& args);
-
/* prints all the system properties */
void print_properties();
RunCommand(title, dumpsys, options);
}
-void send_broadcast(const std::string& action, const std::vector<std::string>& args) {
- std::vector<std::string> am = {"/system/bin/am", "broadcast", "--user", "0", "-a", action};
-
- am.insert(am.end(), args.begin(), args.end());
-
- RunCommand("", am, CommandOptions::WithTimeout(20)
- .Log("Sending broadcast: '%s'\n")
- .Always()
- .DropRoot()
- .RedirectStderr()
- .Build());
-}
-
size_t num_props = 0;
static char* props[2000];
"libutils",
"liblog",
"libbinder",
- "android.hidl.manager@1.0",
- "libhidlbase"
],
clang: true,
using android::base::unique_fd;
using android::base::WriteFully;
-static int sort_func(const String16* lhs, const String16* rhs) {
+static int sort_func(const String16* lhs, const String16* rhs)
+{
return lhs->compare(*rhs);
}
"usage: dumpsys\n"
" To dump all services.\n"
"or:\n"
- " dumpsys [-t TIMEOUT] [--help | --hw | -l | --skip SERVICES | SERVICE [ARGS]]\n"
+ " dumpsys [-t TIMEOUT] [--help | -l | --skip SERVICES | SERVICE [ARGS]]\n"
" --help: shows this help\n"
" -l: only list services, do not dump them\n"
" -t TIMEOUT: TIMEOUT to use in seconds instead of default 10 seconds\n"
- " --hw: list all hw services running on the device\n"
" --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n"
" SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n");
}
return false;
}
-static void ListHardwareServices(android::hidl::manager::V1_0::IServiceManager* hm) {
- using android::hardware::hidl_vec;
- using android::hardware::hidl_string;
- using android::hardware::Return;
- using android::sp;
-
- if (hm == nullptr) {
- ALOGE("Unable to get hardware service manager!");
- aerr << "Failed to get hardware service manager!";
- return;
- }
-
- Return<void> ret = hm->list([](const hidl_vec<hidl_string> ®istered){
- aout << "Currently running hardware services:" << endl;
- for (const auto &service : registered) {
- aout << " " << service << endl;
- }
- });
-
- if (!ret.isOk()) {
- aerr << "Failed to list hardware services: " << ret.description();
- }
-}
-
int Dumpsys::main(int argc, char* const argv[]) {
Vector<String16> services;
Vector<String16> args;
Vector<String16> skippedServices;
bool showListOnly = false;
- bool listHwOnly = false;
bool skipServices = false;
int timeoutArg = 10;
static struct option longOptions[] = {
{"skip", no_argument, 0, 0 },
{"help", no_argument, 0, 0 },
- {"hw", no_argument, 0, 0 },
{ 0, 0, 0, 0 }
};
} else if (!strcmp(longOptions[optionIndex].name, "help")) {
usage();
return 0;
- } else if (!strcmp(longOptions[optionIndex].name, "hw")) {
- listHwOnly = true;
}
break;
}
if ((skipServices && skippedServices.empty()) ||
- (showListOnly && (!services.empty() || !skippedServices.empty())) ||
- (listHwOnly && (skipServices || services.size() > 0 || showListOnly))) {
+ (showListOnly && (!services.empty() || !skippedServices.empty()))) {
usage();
return -1;
}
- if (listHwOnly) {
- ListHardwareServices(hm_);
- return 0;
- }
-
if (services.empty() || showListOnly) {
// gets all services
services = sm_->listServices();
#ifndef FRAMEWORK_NATIVE_CMD_DUMPSYS_H_
#define FRAMEWORK_NATIVE_CMD_DUMPSYS_H_
-#include <android/hidl/manager/1.0/IServiceManager.h>
#include <binder/IServiceManager.h>
namespace android {
class Dumpsys {
public:
- Dumpsys(android::IServiceManager* sm,
- android::hidl::manager::V1_0::IServiceManager* hm) : sm_(sm), hm_(hm) {
+ Dumpsys(android::IServiceManager* sm) : sm_(sm) {
}
int main(int argc, char* const argv[]);
private:
android::IServiceManager* sm_;
- android::hidl::manager::V1_0::IServiceManager* hm_;
};
}
#include <stdio.h>
using namespace android;
-using HServiceManager = android::hidl::manager::V1_0::IServiceManager;
int main(int argc, char* const argv[]) {
signal(SIGPIPE, SIG_IGN);
return 20;
}
- sp<HServiceManager> hm = HServiceManager::getService("manager");
-
- Dumpsys dumpsys(sm.get(), hm.get());
+ Dumpsys dumpsys(sm.get());
return dumpsys.main(argc, argv);
}
srcs: ["dumpsys_test.cpp"],
shared_libs: [
- "android.hidl.manager@1.0",
"libbase",
"libbinder",
- "liblog",
- "libhidlbase",
- "libhidltransport",
"libutils",
],
using ::testing::internal::GetCapturedStderr;
using ::testing::internal::GetCapturedStdout;
-using android::hardware::hidl_vec;
-using android::hardware::hidl_string;
-using android::hardware::Void;
-using HServiceManager = android::hidl::manager::V1_0::IServiceManager;
-using IServiceNotification = android::hidl::manager::V1_0::IServiceNotification;
-
class ServiceManagerMock : public IServiceManager {
public:
MOCK_CONST_METHOD1(getService, sp<IBinder>(const String16&));
MOCK_METHOD0(onAsBinder, IBinder*());
};
-class HardwareServiceManagerMock : public HServiceManager {
- public:
- template<typename T>
- using R = android::hardware::Return<T>; // conflicts with ::testing::Return
-
- MOCK_METHOD2(get, R<sp<IBase>>(const hidl_string&, const hidl_string&));
- MOCK_METHOD3(add,
- R<bool>(const hidl_vec<hidl_string>&,
- const hidl_string&,
- const sp<IBase>&));
- MOCK_METHOD1(list, R<void>(list_cb));
- MOCK_METHOD2(listByInterface,
- R<void>(const hidl_string&, listByInterface_cb));
- MOCK_METHOD3(registerForNotifications,
- R<bool>(const hidl_string&,
- const hidl_string&,
- const sp<IServiceNotification>&));
- MOCK_METHOD1(debugDump, R<void>(debugDump_cb));
-
-};
-
class BinderMock : public BBinder {
public:
BinderMock() {
return MakeAction(new WriteOnFdAction(output));
}
-// gmock black magic to provide a WithArg<0>(List(services)) matcher
-typedef void HardwareListFunction(HServiceManager::list_cb);
-
-class HardwareListAction : public ActionInterface<HardwareListFunction> {
- public:
- explicit HardwareListAction(const hidl_vec<hidl_string> &services) : services_(services) {
- }
- virtual Result Perform(const ArgumentTuple& args) {
- auto cb = ::std::tr1::get<0>(args);
- cb(services_);
- }
-
- private:
- hidl_vec<hidl_string> services_;
-};
-
-Action<HardwareListFunction> HardwareList(const hidl_vec<hidl_string> &services) {
- return MakeAction(new HardwareListAction(services));
-}
-
// Matcher for args using Android's Vector<String16> format
// TODO: move it to some common testing library
MATCHER_P(AndroidElementsAre, expected, "") {
class DumpsysTest : public Test {
public:
- DumpsysTest() : sm_(), hm_(), dump_(&sm_, &hm_), stdout_(), stderr_() {
+ DumpsysTest() : sm_(), dump_(&sm_), stdout_(), stderr_() {
}
void ExpectListServices(std::vector<std::string> services) {
for (auto& service : services) {
services16.add(String16(service.c_str()));
}
-
EXPECT_CALL(sm_, listServices()).WillRepeatedly(Return(services16));
}
- void ExpectListHardwareServices(std::vector<std::string> services) {
- hidl_vec<hidl_string> hidl_services;
- hidl_services.resize(services.size());
- for (size_t i = 0; i < services.size(); i++) {
- hidl_services[i] = services[i];
- }
-
- EXPECT_CALL(hm_, list(_)).WillRepeatedly(DoAll(
- WithArg<0>(HardwareList(hidl_services)),
- Return(Void())));
- }
-
sp<BinderMock> ExpectCheckService(const char* name, bool running = true) {
sp<BinderMock> binder_mock;
if (running) {
EXPECT_THAT(status, Eq(0));
}
- void AssertRunningServices(const std::vector<std::string>& services,
- const std::string &message = "Currently running services:") {
- std::string expected(message);
- expected.append("\n");
+ void AssertRunningServices(const std::vector<std::string>& services) {
+ std::string expected("Currently running services:\n");
for (const std::string& service : services) {
expected.append(" ").append(service).append("\n");
}
}
ServiceManagerMock sm_;
- HardwareServiceManagerMock hm_;
Dumpsys dump_;
private:
std::string stdout_, stderr_;
};
-TEST_F(DumpsysTest, ListHwServices) {
- ExpectListHardwareServices({"Locksmith", "Valet"});
-
- CallMain({"--hw"});
-
- AssertRunningServices({"Locksmith", "Valet"}, "Currently running hardware services:");
-}
-
// Tests 'dumpsys -l' when all services are running
TEST_F(DumpsysTest, ListAllServices) {
ExpectListServices({"Locksmith", "Valet"});
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <hidl/ServiceManagement.h>
-template <typename A, typename B, typename C, typename D, typename E>
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hidl::manager::V1_0::IServiceManager;
+
+template <typename A, typename B, typename C, typename D, typename E, typename F>
void printColumn(std::stringstream &stream,
- const A &a, const B &b, const C &c, const D &d, const E &e) {
+ const A &a, const B &b, const C &c, const D &d, const E &, const F &f) {
using namespace ::std;
stream << left
<< setw(70) << a << "\t"
<< setw(20) << b << "\t"
<< setw(10) << c << "\t"
<< setw(5) << d << "\t"
- << setw(0) << e
+ // TODO(b/34984175): enable selecting columns
+ // << setw(16) << e << "\t"
+ << setw(0) << f
<< endl;
}
+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) {
std::ostringstream os;
os << std::hex << std::setfill('0') << std::setw(16) << t;
return os.str();
}
-::android::status_t getReferencedPids(
+std::pair<hidl_string, hidl_string> split(const hidl_string &s, char c) {
+ const char *pos = strchr(s.c_str(), c);
+ if (pos == nullptr) {
+ return {s, {}};
+ }
+ return {hidl_string(s.c_str(), pos - s.c_str()), hidl_string(pos + 1)};
+}
+
+bool getReferencedPids(
pid_t serverPid, std::map<uint64_t, std::string> *objects) {
std::ifstream ifs("/d/binder/proc/" + std::to_string(serverPid));
if (!ifs.is_open()) {
- return ::android::PERMISSION_DENIED;
+ return false;
}
static const std::regex prefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+");
(*objects)[ptr] += line.substr(pos + proc.size());
}
}
- return ::android::OK;
+ return true;
}
-
-int dump() {
+void dumpAllLibraries(std::stringstream &stream, const std::string &mode,
+ 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;
+ auto ret = manager->list([&] (const auto &fqInstanceNames) {
+ for (const auto &fqInstanceName : fqInstanceNames) {
+ const auto pair = split(fqInstanceName, '/');
+ const auto &serviceName = pair.first;
+ const auto &instanceName = pair.second;
+ printColumn(stream,
+ serviceName,
+ instanceName,
+ mode,
+ "N/A",
+ "N/A",
+ "N/A");
+ }
+ });
+ if (!ret.isOk()) {
+ cerr << "Error: Failed to call debugDump on defaultServiceManager(): "
+ << ret.description() << endl;
+ }
+}
- std::map<std::string, ::android::sp<IServiceManager>> mapping = {
- {"hwbinder", defaultServiceManager()},
- {"passthrough", getPassthroughServiceManager()}
- };
-
- std::stringstream stream;
-
- stream << "All services:" << endl;
- stream << left;
- printColumn(stream, "Interface", "Instance", "Transport", "Server", "Clients");
-
- for (const auto &pair : mapping) {
- const std::string &mode = pair.first;
- const ::android::sp<IServiceManager> &manager = pair.second;
+void dumpPassthrough(std::stringstream &stream, const std::string &mode,
+ 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;
+ auto ret = manager->debugDump([&] (const auto &infos) {
+ for (const auto &info : infos) {
- if (manager == nullptr) {
- cerr << "Failed to get IServiceManager for " << mode << "!" << endl;
- continue;
+ printColumn(stream,
+ info.interfaceName,
+ info.instanceName,
+ mode,
+ info.clientPids.size() == 1 ? std::to_string(info.clientPids[0]) : "N/A",
+ "N/A",
+ join(info.clientPids, " "));
}
+ });
+ if (!ret.isOk()) {
+ cerr << "Error: Failed to call debugDump on defaultServiceManager(): "
+ << ret.description() << endl;
+ }
+}
- auto ret = manager->debugDump([&](const auto ®istered) {
- // server pid, .ptr value of binder object, child pids
- std::map<pid_t, std::map<uint64_t, std::string>> allPids;
- for (const auto &info : registered) {
- if (info.pid < 0) {
- continue;
- }
- pid_t serverPid = info.pid;
- allPids[serverPid].clear();
+void dumpBinderized(std::stringstream &stream, const std::string &mode,
+ 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;
+ auto listRet = manager->list([&] (const auto &fqInstanceNames) {
+ // server pid, .ptr value of binder object, child pids
+ std::map<std::string, DebugInfo> allDebugInfos;
+ std::map<pid_t, std::map<uint64_t, std::string>> allPids;
+ for (const auto &fqInstanceName : fqInstanceNames) {
+ const auto pair = split(fqInstanceName, '/');
+ const auto &serviceName = pair.first;
+ const auto &instanceName = pair.second;
+ auto getRet = manager->get(serviceName, instanceName);
+ if (!getRet.isOk()) {
+ cerr << "Warning: Skipping \"" << fqInstanceName << "\": "
+ << "cannot be fetched from service manager:"
+ << getRet.description() << endl;
+ continue;
+ }
+ sp<IBase> service = getRet;
+ if (service == nullptr) {
+ cerr << "Warning: Skipping \"" << fqInstanceName << "\": "
+ << "cannot be fetched from service manager (null)";
+ continue;
}
- for (auto &pair : allPids) {
- pid_t serverPid = pair.first;
- if (getReferencedPids(serverPid, &allPids[serverPid]) != ::android::OK) {
- std::cerr << "Warning: no information for PID " << serverPid
- << ", are you root?" << std::endl;
+ auto debugRet = service->getDebugInfo([&] (const auto &debugInfo) {
+ allDebugInfos[fqInstanceName] = debugInfo;
+ if (debugInfo.pid >= 0) {
+ allPids[static_cast<pid_t>(debugInfo.pid)].clear();
}
+ });
+ if (!debugRet.isOk()) {
+ cerr << "Warning: Skipping \"" << fqInstanceName << "\": "
+ << "debugging information cannot be retrieved:"
+ << debugRet.description() << endl;
}
- for (const auto &info : registered) {
+ }
+ for (auto &pair : allPids) {
+ pid_t serverPid = pair.first;
+ if (!getReferencedPids(serverPid, &allPids[serverPid])) {
+ std::cerr << "Warning: no information for PID " << serverPid
+ << ", are you root?" << std::endl;
+ }
+ }
+ for (const auto &fqInstanceName : fqInstanceNames) {
+ const auto pair = split(fqInstanceName, '/');
+ const auto &serviceName = pair.first;
+ const auto &instanceName = pair.second;
+ auto it = allDebugInfos.find(fqInstanceName);
+ if (it == allDebugInfos.end()) {
printColumn(stream,
- info.interfaceName,
- info.instanceName.empty() ? "N/A" : info.instanceName,
+ serviceName,
+ instanceName,
mode,
- info.pid < 0 ? "N/A" : std::to_string(info.pid),
- info.pid < 0 || info.ptr == 0 ? "" : allPids[info.pid][info.ptr]);
+ "N/A",
+ "N/A",
+ ""
+ );
+ continue;
}
- });
- if (!ret.isOk()) {
- cerr << "Failed to list services for " << mode << ": "
- << ret.description() << endl;
+ const DebugInfo &info = it->second;
+ printColumn(stream,
+ serviceName,
+ instanceName,
+ mode,
+ info.pid < 0 ? "N/A" : std::to_string(info.pid),
+ info.ptr == 0 ? "N/A" : toHexString(info.ptr),
+ info.pid < 0 || info.ptr == 0 ? "" : allPids[info.pid][info.ptr]
+ );
}
+
+ });
+ if (!listRet.isOk()) {
+ cerr << "Error: Failed to list services for " << mode << ": "
+ << listRet.description() << endl;
}
+}
+
+int dump() {
+ using namespace ::std;
+ using namespace ::android::hardware;
+
+ std::stringstream stream;
+
+ stream << "All services:" << endl;
+ stream << left;
+ printColumn(stream, "Interface", "Instance", "Transport", "Server", "PTR", "Clients");
+
+ auto bManager = defaultServiceManager();
+ if (bManager == nullptr) {
+ cerr << "Failed to get defaultServiceManager()!" << endl;
+ } else {
+ dumpBinderized(stream, "hwbinder", bManager);
+ // Passthrough PIDs are registered to the binderized manager as well.
+ dumpPassthrough(stream, "passthrough", bManager);
+ }
+
+ auto pManager = getPassthroughServiceManager();
+ if (pManager == nullptr) {
+ cerr << "Failed to get getPassthroughServiceManager()!" << endl;
+ } else {
+ dumpAllLibraries(stream, "passthrough", pManager);
+ }
+
cout << stream.rdbuf();
return 0;
}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- This is the standard feature indicating that the device supports Vulkan
+ compute level 0. -->
+<permissions>
+ <feature name="android.hardware.vulkan.compute" version="0" />
+</permissions>
ANDROID_BITMAP_FORMAT_RGBA_8888 = 1,
/** Red: 5 bits, Green: 6 bits, Blue: 5 bits. **/
ANDROID_BITMAP_FORMAT_RGB_565 = 4,
- /** Red: 4 bits, Green: 4 bits, Blue: 4 bits, Alpha: 4 bits. **/
+ /** Deprecated in API level 13. Because of the poor quality of this configuration, it is advised to use ARGB_8888 instead. **/
ANDROID_BITMAP_FORMAT_RGBA_4444 = 7,
- /** Deprecated. */
+ /** Alpha: 8 bits. */
ANDROID_BITMAP_FORMAT_A_8 = 8,
};
virtual void setVolume(float vol) = 0;
+ virtual void setPan(float pan) = 0;
+
+ virtual void setStartDelayMs(int delayMs) = 0;
+
};
// ----------------------------------------------------------------------------
#include "BatteryServiceConstants.h"
-// must be kept in sync with definitions in BatteryProperty.java
+// must be kept in sync with definitions in
+// frameworks/base/core/java/android/os/BatteryManager.java
enum {
- BATTERY_PROP_CHARGE_COUNTER = 1, // equals BatteryProperty.CHARGE_COUNTER constant
- BATTERY_PROP_CURRENT_NOW = 2, // equals BatteryProperty.CURRENT_NOW constant
- BATTERY_PROP_CURRENT_AVG = 3, // equals BatteryProperty.CURRENT_AVG constant
- BATTERY_PROP_CAPACITY = 4, // equals BatteryProperty.CAPACITY constant
- BATTERY_PROP_ENERGY_COUNTER = 5, // equals BatteryProperty.ENERGY_COUNTER constant
+ BATTERY_PROP_CHARGE_COUNTER = 1, // equals BATTERY_PROPERTY_CHARGE_COUNTER
+ BATTERY_PROP_CURRENT_NOW = 2, // equals BATTERY_PROPERTY_CURRENT_NOW
+ BATTERY_PROP_CURRENT_AVG = 3, // equals BATTERY_PROPERTY_CURRENT_AVERAGE
+ BATTERY_PROP_CAPACITY = 4, // equals BATTERY_PROPERTY_CAPACITY
+ BATTERY_PROP_ENERGY_COUNTER = 5, // equals BATTERY_PROPERTY_ENERGY_COUNTER
+ BATTERY_PROP_BATTERY_STATUS = 6, // equals BATTERY_PROPERTY_BATTERY_STATUS
};
struct BatteryProperties {
ProcessInfoService();
status_t getProcessStatesImpl(size_t length, /*in*/ int32_t* pids, /*out*/ int32_t* states);
+ status_t getProcessStatesScoresImpl(size_t length, /*in*/ int32_t* pids,
+ /*out*/ int32_t* states, /*out*/ int32_t *scores);
void updateBinderLocked();
static const int BINDER_ATTEMPT_LIMIT = 5;
/*out*/ states);
}
+ /**
+ * For each PID in the given "pids" input array, write the current process state
+ * for that process into the "states" output array, or
+ * ActivityManager.PROCESS_STATE_NONEXISTENT * to indicate that no process with the given PID
+ * exists. OoM scores will also be written in the "scores" output array.
+ * Please also note that clients calling this method need to have
+ * "GET_PROCESS_STATE_AND_OOM_SCORE" permission.
+ *
+ * Returns NO_ERROR if this operation was successful, or a negative error code otherwise.
+ */
+ static status_t getProcessStatesScoresFromPids(size_t length, /*in*/ int32_t* pids,
+ /*out*/ int32_t* states, /*out*/ int32_t *scores) {
+ return ProcessInfoService::getInstance().getProcessStatesScoresImpl(
+ length, /*in*/ pids, /*out*/ states, /*out*/ scores);
+ }
};
// ----------------------------------------------------------------------
#ifndef ANDROID_GUI_BUFFERITEM_H
#define ANDROID_GUI_BUFFERITEM_H
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
#include <ui/FenceTime.h>
#include <ui/Rect.h>
#include <ui/Region.h>
void setFilteringEnabled(bool enabled);
// getCurrentBuffer returns the buffer associated with the current image.
- sp<GraphicBuffer> getCurrentBuffer() const;
+ // When outSlot is not nullptr, the current buffer slot index is also
+ // returned.
+ sp<GraphicBuffer> getCurrentBuffer(int* outSlot = nullptr) const;
// getCurrentTextureTarget returns the texture target of the current
// texture as returned by updateTexImage().
* limitations under the License.
*/
-#ifndef ANDROID_SF_GRAPHIC_BUFFER_ALLOC_H
-#define ANDROID_SF_GRAPHIC_BUFFER_ALLOC_H
+#ifndef ANDROID_GUI_GRAPHIC_BUFFER_ALLOC_H
+#define ANDROID_GUI_GRAPHIC_BUFFER_ALLOC_H
#include <stdint.h>
#include <sys/types.h>
#include <utils/Errors.h>
namespace android {
-// ---------------------------------------------------------------------------
class GraphicBuffer;
+/*
+ * Concrete implementation of the IGraphicBufferAlloc interface.
+ *
+ * This can create GraphicBuffer instance across processes. This is mainly used
+ * by surfaceflinger.
+ */
+
class GraphicBufferAlloc : public BnGraphicBufferAlloc {
public:
GraphicBufferAlloc();
virtual ~GraphicBufferAlloc();
virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t width,
uint32_t height, PixelFormat format, uint32_t layerCount,
- uint32_t usage, std::string requestorName,
- status_t* error) override;
+ uint64_t producerUsage, uint64_t consumerUsage,
+ std::string requestorName, status_t* error) override;
};
-// ---------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
-#endif // ANDROID_SF_GRAPHIC_BUFFER_ALLOC_H
+#endif // ANDROID_GUI_GRAPHIC_BUFFER_ALLOC_H
/* Create a new GraphicBuffer for the client to use.
*/
virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
- PixelFormat format, uint32_t layerCount, uint32_t usage,
- std::string requestorName, status_t* error) = 0;
+ PixelFormat format, uint32_t layerCount, uint64_t producerUsage,
+ uint64_t consumerUsage, std::string requestorName,
+ status_t* error) = 0;
sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
PixelFormat format, uint32_t layerCount, uint32_t usage,
status_t* error) {
- return createGraphicBuffer(w, h, format, layerCount, usage, "<Unknown>",
- error);
+ return createGraphicBuffer(w, h, format, layerCount, usage,
+ usage, "<Unknown>", error);
+ }
+
+ sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t layerCount, uint32_t usage,
+ std::string requestorName, status_t* error) {
+ return createGraphicBuffer(w, h, format, layerCount, usage,
+ usage, requestorName, error);
+ }
+
+ sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
+ PixelFormat format, uint32_t layerCount, uint64_t producerUsage,
+ uint64_t consumerUsage, status_t* error) {
+ return createGraphicBuffer(w, h, format, layerCount, producerUsage,
+ consumerUsage, "<Unknown>", error);
}
};
#include <binder/IInterface.h>
#include <ui/FrameStats.h>
-
-#include <gui/IGraphicBufferAlloc.h>
-#include <gui/ISurfaceComposerClient.h>
+#include <ui/PixelFormat.h>
#include <vector>
struct DisplayStatInfo;
class HdrCapabilities;
class IDisplayEventConnection;
-class IMemoryHeap;
+class IGraphicBufferAlloc;
+class IGraphicBufferProducer;
+class ISurfaceComposerClient;
class Rect;
enum class FrameEvent;
#define ANDROID_GUI_SURFACE_H
#include <gui/IGraphicBufferProducer.h>
-#include <gui/BufferQueue.h>
+#include <gui/BufferQueueDefs.h>
#include <ui/ANativeObjectBase.h>
#include <ui/Region.h>
-#include <binder/Parcelable.h>
-
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
#include <utils/RefBase.h>
-#include <utils/threads.h>
-#include <utils/KeyedVector.h>
struct ANativeWindow_Buffer;
virtual int attachBuffer(ANativeWindowBuffer*);
protected:
- enum { NUM_BUFFER_SLOTS = BufferQueue::NUM_BUFFER_SLOTS };
+ enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS };
enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
void querySupportedTimestampsLocked() const;
std::unique_ptr<ProducerFrameEventHistory> mFrameEventHistory;
};
-namespace view {
-
-/**
- * A simple holder for an IGraphicBufferProducer, to match the managed-side
- * android.view.Surface parcelable behavior.
- *
- * This implements android/view/Surface.aidl
- *
- * TODO: Convert IGraphicBufferProducer into AIDL so that it can be directly
- * used in managed Binder calls.
- */
-class Surface : public Parcelable {
- public:
-
- String16 name;
- sp<IGraphicBufferProducer> graphicBufferProducer;
-
- virtual status_t writeToParcel(Parcel* parcel) const override;
- virtual status_t readFromParcel(const Parcel* parcel) override;
-
- // nameAlreadyWritten set to true by Surface.java, because it splits
- // Parceling itself between managed and native code, so it only wants a part
- // of the full parceling to happen on its native side.
- status_t writeToParcel(Parcel* parcel, bool nameAlreadyWritten) const;
-
- // nameAlreadyRead set to true by Surface.java, because it splits
- // Parceling itself between managed and native code, so it only wants a part
- // of the full parceling to happen on its native side.
- status_t readFromParcel(const Parcel* parcel, bool nameAlreadyRead);
-
- private:
-
- static String16 readMaybeEmptyString16(const Parcel* parcel);
-};
-
-} // namespace view
-
-}; // namespace android
+} // namespace android
#endif // ANDROID_GUI_SURFACE_H
--- /dev/null
+/*
+ * Copyright (C) 2010 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_GUI_VIEW_SURFACE_H
+#define ANDROID_GUI_VIEW_SURFACE_H
+
+#include <utils/Errors.h>
+#include <utils/StrongPointer.h>
+#include <utils/String16.h>
+
+#include <binder/Parcelable.h>
+
+namespace android {
+
+class IGraphicBufferProducer;
+
+namespace view {
+
+/**
+ * A simple holder for an IGraphicBufferProducer, to match the managed-side
+ * android.view.Surface parcelable behavior.
+ *
+ * This implements android/view/Surface.aidl
+ *
+ * TODO: Convert IGraphicBufferProducer into AIDL so that it can be directly
+ * used in managed Binder calls.
+ */
+class Surface : public Parcelable {
+ public:
+
+ String16 name;
+ sp<IGraphicBufferProducer> graphicBufferProducer;
+
+ virtual status_t writeToParcel(Parcel* parcel) const override;
+ virtual status_t readFromParcel(const Parcel* parcel) override;
+
+ // nameAlreadyWritten set to true by Surface.java, because it splits
+ // Parceling itself between managed and native code, so it only wants a part
+ // of the full parceling to happen on its native side.
+ status_t writeToParcel(Parcel* parcel, bool nameAlreadyWritten) const;
+
+ // nameAlreadyRead set to true by Surface.java, because it splits
+ // Parceling itself between managed and native code, so it only wants a part
+ // of the full parceling to happen on its native side.
+ status_t readFromParcel(const Parcel* parcel, bool nameAlreadyRead);
+
+ private:
+
+ static String16 readMaybeEmptyString16(const Parcel* parcel);
+};
+
+} // namespace view
+} // namespace android
+
+#endif // ANDROID_GUI_VIEW_SURFACE_H
// ---------------------------------------------------------------------------
-class IMemoryHeap;
class ISurfaceComposer;
// ---------------------------------------------------------------------------
std::shared_ptr<Descriptor> createDescriptor();
- gralloc1_error_t getStride(buffer_handle_t buffer, uint32_t* outStride);
-
gralloc1_error_t allocate(
const std::vector<std::shared_ptr<const Descriptor>>& descriptors,
std::vector<buffer_handle_t>* outBuffers);
gralloc1_error_t release(buffer_handle_t buffer);
+ gralloc1_error_t getDimensions(buffer_handle_t buffer,
+ uint32_t* outWidth, uint32_t* outHeight);
+ gralloc1_error_t getFormat(buffer_handle_t buffer,
+ int32_t* outFormat);
+ gralloc1_error_t getLayerCount(buffer_handle_t buffer,
+ uint32_t* outLayerCount);
+ gralloc1_error_t getProducerUsage(buffer_handle_t buffer,
+ uint64_t* outProducerUsage);
+ gralloc1_error_t getConsumerUsage(buffer_handle_t buffer,
+ uint64_t* outConsumerUsage);
+ gralloc1_error_t getBackingStore(buffer_handle_t buffer,
+ uint64_t* outBackingStore);
+ gralloc1_error_t getStride(buffer_handle_t buffer, uint32_t* outStride);
gralloc1_error_t getNumFlexPlanes(buffer_handle_t buffer,
uint32_t* outNumPlanes);
auto usage = GRALLOC1_CONSUMER_USAGE_NONE;
auto error = callBufferFunction(device, bufferHandle,
&Buffer::getConsumerUsage, &usage);
- if (error != GRALLOC1_ERROR_NONE) {
+ if (error == GRALLOC1_ERROR_NONE) {
*outUsage = static_cast<uint64_t>(usage);
}
return error;
auto usage = GRALLOC1_PRODUCER_USAGE_NONE;
auto error = callBufferFunction(device, bufferHandle,
&Buffer::getProducerUsage, &usage);
- if (error != GRALLOC1_ERROR_NONE) {
+ if (error == GRALLOC1_ERROR_NONE) {
*outUsage = static_cast<uint64_t>(usage);
}
return error;
Error retain(buffer_handle_t handle) const;
void release(buffer_handle_t handle) const;
+ Error getDimensions(buffer_handle_t handle,
+ uint32_t* outWidth, uint32_t* outHeight) const;
+ Error getFormat(buffer_handle_t handle, int32_t* outFormat) const;
+ Error getLayerCount(buffer_handle_t handle, uint32_t* outLayerCount) const;
+ Error getProducerUsage(buffer_handle_t handle,
+ uint64_t* outProducerUsage) const;
+ Error getConsumerUsage(buffer_handle_t handle,
+ uint64_t* outConsumerUsage) const;
+ Error getBackingStore(buffer_handle_t handle,
+ uint64_t* outBackingStore) const;
Error getStride(buffer_handle_t handle, uint32_t* outStride) const;
- Error lock(buffer_handle_t handle,
- uint64_t producerUsageMask,
- uint64_t consumerUsageMask,
- const IMapper::Rect& accessRegion,
+ Error lock(buffer_handle_t handle, uint64_t producerUsage,
+ uint64_t consumerUsage, const IMapper::Rect& accessRegion,
int acquireFence, void** outData) const;
- Error lock(buffer_handle_t handle,
- uint64_t producerUsageMask,
- uint64_t consumerUsageMask,
- const IMapper::Rect& accessRegion,
+ Error lock(buffer_handle_t handle, uint64_t producerUsage,
+ uint64_t consumerUsage, const IMapper::Rect& accessRegion,
int acquireFence, FlexLayout* outLayout) const;
int unlock(buffer_handle_t handle) const;
GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
uint32_t inUsage, std::string requestorName = "<Unknown>");
- // creates w * h buffer with a layer count
+ // creates w * h buffer with a layer count using gralloc1
GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
- uint32_t inLayerCount, uint32_t inUsage,
- std::string requestorName = "<Unknown>");
+ uint32_t inLayerCount, uint64_t inProducerUsage,
+ uint64_t inConsumerUsage, std::string requestorName = "<Unknown>");
// create a buffer from an existing handle
GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
uint32_t inLayerCount, uint32_t inUsage, uint32_t inStride,
native_handle_t* inHandle, bool keepOwnership);
+ // create a buffer from an existing handle using gralloc1
+ GraphicBuffer(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
+ uint32_t inLayerCount, uint32_t inProducerUsage,
+ uint32_t inConsumerUsage, uint32_t inStride,
+ native_handle_t* inHandle, bool keepOwnership);
+
// create a buffer from an existing ANativeWindowBuffer
GraphicBuffer(ANativeWindowBuffer* buffer, bool keepOwnership);
status_t lockAsync(uint32_t inUsage, void** vaddr, int fenceFd);
status_t lockAsync(uint32_t inUsage, const Rect& rect, void** vaddr,
int fenceFd);
+ status_t lockAsync(uint64_t inProducerUsage, uint64_t inConsumerUsage,
+ const Rect& rect, void** vaddr, int fenceFd);
status_t lockAsyncYCbCr(uint32_t inUsage, android_ycbcr *ycbcr,
int fenceFd);
status_t lockAsyncYCbCr(uint32_t inUsage, const Rect& rect,
const GraphicBuffer& operator = (const GraphicBuffer& rhs) const;
status_t initSize(uint32_t inWidth, uint32_t inHeight, PixelFormat inFormat,
- uint32_t inLayerCount, uint32_t inUsage, std::string requestorName);
+ uint32_t inLayerCount, uint64_t inProducerUsage,
+ uint64_t inConsumerUsage, std::string requestorName);
void free_handle();
static inline GraphicBufferAllocator& get() { return getInstance(); }
status_t allocate(uint32_t w, uint32_t h, PixelFormat format,
- uint32_t layerCount, uint32_t usage, buffer_handle_t* handle,
- uint32_t* stride, uint64_t graphicBufferId,
+ uint32_t layerCount, uint64_t producerUsage, uint64_t consumerUsage,
+ buffer_handle_t* handle, uint32_t* stride, uint64_t graphicBufferId,
std::string requestorName);
status_t free(buffer_handle_t handle);
uint32_t stride;
PixelFormat format;
uint32_t layerCount;
- uint32_t usage;
+ uint64_t producerUsage;
+ uint64_t consumerUsage;
size_t size;
std::string requestorName;
};
public:
static inline GraphicBufferMapper& get() { return getInstance(); }
+ // This may NOT work on devices without a valid Gralloc2::Mapper.
status_t registerBuffer(buffer_handle_t handle);
+
status_t registerBuffer(const GraphicBuffer* buffer);
status_t unregisterBuffer(buffer_handle_t handle);
+ status_t getDimensions(buffer_handle_t handle,
+ uint32_t* outWidth, uint32_t* outHeight) const;
+
+ status_t getFormat(buffer_handle_t handle, int32_t* outFormat) const;
+
+ status_t getLayerCount(buffer_handle_t handle,
+ uint32_t* outLayerCount) const;
+
+ status_t getProducerUsage(buffer_handle_t handle,
+ uint64_t* outProducerUsage) const;
+
+ status_t getConsumerUsage(buffer_handle_t handle,
+ uint64_t* outConsumerUsage) const;
+
+ status_t getBackingStore(buffer_handle_t handle,
+ uint64_t* outBackingStore) const;
+
+ status_t getStride(buffer_handle_t handle, uint32_t* outStride) const;
+
status_t lock(buffer_handle_t handle,
uint32_t usage, const Rect& bounds, void** vaddr);
status_t lockAsync(buffer_handle_t handle,
uint32_t usage, const Rect& bounds, void** vaddr, int fenceFd);
+ status_t lockAsync(buffer_handle_t handle,
+ uint64_t producerUsage, uint64_t consumerUsage, const Rect& bounds,
+ void** vaddr, int fenceFd);
+
status_t lockAsyncYCbCr(buffer_handle_t handle,
uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr,
int fenceFd);
* limitations under the License.
*/
-#ifndef ANDROID_GUI_GRAPHICS_ENV_H
-#define ANDROID_GUI_GRAPHICS_ENV_H 1
+#ifndef ANDROID_UI_GRAPHICS_ENV_H
+#define ANDROID_UI_GRAPHICS_ENV_H 1
#include <string>
*/
extern "C" android_namespace_t* android_getDriverNamespace();
-#endif // ANDROID_GUI_GRAPHICS_ENV_H
+#endif // ANDROID_UI_GRAPHICS_ENV_H
#ifndef ANDROID_UI_HDR_CAPABILTIES_H
#define ANDROID_UI_HDR_CAPABILTIES_H
-#include <binder/Parcelable.h>
+#include <stdint.h>
+
+#include <vector>
+
+#include <utils/Flattenable.h>
namespace android {
-class HdrCapabilities : public Parcelable
+class HdrCapabilities : public LightFlattenable<HdrCapabilities>
{
public:
HdrCapabilities(const std::vector<int32_t /*android_hdr_t*/>& types,
mMinLuminance(minLuminance) {}
// Make this move-constructable and move-assignable
- HdrCapabilities(HdrCapabilities&& other) = default;
- HdrCapabilities& operator=(HdrCapabilities&& other) = default;
+ HdrCapabilities(HdrCapabilities&& other);
+ HdrCapabilities& operator=(HdrCapabilities&& other);
HdrCapabilities()
: mSupportedHdrTypes(),
mMaxAverageLuminance(-1.0f),
mMinLuminance(-1.0f) {}
- virtual ~HdrCapabilities() = default;
+ ~HdrCapabilities();
const std::vector<int32_t /*android_hdr_t*/>& getSupportedHdrTypes() const {
return mSupportedHdrTypes;
float getDesiredMaxAverageLuminance() const { return mMaxAverageLuminance; }
float getDesiredMinLuminance() const { return mMinLuminance; }
- // Parcelable interface
- virtual status_t writeToParcel(Parcel* parcel) const override;
- virtual status_t readFromParcel(const Parcel* parcel) override;
+ // Flattenable protocol
+ bool isFixedSize() const { return false; }
+ size_t getFlattenedSize() const;
+ status_t flatten(void* buffer, size_t size) const;
+ status_t unflatten(void const* buffer, size_t size);
private:
std::vector<int32_t /*android_hdr_t*/> mSupportedHdrTypes;
return TIMED_OUT;
}
+status_t ProcessInfoService::getProcessStatesScoresImpl(size_t length,
+ /*in*/ int32_t* pids, /*out*/ int32_t* states,
+ /*out*/ int32_t *scores) {
+ status_t err = NO_ERROR;
+ sp<IProcessInfoService> pis;
+ mProcessInfoLock.lock();
+ pis = mProcessInfoService;
+ mProcessInfoLock.unlock();
+
+ for (int i = 0; i < BINDER_ATTEMPT_LIMIT; i++) {
+
+ if (pis != NULL) {
+ err = pis->getProcessStatesAndOomScoresFromPids(length,
+ /*in*/ pids, /*out*/ states, /*out*/ scores);
+ if (err == NO_ERROR) return NO_ERROR; // success
+ if (IInterface::asBinder(pis)->isBinderAlive()) return err;
+ }
+ sleep(1);
+
+ mProcessInfoLock.lock();
+ if (pis == mProcessInfoService) {
+ updateBinderLocked();
+ }
+ pis = mProcessInfoService;
+ mProcessInfoLock.unlock();
+ }
+
+ ALOGW("%s: Could not retrieve process states and scores "
+ "from ProcessInfoService after %d retries.", __FUNCTION__,
+ BINDER_ATTEMPT_LIMIT);
+
+ return TIMED_OUT;
+}
+
void ProcessInfoService::updateBinderLocked() {
const sp<IServiceManager> sm(defaultServiceManager());
if (sm != NULL) {
fd = -1;
}
if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
- ALOGE("Binder driver protocol does not match user space protocol!");
+ ALOGE("Binder driver protocol(%d) does not match user space protocol(%d)! ioctl() return value: %d",
+ vers, BINDER_CURRENT_PROTOCOL_VERSION, result);
close(fd);
fd = -1;
}
"FrameTimestamps.cpp",
"GLConsumer.cpp",
"GraphicBufferAlloc.cpp",
- "GraphicsEnv.cpp",
"GuiConfig.cpp",
"IDisplayEventConnection.cpp",
"IGraphicBufferAlloc.cpp",
"SurfaceControl.cpp",
"SurfaceComposerClient.cpp",
"SyncFeatures.cpp",
+ "view/Surface.cpp",
],
shared_libs: [
- "libnativeloader",
"libsync",
"libbinder",
"libcutils",
return mCurrentFrameNumber;
}
-sp<GraphicBuffer> GLConsumer::getCurrentBuffer() const {
+sp<GraphicBuffer> GLConsumer::getCurrentBuffer(int* outSlot) const {
Mutex::Autolock lock(mMutex);
- return (mCurrentTextureImage == NULL) ?
+
+ if (outSlot != nullptr) {
+ *outSlot = mCurrentTexture;
+ }
+
+ return (mCurrentTextureImage == nullptr) ?
NULL : mCurrentTextureImage->graphicBuffer();
}
** limitations under the License.
*/
-#include <log/log.h>
+#include <gui/GraphicBufferAlloc.h>
-#include <ui/GraphicBuffer.h>
+#include <log/log.h>
-#include <gui/GraphicBufferAlloc.h>
-// ----------------------------------------------------------------------------
namespace android {
-// ----------------------------------------------------------------------------
-GraphicBufferAlloc::GraphicBufferAlloc() {
-}
-
-GraphicBufferAlloc::~GraphicBufferAlloc() {
-}
+GraphicBufferAlloc::GraphicBufferAlloc() = default;
+GraphicBufferAlloc::~GraphicBufferAlloc() = default;
sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t width,
uint32_t height, PixelFormat format, uint32_t layerCount,
- uint32_t usage, std::string requestorName, status_t* error) {
+ uint64_t producerUsage, uint64_t consumerUsage,
+ std::string requestorName, status_t* error) {
sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(
- width, height, format, layerCount, usage,
+ width, height, format, layerCount, producerUsage, consumerUsage,
std::move(requestorName)));
status_t err = graphicBuffer->initCheck();
*error = err;
if (err == NO_MEMORY) {
GraphicBuffer::dumpAllocationsToSystemLog();
}
- ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%u, h=%u, lc=%u) "
- "failed (%s), handle=%p",
+ ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%u, h=%u, lc=%u) failed (%s), handle=%p",
width, height, layerCount, strerror(-err),
graphicBuffer->handle);
- return 0;
+ graphicBuffer.clear();
}
return graphicBuffer;
}
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
+} // namespace android
virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t width,
uint32_t height, PixelFormat format, uint32_t layerCount,
- uint32_t usage, std::string requestorName, status_t* error) {
+ uint64_t producerUsage, uint64_t consumerUsage,
+ std::string requestorName, status_t* error) {
Parcel data, reply;
data.writeInterfaceToken(IGraphicBufferAlloc::getInterfaceDescriptor());
data.writeUint32(width);
data.writeUint32(height);
data.writeInt32(static_cast<int32_t>(format));
data.writeUint32(layerCount);
- data.writeUint32(usage);
+ data.writeUint64(producerUsage);
+ data.writeUint64(consumerUsage);
if (requestorName.empty()) {
requestorName += "[PID ";
requestorName += std::to_string(getpid());
uint32_t height = data.readUint32();
PixelFormat format = static_cast<PixelFormat>(data.readInt32());
uint32_t layerCount = data.readUint32();
- uint32_t usage = data.readUint32();
+ uint64_t producerUsage = data.readUint64();
+ uint64_t consumerUsage = data.readUint64();
status_t error = NO_ERROR;
std::string requestorName;
data.readUtf8FromUtf16(&requestorName);
sp<GraphicBuffer> result = createGraphicBuffer(width, height,
- format, layerCount, usage, requestorName, &error);
+ format, layerCount, producerUsage, consumerUsage,
+ requestorName, &error);
reply->writeInt32(error);
if (result != 0) {
reply->write(*result);
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
-#include <gui/BitTube.h>
#include <gui/IDisplayEventConnection.h>
-#include <gui/ISurfaceComposer.h>
+#include <gui/IGraphicBufferAlloc.h>
#include <gui/IGraphicBufferProducer.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/ISurfaceComposerClient.h>
#include <private/gui/LayerState.h>
namespace android {
-class IDisplayEventConnection;
-
class BpSurfaceComposer : public BpInterface<ISurfaceComposer>
{
public:
}
result = reply.readInt32();
if (result == NO_ERROR) {
- result = reply.readParcelable(outCapabilities);
+ result = reply.read(*outCapabilities);
}
return result;
}
result = getHdrCapabilities(display, &capabilities);
reply->writeInt32(result);
if (result == NO_ERROR) {
- reply->writeParcelable(capabilities);
+ reply->write(capabilities);
}
return NO_ERROR;
}
mFlags |= SENSOR_FLAG_WAKE_UP;
}
break;
+ case SENSOR_TYPE_LOW_LATENCY_OFFBODY_DETECT:
+ mStringType = SENSOR_STRING_TYPE_LOW_LATENCY_OFFBODY_DETECT;
+ mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
+ break;
case SENSOR_TYPE_WRIST_TILT_GESTURE:
mStringType = SENSOR_STRING_TYPE_WRIST_TILT_GESTURE;
mFlags |= SENSOR_FLAG_SPECIAL_REPORTING_MODE;
if (type == SENSOR_TYPE_PROXIMITY || type == SENSOR_TYPE_SIGNIFICANT_MOTION ||
type == SENSOR_TYPE_TILT_DETECTOR || type == SENSOR_TYPE_WAKE_GESTURE ||
type == SENSOR_TYPE_GLANCE_GESTURE || type == SENSOR_TYPE_PICK_UP_GESTURE ||
- type == SENSOR_TYPE_WRIST_TILT_GESTURE) {
+ type == SENSOR_TYPE_WRIST_TILT_GESTURE ||
+ type == SENSOR_TYPE_LOW_LATENCY_OFFBODY_DETECT) {
wakeUpSensor = true;
}
// For now we just return the first sensor of that type we find.
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
//#define LOG_NDEBUG 0
-#include <android/native_window.h>
+#include <gui/Surface.h>
-#include <binder/Parcel.h>
+#include <android/native_window.h>
#include <utils/Log.h>
#include <utils/Trace.h>
#include <ui/Region.h>
#include <ui/DisplayStatInfo.h>
+#include <gui/BufferItem.h>
#include <gui/IProducerListener.h>
-#include <gui/ISurfaceComposer.h>
-#include <gui/SurfaceComposerClient.h>
-#include <gui/GLConsumer.h>
-#include <gui/Surface.h>
+#include <gui/ISurfaceComposer.h>
#include <private/gui/ComposerService.h>
namespace android {
return mGraphicBufferProducer->getUniqueId(outId);
}
-namespace view {
-
-status_t Surface::writeToParcel(Parcel* parcel) const {
- return writeToParcel(parcel, false);
-}
-
-status_t Surface::writeToParcel(Parcel* parcel, bool nameAlreadyWritten) const {
- if (parcel == nullptr) return BAD_VALUE;
-
- status_t res = OK;
-
- if (!nameAlreadyWritten) {
- res = parcel->writeString16(name);
- if (res != OK) return res;
-
- /* isSingleBuffered defaults to no */
- res = parcel->writeInt32(0);
- if (res != OK) return res;
- }
-
- res = parcel->writeStrongBinder(
- IGraphicBufferProducer::asBinder(graphicBufferProducer));
-
- return res;
-}
-
-status_t Surface::readFromParcel(const Parcel* parcel) {
- return readFromParcel(parcel, false);
-}
-
-status_t Surface::readFromParcel(const Parcel* parcel, bool nameAlreadyRead) {
- if (parcel == nullptr) return BAD_VALUE;
-
- status_t res = OK;
- if (!nameAlreadyRead) {
- name = readMaybeEmptyString16(parcel);
- // Discard this for now
- int isSingleBuffered;
- res = parcel->readInt32(&isSingleBuffered);
- if (res != OK) {
- ALOGE("Can't read isSingleBuffered");
- return res;
- }
- }
-
- sp<IBinder> binder;
-
- res = parcel->readNullableStrongBinder(&binder);
- if (res != OK) {
- ALOGE("%s: Can't read strong binder", __FUNCTION__);
- return res;
- }
-
- graphicBufferProducer = interface_cast<IGraphicBufferProducer>(binder);
-
- return OK;
-}
-
-String16 Surface::readMaybeEmptyString16(const Parcel* parcel) {
- size_t len;
- const char16_t* str = parcel->readString16Inplace(&len);
- if (str != nullptr) {
- return String16(str, len);
- } else {
- return String16();
- }
-}
-
-} // namespace view
-
}; // namespace android
--- /dev/null
+/*
+ * Copyright (C) 2010 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 "Surface"
+
+#include <gui/view/Surface.h>
+
+#include <binder/Parcel.h>
+
+#include <utils/Log.h>
+
+#include <gui/IGraphicBufferProducer.h>
+
+namespace android {
+namespace view {
+
+status_t Surface::writeToParcel(Parcel* parcel) const {
+ return writeToParcel(parcel, false);
+}
+
+status_t Surface::writeToParcel(Parcel* parcel, bool nameAlreadyWritten) const {
+ if (parcel == nullptr) return BAD_VALUE;
+
+ status_t res = OK;
+
+ if (!nameAlreadyWritten) {
+ res = parcel->writeString16(name);
+ if (res != OK) return res;
+
+ /* isSingleBuffered defaults to no */
+ res = parcel->writeInt32(0);
+ if (res != OK) return res;
+ }
+
+ res = parcel->writeStrongBinder(
+ IGraphicBufferProducer::asBinder(graphicBufferProducer));
+
+ return res;
+}
+
+status_t Surface::readFromParcel(const Parcel* parcel) {
+ return readFromParcel(parcel, false);
+}
+
+status_t Surface::readFromParcel(const Parcel* parcel, bool nameAlreadyRead) {
+ if (parcel == nullptr) return BAD_VALUE;
+
+ status_t res = OK;
+ if (!nameAlreadyRead) {
+ name = readMaybeEmptyString16(parcel);
+ // Discard this for now
+ int isSingleBuffered;
+ res = parcel->readInt32(&isSingleBuffered);
+ if (res != OK) {
+ ALOGE("Can't read isSingleBuffered");
+ return res;
+ }
+ }
+
+ sp<IBinder> binder;
+
+ res = parcel->readNullableStrongBinder(&binder);
+ if (res != OK) {
+ ALOGE("%s: Can't read strong binder", __FUNCTION__);
+ return res;
+ }
+
+ graphicBufferProducer = interface_cast<IGraphicBufferProducer>(binder);
+
+ return OK;
+}
+
+String16 Surface::readMaybeEmptyString16(const Parcel* parcel) {
+ size_t len;
+ const char16_t* str = parcel->readString16Inplace(&len);
+ if (str != nullptr) {
+ return String16(str, len);
+ } else {
+ return String16();
+ }
+}
+
+} // namespace view
+} // namespace android
"GraphicBuffer.cpp",
"GraphicBufferAllocator.cpp",
"GraphicBufferMapper.cpp",
+ "GraphicsEnv.cpp",
"HdrCapabilities.cpp",
"PixelFormat.cpp",
"Rect.cpp",
shared_libs: [
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.mapper@2.0",
- "libbinder",
+ "libnativeloader",
"libcutils",
"libhardware",
"libhidlbase",
return descriptor;
}
-gralloc1_error_t Device::getStride(buffer_handle_t buffer, uint32_t* outStride)
-{
- int32_t intError = mFunctions.getStride(mDevice, buffer, outStride);
- return static_cast<gralloc1_error_t>(intError);
-}
-
static inline bool allocationSucceded(gralloc1_error_t error)
{
return error == GRALLOC1_ERROR_NONE || error == GRALLOC1_ERROR_NOT_SHARED;
return static_cast<gralloc1_error_t>(intError);
}
+gralloc1_error_t Device::getDimensions(buffer_handle_t buffer,
+ uint32_t* outWidth, uint32_t* outHeight)
+{
+ uint32_t width = 0;
+ uint32_t height = 0;
+ int32_t intError = mFunctions.getDimensions(mDevice, buffer, &width,
+ &height);
+ auto error = static_cast<gralloc1_error_t>(intError);
+ if (error == GRALLOC1_ERROR_NONE) {
+ *outWidth = width;
+ *outHeight = height;
+ }
+ return error;
+}
+
+gralloc1_error_t Device::getFormat(buffer_handle_t buffer,
+ int32_t* outFormat)
+{
+ int32_t format = 0;
+ int32_t intError = mFunctions.getFormat(mDevice, buffer, &format);
+ auto error = static_cast<gralloc1_error_t>(intError);
+ if (error == GRALLOC1_ERROR_NONE) {
+ *outFormat = format;
+ }
+ return error;
+}
+
+gralloc1_error_t Device::getLayerCount(buffer_handle_t buffer,
+ uint32_t* outLayerCount)
+{
+ if (hasCapability(GRALLOC1_CAPABILITY_LAYERED_BUFFERS)) {
+ uint32_t layerCount = 0;
+ int32_t intError = mFunctions.getLayerCount(mDevice, buffer,
+ &layerCount);
+ auto error = static_cast<gralloc1_error_t>(intError);
+ if (error == GRALLOC1_ERROR_NONE) {
+ *outLayerCount = layerCount;
+ }
+ return error;
+ } else {
+ // Layered buffers are not supported on this device.
+ return GRALLOC1_ERROR_UNSUPPORTED;
+ }
+}
+
+gralloc1_error_t Device::getProducerUsage(buffer_handle_t buffer,
+ uint64_t* outProducerUsage)
+{
+ uint64_t usage = 0;
+ int32_t intError = mFunctions.getProducerUsage(mDevice, buffer, &usage);
+ auto error = static_cast<gralloc1_error_t>(intError);
+ if (error == GRALLOC1_ERROR_NONE) {
+ *outProducerUsage = usage;
+ }
+ return error;
+}
+
+gralloc1_error_t Device::getConsumerUsage(buffer_handle_t buffer,
+ uint64_t* outConsumerUsage)
+{
+ uint64_t usage = 0;
+ int32_t intError = mFunctions.getConsumerUsage(mDevice, buffer, &usage);
+ auto error = static_cast<gralloc1_error_t>(intError);
+ if (error == GRALLOC1_ERROR_NONE) {
+ *outConsumerUsage = usage;
+ }
+ return error;
+}
+
+gralloc1_error_t Device::getBackingStore(buffer_handle_t buffer,
+ uint64_t* outBackingStore)
+{
+ uint64_t store = 0;
+ int32_t intError = mFunctions.getBackingStore(mDevice, buffer, &store);
+ auto error = static_cast<gralloc1_error_t>(intError);
+ if (error == GRALLOC1_ERROR_NONE) {
+ *outBackingStore = store;
+ }
+ return error;
+}
+
+gralloc1_error_t Device::getStride(buffer_handle_t buffer,
+ uint32_t* outStride)
+{
+ uint32_t stride = 0;
+ int32_t intError = mFunctions.getStride(mDevice, buffer, &stride);
+ auto error = static_cast<gralloc1_error_t>(intError);
+ if (error == GRALLOC1_ERROR_NONE) {
+ *outStride = stride;
+ }
+ return error;
+}
+
gralloc1_error_t Device::getNumFlexPlanes(buffer_handle_t buffer,
uint32_t* outNumPlanes)
{
const sp<Fence>& acquireFence)
{
ALOGV("Calling lock(%p)", buffer);
- return lockHelper(mFunctions.lock.pfn, buffer, producerUsage,
+ return lockHelper(mFunctions.lock, buffer, producerUsage,
consumerUsage, accessRegion, outData, acquireFence);
}
const sp<Fence>& acquireFence)
{
ALOGV("Calling lockFlex(%p)", buffer);
- return lockHelper(mFunctions.lockFlex.pfn, buffer, producerUsage,
+ return lockHelper(mFunctions.lockFlex, buffer, producerUsage,
consumerUsage, accessRegion, outData, acquireFence);
}
const sp<Fence>& acquireFence)
{
ALOGV("Calling lockYCbCr(%p)", buffer);
- return lockHelper(mFunctions.lockYCbCr.pfn, buffer, producerUsage,
+ return lockHelper(mFunctions.lockYCbCr, buffer, producerUsage,
consumerUsage, accessRegion, outData, acquireFence);
}
"release(%p) failed with %d", handle, error);
}
+Error Mapper::getDimensions(buffer_handle_t handle,
+ uint32_t* outWidth, uint32_t* outHeight) const
+{
+ Error error = kDefaultError;
+ mMapper->getDimensions(handle,
+ [&](const auto& tmpError, const auto& tmpWidth,
+ const auto& tmpHeight)
+ {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ *outWidth = tmpWidth;
+ *outHeight = tmpHeight;
+ });
+
+ return error;
+}
+
+Error Mapper::getFormat(buffer_handle_t handle, int32_t* outFormat) const
+{
+ Error error = kDefaultError;
+ mMapper->getFormat(handle,
+ [&](const auto& tmpError, const auto& tmpFormat)
+ {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ *outFormat = static_cast<int32_t>(tmpFormat);
+ });
+
+ return error;
+}
+
+Error Mapper::getLayerCount(buffer_handle_t handle,
+ uint32_t* outLayerCount) const
+{
+ Error error = kDefaultError;
+ mMapper->getLayerCount(handle,
+ [&](const auto& tmpError, const auto& tmpLayerCount)
+ {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ *outLayerCount = tmpLayerCount;
+ });
+
+ return error;
+}
+
+Error Mapper::getProducerUsage(buffer_handle_t handle,
+ uint64_t* outProducerUsage) const
+{
+ Error error = kDefaultError;
+ mMapper->getProducerUsageMask(handle,
+ [&](const auto& tmpError, const auto& tmpProducerUsage)
+ {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ *outProducerUsage = tmpProducerUsage;
+ });
+
+ return error;
+}
+
+Error Mapper::getConsumerUsage(buffer_handle_t handle,
+ uint64_t* outConsumerUsage) const
+{
+ Error error = kDefaultError;
+ mMapper->getConsumerUsageMask(handle,
+ [&](const auto& tmpError, const auto& tmpConsumerUsage)
+ {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ *outConsumerUsage = tmpConsumerUsage;
+ });
+
+ return error;
+}
+
+Error Mapper::getBackingStore(buffer_handle_t handle,
+ uint64_t* outBackingStore) const
+{
+ Error error = kDefaultError;
+ mMapper->getBackingStore(handle,
+ [&](const auto& tmpError, const auto& tmpStore)
+ {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ *outBackingStore = tmpStore;
+ });
+
+ return error;
+}
+
Error Mapper::getStride(buffer_handle_t handle, uint32_t* outStride) const
{
Error error = kDefaultError;
}
Error Mapper::lock(buffer_handle_t handle,
- uint64_t producerUsageMask,
- uint64_t consumerUsageMask,
+ uint64_t producerUsage,
+ uint64_t consumerUsage,
const IMapper::Rect& accessRegion,
int acquireFence, void** outData) const
{
}
Error error = kDefaultError;
- mMapper->lock(handle, producerUsageMask, consumerUsageMask,
+ mMapper->lock(handle, producerUsage, consumerUsage,
accessRegion, acquireFenceHandle,
[&](const auto& tmpError, const auto& tmpData)
{
}
Error Mapper::lock(buffer_handle_t handle,
- uint64_t producerUsageMask,
- uint64_t consumerUsageMask,
+ uint64_t producerUsage,
+ uint64_t consumerUsage,
const IMapper::Rect& accessRegion,
int acquireFence, FlexLayout* outLayout) const
{
}
Error error = kDefaultError;
- mMapper->lockFlex(handle, producerUsageMask, consumerUsageMask,
+ mMapper->lockFlex(handle, producerUsage, consumerUsage,
accessRegion, acquireFenceHandle,
[&](const auto& tmpError, const auto& tmpLayout)
{
height =
stride =
format =
- layerCount =
usage = 0;
+ layerCount = 0;
handle = NULL;
}
height =
stride =
format =
- layerCount =
usage = 0;
+ layerCount = 0;
handle = NULL;
- mInitCheck = initSize(inWidth, inHeight, inFormat, 1, inUsage,
+ mInitCheck = initSize(inWidth, inHeight, inFormat, 1, inUsage, inUsage,
std::move(requestorName));
}
GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
- PixelFormat inFormat, uint32_t inLayerCount, uint32_t inUsage,
- std::string requestorName)
+ PixelFormat inFormat, uint32_t inLayerCount, uint64_t producerUsage,
+ uint64_t consumerUsage, std::string requestorName)
: BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0)
{
height =
stride =
format =
- layerCount =
usage = 0;
+ layerCount = 0;
handle = NULL;
- mInitCheck = initSize(inWidth, inHeight, inFormat, inLayerCount, inUsage,
- std::move(requestorName));
+ mInitCheck = initSize(inWidth, inHeight, inFormat, inLayerCount,
+ producerUsage, consumerUsage, std::move(requestorName));
}
GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
handle = inHandle;
}
+GraphicBuffer::GraphicBuffer(uint32_t inWidth, uint32_t inHeight,
+ PixelFormat inFormat, uint32_t inLayerCount, uint32_t inProducerUsage,
+ uint32_t inConsumerUsage, uint32_t inStride,
+ native_handle_t* inHandle, bool keepOwnership)
+ : BASE(), mOwner(keepOwnership ? ownHandle : ownNone),
+ mBufferMapper(GraphicBufferMapper::get()),
+ mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0)
+{
+ width = static_cast<int>(inWidth);
+ height = static_cast<int>(inHeight);
+ stride = static_cast<int>(inStride);
+ format = inFormat;
+ layerCount = inLayerCount;
+ usage = static_cast<int>(inConsumerUsage | inProducerUsage);
+ handle = inHandle;
+}
+
+
GraphicBuffer::GraphicBuffer(ANativeWindowBuffer* buffer, bool keepOwnership)
: BASE(), mOwner(keepOwnership ? ownHandle : ownNone),
mBufferMapper(GraphicBufferMapper::get()),
allocator.free(handle);
handle = 0;
}
- return initSize(inWidth, inHeight, inFormat, inLayerCount, inUsage,
+ return initSize(inWidth, inHeight, inFormat, inLayerCount, inUsage, inUsage,
"[Reallocation]");
}
}
status_t GraphicBuffer::initSize(uint32_t inWidth, uint32_t inHeight,
- PixelFormat inFormat, uint32_t inLayerCount, uint32_t inUsage,
- std::string requestorName)
+ PixelFormat inFormat, uint32_t inLayerCount, uint64_t inProducerUsage,
+ uint64_t inConsumerUsage, std::string requestorName)
{
GraphicBufferAllocator& allocator = GraphicBufferAllocator::get();
uint32_t outStride = 0;
status_t err = allocator.allocate(inWidth, inHeight, inFormat, inLayerCount,
- inUsage, &handle, &outStride, mId, std::move(requestorName));
+ inProducerUsage, inConsumerUsage, &handle, &outStride, mId,
+ std::move(requestorName));
if (err == NO_ERROR) {
width = static_cast<int>(inWidth);
height = static_cast<int>(inHeight);
format = inFormat;
layerCount = inLayerCount;
- usage = static_cast<int>(inUsage);
+ usage = static_cast<int>(inProducerUsage | inConsumerUsage);
stride = static_cast<int>(outStride);
}
return err;
status_t GraphicBuffer::lockAsync(uint32_t inUsage, const Rect& rect,
void** vaddr, int fenceFd)
{
+ return lockAsync(inUsage, inUsage, rect, vaddr, fenceFd);
+}
+
+status_t GraphicBuffer::lockAsync(uint64_t inProducerUsage,
+ uint64_t inConsumerUsage, const Rect& rect, void** vaddr, int fenceFd)
+{
if (rect.left < 0 || rect.right > width ||
rect.top < 0 || rect.bottom > height) {
ALOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)",
width, height);
return BAD_VALUE;
}
- status_t res = getBufferMapper().lockAsync(handle, inUsage, rect, vaddr,
- fenceFd);
+ status_t res = getBufferMapper().lockAsync(handle, inProducerUsage,
+ inConsumerUsage, rect, vaddr, fenceFd);
return res;
}
for (size_t i=0 ; i<c ; i++) {
const alloc_rec_t& rec(list.valueAt(i));
if (rec.size) {
- snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %4u | %8X | 0x%08x | %s\n",
+ snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %4u | %8X | 0x%" PRIx64
+ ", 0x%" PRIx64 " | %s\n",
list.keyAt(i), rec.size/1024.0,
rec.width, rec.stride, rec.height, rec.layerCount, rec.format,
- rec.usage, rec.requestorName.c_str());
+ rec.producerUsage, rec.consumerUsage,
+ rec.requestorName.c_str());
} else {
- snprintf(buffer, SIZE, "%10p: unknown | %4u (%4u) x %4u | %4u | %8X | 0x%08x | %s\n",
+ snprintf(buffer, SIZE, "%10p: unknown | %4u (%4u) x %4u | %4u | %8X | 0x%" PRIx64
+ ", 0x%" PRIx64 " | %s\n",
list.keyAt(i),
rec.width, rec.stride, rec.height, rec.layerCount, rec.format,
- rec.usage, rec.requestorName.c_str());
+ rec.producerUsage, rec.consumerUsage,
+ rec.requestorName.c_str());
}
result.append(buffer);
total += rec.size;
public:
HalBuffer(const Gralloc2::Allocator* allocator,
uint32_t width, uint32_t height,
- PixelFormat format, uint32_t layerCount, uint32_t usage)
+ PixelFormat format, uint32_t layerCount, uint64_t producerUsage,
+ uint64_t consumerUsage)
: mAllocator(allocator), mBufferValid(false)
{
Gralloc2::IAllocatorClient::BufferDescriptorInfo info = {};
info.height = height;
info.format = static_cast<Gralloc2::PixelFormat>(format);
info.layerCount = layerCount;
- info.producerUsageMask = usage;
- info.consumerUsageMask = usage;
+ info.producerUsageMask = producerUsage;
+ info.consumerUsageMask = consumerUsage;
Gralloc2::BufferDescriptor descriptor;
auto error = mAllocator->createBufferDescriptor(info, &descriptor);
if (error != Gralloc2::Error::NONE) {
- ALOGE("Failed to create desc (%u x %u) layerCount %u format %d usage %u: %d",
- width, height, layerCount, format, usage, error);
+ ALOGE("Failed to create desc (%u x %u) layerCount %u format %d producerUsage %" PRIx64
+ " consumerUsage %" PRIx64 ": %d",
+ width, height, layerCount, format, producerUsage,
+ consumerUsage, error);
return;
}
}
if (error != Gralloc2::Error::NONE) {
- ALOGE("Failed to allocate (%u x %u) layerCount %u format %d usage %u: %d",
- width, height, layerCount, format, usage, error);
+ ALOGE("Failed to allocate (%u x %u) layerCount %u format %d producerUsage %" PRIx64
+ " consumerUsage %" PRIx64 ": %d",
+ width, height, layerCount, format, producerUsage,
+ consumerUsage, error);
mAllocator->destroyBufferDescriptor(descriptor);
return;
}
} // namespace
status_t GraphicBufferAllocator::allocate(uint32_t width, uint32_t height,
- PixelFormat format, uint32_t layerCount, uint32_t usage,
- buffer_handle_t* handle, uint32_t* stride, uint64_t graphicBufferId,
- std::string requestorName)
+ PixelFormat format, uint32_t layerCount, uint64_t producerUsage,
+ uint64_t consumerUsage, buffer_handle_t* handle, uint32_t* stride,
+ uint64_t graphicBufferId, std::string requestorName)
{
ATRACE_CALL();
if (layerCount < 1)
layerCount = 1;
- // Filter out any usage bits that should not be passed to the gralloc module
- usage &= GRALLOC_USAGE_ALLOC_MASK;
-
gralloc1_error_t error;
if (mAllocator->valid()) {
HalBuffer buffer(mAllocator.get(), width, height, format, layerCount,
- usage);
+ producerUsage, consumerUsage);
if (!buffer.exportHandle(mMapper, handle, stride)) {
return NO_MEMORY;
}
return BAD_VALUE;
}
error = descriptor->setProducerUsage(
- static_cast<gralloc1_producer_usage_t>(usage));
+ static_cast<gralloc1_producer_usage_t>(producerUsage));
if (error != GRALLOC1_ERROR_NONE) {
- ALOGE("Failed to set producer usage to %u: %d", usage, error);
+ ALOGE("Failed to set producer usage to %" PRIx64 ": %d",
+ producerUsage, error);
return BAD_VALUE;
}
error = descriptor->setConsumerUsage(
- static_cast<gralloc1_consumer_usage_t>(usage));
+ static_cast<gralloc1_consumer_usage_t>(consumerUsage));
if (error != GRALLOC1_ERROR_NONE) {
- ALOGE("Failed to set consumer usage to %u: %d", usage, error);
+ ALOGE("Failed to set consumer usage to %" PRIx64 ": %d",
+ consumerUsage, error);
return BAD_VALUE;
}
error = mDevice->allocate(descriptor, graphicBufferId, handle);
if (error != GRALLOC1_ERROR_NONE) {
- ALOGE("Failed to allocate (%u x %u) layerCount %u format %d usage %u: %d",
- width, height, layerCount, format, usage, error);
+ ALOGE("Failed to allocate (%u x %u) layerCount %u format %d "
+ "producerUsage %" PRIx64 " consumerUsage %" PRIx64 ": %d",
+ width, height, layerCount, format, producerUsage,
+ consumerUsage, error);
return NO_MEMORY;
}
rec.stride = *stride;
rec.format = format;
rec.layerCount = layerCount;
- rec.usage = usage;
+ rec.producerUsage = producerUsage;
+ rec.consumerUsage = consumerUsage;
rec.size = static_cast<size_t>(height * (*stride) * bpp);
rec.requestorName = std::move(requestorName);
list.add(*handle, rec);
if (mMapper->valid()) {
error = static_cast<gralloc1_error_t>(mMapper->retain(handle));
} else {
+ // This always returns GRALLOC1_BAD_HANDLE when handle is from a
+ // remote process and mDevice is backed by Gralloc1On0Adapter.
error = mDevice->retain(handle);
+ if (error == GRALLOC1_ERROR_BAD_HANDLE &&
+ mDevice->hasCapability(GRALLOC1_CAPABILITY_ON_ADAPTER)) {
+ ALOGE("registerBuffer by handle is not supported with "
+ "Gralloc1On0Adapter");
+ }
}
ALOGW_IF(error != GRALLOC1_ERROR_NONE, "registerBuffer(%p) failed: %d",
return outRect;
}
+
+status_t GraphicBufferMapper::getDimensions(buffer_handle_t handle,
+ uint32_t* outWidth, uint32_t* outHeight) const
+{
+ ATRACE_CALL();
+
+ gralloc1_error_t error;
+ if (mMapper->valid()) {
+ mMapper->getDimensions(handle, outWidth, outHeight);
+ error = GRALLOC1_ERROR_NONE;
+ } else {
+ error = mDevice->getDimensions(handle, outWidth, outHeight);
+ }
+
+ ALOGW_IF(error != GRALLOC1_ERROR_NONE, "getDimensions(%p, ...): failed %d",
+ handle, error);
+
+ return error;
+}
+
+status_t GraphicBufferMapper::getFormat(buffer_handle_t handle,
+ int32_t* outFormat) const
+{
+ ATRACE_CALL();
+
+ gralloc1_error_t error;
+ if (mMapper->valid()) {
+ mMapper->getFormat(handle, outFormat);
+ error = GRALLOC1_ERROR_NONE;
+ } else {
+ error = mDevice->getFormat(handle, outFormat);
+ }
+
+ ALOGW_IF(error != GRALLOC1_ERROR_NONE, "getFormat(%p, ...): failed %d",
+ handle, error);
+
+ return error;
+}
+
+status_t GraphicBufferMapper::getLayerCount(buffer_handle_t handle,
+ uint32_t* outLayerCount) const
+{
+ ATRACE_CALL();
+
+ gralloc1_error_t error;
+ if (mMapper->valid()) {
+ mMapper->getLayerCount(handle, outLayerCount);
+ error = GRALLOC1_ERROR_NONE;
+ } else {
+ error = mDevice->getLayerCount(handle, outLayerCount);
+ }
+
+ ALOGW_IF(error != GRALLOC1_ERROR_NONE, "getLayerCount(%p, ...): failed %d",
+ handle, error);
+
+ return error;
+}
+
+status_t GraphicBufferMapper::getProducerUsage(buffer_handle_t handle,
+ uint64_t* outProducerUsage) const
+{
+ ATRACE_CALL();
+
+ gralloc1_error_t error;
+ if (mMapper->valid()) {
+ mMapper->getProducerUsage(handle, outProducerUsage);
+ error = GRALLOC1_ERROR_NONE;
+ } else {
+ error = mDevice->getProducerUsage(handle, outProducerUsage);
+ }
+
+ ALOGW_IF(error != GRALLOC1_ERROR_NONE,
+ "getProducerUsage(%p, ...): failed %d", handle, error);
+
+ return error;
+}
+
+status_t GraphicBufferMapper::getConsumerUsage(buffer_handle_t handle,
+ uint64_t* outConsumerUsage) const
+{
+ ATRACE_CALL();
+
+ gralloc1_error_t error;
+ if (mMapper->valid()) {
+ mMapper->getConsumerUsage(handle, outConsumerUsage);
+ error = GRALLOC1_ERROR_NONE;
+ } else {
+ error = mDevice->getConsumerUsage(handle, outConsumerUsage);
+ }
+
+ ALOGW_IF(error != GRALLOC1_ERROR_NONE,
+ "getConsumerUsage(%p, ...): failed %d", handle, error);
+
+ return error;
+}
+
+status_t GraphicBufferMapper::getBackingStore(buffer_handle_t handle,
+ uint64_t* outBackingStore) const
+{
+ ATRACE_CALL();
+
+ gralloc1_error_t error;
+ if (mMapper->valid()) {
+ mMapper->getBackingStore(handle, outBackingStore);
+ error = GRALLOC1_ERROR_NONE;
+ } else {
+ error = mDevice->getBackingStore(handle, outBackingStore);
+ }
+
+ ALOGW_IF(error != GRALLOC1_ERROR_NONE,
+ "getBackingStore(%p, ...): failed %d", handle, error);
+
+ return error;
+}
+
+status_t GraphicBufferMapper::getStride(buffer_handle_t handle,
+ uint32_t* outStride) const
+{
+ ATRACE_CALL();
+
+ gralloc1_error_t error;
+ if (mMapper->valid()) {
+ mMapper->getStride(handle, outStride);
+ error = GRALLOC1_ERROR_NONE;
+ } else {
+ error = mDevice->getStride(handle, outStride);
+ }
+
+ ALOGW_IF(error != GRALLOC1_ERROR_NONE, "getStride(%p, ...): failed %d",
+ handle, error);
+
+ return error;
+}
+
status_t GraphicBufferMapper::lock(buffer_handle_t handle, uint32_t usage,
const Rect& bounds, void** vaddr)
{
status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle,
uint32_t usage, const Rect& bounds, void** vaddr, int fenceFd)
{
+ return lockAsync(handle, usage, usage, bounds, vaddr, fenceFd);
+}
+
+status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle,
+ uint64_t producerUsage, uint64_t consumerUsage, const Rect& bounds,
+ void** vaddr, int fenceFd)
+{
ATRACE_CALL();
gralloc1_rect_t accessRegion = asGralloc1Rect(bounds);
const Gralloc2::IMapper::Rect& accessRect =
*reinterpret_cast<Gralloc2::IMapper::Rect*>(&accessRegion);
error = static_cast<gralloc1_error_t>(mMapper->lock(
- handle, usage, usage, accessRect, fenceFd, vaddr));
+ handle, producerUsage, consumerUsage, accessRect,
+ fenceFd, vaddr));
} else {
sp<Fence> fence = new Fence(fenceFd);
error = mDevice->lock(handle,
- static_cast<gralloc1_producer_usage_t>(usage),
- static_cast<gralloc1_consumer_usage_t>(usage),
+ static_cast<gralloc1_producer_usage_t>(producerUsage),
+ static_cast<gralloc1_consumer_usage_t>(consumerUsage),
&accessRegion, vaddr, fence);
}
//#define LOG_NDEBUG 1
#define LOG_TAG "GraphicsEnv"
-#include <gui/GraphicsEnv.h>
+#include <ui/GraphicsEnv.h>
#include <mutex>
#include <ui/HdrCapabilities.h>
-#include <binder/Parcel.h>
-
namespace android {
-status_t HdrCapabilities::writeToParcel(Parcel* parcel) const
-{
- status_t result = parcel->writeInt32Vector(mSupportedHdrTypes);
- if (result != OK) {
- return result;
- }
- result = parcel->writeFloat(mMaxLuminance);
- if (result != OK) {
- return result;
+#if defined(__clang__)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wundefined-reinterpret-cast"
+#endif
+
+HdrCapabilities::~HdrCapabilities() = default;
+HdrCapabilities::HdrCapabilities(HdrCapabilities&& other) = default;
+HdrCapabilities& HdrCapabilities::operator=(HdrCapabilities&& other) = default;
+
+
+size_t HdrCapabilities::getFlattenedSize() const {
+ return sizeof(mMaxLuminance) +
+ sizeof(mMaxAverageLuminance) +
+ sizeof(mMinLuminance) +
+ sizeof(int32_t) +
+ mSupportedHdrTypes.size() * sizeof(int32_t);
+}
+
+status_t HdrCapabilities::flatten(void* buffer, size_t size) const {
+
+ if (size < getFlattenedSize()) {
+ return NO_MEMORY;
}
- result = parcel->writeFloat(mMaxAverageLuminance);
- if (result != OK) {
- return result;
+
+ int32_t* const buf = static_cast<int32_t*>(buffer);
+ reinterpret_cast<float&>(buf[0]) = mMaxLuminance;
+ reinterpret_cast<float&>(buf[1]) = mMaxAverageLuminance;
+ reinterpret_cast<float&>(buf[2]) = mMinLuminance;
+ buf[3] = static_cast<int32_t>(mSupportedHdrTypes.size());
+ for (size_t i = 0, c = mSupportedHdrTypes.size(); i < c; ++i) {
+ buf[4 + i] = mSupportedHdrTypes[i];
}
- result = parcel->writeFloat(mMinLuminance);
- return result;
+ return NO_ERROR;
}
-status_t HdrCapabilities::readFromParcel(const Parcel* parcel)
-{
- status_t result = parcel->readInt32Vector(&mSupportedHdrTypes);
- if (result != OK) {
- return result;
+status_t HdrCapabilities::unflatten(void const* buffer, size_t size) {
+
+ size_t minSize = sizeof(mMaxLuminance) +
+ sizeof(mMaxAverageLuminance) +
+ sizeof(mMinLuminance) +
+ sizeof(int32_t);
+
+ if (size < minSize) {
+ return NO_MEMORY;
}
- result = parcel->readFloat(&mMaxLuminance);
- if (result != OK) {
- return result;
+
+ int32_t const * const buf = static_cast<int32_t const *>(buffer);
+ const size_t itemCount = size_t(buf[3]);
+
+ // check the buffer is large enough
+ if (size < minSize + itemCount * sizeof(int32_t)) {
+ return BAD_VALUE;
}
- result = parcel->readFloat(&mMaxAverageLuminance);
- if (result != OK) {
- return result;
+
+ mMaxLuminance = reinterpret_cast<float const&>(buf[0]);
+ mMaxAverageLuminance = reinterpret_cast<float const&>(buf[1]);
+ mMinLuminance = reinterpret_cast<float const&>(buf[2]);
+ if (itemCount) {
+ mSupportedHdrTypes.reserve(itemCount);
+ for (size_t i = 0; i < itemCount; ++i) {
+ mSupportedHdrTypes[i] = buf[4 + i];
+ }
}
- result = parcel->readFloat(&mMinLuminance);
- return result;
+ return NO_ERROR;
}
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
} // namespace android
struct DisplayRPC {
// Service path.
- static constexpr char kClientPath[] = "system/display/client";
+ static constexpr char kClientPath[] = "system/vr/display/client";
// Op codes.
enum {
struct DisplayManagerRPC {
// Service path.
- static constexpr char kClientPath[] = "system/display/manager";
+ static constexpr char kClientPath[] = "system/vr/display/manager";
// Op codes.
enum {
struct DisplayScreenshotRPC {
// Service path.
- static constexpr char kClientPath[] = "system/display/screenshot";
+ static constexpr char kClientPath[] = "system/vr/display/screenshot";
// Op codes.
enum {
struct DisplayVSyncRPC {
// Service path.
- static constexpr char kClientPath[] = "system/display/vsync";
+ static constexpr char kClientPath[] = "system/vr/display/vsync";
// Op codes.
enum {
status.GetErrorMessage().c_str());
return -status.error();
}
- *timestamp_ns = status.get();
+
+ if (timestamp_ns != nullptr) {
+ *timestamp_ns = status.get();
+ }
return 0;
}
if (blend_with_previous_layer) {
// Check for unsupported shader combinations:
LOG_ALWAYS_FATAL_IF(num_layers != 1);
- LOG_ALWAYS_FATAL_IF(!use_alpha_vignette);
+ LOG_ALWAYS_FATAL_IF(use_alpha_vignette);
if (kUseFramebufferReadback)
frag_builder += "#define BLEND_WITH_PREVIOUS_LAYER\n";
}
# Java platform library for the system implementation of the GVR API.
include $(CLEAR_VARS)
-LOCAL_MODULE := gvr_platform
-LOCAL_MODULE_STEM := com.google.vr.gvr.platform
+LOCAL_MODULE := com.google.vr.gvr.platform
LOCAL_REQUIRED_MODULES := libgvr_system_loader libgvr_system
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_SRC_FILES := $(call all-java-files-under, java)
include $(BUILD_JAVA_LIBRARY)
# Library to perform dlopen on the actual platform library.
package com.google.vr.gvr.platform;
+import android.os.SystemProperties;
+
/**
* Auxiliary class to load the system implementation of the GVR API.
+ * @hide
*/
public class Loader {
- /**
- * Opens a shared library containing the system implementation for the GVR
- * API and returns the handle to it.
- *
- * @return A Long object describing the handle returned by dlopen.
- */
- public static Long loadLibrary() {
- // Note: we cannot safely do caller verifications here, so instead we do
- // them in the service side. This means that private API symbols will be
- // visible to any app adding the appropriate <uses-library> in their
- // manifest, but any requests to such APIs will fail if not done from a
- // trusted package like VrCore.
- //
- // Trusted packages are defined by (package name, signature) pairs in within
- // a system service, and both must match.
-
- // Load a thin JNI library that runs dlopen on request.
- System.loadLibrary("gvr_system_loader");
-
- // Performs dlopen on the library and returns the handle.
- return nativeLoadLibrary("libgvr_system.so");
- }
-
- private static native long nativeLoadLibrary(String library);
+ private static final String VR_MODE_BOOT = "ro.boot.vr";
+
+ /**
+ * Opens a shared library containing the system implementation for the GVR API and returns the
+ * handle to it.
+ *
+ * @return A Long object describing the handle returned by dlopen.
+ */
+ public static Long loadLibrary() {
+ // Note: caller verifications cannot be safely done here. Any app can find and use this API.
+ // Any sensitive functions must have appropriate checks on the service side.
+
+ // Load a thin JNI library that runs dlopen on request.
+ System.loadLibrary("gvr_system_loader");
+
+ // Performs dlopen on the library and returns the handle.
+ return nativeLoadLibrary("libgvr_system.so");
+ }
+
+ /**
+ * Returns true if this device boots directly in VR mode.
+ */
+ public static boolean getVrBoot() {
+ return SystemProperties.getBoolean(VR_MODE_BOOT, false);
+ }
+
+ private static native long nativeLoadLibrary(String library);
}
}
bool gvr_is_feature_supported(const gvr_context* /*gvr*/, int32_t feature) {
- return feature == GVR_FEATURE_ASYNC_REPROJECTION;
+ return feature == GVR_FEATURE_ASYNC_REPROJECTION ||
+ feature == GVR_FEATURE_HEAD_POSE_6DOF;
}
/////////////////////////////////////////////////////////////////////////////
extern "C" {
#endif
-#define DVR_POSE_SERVICE_BASE "system/pose"
+#define DVR_POSE_SERVICE_BASE "system/vr/pose"
#define DVR_POSE_SERVICE_CLIENT (DVR_POSE_SERVICE_BASE "/client")
enum {
#ifndef ANDROID_DVR_SENSOR_IPC_H_
#define ANDROID_DVR_SENSOR_IPC_H_
-#define DVR_SENSOR_SERVICE_BASE "system/sensors"
+#define DVR_SENSOR_SERVICE_BASE "system/vr/sensors"
#define DVR_SENSOR_SERVICE_CLIENT (DVR_SENSOR_SERVICE_BASE "/client")
LOCAL_PATH := $(call my-dir)
+exported_include_dirs := \
+ $(LOCAL_PATH)/include
+
+include_dirs := \
+ frameworks/native/include/vr/vr_manager \
+ $(exported_include_dirs)
+
src_files := \
vr_manager.cpp \
-
-inc_files := \
- frameworks/native/include/vr/vr_manager
+ trusted_uids.cpp
static_libs := \
libutils \
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(src_files)
-LOCAL_C_INCLUDES := $(inc_files)
+LOCAL_C_INCLUDES := $(include_dirs)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(exported_include_dirs)
LOCAL_CFLAGS += -Wall
LOCAL_CFLAGS += -Werror
LOCAL_CFLAGS += -Wunused
LOCAL_CFLAGS += -Wunreachable-code
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(inc_files)
-#LOCAL_SHARED_LIBRARIES := $(sharedLibraries)
LOCAL_STATIC_LIBRARIES := $(static_libs)
LOCAL_MODULE := libvr_manager
include $(BUILD_STATIC_LIBRARY)
--- /dev/null
+#ifndef ANDROID_DVR_TRUSTED_UIDS_H_
+#define ANDROID_DVR_TRUSTED_UIDS_H_
+
+#include <sys/types.h>
+
+namespace android {
+namespace dvr {
+
+/**
+ * Tells if a provided UID can be trusted to access restricted VR APIs.
+ *
+ * UID trust is based on the android.permission.RESTRICTED_VR_ACCESS permission.
+ * AID_SYSTEM and AID_ROOT are automatically trusted by Android.
+ *
+ * UIDs are guaranteed not to be reused until the next reboot even in case
+ * of package reinstall. For performance reasons this method caches results by
+ * default, as otherwise every check would trigger a Java call.
+ *
+ * This function is thread-safe.
+ *
+ * @param uid The uid to check.
+ * @param use_cache If true any cached result for the provided uid will be
+ * reused. If false this call will reach the Application Manager Service
+ * in Java to get updated values. Any updates will be stored in the cache.
+ * @return true if the uid is trusted, false if not or if the VR Manager Service
+ * could not be reached to verify the uid.
+ */
+bool IsTrustedUid(uid_t uid, bool use_cache = true);
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_TRUSTED_UIDS_H_
--- /dev/null
+#include "private/dvr/trusted_uids.h"
+
+#include <mutex>
+#include <unordered_map>
+
+#include <binder/IPermissionController.h>
+#include <binder/IServiceManager.h>
+#include <private/android_filesystem_config.h>
+#include <utils/String16.h>
+#include <vr/vr_manager/vr_manager.h>
+
+namespace android {
+namespace dvr {
+
+bool IsTrustedUid(uid_t uid, bool use_cache) {
+ static std::unordered_map<uid_t, bool> uid_cache;
+ static std::mutex uid_cache_mutex;
+
+ // Whitelist requests from the system UID.
+ // These are already whitelisted by the permission service, but it might not
+ // be available if the ActivityManagerService is up during boot.
+ // This ensures the correct result for system services while booting up.
+ if (uid == AID_SYSTEM)
+ return true;
+
+ std::lock_guard<std::mutex> lock(uid_cache_mutex);
+
+ if (use_cache) {
+ auto it = uid_cache.find(uid);
+ if (it != uid_cache.end())
+ return it->second;
+ }
+
+ sp<IBinder> binder = defaultServiceManager()->getService(String16("permission"));
+ if (binder == 0) {
+ ALOGW("Could not access permission service");
+ return false;
+ }
+
+ // Note: we ignore the pid because it's only used to automatically reply
+ // true if the caller is the Activity Manager Service.
+ bool trusted = interface_cast<IPermissionController>(binder)->checkPermission(
+ String16("android.permission.RESTRICTED_VR_ACCESS"), -1, uid);
+
+ // Cache the information for this uid to avoid future Java calls.
+ uid_cache[uid] = trusted;
+ return trusted;
+}
+
+} // namespace dvr
+} // namespace android
libperformance \
libsensor \
libpdx_default_transport \
+ libvr_manager \
sharedLibraries := \
android.dvr.composer@1.0 \
LOCAL_CFLAGS += -DTRACE=0
LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_GRAPHICS
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-ifeq ($(TARGET_USES_QCOM_BSP), true)
- LOCAL_C_INCLUDES += hardware/qcom/display/libgralloc
- LOCAL_C_INCLUDES += hardware/qcom/display/libqdutils
- LOCAL_SHARED_LIBRARIES += libqdutils
-endif
LOCAL_SHARED_LIBRARIES := $(sharedLibraries)
LOCAL_WHOLE_STATIC_LIBRARIES := $(staticLibraries)
LOCAL_MODULE := libvrflinger
return hardware_composer_.SetDisplaySurfaces(std::move(visible_surfaces));
}
+void DisplayService::OnHardwareComposerRefresh() {
+ hardware_composer_.OnHardwareComposerRefresh();
+}
+
void DisplayService::SetDisplayConfigurationUpdateNotifier(
DisplayConfigurationUpdateNotifier update_notifier) {
update_notifier_ = update_notifier;
}
}
+ void OnHardwareComposerRefresh();
+
private:
friend BASE;
friend DisplaySurface;
ATRACE_NAME("DisplaySurface::OnPostConsumer");
std::lock_guard<std::mutex> autolock(lock_);
+ if (!IsVisible()) {
+ ALOGD_IF(TRACE,
+ "DisplaySurface::OnPostConsumer: Discarding buffer_id=%d on "
+ "invisible surface.",
+ consumer->id());
+ consumer->Discard();
+ return;
+ }
+
if (posted_buffers_.IsFull()) {
ALOGE("Error: posted buffers full, overwriting");
posted_buffers_.PopBack();
display_transform_(HWC_TRANSFORM_NONE),
display_surfaces_updated_(false),
hardware_layers_need_update_(false),
- display_on_(false),
active_layer_count_(0),
gpu_layer_(nullptr),
+ post_thread_state_(PostThreadState::kPaused),
terminate_post_thread_event_fd_(-1),
- pause_post_thread_(true),
backlight_brightness_fd_(-1),
primary_display_vsync_event_fd_(-1),
primary_display_wait_pp_fd_(-1),
}
HardwareComposer::~HardwareComposer(void) {
- if (!IsSuspended()) {
- Suspend();
- }
+ Suspend();
}
bool HardwareComposer::Resume() {
- std::lock_guard<std::mutex> autolock(layer_mutex_);
-
- if (!IsSuspended()) {
- ALOGE("HardwareComposer::Resume: HardwareComposer is already running.");
+ std::lock_guard<std::mutex> post_thread_lock(post_thread_state_mutex_);
+ if (post_thread_state_ == PostThreadState::kRunning) {
return false;
}
+ std::lock_guard<std::mutex> layer_lock(layer_mutex_);
+
int32_t ret = HWC2_ERROR_NONE;
static const uint32_t attributes[] = {
layer->Initialize(hwc2_hidl_.get(), &native_display_metrics_);
}
+#if ENABLE_BACKLIGHT_BRIGHTNESS
+ // TODO(hendrikw): This isn't required at the moment. It's possible that there
+ // is another method to access this when needed.
// Open the backlight brightness control sysfs node.
backlight_brightness_fd_ = LocalHandle(kBacklightBrightnessSysFile, O_RDWR);
ALOGW_IF(!backlight_brightness_fd_,
"HardwareComposer: Failed to open backlight brightness control: %s",
strerror(errno));
+#endif // ENABLE_BACKLIGHT_BRIGHTNESS
// Open the vsync event node for the primary display.
// TODO(eieio): Move this into a platform-specific class.
pose_client_ = dvrPoseCreate();
ALOGE_IF(!pose_client_, "HardwareComposer: Failed to create pose client");
- // Variables used to control the post thread state
- pause_post_thread_ = false;
- terminate_post_thread_event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
-
+ terminate_post_thread_event_fd_.Reset(
+ eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
LOG_ALWAYS_FATAL_IF(
!terminate_post_thread_event_fd_,
"HardwareComposer: Failed to create terminate PostThread event fd : %s",
strerror(errno));
+ post_thread_state_ = PostThreadState::kRunning;
+ post_thread_state_cond_var_.notify_all();
+
// If get_id() is the default thread::id object, it has not been created yet
if (post_thread_.get_id() == std::thread::id()) {
post_thread_ = std::thread(&HardwareComposer::PostThread, this);
} else {
UpdateDisplayState();
- thread_pause_semaphore_.notify_one();
}
return true;
}
bool HardwareComposer::Suspend() {
- // Wait for any pending layer operations to finish
- std::unique_lock<std::mutex> layer_lock(layer_mutex_);
-
- if (IsSuspended()) {
- ALOGE("HardwareComposer::Suspend: HardwareComposer is already suspended.");
+ std::unique_lock<std::mutex> post_thread_lock(post_thread_state_mutex_);
+ if (post_thread_state_ == PostThreadState::kPaused) {
return false;
}
- PausePostThread();
+ post_thread_state_ = PostThreadState::kPauseRequested;
+
+ int error = eventfd_write(terminate_post_thread_event_fd_.Get(), 1);
+ ALOGE_IF(error,
+ "HardwareComposer::Suspend: could not write post "
+ "thread termination event fd : %d",
+ error);
+
+ post_thread_state_cond_var_.wait(
+ post_thread_lock,
+ [this] { return post_thread_state_ == PostThreadState::kPaused; });
+ terminate_post_thread_event_fd_.Close();
+
+ // Wait for any pending layer operations to finish
+ std::lock_guard<std::mutex> layer_lock(layer_mutex_);
EnableVsync(false);
- SetPowerMode(HWC_DISPLAY_PRIMARY, HWC2_POWER_MODE_OFF);
backlight_brightness_fd_.Close();
primary_display_vsync_event_fd_.Close();
return true;
}
-void HardwareComposer::PausePostThread() {
- pause_post_thread_ = true;
-
- int error = eventfd_write(terminate_post_thread_event_fd_.Get(), 1);
- ALOGE_IF(error,
- "HardwareComposer::PausePostThread: could not write post "
- "thread termination event fd : %d",
- error);
-
- std::unique_lock<std::mutex> wait_for_thread(thread_pause_mutex_);
- terminate_post_thread_event_fd_.Close();
-}
-
DisplayMetrics HardwareComposer::GetHmdDisplayMetrics() const {
vec2i screen_size(display_metrics_.width, display_metrics_.height);
DisplayOrientation orientation =
return error;
}
-int32_t HardwareComposer::SetPowerMode(hwc2_display_t display,
- hwc2_power_mode_t mode) {
- if (mode == HWC2_POWER_MODE_OFF) {
- EnableVsync(false);
- }
-
- display_on_ = mode != HWC2_POWER_MODE_OFF;
-
- return (int32_t)hwc2_hidl_->setPowerMode(
- display, (Hwc2::IComposerClient::PowerMode)mode);
-}
-
int32_t HardwareComposer::GetDisplayAttribute(hwc2_display_t display,
hwc2_config_t config,
hwc2_attribute_t attribute,
const bool has_display_surfaces = display_surfaces_.size() > 0;
if (has_display_surfaces) {
- int32_t ret = SetPowerMode(HWC_DISPLAY_PRIMARY, HWC2_POWER_MODE_ON);
-
- ALOGE_IF(ret, "HardwareComposer: Could not set power mode; ret=%d", ret);
-
EnableVsync(true);
}
+
// TODO(skiazyk): We need to do something about accessing this directly,
// supposedly there is a backlight service on the way.
SetBacklightBrightness(255);
- if (!display_on_ && has_display_surfaces) {
- const int error = ReadVSyncTimestamp(&last_vsync_timestamp_);
- ALOGE_IF(error < 0,
- "HardwareComposer::SetDisplaySurfaces: Failed to read vsync "
- "timestamp: %s",
- strerror(-error));
- }
-
// Trigger target-specific performance mode change.
- property_set(kDvrPerformanceProperty, display_on_ ? "performance" : "idle");
+ property_set(kDvrPerformanceProperty, has_display_surfaces ? "performance" : "idle");
}
int HardwareComposer::SetDisplaySurfaces(
std::vector<std::shared_ptr<DisplaySurface>> surfaces) {
- std::lock_guard<std::mutex> autolock(layer_mutex_);
+ // The double lock is necessary because we access both the display surfaces
+ // and post_thread_state_.
+ std::lock_guard<std::mutex> post_thread_state_lock(post_thread_state_mutex_);
+ std::lock_guard<std::mutex> layer_lock(layer_mutex_);
ALOGI("HardwareComposer::SetDisplaySurfaces: surface count=%zd",
surfaces.size());
// TODO(skiazyk): fix this so that it is handled seamlessly with dormant/non-
// dormant state.
- if (!IsSuspended()) {
+ if (post_thread_state_ == PostThreadState::kRunning) {
UpdateDisplayState();
}
// Blocks until the next vsync event is signaled by the display driver.
// TODO(eieio): This is pretty driver specific, this should be moved to a
// separate class eventually.
-int HardwareComposer::BlockUntilVSync() {
+int HardwareComposer::BlockUntilVSync(/*out*/ bool* suspend_requested) {
+ *suspend_requested = false;
const int event_fd = primary_display_vsync_event_fd_.Get();
pollfd pfd[2] = {
{
strerror(error), error);
} while (ret < 0 && error == EINTR);
+ if (ret >= 0 && pfd[1].revents != 0)
+ *suspend_requested = true;
return ret < 0 ? -error : 0;
}
if (error == -EAGAIN) {
// Vsync was turned off, wait for the next vsync event.
- error = BlockUntilVSync();
- if (error < 0)
+ bool suspend_requested = false;
+ error = BlockUntilVSync(&suspend_requested);
+ if (error < 0 || suspend_requested)
return error;
- // If a request to pause the post thread was given, exit immediately
- if (IsSuspended()) {
- return 0;
- }
-
// Try again to get the timestamp for this new vsync interval.
continue;
}
if (distance_to_vsync_est > threshold_ns) {
// Wait for vsync event notification.
- error = BlockUntilVSync();
- if (error < 0)
+ bool suspend_requested = false;
+ error = BlockUntilVSync(&suspend_requested);
+ if (error < 0 || suspend_requested)
return error;
-
- // Again, exit immediately if the thread was requested to pause
- if (IsSuspended()) {
- return 0;
- }
} else {
// Sleep for a short time before retrying.
std::this_thread::sleep_for(std::chrono::milliseconds(1));
// NOLINTNEXTLINE(runtime/int)
prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("PostThread"), 0, 0, 0);
- std::unique_lock<std::mutex> thread_lock(thread_pause_mutex_);
-
// Set the scheduler to SCHED_FIFO with high priority.
int error = dvrSetSchedulerClass(0, "graphics:high");
LOG_ALWAYS_FATAL_IF(
while (1) {
ATRACE_NAME("HardwareComposer::PostThread");
- while (IsSuspended()) {
- ALOGI("HardwareComposer::PostThread: Post thread pause requested.");
- thread_pause_semaphore_.wait(thread_lock);
- // The layers will need to be updated since they were deleted previously
- display_surfaces_updated_ = true;
- hardware_layers_need_update_ = true;
+ {
+ std::unique_lock<std::mutex> post_thread_lock(post_thread_state_mutex_);
+ if (post_thread_state_ == PostThreadState::kPauseRequested) {
+ ALOGI("HardwareComposer::PostThread: Post thread pause requested.");
+ post_thread_state_ = PostThreadState::kPaused;
+ post_thread_state_cond_var_.notify_all();
+ post_thread_state_cond_var_.wait(
+ post_thread_lock,
+ [this] { return post_thread_state_ == PostThreadState::kRunning; });
+ // The layers will need to be updated since they were deleted previously
+ display_surfaces_updated_ = true;
+ hardware_layers_need_update_ = true;
+ }
}
int64_t vsync_timestamp = 0;
strerror(-error));
// Don't bother processing this frame if a pause was requested
- if (IsSuspended()) {
+ std::lock_guard<std::mutex> post_thread_lock(post_thread_state_mutex_);
+ if (post_thread_state_ == PostThreadState::kPauseRequested) {
continue;
}
}
bool HardwareComposer::UpdateLayerConfig(
std::vector<std::shared_ptr<DisplaySurface>>* compositor_surfaces) {
- std::lock_guard<std::mutex> autolock(layer_mutex_);
+ std::lock_guard<std::mutex> layer_lock(layer_mutex_);
if (!display_surfaces_updated_)
return false;
// TODO(eieio): implement display hotplug callbacks.
}
+void HardwareComposer::OnHardwareComposerRefresh() {
+ // TODO(steventhomas): Handle refresh.
+}
+
void HardwareComposer::SetBacklightBrightness(int brightness) {
if (backlight_brightness_fd_) {
std::array<char, 32> text;
if (composition_type_ == HWC2_COMPOSITION_DEVICE) {
ret = (int32_t)hwc2_hidl_->setLayerBuffer(HWC_DISPLAY_PRIMARY,
- hardware_composer_layer_, handle,
+ hardware_composer_layer_, 0,
+ handle,
acquire_fence_fd_.Get());
ALOGE_IF(ret, "HardwareComposer: Error setting layer buffer : %d", ret);
bool Suspend();
bool Resume();
- bool IsSuspended() const { return pause_post_thread_; }
// Get the HMD display metrics for the current display.
DisplayMetrics GetHmdDisplayMetrics() const;
Compositor* GetCompositor() { return &compositor_; }
+ void OnHardwareComposerRefresh();
+
private:
int32_t EnableVsync(bool enabled);
- int32_t SetPowerMode(hwc2_display_t display, hwc2_power_mode_t mode);
class ComposerCallback : public Hwc2::IComposerCallback {
public:
void PostThread();
int ReadWaitPPState();
- int BlockUntilVSync();
+ int BlockUntilVSync(/*out*/ bool* suspend_requested);
int ReadVSyncTimestamp(int64_t* timestamp);
int WaitForVSync(int64_t* timestamp);
int SleepUntil(int64_t wakeup_timestamp);
void HandlePendingScreenshots();
- void PausePostThread();
-
// Hardware composer HAL device.
std::unique_ptr<Hwc2::Composer> hwc2_hidl_;
sp<ComposerCallback> callbacks_;
bool display_surfaces_updated_;
bool hardware_layers_need_update_;
- // Cache whether the display was turned on by us
- bool display_on_; // TODO(hendrikw): The display is always on. Revisit.
-
// Layer array for handling buffer flow into hardware composer layers.
// Note that the first array is the actual storage for the layer objects,
// and the latter is an array of pointers, which can be freely re-arranged
// Handler to hook vsync events outside of this class.
VSyncCallback vsync_callback_;
- // Thread and condition for managing the layer posting thread. This thread
- // wakes up a short time before vsync to hand buffers to post processing and
- // the results to hardware composer.
+ // The layer posting thread. This thread wakes up a short time before vsync to
+ // hand buffers to post processing and the results to hardware composer.
std::thread post_thread_;
+ enum class PostThreadState {
+ // post_thread_state_ starts off paused. When suspending, the control thread
+ // will block until post_thread_state_ == kPaused, indicating the post
+ // thread has completed the transition to paused (most importantly: no more
+ // hardware composer calls).
+ kPaused,
+ // post_thread_state_ is set to kRunning by the control thread (either
+ // surface flinger's main thread or the vr flinger dispatcher thread). The
+ // post thread blocks until post_thread_state_ == kRunning.
+ kRunning,
+ // Set by the control thread to indicate the post thread should pause. The
+ // post thread will change post_thread_state_ from kPauseRequested to
+ // kPaused when it stops.
+ kPauseRequested
+ };
// Control variables to control the state of the post thread
+ PostThreadState post_thread_state_;
+ // Used to wake the post thread up while it's waiting for vsync, for faster
+ // transition to the paused state.
pdx::LocalHandle terminate_post_thread_event_fd_;
- bool pause_post_thread_;
- std::mutex thread_pause_mutex_;
- std::condition_variable thread_pause_semaphore_;
+ // post_thread_state_mutex_ should be held before checking or modifying
+ // post_thread_state_.
+ std::mutex post_thread_state_mutex_;
+ // Used to communicate between the control thread and the post thread.
+ std::condition_variable post_thread_state_cond_var_;
// Backlight LED brightness sysfs node.
pdx::LocalHandle backlight_brightness_fd_;
void EnterVrMode();
void ExitVrMode();
+ void OnHardwareComposerRefresh();
private:
std::thread displayd_thread_;
#include <utils/Trace.h>
#include <pdx/default_transport/service_endpoint.h>
+#include <private/android_filesystem_config.h>
#include <private/dvr/display_types.h>
+#include <private/dvr/trusted_uids.h>
using android::pdx::Message;
using android::pdx::MessageInfo;
ScreenshotData ScreenshotService::OnTakeScreenshot(pdx::Message& message,
int layer_index) {
+ // Also allow AID_SHELL to support vrscreencap commands.
+ if (message.GetEffectiveUserId() != AID_SHELL &&
+ !IsTrustedUid(message.GetEffectiveUserId())) {
+ REPLY_ERROR_RETURN(message, EACCES, {});
+ }
+
AddWaiter(std::move(message), layer_index);
return {};
}
VrFlinger::VrFlinger() {}
int VrFlinger::Run(Hwc2::Composer* hidl) {
+ if (!hidl)
+ return EINVAL;
+
std::shared_ptr<android::pdx::Service> service;
ALOGI("Starting up VrFlinger...");
}
}
+void VrFlinger::OnHardwareComposerRefresh() {
+ if (display_service_) {
+ display_service_->OnHardwareComposerRefresh();
+ } else {
+ ALOGE("OnHardwareComposerRefresh failed : Display service is not started.");
+ }
+}
+
} // namespace dvr
} // namespace android
],
static_libs: ["libEGL_getProcAddress"],
ldflags: ["-Wl,--exclude-libs=ALL"],
-
- required: ["egl.cfg"],
}
cc_defaults {
LOCAL_PATH:= $(call my-dir)
-
-# OpenGL drivers config file
-ifneq ($(BOARD_EGL_CFG),)
-include $(CLEAR_VARS)
-LOCAL_MODULE := egl.cfg
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/egl
-LOCAL_SRC_FILES := ../../../../$(BOARD_EGL_CFG)
-include $(BUILD_PREBUILT)
-endif
#include <cutils/properties.h>
#include <log/log.h>
#include <utils/Trace.h>
+#include <ui/GraphicsEnv.h>
#include <EGL/egl.h>
// ----------------------------------------------------------------------------
Loader::Loader()
- : getProcAddress(NULL),
- mLibGui(nullptr),
- mGetDriverNamespace(nullptr)
+ : getProcAddress(NULL)
{
- // FIXME: See note in GraphicsEnv.h about android_getDriverNamespace().
- // libgui should already be loaded in any process that uses libEGL, but
- // if for some reason it isn't, then we're not going to get a driver
- // namespace anyway, so don't force it to be loaded.
- mLibGui = dlopen("libgui.so", RTLD_NOLOAD | RTLD_LOCAL | RTLD_LAZY);
- if (!mLibGui) {
- ALOGD("failed to load libgui: %s", dlerror());
- return;
- }
- mGetDriverNamespace = reinterpret_cast<decltype(mGetDriverNamespace)>(
- dlsym(mLibGui, "android_getDriverNamespace"));
}
Loader::~Loader() {
- if (mLibGui)
- dlclose(mLibGui);
}
static void* load_wrapper(const char* path) {
ATRACE_CALL();
void* dso = nullptr;
- if (mGetDriverNamespace) {
- android_namespace_t* ns = mGetDriverNamespace();
- if (ns) {
- dso = load_updated_driver(kind, ns);
- }
+ android_namespace_t* ns = android_getDriverNamespace();
+ if (ns) {
+ dso = load_updated_driver(kind, ns);
}
if (!dso) {
dso = load_system_driver(kind);
#include <utils/Singleton.h>
#include <utils/String8.h>
-#include <gui/GraphicsEnv.h>
-
#include <EGL/egl.h>
// ----------------------------------------------------------------------------
getProcAddressType getProcAddress;
- void* mLibGui;
- decltype(android_getDriverNamespace)* mGetDriverNamespace;
-
public:
~Loader();
#include <stdlib.h>
#include <string.h>
-#include <hardware/gralloc.h>
+#include <hardware/gralloc1.h>
#include <system/window.h>
#include <EGL/egl.h>
{
clearError();
- int usage = 0;
+ uint64_t producerUsage = 0;
+ uint64_t consumerUsage = 0;
uint32_t width = 0;
uint32_t height = 0;
uint32_t format = 0;
GET_NONNEGATIVE_VALUE(EGL_LAYER_COUNT_ANDROID, layer_count);
case EGL_NATIVE_BUFFER_USAGE_ANDROID:
if (value & EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID) {
- usage |= GRALLOC_USAGE_PROTECTED;
+ producerUsage |= GRALLOC1_PRODUCER_USAGE_PROTECTED;
}
if (value & EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID) {
- usage |= GRALLOC_USAGE_HW_RENDER;
+ producerUsage |= GRALLOC1_PRODUCER_USAGE_GPU_RENDER_TARGET;
}
if (value & EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID) {
- usage |= GRALLOC_USAGE_HW_TEXTURE;
+ consumerUsage |= GRALLOC1_CONSUMER_USAGE_GPU_TEXTURE;
}
break;
default:
CHECK_ERROR_CONDITION("Unable to write format");
err = data.writeUint32(layer_count);
CHECK_ERROR_CONDITION("Unable to write layer count");
- err = data.writeUint32(usage);
- CHECK_ERROR_CONDITION("Unable to write usage");
+ err = data.writeUint64(producerUsage);
+ CHECK_ERROR_CONDITION("Unable to write producer usage");
+ err = data.writeUint64(consumerUsage);
+ CHECK_ERROR_CONDITION("Unable to write consumer usage");
err = data.writeUtf8AsUtf16(
std::string("[eglCreateNativeClientBufferANDROID pid ") +
std::to_string(getpid()) + ']');
err = gBuffer->initCheck();
if (err != NO_ERROR) {
ALOGE("Unable to create native buffer "
- "{ w=%u, h=%u, f=%u, u=%#x, lc=%u}: %#x", width, height, format,
- usage, layer_count, err);
+ "{ w=%u, h=%u, f=%u, pu=%" PRIx64 " cu=%" PRIx64 ", lc=%u} %#x",
+ width, height, format, producerUsage, consumerUsage,
+ layer_count, err);
goto error_condition;
}
- ALOGV("Created new native buffer %p { w=%u, h=%u, f=%u, u=%#x, lc=%u}",
- gBuffer, width, height, format, usage, layer_count);
+ ALOGV("Created new native buffer %p { w=%u, h=%u, f=%u, pu=%" PRIx64
+ " cu=%" PRIx64 ", lc=%u}",
+ gBuffer, width, height, format, producerUsage, consumerUsage,
+ layer_count);
return static_cast<EGLClientBuffer>(gBuffer->getNativeBuffer());
#undef CHECK_ERROR_CONDITION
#include <EGL/egl.h>
#include <gui/Surface.h>
-
+#include <gui/IConsumerListener.h>
+#include <gui/IProducerListener.h>
+#include <gui/IGraphicBufferConsumer.h>
+#include <gui/BufferQueue.h>
namespace android {
PAUSE = IBinder::FIRST_CALL_TRANSACTION + 1,
STOP = IBinder::FIRST_CALL_TRANSACTION + 2,
SET_VOLUME = IBinder::FIRST_CALL_TRANSACTION + 3,
+ SET_PAN = IBinder::FIRST_CALL_TRANSACTION + 4,
+ SET_START_DELAY_MS = IBinder::FIRST_CALL_TRANSACTION + 5,
};
class BpPlayer : public BpInterface<IPlayer>
data.writeFloat(vol);
remote()->transact(SET_VOLUME, data, &reply);
}
+
+ virtual void setPan(float pan)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IPlayer::getInterfaceDescriptor());
+ data.writeFloat(pan);
+ remote()->transact(SET_PAN, data, &reply);
+ }
+
+ virtual void setStartDelayMs(int32_t delayMs) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IPlayer::getInterfaceDescriptor());
+ data.writeInt32(delayMs);
+ remote()->transact(SET_START_DELAY_MS, data, &reply);
+ }
};
IMPLEMENT_META_INTERFACE(Player, "android.media.IPlayer");
CHECK_INTERFACE(IPlayer, data, reply);
setVolume(data.readFloat());
return NO_ERROR;
- }
+ } break;
+ case SET_PAN: {
+ CHECK_INTERFACE(IPlayer, data, reply);
+ setPan(data.readFloat());
+ return NO_ERROR;
+ } break;
+ case SET_START_DELAY_MS: {
+ CHECK_INTERFACE(IPlayer, data, reply);
+ setStartDelayMs(data.readInt32());
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
OrientationSensor.cpp \
RecentEventLogger.cpp \
RotationVectorSensor.cpp \
+ SensorDevice.cpp \
SensorDirectConnection.cpp \
SensorEventConnection.cpp \
SensorFusion.cpp \
LOCAL_CFLAGS += -fvisibility=hidden
-ifeq ($(ENABLE_TREBLE), true)
-LOCAL_SRC_FILES += SensorDeviceTreble.cpp
-LOCAL_CFLAGS += -DENABLE_TREBLE=1
-else
-LOCAL_SRC_FILES += SensorDevice.cpp
-endif
-
LOCAL_SHARED_LIBRARIES := \
libcutils \
libhardware \
libui \
libgui \
libcrypto \
-
-ifeq ($(ENABLE_TREBLE), true)
-
-LOCAL_SHARED_LIBRARIES += \
libbase \
libhidlbase \
libhidltransport \
LOCAL_STATIC_LIBRARIES := \
android.hardware.sensors@1.0-convert
-endif # ENABLE_TREBLE
-
LOCAL_MODULE:= libsensorservice
include $(BUILD_SHARED_LIBRARY)
* limitations under the License.
*/
+#include <inttypes.h>
+#include <math.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <android-base/logging.h>
+#include <utils/Atomic.h>
+#include <utils/Errors.h>
+#include <utils/Singleton.h>
#include "SensorDevice.h"
#include "SensorService.h"
+#include <sensors/convert.h>
-#include <binder/BinderService.h>
-#include <binder/Parcel.h>
-#include <binder/IServiceManager.h>
-#include <cutils/ashmem.h>
-#include <hardware/sensors.h>
-#include <utils/Atomic.h>
-#include <utils/Errors.h>
-#include <utils/Singleton.h>
+using android::hardware::hidl_vec;
-#include <inttypes.h>
-#include <math.h>
-#include <sys/mman.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <sstream>
-#include <unistd.h>
+using namespace android::hardware::sensors::V1_0;
+using namespace android::hardware::sensors::V1_0::implementation;
namespace android {
// ---------------------------------------------------------------------------
ANDROID_SINGLETON_STATIC_INSTANCE(SensorDevice)
-SensorDevice::SensorDevice()
- : mSensorDevice(0),
- mSensorModule(0) {
- status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID,
- (hw_module_t const**)&mSensorModule);
+static status_t StatusFromResult(Result result) {
+ switch (result) {
+ case Result::OK:
+ return OK;
+ case Result::BAD_VALUE:
+ return BAD_VALUE;
+ case Result::PERMISSION_DENIED:
+ return PERMISSION_DENIED;
+ case Result::INVALID_OPERATION:
+ return INVALID_OPERATION;
+ case Result::NO_MEMORY:
+ return NO_MEMORY;
+ }
+}
- ALOGE_IF(err, "couldn't load %s module (%s)",
- SENSORS_HARDWARE_MODULE_ID, strerror(-err));
+SensorDevice::SensorDevice() {
+ mSensors = ISensors::getService();
- if (mSensorModule) {
- err = sensors_open_1(&mSensorModule->common, &mSensorDevice);
+ if (mSensors == NULL) {
+ return;
+ }
- ALOGE_IF(err, "couldn't open device for module %s (%s)",
- SENSORS_HARDWARE_MODULE_ID, strerror(-err));
+ mSensors->getSensorsList(
+ [&](const auto &list) {
+ const size_t count = list.size();
- if (mSensorDevice) {
+ mActivationCount.setCapacity(count);
+ Info model;
+ for (size_t i=0 ; i < count; i++) {
+ sensor_t sensor;
+ convertToSensor(list[i], &sensor);
+ mSensorList.push_back(sensor);
- sensor_t const* list;
- ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list);
+ mActivationCount.add(list[i].sensorHandle, model);
- if (mSensorDevice->common.version < SENSORS_DEVICE_API_VERSION_1_3) {
- ALOGE(">>>> WARNING <<< Upgrade sensor HAL to version 1_3, ignoring sensors reported by this device");
- count = 0;
- }
+ mSensors->activate(list[i].sensorHandle, 0 /* enabled */);
+ }
+ });
- mActivationCount.setCapacity(count);
- Info model;
- for (size_t i=0 ; i<size_t(count) ; i++) {
- mActivationCount.add(list[i].handle, model);
- mSensorDevice->activate(
- reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice),
- list[i].handle, 0);
- }
- }
- }
+ mIsDirectReportSupported =
+ (mSensors->unregisterDirectChannel(-1) != Result::INVALID_OPERATION);
}
void SensorDevice::handleDynamicSensorConnection(int handle, bool connected) {
if (connected) {
Info model;
mActivationCount.add(handle, model);
- mSensorDevice->activate(
- reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice), handle, 0);
+ mSensors->activate(handle, 0 /* enabled */);
} else {
mActivationCount.removeItem(handle);
}
}
std::string SensorDevice::dump() const {
- if (!mSensorModule) return "HAL not initialized\n";
+ if (mSensors == NULL) return "HAL not initialized\n";
String8 result;
- sensor_t const* list;
- int count = mSensorModule->get_sensors_list(mSensorModule, &list);
-
- result.appendFormat("HAL: %s (%s), version %#010x\n",
- mSensorModule->common.name,
- mSensorModule->common.author,
- getHalDeviceVersion());
- result.appendFormat("Total %d h/w sensors, %zu running:\n", count, mActivationCount.size());
+ mSensors->getSensorsList([&](const auto &list) {
+ const size_t count = list.size();
+
+ result.appendFormat(
+ "Total %zu h/w sensors, %zu running:\n",
+ count,
+ mActivationCount.size());
+
+ Mutex::Autolock _l(mLock);
+ for (size_t i = 0 ; i < count ; i++) {
+ const Info& info = mActivationCount.valueFor(
+ list[i].sensorHandle);
+
+ if (info.batchParams.isEmpty()) continue;
+ result.appendFormat(
+ "0x%08x) active-count = %zu; ",
+ list[i].sensorHandle,
+ info.batchParams.size());
+
+ result.append("sampling_period(ms) = {");
+ for (size_t j = 0; j < info.batchParams.size(); j++) {
+ const BatchParams& params = info.batchParams.valueAt(j);
+ result.appendFormat(
+ "%.1f%s",
+ params.batchDelay / 1e6f,
+ j < info.batchParams.size() - 1 ? ", " : "");
+ }
+ result.appendFormat(
+ "}, selected = %.1f ms; ",
+ info.bestBatchParams.batchDelay / 1e6f);
+
+ result.append("batching_period(ms) = {");
+ for (size_t j = 0; j < info.batchParams.size(); j++) {
+ BatchParams params = info.batchParams.valueAt(j);
+
+ result.appendFormat(
+ "%.1f%s",
+ params.batchTimeout / 1e6f,
+ j < info.batchParams.size() - 1 ? ", " : "");
+ }
- Mutex::Autolock _l(mLock);
- for (int i = 0 ; i < count ; i++) {
- const Info& info = mActivationCount.valueFor(list[i].handle);
- if (info.batchParams.isEmpty()) continue;
- result.appendFormat("0x%08x) active-count = %zu; ", list[i].handle,
- info.batchParams.size());
-
- result.append("sampling_period(ms) = {");
- for (size_t j = 0; j < info.batchParams.size(); j++) {
- const BatchParams& params = info.batchParams.valueAt(j);
- result.appendFormat("%.1f%s", params.batchDelay / 1e6f,
- j < info.batchParams.size() - 1 ? ", " : "");
- }
- result.appendFormat("}, selected = %.1f ms; ", info.bestBatchParams.batchDelay / 1e6f);
+ result.appendFormat(
+ "}, selected = %.1f ms\n",
+ info.bestBatchParams.batchTimeout / 1e6f);
+ }
+ });
- result.append("batching_period(ms) = {");
- for (size_t j = 0; j < info.batchParams.size(); j++) {
- BatchParams params = info.batchParams.valueAt(j);
- result.appendFormat("%.1f%s", params.batchTimeout / 1e6f,
- j < info.batchParams.size() - 1 ? ", " : "");
- }
- result.appendFormat("}, selected = %.1f ms\n", info.bestBatchParams.batchTimeout / 1e6f);
- }
return result.string();
}
ssize_t SensorDevice::getSensorList(sensor_t const** list) {
- if (!mSensorModule) return NO_INIT;
- ssize_t count = mSensorModule->get_sensors_list(mSensorModule, list);
- return count;
+ *list = &mSensorList[0];
+
+ return mSensorList.size();
}
status_t SensorDevice::initCheck() const {
- return mSensorDevice && mSensorModule ? NO_ERROR : NO_INIT;
+ return mSensors != NULL ? NO_ERROR : NO_INIT;
}
ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) {
- if (!mSensorDevice) return NO_INIT;
- ssize_t c;
- do {
- c = mSensorDevice->poll(reinterpret_cast<struct sensors_poll_device_t *> (mSensorDevice),
- buffer, count);
- } while (c == -EINTR);
- return c;
+ if (mSensors == NULL) return NO_INIT;
+
+ ssize_t err;
+
+ mSensors->poll(
+ count,
+ [&](auto result,
+ const auto &events,
+ const auto &dynamicSensorsAdded) {
+ if (result == Result::OK) {
+ convertToSensorEvents(events, dynamicSensorsAdded, buffer);
+ err = (ssize_t)events.size();
+ } else {
+ err = StatusFromResult(result);
+ }
+ });
+
+ return err;
}
void SensorDevice::autoDisable(void *ident, int handle) {
}
status_t SensorDevice::activate(void* ident, int handle, int enabled) {
- if (!mSensorDevice) return NO_INIT;
+ if (mSensors == NULL) return NO_INIT;
+
status_t err(NO_ERROR);
bool actuateHardware = false;
} else {
ALOGD_IF(DEBUG_CONNECTIONS, "disable index=%zd", info.batchParams.indexOfKey(ident));
+ // If a connected dynamic sensor is deactivated, remove it from the
+ // dictionary.
+ auto it = mConnectedDynamicSensors.find(handle);
+ if (it != mConnectedDynamicSensors.end()) {
+ delete it->second;
+ mConnectedDynamicSensors.erase(it);
+ }
+
if (info.removeBatchParamsForIdent(ident) >= 0) {
if (info.numActiveClients() == 0) {
// This is the last connection, we need to de-activate the underlying h/w sensor.
actuateHardware = true;
} else {
- const int halVersion = getHalDeviceVersion();
- if (halVersion >= SENSORS_DEVICE_API_VERSION_1_1) {
- // Call batch for this sensor with the previously calculated best effort
- // batch_rate and timeout. One of the apps has unregistered for sensor
- // events, and the best effort batch parameters might have changed.
- ALOGD_IF(DEBUG_CONNECTIONS,
- "\t>>> actuating h/w batch %d %d %" PRId64 " %" PRId64, handle,
- info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
- info.bestBatchParams.batchTimeout);
- mSensorDevice->batch(mSensorDevice, handle,info.bestBatchParams.flags,
- info.bestBatchParams.batchDelay,
- info.bestBatchParams.batchTimeout);
- }
+ // Call batch for this sensor with the previously calculated best effort
+ // batch_rate and timeout. One of the apps has unregistered for sensor
+ // events, and the best effort batch parameters might have changed.
+ ALOGD_IF(DEBUG_CONNECTIONS,
+ "\t>>> actuating h/w batch %d %d %" PRId64 " %" PRId64, handle,
+ info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
+ info.bestBatchParams.batchTimeout);
+ mSensors->batch(
+ handle,
+ info.bestBatchParams.batchDelay,
+ info.bestBatchParams.batchTimeout);
}
} else {
// sensor wasn't enabled for this ident
if (actuateHardware) {
ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle,
enabled);
- err = mSensorDevice->activate(
- reinterpret_cast<struct sensors_poll_device_t *> (mSensorDevice), handle, enabled);
+ err = StatusFromResult(mSensors->activate(handle, enabled));
ALOGE_IF(err, "Error %s sensor %d (%s)", enabled ? "activating" : "disabling", handle,
strerror(-err));
}
}
- // On older devices which do not support batch, call setDelay().
- if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1 && info.numActiveClients() > 0) {
- ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w setDelay %d %" PRId64, handle,
- info.bestBatchParams.batchDelay);
- mSensorDevice->setDelay(
- reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice),
- handle, info.bestBatchParams.batchDelay);
- }
return err;
}
-status_t SensorDevice::batch(void* ident, int handle, int flags, int64_t samplingPeriodNs,
- int64_t maxBatchReportLatencyNs) {
- if (!mSensorDevice) return NO_INIT;
+status_t SensorDevice::batch(
+ void* ident,
+ int handle,
+ int flags,
+ int64_t samplingPeriodNs,
+ int64_t maxBatchReportLatencyNs) {
+ if (mSensors == NULL) return NO_INIT;
if (samplingPeriodNs < MINIMUM_EVENTS_PERIOD) {
samplingPeriodNs = MINIMUM_EVENTS_PERIOD;
}
- const int halVersion = getHalDeviceVersion();
- if (halVersion < SENSORS_DEVICE_API_VERSION_1_1 && maxBatchReportLatencyNs != 0) {
- // Batch is not supported on older devices return invalid operation.
- return INVALID_OPERATION;
- }
-
ALOGD_IF(DEBUG_CONNECTIONS,
"SensorDevice::batch: ident=%p, handle=0x%08x, flags=%d, period_ns=%" PRId64 " timeout=%" PRId64,
ident, handle, flags, samplingPeriodNs, maxBatchReportLatencyNs);
status_t err(NO_ERROR);
// If the min period or min timeout has changed since the last batch call, call batch.
if (prevBestBatchParams != info.bestBatchParams) {
- if (halVersion >= SENSORS_DEVICE_API_VERSION_1_1) {
- ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w BATCH %d %d %" PRId64 " %" PRId64, handle,
- info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
- info.bestBatchParams.batchTimeout);
- err = mSensorDevice->batch(mSensorDevice, handle, info.bestBatchParams.flags,
- info.bestBatchParams.batchDelay,
- info.bestBatchParams.batchTimeout);
- } else {
- // For older devices which do not support batch, call setDelay() after activate() is
- // called. Some older devices may not support calling setDelay before activate(), so
- // call setDelay in SensorDevice::activate() method.
- }
+ ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w BATCH %d %d %" PRId64 " %" PRId64, handle,
+ info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
+ info.bestBatchParams.batchTimeout);
+ err = StatusFromResult(
+ mSensors->batch(
+ handle,
+ info.bestBatchParams.batchDelay,
+ info.bestBatchParams.batchTimeout));
if (err != NO_ERROR) {
ALOGE("sensor batch failed %p %d %d %" PRId64 " %" PRId64 " err=%s",
- mSensorDevice, handle,
+ mSensors.get(), handle,
info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
info.bestBatchParams.batchTimeout, strerror(-err));
info.removeBatchParamsForIdent(ident);
}
status_t SensorDevice::setDelay(void* ident, int handle, int64_t samplingPeriodNs) {
- if (!mSensorDevice) return NO_INIT;
+ if (mSensors == NULL) return NO_INIT;
if (samplingPeriodNs < MINIMUM_EVENTS_PERIOD) {
samplingPeriodNs = MINIMUM_EVENTS_PERIOD;
}
BatchParams& params = info.batchParams.editValueAt(index);
params.batchDelay = samplingPeriodNs;
info.selectBatchParams();
- return mSensorDevice->setDelay(reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice),
- handle, info.bestBatchParams.batchDelay);
+
+ return StatusFromResult(
+ mSensors->batch(handle, info.bestBatchParams.batchDelay, 0));
}
int SensorDevice::getHalDeviceVersion() const {
- if (!mSensorDevice) return -1;
- return mSensorDevice->common.version;
+ if (mSensors == NULL) return -1;
+ return SENSORS_DEVICE_API_VERSION_1_4;
}
status_t SensorDevice::flush(void* ident, int handle) {
- if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1) {
- return INVALID_OPERATION;
- }
if (isClientDisabled(ident)) return INVALID_OPERATION;
ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w flush %d", handle);
- return mSensorDevice->flush(mSensorDevice, handle);
+ return StatusFromResult(mSensors->flush(handle));
}
bool SensorDevice::isClientDisabled(void* ident) {
Mutex::Autolock _l(mLock);
mDisabledClients.clear();
ALOGI("cleared mDisabledClients");
- const int halVersion = getHalDeviceVersion();
for (size_t i = 0; i< mActivationCount.size(); ++i) {
Info& info = mActivationCount.editValueAt(i);
if (info.batchParams.isEmpty()) continue;
const int sensor_handle = mActivationCount.keyAt(i);
ALOGD_IF(DEBUG_CONNECTIONS, "\t>> reenable actuating h/w sensor enable handle=%d ",
sensor_handle);
- status_t err(NO_ERROR);
- if (halVersion > SENSORS_DEVICE_API_VERSION_1_0) {
- err = mSensorDevice->batch(mSensorDevice, sensor_handle,
- info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
- info.bestBatchParams.batchTimeout);
- ALOGE_IF(err, "Error calling batch on sensor %d (%s)", sensor_handle, strerror(-err));
- }
+ status_t err = StatusFromResult(
+ mSensors->batch(
+ sensor_handle,
+ info.bestBatchParams.batchDelay,
+ info.bestBatchParams.batchTimeout));
+ ALOGE_IF(err, "Error calling batch on sensor %d (%s)", sensor_handle, strerror(-err));
if (err == NO_ERROR) {
- err = mSensorDevice->activate(
- reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice),
- sensor_handle, 1);
+ err = StatusFromResult(
+ mSensors->activate(sensor_handle, 1 /* enabled */));
ALOGE_IF(err, "Error activating sensor %d (%s)", sensor_handle, strerror(-err));
}
-
- if (halVersion <= SENSORS_DEVICE_API_VERSION_1_0) {
- err = mSensorDevice->setDelay(
- reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice),
- sensor_handle, info.bestBatchParams.batchDelay);
- ALOGE_IF(err, "Error calling setDelay sensor %d (%s)", sensor_handle, strerror(-err));
- }
}
}
void SensorDevice::disableAllSensors() {
Mutex::Autolock _l(mLock);
- for (size_t i = 0; i< mActivationCount.size(); ++i) {
+ for (size_t i = 0; i< mActivationCount.size(); ++i) {
const Info& info = mActivationCount.valueAt(i);
// Check if this sensor has been activated previously and disable it.
if (info.batchParams.size() > 0) {
const int sensor_handle = mActivationCount.keyAt(i);
ALOGD_IF(DEBUG_CONNECTIONS, "\t>> actuating h/w sensor disable handle=%d ",
sensor_handle);
- mSensorDevice->activate(
- reinterpret_cast<struct sensors_poll_device_t *> (mSensorDevice),
- sensor_handle, 0);
+ mSensors->activate(sensor_handle, 0 /* enabled */);
+
// Add all the connections that were registered for this sensor to the disabled
// clients list.
for (size_t j = 0; j < info.batchParams.size(); ++j) {
}
}
-status_t SensorDevice::injectSensorData(const sensors_event_t *injected_sensor_event) {
- ALOGD_IF(DEBUG_CONNECTIONS,
- "sensor_event handle=%d ts=%" PRId64 " data=%.2f, %.2f, %.2f %.2f %.2f %.2f",
- injected_sensor_event->sensor,
- injected_sensor_event->timestamp, injected_sensor_event->data[0],
- injected_sensor_event->data[1], injected_sensor_event->data[2],
- injected_sensor_event->data[3], injected_sensor_event->data[4],
- injected_sensor_event->data[5]);
- if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_4) {
- return INVALID_OPERATION;
- }
- return mSensorDevice->inject_sensor_data(mSensorDevice, injected_sensor_event);
+status_t SensorDevice::injectSensorData(
+ const sensors_event_t *injected_sensor_event) {
+ ALOGD_IF(DEBUG_CONNECTIONS,
+ "sensor_event handle=%d ts=%" PRId64 " data=%.2f, %.2f, %.2f %.2f %.2f %.2f",
+ injected_sensor_event->sensor,
+ injected_sensor_event->timestamp, injected_sensor_event->data[0],
+ injected_sensor_event->data[1], injected_sensor_event->data[2],
+ injected_sensor_event->data[3], injected_sensor_event->data[4],
+ injected_sensor_event->data[5]);
+
+ Event ev;
+ convertFromSensorEvent(*injected_sensor_event, &ev);
+
+ return StatusFromResult(mSensors->injectSensorData(ev));
}
status_t SensorDevice::setMode(uint32_t mode) {
- if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_4) {
- return INVALID_OPERATION;
- }
- return mSensorModule->set_operation_mode(mode);
+
+ return StatusFromResult(
+ mSensors->setOperationMode(
+ static_cast<hardware::sensors::V1_0::OperationMode>(mode)));
}
// ---------------------------------------------------------------------------
}
int32_t SensorDevice::registerDirectChannel(const sensors_direct_mem_t* memory) {
+ Mutex::Autolock _l(mLock);
- if (!isDirectReportSupported()) {
- return INVALID_OPERATION;
+ SharedMemType type;
+ switch (memory->type) {
+ case SENSOR_DIRECT_MEM_TYPE_ASHMEM:
+ type = SharedMemType::ASHMEM;
+ break;
+ case SENSOR_DIRECT_MEM_TYPE_GRALLOC:
+ type = SharedMemType::GRALLOC;
+ break;
+ default:
+ return BAD_VALUE;
}
- Mutex::Autolock _l(mLock);
-
- int32_t channelHandle = mSensorDevice->register_direct_channel(
- mSensorDevice, memory, -1 /*channel_handle*/);
- return channelHandle;
+ SharedMemFormat format;
+ if (memory->format != SENSOR_DIRECT_FMT_SENSORS_EVENT) {
+ return BAD_VALUE;
+ }
+ format = SharedMemFormat::SENSORS_EVENT;
+
+ SharedMemInfo mem = {
+ .type = type,
+ .format = format,
+ .size = static_cast<uint32_t>(memory->size),
+ .memoryHandle = memory->handle,
+ };
+
+ int32_t ret;
+ mSensors->registerDirectChannel(mem,
+ [&ret](auto result, auto channelHandle) {
+ if (result == Result::OK) {
+ ret = channelHandle;
+ } else {
+ ret = StatusFromResult(result);
+ }
+ });
+ return ret;
}
void SensorDevice::unregisterDirectChannel(int32_t channelHandle) {
Mutex::Autolock _l(mLock);
-
- mSensorDevice->register_direct_channel(mSensorDevice, nullptr, channelHandle);
+ mSensors->unregisterDirectChannel(channelHandle);
}
-int32_t SensorDevice::configureDirectChannel(int32_t sensorHandle, int32_t channelHandle,
- const struct sensors_direct_cfg_t *config) {
+int32_t SensorDevice::configureDirectChannel(int32_t sensorHandle,
+ int32_t channelHandle, const struct sensors_direct_cfg_t *config) {
+ Mutex::Autolock _l(mLock);
- if (!isDirectReportSupported()) {
- return INVALID_OPERATION;
+ RateLevel rate;
+ switch(config->rate_level) {
+ case SENSOR_DIRECT_RATE_STOP:
+ rate = RateLevel::STOP;
+ break;
+ case SENSOR_DIRECT_RATE_NORMAL:
+ rate = RateLevel::NORMAL;
+ break;
+ case SENSOR_DIRECT_RATE_FAST:
+ rate = RateLevel::FAST;
+ break;
+ case SENSOR_DIRECT_RATE_VERY_FAST:
+ rate = RateLevel::VERY_FAST;
+ break;
+ default:
+ return BAD_VALUE;
}
- Mutex::Autolock _l(mLock);
+ int32_t ret;
+ mSensors->configDirectReport(sensorHandle, channelHandle, rate,
+ [&ret, rate] (auto result, auto token) {
+ if (rate == RateLevel::STOP) {
+ ret = StatusFromResult(result);
+ } else {
+ if (result == Result::OK) {
+ ret = token;
+ } else {
+ ret = StatusFromResult(result);
+ }
+ }
+ });
- int32_t ret = mSensorDevice->config_direct_report(
- mSensorDevice, sensorHandle, channelHandle, config);
- ALOGE_IF(ret < 0, "SensorDevice::configureDirectChannel ret %d", ret);
return ret;
}
bool SensorDevice::isDirectReportSupported() const {
- bool ret = mSensorDevice->register_direct_channel != nullptr
- && mSensorDevice->config_direct_report != nullptr;
- return ret;
+ return mIsDirectReportSupported;
+}
+
+void SensorDevice::convertToSensorEvent(
+ const Event &src, sensors_event_t *dst) {
+ ::android::hardware::sensors::V1_0::implementation::convertToSensorEvent(
+ src, dst);
+
+ if (src.sensorType == SensorType::DYNAMIC_SENSOR_META) {
+ const DynamicSensorInfo &dyn = src.u.dynamic;
+
+ dst->dynamic_sensor_meta.connected = dyn.connected;
+ dst->dynamic_sensor_meta.handle = dyn.sensorHandle;
+ if (dyn.connected) {
+ auto it = mConnectedDynamicSensors.find(dyn.sensorHandle);
+ CHECK(it != mConnectedDynamicSensors.end());
+
+ dst->dynamic_sensor_meta.sensor = it->second;
+
+ memcpy(dst->dynamic_sensor_meta.uuid,
+ dyn.uuid.data(),
+ sizeof(dst->dynamic_sensor_meta.uuid));
+ }
+ }
}
+
+void SensorDevice::convertToSensorEvents(
+ const hidl_vec<Event> &src,
+ const hidl_vec<SensorInfo> &dynamicSensorsAdded,
+ sensors_event_t *dst) {
+ // Allocate a sensor_t structure for each dynamic sensor added and insert
+ // it into the dictionary of connected dynamic sensors keyed by handle.
+ for (size_t i = 0; i < dynamicSensorsAdded.size(); ++i) {
+ const SensorInfo &info = dynamicSensorsAdded[i];
+
+ auto it = mConnectedDynamicSensors.find(info.sensorHandle);
+ CHECK(it == mConnectedDynamicSensors.end());
+
+ sensor_t *sensor = new sensor_t;
+ convertToSensor(info, sensor);
+
+ mConnectedDynamicSensors.insert(
+ std::make_pair(sensor->handle, sensor));
+ }
+
+ for (size_t i = 0; i < src.size(); ++i) {
+ convertToSensorEvent(src[i], &dst[i]);
+ }
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
-
#include "SensorServiceUtils.h"
#include <gui/Sensor.h>
+#include <stdint.h>
+#include <sys/types.h>
#include <utils/KeyedVector.h>
#include <utils/Singleton.h>
#include <utils/String8.h>
-#include <stdint.h>
-#include <sys/types.h>
#include <string>
-
-#ifdef ENABLE_TREBLE
#include <map>
#include "android/hardware/sensors/1.0/ISensors.h"
-#endif
// ---------------------------------------------------------------------------
virtual std::string dump() const;
private:
friend class Singleton<SensorDevice>;
-#ifdef ENABLE_TREBLE
+
sp<android::hardware::sensors::V1_0::ISensors> mSensors;
Vector<sensor_t> mSensorList;
std::map<int32_t, sensor_t*> mConnectedDynamicSensors;
-#else
- sensors_poll_device_1_t* mSensorDevice;
- struct sensors_module_t* mSensorModule;
-#endif
static const nsecs_t MINIMUM_EVENTS_PERIOD = 1000000; // 1000 Hz
mutable Mutex mLock; // protect mActivationCount[].batchParams
bool isClientDisabled(void* ident);
bool isClientDisabledLocked(void* ident);
-#ifdef ENABLE_TREBLE
using Event = hardware::sensors::V1_0::Event;
using SensorInfo = hardware::sensors::V1_0::SensorInfo;
sensors_event_t *dst);
bool mIsDirectReportSupported;
-#endif // ENABLE_TREBLE
};
// ---------------------------------------------------------------------------
+++ /dev/null
-/*
- * Copyright (C) 2010 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 <inttypes.h>
-#include <math.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <android-base/logging.h>
-#include <utils/Atomic.h>
-#include <utils/Errors.h>
-#include <utils/Singleton.h>
-
-#include "SensorDevice.h"
-#include "SensorService.h"
-
-#include <sensors/convert.h>
-
-using android::hardware::hidl_vec;
-
-using namespace android::hardware::sensors::V1_0;
-using namespace android::hardware::sensors::V1_0::implementation;
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-ANDROID_SINGLETON_STATIC_INSTANCE(SensorDevice)
-
-static status_t StatusFromResult(Result result) {
- switch (result) {
- case Result::OK:
- return OK;
- case Result::BAD_VALUE:
- return BAD_VALUE;
- case Result::PERMISSION_DENIED:
- return PERMISSION_DENIED;
- case Result::INVALID_OPERATION:
- return INVALID_OPERATION;
- case Result::NO_MEMORY:
- return NO_MEMORY;
- }
-}
-
-SensorDevice::SensorDevice() {
- mSensors = ISensors::getService();
-
- if (mSensors == NULL) {
- return;
- }
-
- mSensors->getSensorsList(
- [&](const auto &list) {
- const size_t count = list.size();
-
- mActivationCount.setCapacity(count);
- Info model;
- for (size_t i=0 ; i < count; i++) {
- sensor_t sensor;
- convertToSensor(list[i], &sensor);
- mSensorList.push_back(sensor);
-
- mActivationCount.add(list[i].sensorHandle, model);
-
- mSensors->activate(list[i].sensorHandle, 0 /* enabled */);
- }
- });
-
- mIsDirectReportSupported =
- (mSensors->unregisterDirectChannel(-1) != Result::INVALID_OPERATION);
-}
-
-void SensorDevice::handleDynamicSensorConnection(int handle, bool connected) {
- if (connected) {
- Info model;
- mActivationCount.add(handle, model);
- mSensors->activate(handle, 0 /* enabled */);
- } else {
- mActivationCount.removeItem(handle);
- }
-}
-
-std::string SensorDevice::dump() const {
- if (mSensors == NULL) return "HAL not initialized\n";
-
- String8 result;
- mSensors->getSensorsList([&](const auto &list) {
- const size_t count = list.size();
-
- result.appendFormat(
- "Total %zu h/w sensors, %zu running:\n",
- count,
- mActivationCount.size());
-
- Mutex::Autolock _l(mLock);
- for (size_t i = 0 ; i < count ; i++) {
- const Info& info = mActivationCount.valueFor(
- list[i].sensorHandle);
-
- if (info.batchParams.isEmpty()) continue;
- result.appendFormat(
- "0x%08x) active-count = %zu; ",
- list[i].sensorHandle,
- info.batchParams.size());
-
- result.append("sampling_period(ms) = {");
- for (size_t j = 0; j < info.batchParams.size(); j++) {
- const BatchParams& params = info.batchParams.valueAt(j);
- result.appendFormat(
- "%.1f%s",
- params.batchDelay / 1e6f,
- j < info.batchParams.size() - 1 ? ", " : "");
- }
- result.appendFormat(
- "}, selected = %.1f ms; ",
- info.bestBatchParams.batchDelay / 1e6f);
-
- result.append("batching_period(ms) = {");
- for (size_t j = 0; j < info.batchParams.size(); j++) {
- BatchParams params = info.batchParams.valueAt(j);
-
- result.appendFormat(
- "%.1f%s",
- params.batchTimeout / 1e6f,
- j < info.batchParams.size() - 1 ? ", " : "");
- }
-
- result.appendFormat(
- "}, selected = %.1f ms\n",
- info.bestBatchParams.batchTimeout / 1e6f);
- }
- });
-
- return result.string();
-}
-
-ssize_t SensorDevice::getSensorList(sensor_t const** list) {
- *list = &mSensorList[0];
-
- return mSensorList.size();
-}
-
-status_t SensorDevice::initCheck() const {
- return mSensors != NULL ? NO_ERROR : NO_INIT;
-}
-
-ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) {
- if (mSensors == NULL) return NO_INIT;
-
- ssize_t err;
-
- mSensors->poll(
- count,
- [&](auto result,
- const auto &events,
- const auto &dynamicSensorsAdded) {
- if (result == Result::OK) {
- convertToSensorEvents(events, dynamicSensorsAdded, buffer);
- err = (ssize_t)events.size();
- } else {
- err = StatusFromResult(result);
- }
- });
-
- return err;
-}
-
-void SensorDevice::autoDisable(void *ident, int handle) {
- Info& info( mActivationCount.editValueFor(handle) );
- Mutex::Autolock _l(mLock);
- info.removeBatchParamsForIdent(ident);
-}
-
-status_t SensorDevice::activate(void* ident, int handle, int enabled) {
- if (mSensors == NULL) return NO_INIT;
-
- status_t err(NO_ERROR);
- bool actuateHardware = false;
-
- Mutex::Autolock _l(mLock);
- Info& info( mActivationCount.editValueFor(handle) );
-
- ALOGD_IF(DEBUG_CONNECTIONS,
- "SensorDevice::activate: ident=%p, handle=0x%08x, enabled=%d, count=%zu",
- ident, handle, enabled, info.batchParams.size());
-
- if (enabled) {
- ALOGD_IF(DEBUG_CONNECTIONS, "enable index=%zd", info.batchParams.indexOfKey(ident));
-
- if (isClientDisabledLocked(ident)) {
- ALOGE("SensorDevice::activate, isClientDisabledLocked(%p):true, handle:%d",
- ident, handle);
- return INVALID_OPERATION;
- }
-
- if (info.batchParams.indexOfKey(ident) >= 0) {
- if (info.numActiveClients() == 1) {
- // This is the first connection, we need to activate the underlying h/w sensor.
- actuateHardware = true;
- }
- } else {
- // Log error. Every activate call should be preceded by a batch() call.
- ALOGE("\t >>>ERROR: activate called without batch");
- }
- } else {
- ALOGD_IF(DEBUG_CONNECTIONS, "disable index=%zd", info.batchParams.indexOfKey(ident));
-
- // If a connected dynamic sensor is deactivated, remove it from the
- // dictionary.
- auto it = mConnectedDynamicSensors.find(handle);
- if (it != mConnectedDynamicSensors.end()) {
- delete it->second;
- mConnectedDynamicSensors.erase(it);
- }
-
- if (info.removeBatchParamsForIdent(ident) >= 0) {
- if (info.numActiveClients() == 0) {
- // This is the last connection, we need to de-activate the underlying h/w sensor.
- actuateHardware = true;
- } else {
- // Call batch for this sensor with the previously calculated best effort
- // batch_rate and timeout. One of the apps has unregistered for sensor
- // events, and the best effort batch parameters might have changed.
- ALOGD_IF(DEBUG_CONNECTIONS,
- "\t>>> actuating h/w batch %d %d %" PRId64 " %" PRId64, handle,
- info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
- info.bestBatchParams.batchTimeout);
- mSensors->batch(
- handle,
- info.bestBatchParams.batchDelay,
- info.bestBatchParams.batchTimeout);
- }
- } else {
- // sensor wasn't enabled for this ident
- }
-
- if (isClientDisabledLocked(ident)) {
- return NO_ERROR;
- }
- }
-
- if (actuateHardware) {
- ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle,
- enabled);
- err = StatusFromResult(mSensors->activate(handle, enabled));
- ALOGE_IF(err, "Error %s sensor %d (%s)", enabled ? "activating" : "disabling", handle,
- strerror(-err));
-
- if (err != NO_ERROR && enabled) {
- // Failure when enabling the sensor. Clean up on failure.
- info.removeBatchParamsForIdent(ident);
- }
- }
-
- return err;
-}
-
-status_t SensorDevice::batch(
- void* ident,
- int handle,
- int flags,
- int64_t samplingPeriodNs,
- int64_t maxBatchReportLatencyNs) {
- if (mSensors == NULL) return NO_INIT;
-
- if (samplingPeriodNs < MINIMUM_EVENTS_PERIOD) {
- samplingPeriodNs = MINIMUM_EVENTS_PERIOD;
- }
-
- ALOGD_IF(DEBUG_CONNECTIONS,
- "SensorDevice::batch: ident=%p, handle=0x%08x, flags=%d, period_ns=%" PRId64 " timeout=%" PRId64,
- ident, handle, flags, samplingPeriodNs, maxBatchReportLatencyNs);
-
- Mutex::Autolock _l(mLock);
- Info& info(mActivationCount.editValueFor(handle));
-
- if (info.batchParams.indexOfKey(ident) < 0) {
- BatchParams params(flags, samplingPeriodNs, maxBatchReportLatencyNs);
- info.batchParams.add(ident, params);
- } else {
- // A batch has already been called with this ident. Update the batch parameters.
- info.setBatchParamsForIdent(ident, flags, samplingPeriodNs, maxBatchReportLatencyNs);
- }
-
- BatchParams prevBestBatchParams = info.bestBatchParams;
- // Find the minimum of all timeouts and batch_rates for this sensor.
- info.selectBatchParams();
-
- ALOGD_IF(DEBUG_CONNECTIONS,
- "\t>>> curr_period=%" PRId64 " min_period=%" PRId64
- " curr_timeout=%" PRId64 " min_timeout=%" PRId64,
- prevBestBatchParams.batchDelay, info.bestBatchParams.batchDelay,
- prevBestBatchParams.batchTimeout, info.bestBatchParams.batchTimeout);
-
- status_t err(NO_ERROR);
- // If the min period or min timeout has changed since the last batch call, call batch.
- if (prevBestBatchParams != info.bestBatchParams) {
- ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w BATCH %d %d %" PRId64 " %" PRId64, handle,
- info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
- info.bestBatchParams.batchTimeout);
- err = StatusFromResult(
- mSensors->batch(
- handle,
- info.bestBatchParams.batchDelay,
- info.bestBatchParams.batchTimeout));
- if (err != NO_ERROR) {
- ALOGE("sensor batch failed %p %d %d %" PRId64 " %" PRId64 " err=%s",
- mSensors.get(), handle,
- info.bestBatchParams.flags, info.bestBatchParams.batchDelay,
- info.bestBatchParams.batchTimeout, strerror(-err));
- info.removeBatchParamsForIdent(ident);
- }
- }
- return err;
-}
-
-status_t SensorDevice::setDelay(void* ident, int handle, int64_t samplingPeriodNs) {
- if (mSensors == NULL) return NO_INIT;
- if (samplingPeriodNs < MINIMUM_EVENTS_PERIOD) {
- samplingPeriodNs = MINIMUM_EVENTS_PERIOD;
- }
- Mutex::Autolock _l(mLock);
- if (isClientDisabledLocked(ident)) return INVALID_OPERATION;
- Info& info( mActivationCount.editValueFor(handle) );
- // If the underlying sensor is NOT in continuous mode, setDelay() should return an error.
- // Calling setDelay() in batch mode is an invalid operation.
- if (info.bestBatchParams.batchTimeout != 0) {
- return INVALID_OPERATION;
- }
- ssize_t index = info.batchParams.indexOfKey(ident);
- if (index < 0) {
- return BAD_INDEX;
- }
- BatchParams& params = info.batchParams.editValueAt(index);
- params.batchDelay = samplingPeriodNs;
- info.selectBatchParams();
-
- return StatusFromResult(
- mSensors->batch(handle, info.bestBatchParams.batchDelay, 0));
-}
-
-int SensorDevice::getHalDeviceVersion() const {
- if (mSensors == NULL) return -1;
- return SENSORS_DEVICE_API_VERSION_1_4;
-}
-
-status_t SensorDevice::flush(void* ident, int handle) {
- if (isClientDisabled(ident)) return INVALID_OPERATION;
- ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w flush %d", handle);
- return StatusFromResult(mSensors->flush(handle));
-}
-
-bool SensorDevice::isClientDisabled(void* ident) {
- Mutex::Autolock _l(mLock);
- return isClientDisabledLocked(ident);
-}
-
-bool SensorDevice::isClientDisabledLocked(void* ident) {
- return mDisabledClients.indexOf(ident) >= 0;
-}
-
-void SensorDevice::enableAllSensors() {
- Mutex::Autolock _l(mLock);
- mDisabledClients.clear();
- ALOGI("cleared mDisabledClients");
- for (size_t i = 0; i< mActivationCount.size(); ++i) {
- Info& info = mActivationCount.editValueAt(i);
- if (info.batchParams.isEmpty()) continue;
- info.selectBatchParams();
- const int sensor_handle = mActivationCount.keyAt(i);
- ALOGD_IF(DEBUG_CONNECTIONS, "\t>> reenable actuating h/w sensor enable handle=%d ",
- sensor_handle);
- status_t err = StatusFromResult(
- mSensors->batch(
- sensor_handle,
- info.bestBatchParams.batchDelay,
- info.bestBatchParams.batchTimeout));
- ALOGE_IF(err, "Error calling batch on sensor %d (%s)", sensor_handle, strerror(-err));
-
- if (err == NO_ERROR) {
- err = StatusFromResult(
- mSensors->activate(sensor_handle, 1 /* enabled */));
- ALOGE_IF(err, "Error activating sensor %d (%s)", sensor_handle, strerror(-err));
- }
- }
-}
-
-void SensorDevice::disableAllSensors() {
- Mutex::Autolock _l(mLock);
- for (size_t i = 0; i< mActivationCount.size(); ++i) {
- const Info& info = mActivationCount.valueAt(i);
- // Check if this sensor has been activated previously and disable it.
- if (info.batchParams.size() > 0) {
- const int sensor_handle = mActivationCount.keyAt(i);
- ALOGD_IF(DEBUG_CONNECTIONS, "\t>> actuating h/w sensor disable handle=%d ",
- sensor_handle);
- mSensors->activate(sensor_handle, 0 /* enabled */);
-
- // Add all the connections that were registered for this sensor to the disabled
- // clients list.
- for (size_t j = 0; j < info.batchParams.size(); ++j) {
- mDisabledClients.add(info.batchParams.keyAt(j));
- ALOGI("added %p to mDisabledClients", info.batchParams.keyAt(j));
- }
- }
- }
-}
-
-status_t SensorDevice::injectSensorData(
- const sensors_event_t *injected_sensor_event) {
- ALOGD_IF(DEBUG_CONNECTIONS,
- "sensor_event handle=%d ts=%" PRId64 " data=%.2f, %.2f, %.2f %.2f %.2f %.2f",
- injected_sensor_event->sensor,
- injected_sensor_event->timestamp, injected_sensor_event->data[0],
- injected_sensor_event->data[1], injected_sensor_event->data[2],
- injected_sensor_event->data[3], injected_sensor_event->data[4],
- injected_sensor_event->data[5]);
-
- Event ev;
- convertFromSensorEvent(*injected_sensor_event, &ev);
-
- return StatusFromResult(mSensors->injectSensorData(ev));
-}
-
-status_t SensorDevice::setMode(uint32_t mode) {
-
- return StatusFromResult(
- mSensors->setOperationMode(
- static_cast<hardware::sensors::V1_0::OperationMode>(mode)));
-}
-
-// ---------------------------------------------------------------------------
-
-int SensorDevice::Info::numActiveClients() {
- SensorDevice& device(SensorDevice::getInstance());
- int num = 0;
- for (size_t i = 0; i < batchParams.size(); ++i) {
- if (!device.isClientDisabledLocked(batchParams.keyAt(i))) {
- ++num;
- }
- }
- return num;
-}
-
-status_t SensorDevice::Info::setBatchParamsForIdent(void* ident, int flags,
- int64_t samplingPeriodNs,
- int64_t maxBatchReportLatencyNs) {
- ssize_t index = batchParams.indexOfKey(ident);
- if (index < 0) {
- ALOGE("Info::setBatchParamsForIdent(ident=%p, period_ns=%" PRId64 " timeout=%" PRId64 ") failed (%s)",
- ident, samplingPeriodNs, maxBatchReportLatencyNs, strerror(-index));
- return BAD_INDEX;
- }
- BatchParams& params = batchParams.editValueAt(index);
- params.flags = flags;
- params.batchDelay = samplingPeriodNs;
- params.batchTimeout = maxBatchReportLatencyNs;
- return NO_ERROR;
-}
-
-void SensorDevice::Info::selectBatchParams() {
- BatchParams bestParams(0, -1, -1);
- SensorDevice& device(SensorDevice::getInstance());
-
- for (size_t i = 0; i < batchParams.size(); ++i) {
- if (device.isClientDisabledLocked(batchParams.keyAt(i))) continue;
- BatchParams params = batchParams.valueAt(i);
- if (bestParams.batchDelay == -1 || params.batchDelay < bestParams.batchDelay) {
- bestParams.batchDelay = params.batchDelay;
- }
- if (bestParams.batchTimeout == -1 || params.batchTimeout < bestParams.batchTimeout) {
- bestParams.batchTimeout = params.batchTimeout;
- }
- }
- bestBatchParams = bestParams;
-}
-
-ssize_t SensorDevice::Info::removeBatchParamsForIdent(void* ident) {
- ssize_t idx = batchParams.removeItem(ident);
- if (idx >= 0) {
- selectBatchParams();
- }
- return idx;
-}
-
-void SensorDevice::notifyConnectionDestroyed(void* ident) {
- Mutex::Autolock _l(mLock);
- mDisabledClients.remove(ident);
-}
-
-int32_t SensorDevice::registerDirectChannel(const sensors_direct_mem_t* memory) {
- Mutex::Autolock _l(mLock);
-
- SharedMemType type;
- switch (memory->type) {
- case SENSOR_DIRECT_MEM_TYPE_ASHMEM:
- type = SharedMemType::ASHMEM;
- break;
- case SENSOR_DIRECT_MEM_TYPE_GRALLOC:
- type = SharedMemType::GRALLOC;
- break;
- default:
- return BAD_VALUE;
- }
-
- SharedMemFormat format;
- if (memory->format != SENSOR_DIRECT_FMT_SENSORS_EVENT) {
- return BAD_VALUE;
- }
- format = SharedMemFormat::SENSORS_EVENT;
-
- SharedMemInfo mem = {
- .type = type,
- .format = format,
- .size = static_cast<uint32_t>(memory->size),
- .memoryHandle = memory->handle,
- };
-
- int32_t ret;
- mSensors->registerDirectChannel(mem,
- [&ret](auto result, auto channelHandle) {
- if (result == Result::OK) {
- ret = channelHandle;
- } else {
- ret = StatusFromResult(result);
- }
- });
- return ret;
-}
-
-void SensorDevice::unregisterDirectChannel(int32_t channelHandle) {
- Mutex::Autolock _l(mLock);
- mSensors->unregisterDirectChannel(channelHandle);
-}
-
-int32_t SensorDevice::configureDirectChannel(int32_t sensorHandle,
- int32_t channelHandle, const struct sensors_direct_cfg_t *config) {
- Mutex::Autolock _l(mLock);
-
- RateLevel rate;
- switch(config->rate_level) {
- case SENSOR_DIRECT_RATE_STOP:
- rate = RateLevel::STOP;
- break;
- case SENSOR_DIRECT_RATE_NORMAL:
- rate = RateLevel::NORMAL;
- break;
- case SENSOR_DIRECT_RATE_FAST:
- rate = RateLevel::FAST;
- break;
- case SENSOR_DIRECT_RATE_VERY_FAST:
- rate = RateLevel::VERY_FAST;
- break;
- default:
- return BAD_VALUE;
- }
-
- int32_t ret;
- mSensors->configDirectReport(sensorHandle, channelHandle, rate,
- [&ret, rate] (auto result, auto token) {
- if (rate == RateLevel::STOP) {
- ret = StatusFromResult(result);
- } else {
- if (result == Result::OK) {
- ret = token;
- } else {
- ret = StatusFromResult(result);
- }
- }
- });
-
- return ret;
-}
-
-bool SensorDevice::isDirectReportSupported() const {
- return mIsDirectReportSupported;
-}
-
-void SensorDevice::convertToSensorEvent(
- const Event &src, sensors_event_t *dst) {
- ::android::hardware::sensors::V1_0::implementation::convertToSensorEvent(
- src, dst);
-
- if (src.sensorType == SensorType::DYNAMIC_SENSOR_META) {
- const DynamicSensorInfo &dyn = src.u.dynamic;
-
- dst->dynamic_sensor_meta.connected = dyn.connected;
- dst->dynamic_sensor_meta.handle = dyn.sensorHandle;
- if (dyn.connected) {
- auto it = mConnectedDynamicSensors.find(dyn.sensorHandle);
- CHECK(it != mConnectedDynamicSensors.end());
-
- dst->dynamic_sensor_meta.sensor = it->second;
-
- memcpy(dst->dynamic_sensor_meta.uuid,
- dyn.uuid.data(),
- sizeof(dst->dynamic_sensor_meta.uuid));
- }
- }
-}
-
-void SensorDevice::convertToSensorEvents(
- const hidl_vec<Event> &src,
- const hidl_vec<SensorInfo> &dynamicSensorsAdded,
- sensors_event_t *dst) {
- // Allocate a sensor_t structure for each dynamic sensor added and insert
- // it into the dictionary of connected dynamic sensors keyed by handle.
- for (size_t i = 0; i < dynamicSensorsAdded.size(); ++i) {
- const SensorInfo &info = dynamicSensorsAdded[i];
-
- auto it = mConnectedDynamicSensors.find(info.sensorHandle);
- CHECK(it == mConnectedDynamicSensors.end());
-
- sensor_t *sensor = new sensor_t;
- convertToSensor(info, sensor);
-
- mConnectedDynamicSensors.insert(
- std::make_pair(sensor->handle, sensor));
- }
-
- for (size_t i = 0; i < src.size(); ++i) {
- convertToSensorEvent(src[i], &dst[i]);
- }
-}
-
-// ---------------------------------------------------------------------------
-}; // namespace android
if (fstat(fd1, &s1) < 0 || fstat(fd2, &s2) < 0 || s1.st_ino == s2.st_ino) {
ret = true;
}
+ break;
}
case SENSOR_DIRECT_MEM_TYPE_GRALLOC:
LOG_FATAL("%s: Implement GRALLOC or remove", __FUNCTION__);
ret = true;
+ break;
default:
ALOGE("Unexpected mem type %d", mMem.type);
ret = true;
+ break;
}
}
return ret;
case SENSOR_TYPE_STATIONARY_DETECT:
case SENSOR_TYPE_MOTION_DETECT:
case SENSOR_TYPE_HEART_BEAT:
+ case SENSOR_TYPE_LOW_LATENCY_OFFBODY_DETECT:
return 1;
default:
LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\"
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-ifeq ($(TARGET_IN_VR_MODE),true)
- LOCAL_CFLAGS += -DIN_VR_MODE
-endif
-
ifeq ($(TARGET_USES_HWC2),true)
LOCAL_CFLAGS += -DUSE_HWC2
LOCAL_SRC_FILES += \
SurfaceFlinger.cpp \
+ VrStateCallbacks.cpp \
DisplayHardware/HWComposer.cpp
ifeq ($(TARGET_USES_HWC2ON1ADAPTER), true)
LOCAL_CFLAGS += -DBYPASS_IHWC
LOCAL_CFLAGS += -fvisibility=hidden -Werror=format
-LOCAL_STATIC_LIBRARIES := libhwcomposer-command-buffer libtrace_proto libvkjson
+LOCAL_STATIC_LIBRARIES := \
+ libhwcomposer-command-buffer \
+ libtrace_proto \
+ libvkjson \
+ libvr_manager \
+ libvrflinger
+
LOCAL_SHARED_LIBRARIES := \
android.dvr.composer@1.0 \
android.hardware.graphics.allocator@2.0 \
#include <android/dvr/composer/1.0/IVrComposerClient.h>
#include <inttypes.h>
#include <log/log.h>
+#include <gui/BufferQueue.h>
#include "ComposerHal.h"
endCommand();
}
-Composer::Composer() : mWriter(kWriterInitialSize)
+Composer::Composer(bool useVrComposer)
+ : mWriter(kWriterInitialSize),
+ mIsUsingVrComposer(useVrComposer)
{
-#if defined(IN_VR_MODE)
- mIsInVrMode = true;
-#endif
-
- if (mIsInVrMode) {
+ if (mIsUsingVrComposer) {
mComposer = IComposer::getService("vr_hwcomposer");
} else {
mComposer = IComposer::getService("hwcomposer");
Error Composer::createLayer(Display display, Layer* outLayer)
{
- const uint32_t bufferSlotCount = 1;
Error error = kDefaultError;
- mClient->createLayer(display, bufferSlotCount,
+ mClient->createLayer(display, BufferQueue::NUM_BUFFER_SLOTS,
[&](const auto& tmpError, const auto& tmpLayer) {
error = tmpError;
if (error != Error::NONE) {
return unwrapRet(ret);
}
-Error Composer::setClientTarget(Display display, const native_handle_t* target,
+Error Composer::setClientTarget(Display display, uint32_t slot,
+ const native_handle_t* target,
int acquireFence, Dataspace dataspace,
const std::vector<IComposerClient::Rect>& damage)
{
mWriter.selectDisplay(display);
- mWriter.setClientTarget(0, target, acquireFence, dataspace, damage);
+ mWriter.setClientTarget(slot, target, acquireFence, dataspace, damage);
return Error::NONE;
}
Error Composer::setClientTargetSlotCount(Display display)
{
- const uint32_t bufferSlotCount = 1;
+ const uint32_t bufferSlotCount = BufferQueue::NUM_BUFFER_SLOTS;
auto ret = mClient->setClientTargetSlotCount(display, bufferSlotCount);
return unwrapRet(ret);
}
}
Error Composer::setLayerBuffer(Display display, Layer layer,
- const native_handle_t* buffer, int acquireFence)
+ uint32_t slot, const native_handle_t* buffer, int acquireFence)
{
mWriter.selectDisplay(display);
mWriter.selectLayer(layer);
- mWriter.setLayerBuffer(0, buffer, acquireFence);
+ mWriter.setLayerBuffer(slot, buffer, acquireFence);
return Error::NONE;
}
Error Composer::setLayerInfo(Display display, Layer layer, uint32_t type,
uint32_t appId)
{
- if (mIsInVrMode)
- {
+ if (mIsUsingVrComposer) {
mWriter.selectDisplay(display);
mWriter.selectLayer(layer);
mWriter.setLayerInfo(type, appId);
#include <android/hardware/graphics/composer/2.1/IComposer.h>
#include <utils/StrongPointer.h>
#include <IComposerCommandBuffer.h>
-#include <MessageQueue.h>
namespace android {
// Composer is a wrapper to IComposer, a proxy to server-side composer.
class Composer {
public:
- Composer();
+ Composer(bool useVrComposer);
std::vector<IComposer::Capability> getCapabilities();
std::string dumpDebugInfo();
void registerCallback(const sp<IComposerCallback>& callback);
uint32_t getMaxVirtualDisplayCount();
+ bool isUsingVrComposer() const { return mIsUsingVrComposer; }
Error createVirtualDisplay(uint32_t width, uint32_t height,
PixelFormat* format, Display* outDisplay);
Error destroyVirtualDisplay(Display display);
Error presentDisplay(Display display, int* outPresentFence);
Error setActiveConfig(Display display, Config config);
- Error setClientTarget(Display display, const native_handle_t* target,
+
+ /*
+ * The composer caches client targets internally. When target is nullptr,
+ * the composer uses slot to look up the client target from its cache.
+ * When target is not nullptr, the cache is updated with the new target.
+ */
+ Error setClientTarget(Display display, uint32_t slot,
+ const native_handle_t* target,
int acquireFence, Dataspace dataspace,
const std::vector<IComposerClient::Rect>& damage);
Error setColorMode(Display display, ColorMode mode);
Error setCursorPosition(Display display, Layer layer,
int32_t x, int32_t y);
- Error setLayerBuffer(Display display, Layer layer,
+ /* see setClientTarget for the purpose of slot */
+ Error setLayerBuffer(Display display, Layer layer, uint32_t slot,
const native_handle_t* buffer, int acquireFence);
Error setLayerSurfaceDamage(Display display, Layer layer,
const std::vector<IComposerClient::Rect>& damage);
CommandWriter mWriter;
CommandReader mReader;
- bool mIsInVrMode = false;
+ // When true, the we attach to the vr_hwcomposer service instead of the
+ // hwcomposer. This allows us to redirect surfaces to 3d surfaces in vr.
+ const bool mIsUsingVrComposer;
};
} // namespace Hwc2
namespace android {
// ---------------------------------------------------------------------------
+class Fence;
class IGraphicBufferProducer;
class String8;
status_t FramebufferSurface::advanceFrame() {
#ifdef USE_HWC2
+ uint32_t slot = 0;
sp<GraphicBuffer> buf;
sp<Fence> acquireFence(Fence::NO_FENCE);
android_dataspace_t dataspace = HAL_DATASPACE_UNKNOWN;
- status_t result = nextBuffer(buf, acquireFence, dataspace);
+ status_t result = nextBuffer(slot, buf, acquireFence, dataspace);
if (result != NO_ERROR) {
ALOGE("error latching next FramebufferSurface buffer: %s (%d)",
strerror(-result), result);
return result;
}
- result = mHwc.setClientTarget(mDisplayType, acquireFence, buf, dataspace);
+ result = mHwc.setClientTarget(mDisplayType, slot,
+ acquireFence, buf, dataspace);
if (result != NO_ERROR) {
ALOGE("error posting framebuffer: %d", result);
}
}
#ifdef USE_HWC2
-status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer,
- sp<Fence>& outFence, android_dataspace_t& outDataspace) {
+status_t FramebufferSurface::nextBuffer(uint32_t& outSlot,
+ sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence,
+ android_dataspace_t& outDataspace) {
#else
status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence) {
#endif
BufferItem item;
status_t err = acquireBufferLocked(&item, 0);
if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
+#ifdef USE_HWC2
+ mHwcBufferCache->getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer,
+ &outSlot, &outBuffer);
+#else
outBuffer = mCurrentBuffer;
+#endif
return NO_ERROR;
} else if (err != NO_ERROR) {
ALOGE("error acquiring buffer: %s (%d)", strerror(-err), err);
mCurrentFence = item.mFence;
outFence = item.mFence;
- outBuffer = mCurrentBuffer;
#ifdef USE_HWC2
+ mHwcBufferCache->getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer,
+ &outSlot, &outBuffer);
outDataspace = item.mDataSpace;
+#else
+ outBuffer = mCurrentBuffer;
#endif
return NO_ERROR;
}
#ifndef ANDROID_SF_FRAMEBUFFER_SURFACE_H
#define ANDROID_SF_FRAMEBUFFER_SURFACE_H
+#include "DisplaySurface.h"
+
#include <stdint.h>
#include <sys/types.h>
#include <gui/ConsumerBase.h>
-#include "DisplaySurface.h"
+#include <memory>
// ---------------------------------------------------------------------------
namespace android {
class Rect;
class String8;
class HWComposer;
+class HWComposerBufferCache;
// ---------------------------------------------------------------------------
// BufferQueue and releases the previously latched buffer to the
// BufferQueue. The new buffer is returned in the 'buffer' argument.
#ifdef USE_HWC2
- status_t nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence,
- android_dataspace_t& outDataspace);
+ status_t nextBuffer(uint32_t& outSlot, sp<GraphicBuffer>& outBuffer,
+ sp<Fence>& outFence, android_dataspace_t& outDataspace);
#else
status_t nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence);
#endif
HWComposer& mHwc;
#ifdef USE_HWC2
+ std::unique_ptr<HWComposerBufferCache> mHwcBufferCache =
+ std::make_unique<HWComposerBufferCache>();
+
// Previous buffer to release after getting an updated retire fence
bool mHasPendingRelease;
int mPreviousBufferSlot;
mSetLayerVisibleRegion(nullptr),
mSetLayerZOrder(nullptr),
#else
-Device::Device()
- : mComposer(std::make_unique<Hwc2::Composer>()),
+Device::Device(bool useVrComposer)
+ : mComposer(std::make_unique<Hwc2::Composer>(useVrComposer)),
#endif // BYPASS_IHWC
mCapabilities(),
mDisplays(),
return static_cast<Error>(intError);
}
-Error Display::setClientTarget(buffer_handle_t target,
+Error Display::setClientTarget(uint32_t slot, buffer_handle_t target,
const sp<Fence>& acquireFence, android_dataspace_t dataspace)
{
// TODO: Properly encode client target surface damage
int32_t fenceFd = acquireFence->dup();
#ifdef BYPASS_IHWC
+ (void) slot;
int32_t intError = mDevice.mSetClientTarget(mDevice.mHwcDevice, mId, target,
fenceFd, static_cast<int32_t>(dataspace), {0, nullptr});
#else
- auto intError = mDevice.mComposer->setClientTarget(mId, target, fenceFd,
- static_cast<Hwc2::Dataspace>(dataspace),
+ 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);
return static_cast<Error>(intError);
}
-Error Layer::setBuffer(buffer_handle_t buffer,
+Error Layer::setBuffer(uint32_t slot, buffer_handle_t buffer,
const sp<Fence>& acquireFence)
{
int32_t fenceFd = acquireFence->dup();
#ifdef BYPASS_IHWC
+ (void) slot;
int32_t intError = mDevice.mSetLayerBuffer(mDevice.mHwcDevice, mDisplayId,
mId, buffer, fenceFd);
#else
auto intError = mDevice.mComposer->setLayerBuffer(mDisplayId,
- mId, buffer, fenceFd);
+ mId, slot, buffer, fenceFd);
#endif
return static_cast<Error>(intError);
}
#ifdef BYPASS_IHWC
explicit Device(hwc2_device_t* device);
#else
- Device();
+ // 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();
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
[[clang::warn_unused_result]] Error setActiveConfig(
const std::shared_ptr<const Config>& config);
[[clang::warn_unused_result]] Error setClientTarget(
- buffer_handle_t target,
+ uint32_t slot, buffer_handle_t target,
const android::sp<android::Fence>& acquireFence,
android_dataspace_t dataspace);
[[clang::warn_unused_result]] Error setColorMode(android_color_mode_t mode);
hwc2_layer_t getId() const { return mId; }
[[clang::warn_unused_result]] Error setCursorPosition(int32_t x, int32_t y);
- [[clang::warn_unused_result]] Error setBuffer(buffer_handle_t buffer,
+ [[clang::warn_unused_result]] Error setBuffer(uint32_t slot,
+ buffer_handle_t buffer,
const android::sp<android::Fence>& acquireFence);
[[clang::warn_unused_result]] Error setSurfaceDamage(
const android::Region& damage);
auto& hwc1Layer = mHwc1RequestedContents->hwLayers[layer->getHwc1Id()];
hwc1Layer.releaseFenceFd = -1;
hwc1Layer.acquireFenceFd = -1;
+ ALOGV("Applying states for layer %" PRIu64 " ", layer->getId());
layer->applyState(hwc1Layer, applyAllState);
}
mZ(0),
mReleaseFence(),
mHwc1Id(0),
- mHasUnsupportedDataspace(false),
- mHasUnsupportedPlaneAlpha(false) {}
+ mHasUnsupportedPlaneAlpha(false),
+ mHasUnsupportedBackgroundColor(false) {}
bool HWC2On1Adapter::SortLayersByZ::operator()(
const std::shared_ptr<Layer>& lhs, const std::shared_ptr<Layer>& rhs)
return Error::None;
}
-Error HWC2On1Adapter::Layer::setDataspace(android_dataspace_t dataspace)
+Error HWC2On1Adapter::Layer::setDataspace(android_dataspace_t)
{
- mHasUnsupportedDataspace = (dataspace != HAL_DATASPACE_UNKNOWN);
return Error::None;
}
// HWC1 never supports color transforms or dataspaces and only sometimes
// supports plane alpha (depending on the version). These require us to drop
// some or all layers to client composition.
- if (mHasUnsupportedDataspace || mHasUnsupportedPlaneAlpha ||
- mDisplay.hasColorTransform() || mHasUnsupportedBackgroundColor) {
+ ALOGV("applyCompositionType");
+ ALOGV("mHasUnsupportedPlaneAlpha = %d", mHasUnsupportedPlaneAlpha);
+ ALOGV("mDisplay.hasColorTransform() = %d", mDisplay.hasColorTransform());
+ ALOGV("mHasUnsupportedBackgroundColor = %d", mHasUnsupportedBackgroundColor);
+
+ if (mHasUnsupportedPlaneAlpha || mDisplay.hasColorTransform() ||
+ mHasUnsupportedBackgroundColor) {
hwc1Layer.compositionType = HWC_FRAMEBUFFER;
hwc1Layer.flags = HWC_SKIP_LAYER;
return;
}
}
- if (mHwc1DisplayMap.count(0) == 0) {
+ if (mHwc1DisplayMap.count(HWC_DISPLAY_PRIMARY) == 0) {
ALOGE("prepareAllDisplays: Unable to find primary HWC1 display");
return false;
}
DeferredFence mReleaseFence;
size_t mHwc1Id;
- bool mHasUnsupportedDataspace;
bool mHasUnsupportedPlaneAlpha;
bool mHasUnsupportedBackgroundColor;
};
#include "HWComposer.h"
#include "HWC2On1Adapter.h"
#include "HWC2.h"
+#include "ComposerHal.h"
#include "../Layer.h" // needed only for debugging
#include "../SurfaceFlinger.h"
// ---------------------------------------------------------------------------
-HWComposer::HWComposer(const sp<SurfaceFlinger>& flinger)
- : mFlinger(flinger),
- mAdapter(),
+HWComposer::HWComposer(bool useVrComposer)
+ : mAdapter(),
mHwcDevice(),
mDisplayData(2),
mFreeDisplaySlots(),
mVSyncCounts[i] = 0;
}
- loadHwcModule();
+ loadHwcModule(useVrComposer);
}
HWComposer::~HWComposer() {}
}
// Load and prepare the hardware composer module. Sets mHwc.
-void HWComposer::loadHwcModule()
+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) {
static_cast<hwc2_device_t*>(mAdapter.get()));
}
#else
- mHwcDevice = std::make_unique<HWC2::Device>();
+ mHwcDevice = std::make_unique<HWC2::Device>(useVrComposer);
#endif
mRemainingHwcVirtualDisplays = mHwcDevice->getMaxVirtualDisplayCount();
}
void HWComposer::invalidate(const std::shared_ptr<HWC2::Display>& /*display*/) {
- mFlinger->repaintEverything();
+ mEventHandler->onInvalidateReceived(this);
}
void HWComposer::vsync(const std::shared_ptr<HWC2::Display>& display,
snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp);
ATRACE_INT(tag, ++mVSyncCounts[disp] & 1);
- mEventHandler->onVSyncReceived(disp, timestamp);
+ mEventHandler->onVSyncReceived(this, disp, timestamp);
}
status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height,
}
}
-status_t HWComposer::setClientTarget(int32_t displayId,
+status_t HWComposer::setClientTarget(int32_t displayId, uint32_t slot,
const sp<Fence>& acquireFence, const sp<GraphicBuffer>& target,
android_dataspace_t dataspace) {
if (!isValidDisplay(displayId)) {
if ((target != nullptr) && target->getNativeBuffer()) {
handle = target->getNativeBuffer()->handle;
}
- auto error = hwcDisplay->setClientTarget(handle, acquireFence, dataspace);
+ auto error = hwcDisplay->setClientTarget(slot, handle,
+ acquireFence, dataspace);
if (error != HWC2::Error::None) {
ALOGE("Failed to set client target for display %d: %s (%d)", displayId,
to_string(error).c_str(), static_cast<int32_t>(error));
}
*/
+bool HWComposer::isUsingVrComposer() const {
+#ifdef BYPASS_IHWC
+ return false;
+#else
+ return getComposer()->isUsingVrComposer();
+#endif
+}
+
void HWComposer::dump(String8& result) const {
// TODO: In order to provide a dump equivalent to HWC1, we need to shadow
// all the state going into the layers. This is probably better done in
*this = DisplayData();
}
+void HWComposerBufferCache::clear()
+{
+ mBuffers.clear();
+}
+
+void HWComposerBufferCache::getHwcBuffer(int slot,
+ 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;
+ }
+
+ if (static_cast<size_t>(slot) >= mBuffers.size()) {
+ mBuffers.resize(slot + 1);
+ }
+
+ *outSlot = slot;
+
+ if (mBuffers[slot] == buffer) {
+ // already cached in HWC, skip sending the buffer
+ *outBuffer = nullptr;
+ } else {
+ *outBuffer = buffer;
+
+ // update cache
+ mBuffers[slot] = buffer;
+ }
+#endif
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
#include <stdint.h>
#include <sys/types.h>
+#include <gui/BufferQueue.h>
+
#include <ui/Fence.h>
#include <utils/BitSet.h>
class NativeHandle;
class Region;
class String8;
-class SurfaceFlinger;
class HWComposer
{
public:
class EventHandler {
friend class HWComposer;
- virtual void onVSyncReceived(int32_t disp, nsecs_t timestamp) = 0;
+ virtual void onVSyncReceived(
+ HWComposer* composer, int32_t disp, nsecs_t timestamp) = 0;
virtual void onHotplugReceived(int32_t disp, bool connected) = 0;
+ virtual void onInvalidateReceived(HWComposer* composer) = 0;
protected:
virtual ~EventHandler() {}
};
- HWComposer(const sp<SurfaceFlinger>& flinger);
+ // 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.
+ HWComposer(bool useVrComposer);
~HWComposer();
// Asks the HAL what it can do
status_t prepare(DisplayDevice& displayDevice);
- status_t setClientTarget(int32_t displayId, const sp<Fence>& acquireFence,
+ status_t setClientTarget(int32_t displayId, uint32_t slot,
+ const sp<Fence>& acquireFence,
const sp<GraphicBuffer>& target, android_dataspace_t dataspace);
// Present layers to the display and read releaseFences.
status_t setActiveColorMode(int32_t displayId, android_color_mode_t mode);
+ bool isUsingVrComposer() const;
+
// for debugging ----------------------------------------------------------
void dump(String8& out) const;
+ android::Hwc2::Composer* getComposer() const { return mHwcDevice->getComposer(); }
private:
static const int32_t VIRTUAL_DISPLAY_ID_BASE = 2;
- void loadHwcModule();
+ void loadHwcModule(bool useVrComposer);
bool isValidDisplay(int32_t displayId) const;
static void validateChange(HWC2::Composition from, HWC2::Composition to);
HWC2::Vsync vsyncEnabled;
};
- sp<SurfaceFlinger> mFlinger;
std::unique_ptr<HWC2On1Adapter> mAdapter;
std::unique_ptr<HWC2::Device> mHwcDevice;
std::vector<DisplayData> mDisplayData;
mutable Mutex mVsyncLock;
};
+class HWComposerBufferCache {
+public:
+ void clear();
+
+ void getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer,
+ uint32_t* outSlot, sp<GraphicBuffer>* outBuffer);
+
+private:
+ // a vector as we expect "slot" to be in the range of [0, 63] (that is,
+ // less than BufferQueue::NUM_BUFFER_SLOTS).
+ std::vector<sp<GraphicBuffer>> mBuffers;
+};
+
// ---------------------------------------------------------------------------
}; // namespace android
}
void HWComposer::invalidate() {
- mFlinger->repaintEverything();
+ mEventHandler.onInvalidateReceived(this);
}
void HWComposer::vsync(int disp, int64_t timestamp) {
snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp);
ATRACE_INT(tag, ++mVSyncCounts[disp] & 1);
- mEventHandler.onVSyncReceived(disp, timestamp);
+ mEventHandler.onVSyncReceived(this, disp, timestamp);
}
}
} while (err<0 && errno == EINTR);
if (err == 0) {
- mHwc.mEventHandler.onVSyncReceived(0, next_vsync);
+ mHwc.mEventHandler.onVSyncReceived(&mHwc, 0, next_vsync);
}
return true;
public:
class EventHandler {
friend class HWComposer;
- virtual void onVSyncReceived(int disp, nsecs_t timestamp) = 0;
+ virtual void onVSyncReceived(
+ HWComposer* composer, int32_t disp, nsecs_t timestamp) = 0;
virtual void onHotplugReceived(int disp, bool connected) = 0;
+ virtual void onInvalidateReceived(HWComposer* composer) = 0;
protected:
virtual ~EventHandler() {}
};
status_t result = NO_ERROR;
if (fbBuffer != NULL) {
#ifdef USE_HWC2
+ uint32_t hwcSlot = 0;
+ sp<GraphicBuffer> hwcBuffer;
+ mHwcBufferCache->getHwcBuffer(mFbProducerSlot, fbBuffer,
+ &hwcSlot, &hwcBuffer);
+
// TODO: Correctly propagate the dataspace from GL composition
- result = mHwc.setClientTarget(mDisplayId, mFbFence, fbBuffer,
- HAL_DATASPACE_UNKNOWN);
+ result = mHwc.setClientTarget(mDisplayId, hwcSlot, mFbFence,
+ hwcBuffer, HAL_DATASPACE_UNKNOWN);
#else
result = mHwc.fbPost(mDisplayId, mFbFence, fbBuffer);
#endif
#ifndef ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H
#define ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H
+#include "DisplaySurface.h"
+
#include <gui/ConsumerBase.h>
#include <gui/IGraphicBufferProducer.h>
-#include "DisplaySurface.h"
+#include <memory>
// ---------------------------------------------------------------------------
namespace android {
// ---------------------------------------------------------------------------
class HWComposer;
+class HWComposerBufferCache;
class IProducerListener;
/* This DisplaySurface implementation supports virtual displays, where GLES
static const char* dbgSourceStr(Source s);
bool mMustRecompose;
+
+#ifdef USE_HWC2
+ std::unique_ptr<HWComposerBufferCache> mHwcBufferCache =
+ std::make_unique<HWComposerBufferCache>();
+#endif
};
// ---------------------------------------------------------------------------
}
}
+void Layer::onBuffersReleased() {
+#ifdef USE_HWC2
+ Mutex::Autolock lock(mHwcBufferCacheMutex);
+
+ for (auto info : mHwcBufferCaches) {
+ info.second.clear();
+ }
+#endif
+}
+
void Layer::onSidebandStreamChanged() {
if (android_atomic_release_cas(false, true, &mSidebandStreamChanged) == 0) {
// mSidebandStreamChanged was false
Rect bounds = win;
const auto& p = getParent();
if (p != nullptr) {
- bounds = p->computeScreenBounds();
+ // Look in computeScreenBounds recursive call for explanation of
+ // why we pass false here.
+ bounds = p->computeScreenBounds(false /* reduceTransparentRegion */);
}
Transform t = getTransform();
static_cast<int32_t>(error));
}
+ uint32_t hwcSlot = 0;
+ buffer_handle_t hwcHandle = nullptr;
+ {
+ Mutex::Autolock lock(mHwcBufferCacheMutex);
+
+ auto& hwcBufferCache = mHwcBufferCaches[hwcId];
+ sp<GraphicBuffer> hwcBuffer;
+ hwcBufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer,
+ &hwcSlot, &hwcBuffer);
+ if (hwcBuffer != nullptr) {
+ hwcHandle = hwcBuffer->handle;
+ }
+ }
+
auto acquireFence = mSurfaceFlingerConsumer->getCurrentFence();
- error = hwcLayer->setBuffer(mActiveBuffer->handle, acquireFence);
+ error = hwcLayer->setBuffer(hwcSlot, hwcHandle, acquireFence);
if (error != HWC2::Error::None) {
ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(),
mActiveBuffer->handle, to_string(error).c_str(),
}
// update the active buffer
- mActiveBuffer = mSurfaceFlingerConsumer->getCurrentBuffer();
+ mActiveBuffer = mSurfaceFlingerConsumer->getCurrentBuffer(
+ &mActiveBufferSlot);
if (mActiveBuffer == NULL) {
// this can only happen if the very first buffer was rejected.
return outDirtyRegion;
#ifdef USE_HWC2
// -----------------------------------------------------------------------
+ void eraseHwcLayer(int32_t hwcId) {
+ mHwcLayers.erase(hwcId);
+
+ Mutex::Autolock lock(mHwcBufferCacheMutex);
+ mHwcBufferCaches.erase(hwcId);
+ }
+
bool hasHwcLayer(int32_t hwcId) {
if (mHwcLayers.count(hwcId) == 0) {
return false;
}
if (mHwcLayers[hwcId].layer->isAbandoned()) {
ALOGI("Erasing abandoned layer %s on %d", mName.string(), hwcId);
- mHwcLayers.erase(hwcId);
+ eraseHwcLayer(hwcId);
return false;
}
return true;
void setHwcLayer(int32_t hwcId, std::shared_ptr<HWC2::Layer>&& layer) {
if (layer) {
mHwcLayers[hwcId].layer = layer;
+
+ Mutex::Autolock lock(mHwcBufferCacheMutex);
+ mHwcBufferCaches[hwcId] = HWComposerBufferCache();
} else {
- mHwcLayers.erase(hwcId);
+ eraseHwcLayer(hwcId);
}
}
+ void clearHwcLayers() {
+ mHwcLayers.clear();
+ }
+
#endif
// -----------------------------------------------------------------------
// Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener
virtual void onFrameAvailable(const BufferItem& item) override;
virtual void onFrameReplaced(const BufferItem& item) override;
+ virtual void onBuffersReleased() override;
virtual void onSidebandStreamChanged() override;
void commitTransaction(const State& stateToCommit);
FenceTimeline mReleaseTimeline;
// main thread
+ int mActiveBufferSlot = BufferQueue::INVALID_BUFFER_SLOT;
sp<GraphicBuffer> mActiveBuffer;
sp<NativeHandle> mSidebandStream;
Rect mCurrentCrop;
gfx::FloatRect sourceCrop;
};
std::unordered_map<int32_t, HWCInfo> mHwcLayers;
+
+ // We need one HWComposerBufferCache for each HWC display. We cannot have
+ // HWComposerBufferCache in HWCInfo because HWCInfo can only be accessed
+ // from the main thread.
+ Mutex mHwcBufferCacheMutex;
+ std::unordered_map<int32_t, HWComposerBufferCache> mHwcBufferCaches;
#else
bool mIsGlesComposition;
#endif
#include <binder/MemoryHeapBase.h>
#include <binder/PermissionCache.h>
+#include <dvr/vr_flinger.h>
+
#include <ui/DisplayInfo.h>
#include <ui/DisplayStatInfo.h>
#include "LayerDim.h"
#include "MonitoredProducer.h"
#include "SurfaceFlinger.h"
+#include "VrStateCallbacks.h"
#include "DisplayHardware/FramebufferSurface.h"
#include "DisplayHardware/HWComposer.h"
mLayersRemoved(false),
mLayersAdded(false),
mRepaintEverything(0),
- mRenderEngine(NULL),
+ mHwc(nullptr),
+ mRealHwc(nullptr),
+ mVrHwc(nullptr),
+ mRenderEngine(nullptr),
mBootTime(systemTime()),
mBuiltinDisplays(),
mVisibleRegionsDirty(false),
mFrameBuckets(),
mTotalTime(0),
mLastSwapTime(0),
- mNumLayers(0)
+ mNumLayers(0),
+ mEnterVrMode(false)
{
ALOGI("SurfaceFlinger is starting");
mPropagateBackpressure = !atoi(value);
ALOGI_IF(!mPropagateBackpressure, "Disabling backpressure propagation");
- property_get("debug.sf.disable_hwc_vds", value, "0");
- mUseHwcVirtualDisplays = !atoi(value);
- ALOGI_IF(!mUseHwcVirtualDisplays, "Disabling HWC virtual displays");
+ property_get("debug.sf.enable_hwc_vds", value, "0");
+ mUseHwcVirtualDisplays = atoi(value);
+ ALOGI_IF(!mUseHwcVirtualDisplays, "Enabling HWC virtual displays");
- property_get("ro.sf.disable_triple_buffer", value, "0");
- mLayerTripleBufferingDisabled = !atoi(value);
+ property_get("ro.sf.disable_triple_buffer", value, "1");
+ mLayerTripleBufferingDisabled = atoi(value);
ALOGI_IF(mLayerTripleBufferingDisabled, "Disabling Triple Buffering");
}
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglTerminate(display);
+
+ if (mVrStateCallbacks.get()) {
+ sp<IVrManager> vrManagerService = interface_cast<IVrManager>(
+ defaultServiceManager()->checkService(String16("vrmanager")));
+ if (vrManagerService.get()) {
+ vrManagerService->unregisterListener(mVrStateCallbacks);
+ }
+ }
}
void SurfaceFlinger::binderDied(const wp<IBinder>& /* who */)
const int LOGTAG_SF_STOP_BOOTANIM = 60110;
LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
+
+ sp<IVrManager> vrManagerService = interface_cast<IVrManager>(
+ defaultServiceManager()->checkService(String16("vrmanager")));
+ if (vrManagerService.get()) {
+ mVrStateCallbacks = new VrStateCallbacks(*this);
+ vrManagerService->registerListener(mVrStateCallbacks);
+ }
}
void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
// Drop the state lock while we initialize the hardware composer. We drop
// the lock because on creation, it will call back into SurfaceFlinger to
// initialize the primary display.
- mHwc = new HWComposer(this);
+ LOG_ALWAYS_FATAL_IF(mEnterVrMode, "Starting in vr mode is not currently supported.");
+ mRealHwc = new HWComposer(false);
+ mHwc = mRealHwc;
mHwc->setEventHandler(static_cast<HWComposer::EventHandler*>(this));
Mutex::Autolock _l(mStateLock);
}
}
-void SurfaceFlinger::onVSyncReceived(int32_t type, nsecs_t timestamp) {
+void SurfaceFlinger::onVSyncReceived(HWComposer* composer, int32_t type,
+ nsecs_t timestamp) {
+ Mutex::Autolock lock(mStateLock);
+ // Ignore any vsyncs from the non-active hardware composer.
+ if (composer != mHwc) {
+ return;
+ }
+
bool needsHwVsync = false;
{ // Scope for the lock
bool isSecure = true;
int32_t type = DisplayDevice::DISPLAY_PRIMARY;
- createBuiltinDisplayLocked(DisplayDevice::DISPLAY_PRIMARY);
+
+ // When we're using the vr composer, the assumption is that we've
+ // already created the IBinder object for the primary display.
+ if (!mHwc->isUsingVrComposer()) {
+ createBuiltinDisplayLocked(DisplayDevice::DISPLAY_PRIMARY);
+ }
+
wp<IBinder> token = mBuiltinDisplays[type];
sp<IGraphicBufferProducer> producer;
}
}
+void SurfaceFlinger::onInvalidateReceived(HWComposer* composer) {
+ Mutex::Autolock lock(mStateLock);
+ if (composer == mHwc) {
+ repaintEverything();
+ } else {
+ // This isn't from our current hardware composer. If it's a callback
+ // from the real composer, forward the refresh request to vr
+ // flinger. Otherwise ignore it.
+ if (!composer->isUsingVrComposer()) {
+ mVrFlinger->OnHardwareComposerRefresh();
+ }
+ }
+}
+
void SurfaceFlinger::setVsyncEnabled(int disp, int enabled) {
ATRACE_CALL();
getHwComposer().setVsyncEnabled(disp,
enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable);
}
+void SurfaceFlinger::clearHwcLayers(const LayerVector& layers) {
+ for (size_t i = 0; i < layers.size(); ++i) {
+ layers[i]->clearHwcLayers();
+ }
+}
+
+void SurfaceFlinger::resetHwc() {
+ disableHardwareVsync(true);
+ clearHwcLayers(mDrawingState.layersSortedByZ);
+ clearHwcLayers(mCurrentState.layersSortedByZ);
+ // Clear the drawing state so that the logic inside of
+ // handleTransactionLocked will fire. It will determine the delta between
+ // mCurrentState and mDrawingState and re-apply all changes when we make the
+ // transition.
+ mDrawingState.displays.clear();
+ mDisplays.clear();
+}
+
+void SurfaceFlinger::updateVrMode() {
+ {
+ Mutex::Autolock _l(mStateLock);
+ bool enteringVrMode = mEnterVrMode;
+ if (enteringVrMode == mHwc->isUsingVrComposer()) {
+ return;
+ }
+
+ if (enteringVrMode) {
+ // Start vrflinger thread, if it hasn't been started already.
+ if (!mVrFlinger) {
+ mVrFlinger = std::make_unique<dvr::VrFlinger>();
+ int err = mVrFlinger->Run(mHwc->getComposer());
+ if (err != NO_ERROR) {
+ ALOGE("Failed to run vrflinger: %s (%d)", strerror(-err), err);
+ mVrFlinger.reset();
+ mEnterVrMode = false;
+ return;
+ }
+ }
+
+ if (!mVrHwc) {
+ mVrHwc = new HWComposer(true);
+ ALOGV("Vr HWC created");
+ }
+
+ resetHwc();
+
+ mHwc = mVrHwc;
+ mVrFlinger->EnterVrMode();
+ } else {
+ mVrFlinger->ExitVrMode();
+
+ resetHwc();
+
+ mHwc = mRealHwc;
+ enableHardwareVsync();
+ }
+
+ mVisibleRegionsDirty = true;
+ invalidateHwcGeometry();
+ android_atomic_or(1, &mRepaintEverything);
+ setTransactionFlags(eDisplayTransactionNeeded);
+ }
+ if (mVrHwc) {
+ mVrHwc->setEventHandler(static_cast<HWComposer::EventHandler*>(this));
+ }
+}
+
void SurfaceFlinger::onMessageReceived(int32_t what) {
ATRACE_CALL();
switch (what) {
case MessageQueue::INVALIDATE: {
+ updateVrMode();
+
bool frameMissed = !mHadClientComposition &&
mPreviousPresentFence != Fence::NO_FENCE &&
(mPreviousPresentFence->getSignalTime() ==
"adding a supported display, but rendering "
"surface is provided (%p), ignoring it",
state.surface.get());
- if (state.type == DisplayDevice::DISPLAY_EXTERNAL) {
- hwcId = DisplayDevice::DISPLAY_EXTERNAL;
- dispSurface = new FramebufferSurface(*mHwc,
- DisplayDevice::DISPLAY_EXTERNAL,
- bqConsumer);
- producer = bqProducer;
- } else {
- ALOGE("Attempted to add non-external non-virtual"
- " display");
- }
+
+ hwcId = state.type;
+ dispSurface = new FramebufferSurface(*mHwc, hwcId, bqConsumer);
+ producer = bqProducer;
}
const wp<IBinder>& display(curr.keyAt(i));
switch (layer->getCompositionType(hwcId)) {
case HWC2::Composition::Cursor:
case HWC2::Composition::Device:
+ case HWC2::Composition::Sideband:
case HWC2::Composition::SolidColor: {
const Layer::State& state(layer->getDrawingState());
if (layer->getClearClientTarget(hwcId) && !firstLayer &&
#ifndef ANDROID_SURFACE_FLINGER_H
#define ANDROID_SURFACE_FLINGER_H
+#include <memory>
#include <stdint.h>
#include <sys/types.h>
class EventControlThread;
class VSyncSource;
class InjectVSyncSource;
+class VrStateCallbacks;
+
+namespace dvr {
+class VrFlinger;
+} // namespace dvr
// ---------------------------------------------------------------------------
friend class EventThread;
friend class Layer;
friend class MonitoredProducer;
+ friend class VrStateCallbacks;
// This value is specified in number of frames. Log frame stats at most
// every half hour.
/* ------------------------------------------------------------------------
* HWComposer::EventHandler interface
*/
- virtual void onVSyncReceived(int type, nsecs_t timestamp);
+ virtual void onVSyncReceived(HWComposer* composer, int type, nsecs_t timestamp);
virtual void onHotplugReceived(int disp, bool connected);
+ virtual void onInvalidateReceived(HWComposer* composer);
/* ------------------------------------------------------------------------
* Message handling
bool isLayerTripleBufferingDisabled() const {
return this->mLayerTripleBufferingDisabled;
}
+
+#ifdef USE_HWC2
+ /* ------------------------------------------------------------------------
+ * VrFlinger
+ */
+ void clearHwcLayers(const LayerVector& layers);
+ void resetHwc();
+
+ // Check to see if we should change to or from vr mode, and if so, perform
+ // the handoff.
+ void updateVrMode();
+#endif
+
/* ------------------------------------------------------------------------
* Attributes
*/
// access must be protected by mInvalidateLock
volatile int32_t mRepaintEverything;
- // constant members (no synchronization needed for access)
+ // current, real and vr hardware composers.
HWComposer* mHwc;
+#ifdef USE_HWC2
+ HWComposer* mRealHwc;
+ HWComposer* mVrHwc;
+#endif
+ // constant members (no synchronization needed for access)
RenderEngine* mRenderEngine;
nsecs_t mBootTime;
bool mGpuToCpuSupported;
EGLDisplay mEGLDisplay;
sp<IBinder> mBuiltinDisplays[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES];
+#ifdef USE_HWC2
+ std::unique_ptr<dvr::VrFlinger> mVrFlinger;
+#endif
+
// Can only accessed from the main thread, these members
// don't need synchronization
State mDrawingState;
bool mPropagateBackpressure = true;
#endif
SurfaceInterceptor mInterceptor;
- bool mUseHwcVirtualDisplays = true;
+ bool mUseHwcVirtualDisplays = false;
// Restrict layers to use two buffers in their bufferqueues.
bool mLayerTripleBufferingDisabled = false;
// Verify that transaction is being called by an approved process:
// either AID_GRAPHICS or AID_SYSTEM.
status_t CheckTransactCodeCredentials(uint32_t code);
+
+#ifdef USE_HWC2
+ sp<VrStateCallbacks> mVrStateCallbacks;
+
+ std::atomic<bool> mEnterVrMode;
+#endif
};
}; // namespace android
mContentsChangedListener = listener;
}
+void SurfaceFlingerConsumer::onBuffersReleased() {
+ sp<ContentsChangedListener> listener;
+ { // scope for the lock
+ Mutex::Autolock lock(mMutex);
+ ALOG_ASSERT(mFrameAvailableListener.unsafe_get() == mContentsChangedListener.unsafe_get());
+ listener = mContentsChangedListener.promote();
+ }
+
+ if (listener != NULL) {
+ listener->onBuffersReleased();
+ }
+}
+
void SurfaceFlingerConsumer::onSidebandStreamChanged() {
sp<ContentsChangedListener> listener;
{ // scope for the lock
static const status_t BUFFER_REJECTED = UNKNOWN_ERROR + 8;
struct ContentsChangedListener: public FrameAvailableListener {
+ virtual void onBuffersReleased() = 0;
virtual void onSidebandStreamChanged() = 0;
};
FrameEventHistoryDelta* outDelta) override;
private:
+ virtual void onBuffersReleased();
virtual void onSidebandStreamChanged();
wp<ContentsChangedListener> mContentsChangedListener;
ALOGI_IF(mDebugRegion, "showupdates enabled");
ALOGI_IF(mDebugDDMS, "DDMS debugging enabled");
- property_get("debug.sf.disable_hwc_vds", value, "0");
- mUseHwcVirtualDisplays = !atoi(value);
- ALOGI_IF(!mUseHwcVirtualDisplays, "Disabling HWC virtual displays");
+ property_get("debug.sf.enable_hwc_vds", value, "0");
+ mUseHwcVirtualDisplays = atoi(value);
+ ALOGI_IF(!mUseHwcVirtualDisplays, "Enabling HWC virtual displays");
- property_get("ro.sf.disable_triple_buffer", value, "0");
- mLayerTripleBufferingDisabled = !atoi(value);
+ property_get("ro.sf.disable_triple_buffer", value, "1");
+ mLayerTripleBufferingDisabled = atoi(value);
ALOGI_IF(mLayerTripleBufferingDisabled, "Disabling Triple Buffering");
}
}
}
-void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) {
+void SurfaceFlinger::onVSyncReceived(HWComposer* /*composer*/, int type,
+ nsecs_t timestamp) {
bool needsHwVsync = false;
{ // Scope for the lock
}
}
+void SurfaceFlinger::onInvalidateReceived(HWComposer* /*composer*/) {
+ repaintEverything();
+}
+
void SurfaceFlinger::eventControl(int disp, int event, int enabled) {
ATRACE_CALL();
getHwComposer().eventControl(disp, event, enabled);
--- /dev/null
+/*
+ * 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 "VrStateCallbacks.h"
+#include "SurfaceFlinger.h"
+
+namespace android {
+
+VrStateCallbacks::VrStateCallbacks(SurfaceFlinger& flinger)
+ : mFlinger(flinger) {}
+
+void VrStateCallbacks::onVrStateChanged(bool enabled) {
+ mFlinger.mEnterVrMode = enabled;
+ mFlinger.signalTransaction();
+}
+
+} // namespace android
--- /dev/null
+/*
+ * 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_VR_STATE_CALLBACKS_H
+#define ANDROID_VR_STATE_CALLBACKS_H
+
+#include <vr/vr_manager/vr_manager.h>
+
+namespace android {
+
+class SurfaceFlinger;
+
+class VrStateCallbacks : public BnVrStateCallbacks {
+public:
+ VrStateCallbacks(SurfaceFlinger& flinger);
+ void onVrStateChanged(bool enabled) override;
+
+private:
+ SurfaceFlinger& mFlinger;
+};
+
+} // namespace android
+
+#endif // ANDROID_VR_STATE_CALLBACKS_H
cFlags := -DLOG_TAG=\"sensord\" \
-DTRACE=0
-ifeq ($(TARGET_USES_QCOM_BSP), true)
-ifneq ($(TARGET_QCOM_DISPLAY_VARIANT),)
- platform := .
-else
- platform := $(TARGET_BOARD_PLATFORM)
-endif
- cFlags += -DQCOM_B_FAMILY \
- -DQCOM_BSP
-endif
-
include $(CLEAR_VARS)
# Don't strip symbols so we see stack traces in logcat.
LOCAL_STRIP_MODULE := false
LOCAL_SRC_FILES := $(sourceFiles)
-PLATFORM := $(platform)
LOCAL_CFLAGS := $(cFlags)
LOCAL_STATIC_LIBRARIES := $(staticLibraries)
LOCAL_SHARED_LIBRARIES := $(sharedLibraries)
LOCAL_PATH := $(call my-dir)
+binder_src := \
+ vr_window_manager_binder.cpp \
+ aidl/android/service/vr/IVrWindowManager.aidl
+
+static_libs := \
+ libcutils
+
+shared_libs := \
+ libbase \
+ libbinder \
+ libutils
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(binder_src)
+LOCAL_STATIC_LIBRARIES := $(static_libs)
+LOCAL_SHARED_LIBRARIES := $(shared_libs)
+LOCAL_CPPFLAGS += -std=c++11
+LOCAL_CFLAGS += -DLOG_TAG=\"VrWindowManager\"
+LOCAL_LDLIBS := -llog
+LOCAL_MODULE := libvrwm_binder
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_STATIC_LIBRARY)
+
+
native_src := \
application.cpp \
controller_mesh.cpp \
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(src)
-LOCAL_C_INCLUDES := hardware/qcom/display/msm8996/libgralloc
LOCAL_STATIC_LIBRARIES := $(static_libs)
LOCAL_SHARED_LIBRARIES := $(shared_libs)
LOCAL_SHARED_LIBRARIES += libgvr
LOCAL_LDLIBS := -llog
LOCAL_MODULE := libvr_window_manager_jni
LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_TARGET_ARCH := arm arm64 x86 x86_64
LOCAL_MULTILIB := 64
LOCAL_CXX_STL := libc++_static
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(native_src)
-LOCAL_C_INCLUDES := hardware/qcom/display/msm8996/libgralloc
-LOCAL_STATIC_LIBRARIES := $(static_libs)
+LOCAL_STATIC_LIBRARIES := $(static_libs) libvrwm_binder
LOCAL_SHARED_LIBRARIES := $(shared_libs)
LOCAL_SHARED_LIBRARIES += libgvr
LOCAL_STATIC_LIBRARIES += libgvr_ext
LOCAL_LDLIBS := -llog
LOCAL_MODULE := vr_wm
LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_TARGET_ARCH := arm arm64 x86 x86_64
LOCAL_INIT_RC := vr_wm.rc
include $(BUILD_EXECUTABLE)
LOCAL_AAPT_FLAGS += --auto-add-overlay
LOCAL_AAPT_FLAGS += --extra-packages com.google.vr.cardboard
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+LOCAL_MODULE_TARGET_ARCH := arm arm64 x86 x86_64
include $(BUILD_PACKAGE)
+
+
+cmd_src := \
+ vr_wm_ctl.cpp \
+ aidl/android/service/vr/IVrWindowManager.aidl
+
+static_libs := \
+ libcutils
+
+shared_libs := \
+ libbase \
+ libbinder \
+ libutils
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(cmd_src)
+LOCAL_STATIC_LIBRARIES := $(static_libs)
+LOCAL_SHARED_LIBRARIES := $(shared_libs)
+LOCAL_CPPFLAGS += -std=c++11
+LOCAL_CFLAGS += -DLOG_TAG=\"vrwmctl\"
+LOCAL_LDLIBS := -llog
+LOCAL_MODULE := vr_wm_ctl
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_EXECUTABLE)
<service android:name=".VrWindowManagerService" />
<receiver android:name="com.google.vr.windowmanager.BootCompletedReceiver">
<intent-filter>
- <action android:name="android.intent.action.BOOT_COMPLETED" />
+ <!-- action android:name="android.intent.action.BOOT_COMPLETED" / -->
</intent-filter>
</receiver>
</application>
--- /dev/null
+/**
+ * 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.
+ */
+
+package android.service.vr;
+
+/** @hide */
+interface IVrWindowManager {
+ const String SERVICE_NAME = "vr_window_manager";
+ void connectController(in FileDescriptor fd) = 0;
+ void disconnectController() = 1;
+ void enterVrMode() = 2;
+ void exitVrMode() = 3;
+ void setDebugMode(int mode) = 4;
+}
+
}
break;
case MainThreadTask::EnteringVrMode:
- if (!initialized_)
- AllocateResources();
+ if (!initialized_) {
+ if (AllocateResources())
+ ALOGE("Failed to allocate resources");
+ }
break;
case MainThreadTask::ExitingVrMode:
if (initialized_)
if (fade_value_ > 1.0f)
fade_value_ = 1.0f;
- quat controller_quat(controller_orientation_.qw, controller_orientation_.qx,
- controller_orientation_.qy, controller_orientation_.qz);
- controller_position_ = elbow_model_.Update(
- delta, last_pose_.GetRotation(), controller_quat, false);
+ controller_position_ = elbow_model_.Update(delta, last_pose_.GetRotation(),
+ controller_orientation_, false);
dvrBeginRenderFrameEds(graphics_context_, pose.orientation,
pose.translation);
}
void Application::ProcessControllerInput() {
+ if (controller_data_provider_) {
+ shmem_controller_active_ = false;
+ const void* data = controller_data_provider_->LockControllerData();
+ // TODO(kpschoedel): define wire format.
+ if (data) {
+ struct wire_format {
+ uint32_t version;
+ uint32_t timestamph;
+ uint32_t timestampl;
+ uint32_t quat_count;
+ float q[4];
+ uint32_t buttonsh;
+ uint32_t buttonsl;
+ } __attribute__((__aligned__(32)));
+ const wire_format* wire_data = static_cast<const wire_format*>(data);
+ static uint64_t last_timestamp = 0;
+ if (wire_data->version == 1) {
+ shmem_controller_active_ = true;
+ uint64_t timestamp =
+ (((uint64_t)wire_data->timestamph) << 32) | wire_data->timestampl;
+ if (timestamp == last_timestamp) {
+ static uint64_t last_logged_timestamp = 0;
+ if (last_logged_timestamp != last_timestamp) {
+ last_logged_timestamp = last_timestamp;
+ ALOGI("Controller shmem stale T=0x%" PRIX64, last_timestamp);
+ }
+ } else {
+ last_timestamp = timestamp;
+ controller_orientation_ = quat(wire_data->q[3], wire_data->q[0],
+ wire_data->q[1], wire_data->q[2]);
+ shmem_controller_buttons_ =
+ (((uint64_t)wire_data->buttonsh) << 32) | wire_data->buttonsl;
+ }
+ } else if (wire_data->version == 0xFEEDFACE) {
+ static bool logged_init = false;
+ if (!logged_init) {
+ logged_init = true;
+ ALOGI("Controller shmem waiting for data");
+ }
+ }
+ }
+ controller_data_provider_->UnlockControllerData();
+ if (shmem_controller_active_) {
+ // TODO(kpschoedel): change to ALOGV or remove.
+ ALOGI("Controller shmem orientation: %f %f %f %f",
+ controller_orientation_.x(), controller_orientation_.y(),
+ controller_orientation_.z(), controller_orientation_.w());
+ if (shmem_controller_buttons_) {
+ ALOGI("Controller shmem buttons: %017" PRIX64,
+ shmem_controller_buttons_);
+ }
+ return;
+ }
+ }
+
if (!controller_)
return;
controller_connection_state_logged_ = false;
}
- if (new_api_status == gvr::kControllerApiOk)
- controller_orientation_ = controller_state_->GetOrientation();
+ if (new_api_status == gvr::kControllerApiOk) {
+ gvr_quatf orientation = controller_state_->GetOrientation();
+ controller_orientation_ =
+ quat(orientation.qw, orientation.qx, orientation.qy, orientation.qz);
+ }
controller_api_status_ = new_api_status;
controller_connection_state_ = new_connection_state;
#include <chrono>
#include <mutex>
+#include "controller_data_provider.h"
#include "elbow_model.h"
struct DvrGraphicsContext;
void DrawFrame();
+ void SetControllerDataProvider(ControllerDataProvider* provider) {
+ controller_data_provider_ = provider;
+ }
+
protected:
enum class MainThreadTask {
EnteringVrMode,
std::unique_ptr<gvr::ControllerState> controller_state_;
gvr::ControllerApiStatus controller_api_status_;
gvr::ControllerConnectionState controller_connection_state_;
- gvr_quatf controller_orientation_;
+ quat controller_orientation_;
+ bool shmem_controller_active_ = false;
bool controller_api_status_logged_;
bool controller_connection_state_logged_;
+ uint64_t shmem_controller_buttons_;
bool is_visible_ = false;
std::chrono::time_point<std::chrono::system_clock> visibility_button_press_;
jobject app_context_;
jobject class_loader_;
+ // Controller data provider from shared memory buffer.
+ ControllerDataProvider* controller_data_provider_ = nullptr;
+
Application(const Application&) = delete;
void operator=(const Application&) = delete;
};
"1.0",
]
-//cc_library_shared {
-// name: "libvrhwc",
-//
-// srcs: [
-// "impl/sync_timeline.cpp",
-// "impl/vr_composer_view.cpp",
-// "impl/vr_hwc.cpp",
-// "impl/vr_composer_client.cpp",
-// ],
-//
-// static_libs: [
-// "libhwcomposer-client",
-// ],
-//
-// shared_libs: [
-// "android.dvr.composer@1.0",
-// "android.hardware.graphics.composer@2.1",
-// "libbase",
-// "libcutils",
-// "libfmq",
-// "libhardware",
-// "libhidlbase",
-// "libhidltransport",
-// "liblog",
-// "libsync",
-// "libui",
-// "libutils",
-// ],
-//
-// export_include_dirs: ["."],
-//
-// include_dirs: [
-// // Access to software sync timeline.
-// "system/core/libsync",
-//
-// // Access to internal gralloc implementation.
-// "hardware/qcom/display/msm8996/libgralloc",
-// ],
-//
-// cflags: [
-// "-DLOG_TAG=\"vrhwc\"",
-// ],
-//}
+cc_library_shared {
+ name: "libvrhwc",
+
+ srcs: [
+ "impl/sync_timeline.cpp",
+ "impl/vr_composer_view.cpp",
+ "impl/vr_hwc.cpp",
+ "impl/vr_composer_client.cpp",
+ ],
+
+ static_libs: [
+ "libhwcomposer-client",
+ ],
+
+ shared_libs: [
+ "android.dvr.composer@1.0",
+ "android.hardware.graphics.composer@2.1",
+ "libbase",
+ "libcutils",
+ "libfmq",
+ "libhardware",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libsync",
+ "libui",
+ "libutils",
+ ],
+
+ export_include_dirs: ["."],
+
+ include_dirs: [
+ // Access to software sync timeline.
+ "system/core/libsync",
+ ],
+
+ cflags: [
+ "-DLOG_TAG=\"vrhwc\"",
+ ],
+}
*/
#include "vr_hwc.h"
-#include <gralloc_priv.h>
#include <ui/Fence.h>
#include <ui/GraphicBuffer.h>
#include <ui/GraphicBufferMapper.h>
const Config kDefaultConfigId = 1;
sp<GraphicBuffer> GetBufferFromHandle(const native_handle_t* handle) {
- // TODO(dnicoara): Fix this once gralloc1 is available.
- private_handle_t* private_handle = private_handle_t::dynamicCast(handle);
+ uint32_t width = 0, height = 0, stride = 0, layer_count = 1;
+ uint64_t producer_usage = 0, consumer_usage = 0;
+ int32_t format = 0;
+
+ GraphicBufferMapper& mapper = GraphicBufferMapper::get();
+ if (mapper.getDimensions(handle, &width, &height) ||
+ mapper.getStride(handle, &stride) ||
+ mapper.getFormat(handle, &format) ||
+ mapper.getProducerUsage(handle, &producer_usage) ||
+ mapper.getConsumerUsage(handle, &consumer_usage)) {
+ ALOGE("Failed to read handle properties");
+ return nullptr;
+ }
+
+ // This will only succeed if gralloc has GRALLOC1_CAPABILITY_LAYERED_BUFFERS
+ // capability. Otherwise assume a count of 1.
+ mapper.getLayerCount(handle, &layer_count);
+
sp<GraphicBuffer> buffer = new GraphicBuffer(
- private_handle->width, private_handle->height, private_handle->format, 1,
- GraphicBuffer::USAGE_HW_COMPOSER | GraphicBuffer::USAGE_HW_TEXTURE,
- private_handle->width, native_handle_clone(handle), true);
- if (GraphicBufferMapper::get().registerBuffer(buffer.get()) != OK) {
+ width, height, format, layer_count, producer_usage, consumer_usage,
+ stride, native_handle_clone(handle), true);
+ if (mapper.registerBuffer(buffer.get()) != OK) {
ALOGE("Failed to register buffer");
return nullptr;
}
}
}
-std::vector<ComposerView::ComposerLayer> HwcDisplay::GetFrame() {
- // Increment the time the fence is signalled every time we get the
- // presentation frame. This ensures that calling ReleaseFrame() only affects
- // the current frame.
- fence_time_++;
-
+Error HwcDisplay::GetFrame(
+ std::vector<ComposerView::ComposerLayer>* out_frames) {
bool queued_client_target = false;
std::vector<ComposerView::ComposerLayer> frame;
for (const auto& layer : layers_) {
if (layer.composition_type == IComposerClient::Composition::CLIENT) {
- if (!queued_client_target) {
- ComposerView::ComposerLayer client_target_layer = {
- .buffer = buffer_,
- .fence = fence_.get() ? fence_ : new Fence(-1),
- .display_frame = {0, 0, static_cast<int32_t>(buffer_->getWidth()),
- static_cast<int32_t>(buffer_->getHeight())},
- .crop = {0.0f, 0.0f, static_cast<float>(buffer_->getWidth()),
- static_cast<float>(buffer_->getHeight())},
- .blend_mode = IComposerClient::BlendMode::NONE,
- };
-
- frame.push_back(client_target_layer);
- queued_client_target = true;
+ if (queued_client_target)
+ continue;
+
+ if (!buffer_.get()) {
+ ALOGE("Client composition requested but no client target buffer");
+ return Error::BAD_LAYER;
}
+
+ ComposerView::ComposerLayer client_target_layer = {
+ .buffer = buffer_,
+ .fence = fence_.get() ? fence_ : new Fence(-1),
+ .display_frame = {0, 0, static_cast<int32_t>(buffer_->getWidth()),
+ static_cast<int32_t>(buffer_->getHeight())},
+ .crop = {0.0f, 0.0f, static_cast<float>(buffer_->getWidth()),
+ static_cast<float>(buffer_->getHeight())},
+ .blend_mode = IComposerClient::BlendMode::NONE,
+ };
+
+ frame.push_back(client_target_layer);
+ queued_client_target = true;
} else {
+ if (!layer.info.buffer.get() || !layer.info.fence.get()) {
+ ALOGE("Layer requested without valid buffer");
+ return Error::BAD_LAYER;
+ }
+
frame.push_back(layer.info);
}
}
- return frame;
+ if (frame.empty()) {
+ ALOGE("Requested frame with no layers");
+ return Error::BAD_LAYER;
+ }
+
+ // Increment the time the fence is signalled every time we get the
+ // presentation frame. This ensures that calling ReleaseFrame() only affects
+ // the current frame.
+ fence_time_++;
+ out_frames->swap(frame);
+ return Error::NONE;
}
void HwcDisplay::GetReleaseFences(int* present_fence,
base::unique_fd fence(releaseFence);
if (display != kDefaultDisplayId) return Error::BAD_DISPLAY;
- return Error::NONE;
+ ALOGE("Virtual display support not implemented");
+ return Error::UNSUPPORTED;
}
Error VrHwc::validateDisplay(
std::vector<ComposerView::ComposerLayer> frame;
{
std::lock_guard<std::mutex> guard(mutex_);
- frame = display_.GetFrame();
+ Error status = display_.GetFrame(&frame);
+ if (status != Error::NONE)
+ return status;
+
display_.GetReleaseFences(outPresentFence, outLayers, outReleaseFences);
}
#include <android/hardware/graphics/composer/2.1/IComposer.h>
#include <ComposerBase.h>
-#include <ui/GraphicBufferMapper.h>
+#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
#include <utils/StrongPointer.h>
#include <mutex>
std::vector<Layer>* layer_ids,
std::vector<IComposerClient::Composition>* composition);
- std::vector<ComposerView::ComposerLayer> GetFrame();
+ Error GetFrame(std::vector<ComposerView::ComposerLayer>* out_frame);
void GetReleaseFences(int* present_fence, std::vector<Layer>* layer_ids,
std::vector<int>* fences);
--- /dev/null
+#ifndef VR_WINDOW_MANAGER_CONTROLLER_DATA_PROVIDER_H_
+#define VR_WINDOW_MANAGER_CONTROLLER_DATA_PROVIDER_H_
+
+namespace android {
+namespace dvr {
+
+class ControllerDataProvider {
+ public:
+ virtual ~ControllerDataProvider() {}
+ // Returns data pointer or nullptr. If pointer is valid, call to
+ // UnlockControllerData is required.
+ virtual const void* LockControllerData() = 0;
+ virtual void UnlockControllerData() = 0;
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // VR_WINDOW_MANAGER_CONTROLLER_DATA_PROVIDER_H_
\ No newline at end of file
#include "hwc_callback.h"
-#include <gralloc_priv.h>
#include <android-base/unique_fd.h>
#include <log/log.h>
#include <private/dvr/native_buffer.h>
#include <sync/sync.h>
+#include <ui/GraphicBufferMapper.h>
namespace android {
namespace dvr {
namespace {
sp<GraphicBuffer> GetBufferFromHandle(const native_handle_t* handle) {
- // TODO(dnicoara): Fix this once gralloc1 is available.
- private_handle_t* private_handle = private_handle_t::dynamicCast(handle);
+ uint32_t width = 0, height = 0, stride = 0, layer_count = 1;
+ uint64_t producer_usage = 0, consumer_usage = 0;
+ int32_t format = 0;
+
+ GraphicBufferMapper& mapper = GraphicBufferMapper::get();
+ if (mapper.getDimensions(handle, &width, &height) ||
+ mapper.getStride(handle, &stride) ||
+ mapper.getFormat(handle, &format) ||
+ mapper.getProducerUsage(handle, &producer_usage) ||
+ mapper.getConsumerUsage(handle, &consumer_usage)) {
+ ALOGE("Failed to read handle properties");
+ return nullptr;
+ }
+
+ // This will only succeed if gralloc has GRALLOC1_CAPABILITY_LAYERED_BUFFERS
+ // capability. Otherwise assume a count of 1.
+ mapper.getLayerCount(handle, &layer_count);
+
sp<GraphicBuffer> buffer = new GraphicBuffer(
- private_handle->width, private_handle->height, private_handle->format, 1,
- GraphicBuffer::USAGE_HW_COMPOSER | GraphicBuffer::USAGE_HW_TEXTURE |
- GraphicBuffer::USAGE_HW_2D | GraphicBuffer::USAGE_HW_RENDER,
- private_handle->width, native_handle_clone(handle), true);
- if (GraphicBufferMapper::get().registerBuffer(buffer.get()) != OK) {
+ width, height, format, layer_count, producer_usage, consumer_usage,
+ stride, native_handle_clone(handle), true);
+ if (mapper.registerBuffer(buffer.get()) != OK) {
ALOGE("Failed to register buffer");
return nullptr;
}
}
std::lock_guard<std::mutex> guard(mutex_);
- if (client_)
- client_->OnFrame(std::make_unique<Frame>(std::move(hwc_frame)));
+ client_->OnFrame(std::make_unique<Frame>(std::move(hwc_frame)));
return Void();
}
jobject android_context = env->NewLocalRef(android_context_global_ref_);
int init_result = shell_view_.Initialize(env, android_context, class_loader);
- init_result += shell_view_.AllocateResources();
init_result_promise->set_value(init_result);
if (init_result == 0) {
while (!quit_)
namespace {
+constexpr float kLayerScaleFactor = 4.0f;
+
constexpr unsigned int kVRAppLayerCount = 2;
constexpr unsigned int kMaximumPendingFrames = 8;
else
xscale = ar;
+ xscale *= kLayerScaleFactor;
+ yscale *= kLayerScaleFactor;
+
return mat4(Eigen::Scaling<float>(xscale, yscale, 1.0));
}
m(3, 0) = 0.0f; m(3, 1) = 0.0f; m(3, 2) = 0.0f; m(3, 3) = 1.0f;
// clang-format on
- return m;
+ return m * Eigen::AngleAxisf(M_PI * 0.5f, vec3::UnitZ());
}
// Helper function that applies the crop transform to the texture layer and
return layer_transform;
}
-vec3 FromGvrVec3f(const gvr_vec3f& vec3f) {
- return vec3(vec3f.x, vec3f.y, vec3f.z);
-}
-
-quat FromGvrQuatf(const gvr_quatf& quaternion) {
- return quat(quaternion.qw, quaternion.qx, quaternion.qy, quaternion.qz);
-}
-
// Determine if ths frame should be shown or hidden.
-bool CalculateVisibilityFromLayerConfig(const HwcCallback::Frame& frame,
- uint32_t vr_app) {
+ViewMode CalculateVisibilityFromLayerConfig(const HwcCallback::Frame& frame,
+ uint32_t vr_app) {
auto& layers = frame.layers();
// We assume the first two layers are the VR app.
if (layers.size() < kVRAppLayerCount)
- return false;
+ return ViewMode::Hidden;
- if (vr_app != layers[0].appid || layers[0].appid == 0)
- return false;
+ if (vr_app != layers[0].appid || layers[0].appid == 0 ||
+ layers[1].appid != layers[0].appid) {
+ if (layers[1].appid != layers[0].appid && layers[0].appid) {
+ // This might be a 2D app.
+ return ViewMode::App;
+ }
+ return ViewMode::Hidden;
+ }
// If a non-VR-app, non-skipped layer appears, show.
size_t index = kVRAppLayerCount;
// If any non-skipped layers exist now then we show, otherwise hide.
for (size_t i = index; i < layers.size(); i++) {
if (!layers[i].should_skip_layer())
- return true;
+ return ViewMode::VR;
}
- return false;
+ return ViewMode::Hidden;
}
+
} // namespace
ShellView::ShellView() {
if (!InitializeTouch())
ALOGE("Failed to initialize virtual touchpad");
+ surface_flinger_view_.reset(new SurfaceFlingerView);
+ if (!surface_flinger_view_->Initialize(this))
+ return 1;
+
return 0;
}
if (!program_ || !overlay_program_ || !controller_program_)
return 1;
- surface_flinger_view_.reset(new SurfaceFlingerView);
- if (!surface_flinger_view_->Initialize(this))
- return 1;
-
reticle_.reset(new Reticle());
if (!reticle_->Initialize())
return 1;
}
void ShellView::EnableDebug(bool debug) {
+ ALOGI("EnableDebug(%d)", (int)debug); // XXX TODO delete
QueueTask(debug ? MainThreadTask::EnableDebugMode
: MainThreadTask::DisableDebugMode);
}
void ShellView::VrMode(bool mode) {
+ ALOGI("VrMode(%d)", (int)mode); // XXX TODO delete
QueueTask(mode ? MainThreadTask::EnteringVrMode
: MainThreadTask::ExitingVrMode);
}
+void ShellView::dumpInternal(String8& result) {
+ result.append("[shell]\n");
+ result.appendFormat("initialized = %s\n", initialized_ ? "true" : "false");
+ result.appendFormat("is_visible = %s\n", is_visible_ ? "true" : "false");
+ result.appendFormat("debug_mode = %s\n\n", debug_mode_ ? "true" : "false");
+}
+
+void ShellView::AdvanceFrame() {
+ if (!pending_frames_.empty()) {
+ // Check if we should advance the frame.
+ auto& frame = pending_frames_.front();
+ if (frame.visibility == ViewMode::Hidden ||
+ frame.frame->Finish() == HwcCallback::FrameStatus::kFinished) {
+ current_frame_ = std::move(frame);
+ pending_frames_.pop_front();
+
+ for(int i = 0; i < skipped_frame_count_ + 1; i++)
+ surface_flinger_view_->ReleaseFrame();
+ skipped_frame_count_ = 0;
+ }
+ }
+}
+
void ShellView::OnDrawFrame() {
textures_.clear();
has_ime_ = false;
{
std::unique_lock<std::mutex> l(pending_frame_mutex_);
- if (!pending_frames_.empty()) {
- // Check if we should advance the frame.
- auto& frame = pending_frames_.front();
- if (!frame.visibility ||
- frame.frame->Finish() == HwcCallback::FrameStatus::kFinished) {
- current_frame_ = std::move(frame);
- pending_frames_.pop_front();
- }
- }
+ AdvanceFrame();
}
- if (!debug_mode_ && current_frame_.visibility != is_visible_) {
- SetVisibility(current_frame_.visibility);
+ bool visible = current_frame_.visibility != ViewMode::Hidden;
+
+ if (!debug_mode_ && visible != is_visible_) {
+ SetVisibility(current_frame_.visibility != ViewMode::Hidden);
}
- if (!current_frame_.visibility)
+ if (!debug_mode_ && !visible)
return;
ime_texture_ = TextureLayer();
surface_flinger_view_->GetTextures(*current_frame_.frame.get(), &textures_,
- &ime_texture_, debug_mode_);
+ &ime_texture_, debug_mode_,
+ current_frame_.visibility == ViewMode::VR);
has_ime_ = ime_texture_.texture != nullptr;
}
}
void ShellView::OnFrame(std::unique_ptr<HwcCallback::Frame> frame) {
- if (!frame || frame->layers().empty())
- return;
-
- bool visibility = debug_mode_ || CalculateVisibilityFromLayerConfig(
- *frame.get(), current_vr_app_);
- current_vr_app_ = frame->layers().front().appid;
+ ViewMode visibility =
+ CalculateVisibilityFromLayerConfig(*frame.get(), current_vr_app_);
- // If we are not showing the frame there's no need to keep anything around.
- if (!visibility) {
- // Hidden, no change so drop it completely
- if (!current_frame_.visibility)
- return;
+ if (visibility == ViewMode::Hidden && debug_mode_)
+ visibility = ViewMode::VR;
- frame.reset(nullptr);
- }
+ if (frame->layers().empty())
+ current_vr_app_ = 0;
+ else
+ current_vr_app_ = frame->layers().front().appid;
std::unique_lock<std::mutex> l(pending_frame_mutex_);
pending_frames_.emplace_back(std::move(frame), visibility);
- if (pending_frames_.size() > kMaximumPendingFrames)
+ if (pending_frames_.size() > kMaximumPendingFrames) {
+ skipped_frame_count_++;
pending_frames_.pop_front();
+ }
+
+ if (visibility == ViewMode::Hidden &&
+ current_frame_.visibility == ViewMode::Hidden) {
+ // Consume all frames while hidden.
+ while (!pending_frames_.empty())
+ AdvanceFrame();
+ }
// If we are showing ourselves the main thread is not processing anything,
// so give it a kick.
- if (visibility && !current_frame_.visibility)
+ if (visibility != ViewMode::Hidden &&
+ current_frame_.visibility == ViewMode::Hidden) {
+ QueueTask(MainThreadTask::EnteringVrMode);
QueueTask(MainThreadTask::Show);
+ }
}
bool ShellView::IsHit(const vec3& view_location, const vec3& view_direction,
vec3 pointer_location = last_pose_.GetPosition();
quat view_quaternion = last_pose_.GetRotation();
- if (controller_ && controller_api_status_ == gvr::kControllerApiOk) {
- view_quaternion = FromGvrQuatf(controller_orientation_);
+ bool gvr_api_active =
+ controller_ && controller_api_status_ == gvr::kControllerApiOk;
+
+ if (gvr_api_active || shmem_controller_active_) {
+ view_quaternion = controller_orientation_;
vec4 controller_location = controller_translate_ * vec4(0, 0, 0, 1);
pointer_location = vec3(controller_location.x(), controller_location.y(),
controller_location.z());
- if (controller_state_->GetButtonDown(gvr::kControllerButtonClick))
- OnClick(true);
+ if (shmem_controller_active_) {
+ uint64_t buttons = shmem_controller_buttons_;
+ shmem_controller_buttons_ = 0;
+ while (buttons) {
+ switch (buttons & 0xF) {
+ case 0x1:
+ OnClick(false);
+ break;
+ case 0x3:
+ OnTouchpadButton(false, AMOTION_EVENT_BUTTON_BACK);
+ break;
+ case 0x9:
+ OnClick(true);
+ break;
+ case 0xB:
+ OnTouchpadButton(true, AMOTION_EVENT_BUTTON_BACK);
+ break;
+ default:
+ break;
+ }
+ buttons >>= 4;
+ }
+ } else if (controller_) {
+ if (controller_state_->GetButtonDown(gvr::kControllerButtonClick))
+ OnClick(true);
- if (controller_state_->GetButtonUp(gvr::kControllerButtonClick))
- OnClick(false);
+ if (controller_state_->GetButtonUp(gvr::kControllerButtonClick))
+ OnClick(false);
- if (controller_state_->GetButtonDown(gvr::kControllerButtonApp))
- OnTouchpadButton(true, AMOTION_EVENT_BUTTON_BACK);
+ if (controller_state_->GetButtonDown(gvr::kControllerButtonApp))
+ OnTouchpadButton(true, AMOTION_EVENT_BUTTON_BACK);
- if (controller_state_->GetButtonUp(gvr::kControllerButtonApp))
- OnTouchpadButton(false, AMOTION_EVENT_BUTTON_BACK);
+ if (controller_state_->GetButtonUp(gvr::kControllerButtonApp))
+ OnTouchpadButton(false, AMOTION_EVENT_BUTTON_BACK);
+ }
}
vec3 view_direction = vec3(view_quaternion * vec3(0, 0, -1));
void ShellView::DrawController(const mat4& perspective, const mat4& eye_matrix,
const mat4& head_matrix) {
- if (!controller_)
+ if (!controller_ && !shmem_controller_active_)
return;
controller_program_->Use();
controller_program_->GetProgram(), "uViewProjection");
glUniformMatrix4fv(view_projection_location, 1, 0, mvp.data());
- quat view_quaternion = FromGvrQuatf(controller_orientation_);
+ quat view_quaternion = controller_orientation_;
view_quaternion.toRotationMatrix();
vec3 world_pos = last_pose_.GetPosition() + controller_position_;
#include "application.h"
#include "reticle.h"
+#include "shell_view_binder_interface.h"
#include "surface_flinger_view.h"
namespace android {
namespace dvr {
-class ShellView : public Application, public HwcCallback::Client {
+enum class ViewMode {
+ Hidden,
+ VR,
+ App,
+};
+
+class ShellView : public Application,
+ public android::dvr::ShellViewBinderInterface,
+ public HwcCallback::Client {
public:
ShellView();
virtual ~ShellView();
int AllocateResources() override;
void DeallocateResources() override;
- void EnableDebug(bool debug);
- void VrMode(bool mode);
+ // ShellViewBinderInterface:
+ void EnableDebug(bool debug) override;
+ void VrMode(bool mode) override;
+ void dumpInternal(String8& result) override;
protected:
void DrawEye(EyeType eye, const mat4& perspective, const mat4& eye_matrix,
bool OnClick(bool down);
+ void AdvanceFrame();
+
// HwcCallback::Client:
void OnFrame(std::unique_ptr<HwcCallback::Frame> frame) override;
std::unique_ptr<ShaderProgram> overlay_program_;
std::unique_ptr<ShaderProgram> controller_program_;
+ // This starts at -1 so we don't call ReleaseFrame for the first frame.
+ int skipped_frame_count_ = -1;
+
uint32_t current_vr_app_;
// Used to center the scene when the shell becomes visible.
struct PendingFrame {
PendingFrame() = default;
- PendingFrame(std::unique_ptr<HwcCallback::Frame>&& frame, bool visibility)
+ PendingFrame(std::unique_ptr<HwcCallback::Frame>&& frame, ViewMode visibility)
: frame(std::move(frame)), visibility(visibility) {}
PendingFrame(PendingFrame&& r)
: frame(std::move(r.frame)), visibility(r.visibility) {}
}
std::unique_ptr<HwcCallback::Frame> frame;
- bool visibility = false;
+ ViewMode visibility = ViewMode::Hidden;
};
std::deque<PendingFrame> pending_frames_;
std::mutex pending_frame_mutex_;
--- /dev/null
+#ifndef VR_WINDOW_MANAGER_SHELL_VIEWBINDER_INTERFACE_H_
+#define VR_WINDOW_MANAGER_SHELL_VIEWBINDER_INTERFACE_H_
+
+namespace android {
+namespace dvr {
+
+class ShellViewBinderInterface {
+ public:
+ ShellViewBinderInterface() {};
+ virtual ~ShellViewBinderInterface() {};
+
+ virtual void EnableDebug(bool debug) = 0;
+ virtual void VrMode(bool mode) = 0;
+ virtual void dumpInternal(String8& result) = 0;
+};
+
+} // namespace dvr
+} // namespace android
+
+#endif // VR_WINDOW_MANAGER_SHELL_VIEWBINDER_INTERFACE_H_
bool SurfaceFlingerView::GetTextures(const HwcCallback::Frame& frame,
std::vector<TextureLayer>* texture_layers,
TextureLayer* ime_layer,
- bool debug) const {
+ bool debug, bool skip_first_layer) const {
auto& layers = frame.layers();
texture_layers->clear();
size_t start = 0;
// Skip the second layer if it is from the VR app.
- if (!debug) {
+ if (!debug && skip_first_layer) {
start = 1;
if (layers[0].appid && layers[0].appid == layers[1].appid)
start = 2;
return true;
}
+void SurfaceFlingerView::ReleaseFrame() {
+ composer_service_->releaseFrame();
+}
+
} // namespace dvr
} // namespace android
bool GetTextures(const HwcCallback::Frame& layers,
std::vector<TextureLayer>* texture_layers,
- TextureLayer* ime_layer, bool debug) const;
+ TextureLayer* ime_layer, bool debug,
+ bool skip_first_layer) const;
+
+ void ReleaseFrame();
private:
sp<IVrComposerView> composer_service_;
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include "shell_view.h"
+#include "vr_window_manager_binder.h"
int main(int /* argc */, char** /* argv */) {
+ android::dvr::ShellView app;
+ const int app_status = app.Initialize(nullptr, nullptr, nullptr);
+ LOG_ALWAYS_FATAL_IF(app_status != 0, "failed to initialize: %d", app_status);
+
+ android::service::vr::VrWindowManagerBinder service(app);
+ const int status = service.Initialize();
+ LOG_ALWAYS_FATAL_IF(status != 0, "initialization failed: %d", status);
+
android::ProcessState::self()->startThreadPool();
- android::dvr::ShellView app;
- if (app.Initialize(nullptr, nullptr, nullptr)) {
- ALOGE("Failed to initialize");
- return 1;
- }
+ android::sp<android::IServiceManager> sm(android::defaultServiceManager());
+ const android::status_t service_status = sm->addService(
+ android::service::vr::VrWindowManagerBinder::SERVICE_NAME(), &service,
+ false /*allowIsolated*/);
+ LOG_ALWAYS_FATAL_IF(service_status != android::OK, "service not added: %d",
+ static_cast<int>(service_status));
- if (app.AllocateResources()) {
- ALOGE("Failed to allocate resources");
- return 1;
- }
+ app.SetControllerDataProvider(&service);
while (true)
app.DrawFrame();
+ android::IPCThreadState::self()->joinThreadPool();
return 0;
}
--- /dev/null
+#include "vr_window_manager_binder.h"
+
+#include <inttypes.h>
+#include <sys/mman.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/PermissionCache.h>
+#include <binder/Status.h>
+#include <cutils/log.h>
+#include <private/android_filesystem_config.h>
+#include <utils/Errors.h>
+
+namespace android {
+namespace service {
+namespace vr {
+
+namespace {
+const String16 kDumpPermission("android.permission.DUMP");
+const String16 kSendMeControllerInputPermission("TODO"); // TODO(kpschoedel)
+} // anonymous namespace
+
+constexpr size_t AshmemControllerDataProvider::kRegionLength;
+
+status_t AshmemControllerDataProvider::Connect(const int in_fd) {
+ if (in_fd < 0) {
+ return BAD_VALUE;
+ }
+ if (fd_.get() >= 0) {
+ // The VrCore is dead. Long live the VrCore.
+ Disconnect();
+ }
+ void* const shared_region =
+ ::mmap(nullptr, kRegionLength, PROT_READ, MAP_SHARED, in_fd, 0);
+ if (shared_region == MAP_FAILED) {
+ shared_region_ = nullptr;
+ return NO_MEMORY;
+ }
+
+ errno = 0;
+ const int fd = ::fcntl(in_fd, F_DUPFD_CLOEXEC, 0);
+ if (fd < 0) {
+ ::munmap(shared_region, kRegionLength);
+ return -errno;
+ }
+ fd_.reset(fd);
+ ALOGI("controller connected %d -> %d @ %p", in_fd, fd, shared_region);
+
+ std::lock_guard<std::mutex> guard(mutex_);
+ shared_region_ = shared_region;
+ return OK;
+}
+
+status_t AshmemControllerDataProvider::Disconnect() {
+ if (shared_region_ == nullptr || fd_.get() < 0) {
+ return INVALID_OPERATION;
+ }
+ std::lock_guard<std::mutex> guard(mutex_);
+ ::munmap(shared_region_, kRegionLength);
+ shared_region_ = nullptr;
+ fd_.reset();
+ ALOGI("controller disconnected");
+ return OK;
+}
+
+const void* AshmemControllerDataProvider::LockControllerData() {
+ mutex_.lock();
+ if (!shared_region_) {
+ mutex_.unlock();
+ return nullptr;
+ }
+ return shared_region_;
+}
+
+void AshmemControllerDataProvider::UnlockControllerData() { mutex_.unlock(); }
+
+void AshmemControllerDataProvider::dumpInternal(String8& result) {
+ result.appendFormat("[controller]\nfd = %d\n", fd_.get());
+ if (shared_region_) {
+ int32_t* p = reinterpret_cast<int32_t*>(shared_region_);
+ result.appendFormat("header = ");
+ for (int i = 0; i < 8; ++i) {
+ result.appendFormat("%c 0x%08" PRIX32, i ? ',' : '[', p[i]);
+ }
+ result.appendFormat(" ]\n\n");
+ }
+}
+
+int VrWindowManagerBinder::Initialize() { return 0; }
+
+binder::Status VrWindowManagerBinder::connectController(
+ const ::android::base::unique_fd& in_fd) {
+ // TODO(kpschoedel): check permission
+#if 0
+ int32_t pid, uid;
+ if (!PermissionCache::checkCallingPermission(kSendMeControllerInputPermission,
+ &pid, &uid)) {
+ ALOGE("permission denied to pid=%" PRId32 " uid=%" PRId32, pid, uid);
+ return binder::Status::fromStatusT(PERMISSION_DENIED);
+ }
+#endif
+ return binder::Status::fromStatusT(Connect(in_fd.get()));
+}
+
+binder::Status VrWindowManagerBinder::disconnectController() {
+ // TODO(kpschoedel): check permission
+#if 0
+ int32_t pid, uid;
+ if (!PermissionCache::checkCallingPermission(kSendMeControllerInputPermission,
+ &pid, &uid)) {
+ ALOGE("permission denied to pid=%" PRId32 " uid=%" PRId32, pid, uid);
+ return binder::Status::fromStatusT(PERMISSION_DENIED);
+ }
+#endif
+ return binder::Status::fromStatusT(Disconnect());
+}
+
+binder::Status VrWindowManagerBinder::enterVrMode() {
+ // TODO(kpschoedel): check permission
+ app_.VrMode(true);
+ return binder::Status::ok();
+}
+
+binder::Status VrWindowManagerBinder::exitVrMode() {
+ // TODO(kpschoedel): check permission
+ app_.VrMode(false);
+ return binder::Status::ok();
+}
+
+binder::Status VrWindowManagerBinder::setDebugMode(int32_t mode) {
+ // TODO(kpschoedel): check permission
+ app_.EnableDebug(static_cast<bool>(mode));
+ return binder::Status::ok();
+}
+
+status_t VrWindowManagerBinder::dump(
+ int fd, const Vector<String16>& args [[gnu::unused]]) {
+ String8 result;
+ const android::IPCThreadState* ipc = android::IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ if ((uid != AID_SHELL) &&
+ !PermissionCache::checkPermission(kDumpPermission, pid, uid)) {
+ result.appendFormat("Permission denial: can't dump " LOG_TAG
+ " from pid=%d, uid=%d\n",
+ pid, uid);
+ } else {
+ app_.dumpInternal(result);
+ AshmemControllerDataProvider::dumpInternal(result);
+ }
+ write(fd, result.string(), result.size());
+ return OK;
+}
+
+} // namespace vr
+} // namespace service
+} // namespace android
--- /dev/null
+#ifndef VR_WINDOW_MANAGER_VR_WINDOW_MANAGER_BINDER_H_
+#define VR_WINDOW_MANAGER_VR_WINDOW_MANAGER_BINDER_H_
+
+#include <android/service/vr/BnVrWindowManager.h>
+
+#include <mutex>
+
+#include "controller_data_provider.h"
+#include "shell_view_binder_interface.h"
+
+namespace android {
+namespace service {
+namespace vr {
+
+class AshmemControllerDataProvider : public dvr::ControllerDataProvider {
+ public:
+ AshmemControllerDataProvider() {}
+ virtual ~AshmemControllerDataProvider() {}
+
+ status_t Connect(int fd);
+ status_t Disconnect();
+
+ // ControllerDataProvider:
+ const void* LockControllerData() override;
+ void UnlockControllerData() override;
+
+ protected:
+ void dumpInternal(String8& result);
+
+ private:
+ static constexpr size_t kRegionLength = 8192; // TODO(kpschoedel)
+ ::android::base::unique_fd fd_;
+
+ // Mutex for guarding shared_region_.
+ std::mutex mutex_;
+ void* shared_region_ = nullptr;
+
+ AshmemControllerDataProvider(const AshmemControllerDataProvider&) = delete;
+ void operator=(const AshmemControllerDataProvider&) = delete;
+};
+
+class VrWindowManagerBinder : public BnVrWindowManager,
+ public AshmemControllerDataProvider {
+ public:
+ VrWindowManagerBinder(android::dvr::ShellViewBinderInterface& app)
+ : app_(app) {}
+ virtual ~VrWindowManagerBinder() {}
+
+ // Must be called before clients can connect.
+ // Returns 0 if initialization is successful.
+ int Initialize();
+ static char const* getServiceName() { return "vr_window_manager"; }
+
+ protected:
+ // Implements IVrWindowManagerBinder.
+ ::android::binder::Status connectController(
+ const ::android::base::unique_fd& fd) override;
+ ::android::binder::Status disconnectController() override;
+ ::android::binder::Status enterVrMode() override;
+ ::android::binder::Status exitVrMode() override;
+ ::android::binder::Status setDebugMode(int32_t mode) override;
+
+ // Implements BBinder::dump().
+ status_t dump(int fd, const Vector<String16>& args) override;
+
+ private:
+ android::dvr::ShellViewBinderInterface& app_;
+
+ VrWindowManagerBinder(const VrWindowManagerBinder&) = delete;
+ void operator=(const VrWindowManagerBinder&) = delete;
+};
+
+} // namespace vr
+} // namespace service
+} // namespace android
+
+#endif // VR_WINDOW_MANAGER_VR_WINDOW_MANAGER_BINDER_H_
--- /dev/null
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <cutils/log.h>
+
+#include "vr_window_manager_binder.h"
+
+int main() {
+ ALOGI("Starting");
+ android::service::vr::VrWindowManagerBinder service;
+ const int status = service.Initialize();
+ LOG_ALWAYS_FATAL_IF(status != 0, "initialization failed: %d", status);
+
+ signal(SIGPIPE, SIG_IGN);
+ android::sp<android::ProcessState> ps(android::ProcessState::self());
+ ps->setThreadPoolMaxThreadCount(4);
+ ps->startThreadPool();
+ ps->giveThreadPoolName();
+
+ android::sp<android::IServiceManager> sm(android::defaultServiceManager());
+ const android::status_t service_status = sm->addService(
+ android::service::vr::VrWindowManagerBinder::SERVICE_NAME(), &service,
+ false /*allowIsolated*/);
+ LOG_ALWAYS_FATAL_IF(service_status != android::OK, "service not added: %d",
+ static_cast<int>(service_status));
+
+ android::IPCThreadState::self()->joinThreadPool();
+ return 0;
+}
--- /dev/null
+#include <android/service/vr/BpVrWindowManager.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <inttypes.h>
+
+void usage() { fprintf(stderr, "usage: vr_wm_ctl [enter|exit|debug N]\n"); }
+
+int report(const android::binder::Status& status) {
+ if (status.isOk()) {
+ fprintf(stderr, "ok\n");
+ return 0;
+ }
+ fprintf(stderr, "failed (%" PRId32 ") %s\n", status.exceptionCode(),
+ status.exceptionMessage().string());
+ return (int)status.exceptionCode();
+}
+
+int main(int argc, char* argv[]) {
+ android::sp<android::IServiceManager> sm(android::defaultServiceManager());
+ if (sm == nullptr) {
+ fprintf(stderr, "service manager not found\n");
+ exit(1);
+ }
+
+ android::sp<android::service::vr::IVrWindowManager> vrwm =
+ android::interface_cast<android::service::vr::IVrWindowManager>(
+ sm->getService(
+ android::service::vr::IVrWindowManager::SERVICE_NAME()));
+ if (vrwm == nullptr) {
+ fprintf(stderr, "service not found\n");
+ exit(1);
+ }
+
+ android::binder::Status status;
+ if ((argc == 2) && (strcmp(argv[1], "enter") == 0)) {
+ exit(report(vrwm->enterVrMode()));
+ } else if ((argc == 2) && (strcmp(argv[1], "exit") == 0)) {
+ exit(report(vrwm->exitVrMode()));
+ } else if ((argc == 3) && (strcmp(argv[1], "debug") == 0)) {
+ exit(report(vrwm->setDebugMode(atoi(argv[2]))));
+ } else {
+ usage();
+ exit(2);
+ }
+
+ return 0;
+}
platform.HWND hwnd
}
+@internal class Gralloc1Usage {
+ u64 consumer
+ u64 producer
+}
+
@extension("VK_ANDROID_native_buffer")
class VkNativeBufferANDROID {
VkStructureType sType
const void* pNext
platform.buffer_handle_t handle
- int stride
- int format
- int usage
+ s32 stride
+ s32 format
+ s32 usage
+ Gralloc1Usage usage2
}
@extension("VK_ANDROID_native_buffer")
}
@extension("VK_ANDROID_native_buffer")
+@optional
cmd VkResult vkGetSwapchainGrallocUsageANDROID(
VkDevice device,
VkFormat format,
VkImageUsageFlags imageUsage,
- int* grallocUsage) {
+ s32* grallocUsage) {
return ?
}
@extension("VK_ANDROID_native_buffer")
+@optional
cmd VkResult vkGetSwapchainGrallocUsage2ANDROID(
VkDevice device,
VkFormat format,
VkImageUsageFlags imageUsage,
VkSwapchainImageUsageFlagsANDROID swapchainImageUsage,
- int* grallocUsage) {
+ u64* grallocConsumerUsage,
+ u64* grallocProducerUsage) {
return ?
}
The +vk_wsi_swapchin+ and +vk_wsi_device_swapchain+ extensions are primarily be implemented by the platform and live in +libvulkan.so+. The +VkSwapchain+ object and all interaction with +ANativeWindow+ will be handled by the platform and not exposed to drivers. The WSI implementation will rely on a few private interfaces to the driver for this implementation. These will be loaded through the driver's +vkGetDeviceProcAddr+ functions, after passing through any enabled layers.
-Implementations may need swapchain buffers to be allocated with implementation-defined private gralloc usage flags. When creating a swapchain, the platform will ask the driver to translate the requested format and image usage flags into gralloc usage flags by calling
-[source,c]
-----
-VkResult VKAPI vkGetSwapchainGrallocUsageANDROID(
- VkDevice device,
- VkFormat format,
- VkImageUsageFlags imageUsage,
- int* grallocUsage
-);
-----
-The +format+ and +imageUsage+ parameters are taken from the +VkSwapchainCreateInfoKHR+ structure. The driver should fill +*grallocUsage+ with the gralloc usage flags it requires for that format and usage. These will be combined with the usage flags requested by the swapchain consumer when allocating buffers.
-
-Implementations may further need swapchain buffers to be allocated with implementation-defined private gralloc usage flags that depend not only on +format+ and +imageUsage+, but also on the intended usage of the swapchain. The additional usage bits are defined as
+Implementations may need swapchain buffers to be allocated with implementation-defined private gralloc usage flags that depend not only on +format+ and +imageUsage+, but also on the intended usage of the swapchain. The swapchain usage bits are defined as
[source,c]
----
typedef enum VkSwapchainImageUsageFlagBitsANDROID {
typedef VkFlags VkSwapchainImageUsageFlagsANDROID;
----
-If the driver provides the +vkGetSwapchainGrallocUsage2ANDROID+ function, the platform will use it in preference to +vkGetSwapchainGrallocUsageANDROID+ when translating a requested format, image usage flags, and swapchain image usage flags into gralloc usage flags. +vkGetSwapchainGrallocUsage2ANDROID+ behaves in the same way as +vkGetSwapchainGrallocUsageANDROID+, and is declared as
+Implementations may need swapchain buffers to be allocated with implementation-defined private gralloc usage flags. When creating a swapchain, the platform will ask the driver to translate the requested format and image usage flags into gralloc usage flags by calling
[source,c]
----
VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainGrallocUsage2ANDROID(
VkFormat format,
VkImageUsageFlags imageUsage,
VkSwapchainImageUsageFlagsANDROID swapchainImageUsage,
+ uint64_t* grallocConsumerUsage,
+ uint64_t* grallocProducerUsage,
+);
+----
+The +format+ and +imageUsage+ parameters are taken from the +VkSwapchainCreateInfoKHR+ structure. The driver should fill +*grallocConsumerUsage+ and +*grallocProducerUsage+ with the gralloc usage flags it requires for that format and usage. These will be combined with the usage flags requested by the swapchain consumer when allocating buffers.
+
+An older version of this function is deprecated but still supported for backwards compatibility; it will be used if +vkGetSwapchainGrallocUsage2ANDROID+ is not supported:
+[source,c]
+----
+VkResult VKAPI vkGetSwapchainGrallocUsageANDROID(
+ VkDevice device,
+ VkFormat format,
+ VkImageUsageFlags imageUsage,
int* grallocUsage
);
----
// Gralloc format and usage requested when the buffer was allocated.
int format;
- int usage;
+ int usage; // deprecated
+ struct {
+ uint64_t consumer;
+ uint64_t producer;
+ } usage2;
} VkNativeBufferANDROID;
----
* Added VkSwapchainImageUsageFlagBitsANDROID
* Added vkGetSwapchainGrallocUsage2ANDROID
* Added VkSwapchainImageCreateInfoANDROID
+. *2017-02-09*
+ * Extended vkGetSwapchainGrallocUsage2ANDROID and VkNativeBufferANDROID to use gralloc1-style usage bitfields.
\ No newline at end of file
/*]]>*/
</script>
</head>
-<body class="article">
+<body class="book">
<div id="header">
<h1>Vulkan on Android Implementor’s Guide</h1>
<span id="revnumber">version 5</span>
<h2 id="_window_system_integration">2. Window System Integration</h2>
<div class="sectionbody">
<div class="paragraph"><p>The <span class="monospaced">vk_wsi_swapchin</span> and <span class="monospaced">vk_wsi_device_swapchain</span> extensions are primarily be implemented by the platform and live in <span class="monospaced">libvulkan.so</span>. The <span class="monospaced">VkSwapchain</span> object and all interaction with <span class="monospaced">ANativeWindow</span> will be handled by the platform and not exposed to drivers. The WSI implementation will rely on a few private interfaces to the driver for this implementation. These will be loaded through the driver’s <span class="monospaced">vkGetDeviceProcAddr</span> functions, after passing through any enabled layers.</p></div>
-<div class="paragraph"><p>Implementations may need swapchain buffers to be allocated with implementation-defined private gralloc usage flags. When creating a swapchain, the platform will ask the driver to translate the requested format and image usage flags into gralloc usage flags by calling</p></div>
-<div class="listingblock">
-<div class="content"><!-- Generator: GNU source-highlight 3.1.6
-by Lorenzo Bettini
-http://www.lorenzobettini.it
-http://www.gnu.org/software/src-highlite -->
-<pre><tt>VkResult <span style="color: #008080">VKAPI</span> <span style="font-weight: bold"><span style="color: #000000">vkGetSwapchainGrallocUsageANDROID</span></span><span style="color: #990000">(</span>
- <span style="color: #008080">VkDevice</span> device<span style="color: #990000">,</span>
- <span style="color: #008080">VkFormat</span> format<span style="color: #990000">,</span>
- <span style="color: #008080">VkImageUsageFlags</span> imageUsage<span style="color: #990000">,</span>
- <span style="color: #009900">int</span><span style="color: #990000">*</span> grallocUsage
-<span style="color: #990000">);</span></tt></pre></div></div>
-<div class="paragraph"><p>The <span class="monospaced">format</span> and <span class="monospaced">imageUsage</span> parameters are taken from the <span class="monospaced">VkSwapchainCreateInfoKHR</span> structure. The driver should fill <span class="monospaced">*grallocUsage</span> with the gralloc usage flags it requires for that format and usage. These will be combined with the usage flags requested by the swapchain consumer when allocating buffers.</p></div>
-<div class="paragraph"><p>Implementations may further need swapchain buffers to be allocated with implementation-defined private gralloc usage flags that depend not only on <span class="monospaced">format</span> and <span class="monospaced">imageUsage</span>, but also on the intended usage of the swapchain. The additional usage bits are defined as</p></div>
+<div class="paragraph"><p>Implementations may need swapchain buffers to be allocated with implementation-defined private gralloc usage flags that depend not only on <span class="monospaced">format</span> and <span class="monospaced">imageUsage</span>, but also on the intended usage of the swapchain. The swapchain usage bits are defined as</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 3.1.6
by Lorenzo Bettini
VK_SWAPCHAIN_IMAGE_USAGE_FLAG_BITS_MAX_ENUM <span style="color: #990000">=</span> <span style="color: #993399">0x7FFFFFFF</span>
<span style="color: #FF0000">}</span> VkSwapchainImageUsageFlagBitsANDROID<span style="color: #990000">;</span>
<span style="font-weight: bold"><span style="color: #0000FF">typedef</span></span> <span style="color: #008080">VkFlags</span> VkSwapchainImageUsageFlagsANDROID<span style="color: #990000">;</span></tt></pre></div></div>
-<div class="paragraph"><p>If the driver provides the <span class="monospaced">vkGetSwapchainGrallocUsage2ANDROID</span> function, the platform will use it in preference to <span class="monospaced">vkGetSwapchainGrallocUsageANDROID</span> when translating a requested format, image usage flags, and swapchain image usage flags into gralloc usage flags. <span class="monospaced">vkGetSwapchainGrallocUsage2ANDROID</span> behaves in the same way as <span class="monospaced">vkGetSwapchainGrallocUsageANDROID</span>, and is declared as</p></div>
+<div class="paragraph"><p>Implementations may need swapchain buffers to be allocated with implementation-defined private gralloc usage flags. When creating a swapchain, the platform will ask the driver to translate the requested format and image usage flags into gralloc usage flags by calling</p></div>
<div class="listingblock">
<div class="content"><!-- Generator: GNU source-highlight 3.1.6
by Lorenzo Bettini
<span style="color: #008080">VkFormat</span> format<span style="color: #990000">,</span>
<span style="color: #008080">VkImageUsageFlags</span> imageUsage<span style="color: #990000">,</span>
<span style="color: #008080">VkSwapchainImageUsageFlagsANDROID</span> swapchainImageUsage<span style="color: #990000">,</span>
+ uint64_t<span style="color: #990000">*</span> grallocConsumerUsage<span style="color: #990000">,</span>
+ uint64_t<span style="color: #990000">*</span> grallocProducerUsage<span style="color: #990000">,</span>
+<span style="color: #990000">);</span></tt></pre></div></div>
+<div class="paragraph"><p>The <span class="monospaced">format</span> and <span class="monospaced">imageUsage</span> parameters are taken from the <span class="monospaced">VkSwapchainCreateInfoKHR</span> structure. The driver should fill <span class="monospaced">*grallocConsumerUsage</span> and <span class="monospaced">*grallocProducerUsage</span> with the gralloc usage flags it requires for that format and usage. These will be combined with the usage flags requested by the swapchain consumer when allocating buffers.</p></div>
+<div class="paragraph"><p>An older version of this function is deprecated but still supported for backwards compatibility; it will be used if <span class="monospaced">vkGetSwapchainGrallocUsage2ANDROID</span> is not supported:</p></div>
+<div class="listingblock">
+<div class="content"><!-- Generator: GNU source-highlight 3.1.6
+by Lorenzo Bettini
+http://www.lorenzobettini.it
+http://www.gnu.org/software/src-highlite -->
+<pre><tt>VkResult <span style="color: #008080">VKAPI</span> <span style="font-weight: bold"><span style="color: #000000">vkGetSwapchainGrallocUsageANDROID</span></span><span style="color: #990000">(</span>
+ <span style="color: #008080">VkDevice</span> device<span style="color: #990000">,</span>
+ <span style="color: #008080">VkFormat</span> format<span style="color: #990000">,</span>
+ <span style="color: #008080">VkImageUsageFlags</span> imageUsage<span style="color: #990000">,</span>
<span style="color: #009900">int</span><span style="color: #990000">*</span> grallocUsage
<span style="color: #990000">);</span></tt></pre></div></div>
<div class="paragraph"><p><span class="monospaced">VkNativeBufferANDROID</span> is a <span class="monospaced">vkCreateImage</span> extension structure for creating an image backed by a gralloc buffer. This structure is provided to <span class="monospaced">vkCreateImage</span> in the <span class="monospaced">VkImageCreateInfo</span> structure chain. Calls to <span class="monospaced">vkCreateImage</span> with this structure will happen during the first call to <span class="monospaced">vkGetSwapChainInfoWSI(.. VK_SWAP_CHAIN_INFO_TYPE_IMAGES_WSI ..)</span>. The WSI implementation will allocate the number of native buffers requested for the swapchain, then create a <span class="monospaced">VkImage</span> for each one.</p></div>
<span style="font-style: italic"><span style="color: #9A1900">// Gralloc format and usage requested when the buffer was allocated.</span></span>
<span style="color: #009900">int</span> format<span style="color: #990000">;</span>
- <span style="color: #009900">int</span> usage<span style="color: #990000">;</span>
+ <span style="color: #009900">int</span> usage<span style="color: #990000">;</span> <span style="font-style: italic"><span style="color: #9A1900">// deprecated</span></span>
+ <span style="font-weight: bold"><span style="color: #0000FF">struct</span></span> <span style="color: #FF0000">{</span>
+ <span style="color: #008080">uint64_t</span> consumer<span style="color: #990000">;</span>
+ <span style="color: #008080">uint64_t</span> producer<span style="color: #990000">;</span>
+ <span style="color: #FF0000">}</span> usage2<span style="color: #990000">;</span>
<span style="color: #FF0000">}</span> VkNativeBufferANDROID<span style="color: #990000">;</span></tt></pre></div></div>
<div class="paragraph"><p>When creating a gralloc-backed image, the <span class="monospaced">VkImageCreateInfo</span> will have:</p></div>
<div class="listingblock">
</li>
</ul></div>
</li>
+<li>
+<p>
+<strong>2017-02-09</strong>
+</p>
+<div class="ulist"><ul>
+<li>
+<p>
+Extended vkGetSwapchainGrallocUsage2ANDROID and VkNativeBufferANDROID to use gralloc1-style usage bitfields.
+</p>
+</li>
+</ul></div>
+</li>
</ol></div>
</div>
</div>
<div id="footer">
<div id="footer-text">
Version 5<br>
-Last updated 2017-01-12 14:25:30 NZDT
+Last updated 2017-02-09 22:40:30 PST
</div>
</div>
</body>
#define VK_ANDROID_native_buffer 1
#define VK_ANDROID_NATIVE_BUFFER_EXTENSION_NUMBER 11
+/* NOTE ON VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 6
+ *
+ * This version of the extension transitions from gralloc0 to gralloc1 usage
+ * flags (int -> 2x uint64_t). The WSI implementation will temporarily continue
+ * to fill out deprecated fields in VkNativeBufferANDROID, and will call the
+ * deprecated vkGetSwapchainGrallocUsageANDROID if the new
+ * vkGetSwapchainGrallocUsage2ANDROID is not supported. This transitionary
+ * backwards-compatibility support is temporary, and will likely be removed in
+ * (along with all gralloc0 support) in a future release.
+ */
#define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 6
#define VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME "VK_ANDROID_native_buffer"
// Gralloc format and usage requested when the buffer was allocated.
int format;
- int usage;
+ int usage; // DEPRECATED in SPEC_VERSION 6
+ // -- Added in SPEC_VERSION 6 --
+ struct {
+ uint64_t consumer;
+ uint64_t producer;
+ } usage2;
} VkNativeBufferANDROID;
typedef struct {
VkSwapchainImageUsageFlagsANDROID usage;
} VkSwapchainImageCreateInfoANDROID;
+// -- DEPRECATED in SPEC_VERSION 6 --
typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainGrallocUsageANDROID)(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int* grallocUsage);
-typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainGrallocUsage2ANDROID)(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, VkSwapchainImageUsageFlagsANDROID swapchainImageUsage, int* grallocUsage);
+// -- ADDED in SPEC_VERSION 6 --
+typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainGrallocUsage2ANDROID)(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, VkSwapchainImageUsageFlagsANDROID swapchainImageUsage, uint64_t* grallocConsumerUsage, uint64_t* grallocProducerUsage);
typedef VkResult (VKAPI_PTR *PFN_vkAcquireImageANDROID)(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence);
typedef VkResult (VKAPI_PTR *PFN_vkQueueSignalReleaseImageANDROID)(VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd);
#ifndef VK_NO_PROTOTYPES
+
+// -- DEPRECATED in SPEC_VERSION 6 --
VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainGrallocUsageANDROID(
VkDevice device,
VkFormat format,
VkImageUsageFlags imageUsage,
int* grallocUsage
);
+// -- ADDED in SPEC_VERSION 6 --
VKAPI_ATTR VkResult VKAPI_CALL vkGetSwapchainGrallocUsage2ANDROID(
VkDevice device,
VkFormat format,
VkImageUsageFlags imageUsage,
VkSwapchainImageUsageFlagsANDROID swapchainImageUsage,
- int* grallocUsage
+ uint64_t* grallocConsumerUsage,
+ uint64_t* grallocProducerUsage
);
VKAPI_ATTR VkResult VKAPI_CALL vkAcquireImageANDROID(
VkDevice device,
VkImage image,
int* pNativeFenceFd
);
-// -- DEPRECATED --
-VKAPI_ATTR VkResult VKAPI_CALL vkImportNativeFenceANDROID(
- VkDevice device,
- VkSemaphore semaphore,
- int nativeFenceFd
-);
-VKAPI_ATTR VkResult VKAPI_CALL vkQueueSignalNativeFenceANDROID(
- VkQueue queue,
- int* pNativeFenceFd
-);
-// ----------------
#endif
#ifdef __cplusplus
"vulkan_headers",
],
shared_libs: [
- "libgui",
"libziparchive",
"libhardware",
"libsync",
"libbase",
"liblog",
+ "libui",
"libutils",
"libcutils",
"libz",
{{AssertType $ "Function"}}
{{$ext := GetAnnotation $ "extension"}}
- {{$required := (Macro "IsRequiredFunction" $)}}
{{if $ext}}
- INIT_PROC_EXT({{Macro "BaseName" $ext}}, {{$required}}, §
+ INIT_PROC_EXT({{Macro "BaseName" $ext}}, §
{{else}}
- INIT_PROC({{$required}}, §
+ INIT_PROC(§
{{end}}
+ {{if GetAnnotation $ "optional"}}false{{else}}true{{end}}, §
+
{{if (Macro "IsInstanceDispatched" $)}}
instance, §
{{else}}
{{/*
------------------------------------------------------------------------------
- Emits true if a function /must/ be resolved. The only time this is not
- the case is for extension-added functions added in a later revision of the
- extension, and where we have to cope with drivers written against an older
- revision.
-------------------------------------------------------------------------------
-*/}}
-{{define "IsRequiredFunction"}}
- {{AssertType $ "Function"}}
-
- {{if eq $.Name "vkGetSwapchainGrallocUsage2ANDROID"}}
- false
- {{else}}
- true
- {{end}}
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
Emits true if a function is exported and instance-dispatched.
------------------------------------------------------------------------------
*/}}
{{else if eq $.Name "vkCreateImage"}}true
{{else if eq $.Name "vkDestroyImage"}}true
+ {{else if eq $.Name "vkGetPhysicalDeviceProperties"}}true
+
{{end}}
{{$ext := GetAnnotation $ "extension"}}
Node* prev = &head_;
while (prev && prev->next != node)
prev = prev->next;
- prev->next = node->next;
+ if (prev)
+ prev->next = node->next;
}
allocator.pfnFree(allocator.pUserData, node);
#include <android/dlext.h>
#include <cutils/properties.h>
-#include <gui/GraphicsEnv.h>
+#include <ui/GraphicsEnv.h>
#include "driver.h"
#include "stubhal.h"
const InstanceData& data = GetData(physicalDevice);
static const std::array<VkExtensionProperties, 2> loader_extensions = {{
// WSI extensions
+#if 0 // Remove this "#if 0" once the VK_KHR_incremental_present extension is ratified
{VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME,
VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION},
+#endif
{VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME,
VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION},
}};
return VK_ERROR_INCOMPATIBLE_DRIVER;
}
+
+ // sanity check ANDROID_native_buffer implementation, whose set of
+ // entrypoints varies according to the spec version.
+ if ((wrapper.GetHalExtensions()[ProcHook::ANDROID_native_buffer]) &&
+ !data->driver.GetSwapchainGrallocUsageANDROID &&
+ !data->driver.GetSwapchainGrallocUsage2ANDROID) {
+ ALOGE("Driver's implementation of ANDROID_native_buffer is broken;"
+ " must expose at least one of "
+ "vkGetSwapchainGrallocUsageANDROID or "
+ "vkGetSwapchainGrallocUsage2ANDROID");
+
+ data->driver.DestroyDevice(dev, pAllocator);
+ FreeDeviceData(data, data_allocator);
+
+ return VK_ERROR_INCOMPATIBLE_DRIVER;
+ }
+
+ VkPhysicalDeviceProperties properties;
+ instance_data.driver.GetPhysicalDeviceProperties(physicalDevice,
+ &properties);
+
data->driver_device = dev;
+ data->driver_version = properties.driverVersion;
*pDevice = dev;
VkDevice driver_device;
DeviceDriverTable driver;
+ uint32_t driver_version;
};
bool Debuggable();
INIT_PROC(true, instance, DestroyInstance);
INIT_PROC(true, instance, EnumeratePhysicalDevices);
INIT_PROC(true, instance, GetInstanceProcAddr);
+ INIT_PROC(true, instance, GetPhysicalDeviceProperties);
INIT_PROC(true, instance, CreateDevice);
INIT_PROC(true, instance, EnumerateDeviceExtensionProperties);
INIT_PROC_EXT(EXT_debug_report, true, instance, CreateDebugReportCallbackEXT);
INIT_PROC(true, dev, CreateImage);
INIT_PROC(true, dev, DestroyImage);
INIT_PROC(true, dev, AllocateCommandBuffers);
- INIT_PROC_EXT(ANDROID_native_buffer, true, dev, GetSwapchainGrallocUsageANDROID);
+ INIT_PROC_EXT(ANDROID_native_buffer, false, dev, GetSwapchainGrallocUsageANDROID);
INIT_PROC_EXT(ANDROID_native_buffer, false, dev, GetSwapchainGrallocUsage2ANDROID);
INIT_PROC_EXT(ANDROID_native_buffer, true, dev, AcquireImageANDROID);
INIT_PROC_EXT(ANDROID_native_buffer, true, dev, QueueSignalReleaseImageANDROID);
PFN_vkDestroyInstance DestroyInstance;
PFN_vkEnumeratePhysicalDevices EnumeratePhysicalDevices;
PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
+ PFN_vkGetPhysicalDeviceProperties GetPhysicalDeviceProperties;
PFN_vkCreateDevice CreateDevice;
PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties;
PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
enum { MIN_NUM_FRAMES_AGO = 5 };
struct Swapchain {
- Swapchain(Surface& surface_, uint32_t num_images_)
+ Swapchain(Surface& surface_,
+ uint32_t num_images_,
+ VkPresentModeKHR present_mode)
: surface(surface_),
num_images(num_images_),
+ mailbox_mode(present_mode == VK_PRESENT_MODE_MAILBOX_KHR),
frame_timestamps_enabled(false) {
ANativeWindow* window = surface.window.get();
int64_t rdur;
Surface& surface;
uint32_t num_images;
+ bool mailbox_mode;
bool frame_timestamps_enabled;
uint64_t refresh_duration;
const VkPresentModeKHR kModes[] = {
VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_FIFO_KHR,
// TODO(chrisforbes): should only expose this if the driver can.
- VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR,
- VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR,
+ // VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR,
+ // VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR,
};
const uint32_t kNumModes = sizeof(kModes) / sizeof(kModes[0]);
int gralloc_usage = 0;
if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
- result = dispatch.GetSwapchainGrallocUsage2ANDROID(
- device, create_info->imageFormat, create_info->imageUsage,
- swapchain_image_usage, &gralloc_usage);
+ uint64_t consumer_usage, producer_usage;
+ if (GetData(device).driver_version == 256587285) {
+ // HACK workaround for loader/driver mismatch during transition to
+ // vkGetSwapchainGrallocUsage2ANDROID.
+ typedef VkResult(VKAPI_PTR *
+ PFN_vkGetSwapchainGrallocUsage2ANDROID_HACK)(
+ VkDevice device, VkFormat format, VkImageUsageFlags imageUsage,
+ uint64_t * grallocConsumerUsage,
+ uint64_t * grallocProducerUsage);
+ auto get_swapchain_gralloc_usage =
+ reinterpret_cast<PFN_vkGetSwapchainGrallocUsage2ANDROID_HACK>(
+ dispatch.GetSwapchainGrallocUsage2ANDROID);
+ result = get_swapchain_gralloc_usage(
+ device, create_info->imageFormat, create_info->imageUsage,
+ &consumer_usage, &producer_usage);
+ } else {
+ result = dispatch.GetSwapchainGrallocUsage2ANDROID(
+ device, create_info->imageFormat, create_info->imageUsage,
+ swapchain_image_usage, &consumer_usage, &producer_usage);
+ }
if (result != VK_SUCCESS) {
ALOGE("vkGetSwapchainGrallocUsage2ANDROID failed: %d", result);
return VK_ERROR_INITIALIZATION_FAILED;
}
+ // TODO: This is the same translation done by Gralloc1On0Adapter.
+ // Remove it once ANativeWindow has been updated to take gralloc1-style
+ // usages.
+ gralloc_usage =
+ static_cast<int>(consumer_usage) | static_cast<int>(producer_usage);
} else if (dispatch.GetSwapchainGrallocUsageANDROID) {
result = dispatch.GetSwapchainGrallocUsageANDROID(
device, create_info->imageFormat, create_info->imageUsage,
ALOGE("vkGetSwapchainGrallocUsageANDROID failed: %d", result);
return VK_ERROR_INITIALIZATION_FAILED;
}
- } else {
- gralloc_usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
}
err = native_window_set_usage(surface.window.get(), gralloc_usage);
if (err != 0) {
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (!mem)
return VK_ERROR_OUT_OF_HOST_MEMORY;
- Swapchain* swapchain = new (mem) Swapchain(surface, num_images);
+ Swapchain* swapchain =
+ new (mem) Swapchain(surface, num_images, create_info->presentMode);
// -- Dequeue all buffers and create a VkImage for each --
// Any failures during or after this must cancel the dequeued buffers.
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);
result =
dispatch.CreateImage(device, &image_create, nullptr, &img.image);
*SwapchainFromHandle(present_info->pSwapchains[sc]);
uint32_t image_idx = present_info->pImageIndices[sc];
Swapchain::Image& img = swapchain.images[image_idx];
- const VkPresentRegionKHR* region = (regions) ? ®ions[sc] : nullptr;
+ const VkPresentRegionKHR* region =
+ (regions && !swapchain.mailbox_mode) ? ®ions[sc] : nullptr;
const VkPresentTimeGOOGLE* time = (times) ? ×[sc] : nullptr;
VkResult swapchain_result = VK_SUCCESS;
VkResult result;
VkFormat,
VkImageUsageFlags,
VkSwapchainImageUsageFlagsANDROID,
- int* grallocUsage) {
+ uint64_t* grallocConsumerUsage,
+ uint64_t* grallocProducerUsage) {
// The null driver never reads or writes the gralloc buffer
- *grallocUsage = 0;
+ *grallocConsumerUsage = 0;
+ *grallocProducerUsage = 0;
return VK_SUCCESS;
}
VKAPI_ATTR void CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents);
VKAPI_ATTR void CmdEndRenderPass(VkCommandBuffer commandBuffer);
VKAPI_ATTR void CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers);
-VKAPI_ATTR VkResult GetSwapchainGrallocUsageANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int* grallocUsage);
-VKAPI_ATTR VkResult GetSwapchainGrallocUsage2ANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, VkSwapchainImageUsageFlagsANDROID swapchainImageUsage, int* grallocUsage);
+VKAPI_ATTR VkResult GetSwapchainGrallocUsageANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int32_t* grallocUsage);
+VKAPI_ATTR VkResult GetSwapchainGrallocUsage2ANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, VkSwapchainImageUsageFlagsANDROID swapchainImageUsage, uint64_t* grallocConsumerUsage, uint64_t* grallocProducerUsage);
VKAPI_ATTR VkResult AcquireImageANDROID(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence);
VKAPI_ATTR VkResult QueueSignalReleaseImageANDROID(VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd);
VKAPI_ATTR VkResult CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback);