diff options
116 files changed, 2964 insertions, 3104 deletions
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index 1a932c3d04..4f7cdf3e5e 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -4,13 +4,16 @@ clang_format = true [Builtin Hooks Options] # Only turn on clang-format check for the following subfolders. clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp + include/input/ libs/binder/ndk/ libs/graphicsenv/ libs/gui/ + libs/input/ libs/renderengine/ libs/ui/ libs/vr/ services/bufferhub/ + services/inputflinger/ services/surfaceflinger/ services/vr/ diff --git a/cmds/dumpstate/README.md b/cmds/dumpstate/README.md index c818c05117..26dabbbcef 100644 --- a/cmds/dumpstate/README.md +++ b/cmds/dumpstate/README.md @@ -92,6 +92,12 @@ Then to restore the default version: adb shell setprop dumpstate.version default ``` +## To set Bugreport API workflow for bugreport + +``` +adb shell setprop settings_call_bugreport_api true +``` + ## Code style and formatting Use the style defined at the diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl index 26e9984f11..d99bcc8d13 100644 --- a/cmds/installd/binder/android/os/IInstalld.aidl +++ b/cmds/installd/binder/android/os/IInstalld.aidl @@ -127,4 +127,6 @@ interface IInstalld { const int FLAG_USE_QUOTA = 0x1000; const int FLAG_FORCE = 0x2000; + + const int FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES = 0x20000; } diff --git a/cmds/servicemanager/Access.cpp b/cmds/servicemanager/Access.cpp new file mode 100644 index 0000000000..f4005c4dee --- /dev/null +++ b/cmds/servicemanager/Access.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2019 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 "Access.h" + +#include <android-base/logging.h> +#include <binder/IPCThreadState.h> +#include <log/log_safetynet.h> +#include <selinux/android.h> +#include <selinux/avc.h> + +namespace android { + +#ifdef VENDORSERVICEMANAGER +constexpr bool kIsVendor = true; +#else +constexpr bool kIsVendor = false; +#endif + +static std::string getPidcon(pid_t pid) { + android_errorWriteLog(0x534e4554, "121035042"); + + char* lookup = nullptr; + if (getpidcon(pid, &lookup) < 0) { + LOG(ERROR) << "SELinux: getpidcon(pid=" << pid << ") failed to retrieve pid context"; + return ""; + } + std::string result = lookup; + freecon(lookup); + return result; +} + +static struct selabel_handle* getSehandle() { + static struct selabel_handle* gSehandle = nullptr; + + if (gSehandle != nullptr && selinux_status_updated()) { + selabel_close(gSehandle); + gSehandle = nullptr; + } + + if (gSehandle == nullptr) { + gSehandle = kIsVendor + ? selinux_android_vendor_service_context_handle() + : selinux_android_service_context_handle(); + } + + CHECK(gSehandle != nullptr); + return gSehandle; +} + +static int auditCallback(void *data, security_class_t /*cls*/, char *buf, size_t len) { + const Access::CallingContext* ad = reinterpret_cast<Access::CallingContext*>(data); + + if (!ad) { + LOG(ERROR) << "No service manager audit data"; + return 0; + } + + snprintf(buf, len, "service=%s pid=%d uid=%d", ad->name.c_str(), ad->debugPid, ad->uid); + return 0; +} + +Access::Access() { + union selinux_callback cb; + + cb.func_audit = auditCallback; + selinux_set_callback(SELINUX_CB_AUDIT, cb); + + cb.func_log = kIsVendor ? selinux_vendor_log_callback : selinux_log_callback; + selinux_set_callback(SELINUX_CB_LOG, cb); + + CHECK(selinux_status_open(true /*fallback*/) >= 0); + + CHECK(getcon(&mThisProcessContext) == 0); +} + +Access::~Access() { + freecon(mThisProcessContext); +} + +Access::CallingContext Access::getCallingContext(const std::string& name) { + IPCThreadState* ipc = IPCThreadState::self(); + + const char* callingSid = ipc->getCallingSid(); + pid_t callingPid = ipc->getCallingPid(); + + return CallingContext { + .debugPid = callingPid, + .uid = ipc->getCallingUid(), + .sid = callingSid ? std::string(callingSid) : getPidcon(callingPid), + .name = name, + }; +} + +bool Access::canFind(const CallingContext& ctx) { + return actionAllowedFromLookup(ctx, "find"); +} + +bool Access::canAdd(const CallingContext& ctx) { + return actionAllowedFromLookup(ctx, "add"); +} + +bool Access::canList(const CallingContext& ctx) { + CHECK(ctx.name == ""); + + return actionAllowed(ctx, mThisProcessContext, "list"); +} + +bool Access::actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm) { + const char* tclass = "service_manager"; + + return 0 == selinux_check_access(sctx.sid.c_str(), tctx, tclass, perm, reinterpret_cast<void*>(const_cast<CallingContext*>((&sctx)))); +} + +bool Access::actionAllowedFromLookup(const CallingContext& sctx, const char *perm) { + char *tctx = nullptr; + if (selabel_lookup(getSehandle(), &tctx, sctx.name.c_str(), 0) != 0) { + LOG(ERROR) << "SELinux: No match for " << sctx.name << " in service_contexts.\n"; + return false; + } + + bool allowed = actionAllowed(sctx, tctx, perm); + freecon(tctx); + return allowed; +} + +} // android diff --git a/cmds/servicemanager/Access.h b/cmds/servicemanager/Access.h new file mode 100644 index 0000000000..b2c78cc34d --- /dev/null +++ b/cmds/servicemanager/Access.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2019 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. + */ + +#pragma once + +#include <string> +#include <sys/types.h> + +namespace android { + +// singleton +class Access { +public: + Access(); + virtual ~Access(); + + Access(const Access&) = delete; + Access& operator=(const Access&) = delete; + Access(Access&&) = delete; + Access& operator=(Access&&) = delete; + + struct CallingContext { + pid_t debugPid; + uid_t uid; + std::string sid; + + // name of the service + // + // empty if call is unrelated to service (e.g. list) + std::string name; + }; + + virtual CallingContext getCallingContext(const std::string& name); + + virtual bool canFind(const CallingContext& ctx); + virtual bool canAdd(const CallingContext& ctx); + virtual bool canList(const CallingContext& ctx); + +private: + bool actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm); + bool actionAllowedFromLookup(const CallingContext& sctx, const char *perm); + + char* mThisProcessContext = nullptr; +}; + +}; diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp index 428561bc8a..9cf3c5c134 100644 --- a/cmds/servicemanager/Android.bp +++ b/cmds/servicemanager/Android.bp @@ -1,51 +1,51 @@ cc_defaults { - name: "servicemanager_flags", + name: "servicemanager_defaults", cflags: [ "-Wall", "-Wextra", "-Werror", ], - product_variables: { - binder32bit: { - cflags: ["-DBINDER_IPC_32BIT=1"], - }, - }, - shared_libs: ["liblog"], -} - -cc_binary { - name: "bctest", - defaults: ["servicemanager_flags"], srcs: [ - "bctest.c", - "binder.c", + "Access.cpp", + "ServiceManager.cpp", + ], + + shared_libs: [ + "libbase", + "libbinder", // also contains servicemanager_interface + "libcutils", + "liblog", + "libutils", + "libselinux", ], } cc_binary { name: "servicemanager", - defaults: ["servicemanager_flags"], - srcs: [ - "service_manager.c", - "binder.c", - ], - shared_libs: ["libcutils", "libselinux"], + defaults: ["servicemanager_defaults"], init_rc: ["servicemanager.rc"], + srcs: ["main.cpp"], } cc_binary { name: "vndservicemanager", - defaults: ["servicemanager_flags"], + defaults: ["servicemanager_defaults"], + init_rc: ["vndservicemanager.rc"], vendor: true, - srcs: [ - "service_manager.c", - "binder.c", - ], cflags: [ "-DVENDORSERVICEMANAGER=1", ], - shared_libs: ["libcutils", "libselinux"], - init_rc: ["vndservicemanager.rc"], + srcs: ["main.cpp"], +} + +cc_test { + name: "servicemanager_test", + test_suites: ["device-tests"], + defaults: ["servicemanager_defaults"], + srcs: [ + "test_sm.cpp", + ], + static_libs: ["libgmock"], } diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp new file mode 100644 index 0000000000..b88b67d138 --- /dev/null +++ b/cmds/servicemanager/ServiceManager.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2019 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 "ServiceManager.h" + +#include <android-base/logging.h> +#include <cutils/android_filesystem_config.h> +#include <cutils/multiuser.h> + +using ::android::binder::Status; + +namespace android { + +ServiceManager::ServiceManager(std::unique_ptr<Access>&& access) : mAccess(std::move(access)) {} + +Status ServiceManager::getService(const std::string& name, sp<IBinder>* outBinder) { + // Servicemanager is single-threaded and cannot block. This method exists for legacy reasons. + return checkService(name, outBinder); +} + +Status ServiceManager::checkService(const std::string& name, sp<IBinder>* outBinder) { + auto ctx = mAccess->getCallingContext(name); + + auto it = mNameToService.find(name); + if (it == mNameToService.end()) { + *outBinder = nullptr; + return Status::ok(); + } + + const Service& service = it->second; + + if (!service.allowIsolated) { + uid_t appid = multiuser_get_app_id(ctx.uid); + bool isIsolated = appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END; + + if (isIsolated) { + *outBinder = nullptr; + return Status::ok(); + } + } + + // TODO(b/136023468): move this check to be first + if (!mAccess->canFind(ctx)) { + // returns ok and null for legacy reasons + *outBinder = nullptr; + return Status::ok(); + } + + *outBinder = service.binder; + return Status::ok(); +} + +Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) { + auto ctx = mAccess->getCallingContext(name); + + // apps cannot add services + if (multiuser_get_app_id(ctx.uid) >= AID_APP) { + return Status::fromExceptionCode(Status::EX_SECURITY); + } + + if (!mAccess->canAdd(ctx)) { + return Status::fromExceptionCode(Status::EX_SECURITY); + } + + if (binder == nullptr) { + return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); + } + + // match legacy rules + if (name.size() == 0 || name.size() > 127) { + return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); + } + + if (OK != binder->linkToDeath(this)) { + LOG(ERROR) << "Could not linkToDeath when adding " << name; + return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); + } + + auto it = mNameToService.find(name); + if (it != mNameToService.end()) { + if (OK != it->second.binder->unlinkToDeath(this)) { + LOG(WARNING) << "Could not unlinkToDeath when adding " << name; + } + } + + mNameToService[name] = Service { + .binder = binder, + .allowIsolated = allowIsolated, + .dumpPriority = dumpPriority, + }; + + return Status::ok(); +} + +Status ServiceManager::listServices(int32_t dumpPriority, std::vector<std::string>* outList) { + if (!mAccess->canList(mAccess->getCallingContext(""))) { + return Status::fromExceptionCode(Status::EX_SECURITY); + } + + size_t toReserve = 0; + for (auto const& [name, service] : mNameToService) { + (void) name; + + if (service.dumpPriority & dumpPriority) ++toReserve; + } + + CHECK(outList->empty()); + + outList->reserve(toReserve); + for (auto const& [name, service] : mNameToService) { + (void) service; + + if (service.dumpPriority & dumpPriority) { + outList->push_back(name); + } + } + + return Status::ok(); +} + +void ServiceManager::binderDied(const wp<IBinder>& who) { + for (auto it = mNameToService.begin(); it != mNameToService.end();) { + if (who == it->second.binder) { + it = mNameToService.erase(it); + } else { + ++it; + } + } +} + +} // namespace android diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h new file mode 100644 index 0000000000..78e48052b8 --- /dev/null +++ b/cmds/servicemanager/ServiceManager.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2019 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. + */ + +#pragma once + +#include <android/os/BnServiceManager.h> + +#include "Access.h" + +namespace android { + +class ServiceManager : public os::BnServiceManager, public IBinder::DeathRecipient { +public: + ServiceManager(std::unique_ptr<Access>&& access); + + binder::Status getService(const std::string& name, sp<IBinder>* outBinder) override; + binder::Status checkService(const std::string& name, sp<IBinder>* outBinder) override; + binder::Status addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) override; + binder::Status listServices(int32_t dumpPriority, std::vector<std::string>* outList) override; + + void binderDied(const wp<IBinder>& who) override; + +private: + struct Service { + sp<IBinder> binder; + bool allowIsolated; + int32_t dumpPriority; + }; + + std::map<std::string, Service> mNameToService; + std::unique_ptr<Access> mAccess; +}; + +} // namespace android diff --git a/cmds/servicemanager/TEST_MAPPING b/cmds/servicemanager/TEST_MAPPING new file mode 100644 index 0000000000..3e47269fe0 --- /dev/null +++ b/cmds/servicemanager/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "servicemanager_test" + } + ] +} diff --git a/cmds/servicemanager/bctest.c b/cmds/servicemanager/bctest.c deleted file mode 100644 index 354df670e5..0000000000 --- a/cmds/servicemanager/bctest.c +++ /dev/null @@ -1,107 +0,0 @@ -/* Copyright 2008 The Android Open Source Project - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> - -#include "binder.h" - -uint32_t svcmgr_lookup(struct binder_state *bs, uint32_t target, const char *name) -{ - uint32_t handle; - unsigned iodata[512/4]; - struct binder_io msg, reply; - - bio_init(&msg, iodata, sizeof(iodata), 4); - bio_put_uint32(&msg, 0); // strict mode header - bio_put_string16_x(&msg, SVC_MGR_NAME); - bio_put_string16_x(&msg, name); - - if (binder_call(bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE)) - return 0; - - handle = bio_get_ref(&reply); - - if (handle) - binder_acquire(bs, handle); - - binder_done(bs, &msg, &reply); - - return handle; -} - -int svcmgr_publish(struct binder_state *bs, uint32_t target, const char *name, void *ptr) -{ - int status; - unsigned iodata[512/4]; - struct binder_io msg, reply; - - bio_init(&msg, iodata, sizeof(iodata), 4); - bio_put_uint32(&msg, 0); // strict mode header - bio_put_string16_x(&msg, SVC_MGR_NAME); - bio_put_string16_x(&msg, name); - bio_put_obj(&msg, ptr); - - if (binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE)) - return -1; - - status = bio_get_uint32(&reply); - - binder_done(bs, &msg, &reply); - - return status; -} - -unsigned token; - -int main(int argc, char **argv) -{ - struct binder_state *bs; - uint32_t svcmgr = BINDER_SERVICE_MANAGER; - uint32_t handle; - - bs = binder_open("/dev/binder", 128*1024); - if (!bs) { - fprintf(stderr, "failed to open binder driver\n"); - return -1; - } - - argc--; - argv++; - while (argc > 0) { - if (!strcmp(argv[0],"alt")) { - handle = svcmgr_lookup(bs, svcmgr, "alt_svc_mgr"); - if (!handle) { - fprintf(stderr,"cannot find alt_svc_mgr\n"); - return -1; - } - svcmgr = handle; - fprintf(stderr,"svcmgr is via %x\n", handle); - } else if (!strcmp(argv[0],"lookup")) { - if (argc < 2) { - fprintf(stderr,"argument required\n"); - return -1; - } - handle = svcmgr_lookup(bs, svcmgr, argv[1]); - fprintf(stderr,"lookup(%s) = %x\n", argv[1], handle); - argc--; - argv++; - } else if (!strcmp(argv[0],"publish")) { - if (argc < 2) { - fprintf(stderr,"argument required\n"); - return -1; - } - svcmgr_publish(bs, svcmgr, argv[1], &token); - argc--; - argv++; - } else { - fprintf(stderr,"unknown command %s\n", argv[0]); - return -1; - } - argc--; - argv++; - } - return 0; -} diff --git a/cmds/servicemanager/binder.c b/cmds/servicemanager/binder.c deleted file mode 100644 index cf3b1728b6..0000000000 --- a/cmds/servicemanager/binder.c +++ /dev/null @@ -1,682 +0,0 @@ -/* Copyright 2008 The Android Open Source Project - */ - -#define LOG_TAG "Binder" - -#include <errno.h> -#include <fcntl.h> -#include <inttypes.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/mman.h> -#include <unistd.h> - -#include <log/log.h> - -#include "binder.h" - -#define MAX_BIO_SIZE (1 << 30) - -#define TRACE 0 - -void bio_init_from_txn(struct binder_io *io, struct binder_transaction_data *txn); - -#if TRACE -void hexdump(void *_data, size_t len) -{ - unsigned char *data = _data; - size_t count; - - for (count = 0; count < len; count++) { - if ((count & 15) == 0) - fprintf(stderr,"%04zu:", count); - fprintf(stderr," %02x %c", *data, - (*data < 32) || (*data > 126) ? '.' : *data); - data++; - if ((count & 15) == 15) - fprintf(stderr,"\n"); - } - if ((count & 15) != 0) - fprintf(stderr,"\n"); -} - -void binder_dump_txn(struct binder_transaction_data *txn) -{ - struct flat_binder_object *obj; - binder_size_t *offs = (binder_size_t *)(uintptr_t)txn->data.ptr.offsets; - size_t count = txn->offsets_size / sizeof(binder_size_t); - - fprintf(stderr," target %016"PRIx64" cookie %016"PRIx64" code %08x flags %08x\n", - (uint64_t)txn->target.ptr, (uint64_t)txn->cookie, txn->code, txn->flags); - fprintf(stderr," pid %8d uid %8d data %"PRIu64" offs %"PRIu64"\n", - txn->sender_pid, txn->sender_euid, (uint64_t)txn->data_size, (uint64_t)txn->offsets_size); - hexdump((void *)(uintptr_t)txn->data.ptr.buffer, txn->data_size); - while (count--) { - obj = (struct flat_binder_object *) (((char*)(uintptr_t)txn->data.ptr.buffer) + *offs++); - fprintf(stderr," - type %08x flags %08x ptr %016"PRIx64" cookie %016"PRIx64"\n", - obj->type, obj->flags, (uint64_t)obj->binder, (uint64_t)obj->cookie); - } -} - -#define NAME(n) case n: return #n -const char *cmd_name(uint32_t cmd) -{ - switch(cmd) { - NAME(BR_NOOP); - NAME(BR_TRANSACTION_COMPLETE); - NAME(BR_INCREFS); - NAME(BR_ACQUIRE); - NAME(BR_RELEASE); - NAME(BR_DECREFS); - NAME(BR_TRANSACTION); - NAME(BR_REPLY); - NAME(BR_FAILED_REPLY); - NAME(BR_DEAD_REPLY); - NAME(BR_DEAD_BINDER); - default: return "???"; - } -} -#else -#define hexdump(a,b) do{} while (0) -#define binder_dump_txn(txn) do{} while (0) -#endif - -#define BIO_F_SHARED 0x01 /* needs to be buffer freed */ -#define BIO_F_OVERFLOW 0x02 /* ran out of space */ -#define BIO_F_IOERROR 0x04 -#define BIO_F_MALLOCED 0x08 /* needs to be free()'d */ - -struct binder_state -{ - int fd; - void *mapped; - size_t mapsize; -}; - -struct binder_state *binder_open(const char* driver, size_t mapsize) -{ - struct binder_state *bs; - struct binder_version vers; - - bs = malloc(sizeof(*bs)); - if (!bs) { - errno = ENOMEM; - return NULL; - } - - bs->fd = open(driver, O_RDWR | O_CLOEXEC); - if (bs->fd < 0) { - fprintf(stderr,"binder: cannot open %s (%s)\n", - driver, strerror(errno)); - goto fail_open; - } - - if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) || - (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) { - fprintf(stderr, - "binder: kernel driver version (%d) differs from user space version (%d)\n", - vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION); - goto fail_open; - } - - bs->mapsize = mapsize; - bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0); - if (bs->mapped == MAP_FAILED) { - fprintf(stderr,"binder: cannot map device (%s)\n", - strerror(errno)); - goto fail_map; - } - - return bs; - -fail_map: - close(bs->fd); -fail_open: - free(bs); - return NULL; -} - -void binder_close(struct binder_state *bs) -{ - munmap(bs->mapped, bs->mapsize); - close(bs->fd); - free(bs); -} - -int binder_become_context_manager(struct binder_state *bs) -{ - struct flat_binder_object obj; - memset(&obj, 0, sizeof(obj)); - obj.flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX; - - int result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR_EXT, &obj); - - // fallback to original method - if (result != 0) { - android_errorWriteLog(0x534e4554, "121035042"); - - result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0); - } - return result; -} - -int binder_write(struct binder_state *bs, void *data, size_t len) -{ - struct binder_write_read bwr; - int res; - - bwr.write_size = len; - bwr.write_consumed = 0; - bwr.write_buffer = (uintptr_t) data; - bwr.read_size = 0; - bwr.read_consumed = 0; - bwr.read_buffer = 0; - res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); - if (res < 0) { - fprintf(stderr,"binder_write: ioctl failed (%s)\n", - strerror(errno)); - } - return res; -} - -void binder_free_buffer(struct binder_state *bs, - binder_uintptr_t buffer_to_free) -{ - struct { - uint32_t cmd_free; - binder_uintptr_t buffer; - } __attribute__((packed)) data; - data.cmd_free = BC_FREE_BUFFER; - data.buffer = buffer_to_free; - binder_write(bs, &data, sizeof(data)); -} - -void binder_send_reply(struct binder_state *bs, - struct binder_io *reply, - binder_uintptr_t buffer_to_free, - int status) -{ - struct { - uint32_t cmd_free; - binder_uintptr_t buffer; - uint32_t cmd_reply; - struct binder_transaction_data txn; - } __attribute__((packed)) data; - - data.cmd_free = BC_FREE_BUFFER; - data.buffer = buffer_to_free; - data.cmd_reply = BC_REPLY; - data.txn.target.ptr = 0; - data.txn.cookie = 0; - data.txn.code = 0; - if (status) { - data.txn.flags = TF_STATUS_CODE; - data.txn.data_size = sizeof(int); - data.txn.offsets_size = 0; - data.txn.data.ptr.buffer = (uintptr_t)&status; - data.txn.data.ptr.offsets = 0; - } else { - data.txn.flags = 0; - data.txn.data_size = reply->data - reply->data0; - data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0); - data.txn.data.ptr.buffer = (uintptr_t)reply->data0; - data.txn.data.ptr.offsets = (uintptr_t)reply->offs0; - } - binder_write(bs, &data, sizeof(data)); -} - -int binder_parse(struct binder_state *bs, struct binder_io *bio, - uintptr_t ptr, size_t size, binder_handler func) -{ - int r = 1; - uintptr_t end = ptr + (uintptr_t) size; - - while (ptr < end) { - uint32_t cmd = *(uint32_t *) ptr; - ptr += sizeof(uint32_t); -#if TRACE - fprintf(stderr,"%s:\n", cmd_name(cmd)); -#endif - switch(cmd) { - case BR_NOOP: - break; - case BR_TRANSACTION_COMPLETE: - break; - case BR_INCREFS: - case BR_ACQUIRE: - case BR_RELEASE: - case BR_DECREFS: -#if TRACE - fprintf(stderr," %p, %p\n", (void *)ptr, (void *)(ptr + sizeof(void *))); -#endif - ptr += sizeof(struct binder_ptr_cookie); - break; - case BR_TRANSACTION_SEC_CTX: - case BR_TRANSACTION: { - struct binder_transaction_data_secctx txn; - if (cmd == BR_TRANSACTION_SEC_CTX) { - if ((end - ptr) < sizeof(struct binder_transaction_data_secctx)) { - ALOGE("parse: txn too small (binder_transaction_data_secctx)!\n"); - return -1; - } - memcpy(&txn, (void*) ptr, sizeof(struct binder_transaction_data_secctx)); - ptr += sizeof(struct binder_transaction_data_secctx); - } else /* BR_TRANSACTION */ { - if ((end - ptr) < sizeof(struct binder_transaction_data)) { - ALOGE("parse: txn too small (binder_transaction_data)!\n"); - return -1; - } - memcpy(&txn.transaction_data, (void*) ptr, sizeof(struct binder_transaction_data)); - ptr += sizeof(struct binder_transaction_data); - - txn.secctx = 0; - } - - binder_dump_txn(&txn.transaction_data); - if (func) { - unsigned rdata[256/4]; - struct binder_io msg; - struct binder_io reply; - int res; - - bio_init(&reply, rdata, sizeof(rdata), 4); - bio_init_from_txn(&msg, &txn.transaction_data); - res = func(bs, &txn, &msg, &reply); - if (txn.transaction_data.flags & TF_ONE_WAY) { - binder_free_buffer(bs, txn.transaction_data.data.ptr.buffer); - } else { - binder_send_reply(bs, &reply, txn.transaction_data.data.ptr.buffer, res); - } - } - break; - } - case BR_REPLY: { - struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr; - if ((end - ptr) < sizeof(*txn)) { - ALOGE("parse: reply too small!\n"); - return -1; - } - binder_dump_txn(txn); - if (bio) { - bio_init_from_txn(bio, txn); - bio = 0; - } else { - /* todo FREE BUFFER */ - } - ptr += sizeof(*txn); - r = 0; - break; - } - case BR_DEAD_BINDER: { - struct binder_death *death = (struct binder_death *)(uintptr_t) *(binder_uintptr_t *)ptr; - ptr += sizeof(binder_uintptr_t); - death->func(bs, death->ptr); - break; - } - case BR_FAILED_REPLY: - r = -1; - break; - case BR_DEAD_REPLY: - r = -1; - break; - default: - ALOGE("parse: OOPS %d\n", cmd); - return -1; - } - } - - return r; -} - -void binder_acquire(struct binder_state *bs, uint32_t target) -{ - uint32_t cmd[2]; - cmd[0] = BC_ACQUIRE; - cmd[1] = target; - binder_write(bs, cmd, sizeof(cmd)); -} - -void binder_release(struct binder_state *bs, uint32_t target) -{ - uint32_t cmd[2]; - cmd[0] = BC_RELEASE; - cmd[1] = target; - binder_write(bs, cmd, sizeof(cmd)); -} - -void binder_link_to_death(struct binder_state *bs, uint32_t target, struct binder_death *death) -{ - struct { - uint32_t cmd; - struct binder_handle_cookie payload; - } __attribute__((packed)) data; - - data.cmd = BC_REQUEST_DEATH_NOTIFICATION; - data.payload.handle = target; - data.payload.cookie = (uintptr_t) death; - binder_write(bs, &data, sizeof(data)); -} - -int binder_call(struct binder_state *bs, - struct binder_io *msg, struct binder_io *reply, - uint32_t target, uint32_t code) -{ - int res; - struct binder_write_read bwr; - struct { - uint32_t cmd; - struct binder_transaction_data txn; - } __attribute__((packed)) writebuf; - unsigned readbuf[32]; - - if (msg->flags & BIO_F_OVERFLOW) { - fprintf(stderr,"binder: txn buffer overflow\n"); - goto fail; - } - - writebuf.cmd = BC_TRANSACTION; - writebuf.txn.target.handle = target; - writebuf.txn.code = code; - writebuf.txn.flags = 0; - writebuf.txn.data_size = msg->data - msg->data0; - writebuf.txn.offsets_size = ((char*) msg->offs) - ((char*) msg->offs0); - writebuf.txn.data.ptr.buffer = (uintptr_t)msg->data0; - writebuf.txn.data.ptr.offsets = (uintptr_t)msg->offs0; - - bwr.write_size = sizeof(writebuf); - bwr.write_consumed = 0; - bwr.write_buffer = (uintptr_t) &writebuf; - - hexdump(msg->data0, msg->data - msg->data0); - for (;;) { - bwr.read_size = sizeof(readbuf); - bwr.read_consumed = 0; - bwr.read_buffer = (uintptr_t) readbuf; - - res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); - - if (res < 0) { - fprintf(stderr,"binder: ioctl failed (%s)\n", strerror(errno)); - goto fail; - } - - res = binder_parse(bs, reply, (uintptr_t) readbuf, bwr.read_consumed, 0); - if (res == 0) return 0; - if (res < 0) goto fail; - } - -fail: - memset(reply, 0, sizeof(*reply)); - reply->flags |= BIO_F_IOERROR; - return -1; -} - -void binder_loop(struct binder_state *bs, binder_handler func) -{ - int res; - struct binder_write_read bwr; - uint32_t readbuf[32]; - - bwr.write_size = 0; - bwr.write_consumed = 0; - bwr.write_buffer = 0; - - readbuf[0] = BC_ENTER_LOOPER; - binder_write(bs, readbuf, sizeof(uint32_t)); - - for (;;) { - bwr.read_size = sizeof(readbuf); - bwr.read_consumed = 0; - bwr.read_buffer = (uintptr_t) readbuf; - - res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); - - if (res < 0) { - ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno)); - break; - } - - res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func); - if (res == 0) { - ALOGE("binder_loop: unexpected reply?!\n"); - break; - } - if (res < 0) { - ALOGE("binder_loop: io error %d %s\n", res, strerror(errno)); - break; - } - } -} - -void bio_init_from_txn(struct binder_io *bio, struct binder_transaction_data *txn) -{ - bio->data = bio->data0 = (char *)(intptr_t)txn->data.ptr.buffer; - bio->offs = bio->offs0 = (binder_size_t *)(intptr_t)txn->data.ptr.offsets; - bio->data_avail = txn->data_size; - bio->offs_avail = txn->offsets_size / sizeof(size_t); - bio->flags = BIO_F_SHARED; -} - -void bio_init(struct binder_io *bio, void *data, - size_t maxdata, size_t maxoffs) -{ - size_t n = maxoffs * sizeof(size_t); - - if (n > maxdata) { - bio->flags = BIO_F_OVERFLOW; - bio->data_avail = 0; - bio->offs_avail = 0; - return; - } - - bio->data = bio->data0 = (char *) data + n; - bio->offs = bio->offs0 = data; - bio->data_avail = maxdata - n; - bio->offs_avail = maxoffs; - bio->flags = 0; -} - -static void *bio_alloc(struct binder_io *bio, size_t size) -{ - size = (size + 3) & (~3); - if (size > bio->data_avail) { - bio->flags |= BIO_F_OVERFLOW; - return NULL; - } else { - void *ptr = bio->data; - bio->data += size; - bio->data_avail -= size; - return ptr; - } -} - -void binder_done(struct binder_state *bs, - __unused struct binder_io *msg, - struct binder_io *reply) -{ - struct { - uint32_t cmd; - uintptr_t buffer; - } __attribute__((packed)) data; - - if (reply->flags & BIO_F_SHARED) { - data.cmd = BC_FREE_BUFFER; - data.buffer = (uintptr_t) reply->data0; - binder_write(bs, &data, sizeof(data)); - reply->flags = 0; - } -} - -static struct flat_binder_object *bio_alloc_obj(struct binder_io *bio) -{ - struct flat_binder_object *obj; - - obj = bio_alloc(bio, sizeof(*obj)); - - if (obj && bio->offs_avail) { - bio->offs_avail--; - *bio->offs++ = ((char*) obj) - ((char*) bio->data0); - return obj; - } - - bio->flags |= BIO_F_OVERFLOW; - return NULL; -} - -void bio_put_uint32(struct binder_io *bio, uint32_t n) -{ - uint32_t *ptr = bio_alloc(bio, sizeof(n)); - if (ptr) - *ptr = n; -} - -void bio_put_obj(struct binder_io *bio, void *ptr) -{ - struct flat_binder_object *obj; - - obj = bio_alloc_obj(bio); - if (!obj) - return; - - obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; - obj->hdr.type = BINDER_TYPE_BINDER; - obj->binder = (uintptr_t)ptr; - obj->cookie = 0; -} - -void bio_put_ref(struct binder_io *bio, uint32_t handle) -{ - struct flat_binder_object *obj; - - if (handle) - obj = bio_alloc_obj(bio); - else - obj = bio_alloc(bio, sizeof(*obj)); - - if (!obj) - return; - - obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; - obj->hdr.type = BINDER_TYPE_HANDLE; - obj->handle = handle; - obj->cookie = 0; -} - -void bio_put_string16(struct binder_io *bio, const uint16_t *str) -{ - size_t len; - uint16_t *ptr; - - if (!str) { - bio_put_uint32(bio, 0xffffffff); - return; - } - - len = 0; - while (str[len]) len++; - - if (len >= (MAX_BIO_SIZE / sizeof(uint16_t))) { - bio_put_uint32(bio, 0xffffffff); - return; - } - - /* Note: The payload will carry 32bit size instead of size_t */ - bio_put_uint32(bio, (uint32_t) len); - len = (len + 1) * sizeof(uint16_t); - ptr = bio_alloc(bio, len); - if (ptr) - memcpy(ptr, str, len); -} - -void bio_put_string16_x(struct binder_io *bio, const char *_str) -{ - unsigned char *str = (unsigned char*) _str; - size_t len; - uint16_t *ptr; - - if (!str) { - bio_put_uint32(bio, 0xffffffff); - return; - } - - len = strlen(_str); - - if (len >= (MAX_BIO_SIZE / sizeof(uint16_t))) { - bio_put_uint32(bio, 0xffffffff); - return; - } - - /* Note: The payload will carry 32bit size instead of size_t */ - bio_put_uint32(bio, len); - ptr = bio_alloc(bio, (len + 1) * sizeof(uint16_t)); - if (!ptr) - return; - - while (*str) - *ptr++ = *str++; - *ptr++ = 0; -} - -static void *bio_get(struct binder_io *bio, size_t size) -{ - size = (size + 3) & (~3); - - if (bio->data_avail < size){ - bio->data_avail = 0; - bio->flags |= BIO_F_OVERFLOW; - return NULL; - } else { - void *ptr = bio->data; - bio->data += size; - bio->data_avail -= size; - return ptr; - } -} - -uint32_t bio_get_uint32(struct binder_io *bio) -{ - uint32_t *ptr = bio_get(bio, sizeof(*ptr)); - return ptr ? *ptr : 0; -} - -uint16_t *bio_get_string16(struct binder_io *bio, size_t *sz) -{ - size_t len; - - /* Note: The payload will carry 32bit size instead of size_t */ - len = (size_t) bio_get_uint32(bio); - if (sz) - *sz = len; - return bio_get(bio, (len + 1) * sizeof(uint16_t)); -} - -static struct flat_binder_object *_bio_get_obj(struct binder_io *bio) -{ - size_t n; - size_t off = bio->data - bio->data0; - - /* TODO: be smarter about this? */ - for (n = 0; n < bio->offs_avail; n++) { - if (bio->offs[n] == off) - return bio_get(bio, sizeof(struct flat_binder_object)); - } - - bio->data_avail = 0; - bio->flags |= BIO_F_OVERFLOW; - return NULL; -} - -uint32_t bio_get_ref(struct binder_io *bio) -{ - struct flat_binder_object *obj; - - obj = _bio_get_obj(bio); - if (!obj) - return 0; - - if (obj->hdr.type == BINDER_TYPE_HANDLE) - return obj->handle; - - return 0; -} diff --git a/cmds/servicemanager/binder.h b/cmds/servicemanager/binder.h deleted file mode 100644 index a9ccc74130..0000000000 --- a/cmds/servicemanager/binder.h +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright 2008 The Android Open Source Project - */ - -#ifndef _BINDER_H_ -#define _BINDER_H_ - -#include <linux/android/binder.h> -#include <sys/ioctl.h> - -struct binder_state; - -struct binder_io -{ - char *data; /* pointer to read/write from */ - binder_size_t *offs; /* array of offsets */ - size_t data_avail; /* bytes available in data buffer */ - size_t offs_avail; /* entries available in offsets array */ - - char *data0; /* start of data buffer */ - binder_size_t *offs0; /* start of offsets buffer */ - uint32_t flags; - uint32_t unused; -}; - -struct binder_death { - void (*func)(struct binder_state *bs, void *ptr); - void *ptr; -}; - -/* the one magic handle */ -#define BINDER_SERVICE_MANAGER 0U - -#define SVC_MGR_NAME "android.os.IServiceManager" - -enum { - /* Must match definitions in IBinder.h and IServiceManager.h */ - PING_TRANSACTION = B_PACK_CHARS('_','P','N','G'), - SVC_MGR_GET_SERVICE = 1, - SVC_MGR_CHECK_SERVICE, - SVC_MGR_ADD_SERVICE, - SVC_MGR_LIST_SERVICES, -}; - -typedef int (*binder_handler)(struct binder_state *bs, - struct binder_transaction_data_secctx *txn, - struct binder_io *msg, - struct binder_io *reply); - -struct binder_state *binder_open(const char* driver, size_t mapsize); -void binder_close(struct binder_state *bs); - -/* initiate a blocking binder call - * - returns zero on success - */ -int binder_call(struct binder_state *bs, - struct binder_io *msg, struct binder_io *reply, - uint32_t target, uint32_t code); - -/* release any state associate with the binder_io - * - call once any necessary data has been extracted from the - * binder_io after binder_call() returns - * - can safely be called even if binder_call() fails - */ -void binder_done(struct binder_state *bs, - struct binder_io *msg, struct binder_io *reply); - -/* manipulate strong references */ -void binder_acquire(struct binder_state *bs, uint32_t target); -void binder_release(struct binder_state *bs, uint32_t target); - -void binder_link_to_death(struct binder_state *bs, uint32_t target, struct binder_death *death); - -void binder_loop(struct binder_state *bs, binder_handler func); - -int binder_become_context_manager(struct binder_state *bs); - -/* allocate a binder_io, providing a stack-allocated working - * buffer, size of the working buffer, and how many object - * offset entries to reserve from the buffer - */ -void bio_init(struct binder_io *bio, void *data, - size_t maxdata, size_t maxobjects); - -void bio_put_obj(struct binder_io *bio, void *ptr); -void bio_put_ref(struct binder_io *bio, uint32_t handle); -void bio_put_uint32(struct binder_io *bio, uint32_t n); -void bio_put_string16(struct binder_io *bio, const uint16_t *str); -void bio_put_string16_x(struct binder_io *bio, const char *_str); - -uint32_t bio_get_uint32(struct binder_io *bio); -uint16_t *bio_get_string16(struct binder_io *bio, size_t *sz); -uint32_t bio_get_ref(struct binder_io *bio); - -#endif diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp new file mode 100644 index 0000000000..c8ceb42ac8 --- /dev/null +++ b/cmds/servicemanager/main.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2019 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 <android-base/logging.h> +#include <binder/IPCThreadState.h> +#include <binder/ProcessState.h> +#include <binder/Status.h> +#include <utils/StrongPointer.h> + +#include "Access.h" +#include "ServiceManager.h" + +using ::android::sp; +using ::android::ProcessState; +using ::android::IPCThreadState; +using ::android::ServiceManager; +using ::android::Access; + +int main(int argc, char** argv) { + if (argc > 2) { + LOG(FATAL) << "usage: " << argv[0] << " [binder driver]"; + } + + const char* driver = argc == 2 ? argv[1] : "/dev/binder"; + + android::base::InitLogging(nullptr, &android::base::KernelLogger); + + ProcessState::self()->initWithDriver(driver); + ProcessState::self()->setThreadPoolMaxThreadCount(0); + ProcessState::self()->setCallRestriction( + ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY); + + sp<ServiceManager> manager = new ServiceManager(std::make_unique<Access>()); + IPCThreadState::self()->setTheContextObject(manager); + ProcessState::self()->becomeContextManager(nullptr, nullptr); + + IPCThreadState::self()->joinThreadPool(); + + // should not be reached + return EXIT_FAILURE; +} diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c deleted file mode 100644 index ec3fac538d..0000000000 --- a/cmds/servicemanager/service_manager.c +++ /dev/null @@ -1,442 +0,0 @@ -/* Copyright 2008 The Android Open Source Project - */ - -#include <errno.h> -#include <fcntl.h> -#include <inttypes.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <cutils/android_filesystem_config.h> -#include <cutils/multiuser.h> - -#include <selinux/android.h> -#include <selinux/avc.h> - -#include "binder.h" - -#ifdef VENDORSERVICEMANAGER -#define LOG_TAG "VendorServiceManager" -#else -#define LOG_TAG "ServiceManager" -#endif -#include <log/log.h> - -struct audit_data { - pid_t pid; - uid_t uid; - const char *name; -}; - -const char *str8(const uint16_t *x, size_t x_len) -{ - static char buf[128]; - size_t max = 127; - char *p = buf; - - if (x_len < max) { - max = x_len; - } - - if (x) { - while ((max > 0) && (*x != '\0')) { - *p++ = *x++; - max--; - } - } - *p++ = 0; - return buf; -} - -int str16eq(const uint16_t *a, const char *b) -{ - while (*a && *b) - if (*a++ != *b++) return 0; - if (*a || *b) - return 0; - return 1; -} - -static char *service_manager_context; -static struct selabel_handle* sehandle; - -static bool check_mac_perms(pid_t spid, const char* sid, uid_t uid, const char *tctx, const char *perm, const char *name) -{ - char *lookup_sid = NULL; - const char *class = "service_manager"; - bool allowed; - struct audit_data ad; - - if (sid == NULL && getpidcon(spid, &lookup_sid) < 0) { - ALOGE("SELinux: getpidcon(pid=%d) failed to retrieve pid context.\n", spid); - return false; - } - - ad.pid = spid; - ad.uid = uid; - ad.name = name; - - if (sid == NULL) { - android_errorWriteLog(0x534e4554, "121035042"); - } - - int result = selinux_check_access(sid ? sid : lookup_sid, tctx, class, perm, (void *) &ad); - allowed = (result == 0); - - freecon(lookup_sid); - return allowed; -} - -static bool check_mac_perms_from_getcon(pid_t spid, const char* sid, uid_t uid, const char *perm) -{ - return check_mac_perms(spid, sid, uid, service_manager_context, perm, NULL); -} - -static bool check_mac_perms_from_lookup(pid_t spid, const char* sid, uid_t uid, const char *perm, const char *name) -{ - bool allowed; - char *tctx = NULL; - - if (!sehandle) { - ALOGE("SELinux: Failed to find sehandle. Aborting service_manager.\n"); - abort(); - } - - if (selabel_lookup(sehandle, &tctx, name, 0) != 0) { - ALOGE("SELinux: No match for %s in service_contexts.\n", name); - return false; - } - - allowed = check_mac_perms(spid, sid, uid, tctx, perm, name); - freecon(tctx); - return allowed; -} - -static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid, const char* sid, uid_t uid) -{ - const char *perm = "add"; - - if (multiuser_get_app_id(uid) >= AID_APP) { - return 0; /* Don't allow apps to register services */ - } - - return check_mac_perms_from_lookup(spid, sid, uid, perm, str8(name, name_len)) ? 1 : 0; -} - -static int svc_can_list(pid_t spid, const char* sid, uid_t uid) -{ - const char *perm = "list"; - return check_mac_perms_from_getcon(spid, sid, uid, perm) ? 1 : 0; -} - -static int svc_can_find(const uint16_t *name, size_t name_len, pid_t spid, const char* sid, uid_t uid) -{ - const char *perm = "find"; - return check_mac_perms_from_lookup(spid, sid, uid, perm, str8(name, name_len)) ? 1 : 0; -} - -struct svcinfo -{ - struct svcinfo *next; - uint32_t handle; - struct binder_death death; - int allow_isolated; - uint32_t dumpsys_priority; - size_t len; - uint16_t name[0]; -}; - -struct svcinfo *svclist = NULL; - -struct svcinfo *find_svc(const uint16_t *s16, size_t len) -{ - struct svcinfo *si; - - for (si = svclist; si; si = si->next) { - if ((len == si->len) && - !memcmp(s16, si->name, len * sizeof(uint16_t))) { - return si; - } - } - return NULL; -} - -void svcinfo_death(struct binder_state *bs, void *ptr) -{ - struct svcinfo *si = (struct svcinfo* ) ptr; - - ALOGI("service '%s' died\n", str8(si->name, si->len)); - if (si->handle) { - binder_release(bs, si->handle); - si->handle = 0; - } -} - -uint16_t svcmgr_id[] = { - 'a','n','d','r','o','i','d','.','o','s','.', - 'I','S','e','r','v','i','c','e','M','a','n','a','g','e','r' -}; - - -uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid, const char* sid) -{ - struct svcinfo *si = find_svc(s, len); - - if (!si || !si->handle) { - return 0; - } - - if (!si->allow_isolated) { - // If this service doesn't allow access from isolated processes, - // then check the uid to see if it is isolated. - uid_t appid = uid % AID_USER; - if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) { - return 0; - } - } - - if (!svc_can_find(s, len, spid, sid, uid)) { - return 0; - } - - return si->handle; -} - -int do_add_service(struct binder_state *bs, const uint16_t *s, size_t len, uint32_t handle, - uid_t uid, int allow_isolated, uint32_t dumpsys_priority, pid_t spid, const char* sid) { - struct svcinfo *si; - - //ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s, len), handle, - // allow_isolated ? "allow_isolated" : "!allow_isolated", uid); - - if (!handle || (len == 0) || (len > 127)) - return -1; - - if (!svc_can_register(s, len, spid, sid, uid)) { - ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n", - str8(s, len), handle, uid); - return -1; - } - - si = find_svc(s, len); - if (si) { - if (si->handle) { - ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n", - str8(s, len), handle, uid); - svcinfo_death(bs, si); - } - si->handle = handle; - } else { - si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t)); - if (!si) { - ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n", - str8(s, len), handle, uid); - return -1; - } - si->handle = handle; - si->len = len; - memcpy(si->name, s, (len + 1) * sizeof(uint16_t)); - si->name[len] = '\0'; - si->death.func = (void*) svcinfo_death; - si->death.ptr = si; - si->allow_isolated = allow_isolated; - si->dumpsys_priority = dumpsys_priority; - si->next = svclist; - svclist = si; - } - - binder_acquire(bs, handle); - binder_link_to_death(bs, handle, &si->death); - return 0; -} - -int svcmgr_handler(struct binder_state *bs, - struct binder_transaction_data_secctx *txn_secctx, - struct binder_io *msg, - struct binder_io *reply) -{ - struct svcinfo *si; - uint16_t *s; - size_t len; - uint32_t handle; - uint32_t strict_policy; - int allow_isolated; - uint32_t dumpsys_priority; - - struct binder_transaction_data *txn = &txn_secctx->transaction_data; - - //ALOGI("target=%p code=%d pid=%d uid=%d\n", - // (void*) txn->target.ptr, txn->code, txn->sender_pid, txn->sender_euid); - - if (txn->target.ptr != BINDER_SERVICE_MANAGER) - return -1; - - if (txn->code == PING_TRANSACTION) - return 0; - - // Equivalent to Parcel::enforceInterface(), reading the RPC - // header with the strict mode policy mask and the interface name. - // Note that we ignore the strict_policy and don't propagate it - // further (since we do no outbound RPCs anyway). - strict_policy = bio_get_uint32(msg); - bio_get_uint32(msg); // Ignore worksource header. - s = bio_get_string16(msg, &len); - if (s == NULL) { - return -1; - } - - if ((len != (sizeof(svcmgr_id) / 2)) || - memcmp(svcmgr_id, s, sizeof(svcmgr_id))) { - fprintf(stderr,"invalid id %s\n", str8(s, len)); - return -1; - } - - if (sehandle && selinux_status_updated() > 0) { -#ifdef VENDORSERVICEMANAGER - struct selabel_handle *tmp_sehandle = selinux_android_vendor_service_context_handle(); -#else - struct selabel_handle *tmp_sehandle = selinux_android_service_context_handle(); -#endif - if (tmp_sehandle) { - selabel_close(sehandle); - sehandle = tmp_sehandle; - } - } - - switch(txn->code) { - case SVC_MGR_GET_SERVICE: - case SVC_MGR_CHECK_SERVICE: - s = bio_get_string16(msg, &len); - if (s == NULL) { - return -1; - } - handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid, - (const char*) txn_secctx->secctx); - if (!handle) - break; - bio_put_ref(reply, handle); - return 0; - - case SVC_MGR_ADD_SERVICE: - s = bio_get_string16(msg, &len); - if (s == NULL) { - return -1; - } - handle = bio_get_ref(msg); - allow_isolated = bio_get_uint32(msg) ? 1 : 0; - dumpsys_priority = bio_get_uint32(msg); - if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority, - txn->sender_pid, (const char*) txn_secctx->secctx)) - return -1; - break; - - case SVC_MGR_LIST_SERVICES: { - uint32_t n = bio_get_uint32(msg); - uint32_t req_dumpsys_priority = bio_get_uint32(msg); - - if (!svc_can_list(txn->sender_pid, (const char*) txn_secctx->secctx, txn->sender_euid)) { - ALOGE("list_service() uid=%d - PERMISSION DENIED\n", - txn->sender_euid); - return -1; - } - si = svclist; - // walk through the list of services n times skipping services that - // do not support the requested priority - while (si) { - if (si->dumpsys_priority & req_dumpsys_priority) { - if (n == 0) break; - n--; - } - si = si->next; - } - if (si) { - bio_put_string16(reply, si->name); - return 0; - } - return -1; - } - default: - ALOGE("unknown code %d\n", txn->code); - return -1; - } - - bio_put_uint32(reply, 0); - return 0; -} - - -static int audit_callback(void *data, __unused security_class_t cls, char *buf, size_t len) -{ - struct audit_data *ad = (struct audit_data *)data; - - if (!ad || !ad->name) { - ALOGE("No service manager audit data"); - return 0; - } - - snprintf(buf, len, "service=%s pid=%d uid=%d", ad->name, ad->pid, ad->uid); - return 0; -} - -int main(int argc, char** argv) -{ - struct binder_state *bs; - union selinux_callback cb; - char *driver; - - if (argc > 1) { - driver = argv[1]; - } else { - driver = "/dev/binder"; - } - - bs = binder_open(driver, 128*1024); - if (!bs) { -#ifdef VENDORSERVICEMANAGER - ALOGW("failed to open binder driver %s\n", driver); - while (true) { - sleep(UINT_MAX); - } -#else - ALOGE("failed to open binder driver %s\n", driver); -#endif - return -1; - } - - if (binder_become_context_manager(bs)) { - ALOGE("cannot become context manager (%s)\n", strerror(errno)); - return -1; - } - - cb.func_audit = audit_callback; - selinux_set_callback(SELINUX_CB_AUDIT, cb); -#ifdef VENDORSERVICEMANAGER - cb.func_log = selinux_vendor_log_callback; -#else - cb.func_log = selinux_log_callback; -#endif - selinux_set_callback(SELINUX_CB_LOG, cb); - -#ifdef VENDORSERVICEMANAGER - sehandle = selinux_android_vendor_service_context_handle(); -#else - sehandle = selinux_android_service_context_handle(); -#endif - selinux_status_open(true); - - if (sehandle == NULL) { - ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n"); - abort(); - } - - if (getcon(&service_manager_context) != 0) { - ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n"); - abort(); - } - - - binder_loop(bs, svcmgr_handler); - - return 0; -} diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp new file mode 100644 index 0000000000..812d5cacd5 --- /dev/null +++ b/cmds/servicemanager/test_sm.cpp @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2019 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 <binder/ProcessState.h> +#include <cutils/android_filesystem_config.h> +#include <gtest/gtest.h> +#include <gmock/gmock.h> + +#include "Access.h" +#include "ServiceManager.h" + +using android::sp; +using android::Access; +using android::IBinder; +using android::ServiceManager; +using android::os::IServiceManager; +using testing::_; +using testing::ElementsAre; +using testing::NiceMock; +using testing::Return; + +static sp<IBinder> getBinder() { + // It doesn't matter what remote binder it is, we just need one so that linkToDeath will work. + // The context manager (servicemanager) is easy to get and is in another process. + return android::ProcessState::self()->getContextObject(nullptr); +} + +class MockAccess : public Access { +public: + MOCK_METHOD1(getCallingContext, CallingContext(const std::string& name)); + MOCK_METHOD1(canAdd, bool(const CallingContext&)); + MOCK_METHOD1(canFind, bool(const CallingContext&)); + MOCK_METHOD1(canList, bool(const CallingContext&)); +}; + +static sp<ServiceManager> getPermissiveServiceManager() { + std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); + + ON_CALL(*access, getCallingContext(_)).WillByDefault(Return(Access::CallingContext{})); + ON_CALL(*access, canAdd(_)).WillByDefault(Return(true)); + ON_CALL(*access, canFind(_)).WillByDefault(Return(true)); + ON_CALL(*access, canList(_)).WillByDefault(Return(true)); + + sp<ServiceManager> sm = new ServiceManager(std::move(access)); + return sm; +} + +TEST(AddService, HappyHappy) { + auto sm = getPermissiveServiceManager(); + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, EmptyNameDisallowed) { + auto sm = getPermissiveServiceManager(); + EXPECT_FALSE(sm->addService("", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, JustShortEnoughServiceNameHappy) { + auto sm = getPermissiveServiceManager(); + EXPECT_TRUE(sm->addService(std::string(127, 'a'), getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, TooLongNameDisallowed) { + auto sm = getPermissiveServiceManager(); + EXPECT_FALSE(sm->addService(std::string(128, 'a'), getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, AddNullServiceDisallowed) { + auto sm = getPermissiveServiceManager(); + EXPECT_FALSE(sm->addService("foo", nullptr, false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, AddDisallowedFromApp) { + for (uid_t uid : { AID_APP_START, AID_APP_START + 1, AID_APP_END }) { + std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); + EXPECT_CALL(*access, getCallingContext(_)).WillOnce(Return(Access::CallingContext{ + .debugPid = 1337, + .uid = uid, + })); + EXPECT_CALL(*access, canAdd(_)).Times(0); + sp<ServiceManager> sm = new ServiceManager(std::move(access)); + + EXPECT_FALSE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + } + +} + +TEST(AddService, HappyOverExistingService) { + auto sm = getPermissiveServiceManager(); + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(AddService, NoPermissions) { + std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); + + EXPECT_CALL(*access, getCallingContext(_)).WillOnce(Return(Access::CallingContext{})); + EXPECT_CALL(*access, canAdd(_)).WillOnce(Return(false)); + + sp<ServiceManager> sm = new ServiceManager(std::move(access)); + + EXPECT_FALSE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); +} + +TEST(GetService, HappyHappy) { + auto sm = getPermissiveServiceManager(); + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + + sp<IBinder> out; + EXPECT_TRUE(sm->getService("foo", &out).isOk()); + EXPECT_EQ(getBinder(), out); +} + +TEST(GetService, NonExistant) { + auto sm = getPermissiveServiceManager(); + + sp<IBinder> out; + EXPECT_TRUE(sm->getService("foo", &out).isOk()); + EXPECT_EQ(nullptr, out.get()); +} + +TEST(GetService, NoPermissionsForGettingService) { + std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); + + EXPECT_CALL(*access, getCallingContext(_)).WillRepeatedly(Return(Access::CallingContext{})); + EXPECT_CALL(*access, canAdd(_)).WillOnce(Return(true)); + EXPECT_CALL(*access, canFind(_)).WillOnce(Return(false)); + + sp<ServiceManager> sm = new ServiceManager(std::move(access)); + + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + + sp<IBinder> out; + // returns nullptr but has OK status for legacy compatibility + EXPECT_TRUE(sm->getService("foo", &out).isOk()); + EXPECT_EQ(nullptr, out.get()); +} + +TEST(GetService, AllowedFromIsolated) { + std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); + + EXPECT_CALL(*access, getCallingContext(_)) + // something adds it + .WillOnce(Return(Access::CallingContext{})) + // next call is from isolated app + .WillOnce(Return(Access::CallingContext{ + .uid = AID_ISOLATED_START, + })); + EXPECT_CALL(*access, canAdd(_)).WillOnce(Return(true)); + EXPECT_CALL(*access, canFind(_)).WillOnce(Return(true)); + + sp<ServiceManager> sm = new ServiceManager(std::move(access)); + + EXPECT_TRUE(sm->addService("foo", getBinder(), true /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + + sp<IBinder> out; + EXPECT_TRUE(sm->getService("foo", &out).isOk()); + EXPECT_EQ(getBinder(), out.get()); +} + +TEST(GetService, NotAllowedFromIsolated) { + std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); + + EXPECT_CALL(*access, getCallingContext(_)) + // something adds it + .WillOnce(Return(Access::CallingContext{})) + // next call is from isolated app + .WillOnce(Return(Access::CallingContext{ + .uid = AID_ISOLATED_START, + })); + EXPECT_CALL(*access, canAdd(_)).WillOnce(Return(true)); + + // TODO(b/136023468): when security check is first, this should be called first + // EXPECT_CALL(*access, canFind(_)).WillOnce(Return(true)); + + sp<ServiceManager> sm = new ServiceManager(std::move(access)); + + EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + + sp<IBinder> out; + // returns nullptr but has OK status for legacy compatibility + EXPECT_TRUE(sm->getService("foo", &out).isOk()); + EXPECT_EQ(nullptr, out.get()); +} + +TEST(ListServices, NoPermissions) { + std::unique_ptr<MockAccess> access = std::make_unique<NiceMock<MockAccess>>(); + + EXPECT_CALL(*access, getCallingContext(_)).WillOnce(Return(Access::CallingContext{})); + EXPECT_CALL(*access, canList(_)).WillOnce(Return(false)); + + sp<ServiceManager> sm = new ServiceManager(std::move(access)); + + std::vector<std::string> out; + EXPECT_FALSE(sm->listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL, &out).isOk()); + EXPECT_TRUE(out.empty()); +} + +TEST(ListServices, AllServices) { + auto sm = getPermissiveServiceManager(); + + EXPECT_TRUE(sm->addService("sd", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + EXPECT_TRUE(sm->addService("sc", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_NORMAL).isOk()); + EXPECT_TRUE(sm->addService("sb", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_HIGH).isOk()); + EXPECT_TRUE(sm->addService("sa", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL).isOk()); + + std::vector<std::string> out; + EXPECT_TRUE(sm->listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL, &out).isOk()); + + // all there and in the right order + EXPECT_THAT(out, ElementsAre("sa", "sb", "sc", "sd")); +} + +TEST(ListServices, CriticalServices) { + auto sm = getPermissiveServiceManager(); + + EXPECT_TRUE(sm->addService("sd", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); + EXPECT_TRUE(sm->addService("sc", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_NORMAL).isOk()); + EXPECT_TRUE(sm->addService("sb", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_HIGH).isOk()); + EXPECT_TRUE(sm->addService("sa", getBinder(), false /*allowIsolated*/, + IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL).isOk()); + + std::vector<std::string> out; + EXPECT_TRUE(sm->listServices(IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL, &out).isOk()); + + // all there and in the right order + EXPECT_THAT(out, ElementsAre("sa")); +} diff --git a/include/android/surface_control.h b/include/android/surface_control.h index ef2ad9998c..abb8368069 100644 --- a/include/android/surface_control.h +++ b/include/android/surface_control.h @@ -130,7 +130,7 @@ int64_t ASurfaceTransactionStats_getLatchTime(ASurfaceTransactionStats* surface_ /** * Returns a sync fence that signals when the transaction has been presented. * The recipient of the callback takes ownership of the fence and is responsible for closing - * it. + * it. If a device does not support present fences, a -1 will be returned. */ int ASurfaceTransactionStats_getPresentFenceFd(ASurfaceTransactionStats* surface_transaction_stats) __INTRODUCED_IN(29); diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 905b25f397..760d55b751 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -94,7 +94,6 @@ cc_library_shared { "PermissionController.cpp", "ProcessInfoService.cpp", "IpPrefix.cpp", - ":libbinder_aidl", ], }, }, @@ -142,8 +141,7 @@ filegroup { name: "libbinder_aidl", srcs: [ "aidl/android/content/pm/IPackageManagerNative.aidl", + "aidl/android/os/IServiceManager.aidl", ], path: "aidl", } - -subdirs = ["tests"] diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index a2d10ab0ab..3424c28883 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -1062,7 +1062,7 @@ status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags, sp<BBinder> the_context_object; -void setTheContextObject(sp<BBinder> obj) +void IPCThreadState::setTheContextObject(sp<BBinder> obj) { the_context_object = obj; } diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index 0203d41992..07550fb571 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -18,6 +18,7 @@ #include <binder/IServiceManager.h> +#include <android/os/IServiceManager.h> #include <utils/Log.h> #include <binder/IPCThreadState.h> #ifndef __ANDROID_VNDK__ @@ -34,6 +35,9 @@ namespace android { +using AidlServiceManager = android::os::IServiceManager; +using android::binder::Status; + sp<IServiceManager> defaultServiceManager() { static Mutex gDefaultServiceManagerLock; @@ -142,11 +146,12 @@ class BpServiceManager : public BpInterface<IServiceManager> { public: explicit BpServiceManager(const sp<IBinder>& impl) - : BpInterface<IServiceManager>(impl) + : BpInterface<IServiceManager>(impl), + mTheRealServiceManager(interface_cast<AidlServiceManager>(impl)) { } - virtual sp<IBinder> getService(const String16& name) const + sp<IBinder> getService(const String16& name) const override { static bool gSystemBootCompleted = false; @@ -179,43 +184,36 @@ public: return nullptr; } - virtual sp<IBinder> checkService( const String16& name) const - { - Parcel data, reply; - data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); - data.writeString16(name); - remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply); - return reply.readStrongBinder(); + sp<IBinder> checkService(const String16& name) const override { + sp<IBinder> ret; + if (!mTheRealServiceManager->checkService(String8(name).c_str(), &ret).isOk()) { + return nullptr; + } + return ret; } - virtual status_t addService(const String16& name, const sp<IBinder>& service, - bool allowIsolated, int dumpsysPriority) { - Parcel data, reply; - data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); - data.writeString16(name); - data.writeStrongBinder(service); - data.writeInt32(allowIsolated ? 1 : 0); - data.writeInt32(dumpsysPriority); - status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply); - return err == NO_ERROR ? reply.readExceptionCode() : err; + status_t addService(const String16& name, const sp<IBinder>& service, + bool allowIsolated, int dumpsysPriority) override { + Status status = mTheRealServiceManager->addService(String8(name).c_str(), service, allowIsolated, dumpsysPriority); + return status.exceptionCode(); } virtual Vector<String16> listServices(int dumpsysPriority) { - Vector<String16> res; - int n = 0; + std::vector<std::string> ret; + if (!mTheRealServiceManager->listServices(dumpsysPriority, &ret).isOk()) { + return {}; + } - for (;;) { - Parcel data, reply; - data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); - data.writeInt32(n++); - data.writeInt32(dumpsysPriority); - status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply); - if (err != NO_ERROR) - break; - res.add(reply.readString16()); + Vector<String16> res; + res.setCapacity(ret.size()); + for (const std::string& name : ret) { + res.push(String16(name.c_str())); } return res; } + +private: + sp<AidlServiceManager> mTheRealServiceManager; }; IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager"); diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 458961b70d..c389d18243 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -616,7 +616,7 @@ bool Parcel::replaceCallingWorkSourceUid(uid_t uid) return err == NO_ERROR; } -uid_t Parcel::readCallingWorkSourceUid() +uid_t Parcel::readCallingWorkSourceUid() const { if (!mRequestHeaderPresent) { return IPCThreadState::kUnsetWorkSource; diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl new file mode 100644 index 0000000000..50a72aa9e4 --- /dev/null +++ b/libs/binder/aidl/android/os/IServiceManager.aidl @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2006 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.os; + +/** + * Basic interface for finding and publishing system services. + * + * You likely want to use android.os.ServiceManager in Java or + * android::IServiceManager in C++ in order to use this interface. + * + * @hide + */ +interface IServiceManager { + /* + * Must update values in IServiceManager.h + */ + /* Allows services to dump sections according to priorities. */ + const int DUMP_FLAG_PRIORITY_CRITICAL = 1; // 1 << 0 + const int DUMP_FLAG_PRIORITY_HIGH = 2; // 1 << 1 + const int DUMP_FLAG_PRIORITY_NORMAL = 4; // 1 << 2 + /** + * Services are by default registered with a DEFAULT dump priority. DEFAULT priority has the + * same priority as NORMAL priority but the services are not called with dump priority + * arguments. + */ + const int DUMP_FLAG_PRIORITY_DEFAULT = 8; // 1 << 3 + + const int DUMP_FLAG_PRIORITY_ALL = 15; + // DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_HIGH + // | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PRIORITY_DEFAULT; + + /* Allows services to dump sections in protobuf format. */ + const int DUMP_FLAG_PROTO = 16; // 1 << 4 + + /** + * Retrieve an existing service called @a name from the + * service manager. + * + * This is the same as checkService (returns immediately) but + * exists for legacy purposes. + * + * Returns null if the service does not exist. + */ + @UnsupportedAppUsage + IBinder getService(@utf8InCpp String name); + + /** + * Retrieve an existing service called @a name from the service + * manager. Non-blocking. Returns null if the service does not + * exist. + */ + @UnsupportedAppUsage + IBinder checkService(@utf8InCpp String name); + + /** + * Place a new @a service called @a name into the service + * manager. + */ + void addService(@utf8InCpp String name, IBinder service, + boolean allowIsolated, int dumpPriority); + + /** + * Return a list of all currently running services. + */ + @utf8InCpp String[] listServices(int dumpPriority); +} diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h index 614b0b33dd..b810f7e8ee 100644 --- a/libs/binder/include/binder/IPCThreadState.h +++ b/libs/binder/include/binder/IPCThreadState.h @@ -110,6 +110,8 @@ public: // the maximum number of binder threads threads allowed for this process. void blockUntilThreadAvailable(); + // Service manager registration + void setTheContextObject(sp<BBinder> obj); // Is this thread currently serving a binder call. This method // returns true if while traversing backwards from the function call diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index 0cdabb0265..0046e3ae85 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -399,7 +399,7 @@ public: bool replaceCallingWorkSourceUid(uid_t uid); // Returns the work source provided by the caller. This can only be trusted for trusted calling // uid. - uid_t readCallingWorkSourceUid(); + uid_t readCallingWorkSourceUid() const; void readRequestHeaders() const; private: diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp index 5fd4a95d7b..41cbde1c18 100644 --- a/libs/cputimeinstate/cputimeinstate.cpp +++ b/libs/cputimeinstate/cputimeinstate.cpp @@ -23,6 +23,7 @@ #include <inttypes.h> #include <mutex> +#include <optional> #include <set> #include <string> #include <unordered_map> @@ -62,19 +63,20 @@ static std::vector<std::vector<uint32_t>> gPolicyCpus; static std::set<uint32_t> gAllFreqs; static unique_fd gMapFd; -static bool readNumbersFromFile(const std::string &path, std::vector<uint32_t> *out) { +static std::optional<std::vector<uint32_t>> readNumbersFromFile(const std::string &path) { std::string data; - if (!android::base::ReadFileToString(path, &data)) return false; + if (!android::base::ReadFileToString(path, &data)) return {}; auto strings = android::base::Split(data, " \n"); + std::vector<uint32_t> ret; for (const auto &s : strings) { if (s.empty()) continue; uint32_t n; - if (!android::base::ParseUint(s, &n)) return false; - out->emplace_back(n); + if (!android::base::ParseUint(s, &n)) return {}; + ret.emplace_back(n); } - return true; + return ret; } static int isPolicyFile(const struct dirent *d) { @@ -111,20 +113,22 @@ static bool initGlobals() { for (const auto &name : {"available", "boost"}) { std::string path = StringPrintf("%s/%s/scaling_%s_frequencies", basepath, policy.c_str(), name); - if (!readNumbersFromFile(path, &freqs)) return false; + auto nums = readNumbersFromFile(path); + if (!nums) return false; + freqs.insert(freqs.end(), nums->begin(), nums->end()); } std::sort(freqs.begin(), freqs.end()); gPolicyFreqs.emplace_back(freqs); for (auto freq : freqs) gAllFreqs.insert(freq); - std::vector<uint32_t> cpus; std::string path = StringPrintf("%s/%s/%s", basepath, policy.c_str(), "related_cpus"); - if (!readNumbersFromFile(path, &cpus)) return false; - gPolicyCpus.emplace_back(cpus); + auto cpus = readNumbersFromFile(path); + if (!cpus) return false; + gPolicyCpus.emplace_back(*cpus); } - gMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times")}; + gMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times_map")}; if (gMapFd < 0) return false; gInitialized = true; @@ -151,17 +155,15 @@ bool startTrackingUidCpuFreqTimes() { } // Retrieve the times in ns that uid spent running at each CPU frequency and store in freqTimes. -// Returns false on error. Otherwise, returns true and populates freqTimes with a vector of vectors -// using the format: +// Return contains no value on error, otherwise it contains a vector of vectors using the format: // [[t0_0, t0_1, ...], // [t1_0, t1_1, ...], ...] // where ti_j is the ns that uid spent running on the ith cluster at that cluster's jth lowest freq. -bool getUidCpuFreqTimes(uint32_t uid, std::vector<std::vector<uint64_t>> *freqTimes) { - if (!gInitialized && !initGlobals()) return false; +std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t uid) { + if (!gInitialized && !initGlobals()) return {}; time_key_t key = {.uid = uid, .freq = 0}; - freqTimes->clear(); - freqTimes->resize(gNPolicies); + std::vector<std::vector<uint64_t>> out(gNPolicies); std::vector<uint32_t> idxs(gNPolicies, 0); val_t value; @@ -172,32 +174,32 @@ bool getUidCpuFreqTimes(uint32_t uid, std::vector<std::vector<uint64_t>> *freqTi if (errno == ENOENT) memset(&value.ar, 0, sizeof(value.ar)); else - return false; + return {}; } for (uint32_t i = 0; i < gNPolicies; ++i) { if (idxs[i] == gPolicyFreqs[i].size() || freq != gPolicyFreqs[i][idxs[i]]) continue; uint64_t time = 0; for (uint32_t cpu : gPolicyCpus[i]) time += value.ar[cpu]; idxs[i] += 1; - (*freqTimes)[i].emplace_back(time); + out[i].emplace_back(time); } } - return true; + return out; } // Retrieve the times in ns that each uid spent running at each CPU freq and store in freqTimeMap. -// Returns false on error. Otherwise, returns true and populates freqTimeMap with a map from uids to -// vectors of vectors using the format: +// Return contains no value on error, otherwise it contains a map from uids to vectors of vectors +// using the format: // { uid0 -> [[t0_0_0, t0_0_1, ...], [t0_1_0, t0_1_1, ...], ...], // uid1 -> [[t1_0_0, t1_0_1, ...], [t1_1_0, t1_1_1, ...], ...], ... } // where ti_j_k is the ns uid i spent running on the jth cluster at the cluster's kth lowest freq. -bool getUidsCpuFreqTimes( - std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> *freqTimeMap) { - if (!gInitialized && !initGlobals()) return false; +std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>> +getUidsCpuFreqTimes() { + if (!gInitialized && !initGlobals()) return {}; - int fd = bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times"); - if (fd < 0) return false; + int fd = bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times_map"); + if (fd < 0) return {}; BpfMap<time_key_t, val_t> m(fd); std::vector<std::unordered_map<uint32_t, uint32_t>> policyFreqIdxs; @@ -206,25 +208,26 @@ bool getUidsCpuFreqTimes( for (size_t j = 0; j < gPolicyFreqs[i].size(); ++j) freqIdxs[gPolicyFreqs[i][j]] = j; policyFreqIdxs.emplace_back(freqIdxs); } - - auto fn = [freqTimeMap, &policyFreqIdxs](const time_key_t &key, const val_t &val, + std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> map; + auto fn = [&map, &policyFreqIdxs](const time_key_t &key, const val_t &val, const BpfMap<time_key_t, val_t> &) { - if (freqTimeMap->find(key.uid) == freqTimeMap->end()) { - (*freqTimeMap)[key.uid].resize(gNPolicies); + if (map.find(key.uid) == map.end()) { + map[key.uid].resize(gNPolicies); for (uint32_t i = 0; i < gNPolicies; ++i) { - (*freqTimeMap)[key.uid][i].resize(gPolicyFreqs[i].size(), 0); + map[key.uid][i].resize(gPolicyFreqs[i].size(), 0); } } for (size_t policy = 0; policy < gNPolicies; ++policy) { for (const auto &cpu : gPolicyCpus[policy]) { auto freqIdx = policyFreqIdxs[policy][key.freq]; - (*freqTimeMap)[key.uid][policy][freqIdx] += val.ar[cpu]; + map[key.uid][policy][freqIdx] += val.ar[cpu]; } } return android::netdutils::status::ok; }; - return isOk(m.iterateWithValue(fn)); + if (isOk(m.iterateWithValue(fn))) return map; + return {}; } // Clear all time in state data for a given uid. Returns false on error, true otherwise. diff --git a/libs/cputimeinstate/cputimeinstate.h b/libs/cputimeinstate/cputimeinstate.h index 9f6103ed9b..d7b45870ac 100644 --- a/libs/cputimeinstate/cputimeinstate.h +++ b/libs/cputimeinstate/cputimeinstate.h @@ -23,8 +23,9 @@ namespace android { namespace bpf { bool startTrackingUidCpuFreqTimes(); -bool getUidCpuFreqTimes(unsigned int uid, std::vector<std::vector<uint64_t>> *freqTimes); -bool getUidsCpuFreqTimes(std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> *tisMap); +std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t uid); +std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>> + getUidsCpuFreqTimes(); bool clearUidCpuFreqTimes(unsigned int uid); } // namespace bpf diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp index 9837865dfb..d4b87386e0 100644 --- a/libs/cputimeinstate/testtimeinstate.cpp +++ b/libs/cputimeinstate/testtimeinstate.cpp @@ -12,45 +12,46 @@ namespace bpf { using std::vector; TEST(TimeInStateTest, SingleUid) { - vector<vector<uint64_t>> times; - ASSERT_TRUE(getUidCpuFreqTimes(0, ×)); - EXPECT_FALSE(times.empty()); + auto times = getUidCpuFreqTimes(0); + ASSERT_TRUE(times.has_value()); + EXPECT_FALSE(times->empty()); } TEST(TimeInStateTest, AllUid) { vector<size_t> sizes; - std::unordered_map<uint32_t, vector<vector<uint64_t>>> map; - ASSERT_TRUE(getUidsCpuFreqTimes(&map)); + auto map = getUidsCpuFreqTimes(); + ASSERT_TRUE(map.has_value()); - ASSERT_FALSE(map.empty()); + ASSERT_FALSE(map->empty()); - auto firstEntry = map.begin()->second; + auto firstEntry = map->begin()->second; for (const auto &subEntry : firstEntry) sizes.emplace_back(subEntry.size()); - for (const auto &vec : map) { + for (const auto &vec : *map) { ASSERT_EQ(vec.second.size(), sizes.size()); for (size_t i = 0; i < vec.second.size(); ++i) ASSERT_EQ(vec.second[i].size(), sizes[i]); } } TEST(TimeInStateTest, RemoveUid) { - vector<vector<uint64_t>> times, times2; - ASSERT_TRUE(getUidCpuFreqTimes(0, ×)); - ASSERT_FALSE(times.empty()); + auto times = getUidCpuFreqTimes(0); + ASSERT_TRUE(times.has_value()); + ASSERT_FALSE(times->empty()); uint64_t sum = 0; - for (size_t i = 0; i < times.size(); ++i) { - for (auto x : times[i]) sum += x; + for (size_t i = 0; i < times->size(); ++i) { + for (auto x : (*times)[i]) sum += x; } ASSERT_GT(sum, (uint64_t)0); ASSERT_TRUE(clearUidCpuFreqTimes(0)); - ASSERT_TRUE(getUidCpuFreqTimes(0, ×2)); - ASSERT_EQ(times2.size(), times.size()); - for (size_t i = 0; i < times.size(); ++i) { - ASSERT_EQ(times2[i].size(), times[i].size()); - for (size_t j = 0; j < times[i].size(); ++j) ASSERT_LE(times2[i][j], times[i][j]); + auto times2 = getUidCpuFreqTimes(0); + ASSERT_TRUE(times2.has_value()); + ASSERT_EQ(times2->size(), times->size()); + for (size_t i = 0; i < times->size(); ++i) { + ASSERT_EQ((*times2)[i].size(), (*times)[i].size()); + for (size_t j = 0; j < (*times)[i].size(); ++j) ASSERT_LE((*times2)[i][j], (*times)[i][j]); } } diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 24b6c2d6de..a411dd56f6 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -170,11 +170,11 @@ void GraphicsEnv::hintActivityLaunch() { std::lock_guard<std::mutex> lock(mStatsLock); if (mGpuStats.glDriverToSend) { mGpuStats.glDriverToSend = false; - sendGpuStatsLocked(GraphicsEnv::Api::API_GL, true, mGpuStats.glDriverLoadingTime); + sendGpuStatsLocked(GpuStatsInfo::Api::API_GL, true, mGpuStats.glDriverLoadingTime); } if (mGpuStats.vkDriverToSend) { mGpuStats.vkDriverToSend = false; - sendGpuStatsLocked(GraphicsEnv::Api::API_VK, true, mGpuStats.vkDriverLoadingTime); + sendGpuStatsLocked(GpuStatsInfo::Api::API_VK, true, mGpuStats.vkDriverLoadingTime); } }); trySendGpuStatsThread.detach(); @@ -205,32 +205,32 @@ void GraphicsEnv::setGpuStats(const std::string& driverPackageName, mGpuStats.vulkanVersion = vulkanVersion; } -void GraphicsEnv::setDriverToLoad(GraphicsEnv::Driver driver) { +void GraphicsEnv::setDriverToLoad(GpuStatsInfo::Driver driver) { ATRACE_CALL(); std::lock_guard<std::mutex> lock(mStatsLock); switch (driver) { - case GraphicsEnv::Driver::GL: - case GraphicsEnv::Driver::GL_UPDATED: - case GraphicsEnv::Driver::ANGLE: { - if (mGpuStats.glDriverToLoad == GraphicsEnv::Driver::NONE) { + case GpuStatsInfo::Driver::GL: + case GpuStatsInfo::Driver::GL_UPDATED: + case GpuStatsInfo::Driver::ANGLE: { + if (mGpuStats.glDriverToLoad == GpuStatsInfo::Driver::NONE) { mGpuStats.glDriverToLoad = driver; break; } - if (mGpuStats.glDriverFallback == GraphicsEnv::Driver::NONE) { + if (mGpuStats.glDriverFallback == GpuStatsInfo::Driver::NONE) { mGpuStats.glDriverFallback = driver; } break; } - case Driver::VULKAN: - case Driver::VULKAN_UPDATED: { - if (mGpuStats.vkDriverToLoad == GraphicsEnv::Driver::NONE) { + case GpuStatsInfo::Driver::VULKAN: + case GpuStatsInfo::Driver::VULKAN_UPDATED: { + if (mGpuStats.vkDriverToLoad == GpuStatsInfo::Driver::NONE) { mGpuStats.vkDriverToLoad = driver; break; } - if (mGpuStats.vkDriverFallback == GraphicsEnv::Driver::NONE) { + if (mGpuStats.vkDriverFallback == GpuStatsInfo::Driver::NONE) { mGpuStats.vkDriverFallback = driver; } break; @@ -240,13 +240,13 @@ void GraphicsEnv::setDriverToLoad(GraphicsEnv::Driver driver) { } } -void GraphicsEnv::setDriverLoaded(GraphicsEnv::Api api, bool isDriverLoaded, +void GraphicsEnv::setDriverLoaded(GpuStatsInfo::Api api, bool isDriverLoaded, int64_t driverLoadingTime) { ATRACE_CALL(); std::lock_guard<std::mutex> lock(mStatsLock); const bool doNotSend = mGpuStats.appPackageName.empty(); - if (api == GraphicsEnv::Api::API_GL) { + if (api == GpuStatsInfo::Api::API_GL) { if (doNotSend) mGpuStats.glDriverToSend = true; mGpuStats.glDriverLoadingTime = driverLoadingTime; } else { @@ -278,7 +278,7 @@ void GraphicsEnv::setCpuVulkanInUse() { } } -void GraphicsEnv::sendGpuStatsLocked(GraphicsEnv::Api api, bool isDriverLoaded, +void GraphicsEnv::sendGpuStatsLocked(GpuStatsInfo::Api api, bool isDriverLoaded, int64_t driverLoadingTime) { ATRACE_CALL(); @@ -299,16 +299,16 @@ void GraphicsEnv::sendGpuStatsLocked(GraphicsEnv::Api api, bool isDriverLoaded, mGpuStats.driverVersionCode, mGpuStats.driverBuildTime, mGpuStats.appPackageName.c_str(), mGpuStats.vulkanVersion, static_cast<int32_t>(api), isDriverLoaded, driverLoadingTime); - GraphicsEnv::Driver driver = GraphicsEnv::Driver::NONE; + GpuStatsInfo::Driver driver = GpuStatsInfo::Driver::NONE; bool isIntendedDriverLoaded = false; - if (api == GraphicsEnv::Api::API_GL) { + if (api == GpuStatsInfo::Api::API_GL) { driver = mGpuStats.glDriverToLoad; isIntendedDriverLoaded = - isDriverLoaded && (mGpuStats.glDriverFallback == GraphicsEnv::Driver::NONE); + isDriverLoaded && (mGpuStats.glDriverFallback == GpuStatsInfo::Driver::NONE); } else { driver = mGpuStats.vkDriverToLoad; isIntendedDriverLoaded = - isDriverLoaded && (mGpuStats.vkDriverFallback == GraphicsEnv::Driver::NONE); + isDriverLoaded && (mGpuStats.vkDriverFallback == GpuStatsInfo::Driver::NONE); } const sp<IGpuService> gpuService = getGpuService(); diff --git a/libs/graphicsenv/IGpuService.cpp b/libs/graphicsenv/IGpuService.cpp index 5f9624918f..30e5370650 100644 --- a/libs/graphicsenv/IGpuService.cpp +++ b/libs/graphicsenv/IGpuService.cpp @@ -30,7 +30,7 @@ public: virtual void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName, uint64_t driverVersionCode, int64_t driverBuildTime, const std::string& appPackageName, - const int32_t vulkanVersion, GraphicsEnv::Driver driver, + const int32_t vulkanVersion, GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) { Parcel data, reply; data.writeInterfaceToken(IGpuService::getInterfaceDescriptor()); @@ -143,7 +143,7 @@ status_t BnGpuService::onTransact(uint32_t code, const Parcel& data, Parcel* rep if ((status = data.readInt64(&driverLoadingTime)) != OK) return status; setGpuStats(driverPackageName, driverVersionName, driverVersionCode, driverBuildTime, - appPackageName, vulkanVersion, static_cast<GraphicsEnv::Driver>(driver), + appPackageName, vulkanVersion, static_cast<GpuStatsInfo::Driver>(driver), isDriverLoaded, driverLoadingTime); return OK; diff --git a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h index edcccfea4a..c2fd10ae63 100644 --- a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h +++ b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h @@ -72,4 +72,43 @@ public: bool cpuVulkanInUse = false; }; +/* + * class for holding the gpu stats in GraphicsEnv before sending to GpuService. + */ +class GpuStatsInfo { +public: + enum Api { + API_GL = 0, + API_VK = 1, + }; + + enum Driver { + NONE = 0, + GL = 1, + GL_UPDATED = 2, + VULKAN = 3, + VULKAN_UPDATED = 4, + ANGLE = 5, + }; + + GpuStatsInfo() = default; + GpuStatsInfo(const GpuStatsInfo&) = default; + virtual ~GpuStatsInfo() = default; + + std::string driverPackageName = ""; + std::string driverVersionName = ""; + uint64_t driverVersionCode = 0; + int64_t driverBuildTime = 0; + std::string appPackageName = ""; + int32_t vulkanVersion = 0; + Driver glDriverToLoad = Driver::NONE; + Driver glDriverFallback = Driver::NONE; + Driver vkDriverToLoad = Driver::NONE; + Driver vkDriverFallback = Driver::NONE; + bool glDriverToSend = false; + bool vkDriverToSend = false; + int64_t glDriverLoadingTime = 0; + int64_t vkDriverLoadingTime = 0; +}; + } // namespace android diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index f5d19db493..d0fc580fb6 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -17,6 +17,8 @@ #ifndef ANDROID_UI_GRAPHICS_ENV_H #define ANDROID_UI_GRAPHICS_ENV_H 1 +#include <graphicsenv/GpuStatsInfo.h> + #include <mutex> #include <string> #include <vector> @@ -29,59 +31,14 @@ struct NativeLoaderNamespace; class GraphicsEnv { public: - enum Api { - API_GL = 0, - API_VK = 1, - }; - - enum Driver { - NONE = 0, - GL = 1, - GL_UPDATED = 2, - VULKAN = 3, - VULKAN_UPDATED = 4, - ANGLE = 5, - }; - -private: - struct GpuStats { - std::string driverPackageName; - std::string driverVersionName; - uint64_t driverVersionCode; - int64_t driverBuildTime; - std::string appPackageName; - int32_t vulkanVersion; - Driver glDriverToLoad; - Driver glDriverFallback; - Driver vkDriverToLoad; - Driver vkDriverFallback; - bool glDriverToSend; - bool vkDriverToSend; - int64_t glDriverLoadingTime; - int64_t vkDriverLoadingTime; - - GpuStats() - : driverPackageName(""), - driverVersionName(""), - driverVersionCode(0), - driverBuildTime(0), - appPackageName(""), - vulkanVersion(0), - glDriverToLoad(Driver::NONE), - glDriverFallback(Driver::NONE), - vkDriverToLoad(Driver::NONE), - vkDriverFallback(Driver::NONE), - glDriverToSend(false), - vkDriverToSend(false), - glDriverLoadingTime(0), - vkDriverLoadingTime(0) {} - }; - -public: static GraphicsEnv& getInstance(); + // Check if device is debuggable. int getCanLoadSystemLibraries(); + /* + * Apis for updatable driver + */ // Set a search path for loading graphics drivers. The path is a list of // directories separated by ':'. A directory can be contained in a zip file // (drivers must be stored uncompressed and page aligned); such elements @@ -91,17 +48,31 @@ public: // graphics drivers. The string is a list of libraries separated by ':', // which is required by android_link_namespaces. void setDriverPathAndSphalLibraries(const std::string path, const std::string sphalLibraries); + // Get the updatable driver namespace. android_namespace_t* getDriverNamespace(); + + /* + * Apis for GpuStats + */ + // Hint there's real activity launching on the app process. void hintActivityLaunch(); + // Set the initial GpuStats. void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName, uint64_t versionCode, int64_t driverBuildTime, const std::string& appPackageName, const int32_t vulkanVersion); + // Set that CPU type physical device is in use. void setCpuVulkanInUse(); - void setDriverToLoad(Driver driver); - void setDriverLoaded(Api api, bool isDriverLoaded, int64_t driverLoadingTime); - void sendGpuStatsLocked(Api api, bool isDriverLoaded, int64_t driverLoadingTime); - + // Set which driver is intended to load. + void setDriverToLoad(GpuStatsInfo::Driver driver); + // Set which driver is actually loaded. + void setDriverLoaded(GpuStatsInfo::Api api, bool isDriverLoaded, int64_t driverLoadingTime); + + /* + * Apis for ANGLE + */ + // Check if the requested app should use ANGLE. bool shouldUseAngle(std::string appName); + // Check if this app process should use ANGLE. bool shouldUseAngle(); // Set a search path for loading ANGLE libraries. The path is a list of // directories separated by ':'. A directory can be contained in a zip file @@ -110,43 +81,75 @@ public: // /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a void setAngleInfo(const std::string path, const std::string appName, std::string devOptIn, const int rulesFd, const long rulesOffset, const long rulesLength); + // Get the ANGLE driver namespace. android_namespace_t* getAngleNamespace(); + // Get the app name for ANGLE debug message. std::string& getAngleAppName(); + /* + * Apis for debug layer + */ + // Set additional layer search paths. void setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths); + // Get the app namespace for loading layers. NativeLoaderNamespace* getAppNamespace(); - + // Get additional layer search paths. const std::string& getLayerPaths(); - + // Set the Vulkan debug layers. void setDebugLayers(const std::string layers); + // Set the GL debug layers. void setDebugLayersGLES(const std::string layers); + // Get the debug layers to load. const std::string& getDebugLayers(); + // Get the debug layers to load. const std::string& getDebugLayersGLES(); private: enum UseAngle { UNKNOWN, YES, NO }; + // Load requested ANGLE library. void* loadLibrary(std::string name); + // Check ANGLE support with the rules. bool checkAngleRules(void* so); + // Update whether ANGLE should be used. void updateUseAngle(); + // Link updatable driver namespace with llndk and vndk-sp libs. bool linkDriverNamespaceLocked(android_namespace_t* vndkNamespace); + // Send the initial complete GpuStats to GpuService. + void sendGpuStatsLocked(GpuStatsInfo::Api api, bool isDriverLoaded, int64_t driverLoadingTime); GraphicsEnv() = default; + // Path to updatable driver libs. std::string mDriverPath; + // Path to additional sphal libs linked to updatable driver namespace. std::string mSphalLibraries; + // This mutex protects mGpuStats and get gpuservice call. std::mutex mStatsLock; - GpuStats mGpuStats; + // Information bookkept for GpuStats. + GpuStatsInfo mGpuStats; + // Path to ANGLE libs. std::string mAnglePath; + // This App's name. std::string mAngleAppName; + // ANGLE developer opt in status. std::string mAngleDeveloperOptIn; + // ANGLE rules. std::vector<char> mRulesBuffer; + // Use ANGLE flag. UseAngle mUseAngle = UNKNOWN; + // Vulkan debug layers libs. std::string mDebugLayers; + // GL debug layers libs. std::string mDebugLayersGLES; + // Additional debug layers search path. std::string mLayerPaths; + // This mutex protects the namespace creation. std::mutex mNamespaceMutex; + // Updatable driver namespace. android_namespace_t* mDriverNamespace = nullptr; + // ANGLE namespace. android_namespace_t* mAngleNamespace = nullptr; + // This App's namespace. NativeLoaderNamespace* mAppNamespace = nullptr; }; diff --git a/libs/graphicsenv/include/graphicsenv/IGpuService.h b/libs/graphicsenv/include/graphicsenv/IGpuService.h index 34f1c7ee7e..a47bbafcc4 100644 --- a/libs/graphicsenv/include/graphicsenv/IGpuService.h +++ b/libs/graphicsenv/include/graphicsenv/IGpuService.h @@ -37,7 +37,7 @@ public: virtual void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName, uint64_t driverVersionCode, int64_t driverBuildTime, const std::string& appPackageName, - const int32_t vulkanVersion, GraphicsEnv::Driver driver, + const int32_t vulkanVersion, GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) = 0; // set CPU Vulkan in use signal from GraphicsEnvironment. diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 34575f5d47..b2a7557588 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -15,6 +15,10 @@ cc_library_headers { name: "libgui_headers", vendor_available: true, export_include_dirs: ["include"], + + // we must build this module to get the required header as that is generated + export_shared_lib_headers: [ "android.hidl.token@1.0-utils" ], + shared_libs: [ "android.hidl.token@1.0-utils" ], } cc_library_shared { diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index e0e3431ca5..b429d387ad 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -97,7 +97,9 @@ BufferQueueCore::BufferQueueCore() : mSharedBufferCache(Rect::INVALID_RECT, 0, NATIVE_WINDOW_SCALING_MODE_FREEZE, HAL_DATASPACE_UNKNOWN), mLastQueuedSlot(INVALID_BUFFER_SLOT), - mUniqueId(getUniqueId()) + mUniqueId(getUniqueId()), + mAutoPrerotation(false), + mTransformHintInUse(0) { int numStartingBuffers = getMaxBufferCountLocked(); for (int s = 0; s < numStartingBuffers; s++) { @@ -123,10 +125,12 @@ void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const mQueueBufferCanDrop, mLegacyBufferDrop); outResult->appendFormat("%s default-size=[%dx%d] default-format=%d ", prefix.string(), mDefaultWidth, mDefaultHeight, mDefaultBufferFormat); - outResult->appendFormat("transform-hint=%02x frame-counter=%" PRIu64, mTransformHint, - mFrameCounter); + outResult->appendFormat("%s transform-hint=%02x frame-counter=%" PRIu64 "\n", prefix.string(), + mTransformHint, mFrameCounter); + outResult->appendFormat("%s mTransformHintInUse=%02x mAutoPrerotation=%d\n", prefix.string(), + mTransformHintInUse, mAutoPrerotation); - outResult->appendFormat("\n%sFIFO(%zu):\n", prefix.string(), mQueue.size()); + outResult->appendFormat("%sFIFO(%zu):\n", prefix.string(), mQueue.size()); Fifo::const_iterator current(mQueue.begin()); while (current != mQueue.end()) { double timestamp = current->mTimestamp / 1e9; diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 9c311a314f..da091cc61f 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -408,6 +408,10 @@ status_t BufferQueueProducer::dequeueBuffer(int* outSlot, sp<android::Fence>* ou if (useDefaultSize) { width = mCore->mDefaultWidth; height = mCore->mDefaultHeight; + if (mCore->mAutoPrerotation && + (mCore->mTransformHintInUse & NATIVE_WINDOW_TRANSFORM_ROT_90)) { + std::swap(width, height); + } } int found = BufferItem::INVALID_BUFFER_SLOT; @@ -951,7 +955,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, output->width = mCore->mDefaultWidth; output->height = mCore->mDefaultHeight; - output->transformHint = mCore->mTransformHint; + output->transformHint = mCore->mTransformHintInUse = mCore->mTransformHint; output->numPendingBuffers = static_cast<uint32_t>(mCore->mQueue.size()); output->nextFrameNumber = mCore->mFrameCounter + 1; @@ -1132,9 +1136,6 @@ int BufferQueueProducer::query(int what, int *outValue) { case NATIVE_WINDOW_CONSUMER_IS_PROTECTED: value = static_cast<int32_t>(mCore->mConsumerIsProtected); break; - case NATIVE_WINDOW_MAX_BUFFER_COUNT: - value = static_cast<int32_t>(mCore->mMaxBufferCount); - break; default: return BAD_VALUE; } @@ -1194,11 +1195,12 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener, output->width = mCore->mDefaultWidth; output->height = mCore->mDefaultHeight; - output->transformHint = mCore->mTransformHint; + output->transformHint = mCore->mTransformHintInUse = mCore->mTransformHint; output->numPendingBuffers = static_cast<uint32_t>(mCore->mQueue.size()); output->nextFrameNumber = mCore->mFrameCounter + 1; output->bufferReplaced = false; + output->maxBufferCount = mCore->mMaxBufferCount; if (listener != nullptr) { // Set up a death notification so that we can disconnect @@ -1298,6 +1300,7 @@ status_t BufferQueueProducer::disconnect(int api, DisconnectMode mode) { mCore->mConnectedPid = -1; mCore->mSidebandStream.clear(); mCore->mDequeueCondition.notify_all(); + mCore->mAutoPrerotation = false; listener = mCore->mConsumerListener; } else if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) { BQ_LOGE("disconnect: not connected (req=%d)", api); @@ -1341,6 +1344,8 @@ status_t BufferQueueProducer::setSidebandStream(const sp<NativeHandle>& stream) void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, PixelFormat format, uint64_t usage) { ATRACE_CALL(); + + const bool useDefaultSize = !width && !height; while (true) { size_t newBufferCount = 0; uint32_t allocWidth = 0; @@ -1367,6 +1372,11 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, allocWidth = width > 0 ? width : mCore->mDefaultWidth; allocHeight = height > 0 ? height : mCore->mDefaultHeight; + if (useDefaultSize && mCore->mAutoPrerotation && + (mCore->mTransformHintInUse & NATIVE_WINDOW_TRANSFORM_ROT_90)) { + std::swap(allocWidth, allocHeight); + } + allocFormat = format != 0 ? format : mCore->mDefaultBufferFormat; allocUsage = usage | mCore->mConsumerUsageBits; allocName.assign(mCore->mConsumerName.string(), mCore->mConsumerName.size()); @@ -1397,6 +1407,11 @@ void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height, std::unique_lock<std::mutex> lock(mCore->mMutex); uint32_t checkWidth = width > 0 ? width : mCore->mDefaultWidth; uint32_t checkHeight = height > 0 ? height : mCore->mDefaultHeight; + if (useDefaultSize && mCore->mAutoPrerotation && + (mCore->mTransformHintInUse & NATIVE_WINDOW_TRANSFORM_ROT_90)) { + std::swap(checkWidth, checkHeight); + } + PixelFormat checkFormat = format != 0 ? format : mCore->mDefaultBufferFormat; uint64_t checkUsage = usage | mCore->mConsumerUsageBits; @@ -1599,4 +1614,14 @@ status_t BufferQueueProducer::getConsumerUsage(uint64_t* outUsage) const { return NO_ERROR; } +status_t BufferQueueProducer::setAutoPrerotation(bool autoPrerotation) { + ATRACE_CALL(); + BQ_LOGV("setAutoPrerotation: %d", autoPrerotation); + + std::lock_guard<std::mutex> lock(mCore->mMutex); + + mCore->mAutoPrerotation = autoPrerotation; + return NO_ERROR; +} + } // namespace android diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 0e03b7d393..0009a57653 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -73,6 +73,7 @@ enum { GET_UNIQUE_ID, GET_CONSUMER_USAGE, SET_LEGACY_BUFFER_DROP, + SET_AUTO_PREROTATION, }; class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer> @@ -547,6 +548,17 @@ public: } return actualResult; } + + virtual status_t setAutoPrerotation(bool autoPrerotation) { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); + data.writeBool(autoPrerotation); + status_t result = remote()->transact(SET_AUTO_PREROTATION, data, &reply); + if (result == NO_ERROR) { + result = reply.readInt32(); + } + return result; + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -675,6 +687,10 @@ public: status_t getConsumerUsage(uint64_t* outUsage) const override { return mBase->getConsumerUsage(outUsage); } + + status_t setAutoPrerotation(bool autoPrerotation) override { + return mBase->setAutoPrerotation(autoPrerotation); + } }; IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer, @@ -688,6 +704,12 @@ status_t IGraphicBufferProducer::setLegacyBufferDrop(bool drop) { return INVALID_OPERATION; } +status_t IGraphicBufferProducer::setAutoPrerotation(bool autoPrerotation) { + // No-op for IGBP other than BufferQueue. + (void)autoPrerotation; + return INVALID_OPERATION; +} + status_t IGraphicBufferProducer::exportToParcel(Parcel* parcel) { status_t res = OK; res = parcel->writeUint32(USE_BUFFER_QUEUE); @@ -1050,6 +1072,13 @@ status_t BnGraphicBufferProducer::onTransact( reply->writeInt32(result); return NO_ERROR; } + case SET_AUTO_PREROTATION: { + CHECK_INTERFACE(IGraphicBuffer, data, reply); + bool autoPrerotation = data.readBool(); + status_t result = setAutoPrerotation(autoPrerotation); + reply->writeInt32(result); + return NO_ERROR; + } } return BBinder::onTransact(code, data, reply, flags); } @@ -1141,12 +1170,8 @@ status_t IGraphicBufferProducer::QueueBufferInput::unflatten( // ---------------------------------------------------------------------------- constexpr size_t IGraphicBufferProducer::QueueBufferOutput::minFlattenedSize() { - return sizeof(width) + - sizeof(height) + - sizeof(transformHint) + - sizeof(numPendingBuffers) + - sizeof(nextFrameNumber) + - sizeof(bufferReplaced); + return sizeof(width) + sizeof(height) + sizeof(transformHint) + sizeof(numPendingBuffers) + + sizeof(nextFrameNumber) + sizeof(bufferReplaced) + sizeof(maxBufferCount); } size_t IGraphicBufferProducer::QueueBufferOutput::getFlattenedSize() const { @@ -1170,6 +1195,7 @@ status_t IGraphicBufferProducer::QueueBufferOutput::flatten( FlattenableUtils::write(buffer, size, numPendingBuffers); FlattenableUtils::write(buffer, size, nextFrameNumber); FlattenableUtils::write(buffer, size, bufferReplaced); + FlattenableUtils::write(buffer, size, maxBufferCount); return frameTimestamps.flatten(buffer, size, fds, count); } @@ -1187,6 +1213,7 @@ status_t IGraphicBufferProducer::QueueBufferOutput::unflatten( FlattenableUtils::read(buffer, size, numPendingBuffers); FlattenableUtils::read(buffer, size, nextFrameNumber); FlattenableUtils::read(buffer, size, bufferReplaced); + FlattenableUtils::read(buffer, size, maxBufferCount); return frameTimestamps.unflatten(buffer, size, fds, count); } diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 9fe5de82d1..4e6a4e7b4c 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -96,6 +96,7 @@ Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controll mConnectedToCpu = false; mProducerControlledByApp = controlledByApp; mSwapIntervalZero = false; + mMaxBufferCount = 0; } Surface::~Surface() { @@ -961,6 +962,10 @@ int Surface::query(int what, int* value) const { *value = static_cast<int>(mDataSpace); return NO_ERROR; } + case NATIVE_WINDOW_MAX_BUFFER_COUNT: { + *value = mMaxBufferCount; + return NO_ERROR; + } } } return mGraphicBufferProducer->query(what, value); @@ -1072,6 +1077,9 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_GET_CONSUMER_USAGE64: res = dispatchGetConsumerUsage64(args); break; + case NATIVE_WINDOW_SET_AUTO_PREROTATION: + res = dispatchSetAutoPrerotation(args); + break; default: res = NAME_NOT_FOUND; break; @@ -1272,6 +1280,11 @@ int Surface::dispatchGetConsumerUsage64(va_list args) { return getConsumerUsage(usage); } +int Surface::dispatchSetAutoPrerotation(va_list args) { + bool autoPrerotation = va_arg(args, int); + return setAutoPrerotation(autoPrerotation); +} + bool Surface::transformToDisplayInverse() { return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) == NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; @@ -1298,6 +1311,7 @@ int Surface::connect( mDefaultWidth = output.width; mDefaultHeight = output.height; mNextFrameNumber = output.nextFrameNumber; + mMaxBufferCount = output.maxBufferCount; // Ignore transform hint if sticky transform is set or transform to display inverse flag is // set. Transform hint should be ignored if the client is expected to always submit buffers @@ -1339,6 +1353,7 @@ int Surface::disconnect(int api, IGraphicBufferProducer::DisconnectMode mode) { mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE; mTransform = 0; mStickyTransform = 0; + mAutoPrerotation = false; if (api == NATIVE_WINDOW_API_CPU) { mConnectedToCpu = false; @@ -1951,4 +1966,22 @@ status_t Surface::attachAndQueueBufferWithDataspace(Surface* surface, sp<Graphic return err; } +int Surface::setAutoPrerotation(bool autoPrerotation) { + ATRACE_CALL(); + ALOGV("Surface::setAutoPrerotation (%d)", autoPrerotation); + Mutex::Autolock lock(mMutex); + + if (mAutoPrerotation == autoPrerotation) { + return OK; + } + + status_t err = mGraphicBufferProducer->setAutoPrerotation(autoPrerotation); + if (err == NO_ERROR) { + mAutoPrerotation = autoPrerotation; + } + ALOGE_IF(err, "IGraphicBufferProducer::setAutoPrerotation(%d) returned %s", autoPrerotation, + strerror(-err)); + return err; +} + }; // namespace android diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index d6f88fc7a4..c59fddfb9d 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -322,10 +322,99 @@ SurfaceComposerClient::Transaction::Transaction(const Transaction& other) mTransactionNestCount(other.mTransactionNestCount), mAnimation(other.mAnimation), mEarlyWakeup(other.mEarlyWakeup), + mContainsBuffer(other.mContainsBuffer), mDesiredPresentTime(other.mDesiredPresentTime) { mDisplayStates = other.mDisplayStates; mComposerStates = other.mComposerStates; mInputWindowCommands = other.mInputWindowCommands; + mListenerCallbacks = other.mListenerCallbacks; +} + +std::unique_ptr<SurfaceComposerClient::Transaction> +SurfaceComposerClient::Transaction::createFromParcel(const Parcel* parcel) { + auto transaction = std::make_unique<Transaction>(); + if (transaction->readFromParcel(parcel) == NO_ERROR) { + return transaction; + } + return nullptr; +} + +status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel) { + const uint32_t forceSynchronous = parcel->readUint32(); + const uint32_t transactionNestCount = parcel->readUint32(); + const bool animation = parcel->readBool(); + const bool earlyWakeup = parcel->readBool(); + const bool containsBuffer = parcel->readBool(); + const int64_t desiredPresentTime = parcel->readInt64(); + + size_t count = static_cast<size_t>(parcel->readUint32()); + if (count > parcel->dataSize()) { + return BAD_VALUE; + } + SortedVector<DisplayState> displayStates; + displayStates.setCapacity(count); + for (size_t i = 0; i < count; i++) { + DisplayState displayState; + if (displayState.read(*parcel) == BAD_VALUE) { + return BAD_VALUE; + } + displayStates.add(displayState); + } + + count = static_cast<size_t>(parcel->readUint32()); + if (count > parcel->dataSize()) { + return BAD_VALUE; + } + std::unordered_map<sp<SurfaceControl>, ComposerState, SCHash> composerStates; + composerStates.reserve(count); + for (size_t i = 0; i < count; i++) { + sp<SurfaceControl> surfaceControl = SurfaceControl::readFromParcel(parcel); + + ComposerState composerState; + if (composerState.read(*parcel) == BAD_VALUE) { + return BAD_VALUE; + } + composerStates[surfaceControl] = composerState; + } + + InputWindowCommands inputWindowCommands; + inputWindowCommands.read(*parcel); + + // Parsing was successful. Update the object. + mForceSynchronous = forceSynchronous; + mTransactionNestCount = transactionNestCount; + mAnimation = animation; + mEarlyWakeup = earlyWakeup; + mContainsBuffer = containsBuffer; + mDesiredPresentTime = desiredPresentTime; + mDisplayStates = displayStates; + mComposerStates = composerStates; + mInputWindowCommands = inputWindowCommands; + // listener callbacks contain function pointer addresses and may not be safe to parcel. + mListenerCallbacks.clear(); + return NO_ERROR; +} + +status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const { + parcel->writeUint32(mForceSynchronous); + parcel->writeUint32(mTransactionNestCount); + parcel->writeBool(mAnimation); + parcel->writeBool(mEarlyWakeup); + parcel->writeBool(mContainsBuffer); + parcel->writeInt64(mDesiredPresentTime); + parcel->writeUint32(static_cast<uint32_t>(mDisplayStates.size())); + for (auto const& displayState : mDisplayStates) { + displayState.write(*parcel); + } + + parcel->writeUint32(static_cast<uint32_t>(mComposerStates.size())); + for (auto const& [surfaceControl, composerState] : mComposerStates) { + surfaceControl->writeToParcel(parcel); + composerState.write(*parcel); + } + + mInputWindowCommands.write(*parcel); + return NO_ERROR; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) { @@ -336,7 +425,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr mComposerStates[kv.first].state.merge(kv.second.state); } } - other.mComposerStates.clear(); for (auto const& state : other.mDisplayStates) { ssize_t index = mDisplayStates.indexOf(state); @@ -346,7 +434,6 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr mDisplayStates.editItemAt(static_cast<size_t>(index)).merge(state); } } - other.mDisplayStates.clear(); for (const auto& [listener, callbackInfo] : other.mListenerCallbacks) { auto& [callbackIds, surfaceControls] = callbackInfo; @@ -357,17 +444,27 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr .surfaceControls.insert(std::make_move_iterator(surfaceControls.begin()), std::make_move_iterator(surfaceControls.end())); } - other.mListenerCallbacks.clear(); mInputWindowCommands.merge(other.mInputWindowCommands); - other.mInputWindowCommands.clear(); mContainsBuffer = other.mContainsBuffer; - other.mContainsBuffer = false; - + other.clear(); return *this; } +void SurfaceComposerClient::Transaction::clear() { + mComposerStates.clear(); + mDisplayStates.clear(); + mListenerCallbacks.clear(); + mInputWindowCommands.clear(); + mContainsBuffer = false; + mForceSynchronous = 0; + mTransactionNestCount = 0; + mAnimation = false; + mEarlyWakeup = false; + mDesiredPresentTime = -1; +} + void SurfaceComposerClient::doDropReferenceTransaction(const sp<IBinder>& handle, const sp<ISurfaceComposerClient>& client) { sp<ISurfaceComposer> sf(ComposerService::getComposerService()); @@ -623,6 +720,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setRelat layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; + return *this; } s->what |= layer_state_t::eRelativeLayerChanged; s->what &= ~layer_state_t::eLayerChanged; @@ -1052,6 +1150,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::detachCh layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; + return *this; } s->what |= layer_state_t::eDetachChildren; diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index 55488dad0b..b9defdd120 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -71,14 +71,6 @@ SurfaceControl::~SurfaceControl() release(); } -void SurfaceControl::destroy() -{ - if (isValid()) { - SurfaceComposerClient::Transaction().reparent(this, nullptr).apply(); - } - release(); -} - void SurfaceControl::release() { // Trigger an IPC now, to make sure things @@ -186,8 +178,7 @@ void SurfaceControl::writeToParcel(Parcel* parcel) parcel->writeStrongBinder(IGraphicBufferProducer::asBinder(mGraphicBufferProducer)); } -sp<SurfaceControl> SurfaceControl::readFromParcel(Parcel* parcel) -{ +sp<SurfaceControl> SurfaceControl::readFromParcel(const Parcel* parcel) { sp<IBinder> client = parcel->readStrongBinder(); sp<IBinder> handle = parcel->readStrongBinder(); if (client == nullptr || handle == nullptr) diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h index 690a85f395..205e79c879 100644 --- a/libs/gui/include/gui/BufferQueueCore.h +++ b/libs/gui/include/gui/BufferQueueCore.h @@ -348,6 +348,14 @@ private: const uint64_t mUniqueId; + // When buffer size is driven by the consumer and mTransformHint specifies + // a 90 or 270 degree rotation, this indicates whether the width and height + // used by dequeueBuffer will be additionally swapped. + bool mAutoPrerotation; + + // mTransformHintInUse is to cache the mTransformHint used by the producer. + uint32_t mTransformHintInUse; + }; // class BufferQueueCore } // namespace android diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h index d2a47a6aa8..9ad92a6e78 100644 --- a/libs/gui/include/gui/BufferQueueProducer.h +++ b/libs/gui/include/gui/BufferQueueProducer.h @@ -190,6 +190,9 @@ public: // See IGraphicBufferProducer::getConsumerUsage virtual status_t getConsumerUsage(uint64_t* outUsage) const override; + // See IGraphicBufferProducer::setAutoPrerotation + virtual status_t setAutoPrerotation(bool autoPrerotation); + private: // This is required by the IBinder::DeathRecipient interface virtual void binderDied(const wp<IBinder>& who); diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index 3dde8c8c80..abe1e3f6e6 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -412,6 +412,7 @@ public: uint64_t nextFrameNumber{0}; FrameEventHistoryDelta frameTimestamps; bool bufferReplaced{false}; + int maxBufferCount{0}; }; virtual status_t queueBuffer(int slot, const QueueBufferInput& input, @@ -629,6 +630,14 @@ public: // NATIVE_WINDOW_CONSUMER_USAGE_BITS attribute. virtual status_t getConsumerUsage(uint64_t* outUsage) const = 0; + // Enable/disable the auto prerotation at buffer allocation when the buffer + // size is driven by the consumer. + // + // When buffer size is driven by the consumer and the transform hint + // specifies a 90 or 270 degree rotation, if auto prerotation is enabled, + // the width and height used for dequeueBuffer will be additionally swapped. + virtual status_t setAutoPrerotation(bool autoPrerotation); + // Static method exports any IGraphicBufferProducer object to a parcel. It // handles null producer as well. static status_t exportToParcel(const sp<IGraphicBufferProducer>& producer, diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 5c6a1ee383..fe528b3711 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -230,6 +230,7 @@ private: int dispatchGetWideColorSupport(va_list args); int dispatchGetHdrSupport(va_list args); int dispatchGetConsumerUsage64(va_list args); + int dispatchSetAutoPrerotation(va_list args); bool transformToDisplayInverse(); protected: @@ -265,6 +266,7 @@ public: virtual int setAsyncMode(bool async); virtual int setSharedBufferMode(bool sharedBufferMode); virtual int setAutoRefresh(bool autoRefresh); + virtual int setAutoPrerotation(bool autoPrerotation); virtual int setBuffersDimensions(uint32_t width, uint32_t height); virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds); virtual int unlockAndPost(); @@ -434,6 +436,7 @@ protected: // Caches the values that have been passed to the producer. bool mSharedBufferMode; bool mAutoRefresh; + bool mAutoPrerotation; // If in shared buffer mode and auto refresh is enabled, store the shared // buffer slot and return it for all calls to queue/dequeue without going @@ -466,6 +469,7 @@ protected: bool mReportRemovedBuffers = false; std::vector<sp<GraphicBuffer>> mRemovedBuffers; + int mMaxBufferCount; }; } // namespace android diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 0e17c7b015..4dda97f5e1 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -285,7 +285,7 @@ public: std::unordered_set<sp<SurfaceControl>, SCHash> surfaceControls; }; - class Transaction { + class Transaction : Parcelable { std::unordered_map<sp<SurfaceControl>, ComposerState, SCHash> mComposerStates; SortedVector<DisplayState > mDisplayStates; std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash> @@ -325,6 +325,15 @@ public: virtual ~Transaction() = default; Transaction(Transaction const& other); + // Factory method that creates a new Transaction instance from the parcel. + static std::unique_ptr<Transaction> createFromParcel(const Parcel* parcel); + + status_t writeToParcel(Parcel* parcel) const override; + status_t readFromParcel(const Parcel* parcel) override; + + // Clears the contents of the transaction without applying it. + void clear(); + status_t apply(bool synchronous = false); // Merge another transaction in to this one, clearing other // as if it had been applied. diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h index 23bfc0256b..ae4a14690f 100644 --- a/libs/gui/include/gui/SurfaceControl.h +++ b/libs/gui/include/gui/SurfaceControl.h @@ -44,7 +44,7 @@ class SurfaceComposerClient; class SurfaceControl : public RefBase { public: - static sp<SurfaceControl> readFromParcel(Parcel* parcel); + static sp<SurfaceControl> readFromParcel(const Parcel* parcel); void writeToParcel(Parcel* parcel); static bool isValid(const sp<SurfaceControl>& surface) { @@ -81,7 +81,7 @@ public: status_t getLayerFrameStats(FrameStats* outStats) const; sp<SurfaceComposerClient> getClient() const; - + explicit SurfaceControl(const sp<SurfaceControl>& other); SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle, diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 119e888edb..98dc1e6337 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -169,6 +169,18 @@ TEST_F(BufferQueueTest, DISABLED_BufferQueueInAnotherProcess) { ASSERT_EQ(OK, item.mGraphicBuffer->unlock()); } +TEST_F(BufferQueueTest, GetMaxBufferCountInQueueBufferOutput_Succeeds) { + createBufferQueue(); + sp<DummyConsumer> dc(new DummyConsumer); + mConsumer->consumerConnect(dc, false); + int bufferCount = 50; + mConsumer->setMaxBufferCount(bufferCount); + + IGraphicBufferProducer::QueueBufferOutput output; + mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false, &output); + ASSERT_EQ(output.maxBufferCount, bufferCount); +} + TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) { createBufferQueue(); sp<DummyConsumer> dc(new DummyConsumer); diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp index d33ecfbdb9..c9de37d957 100644 --- a/libs/gui/tests/RegionSampling_test.cpp +++ b/libs/gui/tests/RegionSampling_test.cpp @@ -297,4 +297,70 @@ TEST_F(RegionSamplingTest, DISABLED_CollectsLumaFromTwoRegions) { composer->removeRegionSamplingListener(grayListener); } +TEST_F(RegionSamplingTest, DISABLED_TestIfInvalidInputParameters) { + sp<ISurfaceComposer> composer = ComposerService::getComposerService(); + sp<Listener> listener = new Listener(); + const Rect sampleArea{100, 100, 200, 200}; + // Invalid input sampleArea + EXPECT_EQ(BAD_VALUE, + composer->addRegionSamplingListener(Rect::INVALID_RECT, mTopLayer->getHandle(), + listener)); + listener->reset(); + // Invalid input binder + EXPECT_EQ(NO_ERROR, composer->addRegionSamplingListener(sampleArea, NULL, listener)); + // Invalid input listener + EXPECT_EQ(BAD_VALUE, + composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), NULL)); + EXPECT_EQ(BAD_VALUE, composer->removeRegionSamplingListener(NULL)); + // remove the listener + composer->removeRegionSamplingListener(listener); +} + +TEST_F(RegionSamplingTest, DISABLED_TestCallbackAfterRemoveListener) { + fill_render(rgba_green); + sp<ISurfaceComposer> composer = ComposerService::getComposerService(); + sp<Listener> listener = new Listener(); + const Rect sampleArea{100, 100, 200, 200}; + composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener); + fill_render(rgba_green); + + EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received"; + EXPECT_NEAR(listener->luma(), luma_green, error_margin); + + listener->reset(); + composer->removeRegionSamplingListener(listener); + fill_render(rgba_green); + EXPECT_FALSE(listener->wait_event(100ms)) + << "callback should stop after remove the region sampling listener"; +} + +TEST_F(RegionSamplingTest, DISABLED_CollectsLumaFromMovingLayer) { + sp<ISurfaceComposer> composer = ComposerService::getComposerService(); + sp<Listener> listener = new Listener(); + Rect sampleArea{100, 100, 200, 200}; + + // Test: listener in (100, 100). See layer before move, no layer after move. + fill_render(rgba_blue); + composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener); + EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received"; + EXPECT_NEAR(listener->luma(), luma_blue, error_margin); + listener->reset(); + SurfaceComposerClient::Transaction{}.setPosition(mContentLayer, 600, 600).apply(); + EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received"; + EXPECT_NEAR(listener->luma(), luma_gray, error_margin); + composer->removeRegionSamplingListener(listener); + + // Test: listener offset to (600, 600). No layer before move, see layer after move. + fill_render(rgba_green); + sampleArea.offsetTo(600, 600); + composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener); + EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received"; + EXPECT_NEAR(listener->luma(), luma_gray, error_margin); + listener->reset(); + SurfaceComposerClient::Transaction{}.setPosition(mContentLayer, 600, 600).apply(); + EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received"; + EXPECT_NEAR(listener->luma(), luma_green, error_margin); + composer->removeRegionSamplingListener(listener); +} + } // namespace android::test diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index d3708586f5..7718bc1b8e 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -1746,4 +1746,74 @@ TEST_F(GetFrameTimestampsTest, PresentUnsupportedNoSync) { EXPECT_EQ(-1, outDisplayPresentTime); } +TEST_F(SurfaceTest, DequeueWithConsumerDrivenSize) { + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp<DummyConsumer> dummyConsumer(new DummyConsumer); + consumer->consumerConnect(dummyConsumer, false); + consumer->setDefaultBufferSize(10, 10); + + sp<Surface> surface = new Surface(producer); + sp<ANativeWindow> window(surface); + native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU); + native_window_set_buffers_dimensions(window.get(), 0, 0); + + int fence; + ANativeWindowBuffer* buffer; + + // Buffer size is driven by the consumer + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(10, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); + + // Buffer size is driven by the consumer + consumer->setDefaultBufferSize(10, 20); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(20, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); + + // Transform hint isn't synced to producer before queueBuffer or connect + consumer->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_270); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(20, buffer->height); + ASSERT_EQ(NO_ERROR, window->queueBuffer(window.get(), buffer, fence)); + + // Transform hint is synced to producer but no auto prerotation + consumer->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_270); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(20, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); + + // Prerotation is driven by the consumer with the transform hint used by producer + native_window_set_auto_prerotation(window.get(), true); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(20, buffer->width); + EXPECT_EQ(10, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); + + // Turn off auto prerotaton + native_window_set_auto_prerotation(window.get(), false); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(20, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); + + // Test auto prerotation bit is disabled after disconnect + native_window_set_auto_prerotation(window.get(), true); + native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_CPU); + native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU); + consumer->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_270); + native_window_set_buffers_dimensions(window.get(), 0, 0); + ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence)); + EXPECT_EQ(10, buffer->width); + EXPECT_EQ(20, buffer->height); + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); +} + } // namespace android diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp index 0c22bfefed..56900c129e 100644 --- a/libs/input/Keyboard.cpp +++ b/libs/input/Keyboard.cpp @@ -38,29 +38,29 @@ KeyMap::KeyMap() { KeyMap::~KeyMap() { } -status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier, +status_t KeyMap::load(const InputDeviceIdentifier& deviceIdentifier, const PropertyMap* deviceConfiguration) { // Use the configured key layout if available. if (deviceConfiguration) { String8 keyLayoutName; if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"), keyLayoutName)) { - status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName.c_str()); + status_t status = loadKeyLayout(deviceIdentifier, keyLayoutName.c_str()); if (status == NAME_NOT_FOUND) { ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but " "it was not found.", - deviceIdenfifier.name.c_str(), keyLayoutName.string()); + deviceIdentifier.name.c_str(), keyLayoutName.string()); } } String8 keyCharacterMapName; if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"), keyCharacterMapName)) { - status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName.c_str()); + status_t status = loadKeyCharacterMap(deviceIdentifier, keyCharacterMapName.c_str()); if (status == NAME_NOT_FOUND) { ALOGE("Configuration for keyboard device '%s' requested keyboard character " "map '%s' but it was not found.", - deviceIdenfifier.name.c_str(), keyLayoutName.string()); + deviceIdentifier.name.c_str(), keyCharacterMapName.string()); } } @@ -70,25 +70,25 @@ status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier, } // Try searching by device identifier. - if (probeKeyMap(deviceIdenfifier, "")) { + if (probeKeyMap(deviceIdentifier, "")) { return OK; } // Fall back on the Generic key map. // TODO Apply some additional heuristics here to figure out what kind of // generic key map to use (US English, etc.) for typical external keyboards. - if (probeKeyMap(deviceIdenfifier, "Generic")) { + if (probeKeyMap(deviceIdentifier, "Generic")) { return OK; } // Try the Virtual key map as a last resort. - if (probeKeyMap(deviceIdenfifier, "Virtual")) { + if (probeKeyMap(deviceIdentifier, "Virtual")) { return OK; } // Give up! ALOGE("Could not determine key map for device '%s' and no default key maps were found!", - deviceIdenfifier.name.c_str()); + deviceIdentifier.name.c_str()); return NAME_NOT_FOUND; } diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index 8435dac636..1751443419 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -262,3 +262,7 @@ int ANativeWindow_setSharedBufferMode(ANativeWindow* window, bool sharedBufferMo int ANativeWindow_setAutoRefresh(ANativeWindow* window, bool autoRefresh) { return native_window_set_auto_refresh(window, autoRefresh); } + +int ANativeWindow_setAutoPrerotation(ANativeWindow* window, bool autoPrerotation) { + return native_window_set_auto_prerotation(window, autoPrerotation); +} diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 61590e0196..8cbf0a4244 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -203,41 +203,42 @@ enum { */ enum { // clang-format off - NATIVE_WINDOW_SET_USAGE = 0, /* deprecated */ - NATIVE_WINDOW_CONNECT = 1, /* deprecated */ - NATIVE_WINDOW_DISCONNECT = 2, /* deprecated */ - NATIVE_WINDOW_SET_CROP = 3, /* private */ - NATIVE_WINDOW_SET_BUFFER_COUNT = 4, - NATIVE_WINDOW_SET_BUFFERS_GEOMETRY = 5, /* deprecated */ - NATIVE_WINDOW_SET_BUFFERS_TRANSFORM = 6, - NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP = 7, - NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS = 8, - NATIVE_WINDOW_SET_BUFFERS_FORMAT = 9, - NATIVE_WINDOW_SET_SCALING_MODE = 10, /* private */ - NATIVE_WINDOW_LOCK = 11, /* private */ - NATIVE_WINDOW_UNLOCK_AND_POST = 12, /* private */ - NATIVE_WINDOW_API_CONNECT = 13, /* private */ - NATIVE_WINDOW_API_DISCONNECT = 14, /* private */ - NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */ - NATIVE_WINDOW_SET_POST_TRANSFORM_CROP = 16, /* deprecated, unimplemented */ - NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17, /* private */ - NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18, - NATIVE_WINDOW_SET_BUFFERS_DATASPACE = 19, - NATIVE_WINDOW_SET_SURFACE_DAMAGE = 20, /* private */ - NATIVE_WINDOW_SET_SHARED_BUFFER_MODE = 21, - NATIVE_WINDOW_SET_AUTO_REFRESH = 22, - NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION = 23, - NATIVE_WINDOW_GET_NEXT_FRAME_ID = 24, - NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS = 25, - NATIVE_WINDOW_GET_COMPOSITOR_TIMING = 26, - NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 27, - NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28, - NATIVE_WINDOW_GET_HDR_SUPPORT = 29, - NATIVE_WINDOW_SET_USAGE64 = 30, - NATIVE_WINDOW_GET_CONSUMER_USAGE64 = 31, - NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA = 32, - NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA = 33, + NATIVE_WINDOW_SET_USAGE = 0, /* deprecated */ + NATIVE_WINDOW_CONNECT = 1, /* deprecated */ + NATIVE_WINDOW_DISCONNECT = 2, /* deprecated */ + NATIVE_WINDOW_SET_CROP = 3, /* private */ + NATIVE_WINDOW_SET_BUFFER_COUNT = 4, + NATIVE_WINDOW_SET_BUFFERS_GEOMETRY = 5, /* deprecated */ + NATIVE_WINDOW_SET_BUFFERS_TRANSFORM = 6, + NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP = 7, + NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS = 8, + NATIVE_WINDOW_SET_BUFFERS_FORMAT = 9, + NATIVE_WINDOW_SET_SCALING_MODE = 10, /* private */ + NATIVE_WINDOW_LOCK = 11, /* private */ + NATIVE_WINDOW_UNLOCK_AND_POST = 12, /* private */ + NATIVE_WINDOW_API_CONNECT = 13, /* private */ + NATIVE_WINDOW_API_DISCONNECT = 14, /* private */ + NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */ + NATIVE_WINDOW_SET_POST_TRANSFORM_CROP = 16, /* deprecated, unimplemented */ + NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17, /* private */ + NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18, + NATIVE_WINDOW_SET_BUFFERS_DATASPACE = 19, + NATIVE_WINDOW_SET_SURFACE_DAMAGE = 20, /* private */ + NATIVE_WINDOW_SET_SHARED_BUFFER_MODE = 21, + NATIVE_WINDOW_SET_AUTO_REFRESH = 22, + NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION = 23, + NATIVE_WINDOW_GET_NEXT_FRAME_ID = 24, + NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS = 25, + NATIVE_WINDOW_GET_COMPOSITOR_TIMING = 26, + NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 27, + NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28, + NATIVE_WINDOW_GET_HDR_SUPPORT = 29, + NATIVE_WINDOW_SET_USAGE64 = 30, + NATIVE_WINDOW_GET_CONSUMER_USAGE64 = 31, + NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA = 32, + NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA = 33, NATIVE_WINDOW_SET_BUFFERS_HDR10_PLUS_METADATA = 34, + NATIVE_WINDOW_SET_AUTO_PREROTATION = 35, // clang-format on }; @@ -985,4 +986,18 @@ static inline int native_window_get_consumer_usage(struct ANativeWindow* window, return window->perform(window, NATIVE_WINDOW_GET_CONSUMER_USAGE64, outUsage); } +/* + * native_window_set_auto_prerotation(..., autoPrerotation) + * Enable/disable the auto prerotation at buffer allocation when the buffer size + * is driven by the consumer. + * + * When buffer size is driven by the consumer and the transform hint specifies + * a 90 or 270 degree rotation, if auto prerotation is enabled, the width and + * height used for dequeueBuffer will be additionally swapped. + */ +static inline int native_window_set_auto_prerotation(struct ANativeWindow* window, + bool autoPrerotation) { + return window->perform(window, NATIVE_WINDOW_SET_AUTO_PREROTATION, autoPrerotation); +} + __END_DECLS diff --git a/libs/nativewindow/include/vndk/window.h b/libs/nativewindow/include/vndk/window.h index 995ba44d20..500052c936 100644 --- a/libs/nativewindow/include/vndk/window.h +++ b/libs/nativewindow/include/vndk/window.h @@ -316,6 +316,15 @@ int ANativeWindow_setSharedBufferMode(ANativeWindow* window, bool sharedBufferMo */ int ANativeWindow_setAutoRefresh(ANativeWindow* window, bool autoRefresh); +/* + * Enable/disable the auto prerotation at buffer allocation when the buffer size + * is driven by the consumer. + * + * When buffer size is driven by the consumer and the transform hint specifies + * a 90 or 270 degree rotation, if auto prerotation is enabled, the width and + * height used for dequeueBuffer will be additionally swapped. + */ +int ANativeWindow_setAutoPrerotation(ANativeWindow* window, bool autoPrerotation); /*****************************************************************************/ diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index bad8b11540..119a07dad7 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -28,6 +28,7 @@ LIBNATIVEWINDOW { ANativeWindow_queryf; # vndk ANativeWindow_queueBuffer; # vndk ANativeWindow_release; + ANativeWindow_setAutoPrerotation; # vndk ANativeWindow_setAutoRefresh; # vndk ANativeWindow_setBufferCount; # vndk ANativeWindow_setBuffersDataSpace; # introduced=28 diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index 46a8e9eecf..6e7ec336e9 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -456,10 +456,6 @@ void GLESRenderEngine::primeCache() const { mFeatureFlags & USE_COLOR_MANAGEMENT); } -bool GLESRenderEngine::isCurrent() const { - return mEGLDisplay == eglGetCurrentDisplay() && mEGLContext == eglGetCurrentContext(); -} - base::unique_fd GLESRenderEngine::flush() { ATRACE_CALL(); if (!GLExtensions::getInstance().hasNativeFenceSync()) { @@ -795,7 +791,6 @@ status_t GLESRenderEngine::bindFrameBuffer(Framebuffer* framebuffer) { glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureName, 0); uint32_t glStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); - ALOGE_IF(glStatus != GL_FRAMEBUFFER_COMPLETE_OES, "glCheckFramebufferStatusOES error %d", glStatus); @@ -1013,33 +1008,6 @@ status_t GLESRenderEngine::drawLayers(const DisplaySettings& display, return NO_ERROR; } -void GLESRenderEngine::setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, - ui::Transform::orientation_flags rotation) { - setViewportAndProjection(Rect(vpw, vph), sourceCrop); - - if (rotation == ui::Transform::ROT_0) { - return; - } - - // Apply custom rotation to the projection. - float rot90InRadians = 2.0f * static_cast<float>(M_PI) / 4.0f; - mat4 m = mState.projectionMatrix; - switch (rotation) { - case ui::Transform::ROT_90: - m = mat4::rotate(rot90InRadians, vec3(0, 0, 1)) * m; - break; - case ui::Transform::ROT_180: - m = mat4::rotate(rot90InRadians * 2.0f, vec3(0, 0, 1)) * m; - break; - case ui::Transform::ROT_270: - m = mat4::rotate(rot90InRadians * 3.0f, vec3(0, 0, 1)) * m; - break; - default: - break; - } - mState.projectionMatrix = m; -} - void GLESRenderEngine::setViewportAndProjection(Rect viewport, Rect clip) { ATRACE_CALL(); mVpWidth = viewport.getWidth(); @@ -1103,14 +1071,6 @@ void GLESRenderEngine::setupLayerTexturing(const Texture& texture) { mState.textureEnabled = true; } -void GLESRenderEngine::setupLayerBlackedOut() { - glBindTexture(GL_TEXTURE_2D, mProtectedTexName); - Texture texture(Texture::TEXTURE_2D, mProtectedTexName); - texture.setDimensions(1, 1); // FIXME: we should get that from somewhere - mState.texture = texture; - mState.textureEnabled = true; -} - void GLESRenderEngine::setColorTransform(const mat4& colorTransform) { mState.colorMatrix = colorTransform; } diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index de793c2142..70b704abce 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -50,7 +50,6 @@ class GLESRenderEngine : public impl::RenderEngine { public: static std::unique_ptr<GLESRenderEngine> create(int hwcFormat, uint32_t featureFlags, uint32_t imageCacheSize); - static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig); GLESRenderEngine(uint32_t featureFlags, // See RenderEngine::FeatureFlag EGLDisplay display, EGLConfig config, EGLContext ctxt, EGLSurface dummy, @@ -58,17 +57,7 @@ public: uint32_t imageCacheSize); ~GLESRenderEngine() override EXCLUDES(mRenderingMutex); - std::unique_ptr<Framebuffer> createFramebuffer() override; - std::unique_ptr<Image> createImage() override; - void primeCache() const override; - bool isCurrent() const override; - base::unique_fd flush() override; - bool finish() override; - bool waitFence(base::unique_fd fenceFd) override; - void clearWithColor(float red, float green, float blue, float alpha) override; - void fillRegionWithColor(const Region& region, float red, float green, float blue, - float alpha) override; void genTextures(size_t count, uint32_t* names) override; void deleteTextures(size_t count, uint32_t const* names) override; void bindExternalTextureImage(uint32_t texName, const Image& image) override; @@ -78,7 +67,6 @@ public: void unbindExternalTextureBuffer(uint64_t bufferId) EXCLUDES(mRenderingMutex); status_t bindFrameBuffer(Framebuffer* framebuffer) override; void unbindFrameBuffer(Framebuffer* framebuffer) override; - void checkErrors() const override; bool isProtected() const override { return mInProtectedContext; } bool supportsProtectedContent() const override; @@ -88,9 +76,7 @@ public: base::unique_fd&& bufferFence, base::unique_fd* drawFence) EXCLUDES(mRenderingMutex) override; - // internal to RenderEngine EGLDisplay getEGLDisplay() const { return mEGLDisplay; } - EGLConfig getEGLConfig() const { return mEGLConfig; } // Creates an output image for rendering to EGLImageKHR createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer, bool isProtected, bool useFramebufferCache); @@ -104,27 +90,6 @@ public: protected: Framebuffer* getFramebufferForDrawing() override; void dump(std::string& result) override; - void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, - ui::Transform::orientation_flags rotation) override; - void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture, - const half4& color, float cornerRadius) override; - void setupLayerTexturing(const Texture& texture) override; - void setupLayerBlackedOut() override; - void setupFillWithColor(float r, float g, float b, float a) override; - void setColorTransform(const mat4& colorTransform) override; - void disableTexturing() override; - void disableBlending() override; - void setupCornerRadiusCropSize(float width, float height) override; - - // HDR and color management related functions and state - void setSourceY410BT2020(bool enable) override; - void setSourceDataSpace(ui::Dataspace source) override; - void setOutputDataSpace(ui::Dataspace dataspace) override; - void setDisplayMaxLuminance(const float maxLuminance) override; - - // drawing - void drawMesh(const Mesh& mesh) override; - size_t getMaxTextureSize() const override; size_t getMaxViewportDims() const override; @@ -136,12 +101,16 @@ private: GLES_VERSION_3_0 = 0x30000, }; + static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig); static GlesVersion parseGlesVersion(const char* str); static EGLContext createEglContext(EGLDisplay display, EGLConfig config, EGLContext shareContext, bool useContextPriority, Protection protection); static EGLSurface createDummyEglPbufferSurface(EGLDisplay display, EGLConfig config, int hwcFormat, Protection protection); + std::unique_ptr<Framebuffer> createFramebuffer(); + std::unique_ptr<Image> createImage(); + void checkErrors() const; void setScissor(const Rect& region); void disableScissor(); bool waitSync(EGLSyncKHR sync, EGLint flags); @@ -165,6 +134,28 @@ private: // blending is an expensive operation, we want to turn off blending when it's not necessary. void handleRoundedCorners(const DisplaySettings& display, const LayerSettings& layer, const Mesh& mesh); + base::unique_fd flush(); + bool finish(); + bool waitFence(base::unique_fd fenceFd); + void clearWithColor(float red, float green, float blue, float alpha); + void fillRegionWithColor(const Region& region, float red, float green, float blue, float alpha); + void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture, + const half4& color, float cornerRadius); + void setupLayerTexturing(const Texture& texture); + void setupFillWithColor(float r, float g, float b, float a); + void setColorTransform(const mat4& colorTransform); + void disableTexturing(); + void disableBlending(); + void setupCornerRadiusCropSize(float width, float height); + + // HDR and color management related functions and state + void setSourceY410BT2020(bool enable); + void setSourceDataSpace(ui::Dataspace source); + void setOutputDataSpace(ui::Dataspace dataspace); + void setDisplayMaxLuminance(const float maxLuminance); + + // drawing + void drawMesh(const Mesh& mesh); EGLDisplay mEGLDisplay; EGLConfig mEGLConfig; diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index e7070041f2..8a798eefd1 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -77,10 +77,6 @@ public: // This interface, while still in use until a suitable replacement is built, // should be considered deprecated, minus some methods which still may be // used to support legacy behavior. - - virtual std::unique_ptr<Framebuffer> createFramebuffer() = 0; - virtual std::unique_ptr<Image> createImage() = 0; - virtual void primeCache() const = 0; // dump the extension strings. always call the base class. @@ -88,24 +84,6 @@ public: virtual bool useNativeFenceSync() const = 0; virtual bool useWaitSync() const = 0; - - virtual bool isCurrent() const = 0; - - // helpers - // flush submits RenderEngine command stream for execution and returns a - // native fence fd that is signaled when the execution has completed. It - // returns -1 on errors. - virtual base::unique_fd flush() = 0; - // finish waits until RenderEngine command stream has been executed. It - // returns false on errors. - virtual bool finish() = 0; - // waitFence inserts a wait on an external fence fd to RenderEngine - // command stream. It returns false on errors. - virtual bool waitFence(base::unique_fd fenceFd) = 0; - - virtual void clearWithColor(float red, float green, float blue, float alpha) = 0; - virtual void fillRegionWithColor(const Region& region, float red, float green, float blue, - float alpha) = 0; virtual void genTextures(size_t count, uint32_t* names) = 0; virtual void deleteTextures(size_t count, uint32_t const* names) = 0; virtual void bindExternalTextureImage(uint32_t texName, const Image& image) = 0; @@ -126,40 +104,6 @@ public: virtual status_t bindFrameBuffer(Framebuffer* framebuffer) = 0; virtual void unbindFrameBuffer(Framebuffer* framebuffer) = 0; - // set-up - virtual void checkErrors() const = 0; - virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, - ui::Transform::orientation_flags rotation) = 0; - virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture, - const half4& color, float cornerRadius) = 0; - virtual void setupLayerTexturing(const Texture& texture) = 0; - virtual void setupLayerBlackedOut() = 0; - virtual void setupFillWithColor(float r, float g, float b, float a) = 0; - // Sets up the crop size for corner radius clipping. - // - // Having corner radius will force GPU composition on the layer and its children, drawing it - // with a special shader. The shader will receive the radius and the crop rectangle as input, - // modifying the opacity of the destination texture, multiplying it by a number between 0 and 1. - // We query Layer#getRoundedCornerState() to retrieve the radius as well as the rounded crop - // rectangle to figure out how to apply the radius for this layer. The crop rectangle will be - // in local layer coordinate space, so we have to take the layer transform into account when - // walking up the tree. - virtual void setupCornerRadiusCropSize(float width, float height) = 0; - - // Set a color transform matrix that is applied in linear space right before OETF. - virtual void setColorTransform(const mat4& /* colorTransform */) = 0; - virtual void disableTexturing() = 0; - virtual void disableBlending() = 0; - - // HDR and color management support - virtual void setSourceY410BT2020(bool enable) = 0; - virtual void setSourceDataSpace(ui::Dataspace source) = 0; - virtual void setOutputDataSpace(ui::Dataspace dataspace) = 0; - virtual void setDisplayMaxLuminance(const float maxLuminance) = 0; - - // drawing - virtual void drawMesh(const Mesh& mesh) = 0; - // queries virtual size_t getMaxTextureSize() const = 0; virtual size_t getMaxViewportDims() const = 0; diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index e33bcfd994..f099cd2455 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -34,20 +34,12 @@ public: RenderEngine(); ~RenderEngine() override; - MOCK_METHOD0(createFramebuffer, std::unique_ptr<renderengine::Framebuffer>()); - MOCK_METHOD0(createImage, std::unique_ptr<renderengine::Image>()); MOCK_METHOD0(getFramebufferForDrawing, Framebuffer*()); MOCK_CONST_METHOD0(primeCache, void()); MOCK_METHOD1(dump, void(std::string&)); MOCK_CONST_METHOD0(useNativeFenceSync, bool()); MOCK_CONST_METHOD0(useWaitSync, bool()); MOCK_CONST_METHOD0(isCurrent, bool()); - MOCK_METHOD0(flush, base::unique_fd()); - MOCK_METHOD0(finish, bool()); - MOCK_METHOD1(waitFence, bool(base::unique_fd*)); - bool waitFence(base::unique_fd fd) override { return waitFence(&fd); }; - MOCK_METHOD4(clearWithColor, void(float, float, float, float)); - MOCK_METHOD5(fillRegionWithColor, void(const Region&, float, float, float, float)); MOCK_METHOD2(genTextures, void(size_t, uint32_t*)); MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*)); MOCK_METHOD2(bindExternalTextureImage, void(uint32_t, const renderengine::Image&)); @@ -55,22 +47,6 @@ public: MOCK_METHOD3(bindExternalTextureBuffer, status_t(uint32_t, const sp<GraphicBuffer>&, const sp<Fence>&)); MOCK_METHOD1(unbindExternalTextureBuffer, void(uint64_t)); - MOCK_CONST_METHOD0(checkErrors, void()); - MOCK_METHOD4(setViewportAndProjection, - void(size_t, size_t, Rect, ui::Transform::orientation_flags)); - MOCK_METHOD5(setupLayerBlending, void(bool, bool, bool, const half4&, float)); - MOCK_METHOD1(setupLayerTexturing, void(const Texture&)); - MOCK_METHOD0(setupLayerBlackedOut, void()); - MOCK_METHOD4(setupFillWithColor, void(float, float, float, float)); - MOCK_METHOD2(setupCornerRadiusCropSize, void(float, float)); - MOCK_METHOD1(setColorTransform, void(const mat4&)); - MOCK_METHOD1(setSaturationMatrix, void(const mat4&)); - MOCK_METHOD0(disableTexturing, void()); - MOCK_METHOD0(disableBlending, void()); - MOCK_METHOD1(setSourceY410BT2020, void(bool)); - MOCK_METHOD1(setSourceDataSpace, void(ui::Dataspace)); - MOCK_METHOD1(setOutputDataSpace, void(ui::Dataspace)); - MOCK_METHOD1(setDisplayMaxLuminance, void(const float)); MOCK_METHOD1(bindFrameBuffer, status_t(renderengine::Framebuffer*)); MOCK_METHOD1(unbindFrameBuffer, void(renderengine::Framebuffer*)); MOCK_METHOD1(drawMesh, void(const renderengine::Mesh&)); diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp index da91a979fe..1dfc1e9e88 100644 --- a/libs/ui/BufferHubBuffer.cpp +++ b/libs/ui/BufferHubBuffer.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#define LOG_TAG "BufferHubBuffer" #include <poll.h> #include <android-base/unique_fd.h> diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index 3fc6a2d34a..579e68e917 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -626,7 +626,7 @@ status_t GraphicBuffer::unflattenBufferHubBuffer(void const*& buffer, size_t& si bufferHubBuffer->desc().layers, bufferHubBuffer->desc().usage, bufferHubBuffer->desc().stride); mBufferId = bufferHubBuffer->id(); - mBufferHubBuffer.reset(std::move(bufferHubBuffer.get())); + mBufferHubBuffer = std::move(bufferHubBuffer); return NO_ERROR; } diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp index 373fa4f221..c5170d091c 100644 --- a/libs/ui/tests/Android.bp +++ b/libs/ui/tests/Android.bp @@ -46,6 +46,24 @@ cc_test { cflags: ["-Wall", "-Werror"], } +// This test has a main method, and requires a separate binary to be built. +cc_test { + name: "GraphicBufferOverBinder_test", + srcs: ["GraphicBufferOverBinder_test.cpp"], + cflags: ["-Wall", "-Werror"], + header_libs: [ + "libdvr_headers", + ], + shared_libs: [ + "android.frameworks.bufferhub@1.0", + "libbinder", + "libgui", + "liblog", + "libui", + "libutils", + ], +} + cc_test { name: "BufferHub_test", header_libs: [ diff --git a/libs/ui/tests/GraphicBufferOverBinder_test.cpp b/libs/ui/tests/GraphicBufferOverBinder_test.cpp new file mode 100644 index 0000000000..7c0a44a64f --- /dev/null +++ b/libs/ui/tests/GraphicBufferOverBinder_test.cpp @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2019 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 "GraphicBufferOverBinder_test" + +#include <binder/IServiceManager.h> +#include <binder/Parcel.h> +#include <binder/ProcessState.h> +#include <gtest/gtest.h> +#include <gui/BufferQueue.h> +#include <gui/IGraphicBufferConsumer.h> +#include <gui/IGraphicBufferProducer.h> +#include <ui/BufferHubBuffer.h> +#include <ui/GraphicBuffer.h> +#include <utils/Log.h> + +namespace android { + +constexpr uint32_t kTestWidth = 1024; +constexpr uint32_t kTestHeight = 1; +constexpr uint32_t kTestFormat = HAL_PIXEL_FORMAT_BLOB; +constexpr uint32_t kTestLayerCount = 1; +constexpr uint64_t kTestUsage = GraphicBuffer::USAGE_SW_WRITE_OFTEN; +static const String16 kTestServiceName = String16("GraphicBufferOverBinderTestService"); +enum GraphicBufferOverBinderTestServiceCode { + GRAPHIC_BUFFER = IBinder::FIRST_CALL_TRANSACTION, + GRAPHIC_BUFFER_FROM_BUFFER_HUB_BUFFER, +}; + +class GraphicBufferOverBinderTestService : public BBinder { +public: + GraphicBufferOverBinderTestService() { + // GraphicBuffer + mGraphicBuffer = new GraphicBuffer(kTestWidth, kTestHeight, kTestFormat, kTestLayerCount, + kTestUsage); + ALOGI("mGraphicBuffer id %" PRIi32, mGraphicBuffer->getBufferId()); + + // BufferHub-backed GraphicBuffer + std::unique_ptr<BufferHubBuffer> bufferHubBuffer = + BufferHubBuffer::create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat, + kTestUsage, /*userMetadataSize=*/0); + mBufferhubBackedGraphicBuffer = new GraphicBuffer(std::move(bufferHubBuffer)); + if (!mBufferhubBackedGraphicBuffer->isBufferHubBuffer()) { + ALOGE("Failed to back GraphicBuffer with BufferHub."); + } + if (bufferHubBuffer != nullptr) { + ALOGE("Failed to move BufferHubBuffer to GraphicBuffer"); + } + ALOGI("mBufferhubBackedGraphicBuffer id %" PRIi32, + mBufferhubBackedGraphicBuffer->getBufferId()); + } + + ~GraphicBufferOverBinderTestService() = default; + + virtual status_t onTransact(uint32_t code, const Parcel& /*data*/, Parcel* reply, + uint32_t /*flags*/ = 0) { + switch (code) { + case GRAPHIC_BUFFER: { + return reply->write(*mGraphicBuffer); + } + case GRAPHIC_BUFFER_FROM_BUFFER_HUB_BUFFER: { + return reply->write(*mBufferhubBackedGraphicBuffer); + } + default: + return UNKNOWN_TRANSACTION; + }; + } + +protected: + sp<GraphicBuffer> mGraphicBuffer; + sp<GraphicBuffer> mBufferhubBackedGraphicBuffer; +}; + +static int runBinderServer() { + ProcessState::self()->startThreadPool(); + + sp<IServiceManager> sm = defaultServiceManager(); + sp<GraphicBufferOverBinderTestService> service = new GraphicBufferOverBinderTestService; + sm->addService(kTestServiceName, service, false); + + ALOGI("Binder server running..."); + + while (true) { + int stat, retval; + retval = wait(&stat); + if (retval == -1 && errno == ECHILD) { + break; + } + } + + ALOGI("Binder server exiting..."); + return 0; +} + +class GraphicBufferOverBinderTest : public ::testing::TestWithParam<uint32_t> { +protected: + virtual void SetUp() { + mService = defaultServiceManager()->getService(kTestServiceName); + if (mService == nullptr) { + ALOGE("Failed to connect to the test service."); + return; + } + + ALOGI("Binder service is ready for client."); + } + + status_t GetGraphicBuffer(sp<GraphicBuffer>* outBuf, uint32_t opCode) { + Parcel data; + Parcel reply; + status_t error = mService->transact(opCode, data, &reply); + if (error != NO_ERROR) { + ALOGE("Failed to get graphic buffer over binder, error=%d.", error); + return error; + } + + *outBuf = new GraphicBuffer(); + return reply.read(**outBuf); + } + +private: + sp<IBinder> mService; +}; + +TEST_F(GraphicBufferOverBinderTest, SendGraphicBufferOverBinder) { + sp<GraphicBuffer> gb; + EXPECT_EQ(GetGraphicBuffer(&gb, GRAPHIC_BUFFER), OK); + EXPECT_NE(gb, nullptr); + EXPECT_FALSE(gb->isBufferHubBuffer()); + void* vaddr; + EXPECT_EQ(gb->lock(kTestUsage, &vaddr), OK); + EXPECT_EQ(gb->unlock(), OK); +} + +TEST_F(GraphicBufferOverBinderTest, SendGraphicBufferFromBufferHubBufferOverBinder) { + sp<GraphicBuffer> gb; + EXPECT_EQ(GetGraphicBuffer(&gb, GRAPHIC_BUFFER_FROM_BUFFER_HUB_BUFFER), NO_ERROR); + EXPECT_NE(gb, nullptr); + EXPECT_TRUE(gb->isBufferHubBuffer()); + void* vaddr; + EXPECT_EQ(gb->lock(kTestUsage, &vaddr), OK); + EXPECT_EQ(gb->unlock(), OK); +} + +} // namespace android + +int main(int argc, char** argv) { + pid_t pid = fork(); + if (pid == 0) { + android::ProcessState::self()->startThreadPool(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); + + } else { + ALOGI("Test process pid: %d.", pid); + return android::runBinderServer(); + } +} diff --git a/libs/vr/libbufferhub/consumer_buffer.cpp b/libs/vr/libbufferhub/consumer_buffer.cpp index 115e8666e5..7823e36d3d 100644 --- a/libs/vr/libbufferhub/consumer_buffer.cpp +++ b/libs/vr/libbufferhub/consumer_buffer.cpp @@ -52,12 +52,6 @@ int ConsumerBuffer::LocalAcquire(DvrNativeBufferMetadata* out_meta, while (!buffer_state_->compare_exchange_weak( current_buffer_state, updated_buffer_state, std::memory_order_acq_rel, std::memory_order_acquire)) { - ALOGD( - "%s Failed to acquire the buffer. Current buffer state was changed to " - "%" PRIx32 - " when trying to acquire the buffer and modify the buffer state to " - "%" PRIx32 ". About to try again if the buffer is still posted.", - __FUNCTION__, current_buffer_state, updated_buffer_state); if (!BufferHubDefs::isClientPosted(current_buffer_state, client_state_mask())) { ALOGE( @@ -152,12 +146,6 @@ int ConsumerBuffer::LocalRelease(const DvrNativeBufferMetadata* meta, while (!buffer_state_->compare_exchange_weak( current_buffer_state, updated_buffer_state, std::memory_order_acq_rel, std::memory_order_acquire)) { - ALOGD( - "%s: Failed to release the buffer. Current buffer state was changed to " - "%" PRIx32 - " when trying to release the buffer and modify the buffer state to " - "%" PRIx32 ". About to try again.", - __FUNCTION__, current_buffer_state, updated_buffer_state); // The failure of compare_exchange_weak updates current_buffer_state. updated_buffer_state = current_buffer_state & (~client_state_mask()); } diff --git a/libs/vr/libbufferhub/producer_buffer.cpp b/libs/vr/libbufferhub/producer_buffer.cpp index 3d88ba5dbe..aa9d07282b 100644 --- a/libs/vr/libbufferhub/producer_buffer.cpp +++ b/libs/vr/libbufferhub/producer_buffer.cpp @@ -96,13 +96,6 @@ int ProducerBuffer::LocalPost(const DvrNativeBufferMetadata* meta, while (!buffer_state_->compare_exchange_weak( current_buffer_state, updated_buffer_state, std::memory_order_acq_rel, std::memory_order_acquire)) { - ALOGD( - "%s: Failed to post the buffer. Current buffer state was changed to " - "%" PRIx32 - " when trying to post the buffer and modify the buffer state to " - "%" PRIx32 - ". About to try again if the buffer is still gained by this client.", - __FUNCTION__, current_buffer_state, updated_buffer_state); if (!BufferHubDefs::isClientGained(current_buffer_state, client_state_mask())) { ALOGE( @@ -186,15 +179,6 @@ int ProducerBuffer::LocalGain(DvrNativeBufferMetadata* out_meta, while (!buffer_state_->compare_exchange_weak( current_buffer_state, updated_buffer_state, std::memory_order_acq_rel, std::memory_order_acquire)) { - ALOGD( - "%s: Failed to gain the buffer. Current buffer state was changed to " - "%" PRIx32 - " when trying to gain the buffer and modify the buffer state to " - "%" PRIx32 - ". About to try again if the buffer is still not read by other " - "clients.", - __FUNCTION__, current_buffer_state, updated_buffer_state); - if (BufferHubDefs::isAnyClientAcquired(current_buffer_state) || BufferHubDefs::isAnyClientGained(current_buffer_state) || (BufferHubDefs::isAnyClientPosted( diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp index abc7a72716..8144c8a7c5 100644 --- a/opengl/libs/Android.bp +++ b/opengl/libs/Android.bp @@ -162,7 +162,7 @@ cc_library_shared { "libEGL_getProcAddress", "libEGL_blobCache", ], - ldflags: ["-Wl,--exclude-libs=ALL"], + ldflags: ["-Wl,--exclude-libs=ALL,--Bsymbolic-functions"], export_include_dirs: ["EGL/include"], } diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 038a432337..23e11a82ac 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -311,7 +311,7 @@ void* Loader::open(egl_connection_t* cnx) } if (!hnd) { - android::GraphicsEnv::getInstance().setDriverLoaded(android::GraphicsEnv::Api::API_GL, + android::GraphicsEnv::getInstance().setDriverLoaded(android::GpuStatsInfo::Api::API_GL, false, systemTime() - openTime); } @@ -330,7 +330,7 @@ void* Loader::open(egl_connection_t* cnx) } if (!cnx->libEgl || !cnx->libGles2 || !cnx->libGles1) { - android::GraphicsEnv::getInstance().setDriverLoaded(android::GraphicsEnv::Api::API_GL, + android::GraphicsEnv::getInstance().setDriverLoaded(android::GpuStatsInfo::Api::API_GL, false, systemTime() - openTime); } @@ -340,7 +340,7 @@ void* Loader::open(egl_connection_t* cnx) LOG_ALWAYS_FATAL_IF(!cnx->libGles2 || !cnx->libGles1, "couldn't load system OpenGL ES wrapper libraries"); - android::GraphicsEnv::getInstance().setDriverLoaded(android::GraphicsEnv::Api::API_GL, true, + android::GraphicsEnv::getInstance().setDriverLoaded(android::GpuStatsInfo::Api::API_GL, true, systemTime() - openTime); return (void*)hnd; @@ -637,7 +637,7 @@ Loader::driver_t* Loader::attempt_to_load_angle(egl_connection_t* cnx) { return nullptr; } - android::GraphicsEnv::getInstance().setDriverToLoad(android::GraphicsEnv::Driver::ANGLE); + android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::ANGLE); driver_t* hnd = nullptr; // ANGLE doesn't ship with GLES library, and thus we skip GLES driver. @@ -666,7 +666,7 @@ Loader::driver_t* Loader::attempt_to_load_updated_driver(egl_connection_t* cnx) } ALOGD("Load updated gl driver."); - android::GraphicsEnv::getInstance().setDriverToLoad(android::GraphicsEnv::Driver::GL_UPDATED); + android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::GL_UPDATED); driver_t* hnd = nullptr; void* dso = load_updated_driver("GLES", ns); if (dso) { @@ -697,7 +697,7 @@ Loader::driver_t* Loader::attempt_to_load_updated_driver(egl_connection_t* cnx) Loader::driver_t* Loader::attempt_to_load_system_driver(egl_connection_t* cnx, const char* suffix, const bool exact) { ATRACE_CALL(); - android::GraphicsEnv::getInstance().setDriverToLoad(android::GraphicsEnv::Driver::GL); + android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::GL); driver_t* hnd = nullptr; void* dso = load_system_driver("GLES", suffix, exact); if (dso) { diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp index 8accf9d450..72757dd02b 100644 --- a/services/gpuservice/GpuService.cpp +++ b/services/gpuservice/GpuService.cpp @@ -51,7 +51,7 @@ GpuService::GpuService() : mGpuStats(std::make_unique<GpuStats>()){}; void GpuService::setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName, uint64_t driverVersionCode, int64_t driverBuildTime, const std::string& appPackageName, - const int32_t vulkanVersion, GraphicsEnv::Driver driver, + const int32_t vulkanVersion, GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) { ATRACE_CALL(); diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h index 822690134a..3e0e1b5f9b 100644 --- a/services/gpuservice/GpuService.h +++ b/services/gpuservice/GpuService.h @@ -46,7 +46,7 @@ private: void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName, uint64_t driverVersionCode, int64_t driverBuildTime, const std::string& appPackageName, const int32_t vulkanVersion, - GraphicsEnv::Driver driver, bool isDriverLoaded, + GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) override; status_t getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const override; status_t getGpuStatsAppInfo(std::vector<GpuStatsAppInfo>* outStats) const override; diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp index 37c6abc96b..576c72cd3c 100644 --- a/services/gpuservice/gpustats/GpuStats.cpp +++ b/services/gpuservice/gpustats/GpuStats.cpp @@ -27,20 +27,20 @@ namespace android { -static void addLoadingCount(GraphicsEnv::Driver driver, bool isDriverLoaded, +static void addLoadingCount(GpuStatsInfo::Driver driver, bool isDriverLoaded, GpuStatsGlobalInfo* const outGlobalInfo) { switch (driver) { - case GraphicsEnv::Driver::GL: - case GraphicsEnv::Driver::GL_UPDATED: + case GpuStatsInfo::Driver::GL: + case GpuStatsInfo::Driver::GL_UPDATED: outGlobalInfo->glLoadingCount++; if (!isDriverLoaded) outGlobalInfo->glLoadingFailureCount++; break; - case GraphicsEnv::Driver::VULKAN: - case GraphicsEnv::Driver::VULKAN_UPDATED: + case GpuStatsInfo::Driver::VULKAN: + case GpuStatsInfo::Driver::VULKAN_UPDATED: outGlobalInfo->vkLoadingCount++; if (!isDriverLoaded) outGlobalInfo->vkLoadingFailureCount++; break; - case GraphicsEnv::Driver::ANGLE: + case GpuStatsInfo::Driver::ANGLE: outGlobalInfo->angleLoadingCount++; if (!isDriverLoaded) outGlobalInfo->angleLoadingFailureCount++; break; @@ -49,22 +49,22 @@ static void addLoadingCount(GraphicsEnv::Driver driver, bool isDriverLoaded, } } -static void addLoadingTime(GraphicsEnv::Driver driver, int64_t driverLoadingTime, +static void addLoadingTime(GpuStatsInfo::Driver driver, int64_t driverLoadingTime, GpuStatsAppInfo* const outAppInfo) { switch (driver) { - case GraphicsEnv::Driver::GL: - case GraphicsEnv::Driver::GL_UPDATED: + case GpuStatsInfo::Driver::GL: + case GpuStatsInfo::Driver::GL_UPDATED: if (outAppInfo->glDriverLoadingTime.size() < GpuStats::MAX_NUM_LOADING_TIMES) { outAppInfo->glDriverLoadingTime.emplace_back(driverLoadingTime); } break; - case GraphicsEnv::Driver::VULKAN: - case GraphicsEnv::Driver::VULKAN_UPDATED: + case GpuStatsInfo::Driver::VULKAN: + case GpuStatsInfo::Driver::VULKAN_UPDATED: if (outAppInfo->vkDriverLoadingTime.size() < GpuStats::MAX_NUM_LOADING_TIMES) { outAppInfo->vkDriverLoadingTime.emplace_back(driverLoadingTime); } break; - case GraphicsEnv::Driver::ANGLE: + case GpuStatsInfo::Driver::ANGLE: if (outAppInfo->angleDriverLoadingTime.size() < GpuStats::MAX_NUM_LOADING_TIMES) { outAppInfo->angleDriverLoadingTime.emplace_back(driverLoadingTime); } @@ -77,7 +77,7 @@ static void addLoadingTime(GraphicsEnv::Driver driver, int64_t driverLoadingTime void GpuStats::insert(const std::string& driverPackageName, const std::string& driverVersionName, uint64_t driverVersionCode, int64_t driverBuildTime, const std::string& appPackageName, const int32_t vulkanVersion, - GraphicsEnv::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) { + GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) { ATRACE_CALL(); std::lock_guard<std::mutex> lock(mLock); diff --git a/services/gpuservice/gpustats/GpuStats.h b/services/gpuservice/gpustats/GpuStats.h index b293f5988d..a79b2ba208 100644 --- a/services/gpuservice/gpustats/GpuStats.h +++ b/services/gpuservice/gpustats/GpuStats.h @@ -36,7 +36,7 @@ public: void insert(const std::string& driverPackageName, const std::string& driverVersionName, uint64_t driverVersionCode, int64_t driverBuildTime, const std::string& appPackageName, const int32_t vulkanVersion, - GraphicsEnv::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime); + GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime); // Set CPU Vulkan in use signal into app stats. void setCpuVulkanInUse(const std::string& appPackageName, const uint64_t driverVersionCode); // dumpsys interface diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp index ce5627271a..af023148cc 100644 --- a/services/inputflinger/EventHub.cpp +++ b/services/inputflinger/EventHub.cpp @@ -28,7 +28,6 @@ #include <sys/limits.h> #include <sys/inotify.h> #include <sys/ioctl.h> -#include <sys/utsname.h> #include <unistd.h> #define LOG_TAG "EventHub" @@ -94,14 +93,6 @@ static std::string sha1(const std::string& in) { return out; } -static void getLinuxRelease(int* major, int* minor) { - struct utsname info; - if (uname(&info) || sscanf(info.release, "%d.%d", major, minor) <= 0) { - *major = 0, *minor = 0; - ALOGE("Could not get linux version: %s", strerror(errno)); - } -} - /** * Return true if name matches "v4l-touch*" */ @@ -292,11 +283,6 @@ EventHub::EventHub(void) : result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem); LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d", errno); - - int major, minor; - getLinuxRelease(&major, &minor); - // EPOLLWAKEUP was introduced in kernel 3.5 - mUsingEpollWakeup = major > 3 || (major == 3 && minor >= 5); } EventHub::~EventHub(void) { @@ -1487,28 +1473,13 @@ void EventHub::configureFd(Device* device) { } } - std::string wakeMechanism = "EPOLLWAKEUP"; - if (!mUsingEpollWakeup) { -#ifndef EVIOCSSUSPENDBLOCK - // uapi headers don't include EVIOCSSUSPENDBLOCK, and future kernels - // will use an epoll flag instead, so as long as we want to support - // this feature, we need to be prepared to define the ioctl ourselves. -#define EVIOCSSUSPENDBLOCK _IOW('E', 0x91, int) -#endif - if (ioctl(device->fd, EVIOCSSUSPENDBLOCK, 1)) { - wakeMechanism = "<none>"; - } else { - wakeMechanism = "EVIOCSSUSPENDBLOCK"; - } - } // Tell the kernel that we want to use the monotonic clock for reporting timestamps // associated with input events. This is important because the input system // uses the timestamps extensively and assumes they were recorded using the monotonic // clock. int clockId = CLOCK_MONOTONIC; bool usingClockIoctl = !ioctl(device->fd, EVIOCSCLOCKID, &clockId); - ALOGI("wakeMechanism=%s, usingClockIoctl=%s", wakeMechanism.c_str(), - toString(usingClockIoctl)); + ALOGI("usingClockIoctl=%s", toString(usingClockIoctl)); } void EventHub::openVideoDeviceLocked(const std::string& devicePath) { diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h index 63a20ef3e2..eb4e8f2e50 100644 --- a/services/inputflinger/EventHub.h +++ b/services/inputflinger/EventHub.h @@ -479,8 +479,6 @@ private: size_t mPendingEventCount; size_t mPendingEventIndex; bool mPendingINotify; - - bool mUsingEpollWakeup; }; }; // namespace android diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp index 6a7f2797f4..7c061c5857 100644 --- a/services/inputflinger/InputClassifier.cpp +++ b/services/inputflinger/InputClassifier.cpp @@ -276,7 +276,7 @@ void MotionClassifier::enqueueEvent(ClassifierEvent&& event) { bool eventAdded = mEvents.push(std::move(event)); if (!eventAdded) { // If the queue is full, suspect the HAL is slow in processing the events. - ALOGE("Dropped event with eventTime %" PRId64, event.args->eventTime); + ALOGE("Could not add the event to the queue. Resetting"); reset(); } } diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 5b298b4a93..6e953f4af6 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -149,7 +149,7 @@ filegroup { "Scheduler/DispSyncSource.cpp", "Scheduler/EventControlThread.cpp", "Scheduler/EventThread.cpp", - "Scheduler/IdleTimer.cpp", + "Scheduler/OneShotTimer.cpp", "Scheduler/LayerHistory.cpp", "Scheduler/LayerInfo.cpp", "Scheduler/MessageQueue.cpp", diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp index 6709fb4b48..096cd1a9cc 100644 --- a/services/surfaceflinger/BufferLayerConsumer.cpp +++ b/services/surfaceflinger/BufferLayerConsumer.cpp @@ -419,30 +419,6 @@ std::shared_ptr<FenceTime> BufferLayerConsumer::getCurrentFenceTime() const { return mCurrentFenceTime; } -status_t BufferLayerConsumer::doFenceWaitLocked() const { - if (mCurrentFence->isValid()) { - if (mRE.useWaitSync()) { - base::unique_fd fenceFd(mCurrentFence->dup()); - if (fenceFd == -1) { - BLC_LOGE("doFenceWait: error dup'ing fence fd: %d", errno); - return -errno; - } - if (!mRE.waitFence(std::move(fenceFd))) { - BLC_LOGE("doFenceWait: failed to wait on fence fd"); - return UNKNOWN_ERROR; - } - } else { - status_t err = mCurrentFence->waitForever("BufferLayerConsumer::doFenceWaitLocked"); - if (err != NO_ERROR) { - BLC_LOGE("doFenceWait: error waiting for fence: %d", err); - return err; - } - } - } - - return NO_ERROR; -} - void BufferLayerConsumer::freeBufferLocked(int slotIndex) { BLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); std::lock_guard<std::mutex> lock(mImagesMutex); diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h index e3f6100c35..144686c83d 100644 --- a/services/surfaceflinger/BufferLayerConsumer.h +++ b/services/surfaceflinger/BufferLayerConsumer.h @@ -252,11 +252,6 @@ private: // mCurrentTextureImage must not be nullptr. void computeCurrentTransformMatrixLocked(); - // doFenceWaitLocked inserts a wait command into the RenderEngine command - // stream to ensure that it is safe for future RenderEngine commands to - // access the current texture buffer. - status_t doFenceWaitLocked() const; - // getCurrentCropLocked returns the cropping rectangle of the current buffer. Rect getCurrentCropLocked() const; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h index e21128ca81..9bff73e950 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h @@ -83,10 +83,6 @@ public: // Called after the HWC calls are made to present the display virtual void onPresentDisplayCompleted() = 0; - // Called to set the viewport and projection state for rendering into this - // surface - virtual void setViewportAndProjection() = 0; - // Called after the surface has been rendering to signal the surface should // be made ready for displaying virtual void flip() = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h index 0f57315eb6..e4c9c80429 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h @@ -56,7 +56,6 @@ public: sp<GraphicBuffer> dequeueBuffer(base::unique_fd* bufferFence) override; void queueBuffer(base::unique_fd&& readyFence) override; void onPresentDisplayCompleted() override; - void setViewportAndProjection() override; void flip() override; // Debugging diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h index ca2299aa26..146a2eae64 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h @@ -41,7 +41,6 @@ public: MOCK_METHOD1(dequeueBuffer, sp<GraphicBuffer>(base::unique_fd*)); MOCK_METHOD1(queueBuffer, void(base::unique_fd&&)); MOCK_METHOD0(onPresentDisplayCompleted, void()); - MOCK_METHOD0(setViewportAndProjection, void()); MOCK_METHOD0(flip, void()); MOCK_CONST_METHOD1(dump, void(std::string& result)); MOCK_CONST_METHOD0(getPageFlipCount, std::uint32_t()); diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp index 3fcd9d155d..8a91316e65 100644 --- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp +++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp @@ -215,13 +215,6 @@ void RenderSurface::onPresentDisplayCompleted() { mDisplaySurface->onFrameCommitted(); } -void RenderSurface::setViewportAndProjection() { - auto& renderEngine = mCompositionEngine.getRenderEngine(); - Rect sourceCrop = Rect(mSize); - renderEngine.setViewportAndProjection(mSize.width, mSize.height, sourceCrop, - ui::Transform::ROT_0); -} - void RenderSurface::flip() { mPageFlipCount++; } diff --git a/services/surfaceflinger/CompositionEngine/tests/FloatRectMatcher.h b/services/surfaceflinger/CompositionEngine/tests/FloatRectMatcher.h new file mode 100644 index 0000000000..6741cc9b7a --- /dev/null +++ b/services/surfaceflinger/CompositionEngine/tests/FloatRectMatcher.h @@ -0,0 +1,48 @@ +/* + * Copyright 2019 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. + */ + +#pragma once + +#include <string> + +#include <android-base/stringprintf.h> +#include <gmock/gmock.h> + +namespace { + +using android::base::StringAppendF; +using FloatRect = android::FloatRect; + +void dumpFloatRect(const FloatRect& rect, std::string& result, const char* name) { + StringAppendF(&result, "%s (%f %f %f %f) ", name, rect.left, rect.top, rect.right, rect.bottom); +} + +// Checks for a region match +MATCHER_P(FloatRectEq, expected, "") { + std::string buf; + buf.append("FloatRects are not equal\n"); + dumpFloatRect(expected, buf, "expected rect"); + dumpFloatRect(arg, buf, "actual rect"); + *result_listener << buf; + + const float TOLERANCE = 1e-3f; + return (std::fabs(expected.left - arg.left) < TOLERANCE) && + (std::fabs(expected.top - arg.top) < TOLERANCE) && + (std::fabs(expected.right - arg.right) < TOLERANCE) && + (std::fabs(expected.bottom - arg.bottom) < TOLERANCE); +} + +} // namespace diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index 2060c5aaff..ae906cd525 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -21,6 +21,7 @@ #include <compositionengine/mock/Output.h> #include <gtest/gtest.h> +#include "FloatRectMatcher.h" #include "MockHWC2.h" #include "MockHWComposer.h" #include "RectMatcher.h" @@ -106,6 +107,114 @@ TEST_F(OutputLayerTest, initializingOutputLayerWithHwcDisplayCreatesHwcLayer) { } /* + * OutputLayer::calculateOutputSourceCrop() + */ + +struct OutputLayerSourceCropTest : public OutputLayerTest { + OutputLayerSourceCropTest() { + // Set reasonable default values for a simple case. Each test will + // set one specific value to something different. + mLayerState.frontEnd.geomUsesSourceCrop = true; + mLayerState.frontEnd.geomContentCrop = Rect{0, 0, 1920, 1080}; + mLayerState.frontEnd.geomActiveTransparentRegion = Region{}; + mLayerState.frontEnd.geomLayerBounds = FloatRect{0.f, 0.f, 1920.f, 1080.f}; + mLayerState.frontEnd.geomLayerTransform = ui::Transform{TR_IDENT}; + mLayerState.frontEnd.geomBufferSize = Rect{0, 0, 1920, 1080}; + mLayerState.frontEnd.geomBufferTransform = TR_IDENT; + + mOutputState.viewport = Rect{0, 0, 1920, 1080}; + } + + FloatRect calculateOutputSourceCrop() { + mLayerState.frontEnd.geomInverseLayerTransform = + mLayerState.frontEnd.geomLayerTransform.inverse(); + + return mOutputLayer.calculateOutputSourceCrop(); + } +}; + +TEST_F(OutputLayerSourceCropTest, computesEmptyIfSourceCropNotUsed) { + mLayerState.frontEnd.geomUsesSourceCrop = false; + + const FloatRect expected{}; + EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected)); +} + +TEST_F(OutputLayerSourceCropTest, correctForSimpleDefaultCase) { + const FloatRect expected{0.f, 0.f, 1920.f, 1080.f}; + EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected)); +} + +TEST_F(OutputLayerSourceCropTest, handlesBoundsOutsideViewport) { + mLayerState.frontEnd.geomLayerBounds = FloatRect{-2000.f, -2000.f, 2000.f, 2000.f}; + + const FloatRect expected{0.f, 0.f, 1920.f, 1080.f}; + EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected)); +} + +TEST_F(OutputLayerSourceCropTest, handlesBoundsOutsideViewportRotated) { + mLayerState.frontEnd.geomLayerBounds = FloatRect{-2000.f, -2000.f, 2000.f, 2000.f}; + mLayerState.frontEnd.geomLayerTransform.set(HAL_TRANSFORM_ROT_90, 1920, 1080); + + const FloatRect expected{0.f, 0.f, 1080.f, 1080.f}; + EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected)); +} + +TEST_F(OutputLayerSourceCropTest, calculateOutputSourceCropWorksWithATransformedBuffer) { + struct Entry { + uint32_t bufferInvDisplay; + uint32_t buffer; + uint32_t display; + FloatRect expected; + }; + // Not an exhaustive list of cases, but hopefully enough. + const std::array<Entry, 12> testData = { + // clang-format off + // inv buffer display expected + /* 0 */ Entry{false, TR_IDENT, TR_IDENT, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, + /* 1 */ Entry{false, TR_IDENT, TR_ROT_90, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, + /* 2 */ Entry{false, TR_IDENT, TR_ROT_180, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, + /* 3 */ Entry{false, TR_IDENT, TR_ROT_270, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, + + /* 4 */ Entry{true, TR_IDENT, TR_IDENT, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, + /* 5 */ Entry{true, TR_IDENT, TR_ROT_90, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, + /* 6 */ Entry{true, TR_IDENT, TR_ROT_180, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, + /* 7 */ Entry{true, TR_IDENT, TR_ROT_270, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, + + /* 8 */ Entry{false, TR_IDENT, TR_IDENT, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, + /* 9 */ Entry{false, TR_ROT_90, TR_ROT_90, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, + /* 10 */ Entry{false, TR_ROT_180, TR_ROT_180, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, + /* 11 */ Entry{false, TR_ROT_270, TR_ROT_270, FloatRect{0.f, 0.f, 1920.f, 1080.f}}, + + // clang-format on + }; + + for (size_t i = 0; i < testData.size(); i++) { + const auto& entry = testData[i]; + + mLayerState.frontEnd.geomBufferUsesDisplayInverseTransform = entry.bufferInvDisplay; + mLayerState.frontEnd.geomBufferTransform = entry.buffer; + mOutputState.orientation = entry.display; + + EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(entry.expected)) << "entry " << i; + } +} + +TEST_F(OutputLayerSourceCropTest, geomContentCropAffectsCrop) { + mLayerState.frontEnd.geomContentCrop = Rect{0, 0, 960, 540}; + + const FloatRect expected{0.f, 0.f, 960.f, 540.f}; + EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected)); +} + +TEST_F(OutputLayerSourceCropTest, viewportAffectsCrop) { + mOutputState.viewport = Rect{0, 0, 960, 540}; + + const FloatRect expected{0.f, 0.f, 960.f, 540.f}; + EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected)); +} + +/* * OutputLayer::calculateOutputDisplayFrame() */ @@ -163,7 +272,7 @@ TEST_F(OutputLayerDisplayFrameTest, emptyGeomCropIsNotUsedToComputeFrame) { EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected)); } -TEST_F(OutputLayerDisplayFrameTest, geomLayerSnapToBoundsAffectsFrame) { +TEST_F(OutputLayerDisplayFrameTest, geomLayerBoundsAffectsFrame) { mLayerState.frontEnd.geomLayerBounds = FloatRect{0.f, 0.f, 960.f, 540.f}; const Rect expected{0, 0, 960, 540}; EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected)); @@ -242,6 +351,159 @@ TEST_F(OutputLayerTest, calculateOutputRelativeBufferTransformTestsNeeded) { } } +TEST_F(OutputLayerTest, + calculateOutputRelativeBufferTransformTestWithOfBufferUsesDisplayInverseTransform) { + mLayerState.frontEnd.geomBufferUsesDisplayInverseTransform = true; + + struct Entry { + uint32_t layer; + uint32_t buffer; + uint32_t display; + uint32_t expected; + }; + // Not an exhaustive list of cases, but hopefully enough. + const std::array<Entry, 24> testData = { + // clang-format off + // layer buffer display expected + /* 0 */ Entry{TR_IDENT, TR_IDENT, TR_IDENT, TR_IDENT}, + /* 1 */ Entry{TR_IDENT, TR_IDENT, TR_ROT_90, TR_IDENT}, + /* 2 */ Entry{TR_IDENT, TR_IDENT, TR_ROT_180, TR_IDENT}, + /* 3 */ Entry{TR_IDENT, TR_IDENT, TR_ROT_270, TR_IDENT}, + + /* 4 */ Entry{TR_IDENT, TR_FLP_H, TR_IDENT, TR_FLP_H}, + /* 5 */ Entry{TR_IDENT, TR_FLP_H, TR_ROT_90, TR_FLP_H}, + /* 6 */ Entry{TR_IDENT, TR_FLP_H, TR_ROT_180, TR_FLP_H}, + /* 7 */ Entry{TR_IDENT, TR_FLP_H, TR_ROT_270, TR_FLP_H}, + + /* 8 */ Entry{TR_IDENT, TR_FLP_V, TR_IDENT, TR_FLP_V}, + /* 9 */ Entry{TR_IDENT, TR_ROT_90, TR_ROT_90, TR_ROT_90}, + /* 10 */ Entry{TR_IDENT, TR_ROT_180, TR_ROT_180, TR_ROT_180}, + /* 11 */ Entry{TR_IDENT, TR_ROT_270, TR_ROT_270, TR_ROT_270}, + + /* 12 */ Entry{TR_ROT_90, TR_IDENT, TR_IDENT, TR_IDENT}, + /* 13 */ Entry{TR_ROT_90, TR_FLP_H, TR_ROT_90, TR_FLP_H}, + /* 14 */ Entry{TR_ROT_90, TR_IDENT, TR_ROT_180, TR_IDENT}, + /* 15 */ Entry{TR_ROT_90, TR_FLP_H, TR_ROT_270, TR_FLP_H}, + + /* 16 */ Entry{TR_ROT_180, TR_FLP_H, TR_IDENT, TR_FLP_H}, + /* 17 */ Entry{TR_ROT_180, TR_IDENT, TR_ROT_90, TR_IDENT}, + /* 18 */ Entry{TR_ROT_180, TR_FLP_H, TR_ROT_180, TR_FLP_H}, + /* 19 */ Entry{TR_ROT_180, TR_IDENT, TR_ROT_270, TR_IDENT}, + + /* 20 */ Entry{TR_ROT_270, TR_IDENT, TR_IDENT, TR_IDENT}, + /* 21 */ Entry{TR_ROT_270, TR_FLP_H, TR_ROT_90, TR_FLP_H}, + /* 22 */ Entry{TR_ROT_270, TR_FLP_H, TR_ROT_180, TR_FLP_H}, + /* 23 */ Entry{TR_ROT_270, TR_IDENT, TR_ROT_270, TR_IDENT}, + // clang-format on + }; + + for (size_t i = 0; i < testData.size(); i++) { + const auto& entry = testData[i]; + + mLayerState.frontEnd.geomLayerTransform = ui::Transform{entry.layer}; + mLayerState.frontEnd.geomBufferTransform = entry.buffer; + mOutputState.orientation = entry.display; + + auto actual = mOutputLayer.calculateOutputRelativeBufferTransform(); + EXPECT_EQ(entry.expected, actual) << "entry " << i; + } +} + +/* + * OutputLayer::updateCompositionState() + */ + +struct OutputLayerPartialMockForUpdateCompositionState : public impl::OutputLayer { + OutputLayerPartialMockForUpdateCompositionState(const compositionengine::Output& output, + std::shared_ptr<compositionengine::Layer> layer, + sp<compositionengine::LayerFE> layerFE) + : impl::OutputLayer(output, layer, layerFE) {} + // Mock everything called by updateCompositionState to simplify testing it. + MOCK_CONST_METHOD0(calculateOutputSourceCrop, FloatRect()); + MOCK_CONST_METHOD0(calculateOutputDisplayFrame, Rect()); + MOCK_CONST_METHOD0(calculateOutputRelativeBufferTransform, uint32_t()); +}; + +struct OutputLayerUpdateCompositionStateTest : public OutputLayerTest { +public: + OutputLayerUpdateCompositionStateTest() { + EXPECT_CALL(*mLayer, getState()).WillRepeatedly(ReturnRef(mLayerState)); + EXPECT_CALL(mOutput, getState()).WillRepeatedly(ReturnRef(mOutputState)); + } + + ~OutputLayerUpdateCompositionStateTest() = default; + + void setupGeometryChildCallValues() { + EXPECT_CALL(mOutputLayer, calculateOutputSourceCrop()).WillOnce(Return(kSourceCrop)); + EXPECT_CALL(mOutputLayer, calculateOutputDisplayFrame()).WillOnce(Return(kDisplayFrame)); + EXPECT_CALL(mOutputLayer, calculateOutputRelativeBufferTransform()) + .WillOnce(Return(mBufferTransform)); + } + + void validateComputedGeometryState() { + const auto& state = mOutputLayer.getState(); + EXPECT_EQ(kSourceCrop, state.sourceCrop); + EXPECT_EQ(kDisplayFrame, state.displayFrame); + EXPECT_EQ(static_cast<Hwc2::Transform>(mBufferTransform), state.bufferTransform); + } + + const FloatRect kSourceCrop{1.f, 2.f, 3.f, 4.f}; + const Rect kDisplayFrame{11, 12, 13, 14}; + uint32_t mBufferTransform{21}; + + using OutputLayer = OutputLayerPartialMockForUpdateCompositionState; + StrictMock<OutputLayer> mOutputLayer{mOutput, mLayer, mLayerFE}; +}; + +TEST_F(OutputLayerUpdateCompositionStateTest, setsStateNormally) { + mLayerState.frontEnd.isSecure = true; + mOutputState.isSecure = true; + + setupGeometryChildCallValues(); + + mOutputLayer.updateCompositionState(true); + + validateComputedGeometryState(); + + EXPECT_EQ(false, mOutputLayer.getState().forceClientComposition); +} + +TEST_F(OutputLayerUpdateCompositionStateTest, + alsoSetsForceCompositionIfSecureLayerOnNonsecureOutput) { + mLayerState.frontEnd.isSecure = true; + mOutputState.isSecure = false; + + setupGeometryChildCallValues(); + + mOutputLayer.updateCompositionState(true); + + validateComputedGeometryState(); + + EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition); +} + +TEST_F(OutputLayerUpdateCompositionStateTest, + alsoSetsForceCompositionIfUnsupportedBufferTransform) { + mLayerState.frontEnd.isSecure = true; + mOutputState.isSecure = true; + + mBufferTransform = ui::Transform::ROT_INVALID; + + setupGeometryChildCallValues(); + + mOutputLayer.updateCompositionState(true); + + validateComputedGeometryState(); + + EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition); +} + +TEST_F(OutputLayerUpdateCompositionStateTest, doesNotRecomputeGeometryIfNotRequested) { + mOutputLayer.updateCompositionState(false); + + EXPECT_EQ(false, mOutputLayer.getState().forceClientComposition); +} + /* * OutputLayer::writeStateToHWC() */ diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp index f75a4dcb85..87419ea6a8 100644 --- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp @@ -364,20 +364,6 @@ TEST_F(RenderSurfaceTest, onPresentDisplayCompletedForwardsSignal) { } /* ------------------------------------------------------------------------ - * RenderSurface::setViewportAndProjection() - */ - -TEST_F(RenderSurfaceTest, setViewportAndProjectionAppliesChang) { - mSurface.setSizeForTest(ui::Size(100, 200)); - - EXPECT_CALL(mRenderEngine, - setViewportAndProjection(100, 200, Rect(100, 200), ui::Transform::ROT_0)) - .Times(1); - - mSurface.setViewportAndProjection(); -} - -/* ------------------------------------------------------------------------ * RenderSurface::flip() */ diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index bda7e4308f..83ab5cfce2 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -430,7 +430,7 @@ void Layer::latchGeometry(compositionengine::LayerFECompositionState& compositio auto& parentState = parent->getDrawingState(); const int parentType = parentState.metadata.getInt32(METADATA_WINDOW_TYPE, 0); const int parentAppId = parentState.metadata.getInt32(METADATA_OWNER_UID, 0); - if (parentType >= 0 || parentAppId >= 0) { + if (parentType > 0 && parentAppId > 0) { type = parentType; appId = parentAppId; } @@ -619,32 +619,6 @@ bool Layer::addSyncPoint(const std::shared_ptr<SyncPoint>& point) { // local state // ---------------------------------------------------------------------------- -void Layer::computeGeometry(const RenderArea& renderArea, - renderengine::Mesh& mesh, - bool useIdentityTransform) const { - const ui::Transform renderAreaTransform(renderArea.getTransform()); - FloatRect win = getBounds(); - - vec2 lt = vec2(win.left, win.top); - vec2 lb = vec2(win.left, win.bottom); - vec2 rb = vec2(win.right, win.bottom); - vec2 rt = vec2(win.right, win.top); - - ui::Transform layerTransform = getTransform(); - if (!useIdentityTransform) { - lt = layerTransform.transform(lt); - lb = layerTransform.transform(lb); - rb = layerTransform.transform(rb); - rt = layerTransform.transform(rt); - } - - renderengine::Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>()); - position[0] = renderAreaTransform.transform(lt); - position[1] = renderAreaTransform.transform(lb); - position[2] = renderAreaTransform.transform(rb); - position[3] = renderAreaTransform.transform(rt); -} - bool Layer::isSecure() const { const State& s(mDrawingState); return (s.flags & layer_state_t::eLayerSecure); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 6db6beb4f6..8a4d87f889 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -357,8 +357,6 @@ public: return getLayerStack() == layerStack && (!mPrimaryDisplayOnly || isPrimaryDisplay); } - void computeGeometry(const RenderArea& renderArea, renderengine::Mesh& mesh, - bool useIdentityTransform) const; FloatRect getBounds(const Region& activeTransparentRegion) const; FloatRect getBounds() const; diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp index c60421b538..7a959f7b19 100644 --- a/services/surfaceflinger/MonitoredProducer.cpp +++ b/services/surfaceflinger/MonitoredProducer.cpp @@ -154,6 +154,10 @@ status_t MonitoredProducer::getConsumerUsage(uint64_t* outUsage) const { return mProducer->getConsumerUsage(outUsage); } +status_t MonitoredProducer::setAutoPrerotation(bool autoPrerotation) { + return mProducer->setAutoPrerotation(autoPrerotation); +} + IBinder* MonitoredProducer::onAsBinder() { return this; } diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h index d346f821d3..788919b3da 100644 --- a/services/surfaceflinger/MonitoredProducer.h +++ b/services/surfaceflinger/MonitoredProducer.h @@ -70,6 +70,7 @@ public: virtual void getFrameTimestamps(FrameEventHistoryDelta *outDelta) override; virtual status_t getUniqueId(uint64_t* outId) const override; virtual status_t getConsumerUsage(uint64_t* outUsage) const override; + virtual status_t setAutoPrerotation(bool autoPrerotation) override; // The Layer which created this producer, and on which queued Buffer's will be displayed. sp<Layer> getLayer() const; diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h index 96ffe207e4..99c07c288e 100644 --- a/services/surfaceflinger/RegionSamplingThread.h +++ b/services/surfaceflinger/RegionSamplingThread.h @@ -27,7 +27,7 @@ #include <ui/GraphicBuffer.h> #include <ui/Rect.h> #include <utils/StrongPointer.h> -#include "Scheduler/IdleTimer.h" +#include "Scheduler/OneShotTimer.h" namespace android { @@ -107,7 +107,7 @@ private: SurfaceFlinger& mFlinger; Scheduler& mScheduler; const TimingTunables mTunables; - scheduler::IdleTimer mIdleTimer; + scheduler::OneShotTimer mIdleTimer; std::unique_ptr<SamplingOffsetCallback> const mPhaseCallback; diff --git a/services/surfaceflinger/Scheduler/IdleTimer.cpp b/services/surfaceflinger/Scheduler/OneShotTimer.cpp index 37fdfc7c62..4870a3bbdd 100644 --- a/services/surfaceflinger/Scheduler/IdleTimer.cpp +++ b/services/surfaceflinger/Scheduler/OneShotTimer.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "IdleTimer.h" +#include "OneShotTimer.h" #include <chrono> #include <thread> @@ -22,23 +22,23 @@ namespace android { namespace scheduler { -IdleTimer::IdleTimer(const Interval& interval, const ResetCallback& resetCallback, - const TimeoutCallback& timeoutCallback) +OneShotTimer::OneShotTimer(const Interval& interval, const ResetCallback& resetCallback, + const TimeoutCallback& timeoutCallback) : mInterval(interval), mResetCallback(resetCallback), mTimeoutCallback(timeoutCallback) {} -IdleTimer::~IdleTimer() { +OneShotTimer::~OneShotTimer() { stop(); } -void IdleTimer::start() { +void OneShotTimer::start() { { std::lock_guard<std::mutex> lock(mMutex); mState = TimerState::RESET; } - mThread = std::thread(&IdleTimer::loop, this); + mThread = std::thread(&OneShotTimer::loop, this); } -void IdleTimer::stop() { +void OneShotTimer::stop() { { std::lock_guard<std::mutex> lock(mMutex); mState = TimerState::STOPPED; @@ -49,7 +49,7 @@ void IdleTimer::stop() { } } -void IdleTimer::loop() { +void OneShotTimer::loop() { while (true) { bool triggerReset = false; bool triggerTimeout = false; @@ -100,7 +100,7 @@ void IdleTimer::loop() { } } // namespace scheduler -void IdleTimer::reset() { +void OneShotTimer::reset() { { std::lock_guard<std::mutex> lock(mMutex); mState = TimerState::RESET; diff --git a/services/surfaceflinger/Scheduler/IdleTimer.h b/services/surfaceflinger/Scheduler/OneShotTimer.h index 2646688860..fd1aa02226 100644 --- a/services/surfaceflinger/Scheduler/IdleTimer.h +++ b/services/surfaceflinger/Scheduler/OneShotTimer.h @@ -29,15 +29,15 @@ namespace scheduler { * Class that sets off a timer for a given interval, and fires a callback when the * interval expires. */ -class IdleTimer { +class OneShotTimer { public: using Interval = std::chrono::milliseconds; using ResetCallback = std::function<void()>; using TimeoutCallback = std::function<void()>; - IdleTimer(const Interval& interval, const ResetCallback& resetCallback, - const TimeoutCallback& timeoutCallback); - ~IdleTimer(); + OneShotTimer(const Interval& interval, const ResetCallback& resetCallback, + const TimeoutCallback& timeoutCallback); + ~OneShotTimer(); // Initializes and turns on the idle timer. void start(); diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index cfdbd91e35..27f42d23a3 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -38,9 +38,9 @@ #include "DispSyncSource.h" #include "EventControlThread.h" #include "EventThread.h" -#include "IdleTimer.h" #include "InjectVSyncSource.h" #include "LayerInfo.h" +#include "OneShotTimer.h" #include "SchedulerUtils.h" #include "SurfaceFlingerProperties.h" @@ -86,34 +86,29 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, if (mSetIdleTimerMs > 0) { if (mSupportKernelTimer) { - mIdleTimer = - std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds( - mSetIdleTimerMs), - [this] { resetKernelTimerCallback(); }, - [this] { - expiredKernelTimerCallback(); - }); + mIdleTimer = std::make_unique<scheduler::OneShotTimer>( + std::chrono::milliseconds(mSetIdleTimerMs), + [this] { resetKernelTimerCallback(); }, + [this] { expiredKernelTimerCallback(); }); } else { - mIdleTimer = std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds( - mSetIdleTimerMs), - [this] { resetTimerCallback(); }, - [this] { expiredTimerCallback(); }); + mIdleTimer = std::make_unique<scheduler::OneShotTimer>( + std::chrono::milliseconds(mSetIdleTimerMs), [this] { resetTimerCallback(); }, + [this] { expiredTimerCallback(); }); } mIdleTimer->start(); } if (mSetTouchTimerMs > 0) { // Touch events are coming to SF every 100ms, so the timer needs to be higher than that - mTouchTimer = - std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds(mSetTouchTimerMs), - [this] { resetTouchTimerCallback(); }, - [this] { expiredTouchTimerCallback(); }); + mTouchTimer = std::make_unique<scheduler::OneShotTimer>( + std::chrono::milliseconds(mSetTouchTimerMs), [this] { resetTouchTimerCallback(); }, + [this] { expiredTouchTimerCallback(); }); mTouchTimer->start(); } } Scheduler::~Scheduler() { - // Ensure the IdleTimer thread is joined before we start destroying state. + // Ensure the OneShotTimer threads are joined before we start destroying state. mTouchTimer.reset(); mIdleTimer.reset(); } diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index eaad37c3ee..a30776059f 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -26,9 +26,9 @@ #include "DispSync.h" #include "EventControlThread.h" #include "EventThread.h" -#include "IdleTimer.h" #include "InjectVSyncSource.h" #include "LayerHistory.h" +#include "OneShotTimer.h" #include "RefreshRateConfigs.h" #include "SchedulerUtils.h" @@ -273,14 +273,14 @@ private: // Timer that records time between requests for next vsync. If the time is higher than a given // interval, a callback is fired. Set this variable to >0 to use this feature. int64_t mSetIdleTimerMs = 0; - std::unique_ptr<scheduler::IdleTimer> mIdleTimer; + std::unique_ptr<scheduler::OneShotTimer> mIdleTimer; // Enables whether to use idle timer callbacks that support the kernel // timer. bool mSupportKernelTimer; // Timer used to monitor touch events. int64_t mSetTouchTimerMs = 0; - std::unique_ptr<scheduler::IdleTimer> mTouchTimer; + std::unique_ptr<scheduler::OneShotTimer> mTouchTimer; std::mutex mCallbackLock; ChangeRefreshRateCallback mChangeRefreshRateCallback GUARDED_BY(mCallbackLock); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 459cd0af89..2cb2544448 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1801,6 +1801,12 @@ void SurfaceFlinger::handleMessageRefresh() { mVsyncModulator.onRefreshed(mHadClientComposition); mLayersWithQueuedFrames.clear(); + if (mVisibleRegionsDirty) { + mVisibleRegionsDirty = false; + if (mTracingEnabled) { + mTracing.notify("visibleRegionsDirty"); + } + } } @@ -1810,9 +1816,6 @@ bool SurfaceFlinger::handleMessageInvalidate() { if (mVisibleRegionsDirty) { computeLayerBounds(); - if (mTracingEnabled) { - mTracing.notify("visibleRegionsDirty"); - } } for (auto& layer : mLayersPendingRefresh) { @@ -2214,7 +2217,6 @@ void SurfaceFlinger::rebuildLayerStacks() { // rebuild the visible layer list per screen if (CC_UNLIKELY(mVisibleRegionsDirty)) { ATRACE_NAME("rebuildLayerStacks VR Dirty"); - mVisibleRegionsDirty = false; invalidateHwcGeometry(); for (const auto& pair : mDisplays) { @@ -3532,11 +3534,6 @@ bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice, return true; } -void SurfaceFlinger::drawWormhole(const Region& region) const { - auto& engine(getRenderEngine()); - engine.fillRegionWithColor(region, 0, 0, 0, 0); -} - status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBinder>& handle, const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc, const sp<IBinder>& parentHandle, @@ -3931,6 +3928,11 @@ uint32_t SurfaceFlinger::setClientStateLocked( sp<Layer> layer(client->getLayerUser(s.surface)); if (layer == nullptr) { + for (auto& listenerCallback : listenerCallbacks) { + mTransactionCompletedThread.addUnpresentedCallbackHandle( + new CallbackHandle(listenerCallback.transactionCompletedListener, + listenerCallback.callbackIds, s.surface)); + } return 0; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 6d4b2d755c..1a9dcdd2ef 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -790,7 +790,6 @@ private: void postFramebuffer(const sp<DisplayDevice>& display); void postFrame(); - void drawWormhole(const Region& region) const; /* ------------------------------------------------------------------------ * Display management diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h index 4773307a65..18524f02d8 100644 --- a/services/surfaceflinger/SurfaceTracing.h +++ b/services/surfaceflinger/SurfaceTracing.h @@ -61,7 +61,7 @@ public: void setTraceFlags(uint32_t flags); private: - static constexpr auto kDefaultBufferCapInByte = 100_MB; + static constexpr auto kDefaultBufferCapInByte = 5_MB; static constexpr auto kDefaultFileName = "/data/misc/wmtrace/layers_trace.pb"; class LayersTraceBuffer { // ring buffer diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop index decabd5e88..a8ec7649c6 100644 --- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop +++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop @@ -36,7 +36,7 @@ owner: Platform prop { api_name: "vsync_event_phase_offset_ns" type: Long - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.vsync_event_phase_offset_ns" } @@ -44,7 +44,7 @@ prop { prop { api_name: "vsync_sf_event_phase_offset_ns" type: Long - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.vsync_sf_event_phase_offset_ns" } @@ -53,7 +53,7 @@ prop { prop { api_name: "use_context_priority" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.use_context_priority" } @@ -62,7 +62,7 @@ prop { prop { api_name: "max_frame_buffer_acquired_buffers" type: Long - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.max_frame_buffer_acquired_buffers" } @@ -80,7 +80,7 @@ prop { prop { api_name: "has_wide_color_display" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.has_wide_color_display" } @@ -90,7 +90,7 @@ prop { prop { api_name: "running_without_sync_framework" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.running_without_sync_framework" } @@ -108,7 +108,7 @@ prop { prop { api_name: "has_HDR_display" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.has_HDR_display" } @@ -117,7 +117,7 @@ prop { prop { api_name: "present_time_offset_from_vsync_ns" type: Long - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.present_time_offset_from_vsync_ns" } @@ -129,7 +129,7 @@ prop { prop { api_name: "force_hwc_copy_for_virtual_displays" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.force_hwc_copy_for_virtual_displays" } @@ -139,7 +139,7 @@ prop { prop { api_name: "max_virtual_display_dimension" type: Long - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.max_virtual_display_dimension" } @@ -151,7 +151,7 @@ prop { prop { api_name: "use_vr_flinger" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.use_vr_flinger" } @@ -161,7 +161,7 @@ prop { prop { api_name: "start_graphics_allocator_service" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.start_graphics_allocator_service" } @@ -171,7 +171,7 @@ prop { api_name: "primary_display_orientation" type: Enum enum_values: "ORIENTATION_0|ORIENTATION_90|ORIENTATION_180|ORIENTATION_270" - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.primary_display_orientation" } @@ -182,7 +182,7 @@ prop { prop { api_name: "use_color_management" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.use_color_management" } @@ -209,7 +209,7 @@ prop { prop { api_name: "default_composition_dataspace" type: Long - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.default_composition_dataspace" } @@ -220,7 +220,7 @@ prop { prop { api_name: "default_composition_pixel_format" type: Integer - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.default_composition_pixel_format" } @@ -235,7 +235,7 @@ prop { prop { api_name: "wcg_composition_dataspace" type: Long - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.wcg_composition_dataspace" } @@ -246,7 +246,7 @@ prop { prop { api_name: "wcg_composition_pixel_format" type: Integer - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.wcg_composition_pixel_format" } @@ -258,7 +258,7 @@ prop { prop { api_name: "display_primary_red" type: DoubleList - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.display_primary_red" } @@ -266,7 +266,7 @@ prop { prop { api_name: "display_primary_green" type: DoubleList - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.display_primary_green" } @@ -274,7 +274,7 @@ prop { prop { api_name: "display_primary_blue" type: DoubleList - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.display_primary_blue" } @@ -282,7 +282,7 @@ prop { prop { api_name: "display_primary_white" type: DoubleList - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.display_primary_white" } @@ -293,7 +293,7 @@ prop { prop { api_name: "set_idle_timer_ms" type: Integer - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.set_idle_timer_ms" } @@ -304,7 +304,7 @@ prop { prop { api_name: "set_touch_timer_ms" type: Integer - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.set_touch_timer_ms" } @@ -314,7 +314,7 @@ prop { prop { api_name: "use_smart_90_for_video" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.use_smart_90_for_video" } @@ -322,7 +322,7 @@ prop { prop { api_name: "enable_protected_contents" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.protected_contents" } @@ -332,7 +332,7 @@ prop { prop { api_name: "support_kernel_idle_timer" type: Boolean - scope: System + scope: Public access: Readonly prop_name: "ro.surface_flinger.support_kernel_idle_timer" } diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index f842d61c7f..4917bc2a51 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -42,7 +42,7 @@ cc_test { "DisplayTransactionTest.cpp", "EventControlThreadTest.cpp", "EventThreadTest.cpp", - "IdleTimerTest.cpp", + "OneShotTimerTest.cpp", "LayerHistoryTest.cpp", "LayerMetadataTest.cpp", "SchedulerTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 4f8ed1ae1c..e6211c488e 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -303,11 +303,6 @@ struct BaseDisplayVariant { EXPECT_CALL(*test->mComposer, getReleaseFences(HWC_DISPLAY, _, _)).Times(1); EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true)); - // TODO: remove once we verify that we can just grab the fence from the - // FramebufferSurface. - EXPECT_CALL(*test->mRenderEngine, flush()).WillRepeatedly(Invoke([]() { - return base::unique_fd(); - })); EXPECT_CALL(*test->mDisplaySurface, onFrameCommitted()).Times(1); EXPECT_CALL(*test->mDisplaySurface, advanceFrame()).Times(1); diff --git a/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp index eff22b6640..0208728026 100644 --- a/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp +++ b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp @@ -21,17 +21,17 @@ #include <utils/Log.h> #include "AsyncCallRecorder.h" -#include "Scheduler/IdleTimer.h" +#include "Scheduler/OneShotTimer.h" using namespace std::chrono_literals; namespace android { namespace scheduler { -class IdleTimerTest : public testing::Test { +class OneShotTimerTest : public testing::Test { protected: - IdleTimerTest() = default; - ~IdleTimerTest() override = default; + OneShotTimerTest() = default; + ~OneShotTimerTest() override = default; // This timeout should be used when a 3ms callback is expected. // While the tests typically request a callback after 3ms, the scheduler @@ -46,7 +46,7 @@ protected: AsyncCallRecorder<void (*)()> mResetTimerCallback; AsyncCallRecorder<void (*)()> mExpiredTimerCallback; - std::unique_ptr<IdleTimer> mIdleTimer; + std::unique_ptr<OneShotTimer> mIdleTimer; void clearPendingCallbacks() { while (mExpiredTimerCallback.waitForCall(0us).has_value()) { @@ -55,13 +55,14 @@ protected: }; namespace { -TEST_F(IdleTimerTest, createAndDestroyTest) { - mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, [] {}, [] {}); +TEST_F(OneShotTimerTest, createAndDestroyTest) { + mIdleTimer = std::make_unique<scheduler::OneShotTimer>( + 3ms, [] {}, [] {}); } -TEST_F(IdleTimerTest, startStopTest) { - mIdleTimer = std::make_unique<scheduler::IdleTimer>(30ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); +TEST_F(OneShotTimerTest, startStopTest) { + mIdleTimer = std::make_unique<scheduler::OneShotTimer>(30ms, mResetTimerCallback.getInvocable(), + mExpiredTimerCallback.getInvocable()); auto startTime = std::chrono::steady_clock::now(); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); @@ -70,7 +71,7 @@ TEST_F(IdleTimerTest, startStopTest) { bool callbackCalled = mExpiredTimerCallback.waitForCall(25ms).has_value(); // Under ideal conditions there should be no event. But occasionally // it is possible that the wait just prior takes more than 30ms, and - // a callback is observed. We check the elapsed time since before the IdleTimer + // a callback is observed. We check the elapsed time since before the OneShotTimer // thread was started as a sanity check to not have a flakey test. EXPECT_FALSE(callbackCalled && std::chrono::steady_clock::now() - startTime < 30ms); @@ -79,9 +80,9 @@ TEST_F(IdleTimerTest, startStopTest) { mIdleTimer->stop(); } -TEST_F(IdleTimerTest, resetTest) { - mIdleTimer = std::make_unique<scheduler::IdleTimer>(20ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); +TEST_F(OneShotTimerTest, resetTest) { + mIdleTimer = std::make_unique<scheduler::OneShotTimer>(20ms, mResetTimerCallback.getInvocable(), + mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); // Observe any event that happens in about 25ms. We don't care if one was @@ -104,9 +105,9 @@ TEST_F(IdleTimerTest, resetTest) { EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value()); } -TEST_F(IdleTimerTest, resetBackToBackTest) { - mIdleTimer = std::make_unique<scheduler::IdleTimer>(20ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); +TEST_F(OneShotTimerTest, resetBackToBackTest) { + mIdleTimer = std::make_unique<scheduler::OneShotTimer>(20ms, mResetTimerCallback.getInvocable(), + mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); @@ -135,9 +136,9 @@ TEST_F(IdleTimerTest, resetBackToBackTest) { EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value()); } -TEST_F(IdleTimerTest, startNotCalledTest) { - mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); +TEST_F(OneShotTimerTest, startNotCalledTest) { + mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(), + mExpiredTimerCallback.getInvocable()); // The start hasn't happened, so the callback does not happen. EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value()); EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value()); @@ -147,9 +148,9 @@ TEST_F(IdleTimerTest, startNotCalledTest) { EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value()); } -TEST_F(IdleTimerTest, idleTimerIdlesTest) { - mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); +TEST_F(OneShotTimerTest, idleTimerIdlesTest) { + mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(), + mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); @@ -167,18 +168,18 @@ TEST_F(IdleTimerTest, idleTimerIdlesTest) { EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value()); } -TEST_F(IdleTimerTest, timeoutCallbackExecutionTest) { - mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); +TEST_F(OneShotTimerTest, timeoutCallbackExecutionTest) { + mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(), + mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value()); mIdleTimer->stop(); } -TEST_F(IdleTimerTest, noCallbacksAfterStopAndResetTest) { - mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); +TEST_F(OneShotTimerTest, noCallbacksAfterStopAndResetTest) { + mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(), + mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value()); @@ -190,9 +191,9 @@ TEST_F(IdleTimerTest, noCallbacksAfterStopAndResetTest) { EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value()); } -TEST_F(IdleTimerTest, noCallbacksAfterStopTest) { - mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(), - mExpiredTimerCallback.getInvocable()); +TEST_F(OneShotTimerTest, noCallbacksAfterStopTest) { + mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(), + mExpiredTimerCallback.getInvocable()); mIdleTimer->start(); EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value()); diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp index a7fd912294..b71964ba00 100644 --- a/services/vr/bufferhubd/producer_channel.cpp +++ b/services/vr/bufferhubd/producer_channel.cpp @@ -350,7 +350,7 @@ Status<RemoteChannelHandle> ProducerChannel::CreateConsumer( while (!buffer_state_->compare_exchange_weak( current_buffer_state, updated_buffer_state, std::memory_order_acq_rel, std::memory_order_acquire)) { - ALOGI( + ALOGV( "%s: Failed to post to the new consumer. " "Current buffer state was changed to %" PRIx32 " when trying to acquire the buffer and modify the buffer state to " diff --git a/services/vr/hardware_composer/impl/vr_hwc.cpp b/services/vr/hardware_composer/impl/vr_hwc.cpp index fb7932d804..7323277248 100644 --- a/services/vr/hardware_composer/impl/vr_hwc.cpp +++ b/services/vr/hardware_composer/impl/vr_hwc.cpp @@ -994,6 +994,26 @@ void VrHwc::UpdateVsyncCallbackEnabledLocked() { vsync_callback_->SetEventCallback(send_vsync ? event_callback_ : nullptr); } +Return<void> VrHwc::debug(const hidl_handle& fd, + const hidl_vec<hidl_string>& args) { + std::string result; + + { + std::lock_guard<std::mutex> guard(mutex_); + for (const auto& pair : displays_) { + result += StringPrintf("Display id: %d\n", static_cast<int>(pair.first)); + pair.second->dumpDebugInfo(&result); + } + result += "\n"; + } + + FILE* out = fdopen(dup(fd->data[0]), "w"); + fprintf(out, "%s", result.c_str()); + fclose(out); + + return Void(); +} + void HwcLayer::dumpDebugInfo(std::string* result) const { if (!result) { return; diff --git a/services/vr/hardware_composer/impl/vr_hwc.h b/services/vr/hardware_composer/impl/vr_hwc.h index e8c0212039..15358c57bb 100644 --- a/services/vr/hardware_composer/impl/vr_hwc.h +++ b/services/vr/hardware_composer/impl/vr_hwc.h @@ -295,6 +295,9 @@ class VrHwc : public IComposer, public ComposerHal, public ComposerView { void RegisterObserver(Observer* observer) override; void UnregisterObserver(Observer* observer) override; + Return<void> debug(const hidl_handle& fd, + const hidl_vec<hidl_string>& args) override; + private: class VsyncCallback : public BnVsyncCallback { public: diff --git a/services/vr/virtual_touchpad/virtual_touchpad.rc b/services/vr/virtual_touchpad/virtual_touchpad.rc index 99315ef341..0de0f9eec7 100644 --- a/services/vr/virtual_touchpad/virtual_touchpad.rc +++ b/services/vr/virtual_touchpad/virtual_touchpad.rc @@ -1,5 +1,5 @@ service virtual_touchpad /system/bin/virtual_touchpad class core user system - group system input + group system input uhid writepid /dev/cpuset/system/tasks diff --git a/vulkan/api/templates/asciidoc.tmpl b/vulkan/api/templates/asciidoc.tmpl deleted file mode 100644 index 3009e19cad..0000000000 --- a/vulkan/api/templates/asciidoc.tmpl +++ /dev/null @@ -1,151 +0,0 @@ -{{Include "vulkan_common.tmpl"}} -{{if not (Global "AsciiDocPath")}}{{Global "AsciiDocPath" "../../doc/specs/vulkan/"}}{{end}} -{{$ | Macro "AsciiDoc.Main"}} - - -{{/* -------------------------------------------------------------------------------- - AsciiDoc generation main entry point. -------------------------------------------------------------------------------- -*/}} -{{define "AsciiDoc.Main"}} - {{$docPath := Global "AsciiDocPath"}} - - {{/* Generate AsciiDoc files for API enums and bitfields (flags). */}} - {{range $e := $.Enums}} - {{if not $e.IsBitfield}} - {{$filename := print $docPath "enums/" (Macro "EnumName" $e) ".txt"}} - {{Macro "AsciiDoc.Write" "Code" (Macro "AsciiDoc.Enum" $e) "File" $filename}} - {{else}} - {{$filename := print $docPath "flags/" (Macro "EnumName" $e) ".txt"}} - {{Macro "AsciiDoc.Write" "Code" (Macro "AsciiDoc.Flag" $e) "File" $filename}} - {{end}} - {{end}} - - {{/* Generate AsciiDoc files for API commands (protos). */}} - {{range $f := (AllCommands $)}} - {{if not (GetAnnotation $f "pfn")}} - {{$filename := print $docPath "protos/" $f.Name ".txt"}} - {{Macro "AsciiDoc.Write" "Code" (Macro "AsciiDoc.Proto" $f) "File" $filename}} - {{end}} - {{end}} - - {{/* Generate AsciiDoc files for API structs. */}} - {{range $c := $.Classes}} - {{if not (GetAnnotation $c "internal")}} - {{$filename := print $docPath "structs/" $c.Name ".txt"}} - {{Macro "AsciiDoc.Write" "Code" (Macro "AsciiDoc.Struct" $c) "File" $filename}} - {{end}} - {{end}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the AsciiDoc contents for the specified API enum. -------------------------------------------------------------------------------- -*/}} -{{define "AsciiDoc.Enum"}} - {{AssertType $ "Enum"}} - - {{Macro "Docs" $.Docs}} - typedef enum { - {{range $i, $e := $.Entries}} - {{Macro "EnumEntry" $e}} = {{AsSigned $e.Value}}, {{Macro "Docs" $e.Docs}} - {{end}} - ¶ - {{$name := Macro "EnumName" $ | TrimRight "ABCDEFGHIJKLMNOQRSTUVWXYZ" | SplitPascalCase | Upper | JoinWith "_"}} - {{$first := Macro "EnumFirstEntry" $}} - {{$last := Macro "EnumLastEntry" $}} - {{$name}}_BEGIN_RANGE = {{$first}}, - {{$name}}_END_RANGE = {{$last}}, - {{$name}}_NUM = ({{$last}} - {{$first}} + 1), - {{$name}}_MAX_ENUM = 0x7FFFFFFF - } {{Macro "EnumName" $}}; -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the AsciiDoc contents for the specified API bitfield. -------------------------------------------------------------------------------- -*/}} -{{define "AsciiDoc.Flag"}} - {{AssertType $ "Enum"}} - - {{Macro "Docs" $.Docs}} - typedef VkFlags {{Macro "EnumName" $}}; - {{if $.Entries}} - typedef enum { - {{range $e := $.Entries}} - {{Macro "BitfieldEntryName" $e}} = {{printf "%#.8x" $e.Value}}, {{Macro "Docs" $e.Docs}} - {{end}} - } {{Macro "EnumName" $ | TrimRight "s"}}Bits; - {{end}} -{{end}} - - - -{{/* -------------------------------------------------------------------------------- - Emits the AsciiDoc contents for the specified API class. -------------------------------------------------------------------------------- -*/}} -{{define "AsciiDoc.Struct"}} - {{AssertType $ "Class"}} - - {{Macro "Docs" $.Docs}} - typedef {{if GetAnnotation $ "union"}}union{{else}}struct{{end}} { - {{range $f := $.Fields}} - {{Node "Type" $f}} {{$f.Name}}{{Macro "ArrayPostfix" (TypeOf $f)}}; {{Macro "Docs" $f.Docs}} - {{end}} - } {{Macro "StructName" $}}; -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the AsciiDoc contents for the specified API function. -------------------------------------------------------------------------------- -*/}} -{{define "AsciiDoc.Proto"}} - {{AssertType $ "Function"}} - - {{Macro "Docs" $.Docs}} - {{Node "Type" $.Return}} VKAPI {{Macro "FunctionName" $}}({{Macro "Parameters" $}}); -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Wraps the specified Code in AsciiDoc source tags then writes to the specified File. -------------------------------------------------------------------------------- -*/}} -{{define "AsciiDoc.Write"}} - {{AssertType $.Code "string"}} - {{AssertType $.File "string"}} - - {{$code := $.Code | Format (Global "clang-format")}} - {{JoinWith "\n" (Macro "AsciiDoc.Header") $code (Macro "AsciiDoc.Footer") ""| Write $.File}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits an AsciiDoc source header. -------------------------------------------------------------------------------- -*/}} -{{define "AsciiDoc.Header"}} -[source,{basebackend@docbook:c++:cpp}] ------------------------------------------------------------------------------- -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits an AsciiDoc source footer. -------------------------------------------------------------------------------- -*/}} -{{define "AsciiDoc.Footer"}} ------------------------------------------------------------------------------- -{{end}} diff --git a/vulkan/api/templates/vk_xml.tmpl b/vulkan/api/templates/vk_xml.tmpl deleted file mode 100644 index 893bde7833..0000000000 --- a/vulkan/api/templates/vk_xml.tmpl +++ /dev/null @@ -1,435 +0,0 @@ -{{Include "vulkan_common.tmpl"}} -{{Macro "DefineGlobals" $}} -{{$ | Macro "vk.xml" | Reflow 4 | Write "vk.xml"}} - - -{{/* -------------------------------------------------------------------------------- - Entry point -------------------------------------------------------------------------------- -*/}} -{{define "vk.xml"}} -<?xml version="1.0" encoding="UTF-8"?> -<registry> - »<comment>« -Copyright (c) 2015 The Khronos Group Inc. -¶ -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and/or associated documentation files (the -"Materials"), to deal in the Materials without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Materials, and to -permit persons to whom the Materials are furnished to do so, subject to -the following conditions: -¶ -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Materials. -¶ -THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. -¶ ------------------------------------------------------------------------- -¶ -This file, vk.xml, is the Vulkan API Registry.» - </comment> -¶ - <!-- SECTION: Vulkan type definitions --> - <types>» - <type name="vk_platform" category="include">#include "vk_platform.h"</type> -¶ - <type category="define">#define <name>VK_MAKE_VERSION</name>(major, minor, patch) \ - «((major << 22) | (minor << 12) | patch)</type>» -¶ - <type category="define">// Vulkan API version supported by this file«« -#define <name>VK_API_VERSION</name> <type>VK_MAKE_VERSION</type>({{Global "VERSION_MAJOR"}}, {{Global "VERSION_MINOR"}}, {{Global "VERSION_PATCH"}})</type> -¶ - »»<type category="define">«« -#if (_MSC_VER >= 1800 || __cplusplus >= 201103L) -#define <name>VK_NONDISP_HANDLE_OPERATOR_BOOL</name>() explicit operator bool() const { return handle != 0; } -#else -#define VK_NONDISP_HANDLE_OPERATOR_BOOL() -«#endif - »»»</type> -¶ - <type category="define">««« -#define <name>VK_DEFINE_HANDLE</name>(obj) typedef struct obj##_T* obj;</type> - »»»<type category="define">««« -#if defined(__cplusplus) - »»#if (_MSC_VER >= 1800 || __cplusplus >= 201103L) - »// The bool operator only works if there are no implicit conversions from an obj to - // a bool-compatible type, which can then be used to unintentionally violate type safety. - // C++11 and above supports the "explicit" keyword on conversion operators to stop this - // from happening. Otherwise users of C++ below C++11 won't get direct access to evaluating - // the object handle as a bool in expressions like: - // if (obj) vkDestroy(obj); - #define VK_NONDISP_HANDLE_OPERATOR_BOOL() explicit operator bool() const { return handle != 0; } - #define VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \ - explicit obj(uint64_t x) : handle(x) { } \ - obj(decltype(nullptr)) : handle(0) { } - «#else» - #define VK_NONDISP_HANDLE_OPERATOR_BOOL() - #define VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \ - obj(uint64_t x) : handle(x) { } - «#endif - #define <name>VK_DEFINE_NONDISP_HANDLE</name>(obj) \» - struct obj { \ - obj() { } \ - VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \ - obj& operator =(uint64_t x) { handle = x; return *this; } \ - bool operator==(const obj& other) const { return handle == other.handle; } \ - bool operator!=(const obj& other) const { return handle != other.handle; } \ - bool operator!() const { return !handle; } \ - VK_NONDISP_HANDLE_OPERATOR_BOOL() \ - uint64_t handle; \ - }; -««#else - »#define VK_DEFINE_NONDISP_HANDLE(obj) typedef struct obj##_T { uint64_t handle; } obj;« -#endif - »»</type> -¶ - <type category="define"> -#if defined(__cplusplus) && ((defined(_MSC_VER) && _MSC_VER >= 1800) || __cplusplus >= 201103L) - »#define <name>VK_NULL_HANDLE</name> nullptr -«#else - »#define VK_NULL_HANDLE 0 -«#endif - »»</type> -¶ - <type requires="vk_platform" name="VkDeviceSize"/> - <type requires="vk_platform" name="VkSampleMask"/> - <type requires="vk_platform" name="VkFlags"/> - <!-- Basic C types, pulled in via vk_platform.h --> - <type requires="vk_platform" name="char"/> - <type requires="vk_platform" name="float"/> - <type requires="vk_platform" name="VkBool32"/> - <type requires="vk_platform" name="uint8_t"/> - <type requires="vk_platform" name="uint32_t"/> - <type requires="vk_platform" name="uint64_t"/> - <type requires="vk_platform" name="int32_t"/> - <type requires="vk_platform" name="size_t"/> - <!-- Bitfield types --> - {{range $e := $.Enums}} - {{if $e.IsBitfield}} - {{$bits := print (Macro "EnumName" $e | TrimRight "s") "Bits"}} - <type{{if $e.Entries}} requires="{{$bits}}"{{end}} category="bitmask">typedef <type>VkFlags</type> <name>{{$e.Name}}</name>;</type>§ - {{if $e.Entries}}{{Macro "XML.Docs" $e.Docs}} - {{else}}{{Macro "XML.Docs" (Strings $e.Docs "(no bits yet)")}} - {{end}} - {{end}} - {{end}} -¶ - <!-- Types which can be void pointers or class pointers, selected at compile time --> - {{range $i, $p := $.Pseudonyms}} - {{ if (GetAnnotation $p "dispatchHandle")}} - {{if Global "VK_DEFINE_HANDLE_TYPE_DEFINED"}} - <type category="handle">VK_DEFINE_HANDLE(<name>{{$p.Name}}</name>)</type> - {{else}} - {{Global "VK_DEFINE_HANDLE_TYPE_DEFINED" "YES"}} - <type category="handle"><type>VK_DEFINE_HANDLE</type>(<name>{{$p.Name}}</name>)</type> - {{end}} - {{else if (GetAnnotation $p "nonDispatchHandle")}} - {{if Global "VK_DEFINE_NONDISP_HANDLE_TYPE_DEFINED"}} - <type category="handle">VK_DEFINE_NONDISP_HANDLE(<name>{{$p.Name}}</name>)</type> - {{else}} - {{Global "VK_DEFINE_NONDISP_HANDLE_TYPE_DEFINED" "YES"}} - <type category="handle"><type>VK_DEFINE_NONDISP_HANDLE</type>(<name>{{$p.Name}}</name>)</type> - {{end}} - {{end}} - {{end}} -¶ - <!-- Types generated from corresponding <enums> tags below --> - {{range $e := SortBy $.Enums "EnumName"}} - {{if and $e.Entries (not (GetAnnotation $e "internal"))}} - {{if $e.IsBitfield}} - <type name="{{Macro "EnumName" $e | TrimRight "s"}}Bits" category="enum"/> - {{else}} - <type name="{{$e.Name}}" category="enum"/> - {{end}} - {{end}} - {{end}} -¶ - <!-- The PFN_vk*Function types are used by VkAllocCallbacks below --> - <type>typedef void* (VKAPI *<name>PFN_vkAllocFunction</name>)(« - void* pUserData, - size_t size, - size_t alignment, - <type>VkSystemAllocType</type> allocType);</type>» - <type>typedef void (VKAPI *<name>PFN_vkFreeFunction</name>)(« - void* pUserData, - void* pMem);</type>» -¶ - <!-- The PFN_vkVoidFunction type are used by VkGet*ProcAddr below --> - <type>typedef void (VKAPI *<name>PFN_vkVoidFunction</name>)(void);</type> -¶ - <!-- Struct types --> - {{range $c := $.Classes}} - {{if not (GetAnnotation $c "internal")}} - {{Macro "Struct" $c}} - {{end}} - {{end}} - «</types> -¶ - <!-- SECTION: Vulkan enumerant (token) definitions. --> -¶ - <enums namespace="VK" comment="Misc. hardcoded constants - not an enumerated type">» - <!-- This is part of the header boilerplate --> - {{range $d := $.Definitions}} - {{if HasPrefix $d.Name "VK_"}} - <enum value="{{$d.Expression}}" name="{{$d.Name}}"/>{{Macro "XML.Docs" $d.Docs}} - {{end}} - {{end}} - <enum value="1000.0f" name="VK_LOD_CLAMP_NONE"/> - <enum value="(-0U)" name="VK_REMAINING_MIP_LEVELS"/> - <enum value="(~0U)" name="VK_REMAINING_ARRAY_LAYERS"/> - <enum value="(_0ULL)" name="VK_WHOLE_SIZE"/> - <enum value="(~0U)" name="VK_ATTACHMENT_UNUSED"/> - <enum value="(~0U)" name="VK_QUEUE_FAMILY_IGNORED"/> - <enum value="(~0U)" name="VK_SUBPASS_EXTERNAL"/> - «</enums> -¶ - <!-- Unlike OpenGL, most tokens in Vulkan are actual typed enumerants in» - their own numeric namespaces. The "name" attribute is the C enum - type name, and is pulled in from a <type> definition above - (slightly clunky, but retains the type / enum distinction). "type" - attributes of "enum" or "bitmask" indicate that these values should - be generated inside an appropriate definition. -->« -¶ - {{range $e := $.Enums}} - {{if not (or $e.IsBitfield (GetAnnotation $e "internal"))}} - {{Macro "XML.Enum" $e}} - {{end}} - {{end}} -¶ - <!-- Flags --> - {{range $e := $.Enums}} - {{if $e.IsBitfield}} - {{Macro "XML.Bitfield" $e}} - {{end}} - {{end}} -¶ - <!-- SECTION: Vulkan command definitions --> - <commands namespace="vk">» - {{range $f := AllCommands $}} - {{if not (GetAnnotation $f "pfn")}} - {{Macro "XML.Function" $f}} - {{end}} - {{end}} - «</commands> -¶ - <!-- SECTION: Vulkan API interface definitions --> - <feature api="vulkan" name="VK_VERSION_1_0" number="1.0">» - <require comment="Header boilerplate">» - <type name="vk_platform"/> - «</require> - <require comment="API version">» - <type name="VK_API_VERSION"/> - «</require> - <require comment="API constants">» - <enum name="VK_LOD_CLAMP_NONE"/> - <enum name="VK_REMAINING_MIP_LEVELS"/> - <enum name="VK_REMAINING_ARRAY_LAYERS"/> - <enum name="VK_WHOLE_SIZE"/> - <enum name="VK_ATTACHMENT_UNUSED"/> - <enum name="VK_TRUE"/> - <enum name="VK_FALSE"/> - «</require> - <require comment="All functions (TODO: split by type)">» - {{range $f := AllCommands $}} - {{if not (GetAnnotation $f "pfn")}} - <command name="{{$f.Name}}"/> - {{end}} - {{end}} - </require> - «<require comment="Types not directly used by the API">» - <!-- Include <type name="typename"/> here for e.g. structs that» - are not parameter types of commands, but still need to be - defined in the API. - «--> - <type name="VkBufferMemoryBarrier"/> - <type name="VkDispatchIndirectCmd"/> - <type name="VkDrawIndexedIndirectCmd"/> - <type name="VkDrawIndirectCmd"/> - <type name="VkImageMemoryBarrier"/> - <type name="VkMemoryBarrier"/> - «</require> - «</feature> -¶ - <!-- SECTION: Vulkan extension interface definitions (none yet) --> -«</registry> -{{end}} - -{{/* -------------------------------------------------------------------------------- - Emits the C declaration for the specified bitfield. -------------------------------------------------------------------------------- -*/}} -{{define "XML.Bitfield"}} - {{AssertType $ "Enum"}} - - {{if $.Entries}} - <enums namespace="VK" name="{{Macro "EnumName" $ | TrimRight "s"}}Bits" type="bitmask">» - {{range $e := $.Entries}} - {{$pos := Bitpos $e.Value}} - <enum § - {{if gt $pos -1}} bitpos="{{$pos}}" § - {{else}}value="{{if $e.Value}}{{printf "0x%.8X" $e.Value}}{{else}}0{{end}}" § - {{end}}name="{{Macro "BitfieldEntryName" $e}}" § - {{if $d := $e.Docs}} comment="{{$d | JoinWith " "}}"{{end}}/> - {{end}} - «</enums> - {{end}} - -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the C declaration for the specified enum. -------------------------------------------------------------------------------- -*/}} -{{define "XML.Enum"}} - {{AssertType $ "Enum"}} - - <enums namespace="VK" name="{{Macro "EnumName" $}}" type="enum" § - expand="{{Macro "EnumName" $ | SplitPascalCase | Upper | JoinWith "_"}}"{{if $.Docs}} comment="{{$.Docs | JoinWith " "}}"{{end}}>» - {{range $i, $e := $.Entries}} - <enum value="{{AsSigned $e.Value}}" name="{{Macro "BitfieldEntryName" $e}}"{{if $e.Docs}} comment="{{$e.Docs | JoinWith " "}}"{{end}}/> - {{end}} - {{if $lu := GetAnnotation $ "lastUnused"}} - <unused start="{{index $lu.Arguments 0}}"/> - {{end}} - «</enums> -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the C declaration for the specified class. -------------------------------------------------------------------------------- -*/}} -{{define "Struct"}} - {{AssertType $ "Class"}} - - <type category="{{Macro "StructType" $}}" name="{{Macro "StructName" $}}"{{if $.Docs}} comment="{{$.Docs | JoinWith " "}}"{{end}}>» - {{range $f := $.Fields}} - <member>{{Node "XML.Type" $f}} <name>{{$f.Name}}</name>{{Macro "XML.ArrayPostfix" $f}}</member>{{Macro "XML.Docs" $f.Docs}} - {{end}} - «</type> -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits either 'struct' or 'union' for the specified class. -------------------------------------------------------------------------------- -*/}} -{{define "StructType"}} - {{AssertType $ "Class"}} - - {{if GetAnnotation $ "union"}}union{{else}}struct{{end}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the C function pointer typedef declaration for the specified command. -------------------------------------------------------------------------------- -*/}} -{{define "XML.Function"}} - {{AssertType $ "Function"}} - - {{$ts := GetAnnotation $ "threadSafety"}} - <command{{if $ts}} threadsafe="{{index $ts.Arguments 0}}"{{end}}>» - <proto>{{Node "XML.Type" $.Return}} <name>{{$.Name}}</name></proto> - {{range $p := $.CallParameters}} - <param>{{Node "XML.Type" $p}} <name>{{$p.Name}}{{Macro "ArrayPostfix" $p}}</name></param> - {{end}} - «</command> -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the XML translation for the specified documentation block (string array). -------------------------------------------------------------------------------- -*/}} -{{define "XML.Docs"}} - {{if $}} <!-- {{JoinWith " " $ | Replace "<" "" | Replace ">" ""}} -->{{end}} -{{end}} - -{{/* -------------------------------------------------------------------------------- - Emits the C translation for the specified type. -------------------------------------------------------------------------------- -*/}} -{{define "XML.Type.Class" }}<type>{{Macro "StructName" $.Type}}</type>{{end}} -{{define "XML.Type.Pseudonym" }}<type>{{$.Type.Name}}</type>{{end}} -{{define "XML.Type.Enum" }}<type>{{$.Type.Name}}</type>{{end}} -{{define "XML.Type.StaticArray"}}{{Node "XML.Type" $.Type.ValueType}}{{end}} -{{define "XML.Type.Pointer" }}{{if $.Type.Const}}{{Node "XML.ConstType" $.Type.To}}{{else}}{{Node "XML.Type" $.Type.To}}{{end}}*{{end}} -{{define "XML.Type.Slice" }}<type>{{Node "XML.Type" $.Type.To}}</type>*{{end}} -{{define "XML.Type#s8" }}<type>int8_t</type>{{end}} -{{define "XML.Type#u8" }}<type>uint8_t</type>{{end}} -{{define "XML.Type#s16" }}<type>int16_t</type>{{end}} -{{define "XML.Type#u16" }}<type>uint16_t</type>{{end}} -{{define "XML.Type#s32" }}<type>int32_t</type>{{end}} -{{define "XML.Type#u32" }}<type>uint32_t</type>{{end}} -{{define "XML.Type#f32" }}<type>float</type>{{end}} -{{define "XML.Type#s64" }}<type>int64_t</type>{{end}} -{{define "XML.Type#u64" }}<type>uint64_t</type>{{end}} -{{define "XML.Type#f64" }}<type>double</type>{{end}} -{{define "XML.Type#char" }}<type>char</type>{{end}} -{{define "XML.Type#void" }}void{{end}} - -{{define "XML.ConstType_Default"}}const {{Node "XML.Type" $.Type}}{{end}} -{{define "XML.ConstType.Pointer"}}{{Node "XML.Type" $.Type}} const{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits a C type and name for the given parameter -------------------------------------------------------------------------------- -*/}} -{{define "XML.Parameter"}} - {{AssertType $ "Parameter"}} - - <type>{{Macro "ParameterType" $}}</type> <name>{{$.Name}}{{Macro "ArrayPostfix" $}}</name> -{{end}} - -{{/* -------------------------------------------------------------------------------- - Emits a comma-separated list of C type-name paired parameters for the given - command. -------------------------------------------------------------------------------- -*/}} -{{define "XML.Parameters"}} - {{AssertType $ "Function"}} - - {{ForEach $.CallParameters "XML.Parameter" | JoinWith ", "}} - {{if not $.CallParameters}}<type>void</type>{{end}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the fixed-size-array postfix for pseudonym types annotated with @array -------------------------------------------------------------------------------- -*/}} -{{define "XML.ArrayPostfix"}}{{Node "XML.ArrayPostfix" $}}{{end}} -{{define "XML.ArrayPostfix.StaticArray"}}[{{Node "XML.NamedValue" $.Type.SizeExpr}}]{{end}} -{{define "XML.ArrayPostfix_Default"}}{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the value of the given constant, or the <enum> tagged name if existant. -------------------------------------------------------------------------------- -*/}} -{{define "XML.NamedValue.Definition"}}<enum>{{$.Node.Name}}</enum>{{end}} -{{define "XML.NamedValue.EnumEntry"}}<enum>{{$.Node.Name}}</enum>{{end}} -{{define "XML.NamedValue_Default"}}{{$.Node}}{{end}} diff --git a/vulkan/api/templates/vulkan_h.tmpl b/vulkan/api/templates/vulkan_h.tmpl deleted file mode 100644 index 83a5e40804..0000000000 --- a/vulkan/api/templates/vulkan_h.tmpl +++ /dev/null @@ -1,295 +0,0 @@ -{{Include "vulkan_common.tmpl"}} -{{Macro "DefineGlobals" $}} -{{$ | Macro "vulkan.h" | Format (Global "clang-format") | Write "../include/vulkan.h"}} - - -{{/* -------------------------------------------------------------------------------- - Entry point -------------------------------------------------------------------------------- -*/}} -{{define "vulkan.h"}} -#ifndef __vulkan_h_ -#define __vulkan_h_ 1 -¶ -#ifdef __cplusplus -extern "C" { -#endif -¶ -/* -** Copyright (c) 2015-2016 The Khronos Group Inc. -** -** Permission is hereby granted, free of charge, to any person obtaining a -** copy of this software and/or associated documentation files (the -** "Materials"), to deal in the Materials without restriction, including -** without limitation the rights to use, copy, modify, merge, publish, -** distribute, sublicense, and/or sell copies of the Materials, and to -** permit persons to whom the Materials are furnished to do so, subject to -** the following conditions: -** -** The above copyright notice and this permission notice shall be included -** in all copies or substantial portions of the Materials. -** -** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. -*/ -¶ -/* -** This header is generated from the Khronos Vulkan API Registry. -** -*/ -¶ -#define VK_VERSION_1_0 1 -#include "vk_platform.h" -¶ -#define VK_MAKE_VERSION(major, minor, patch) (((major) << 22) | ((minor) << 12) | (patch)) -¶ -// Vulkan API version supported by this file -#define VK_API_VERSION \ - VK_MAKE_VERSION({{Global "VERSION_MAJOR"}}, {{Global "VERSION_MINOR"}}, {{Global "VERSION_PATCH"}}) -¶ -#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22) -#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff) -#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff) -¶ -#if defined(__cplusplus) && ((defined(_MSC_VER) && _MSC_VER >= 1800 || __cplusplus >= 201103L) - #define VK_NULL_HANDLE nullptr -#else - #define VK_NULL_HANDLE 0 -#endif -¶ -#define VK_DEFINE_HANDLE(obj) typedef struct obj##_T* obj; -¶ -#if defined(__cplusplus) -#if ((defined(_MSC_VER) && _MSC_VER >= 1800 || __cplusplus >= 201103L) -// The bool operator only works if there are no implicit conversions from an obj to -// a bool-compatible type, which can then be used to unintentionally violate type safety. -// C++11 and above supports the "explicit" keyword on conversion operators to stop this -// from happening. Otherwise users of C++ below C++11 won't get direct access to evaluating -// the object handle as a bool in expressions like: -// if (obj) vkDestroy(obj); -#define VK_NONDISP_HANDLE_OPERATOR_BOOL() \ - explicit operator bool() const { return handle != 0; } -#define VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \ - explicit obj(uint64_t x) : handle(x) { } \ - obj(decltype(nullptr)) : handle(0) { } -#else -#define VK_NONDISP_HANDLE_OPERATOR_BOOL() -#define VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \ - obj(uint64_t x) : handle(x) { } -#endif -#define VK_DEFINE_NONDISP_HANDLE(obj) \ - struct obj { \ - obj() : handle(0) { } \ - VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \ - obj& operator=(uint64_t x) { \ - handle = x; \ - return *this; \ - } \ - bool operator==(const obj& other) const { return handle == other.handle; } \ - bool operator!=(const obj& other) const { return handle != other.handle; } \ - bool operator!() const { return !handle; } \ - VK_NONDISP_HANDLE_OPERATOR_BOOL() \ - uint64_t handle; \ - }; -#else -#define VK_DEFINE_NONDISP_HANDLE(obj) \ - typedef struct obj##_T { uint64_t handle; } obj; -#endif -¶ -#define VK_LOD_CLAMP_NONE 1000.0f -#define VK_REMAINING_MIP_LEVELS (~0U) -#define VK_REMAINING_ARRAY_LAYERS (~0U) -#define VK_WHOLE_SIZE (~0ULL) -#define VK_ATTACHMENT_UNUSED (~0U) -define VK_QUEUE_FAMILY_IGNORED (~0U) -define VK_SUBPASS_EXTERNAL (~0U) -{{range $d := $.Definitions}} - {{if HasPrefix $d.Name "VK_"}}#define {{$d.Name}} {{$d.Expression}}{{end}} -{{end}} -¶ -{{range $i, $p := $.Pseudonyms}} - {{if GetAnnotation $p "dispatchHandle"}}VK_DEFINE_HANDLE({{$p.Name}}) - {{else if GetAnnotation $p "nonDispatchHandle"}}VK_DEFINE_NONDISP_HANDLE({{$p.Name}}) - {{end}} -{{end}} -¶ -// ------------------------------------------------------------------------------------------------ -// Enumerations -¶ - {{range $e := $.Enums}} - {{if not $e.IsBitfield}} - {{Macro "Enum" $e}} - {{end}} - {{end}} -¶ -// ------------------------------------------------------------------------------------------------ -// Flags -¶ - {{range $e := $.Enums}} - {{if $e.IsBitfield}} - {{Macro "Bitfield" $e}} - {{end}} - {{end}} -¶ -// ------------------------------------------------------------------------------------------------ -// Vulkan structures -¶ - {{/* Function pointers */}} - {{range $f := AllCommands $}} - {{if GetAnnotation $f "pfn"}} - {{Macro "FunctionTypedef" $f}} - {{end}} - {{end}} -¶ - {{range $c := $.Classes}} - {{if not (GetAnnotation $c "internal")}} - {{Macro "Struct" $c}} - {{end}} - {{end}} -¶ -// ------------------------------------------------------------------------------------------------ -// API functions -¶ - {{range $f := AllCommands $}} - {{if not (GetAnnotation $f "pfn")}} - {{Macro "FunctionTypedef" $f}} - {{end}} - {{end}} -¶ -#ifdef VK_NO_PROTOTYPES -¶ - {{range $f := AllCommands $}} - {{if not (GetAnnotation $f "pfn")}} - {{Macro "FunctionDecl" $f}} - {{end}} - {{end}} -¶ -#endif -¶ -#ifdef __cplusplus -} -#endif -¶ -#endif -{{end}} - -{{/* -------------------------------------------------------------------------------- - Emits the C declaration for the specified bitfield. -------------------------------------------------------------------------------- -*/}} -{{define "Bitfield"}} - {{AssertType $ "Enum"}} - - {{Macro "Docs" $.Docs}} - typedef VkFlags {{Macro "EnumName" $}}; - {{if $.Entries}} - typedef enum { - {{range $b := $.Entries}} - {{Macro "BitfieldEntryName" $b}} = {{printf "0x%.8X" $b.Value}}, {{Macro "Docs" $b.Docs}} - {{end}} - } {{Macro "EnumName" $ | TrimRight "s"}}Bits; - {{end}} - ¶ -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the C declaration for the specified enum. -------------------------------------------------------------------------------- -*/}} -{{define "Enum"}} - {{AssertType $ "Enum"}} - - {{Macro "Docs" $.Docs}} - typedef enum { - {{range $i, $e := $.Entries}} - {{Macro "EnumEntry" $e}} = {{printf "0x%.8X" $e.Value}}, {{Macro "Docs" $e.Docs}} - {{end}} - ¶ - {{$name := Macro "EnumName" $ | TrimRight "ABCDEFGHIJKLMNOQRSTUVWXYZ" | SplitPascalCase | Upper | JoinWith "_"}} - {{if GetAnnotation $ "enumMaxOnly"}} - VK_MAX_ENUM({{$name | SplitOn "VK_"}}) - {{else}} - {{$first := Macro "EnumFirstEntry" $ | SplitOn $name | TrimLeft "_"}} - {{$last := Macro "EnumLastEntry" $ | SplitOn $name | TrimLeft "_"}} - VK_ENUM_RANGE({{$name | SplitOn "VK_"}}, {{$first}}, {{$last}}) - {{end}} - } {{Macro "EnumName" $}}; - ¶ -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the C declaration for the specified class. -------------------------------------------------------------------------------- -*/}} -{{define "Struct"}} - {{AssertType $ "Class"}} - - {{Macro "Docs" $.Docs}} - typedef {{Macro "StructType" $}} { - {{ForEach $.Fields "Field" | JoinWith "\n"}} - } {{Macro "StructName" $}}; - ¶ -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the C declaration for the specified class field. -------------------------------------------------------------------------------- -*/}} -{{define "Field"}} - {{AssertType $ "Field"}} - - {{Node "Type" $}} {{$.Name}}§ - {{Macro "ArrayPostfix" (TypeOf $)}}; {{Macro "Docs" $.Docs}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits either 'struct' or 'union' for the specified class. -------------------------------------------------------------------------------- -*/}} -{{define "StructType"}} - {{AssertType $ "Class"}} - - {{if GetAnnotation $ "union"}}union{{else}}struct{{end}} -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the C function pointer typedef declaration for the specified command. -------------------------------------------------------------------------------- -*/}} -{{define "FunctionTypedef"}} - {{AssertType $ "Function"}} - - typedef {{Node "Type" $.Return}} (VKAPI* {{Macro "FunctionPtrName" $}})({{Macro "Parameters" $}}); -{{end}} - - -{{/* -------------------------------------------------------------------------------- - Emits the C function declaration for the specified command. -------------------------------------------------------------------------------- -*/}} -{{define "FunctionDecl"}} - {{AssertType $ "Function"}} - - {{if not (GetAnnotation $ "fptr")}} - {{Macro "Docs" $.Docs}} - {{Node "Type" $.Return}} VKAPI {{Macro "FunctionName" $}}({{Macro "Parameters" $}}); - {{end}} -{{end}} diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp index df86af0c3b..ad46c3bf93 100644 --- a/vulkan/libvulkan/api_gen.cpp +++ b/vulkan/libvulkan/api_gen.cpp @@ -16,12 +16,11 @@ // WARNING: This file is generated. See ../README.md for instructions. +#include <log/log.h> #include <string.h> #include <algorithm> -#include <log/log.h> - // to catch mismatches between vulkan.h and this file #undef VK_NO_PROTOTYPES #include "api.h" diff --git a/vulkan/libvulkan/api_gen.h b/vulkan/libvulkan/api_gen.h index 4bedbeb16e..f5822249b3 100644 --- a/vulkan/libvulkan/api_gen.h +++ b/vulkan/libvulkan/api_gen.h @@ -20,7 +20,9 @@ #define LIBVULKAN_API_GEN_H #include <vulkan/vulkan.h> + #include <bitset> + #include "driver_gen.h" namespace vulkan { diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl index bdd3573b11..940b747f1b 100644 --- a/vulkan/libvulkan/code-generator.tmpl +++ b/vulkan/libvulkan/code-generator.tmpl @@ -37,8 +37,10 @@ #ifndef LIBVULKAN_API_GEN_H #define LIBVULKAN_API_GEN_H ¶ -#include <bitset> #include <vulkan/vulkan.h> +¶ +#include <bitset> +¶ #include "driver_gen.h" ¶ namespace vulkan {« @@ -90,12 +92,11 @@ bool InitDispatchTable( ¶ // WARNING: This file is generated. See ../README.md for instructions. ¶ +#include <log/log.h> #include <string.h> ¶ #include <algorithm> ¶ -#include <log/log.h> -¶ // to catch mismatches between vulkan.h and this file #undef VK_NO_PROTOTYPES #include "api.h" @@ -217,9 +218,10 @@ namespace {« #ifndef LIBVULKAN_DRIVER_GEN_H #define LIBVULKAN_DRIVER_GEN_H ¶ -#include <bitset> -#include <vulkan/vulkan.h> #include <vulkan/vk_android_native_buffer.h> +#include <vulkan/vulkan.h> +¶ +#include <bitset> ¶ namespace vulkan {« namespace driver {« @@ -271,12 +273,11 @@ bool InitDriverTable(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc, ¶ // WARNING: This file is generated. See ../README.md for instructions. ¶ +#include <log/log.h> #include <string.h> ¶ #include <algorithm> ¶ -#include <log/log.h> -¶ #include "driver.h" ¶ namespace vulkan {« diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp index 23506bad54..680f94f42a 100644 --- a/vulkan/libvulkan/driver.cpp +++ b/vulkan/libvulkan/driver.cpp @@ -16,30 +16,29 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include "driver.h" + +#include <dlfcn.h> #include <malloc.h> #include <stdlib.h> #include <string.h> -#include <sys/prctl.h> - -#include <dlfcn.h> -#include <algorithm> -#include <array> -#include <new> - -#include <log/log.h> #include <android/dlext.h> #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> +#include <android-base/properties.h> #include <configstore/Utils.h> #include <cutils/properties.h> #include <graphicsenv/GraphicsEnv.h> +#include <log/log.h> +#include <sys/prctl.h> #include <utils/Timers.h> #include <utils/Trace.h> -#include <utils/Vector.h> -#include "android-base/properties.h" +#include <algorithm> +#include <array> +#include <new> +#include <vector> -#include "driver.h" #include "stubhal.h" using namespace android::hardware::configstore; @@ -212,7 +211,7 @@ int LoadBuiltinDriver(const hwvulkan_module_t** module) { if (!ns) return -ENOENT; android::GraphicsEnv::getInstance().setDriverToLoad( - android::GraphicsEnv::Driver::VULKAN); + android::GpuStatsInfo::Driver::VULKAN); return LoadDriver(ns, module); } @@ -223,7 +222,7 @@ int LoadUpdatedDriver(const hwvulkan_module_t** module) { if (!ns) return -ENOENT; android::GraphicsEnv::getInstance().setDriverToLoad( - android::GraphicsEnv::Driver::VULKAN_UPDATED); + android::GpuStatsInfo::Driver::VULKAN_UPDATED); return LoadDriver(ns, module); } @@ -258,7 +257,7 @@ bool Hal::Open() { } if (result != 0) { android::GraphicsEnv::getInstance().setDriverLoaded( - android::GraphicsEnv::Api::API_VK, false, systemTime() - openTime); + android::GpuStatsInfo::Api::API_VK, false, systemTime() - openTime); ALOGV("unable to load Vulkan HAL, using stub HAL (result=%d)", result); return true; } @@ -272,7 +271,7 @@ bool Hal::Open() { ATRACE_END(); if (result != 0) { android::GraphicsEnv::getInstance().setDriverLoaded( - android::GraphicsEnv::Api::API_VK, false, systemTime() - openTime); + android::GpuStatsInfo::Api::API_VK, false, systemTime() - openTime); // Any device with a Vulkan HAL should be able to open the device. ALOGE("failed to open Vulkan HAL device: %s (%d)", strerror(-result), result); @@ -284,7 +283,7 @@ bool Hal::Open() { hal_.InitDebugReportIndex(); android::GraphicsEnv::getInstance().setDriverLoaded( - android::GraphicsEnv::Api::API_VK, true, systemTime() - openTime); + android::GpuStatsInfo::Api::API_VK, true, systemTime() - openTime); return true; } @@ -809,8 +808,7 @@ VkResult EnumerateInstanceExtensionProperties( const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties) { - - android::Vector<VkExtensionProperties> loader_extensions; + std::vector<VkExtensionProperties> loader_extensions; loader_extensions.push_back({ VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_SURFACE_SPEC_VERSION}); @@ -833,7 +831,7 @@ VkResult EnumerateInstanceExtensionProperties( uint32_t count = std::min( *pPropertyCount, static_cast<uint32_t>(loader_extensions.size())); - std::copy_n(loader_extensions.begin(), count, pProperties); + std::copy_n(loader_extensions.data(), count, pProperties); if (count < loader_extensions.size()) { *pPropertyCount = count; @@ -879,8 +877,7 @@ VkResult EnumerateInstanceExtensionProperties( bool QueryPresentationProperties( VkPhysicalDevice physicalDevice, - VkPhysicalDevicePresentationPropertiesANDROID *presentation_properties) -{ + VkPhysicalDevicePresentationPropertiesANDROID *presentation_properties) { const InstanceData& data = GetData(physicalDevice); // GPDP2 must be present and enabled on the instance. @@ -920,7 +917,7 @@ VkResult EnumerateDeviceExtensionProperties( VkExtensionProperties* pProperties) { const InstanceData& data = GetData(physicalDevice); // extensions that are unconditionally exposed by the loader - android::Vector<VkExtensionProperties> loader_extensions; + std::vector<VkExtensionProperties> loader_extensions; loader_extensions.push_back({ VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME, VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION}); @@ -956,7 +953,7 @@ VkResult EnumerateDeviceExtensionProperties( uint32_t count = std::min( *pPropertyCount, static_cast<uint32_t>(loader_extensions.size())); - std::copy_n(loader_extensions.begin(), count, pProperties); + std::copy_n(loader_extensions.data(), count, pProperties); if (count < loader_extensions.size()) { *pPropertyCount = count; @@ -1245,11 +1242,10 @@ VkResult EnumeratePhysicalDeviceGroups( if (!device_count) return VK_INCOMPLETE; - android::Vector<VkPhysicalDevice> devices; - devices.resize(device_count); + std::vector<VkPhysicalDevice> devices(device_count); *pPhysicalDeviceGroupCount = device_count; - result = EnumeratePhysicalDevices(instance, &device_count, - devices.editArray()); + result = + EnumeratePhysicalDevices(instance, &device_count, devices.data()); if (result < 0) return result; diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp index 574c3273d0..7020be1eda 100644 --- a/vulkan/libvulkan/driver_gen.cpp +++ b/vulkan/libvulkan/driver_gen.cpp @@ -16,12 +16,11 @@ // WARNING: This file is generated. See ../README.md for instructions. +#include <log/log.h> #include <string.h> #include <algorithm> -#include <log/log.h> - #include "driver.h" namespace vulkan { diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h index 3faf6c0e32..c299549dae 100644 --- a/vulkan/libvulkan/driver_gen.h +++ b/vulkan/libvulkan/driver_gen.h @@ -21,6 +21,7 @@ #include <vulkan/vk_android_native_buffer.h> #include <vulkan/vulkan.h> + #include <bitset> namespace vulkan { diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index a8949d36f4..761d128d79 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -24,7 +24,6 @@ #include <ui/BufferQueueDefs.h> #include <utils/StrongPointer.h> #include <utils/Trace.h> -#include <utils/Vector.h> #include <algorithm> #include <unordered_set> @@ -34,10 +33,6 @@ using android::hardware::graphics::common::V1_0::BufferUsage; -// TODO(jessehall): Currently we don't have a good error code for when a native -// window operation fails. Just returning INITIALIZATION_FAILED for now. Later -// versions (post SDK 0.9) of the API/extension have a better error code. -// When updating to that version, audit all error returns. namespace vulkan { namespace driver { @@ -48,29 +43,12 @@ const VkSurfaceTransformFlagsKHR kSupportedTransforms = VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR | VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR | VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR | - // TODO(jessehall): See TODO in TranslateNativeToVulkanTransform. - // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR | - // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR | - // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR | - // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR | + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR | + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR | + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR | + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR | VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR; -int TranslateVulkanToNativeTransform(VkSurfaceTransformFlagBitsKHR transform) { - switch (transform) { - // TODO: See TODO in TranslateNativeToVulkanTransform - case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR: - return NATIVE_WINDOW_TRANSFORM_ROT_90; - case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR: - return NATIVE_WINDOW_TRANSFORM_ROT_180; - case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR: - return NATIVE_WINDOW_TRANSFORM_ROT_270; - case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR: - case VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR: - default: - return 0; - } -} - VkSurfaceTransformFlagBitsKHR TranslateNativeToVulkanTransform(int native) { // Native and Vulkan transforms are isomorphic, but are represented // differently. Vulkan transforms are built up of an optional horizontal @@ -78,27 +56,22 @@ VkSurfaceTransformFlagBitsKHR TranslateNativeToVulkanTransform(int native) { // transforms are built up from a horizontal flip, vertical flip, and // 90-degree rotation, all optional but always in that order. - // TODO(jessehall): For now, only support pure rotations, not - // flip or flip-and-rotate, until I have more time to test them and build - // sample code. As far as I know we never actually use anything besides - // pure rotations anyway. - switch (native) { - case 0: // 0x0 + case 0: return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; - // case NATIVE_WINDOW_TRANSFORM_FLIP_H: // 0x1 - // return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR; - // case NATIVE_WINDOW_TRANSFORM_FLIP_V: // 0x2 - // return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR; - case NATIVE_WINDOW_TRANSFORM_ROT_180: // FLIP_H | FLIP_V + case NATIVE_WINDOW_TRANSFORM_FLIP_H: + return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR; + case NATIVE_WINDOW_TRANSFORM_FLIP_V: + return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR; + case NATIVE_WINDOW_TRANSFORM_ROT_180: return VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR; - case NATIVE_WINDOW_TRANSFORM_ROT_90: // 0x4 + case NATIVE_WINDOW_TRANSFORM_ROT_90: return VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR; - // case NATIVE_WINDOW_TRANSFORM_FLIP_H | NATIVE_WINDOW_TRANSFORM_ROT_90: - // return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR; - // case NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_ROT_90: - // return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR; - case NATIVE_WINDOW_TRANSFORM_ROT_270: // FLIP_H | FLIP_V | ROT_90 + case NATIVE_WINDOW_TRANSFORM_FLIP_H | NATIVE_WINDOW_TRANSFORM_ROT_90: + return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR; + case NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_ROT_90: + return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR; + case NATIVE_WINDOW_TRANSFORM_ROT_270: return VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR; case NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY: default: @@ -106,6 +79,31 @@ VkSurfaceTransformFlagBitsKHR TranslateNativeToVulkanTransform(int native) { } } +int TranslateVulkanToNativeTransform(VkSurfaceTransformFlagBitsKHR transform) { + switch (transform) { + case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR: + return NATIVE_WINDOW_TRANSFORM_ROT_90; + case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR: + return NATIVE_WINDOW_TRANSFORM_ROT_180; + case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR: + return NATIVE_WINDOW_TRANSFORM_ROT_270; + case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR: + return NATIVE_WINDOW_TRANSFORM_FLIP_H; + case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR: + return NATIVE_WINDOW_TRANSFORM_FLIP_H | + NATIVE_WINDOW_TRANSFORM_ROT_90; + case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR: + return NATIVE_WINDOW_TRANSFORM_FLIP_V; + case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR: + return NATIVE_WINDOW_TRANSFORM_FLIP_V | + NATIVE_WINDOW_TRANSFORM_ROT_90; + case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR: + case VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR: + default: + return 0; + } +} + int InvertTransformToNative(VkSurfaceTransformFlagBitsKHR transform) { switch (transform) { case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR: @@ -114,17 +112,16 @@ int InvertTransformToNative(VkSurfaceTransformFlagBitsKHR transform) { return NATIVE_WINDOW_TRANSFORM_ROT_180; case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR: return NATIVE_WINDOW_TRANSFORM_ROT_90; - // TODO(jessehall): See TODO in TranslateNativeToVulkanTransform. - // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR: - // return NATIVE_WINDOW_TRANSFORM_FLIP_H; - // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR: - // return NATIVE_WINDOW_TRANSFORM_FLIP_H | - // NATIVE_WINDOW_TRANSFORM_ROT_90; - // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR: - // return NATIVE_WINDOW_TRANSFORM_FLIP_V; - // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR: - // return NATIVE_WINDOW_TRANSFORM_FLIP_V | - // NATIVE_WINDOW_TRANSFORM_ROT_90; + case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR: + return NATIVE_WINDOW_TRANSFORM_FLIP_H; + case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR: + return NATIVE_WINDOW_TRANSFORM_FLIP_H | + NATIVE_WINDOW_TRANSFORM_ROT_90; + case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR: + return NATIVE_WINDOW_TRANSFORM_FLIP_V; + case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR: + return NATIVE_WINDOW_TRANSFORM_FLIP_V | + NATIVE_WINDOW_TRANSFORM_ROT_90; case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR: case VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR: default: @@ -134,7 +131,6 @@ int InvertTransformToNative(VkSurfaceTransformFlagBitsKHR transform) { class TimingInfo { public: - TimingInfo() = default; TimingInfo(const VkPresentTimeGOOGLE* qp, uint64_t nativeFrameId) : vals_{qp->presentID, qp->desiredPresentTime, 0, 0, 0}, native_frame_id_(nativeFrameId) {} @@ -201,8 +197,6 @@ class TimingInfo { { NATIVE_WINDOW_TIMESTAMP_PENDING }; }; -// ---------------------------------------------------------------------------- - struct Surface { android::sp<ANativeWindow> window; VkSwapchainKHR swapchain_handle; @@ -270,7 +264,7 @@ struct Swapchain { bool dequeued; } images[android::BufferQueueDefs::NUM_BUFFER_SLOTS]; - android::Vector<TimingInfo> timing; + std::vector<TimingInfo> timing; }; VkSwapchainKHR HandleFromSwapchain(Swapchain* swapchain) { @@ -285,6 +279,8 @@ void ReleaseSwapchainImage(VkDevice device, ANativeWindow* window, int release_fence, Swapchain::Image& image) { + ATRACE_CALL(); + ALOG_ASSERT(release_fence == -1 || image.dequeued, "ReleaseSwapchainImage: can't provide a release fence for " "non-dequeued images"); @@ -323,7 +319,9 @@ void ReleaseSwapchainImage(VkDevice device, } if (image.image) { + ATRACE_BEGIN("DestroyImage"); GetData(device).driver.DestroyImage(device, image.image, nullptr); + ATRACE_END(); image.image = VK_NULL_HANDLE; } @@ -349,7 +347,7 @@ uint32_t get_num_ready_timings(Swapchain& swapchain) { uint32_t num_ready = 0; const size_t num_timings = swapchain.timing.size() - MIN_NUM_FRAMES_AGO + 1; for (uint32_t i = 0; i < num_timings; i++) { - TimingInfo& ti = swapchain.timing.editItemAt(i); + TimingInfo& ti = swapchain.timing[i]; if (ti.ready()) { // This TimingInfo is ready to be reported to the user. Add it // to the num_ready. @@ -419,7 +417,7 @@ void copy_ready_timings(Swapchain& swapchain, } uint32_t num_copied = 0; - size_t num_to_remove = 0; + int32_t num_to_remove = 0; for (uint32_t i = 0; i <= last_ready && num_copied < *count; i++) { const TimingInfo& ti = swapchain.timing[i]; if (ti.ready()) { @@ -431,7 +429,8 @@ void copy_ready_timings(Swapchain& swapchain, // Discard old frames that aren't ready if newer frames are ready. // We don't expect to get the timing info for those old frames. - swapchain.timing.removeItemsAt(0, num_to_remove); + swapchain.timing.erase(swapchain.timing.begin(), + swapchain.timing.begin() + num_to_remove); *count = num_copied; } @@ -539,15 +538,12 @@ VkResult CreateAndroidSurfaceKHR( strerror(-err), err); surface->~Surface(); allocator->pfnFree(allocator->pUserData, surface); - return VK_ERROR_INITIALIZATION_FAILED; + return VK_ERROR_SURFACE_LOST_KHR; } - // TODO(jessehall): Create and use NATIVE_WINDOW_API_VULKAN. err = native_window_api_connect(surface->window.get(), NATIVE_WINDOW_API_EGL); if (err != 0) { - // TODO(jessehall): Improve error reporting. Can we enumerate possible - // errors and translate them to valid Vulkan result codes? ALOGE("native_window_api_connect() failed: %s (%d)", strerror(-err), err); surface->~Surface(); @@ -656,7 +652,6 @@ VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR( return VK_ERROR_SURFACE_LOST_KHR; } - // TODO(jessehall): Figure out what the min/max values should be. int max_buffer_count; err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &max_buffer_count); if (err != 0) { @@ -670,8 +665,7 @@ VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR( capabilities->currentExtent = VkExtent2D{static_cast<uint32_t>(width), static_cast<uint32_t>(height)}; - // TODO(jessehall): Figure out what the max extent should be. Maximum - // texture dimension maybe? + // TODO(http://b/134182502): Figure out what the max extent should be. capabilities->minImageExtent = VkExtent2D{1, 1}; capabilities->maxImageExtent = VkExtent2D{4096, 4096}; @@ -685,11 +679,6 @@ VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR( // associated with the bufferqueue. It can't be changed from here. capabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; - // TODO(jessehall): I think these are right, but haven't thought hard about - // it. Do we need to query the driver for support of any of these? - // Currently not included: - // - VK_IMAGE_USAGE_DEPTH_STENCIL_BIT: definitely not - // - VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT: definitely not capabilities->supportedUsageFlags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | @@ -729,8 +718,7 @@ VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, int err = native_window_get_wide_color_support(surface.window.get(), &wide_color_support); if (err) { - // Not allowed to return a more sensible error code, so do this - return VK_ERROR_OUT_OF_HOST_MEMORY; + return VK_ERROR_SURFACE_LOST_KHR; } ALOGV("wide_color_support is: %d", wide_color_support); wide_color_support = @@ -828,11 +816,10 @@ VkResult GetPhysicalDeviceSurfaceFormats2KHR( } else { // temp vector for forwarding; we'll marshal it into the pSurfaceFormats // after the call. - android::Vector<VkSurfaceFormatKHR> surface_formats; - surface_formats.resize(*pSurfaceFormatCount); + std::vector<VkSurfaceFormatKHR> surface_formats(*pSurfaceFormatCount); VkResult result = GetPhysicalDeviceSurfaceFormatsKHR( physicalDevice, pSurfaceInfo->surface, pSurfaceFormatCount, - &surface_formats.editItemAt(0)); + surface_formats.data()); if (result == VK_SUCCESS || result == VK_INCOMPLETE) { // marshal results individually due to stride difference. @@ -874,7 +861,7 @@ VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev, } uint32_t max_buffer_count = static_cast<uint32_t>(query_value); - android::Vector<VkPresentModeKHR> present_modes; + std::vector<VkPresentModeKHR> present_modes; if (min_undequeued_buffers + 1 < max_buffer_count) present_modes.push_back(VK_PRESENT_MODE_MAILBOX_KHR); present_modes.push_back(VK_PRESENT_MODE_FIFO_KHR); @@ -894,7 +881,7 @@ VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev, if (*count < num_modes) result = VK_INCOMPLETE; *count = std::min(*count, num_modes); - std::copy(present_modes.begin(), present_modes.begin() + int(*count), modes); + std::copy_n(present_modes.data(), *count, modes); } else { *count = num_modes; } @@ -978,6 +965,40 @@ VkResult GetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice, return VK_SUCCESS; } +static void DestroySwapchainInternal(VkDevice device, + VkSwapchainKHR swapchain_handle, + const VkAllocationCallbacks* allocator) { + ATRACE_CALL(); + + const auto& dispatch = GetData(device).driver; + Swapchain* swapchain = SwapchainFromHandle(swapchain_handle); + if (!swapchain) { + return; + } + + bool active = swapchain->surface.swapchain_handle == swapchain_handle; + ANativeWindow* window = active ? swapchain->surface.window.get() : nullptr; + + if (window && swapchain->frame_timestamps_enabled) { + native_window_enable_frame_timestamps(window, false); + } + + for (uint32_t i = 0; i < swapchain->num_images; i++) { + ReleaseSwapchainImage(device, window, -1, swapchain->images[i]); + } + + if (active) { + swapchain->surface.swapchain_handle = VK_NULL_HANDLE; + } + + if (!allocator) { + allocator = &GetData(device).allocator; + } + + swapchain->~Swapchain(); + allocator->pfnFree(allocator->pUserData, swapchain); +} + VKAPI_ATTR VkResult CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* create_info, @@ -1052,6 +1073,8 @@ VkResult CreateSwapchainKHR(VkDevice device, // non-FREE state at any given time. Disconnecting and re-connecting // orphans the previous buffers, getting us back to the state where we can // dequeue all buffers. + // + // TODO(http://b/134186185) recycle swapchain images more efficiently err = native_window_api_disconnect(surface.window.get(), NATIVE_WINDOW_API_EGL); ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)", @@ -1072,8 +1095,6 @@ VkResult CreateSwapchainKHR(VkDevice device, create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR ? 0 : 1; err = surface.window->setSwapInterval(surface.window.get(), swap_interval); if (err != 0) { - // TODO(jessehall): Improve error reporting. Can we enumerate possible - // errors and translate them to valid Vulkan result codes? ALOGE("native_window->setSwapInterval(1) failed: %s (%d)", strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; @@ -1100,8 +1121,6 @@ VkResult CreateSwapchainKHR(VkDevice device, err = native_window_set_buffers_format(surface.window.get(), native_pixel_format); if (err != 0) { - // TODO(jessehall): Improve error reporting. Can we enumerate possible - // errors and translate them to valid Vulkan result codes? ALOGE("native_window_set_buffers_format(%d) failed: %s (%d)", native_pixel_format, strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; @@ -1109,8 +1128,6 @@ VkResult CreateSwapchainKHR(VkDevice device, err = native_window_set_buffers_data_space(surface.window.get(), native_dataspace); if (err != 0) { - // TODO(jessehall): Improve error reporting. Can we enumerate possible - // errors and translate them to valid Vulkan result codes? ALOGE("native_window_set_buffers_data_space(%d) failed: %s (%d)", native_dataspace, strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; @@ -1120,8 +1137,6 @@ VkResult CreateSwapchainKHR(VkDevice device, surface.window.get(), static_cast<int>(create_info->imageExtent.width), static_cast<int>(create_info->imageExtent.height)); if (err != 0) { - // TODO(jessehall): Improve error reporting. Can we enumerate possible - // errors and translate them to valid Vulkan result codes? ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)", create_info->imageExtent.width, create_info->imageExtent.height, strerror(-err), err); @@ -1140,8 +1155,6 @@ VkResult CreateSwapchainKHR(VkDevice device, surface.window.get(), InvertTransformToNative(create_info->preTransform)); if (err != 0) { - // TODO(jessehall): Improve error reporting. Can we enumerate possible - // errors and translate them to valid Vulkan result codes? ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)", InvertTransformToNative(create_info->preTransform), strerror(-err), err); @@ -1151,8 +1164,6 @@ VkResult CreateSwapchainKHR(VkDevice device, err = native_window_set_scaling_mode( surface.window.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); if (err != 0) { - // TODO(jessehall): Improve error reporting. Can we enumerate possible - // errors and translate them to valid Vulkan result codes? ALOGE("native_window_set_scaling_mode(SCALE_TO_WINDOW) failed: %s (%d)", strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; @@ -1182,8 +1193,6 @@ VkResult CreateSwapchainKHR(VkDevice device, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value); if (err != 0 || query_value < 0) { - // TODO(jessehall): Improve error reporting. Can we enumerate possible - // errors and translate them to valid Vulkan result codes? ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err, query_value); return VK_ERROR_SURFACE_LOST_KHR; @@ -1201,8 +1210,6 @@ VkResult CreateSwapchainKHR(VkDevice device, // can't actually use!). err = native_window_set_buffer_count(surface.window.get(), std::max(2u, num_images)); if (err != 0) { - // TODO(jessehall): Improve error reporting. Can we enumerate possible - // errors and translate them to valid Vulkan result codes? ALOGE("native_window_set_buffer_count(%d) failed: %s (%d)", num_images, strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; @@ -1211,7 +1218,7 @@ VkResult CreateSwapchainKHR(VkDevice device, int32_t legacy_usage = 0; if (dispatch.GetSwapchainGrallocUsage2ANDROID) { uint64_t consumer_usage, producer_usage; - ATRACE_BEGIN("dispatch.GetSwapchainGrallocUsage2ANDROID"); + ATRACE_BEGIN("GetSwapchainGrallocUsage2ANDROID"); result = dispatch.GetSwapchainGrallocUsage2ANDROID( device, create_info->imageFormat, create_info->imageUsage, swapchain_image_usage, &consumer_usage, &producer_usage); @@ -1223,7 +1230,7 @@ VkResult CreateSwapchainKHR(VkDevice device, legacy_usage = android_convertGralloc1To0Usage(producer_usage, consumer_usage); } else if (dispatch.GetSwapchainGrallocUsageANDROID) { - ATRACE_BEGIN("dispatch.GetSwapchainGrallocUsageANDROID"); + ATRACE_BEGIN("GetSwapchainGrallocUsageANDROID"); result = dispatch.GetSwapchainGrallocUsageANDROID( device, create_info->imageFormat, create_info->imageUsage, &legacy_usage); @@ -1242,8 +1249,6 @@ VkResult CreateSwapchainKHR(VkDevice device, } err = native_window_set_usage(surface.window.get(), native_usage); if (err != 0) { - // TODO(jessehall): Improve error reporting. Can we enumerate possible - // errors and translate them to valid Vulkan result codes? ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; } @@ -1301,8 +1306,6 @@ VkResult CreateSwapchainKHR(VkDevice device, err = surface.window->dequeueBuffer(surface.window.get(), &buffer, &img.dequeue_fence); if (err != 0) { - // TODO(jessehall): Improve error reporting. Can we enumerate - // possible errors and translate them to valid Vulkan result codes? ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err); result = VK_ERROR_SURFACE_LOST_KHR; break; @@ -1322,7 +1325,7 @@ VkResult CreateSwapchainKHR(VkDevice device, &image_native_buffer.usage2.producer, &image_native_buffer.usage2.consumer); - ATRACE_BEGIN("dispatch.CreateImage"); + ATRACE_BEGIN("CreateImage"); result = dispatch.CreateImage(device, &image_create, nullptr, &img.image); ATRACE_END(); @@ -1335,9 +1338,6 @@ VkResult CreateSwapchainKHR(VkDevice device, // -- Cancel all buffers, returning them to the queue -- // If an error occurred before, also destroy the VkImage and release the // buffer reference. Otherwise, we retain a strong reference to the buffer. - // - // TODO(jessehall): The error path here is the same as DestroySwapchain, - // but not the non-error path. Should refactor/unify. for (uint32_t i = 0; i < num_images; i++) { Swapchain::Image& img = swapchain->images[i]; if (img.dequeued) { @@ -1348,18 +1348,11 @@ VkResult CreateSwapchainKHR(VkDevice device, img.dequeued = false; } } - if (result != VK_SUCCESS) { - if (img.image) { - ATRACE_BEGIN("dispatch.DestroyImage"); - dispatch.DestroyImage(device, img.image, nullptr); - ATRACE_END(); - } - } } if (result != VK_SUCCESS) { - swapchain->~Swapchain(); - allocator->pfnFree(allocator->pUserData, swapchain); + DestroySwapchainInternal(device, HandleFromSwapchain(swapchain), + allocator); return result; } @@ -1374,24 +1367,7 @@ void DestroySwapchainKHR(VkDevice device, const VkAllocationCallbacks* allocator) { ATRACE_CALL(); - const auto& dispatch = GetData(device).driver; - Swapchain* swapchain = SwapchainFromHandle(swapchain_handle); - if (!swapchain) - return; - bool active = swapchain->surface.swapchain_handle == swapchain_handle; - ANativeWindow* window = active ? swapchain->surface.window.get() : nullptr; - - if (swapchain->frame_timestamps_enabled) { - native_window_enable_frame_timestamps(window, false); - } - for (uint32_t i = 0; i < swapchain->num_images; i++) - ReleaseSwapchainImage(device, window, -1, swapchain->images[i]); - if (active) - swapchain->surface.swapchain_handle = VK_NULL_HANDLE; - if (!allocator) - allocator = &GetData(device).allocator; - swapchain->~Swapchain(); - allocator->pfnFree(allocator->pUserData, swapchain); + DestroySwapchainInternal(device, swapchain_handle, allocator); } VKAPI_ATTR @@ -1457,8 +1433,6 @@ VkResult AcquireNextImageKHR(VkDevice device, int fence_fd; err = window->dequeueBuffer(window, &buffer, &fence_fd); if (err != 0) { - // TODO(jessehall): Improve error reporting. Can we enumerate possible - // errors and translate them to valid Vulkan result codes? ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err); return VK_ERROR_SURFACE_LOST_KHR; } @@ -1513,8 +1487,6 @@ VkResult AcquireNextImage2KHR(VkDevice device, uint32_t* pImageIndex) { ATRACE_CALL(); - // TODO: this should actually be the other way around and this function - // should handle any additional structures that get passed in return AcquireNextImageKHR(device, pAcquireInfo->swapchain, pAcquireInfo->timeout, pAcquireInfo->semaphore, pAcquireInfo->fence, pImageIndex); @@ -1673,9 +1645,9 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { // Add a new timing record with the user's presentID and // the nativeFrameId. - swapchain.timing.push_back(TimingInfo(time, nativeFrameId)); + swapchain.timing.emplace_back(time, nativeFrameId); while (swapchain.timing.size() > MAX_TIMING_INFOS) { - swapchain.timing.removeAt(0); + swapchain.timing.erase(swapchain.timing.begin()); } if (time->desiredPresentTime) { // Set the desiredPresentTime: @@ -1692,17 +1664,16 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { err = window->queueBuffer(window, img.buffer.get(), fence); // queueBuffer always closes fence, even on error if (err != 0) { - // TODO(jessehall): What now? We should probably cancel the - // buffer, I guess? ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err); swapchain_result = WorstPresentResult( swapchain_result, VK_ERROR_OUT_OF_DATE_KHR); + } else { + if (img.dequeue_fence >= 0) { + close(img.dequeue_fence); + img.dequeue_fence = -1; + } + img.dequeued = false; } - if (img.dequeue_fence >= 0) { - close(img.dequeue_fence); - img.dequeue_fence = -1; - } - img.dequeued = false; // If the swapchain is in shared mode, immediately dequeue the // buffer so it can be presented again without an intervening @@ -1729,7 +1700,6 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { } } if (swapchain_result != VK_SUCCESS) { - ReleaseSwapchainImage(device, window, fence, img); OrphanSwapchain(device, &swapchain); } int window_transform_hint; diff --git a/vulkan/nulldrv/null_driver.tmpl b/vulkan/nulldrv/null_driver.tmpl index ce155172e9..0f5301595c 100644 --- a/vulkan/nulldrv/null_driver.tmpl +++ b/vulkan/nulldrv/null_driver.tmpl @@ -97,9 +97,10 @@ VKAPI_ATTR VkResult QueueSignalReleaseImageANDROID(VkQueue queue, uint32_t waitS ¶ // WARNING: This file is generated. See ../README.md for instructions. ¶ -#include "null_driver_gen.h" #include <algorithm> ¶ +#include "null_driver_gen.h" +¶ using namespace null_driver; ¶ namespace { diff --git a/vulkan/nulldrv/null_driver_gen.cpp b/vulkan/nulldrv/null_driver_gen.cpp index 92b7468321..b8d7d2b643 100644 --- a/vulkan/nulldrv/null_driver_gen.cpp +++ b/vulkan/nulldrv/null_driver_gen.cpp @@ -17,6 +17,7 @@ // WARNING: This file is generated. See ../README.md for instructions. #include <algorithm> + #include "null_driver_gen.h" using namespace null_driver; diff --git a/vulkan/scripts/api_generator.py b/vulkan/scripts/api_generator.py new file mode 100644 index 0000000000..05dc9957b0 --- /dev/null +++ b/vulkan/scripts/api_generator.py @@ -0,0 +1,344 @@ +#!/usr/bin/env python3 +# +# Copyright 2019 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 script provides the functions required for generating the +# vulkan api framework directly from the vulkan registry (vk.xml) + +import os +import generator_common as gencom + +def isInstanceDispatchTableEntry(functionName): + if functionName == 'vkEnumerateDeviceLayerProperties': # deprecated, unused internally - @dbd33bc + return False + if gencom.gencom.isFunctionExported(functionName) and gencom.isInstanceDispatched(functionName): + return True + return False + +def isDeviceDispatchTableEntry(functionName): + if gencom.gencom.isFunctionExported(functionName) and gencom.gencom.isDeviceDispatched(functionName): + return True + return False + +def api_genh(): + + header = """#ifndef LIBVULKAN_API_GEN_H +#define LIBVULKAN_API_GEN_H + +#include <vulkan/vulkan.h> + +#include <bitset> + +#include "driver_gen.h" + +namespace vulkan { +namespace api { + +""" + + tail = """ +bool InitDispatchTable( + VkInstance instance, + PFN_vkGetInstanceProcAddr get_proc, + const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions); +bool InitDispatchTable( + VkDevice dev, + PFN_vkGetDeviceProcAddr get_proc, + const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions); + +} // namespace api +} // namespace vulkan + +#endif // LIBVULKAN_API_GEN_H +""" + genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','api_gen2.h') + with open(genfile, 'w') as f: + instanceDispatchTableEntries = [] + deviceDispatchTableEntries = [] + for commands in gencom.allCommandsList: + if commands not in gencom.aliasDict: + if gencom.isInstanceDispatchTableEntry(commands): + instanceDispatchTableEntries.append('PFN_'+commands+' '+commands[2:]+';') + elif gencom.isDeviceDispatchTableEntry(commands): + deviceDispatchTableEntries.append('PFN_'+commands+' '+commands[2:]+';') + + f.write (gencom.copyright) + f.write (gencom.warning) + f.write (header) + f.write ('struct InstanceDispatchTable {\n') + gencom.clang_off(f,1) + for functions in instanceDispatchTableEntries: + f.write(gencom.clang_off_spaces + functions + '\n') + gencom.clang_on(f,1) + f.write ('};\n\n') + + f.write ('struct DeviceDispatchTable {\n') + gencom.clang_off(f,1) + for functions in deviceDispatchTableEntries: + f.write(gencom.clang_off_spaces + functions + '\n') + gencom.clang_on(f,1) + f.write ('};\n') + + f.write (tail) + f.close() + +def defineInitProc(name, f): + f.write ('#define UNLIKELY(expr) __builtin_expect((expr), 0)\n') + f.write ('\n') + f.write ("""#define INIT_PROC(required, obj, proc) \\ + do { \\ + data.""" + name + """.proc = \\ + reinterpret_cast<PFN_vk##proc>(get_proc(obj, "vk" #proc)); \\ + if (UNLIKELY(required && !data.""" + name + """.proc)) { \\ + ALOGE("missing " #obj " proc: vk" #proc); \\ + success = false; \\ + } \\ + } while (0)\n\n""") + +def defineInitProcExt(f): + f.write ('// Exported extension functions may be invoked even when their extensions\n') + f.write ('// are disabled. Dispatch to stubs when that happens.\n') + f.write ("""#define INIT_PROC_EXT(ext, required, obj, proc) \\ + do { \\ + if (extensions[driver::ProcHook::ext]) \\ + INIT_PROC(required, obj, proc); \\ + else \\ + data.dispatch.proc = disabled##proc; \\ + } while (0)\n\n""") + +def defineExtensionStub(functionName, f): + if functionName in gencom.extensionsDict and gencom.isFunctionExported(functionName): + extname = gencom.extensionsDict[functionName] + base_name = functionName[2:] + pList = gencom.paramDict[functionName] + firstParam = pList[0][0] + pList[0][1] + tailParams = [x[0][:-1] for x in pList[1:]] + tailP = ', '.join(tailParams) + f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[functionName] + ' disabled' + base_name + '(' + firstParam + ', ' + tailP + ') {\n') + f.write (gencom.clang_off_spaces) + f.write ('driver::Logger(' + pList[0][1] + ').Err(' + pList[0][1] + ', \"' + extname + ' not enabled. Exported ' + functionName + ' not executed.\");\n') + if gencom.returnTypeDict[functionName] != 'void': + f.write(gencom.clang_off_spaces + 'return VK_SUCCESS;\n') + f.write ('}\n\n') + +def isIntercepted(functionName): + if gencom.isFunctionSupported(functionName): + if gencom.isGloballyDispatched(functionName): + return True + elif functionName == 'vkCreateDevice': + return True + elif functionName == 'vkEnumerateDeviceLayerProperties': + return True + elif functionName == 'vkEnumerateDeviceExtensionProperties': + return True + elif functionName == 'vkDestroyInstance': + return True + elif functionName == 'vkDestroyDevice': + return True + return False + +def interceptInstanceProcAddr(functionName, f): + indent = 1 + f.write (gencom.clang_off_spaces*indent + '// global functions\n' + gencom.clang_off_spaces*indent+ 'if (instance == VK_NULL_HANDLE) {\n') + indent = indent + 1 + for cmds in gencom.allCommandsList: + if gencom.isGloballyDispatched(cmds): + f.write(gencom.clang_off_spaces*indent + 'if (strcmp(pName, \"' + cmds + '\") == 0) return reinterpret_cast<PFN_vkVoidFunction>(' + cmds[2:] + ');\n') + + f.write ('\n') + f.write (""" ALOGE("invalid vkGetInstanceProcAddr(VK_NULL_HANDLE, \\\"%s\\\") call", pName); + return nullptr; + } + + static const struct Hook { + const char* name; + PFN_vkVoidFunction proc; + } hooks[] = {\n""") + sortedCommandsList = sorted(gencom.allCommandsList) + for cmds in sortedCommandsList: + if gencom.isFunctionExported(cmds): + if gencom.isGloballyDispatched(cmds): + f.write (gencom.clang_off_spaces*2 + '{ \"' + cmds + '\", nullptr },\n') + elif isIntercepted(cmds) or cmds == 'vkGetInstanceProcAddr' or gencom.isDeviceDispatched(cmds): + f.write (gencom.clang_off_spaces*2 + '{ \"' + cmds + '\", reinterpret_cast<PFN_vkVoidFunction>(' + cmds[2:] + ') },\n') + f.write (gencom.clang_off_spaces + """}; + // clang-format on + constexpr size_t count = sizeof(hooks) / sizeof(hooks[0]); + auto hook = std::lower_bound( + hooks, hooks + count, pName, + [](const Hook& h, const char* n) { return strcmp(h.name, n) < 0; }); + if (hook < hooks + count && strcmp(hook->name, pName) == 0) { + if (!hook->proc) { + vulkan::driver::Logger(instance).Err( + instance, "invalid vkGetInstanceProcAddr(%p, \\\"%s\\\") call", + instance, pName); + } + return hook->proc; + } + // clang-format off\n\n""") + +def interceptDeviceProcAddr(functionName, f): + f.write (gencom.clang_off_spaces + """if (device == VK_NULL_HANDLE) { + ALOGE("invalid vkGetDeviceProcAddr(VK_NULL_HANDLE, ...) call"); + return nullptr; + }\n\n""") + f.write (gencom.clang_off_spaces + 'static const char* const known_non_device_names[] = {\n') + sortedCommandsList = sorted(gencom.allCommandsList) + for cmds in sortedCommandsList: + if gencom.isFunctionSupported(cmds): + if not gencom.isDeviceDispatched(cmds): + f.write(gencom.clang_off_spaces*2 + '\"' + cmds + '\",\n') + f.write(gencom.clang_off_spaces + '};\n') + f.write(gencom.clang_off_spaces + """// clang-format on + constexpr size_t count = + sizeof(known_non_device_names) / sizeof(known_non_device_names[0]); + if (!pName || + std::binary_search( + known_non_device_names, known_non_device_names + count, pName, + [](const char* a, const char* b) { return (strcmp(a, b) < 0); })) { + vulkan::driver::Logger(device).Err( + device, "invalid vkGetDeviceProcAddr(%p, \\\"%s\\\") call", device, + (pName) ? pName : "(null)"); + return nullptr; + } + // clang-format off\n\n""") + for cmds in gencom.allCommandsList: + if gencom.isDeviceDispatched(cmds): + if isIntercepted(cmds) or cmds == 'vkGetDeviceProcAddr': + f.write (gencom.clang_off_spaces + 'if (strcmp(pName, "' + cmds + '") == 0) return reinterpret_cast<PFN_vkVoidFunction>(' + cmds[2:] + ');\n') + f.write ('\n') + +def apiDispatch(functionName, f): + assert not isIntercepted(functionName) + + f.write (gencom.clang_off_spaces) + if gencom.returnTypeDict[functionName] != 'void': + f.write ('return ') + + paramList = gencom.paramDict[functionName] + p0 = paramList[0][1] + f.write('GetData(' + p0 + ').dispatch.' + functionName[2:] + '(' + ', '.join(i[1] for i in paramList) + ');\n') + + +def api_gencpp(): + genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','api_gen2.cpp') + header = """#include <log/log.h> +#include <string.h> + +#include <algorithm> + +// to catch mismatches between vulkan.h and this file +#undef VK_NO_PROTOTYPES +#include "api.h" + +namespace vulkan { +namespace api { + +""" + with open(genfile, 'w') as f: + f.write (gencom.copyright) + f.write (gencom.warning) + f.write ("""#include <log/log.h> +#include <string.h> + +#include <algorithm> + +// to catch mismatches between vulkan.h and this file +#undef VK_NO_PROTOTYPES +#include "api.h" + +namespace vulkan { +namespace api {\n\n""") + defineInitProc('dispatch',f) + defineInitProcExt(f) + f.write ('namespace {\n\n') + gencom.clang_off(f,0) + f.write ('\n') + for cmds in gencom.allCommandsList: + defineExtensionStub(cmds,f) + gencom.clang_on(f,0) + f.write ('\n} // namespace\n\n') + f.write ("""bool InitDispatchTable( + VkInstance instance, + PFN_vkGetInstanceProcAddr get_proc, + const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions) { + auto& data = GetData(instance); + bool success = true;\n\n""") + gencom.clang_off(f,1) + for cmds in gencom.allCommandsList: + if gencom.isInstanceDispatchTableEntry(cmds): + gencom.initProc(cmds, f) + gencom.clang_on(f,1) + f.write ('\n') + f.write (' return success;\n}\n\n') + f.write ("""bool InitDispatchTable( + VkDevice dev, + PFN_vkGetDeviceProcAddr get_proc, + const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions) { + auto& data = GetData(dev); + bool success = true;\n\n""") + + gencom.clang_off(f,1) + for cmds in gencom.allCommandsList: + if gencom.isDeviceDispatchTableEntry(cmds): + gencom.initProc(cmds, f) + gencom.clang_on(f,1) + f.write ('\n') + f.write (' return success;\n}\n\n') + + gencom.clang_off(f,0) + + f.write ('\nnamespace {\n\n') + f.write('// forward declarations needed by GetInstanceProcAddr and GetDeviceProcAddr\n') + for cmds in gencom.allCommandsList: + if gencom.isFunctionExported(cmds) and not isIntercepted(cmds): + paramList = [''.join(i) for i in gencom.paramDict[cmds]] + f.write ('VKAPI_ATTR '+gencom.returnTypeDict[cmds] + ' ' + cmds[2:] + '(' + ', '.join(paramList) + ');\n') + + f.write ('\n') + + for cmds in gencom.allCommandsList: + if gencom.isFunctionExported(cmds) and not isIntercepted(cmds): + paramList = [''.join(i) for i in gencom.paramDict[cmds]] + f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[cmds] + ' ' + cmds[2:] + '(' + ', '.join(paramList) + ') {\n') + if cmds == 'vkGetInstanceProcAddr': + interceptInstanceProcAddr(cmds, f) + elif cmds == 'vkGetDeviceProcAddr': + interceptDeviceProcAddr(cmds, f) + apiDispatch(cmds, f) + f.write('}\n\n') + f.write ("""\n} // anonymous namespace + +// clang-format on + +} // namespace api +} // namespace vulkan + +// clang-format off\n\n""") + + for cmds in gencom.allCommandsList: + if gencom.isFunctionExported(cmds): + paramList = [''.join(i) for i in gencom.paramDict[cmds]] + f.write ('__attribute__((visibility("default")))\n') + f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[cmds] + ' ' + cmds + '(' + ', '.join(paramList) + ') {\n') + f.write (gencom.clang_off_spaces) + if gencom.returnTypeDict[cmds] != 'void': + f.write ('return ') + paramList = gencom.paramDict[cmds] + f.write ('vulkan::api::' + cmds[2:] + '(' + ', '.join(i[1] for i in paramList) + ');\n') + f.write ('}\n\n') + + gencom.clang_on(f, 0) + diff --git a/vulkan/scripts/code_generator.py b/vulkan/scripts/code_generator.py new file mode 100644 index 0000000000..91c0d3023a --- /dev/null +++ b/vulkan/scripts/code_generator.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# +# Copyright 2019 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 script provides the main function for generating +# vulkan framework directly from the vulkan registry (vk.xml). + +import generator_common as gencom +import api_generator as apigen + +if __name__ == '__main__': + gencom.parseVulkanRegistry() + apigen.api_genh() + apigen.api_gencpp() diff --git a/vulkan/scripts/generator_common.py b/vulkan/scripts/generator_common.py new file mode 100644 index 0000000000..313357d288 --- /dev/null +++ b/vulkan/scripts/generator_common.py @@ -0,0 +1,238 @@ +#!/usr/bin/env python3 +# +# Copyright 2019 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 script provides the common functions for generating the +# vulkan framework directly from the vulkan registry (vk.xml). + +copyright = """/* + * Copyright 2016 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. + */ + +""" + +warning = '// WARNING: This file is generated. See ../README.md for instructions.\n\n' + +blacklistedExtensions = [ + 'VK_KHR_display', + 'VK_KHR_display_swapchain', + 'VK_KHR_mir_surface', + 'VK_KHR_xcb_surface', + 'VK_KHR_xlib_surface', + 'VK_KHR_wayland_surface', + 'VK_KHR_win32_surface', + 'VK_KHR_external_memory_win32', + 'VK_KHR_win32_keyed_mutex', + 'VK_KHR_external_semaphore_win32', + 'VK_KHR_external_fence_win32', + 'VK_EXT_acquire_xlib_display', + 'VK_EXT_direct_mode_display', + 'VK_EXT_display_surface_counter', + 'VK_EXT_display_control', + 'VK_FUCHSIA_imagepipe_surface', + 'VK_MVK_ios_surface', + 'VK_MVK_macos_surface', + 'VK_NN_vi_surface', + 'VK_NV_external_memory_win32', + 'VK_NV_win32_keyed_mutex', + 'VK_EXT_metal_surface', #not present in vulkan.api + 'VK_NVX_image_view_handle', #not present in vulkan.api + 'VK_NV_cooperative_matrix' #not present in vulkan.api +] + +exportedExtensions = [ + 'VK_KHR_surface', + 'VK_KHR_swapchain', + 'VK_KHR_android_surface', + 'VK_ANDROID_external_memory_android_hardware_buffer' +] + +def isFunctionSupported(functionName): + if functionName not in extensionsDict: + return True + else: + if extensionsDict[functionName] not in blacklistedExtensions: + return True + return False + +def isInstanceDispatched(functionName): + return isFunctionSupported(functionName) and getDispatchTableType(functionName) == 'Instance' + +def isDeviceDispatched(functionName): + return isFunctionSupported(functionName) and getDispatchTableType(functionName) == 'Device' + +def isGloballyDispatched(functionName): + return isFunctionSupported(functionName) and getDispatchTableType(functionName) == 'Global' + +def isExtensionExported(extensionName): + if extensionName in exportedExtensions: + return True + return False + +def isFunctionExported(functionName): + if isFunctionSupported(functionName): + if functionName in extensionsDict: + return isExtensionExported(extensionsDict[functionName]) + return True + return False + +def getDispatchTableType(functionName): + if functionName not in paramDict: + return None + + switchCase = { + 'VkInstance ' : 'Instance', + 'VkPhysicalDevice ' : 'Instance', + 'VkDevice ' : 'Device', + 'VkQueue ' : 'Device', + 'VkCommandBuffer ' : 'Device' + } + + if len(paramDict[functionName])>0: + return switchCase.get(paramDict[functionName][0][0], 'Global') + return 'Global' + +def isInstanceDispatchTableEntry(functionName): + if functionName == 'vkEnumerateDeviceLayerProperties': # deprecated, unused internally - @dbd33bc + return False + if isFunctionExported(functionName) and isInstanceDispatched(functionName): + return True + return False + +def isDeviceDispatchTableEntry(functionName): + if isFunctionExported(functionName) and isDeviceDispatched(functionName): + return True + return False + + +def clang_on(f, indent): + f.write (clang_off_spaces * indent + '// clang-format on\n') + +def clang_off(f, indent): + f.write (clang_off_spaces * indent + '// clang-format off\n') + +clang_off_spaces = ' '*4 + +parametersList = [] +paramDict = {} +allCommandsList = [] +extensionsDict = {} +returnTypeDict = {} +versionDict = {} +aliasDict = {} + +def parseVulkanRegistry(): + import xml.etree.ElementTree as ET + import os + vulkan_registry = os.path.join(os.path.dirname(__file__),'..','..','..','..','external','vulkan-headers','registry','vk.xml') + tree = ET.parse(vulkan_registry) + root = tree.getroot() + protoset = False + fnName = "" + fnType = "" + for commands in root.iter('commands'): + for command in commands: + if command.tag == 'command': + if protoset == True: + paramDict[fnName] = parametersList.copy() + parametersList.clear() + protoset = False + if command.get('alias') != None: + alias = command.get('alias') + fnName = command.get('name') + aliasDict[fnName] = alias + allCommandsList.append(fnName) + paramDict[fnName] = paramDict[alias].copy() + for params in command: + if(params.tag == 'param'): + paramtype = "" + if params.text!=None: + paramtype = params.text + typeval = params.find('type') + paramtype = paramtype + typeval.text + if typeval.tail!=None: + paramtype = paramtype + typeval.tail + pname = params.find('name') + paramname = pname.text + if pname.tail != None: + parametersList.append((paramtype,paramname,pname.tail)) + else: + parametersList.append((paramtype,paramname)) + if params.tag == 'proto': + for c in params: + if c.tag == 'type': + fnType = c.text + if c.tag == 'name': + fnName = c.text + protoset = True + allCommandsList.append(fnName) + returnTypeDict[fnName] = fnType + + for exts in root.iter('extensions'): + for extension in exts: + apiversion = "" + if extension.tag == 'extension': + extname = extension.get('name') + for req in extension: + if req.get('feature')!=None: + apiversion = req.get('feature') + for commands in req: + if commands.tag == 'command': + commandname = commands.get('name') + if commandname not in extensionsDict: + extensionsDict[commandname] = extname + if apiversion != "": + versionDict[commandname] = apiversion + + for feature in root.iter('feature'): + apiversion = feature.get('name') + for req in feature: + for command in req: + if command.tag == 'command': + cmdName = command.get('name') + if cmdName in allCommandsList: + versionDict[cmdName] = apiversion + + +def initProc(name, f): + if name in extensionsDict: + f.write (' INIT_PROC_EXT(' + extensionsDict[name][3:] + ', ') + else: + f.write (' INIT_PROC(') + + if name in versionDict and versionDict[name] == 'VK_VERSION_1_1': + f.write('false, ') + else: + f.write('true, ') + + if isInstanceDispatched(name): + f.write('instance, ') + else: + f.write('dev, ') + + f.write(name[2:] + ');\n') + |