diff options
134 files changed, 3570 insertions, 1871 deletions
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index 922367f54a..8bcb1e5da5 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -5,6 +5,7 @@ clang_format = true # Only turn on clang-format check for the following subfolders. clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp cmds/idlcli/ + cmds/servicemanager/ include/input/ include/powermanager/ libs/binder/fuzzer/ diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp index c04b558e2d..3a87776162 100644 --- a/cmds/installd/otapreopt_chroot.cpp +++ b/cmds/installd/otapreopt_chroot.cpp @@ -27,6 +27,7 @@ #include <android-base/file.h> #include <android-base/logging.h> #include <android-base/macros.h> +#include <android-base/scopeguard.h> #include <android-base/stringprintf.h> #include <android-base/unique_fd.h> #include <libdm/dm.h> @@ -72,6 +73,15 @@ static void ActivateApexPackages() { } } +static void DeactivateApexPackages() { + std::vector<std::string> apexd_cmd{"/system/bin/apexd", "--unmount-all"}; + std::string apexd_error_msg; + bool exec_result = Exec(apexd_cmd, &apexd_error_msg); + if (!exec_result) { + PLOG(ERROR) << "Running /system/bin/apexd --unmount-all failed: " << apexd_error_msg; + } +} + static void TryExtraMount(const char* name, const char* slot, const char* target) { std::string partition_name = StringPrintf("%s%s", name, slot); @@ -231,10 +241,30 @@ static int otapreopt_chroot(const int argc, char **arg) { exit(205); } + // Call apexd --unmount-all to free up loop and dm block devices, so that we can re-use + // them during the next invocation. Since otapreopt_chroot calls exit in case something goes + // wrong we need to register our own atexit handler. + // We want to register this handler before actually activating apex packages. This is mostly + // due to the fact that if fail to unmount apexes, then on the next run of otapreopt_chroot + // we will ask for new loop devices instead of re-using existing ones, and we really don't want + // to do that. :) + if (atexit(DeactivateApexPackages) != 0) { + LOG(ERROR) << "Failed to register atexit hander"; + exit(206); + } + // Try to mount APEX packages in "/apex" in the chroot dir. We need at least // the ART APEX, as it is required by otapreopt to run dex2oat. ActivateApexPackages(); + auto cleanup = android::base::make_scope_guard([](){ + std::vector<std::string> apexd_cmd{"/system/bin/apexd", "--unmount-all"}; + std::string apexd_error_msg; + bool exec_result = Exec(apexd_cmd, &apexd_error_msg); + if (!exec_result) { + PLOG(ERROR) << "Running /system/bin/apexd --unmount-all failed: " << apexd_error_msg; + } + }); // Check that an ART APEX has been activated; clean up and exit // early otherwise. static constexpr const std::string_view kRequiredApexs[] = { diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp index c47df52984..c4ecd070c1 100644 --- a/cmds/installd/utils.cpp +++ b/cmds/installd/utils.cpp @@ -1062,6 +1062,8 @@ int prepare_app_cache_dir(const std::string& parent, const char* name, mode_t ta static const char* kProcFilesystems = "/proc/filesystems"; bool supports_sdcardfs() { + if (!property_get_bool("external_storage.sdcardfs.enabled", true)) + return false; std::string supported; if (!android::base::ReadFileToString(kProcFilesystems, &supported)) { PLOG(ERROR) << "Failed to read supported filesystems"; diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp index b6ff28d416..7c1ca91528 100644 --- a/cmds/lshal/test.cpp +++ b/cmds/lshal/test.cpp @@ -508,10 +508,10 @@ TEST_F(ListTest, DumpVintf) { EXPECT_THAT(output, HasSubstr("a.h.foo6@6.0::IFoo/6")); EXPECT_EQ("", err.str()); + std::string error; vintf::HalManifest m; - EXPECT_EQ(true, vintf::gHalManifestConverter(&m, out.str())) - << "--init-vintf does not emit valid HAL manifest: " - << vintf::gHalManifestConverter.lastError(); + EXPECT_EQ(true, vintf::gHalManifestConverter(&m, out.str(), &error)) + << "--init-vintf does not emit valid HAL manifest: " << error; } // test default columns diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp index 9de344a820..3ebdeee7aa 100644 --- a/cmds/servicemanager/Android.bp +++ b/cmds/servicemanager/Android.bp @@ -14,6 +14,7 @@ cc_defaults { "-Wall", "-Wextra", "-Werror", + "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION", ], srcs: [ diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp index 0dbab4e055..2f5524940e 100644 --- a/cmds/servicemanager/ServiceManager.cpp +++ b/cmds/servicemanager/ServiceManager.cpp @@ -239,7 +239,8 @@ Status ServiceManager::addService(const std::string& name, const sp<IBinder>& bi #endif // !VENDORSERVICEMANAGER // implicitly unlinked when the binder is removed - if (binder->remoteBinder() != nullptr && binder->linkToDeath(this) != OK) { + if (binder->remoteBinder() != nullptr && + binder->linkToDeath(sp<ServiceManager>::fromExisting(this)) != OK) { LOG(ERROR) << "Could not linkToDeath when adding " << name; return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } @@ -307,7 +308,9 @@ Status ServiceManager::registerForNotifications( return Status::fromExceptionCode(Status::EX_NULL_POINTER); } - if (OK != IInterface::asBinder(callback)->linkToDeath(this)) { + if (OK != + IInterface::asBinder(callback)->linkToDeath( + sp<ServiceManager>::fromExisting(this))) { LOG(ERROR) << "Could not linkToDeath when adding " << name; return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } @@ -461,7 +464,8 @@ Status ServiceManager::registerClientCallback(const std::string& name, const sp< return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); } - if (OK != IInterface::asBinder(cb)->linkToDeath(this)) { + if (OK != + IInterface::asBinder(cb)->linkToDeath(sp<ServiceManager>::fromExisting(this))) { LOG(ERROR) << "Could not linkToDeath when adding client callback for " << name; return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } @@ -491,7 +495,7 @@ void ServiceManager::removeClientCallback(const wp<IBinder>& who, } ssize_t ServiceManager::Service::getNodeStrongRefCount() { - sp<BpBinder> bpBinder = binder->remoteBinder(); + sp<BpBinder> bpBinder = sp<BpBinder>::fromExisting(binder->remoteBinder()); if (bpBinder == nullptr) return -1; return ProcessState::self()->getStrongRefCountForNode(bpBinder); diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp index 627dfe6382..8c1beaca20 100644 --- a/cmds/servicemanager/main.cpp +++ b/cmds/servicemanager/main.cpp @@ -39,7 +39,7 @@ using ::android::sp; class BinderCallback : public LooperCallback { public: static sp<BinderCallback> setupTo(const sp<Looper>& looper) { - sp<BinderCallback> cb = new BinderCallback; + sp<BinderCallback> cb = sp<BinderCallback>::make(); int binder_fd = -1; IPCThreadState::self()->setupPolling(&binder_fd); @@ -65,7 +65,7 @@ public: class ClientCallbackCallback : public LooperCallback { public: static sp<ClientCallbackCallback> setupTo(const sp<Looper>& looper, const sp<ServiceManager>& manager) { - sp<ClientCallbackCallback> cb = new ClientCallbackCallback(manager); + sp<ClientCallbackCallback> cb = sp<ClientCallbackCallback>::make(manager); int fdTimer = timerfd_create(CLOCK_MONOTONIC, 0 /*flags*/); LOG_ALWAYS_FATAL_IF(fdTimer < 0, "Failed to timerfd_create: fd: %d err: %d", fdTimer, errno); @@ -105,6 +105,7 @@ public: return 1; // Continue receiving callbacks. } private: + friend sp<ClientCallbackCallback>; ClientCallbackCallback(const sp<ServiceManager>& manager) : mManager(manager) {} sp<ServiceManager> mManager; }; @@ -120,7 +121,7 @@ int main(int argc, char** argv) { ps->setThreadPoolMaxThreadCount(0); ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY); - sp<ServiceManager> manager = new ServiceManager(std::make_unique<Access>()); + sp<ServiceManager> manager = sp<ServiceManager>::make(std::make_unique<Access>()); if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) { LOG(ERROR) << "Could not self register servicemanager"; } diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp index fb9f9df856..5d5a75e174 100644 --- a/cmds/servicemanager/test_sm.cpp +++ b/cmds/servicemanager/test_sm.cpp @@ -46,7 +46,7 @@ static sp<IBinder> getBinder() { } }; - return new LinkableBinder; + return sp<LinkableBinder>::make(); } class MockAccess : public Access { @@ -71,7 +71,7 @@ static sp<ServiceManager> getPermissiveServiceManager() { ON_CALL(*access, canFind(_, _)).WillByDefault(Return(true)); ON_CALL(*access, canList(_)).WillByDefault(Return(true)); - sp<ServiceManager> sm = new NiceMock<MockServiceManager>(std::move(access)); + sp<ServiceManager> sm = sp<NiceMock<MockServiceManager>>::make(std::move(access)); return sm; } @@ -119,7 +119,7 @@ TEST(AddService, AddDisallowedFromApp) { .uid = uid, })); EXPECT_CALL(*access, canAdd(_, _)).Times(0); - sp<ServiceManager> sm = new NiceMock<MockServiceManager>(std::move(access)); + sp<ServiceManager> sm = sp<NiceMock<MockServiceManager>>::make(std::move(access)); EXPECT_FALSE(sm->addService("foo", getBinder(), false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); @@ -161,7 +161,7 @@ TEST(AddService, NoPermissions) { EXPECT_CALL(*access, getCallingContext()).WillOnce(Return(Access::CallingContext{})); EXPECT_CALL(*access, canAdd(_, _)).WillOnce(Return(false)); - sp<ServiceManager> sm = new NiceMock<MockServiceManager>(std::move(access)); + sp<ServiceManager> sm = sp<NiceMock<MockServiceManager>>::make(std::move(access)); EXPECT_FALSE(sm->addService("foo", getBinder(), false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); @@ -194,7 +194,7 @@ TEST(GetService, NoPermissionsForGettingService) { EXPECT_CALL(*access, canAdd(_, _)).WillOnce(Return(true)); EXPECT_CALL(*access, canFind(_, _)).WillOnce(Return(false)); - sp<ServiceManager> sm = new NiceMock<MockServiceManager>(std::move(access)); + sp<ServiceManager> sm = sp<NiceMock<MockServiceManager>>::make(std::move(access)); EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); @@ -218,7 +218,7 @@ TEST(GetService, AllowedFromIsolated) { EXPECT_CALL(*access, canAdd(_, _)).WillOnce(Return(true)); EXPECT_CALL(*access, canFind(_, _)).WillOnce(Return(true)); - sp<ServiceManager> sm = new NiceMock<MockServiceManager>(std::move(access)); + sp<ServiceManager> sm = sp<NiceMock<MockServiceManager>>::make(std::move(access)); sp<IBinder> service = getBinder(); EXPECT_TRUE(sm->addService("foo", service, true /*allowIsolated*/, @@ -244,7 +244,7 @@ TEST(GetService, NotAllowedFromIsolated) { // TODO(b/136023468): when security check is first, this should be called first // EXPECT_CALL(*access, canFind(_, _)).WillOnce(Return(true)); - sp<ServiceManager> sm = new NiceMock<MockServiceManager>(std::move(access)); + sp<ServiceManager> sm = sp<NiceMock<MockServiceManager>>::make(std::move(access)); EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); @@ -261,7 +261,7 @@ TEST(ListServices, NoPermissions) { EXPECT_CALL(*access, getCallingContext()).WillOnce(Return(Access::CallingContext{})); EXPECT_CALL(*access, canList(_)).WillOnce(Return(false)); - sp<ServiceManager> sm = new NiceMock<MockServiceManager>(std::move(access)); + sp<ServiceManager> sm = sp<NiceMock<MockServiceManager>>::make(std::move(access)); std::vector<std::string> out; EXPECT_FALSE(sm->listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL, &out).isOk()); @@ -329,9 +329,9 @@ TEST(ServiceNotifications, NoPermissionsRegister) { EXPECT_CALL(*access, getCallingContext()).WillOnce(Return(Access::CallingContext{})); EXPECT_CALL(*access, canFind(_,_)).WillOnce(Return(false)); - sp<ServiceManager> sm = new ServiceManager(std::move(access)); + sp<ServiceManager> sm = sp<ServiceManager>::make(std::move(access)); - sp<CallbackHistorian> cb = new CallbackHistorian; + sp<CallbackHistorian> cb = sp<CallbackHistorian>::make(); EXPECT_EQ(sm->registerForNotifications("foofoo", cb).exceptionCode(), Status::EX_SECURITY); @@ -343,9 +343,9 @@ TEST(ServiceNotifications, NoPermissionsUnregister) { EXPECT_CALL(*access, getCallingContext()).WillOnce(Return(Access::CallingContext{})); EXPECT_CALL(*access, canFind(_,_)).WillOnce(Return(false)); - sp<ServiceManager> sm = new ServiceManager(std::move(access)); + sp<ServiceManager> sm = sp<ServiceManager>::make(std::move(access)); - sp<CallbackHistorian> cb = new CallbackHistorian; + sp<CallbackHistorian> cb = sp<CallbackHistorian>::make(); // should always hit security error first EXPECT_EQ(sm->unregisterForNotifications("foofoo", cb).exceptionCode(), @@ -355,7 +355,7 @@ TEST(ServiceNotifications, NoPermissionsUnregister) { TEST(ServiceNotifications, InvalidName) { auto sm = getPermissiveServiceManager(); - sp<CallbackHistorian> cb = new CallbackHistorian; + sp<CallbackHistorian> cb = sp<CallbackHistorian>::make(); EXPECT_EQ(sm->registerForNotifications("foo@foo", cb).exceptionCode(), Status::EX_ILLEGAL_ARGUMENT); @@ -371,7 +371,7 @@ TEST(ServiceNotifications, NullCallback) { TEST(ServiceNotifications, Unregister) { auto sm = getPermissiveServiceManager(); - sp<CallbackHistorian> cb = new CallbackHistorian; + sp<CallbackHistorian> cb = sp<CallbackHistorian>::make(); EXPECT_TRUE(sm->registerForNotifications("foofoo", cb).isOk()); EXPECT_EQ(sm->unregisterForNotifications("foofoo", cb).exceptionCode(), 0); @@ -380,7 +380,7 @@ TEST(ServiceNotifications, Unregister) { TEST(ServiceNotifications, UnregisterWhenNoRegistrationExists) { auto sm = getPermissiveServiceManager(); - sp<CallbackHistorian> cb = new CallbackHistorian; + sp<CallbackHistorian> cb = sp<CallbackHistorian>::make(); EXPECT_EQ(sm->unregisterForNotifications("foofoo", cb).exceptionCode(), Status::EX_ILLEGAL_STATE); @@ -389,7 +389,7 @@ TEST(ServiceNotifications, UnregisterWhenNoRegistrationExists) { TEST(ServiceNotifications, NoNotification) { auto sm = getPermissiveServiceManager(); - sp<CallbackHistorian> cb = new CallbackHistorian; + sp<CallbackHistorian> cb = sp<CallbackHistorian>::make(); EXPECT_TRUE(sm->registerForNotifications("foofoo", cb).isOk()); EXPECT_TRUE(sm->addService("otherservice", getBinder(), @@ -402,7 +402,7 @@ TEST(ServiceNotifications, NoNotification) { TEST(ServiceNotifications, GetNotification) { auto sm = getPermissiveServiceManager(); - sp<CallbackHistorian> cb = new CallbackHistorian; + sp<CallbackHistorian> cb = sp<CallbackHistorian>::make(); sp<IBinder> service = getBinder(); @@ -417,7 +417,7 @@ TEST(ServiceNotifications, GetNotification) { TEST(ServiceNotifications, GetNotificationForAlreadyRegisteredService) { auto sm = getPermissiveServiceManager(); - sp<CallbackHistorian> cb = new CallbackHistorian; + sp<CallbackHistorian> cb = sp<CallbackHistorian>::make(); sp<IBinder> service = getBinder(); @@ -433,7 +433,7 @@ TEST(ServiceNotifications, GetNotificationForAlreadyRegisteredService) { TEST(ServiceNotifications, GetMultipleNotification) { auto sm = getPermissiveServiceManager(); - sp<CallbackHistorian> cb = new CallbackHistorian; + sp<CallbackHistorian> cb = sp<CallbackHistorian>::make(); sp<IBinder> binder1 = getBinder(); sp<IBinder> binder2 = getBinder(); diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto index 79aab822e4..06afefd3c8 100644 --- a/cmds/surfacereplayer/proto/src/trace.proto +++ b/cmds/surfacereplayer/proto/src/trace.proto @@ -50,7 +50,6 @@ message SurfaceChange { CornerRadiusChange corner_radius = 16; ReparentChange reparent = 17; RelativeParentChange relative_parent = 18; - ReparentChildrenChange reparent_children = 19; BackgroundBlurRadiusChange background_blur_radius = 20; ShadowRadiusChange shadow_radius = 21; BlurRegionsChange blur_regions = 22; @@ -190,10 +189,6 @@ message ReparentChange { required int32 parent_id = 1; } -message ReparentChildrenChange { - required int32 parent_id = 1; -} - message RelativeParentChange { required int32 relative_parent_id = 1; required int32 z = 2; diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp index bbbe6f7ec4..a6d9a3feb6 100644 --- a/cmds/surfacereplayer/replayer/Replayer.cpp +++ b/cmds/surfacereplayer/replayer/Replayer.cpp @@ -410,9 +410,6 @@ status_t Replayer::doSurfaceTransaction( case SurfaceChange::SurfaceChangeCase::kReparent: setReparentChange(transaction, change.id(), change.reparent()); break; - case SurfaceChange::SurfaceChangeCase::kReparentChildren: - setReparentChildrenChange(transaction, change.id(), change.reparent_children()); - break; case SurfaceChange::SurfaceChangeCase::kRelativeParent: setRelativeParentChange(transaction, change.id(), change.relative_parent()); break; @@ -709,15 +706,6 @@ void Replayer::setRelativeParentChange(SurfaceComposerClient::Transaction& t, t.setRelativeLayer(mLayers[id], mLayers[c.relative_parent_id()], c.z()); } -void Replayer::setReparentChildrenChange(SurfaceComposerClient::Transaction& t, - layer_id id, const ReparentChildrenChange& c) { - if (mLayers.count(c.parent_id()) == 0 || mLayers[c.parent_id()] == nullptr) { - ALOGE("Layer %d not found in reparent children transaction", c.parent_id()); - return; - } - t.reparentChildren(mLayers[id], mLayers[c.parent_id()]); -} - void Replayer::setShadowRadiusChange(SurfaceComposerClient::Transaction& t, layer_id id, const ShadowRadiusChange& c) { t.setShadowRadius(mLayers[id], c.radius()); diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h index 324d591eaa..252db2bfbb 100644 --- a/cmds/surfacereplayer/replayer/Replayer.h +++ b/cmds/surfacereplayer/replayer/Replayer.h @@ -116,8 +116,6 @@ class Replayer { layer_id id, const ReparentChange& c); void setRelativeParentChange(SurfaceComposerClient::Transaction& t, layer_id id, const RelativeParentChange& c); - void setReparentChildrenChange(SurfaceComposerClient::Transaction& t, - layer_id id, const ReparentChildrenChange& c); void setShadowRadiusChange(SurfaceComposerClient::Transaction& t, layer_id id, const ShadowRadiusChange& c); void setBlurRegionsChange(SurfaceComposerClient::Transaction& t, diff --git a/include/android/surface_control.h b/include/android/surface_control.h index ee7595769c..c5e3587517 100644 --- a/include/android/surface_control.h +++ b/include/android/surface_control.h @@ -497,6 +497,35 @@ void ASurfaceTransaction_setFrameRateWithChangeStrategy(ASurfaceTransaction* tra int8_t compatibility, int8_t changeFrameRateStrategy) __INTRODUCED_IN(31); +/** + * Indicate whether to enable backpressure for buffer submission to a given SurfaceControl. + * + * By default backpressure is disabled, which means submitting a buffer prior to receiving + * a callback for the previous buffer could lead to that buffer being "dropped". In cases + * where you are selecting for latency, this may be a desirable behavior! We had a new buffer + * ready, why shouldn't we show it? + * + * When back pressure is enabled, each buffer will be required to be presented + * before it is released and the callback delivered + * (absent the whole SurfaceControl being removed). + * + * Most apps are likely to have some sort of backpressure internally, e.g. you are + * waiting on the callback from frame N-2 before starting frame N. In high refresh + * rate scenarios there may not be much time between SurfaceFlinger completing frame + * N-1 (and therefore releasing buffer N-2) and beginning frame N. This means + * your app may not have enough time to respond in the callback. Using this flag + * and pushing buffers earlier for server side queuing will be advantageous + * in such cases. + * + * \param transaction The transaction in which to make the change. + * \param surface_control The ASurfaceControl on which to control buffer backpressure behavior. + * \param enableBackPressure Whether to enable back pressure. + */ +void ASurfaceTransaction_setEnableBackPressure(ASurfaceTransaction* transaction, + ASurfaceControl* surface_control, + bool enableBackPressure) + __INTRODUCED_IN(31); + __END_DECLS #endif // ANDROID_SURFACE_CONTROL_H diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h index 2deb99d154..712adfa57b 100644 --- a/include/input/InputDevice.h +++ b/include/input/InputDevice.h @@ -177,6 +177,14 @@ struct InputDeviceLightInfo { int32_t ordinal; }; +struct InputDeviceBatteryInfo { + explicit InputDeviceBatteryInfo(std::string name, int32_t id) : name(name), id(id) {} + // Name string of the battery. + std::string name; + // Battery id + int32_t id; +}; + /* * Describes the characteristics and capabilities of an input device. */ @@ -219,6 +227,7 @@ public: float min, float max, float flat, float fuzz, float resolution); void addMotionRange(const MotionRange& range); void addSensorInfo(const InputDeviceSensorInfo& info); + void addBatteryInfo(const InputDeviceBatteryInfo& info); void addLightInfo(const InputDeviceLightInfo& info); inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; } @@ -276,6 +285,8 @@ private: std::unordered_map<InputDeviceSensorType, InputDeviceSensorInfo> mSensors; /* Map from light ID to light info */ std::unordered_map<int32_t, InputDeviceLightInfo> mLights; + /* Map from battery ID to battery info */ + std::unordered_map<int32_t, InputDeviceBatteryInfo> mBatteries; }; /* Types of input device configuration files. */ diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index b0e8c7c00c..e980dd04ec 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -60,20 +60,13 @@ cc_library_headers { // Currently, these are only on system android (not vendor, not host) // TODO(b/183654927) - move these into separate libraries libbinder_device_interface_sources = [ - "ActivityManager.cpp", "AppOpsManager.cpp", - "IActivityManager.cpp", "IAppOpsCallback.cpp", "IAppOpsService.cpp", - "IMediaResourceMonitor.cpp", + "IPermissionController.cpp", - "IProcessInfoService.cpp", - "IUidObserver.cpp", "PermissionCache.cpp", "PermissionController.cpp", - "ProcessInfoService.cpp", - "IpPrefix.cpp", - ":activity_manager_procstate_aidl", ] cc_library { @@ -283,3 +276,36 @@ cc_library { "libutils", ], } + +cc_library { + name: "libprocessinfoservice_aidl", + srcs: [ + "IProcessInfoService.cpp", + "ProcessInfoService.cpp", + ], + export_include_dirs: ["include_processinfo"], + shared_libs: [ + "libbinder", + "libutils", + "liblog", + ], +} + +cc_library { + name: "libactivitymanager_aidl", + srcs: [ + "ActivityManager.cpp", + "IActivityManager.cpp", + "IUidObserver.cpp", + ":activity_manager_procstate_aidl", + ], + export_include_dirs: ["include_activitymanager"], + shared_libs: [ + "libbinder", + "libutils", + "liblog", + ], + aidl: { + export_aidl_headers: true, + }, +} diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index 825a821cc4..53b36fffdc 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -194,10 +194,13 @@ bool BpBinder::isDescriptorCached() const { const String16& BpBinder::getInterfaceDescriptor() const { if (isDescriptorCached() == false) { - Parcel send, reply; + sp<BpBinder> thiz = const_cast<BpBinder*>(this); + + Parcel data; + data.markForBinder(thiz); + Parcel reply; // do the IPC without a lock held. - status_t err = const_cast<BpBinder*>(this)->transact( - INTERFACE_TRANSACTION, send, &reply); + status_t err = thiz->transact(INTERFACE_TRANSACTION, data, &reply); if (err == NO_ERROR) { String16 res(reply.readString16()); Mutex::Autolock _l(mLock); diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp index 18979697f8..d59f44562e 100644 --- a/libs/binder/IAppOpsService.cpp +++ b/libs/binder/IAppOpsService.cpp @@ -18,8 +18,8 @@ #include <binder/IAppOpsService.h> -#include <utils/Log.h> #include <binder/Parcel.h> +#include <utils/Log.h> #include <utils/String8.h> #include <optional> @@ -63,6 +63,9 @@ public: remote()->transact(NOTE_OPERATION_TRANSACTION, data, &reply); // fail on exception if (reply.readExceptionCode() != 0) return MODE_ERRORED; + // TODO b/184855056: extract to class + reply.readInt32(); + reply.readByte(); return reply.readInt32(); } @@ -84,6 +87,9 @@ public: remote()->transact(START_OPERATION_TRANSACTION, data, &reply); // fail on exception if (reply.readExceptionCode() != 0) return MODE_ERRORED; + // TODO b/184855056: extract to class + reply.readInt32(); + reply.readByte(); return reply.readInt32(); } diff --git a/libs/binder/IMediaResourceMonitor.cpp b/libs/binder/IMediaResourceMonitor.cpp deleted file mode 100644 index f5fa817b5e..0000000000 --- a/libs/binder/IMediaResourceMonitor.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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. - */ - -#include <binder/IMediaResourceMonitor.h> -#include <binder/Parcel.h> -#include <utils/Errors.h> -#include <sys/types.h> - -namespace android { - -// ---------------------------------------------------------------------- - -class BpMediaResourceMonitor : public BpInterface<IMediaResourceMonitor> { -public: - explicit BpMediaResourceMonitor(const sp<IBinder>& impl) - : BpInterface<IMediaResourceMonitor>(impl) {} - - virtual void notifyResourceGranted(/*in*/ int32_t pid, /*in*/ const int32_t type) - { - Parcel data, reply; - data.writeInterfaceToken(IMediaResourceMonitor::getInterfaceDescriptor()); - data.writeInt32(pid); - data.writeInt32(type); - remote()->transact(NOTIFY_RESOURCE_GRANTED, data, &reply, IBinder::FLAG_ONEWAY); - } -}; - -IMPLEMENT_META_INTERFACE(MediaResourceMonitor, "android.media.IMediaResourceMonitor") - -// ---------------------------------------------------------------------- - -// NOLINTNEXTLINE(google-default-arguments) -status_t BnMediaResourceMonitor::onTransact( uint32_t code, const Parcel& data, Parcel* reply, - uint32_t flags) { - switch(code) { - case NOTIFY_RESOURCE_GRANTED: { - CHECK_INTERFACE(IMediaResourceMonitor, data, reply); - int32_t pid = data.readInt32(); - const int32_t type = data.readInt32(); - notifyResourceGranted(/*in*/ pid, /*in*/ type); - return NO_ERROR; - } break; - default: - return BBinder::onTransact(code, data, reply, flags); - } -} - -// ---------------------------------------------------------------------- - -} // namespace android diff --git a/libs/binder/IProcessInfoService.cpp b/libs/binder/IProcessInfoService.cpp index 570edb9eb7..d26754e96c 100644 --- a/libs/binder/IProcessInfoService.cpp +++ b/libs/binder/IProcessInfoService.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include <binder/IProcessInfoService.h> +#include <processinfo/IProcessInfoService.h> #include <binder/Parcel.h> #include <utils/Errors.h> #include <sys/types.h> diff --git a/libs/binder/IpPrefix.cpp b/libs/binder/IpPrefix.cpp deleted file mode 100644 index 4edc493f11..0000000000 --- a/libs/binder/IpPrefix.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2015 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 "IpPrefix" - -#include <binder/IpPrefix.h> -#include <vector> - -#include <binder/IBinder.h> -#include <binder/Parcel.h> -#include <log/log.h> -#include <utils/Errors.h> - -using android::BAD_VALUE; -using android::NO_ERROR; -using android::Parcel; -using android::status_t; - -namespace android { - -namespace net { - -#define RETURN_IF_FAILED(calledOnce) \ - { \ - status_t returnStatus = calledOnce; \ - if (returnStatus) { \ - ALOGE("Failed at %s:%d (%s)", __FILE__, __LINE__, __func__); \ - return returnStatus; \ - } \ - } - -status_t IpPrefix::writeToParcel(Parcel* parcel) const { - /* - * Keep implementation in sync with writeToParcel() in - * frameworks/base/core/java/android/net/IpPrefix.java. - */ - std::vector<uint8_t> byte_vector; - - if (mIsIpv6) { - const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&mUnion.mIn6Addr); - byte_vector.insert(byte_vector.end(), bytes, bytes+sizeof(mUnion.mIn6Addr)); - } else { - const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&mUnion.mInAddr); - byte_vector.insert(byte_vector.end(), bytes, bytes+sizeof(mUnion.mIn6Addr)); - } - - RETURN_IF_FAILED(parcel->writeByteVector(byte_vector)); - RETURN_IF_FAILED(parcel->writeInt32(static_cast<int32_t>(mPrefixLength))); - - return NO_ERROR; -} - -status_t IpPrefix::readFromParcel(const Parcel* parcel) { - /* - * Keep implementation in sync with readFromParcel() in - * frameworks/base/core/java/android/net/IpPrefix.java. - */ - std::vector<uint8_t> byte_vector; - - RETURN_IF_FAILED(parcel->readByteVector(&byte_vector)); - RETURN_IF_FAILED(parcel->readInt32(&mPrefixLength)); - - if (byte_vector.size() == 16) { - mIsIpv6 = true; - memcpy((void*)&mUnion.mIn6Addr, &byte_vector[0], sizeof(mUnion.mIn6Addr)); - - } else if (byte_vector.size() == 4) { - mIsIpv6 = false; - memcpy((void*)&mUnion.mInAddr, &byte_vector[0], sizeof(mUnion.mInAddr)); - - } else { - ALOGE("Failed at %s:%d (%s)", __FILE__, __LINE__, __func__); \ - return BAD_VALUE; - } - - return NO_ERROR; -} - -const struct in6_addr& IpPrefix::getAddressAsIn6Addr() const -{ - return mUnion.mIn6Addr; -} - -const struct in_addr& IpPrefix::getAddressAsInAddr() const -{ - return mUnion.mInAddr; -} - -bool IpPrefix::getAddressAsIn6Addr(struct in6_addr* addr) const -{ - if (isIpv6()) { - *addr = mUnion.mIn6Addr; - return true; - } - return false; -} - -bool IpPrefix::getAddressAsInAddr(struct in_addr* addr) const -{ - if (isIpv4()) { - *addr = mUnion.mInAddr; - return true; - } - return false; -} - -bool IpPrefix::isIpv6() const -{ - return mIsIpv6; -} - -bool IpPrefix::isIpv4() const -{ - return !mIsIpv6; -} - -int32_t IpPrefix::getPrefixLength() const -{ - return mPrefixLength; -} - -void IpPrefix::setAddress(const struct in6_addr& addr) -{ - mUnion.mIn6Addr = addr; - mIsIpv6 = true; -} - -void IpPrefix::setAddress(const struct in_addr& addr) -{ - mUnion.mInAddr = addr; - mIsIpv6 = false; -} - -void IpPrefix::setPrefixLength(int32_t prefix) -{ - mPrefixLength = prefix; -} - -bool operator==(const IpPrefix& lhs, const IpPrefix& rhs) -{ - if (lhs.mIsIpv6 != rhs.mIsIpv6) { - return false; - } - - if (lhs.mPrefixLength != rhs.mPrefixLength) { - return false; - } - - if (lhs.mIsIpv6) { - return 0 == memcmp(lhs.mUnion.mIn6Addr.s6_addr, rhs.mUnion.mIn6Addr.s6_addr, sizeof(struct in6_addr)); - } - - return 0 == memcmp(&lhs.mUnion.mInAddr, &rhs.mUnion.mInAddr, sizeof(struct in_addr)); -} - -} // namespace net - -} // namespace android diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 7fedba2666..0425159f63 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -418,6 +418,11 @@ status_t Parcel::setData(const uint8_t* buffer, size_t len) status_t Parcel::appendFrom(const Parcel *parcel, size_t offset, size_t len) { + if (parcel->isForRpc() != isForRpc()) { + ALOGE("Cannot append Parcel of one format to another."); + return BAD_TYPE; + } + status_t err; const uint8_t *data = parcel->mData; const binder_size_t *objects = parcel->mObjects; @@ -555,12 +560,17 @@ void Parcel::markSensitive() const } void Parcel::markForBinder(const sp<IBinder>& binder) { + LOG_ALWAYS_FATAL_IF(mData != nullptr, "format must be set before data is written"); + if (binder && binder->remoteBinder() && binder->remoteBinder()->isRpcBinder()) { markForRpc(binder->remoteBinder()->getPrivateAccessorForId().rpcConnection()); } } void Parcel::markForRpc(const sp<RpcConnection>& connection) { + LOG_ALWAYS_FATAL_IF(mData != nullptr && mOwner == nullptr, + "format must be set before data is written OR on IPC data"); + LOG_ALWAYS_FATAL_IF(connection == nullptr, "markForRpc requires connection"); mConnection = connection; } @@ -2100,6 +2110,9 @@ size_t Parcel::ipcObjectsCount() const void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize, const binder_size_t* objects, size_t objectsCount, release_func relFunc) { + // this code uses 'mOwner == nullptr' to understand whether it owns memory + LOG_ALWAYS_FATAL_IF(relFunc == nullptr, "must provide cleanup function"); + freeData(); mData = const_cast<uint8_t*>(data); diff --git a/libs/binder/ProcessInfoService.cpp b/libs/binder/ProcessInfoService.cpp index f75141e5da..0fb954a450 100644 --- a/libs/binder/ProcessInfoService.cpp +++ b/libs/binder/ProcessInfoService.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include <binder/ProcessInfoService.h> +#include <processinfo/ProcessInfoService.h> #include <binder/IServiceManager.h> #include <utils/Log.h> diff --git a/libs/binder/RpcConnection.cpp b/libs/binder/RpcConnection.cpp index 83a1618e9f..dab3246fc5 100644 --- a/libs/binder/RpcConnection.cpp +++ b/libs/binder/RpcConnection.cpp @@ -20,6 +20,7 @@ #include <binder/Parcel.h> #include <binder/Stability.h> +#include <utils/String8.h> #include "RpcState.h" #include "RpcWireFormat.h" @@ -29,14 +30,20 @@ #include <sys/un.h> #include <unistd.h> -#if defined(__GLIBC__) +#ifdef __GLIBC__ extern "C" pid_t gettid(); #endif +#ifdef __BIONIC__ +#include <linux/vm_sockets.h> +#endif + namespace android { using base::unique_fd; +RpcConnection::SocketAddress::~SocketAddress() {} + RpcConnection::RpcConnection() { LOG_RPC_DETAIL("RpcConnection created %p", this); @@ -50,65 +57,68 @@ sp<RpcConnection> RpcConnection::make() { return new RpcConnection; } -bool RpcConnection::setupUnixDomainServer(const char* path) { - LOG_ALWAYS_FATAL_IF(mServer.get() != -1, "Only supports one server now"); - - unique_fd serverFd(TEMP_FAILURE_RETRY(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0))); - if (serverFd == -1) { - ALOGE("Could not create socket at %s: %s", path, strerror(errno)); - return false; +class UnixSocketAddress : public RpcConnection::SocketAddress { +public: + explicit UnixSocketAddress(const char* path) : mAddr({.sun_family = AF_UNIX}) { + unsigned int pathLen = strlen(path) + 1; + LOG_ALWAYS_FATAL_IF(pathLen > sizeof(mAddr.sun_path), "%u %s", pathLen, path); + memcpy(mAddr.sun_path, path, pathLen); } - - struct sockaddr_un addr = { - .sun_family = AF_UNIX, - }; - - unsigned int pathLen = strlen(path) + 1; - LOG_ALWAYS_FATAL_IF(pathLen > sizeof(addr.sun_path), "%u", pathLen); - memcpy(addr.sun_path, path, pathLen); - - if (0 != TEMP_FAILURE_RETRY(bind(serverFd.get(), (struct sockaddr*)&addr, sizeof(addr)))) { - ALOGE("Could not bind socket at %s: %s", path, strerror(errno)); - return false; + virtual ~UnixSocketAddress() {} + std::string toString() const override { + return String8::format("path '%.*s'", static_cast<int>(sizeof(mAddr.sun_path)), + mAddr.sun_path) + .c_str(); } + const sockaddr* addr() const override { return reinterpret_cast<const sockaddr*>(&mAddr); } + size_t addrSize() const override { return sizeof(mAddr); } - if (0 != TEMP_FAILURE_RETRY(listen(serverFd.get(), 1 /*backlog*/))) { - ALOGE("Could not listen socket at %s: %s", path, strerror(errno)); - return false; - } +private: + sockaddr_un mAddr; +}; - mServer = std::move(serverFd); - return true; +bool RpcConnection::setupUnixDomainServer(const char* path) { + return addServer(UnixSocketAddress(path)); } bool RpcConnection::addUnixDomainClient(const char* path) { - LOG_RPC_DETAIL("Connecting on path: %s", path); + return addClient(UnixSocketAddress(path)); +} - unique_fd serverFd(TEMP_FAILURE_RETRY(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0))); - if (serverFd == -1) { - ALOGE("Could not create socket at %s: %s", path, strerror(errno)); - return false; +#ifdef __BIONIC__ + +class VsockSocketAddress : public RpcConnection::SocketAddress { +public: + VsockSocketAddress(unsigned int cid, unsigned int port) + : mAddr({ + .svm_family = AF_VSOCK, + .svm_port = port, + .svm_cid = cid, + }) {} + virtual ~VsockSocketAddress() {} + std::string toString() const override { + return String8::format("cid %du port %du", mAddr.svm_cid, mAddr.svm_port).c_str(); } + const sockaddr* addr() const override { return reinterpret_cast<const sockaddr*>(&mAddr); } + size_t addrSize() const override { return sizeof(mAddr); } - struct sockaddr_un addr = { - .sun_family = AF_UNIX, - }; +private: + sockaddr_vm mAddr; +}; - unsigned int pathLen = strlen(path) + 1; - LOG_ALWAYS_FATAL_IF(pathLen > sizeof(addr.sun_path), "%u", pathLen); - memcpy(addr.sun_path, path, pathLen); +bool RpcConnection::setupVsockServer(unsigned int port) { + // realizing value w/ this type at compile time to avoid ubsan abort + constexpr unsigned int kAnyCid = VMADDR_CID_ANY; - if (0 != TEMP_FAILURE_RETRY(connect(serverFd.get(), (struct sockaddr*)&addr, sizeof(addr)))) { - ALOGE("Could not connect socket at %s: %s", path, strerror(errno)); - return false; - } - - LOG_RPC_DETAIL("Unix domain client with fd %d", serverFd.get()); + return addServer(VsockSocketAddress(kAnyCid, port)); +} - addClient(std::move(serverFd)); - return true; +bool RpcConnection::addVsockClient(unsigned int cid, unsigned int port) { + return addClient(VsockSocketAddress(cid, port)); } +#endif // __BIONIC__ + sp<IBinder> RpcConnection::getRootObject() { ExclusiveSocket socket(this, SocketUse::CLIENT); return state()->getRootObject(socket.fd(), this); @@ -130,11 +140,8 @@ status_t RpcConnection::sendDecStrong(const RpcAddress& address) { void RpcConnection::join() { // establish a connection { - struct sockaddr_un clientSa; - socklen_t clientSaLen = sizeof(clientSa); - - unique_fd clientFd(TEMP_FAILURE_RETRY( - accept4(mServer.get(), (struct sockaddr*)&clientSa, &clientSaLen, SOCK_CLOEXEC))); + unique_fd clientFd( + TEMP_FAILURE_RETRY(accept4(mServer.get(), nullptr, 0 /*length*/, SOCK_CLOEXEC))); if (clientFd < 0) { // If this log becomes confusing, should save more state from setupUnixDomainServer // in order to output here. @@ -144,7 +151,7 @@ void RpcConnection::join() { LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.get(), clientFd.get()); - addServer(std::move(clientFd)); + assignServerToThisThread(std::move(clientFd)); } // We may not use the connection we just established (two threads might @@ -170,14 +177,57 @@ wp<RpcServer> RpcConnection::server() { return mForServer; } -void RpcConnection::addClient(base::unique_fd&& fd) { +bool RpcConnection::addServer(const SocketAddress& addr) { + LOG_ALWAYS_FATAL_IF(mServer.get() != -1, "Each RpcConnection can only have one server."); + + unique_fd serverFd( + TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0))); + if (serverFd == -1) { + ALOGE("Could not create socket: %s", strerror(errno)); + return false; + } + + if (0 != TEMP_FAILURE_RETRY(bind(serverFd.get(), addr.addr(), addr.addrSize()))) { + int savedErrno = errno; + ALOGE("Could not bind socket at %s: %s", addr.toString().c_str(), strerror(savedErrno)); + return false; + } + + if (0 != TEMP_FAILURE_RETRY(listen(serverFd.get(), 1 /*backlog*/))) { + int savedErrno = errno; + ALOGE("Could not listen socket at %s: %s", addr.toString().c_str(), strerror(savedErrno)); + return false; + } + + mServer = std::move(serverFd); + return true; +} + +bool RpcConnection::addClient(const SocketAddress& addr) { + unique_fd serverFd( + TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0))); + if (serverFd == -1) { + int savedErrno = errno; + ALOGE("Could not create socket at %s: %s", addr.toString().c_str(), strerror(savedErrno)); + return false; + } + + if (0 != TEMP_FAILURE_RETRY(connect(serverFd.get(), addr.addr(), addr.addrSize()))) { + int savedErrno = errno; + ALOGE("Could not connect socket at %s: %s", addr.toString().c_str(), strerror(savedErrno)); + return false; + } + + LOG_RPC_DETAIL("Socket at %s client with fd %d", addr.toString().c_str(), serverFd.get()); + std::lock_guard<std::mutex> _l(mSocketMutex); sp<ConnectionSocket> connection = new ConnectionSocket(); - connection->fd = std::move(fd); + connection->fd = std::move(serverFd); mClients.push_back(connection); + return true; } -void RpcConnection::addServer(base::unique_fd&& fd) { +void RpcConnection::assignServerToThisThread(base::unique_fd&& fd) { std::lock_guard<std::mutex> _l(mSocketMutex); sp<ConnectionSocket> connection = new ConnectionSocket(); connection->fd = std::move(fd); diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp index 64e842e927..755ff35781 100644 --- a/libs/binder/RpcState.cpp +++ b/libs/binder/RpcState.cpp @@ -192,7 +192,7 @@ bool RpcState::rpcSend(const base::unique_fd& fd, const char* what, const void* return false; } - ssize_t sent = TEMP_FAILURE_RETRY(send(fd.get(), data, size, 0)); + ssize_t sent = TEMP_FAILURE_RETRY(send(fd.get(), data, size, MSG_NOSIGNAL)); if (sent < 0 || sent != static_cast<ssize_t>(size)) { ALOGE("Failed to send %s (sent %zd of %zu bytes) on fd %d, error: %s", what, sent, size, @@ -212,7 +212,7 @@ bool RpcState::rpcRec(const base::unique_fd& fd, const char* what, void* data, s return false; } - ssize_t recd = TEMP_FAILURE_RETRY(recv(fd.get(), data, size, MSG_WAITALL)); + ssize_t recd = TEMP_FAILURE_RETRY(recv(fd.get(), data, size, MSG_WAITALL | MSG_NOSIGNAL)); if (recd < 0 || recd != static_cast<ssize_t>(size)) { terminate(); @@ -312,8 +312,8 @@ status_t RpcState::transact(const base::unique_fd& fd, const RpcAddress& address return waitForReply(fd, connection, reply); } -static void cleanup_data(Parcel* p, const uint8_t* data, size_t dataSize, - const binder_size_t* objects, size_t objectsCount) { +static void cleanup_reply_data(Parcel* p, const uint8_t* data, size_t dataSize, + const binder_size_t* objects, size_t objectsCount) { (void)p; delete[] const_cast<uint8_t*>(data - offsetof(RpcWireReply, data)); (void)dataSize; @@ -351,7 +351,7 @@ status_t RpcState::waitForReply(const base::unique_fd& fd, const sp<RpcConnectio if (rpcReply->status != OK) return rpcReply->status; reply->ipcSetDataReference(rpcReply->data, command.bodySize - offsetof(RpcWireReply, data), - nullptr, 0, cleanup_data); + nullptr, 0, cleanup_reply_data); reply->markForRpc(connection); @@ -427,6 +427,15 @@ status_t RpcState::processTransact(const base::unique_fd& fd, const sp<RpcConnec return processTransactInternal(fd, connection, std::move(transactionData)); } +static void do_nothing_to_transact_data(Parcel* p, const uint8_t* data, size_t dataSize, + const binder_size_t* objects, size_t objectsCount) { + (void)p; + (void)data; + (void)dataSize; + (void)objects; + (void)objectsCount; +} + status_t RpcState::processTransactInternal(const base::unique_fd& fd, const sp<RpcConnection>& connection, std::vector<uint8_t>&& transactionData) { @@ -490,7 +499,12 @@ status_t RpcState::processTransactInternal(const base::unique_fd& fd, } Parcel data; - data.setData(transaction->data, transactionData.size() - offsetof(RpcWireTransaction, data)); + // transaction->data is owned by this function. Parcel borrows this data and + // only holds onto it for the duration of this function call. Parcel will be + // deleted before the 'transactionData' object. + data.ipcSetDataReference(transaction->data, + transactionData.size() - offsetof(RpcWireTransaction, data), + nullptr /*object*/, 0 /*objectCount*/, do_nothing_to_transact_data); data.markForRpc(connection); Parcel reply; diff --git a/libs/binder/Stability.cpp b/libs/binder/Stability.cpp index c3f1ba7b4d..f12ef4e35b 100644 --- a/libs/binder/Stability.cpp +++ b/libs/binder/Stability.cpp @@ -38,18 +38,30 @@ Stability::Category Stability::Category::currentFromLevel(Level level) { }; } -void Stability::forceDowngradeCompilationUnit(const sp<IBinder>& binder) { +void Stability::forceDowngradeToStability(const sp<IBinder>& binder, Level level) { // Downgrading a remote binder would require also copying the version from // the binder sent here. In practice though, we don't need to downgrade the // stability of a remote binder, since this would as an effect only restrict // what we can do to it. LOG_ALWAYS_FATAL_IF(!binder || !binder->localBinder(), "Can only downgrade local binder"); - auto stability = Category::currentFromLevel(getLocalLevel()); + auto stability = Category::currentFromLevel(level); status_t result = setRepr(binder.get(), stability.repr(), REPR_LOG | REPR_ALLOW_DOWNGRADE); LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object."); } +void Stability::forceDowngradeToLocalStability(const sp<IBinder>& binder) { + forceDowngradeToStability(binder, getLocalLevel()); +} + +void Stability::forceDowngradeToSystemStability(const sp<IBinder>& binder) { + forceDowngradeToStability(binder, Level::SYSTEM); +} + +void Stability::forceDowngradeToVendorStability(const sp<IBinder>& binder) { + forceDowngradeToStability(binder, Level::VENDOR); +} + std::string Stability::Category::debugString() { return levelString(level) + " wire protocol version " + std::to_string(version); diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h index eac1bb2c01..c048cbed37 100644 --- a/libs/binder/include/binder/AppOpsManager.h +++ b/libs/binder/include/binder/AppOpsManager.h @@ -143,7 +143,10 @@ public: OP_COARSE_LOCATION_SOURCE = 109, OP_MANAGE_MEDIA = 110, OP_BLUETOOTH_CONNECT = 111, - _NUM_OP = 112 + OP_UWB_RANGING = 112, + OP_ACTIVITY_RECOGNITION_SOURCE = 113, + OP_BLUETOOTH_ADVERTISE = 114, + _NUM_OP = 115 }; AppOpsManager(); diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h index f930d2905e..b86fc0b629 100644 --- a/libs/binder/include/binder/IInterface.h +++ b/libs/binder/include/binder/IInterface.h @@ -186,7 +186,7 @@ template<typename INTERFACE> inline sp<IInterface> BnInterface<INTERFACE>::queryLocalInterface( const String16& _descriptor) { - if (_descriptor == INTERFACE::descriptor) return this; + if (_descriptor == INTERFACE::descriptor) return sp<IInterface>::fromExisting(this); return nullptr; } diff --git a/libs/binder/include/binder/IMediaResourceMonitor.h b/libs/binder/include/binder/IMediaResourceMonitor.h deleted file mode 100644 index f92d557932..0000000000 --- a/libs/binder/include/binder/IMediaResourceMonitor.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#ifndef __ANDROID_VNDK__ - -#include <binder/IInterface.h> - -namespace android { - -// ---------------------------------------------------------------------- - -class IMediaResourceMonitor : public IInterface { -public: - DECLARE_META_INTERFACE(MediaResourceMonitor) - - // Values should be in sync with Intent.EXTRA_MEDIA_RESOURCE_TYPE_XXX. - enum { - TYPE_VIDEO_CODEC = 0, - TYPE_AUDIO_CODEC = 1, - }; - - virtual void notifyResourceGranted(/*in*/ int32_t pid, /*in*/ const int32_t type) = 0; - - enum { - NOTIFY_RESOURCE_GRANTED = IBinder::FIRST_CALL_TRANSACTION, - }; -}; - -// ---------------------------------------------------------------------- - -class BnMediaResourceMonitor : public BnInterface<IMediaResourceMonitor> { -public: - // NOLINTNEXTLINE(google-default-arguments) - virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, - uint32_t flags = 0); -}; - -// ---------------------------------------------------------------------- - -} // namespace android - -#else // __ANDROID_VNDK__ -#error "This header is not visible to vendors" -#endif // __ANDROID_VNDK__ diff --git a/libs/binder/include/binder/IpPrefix.h b/libs/binder/include/binder/IpPrefix.h deleted file mode 100644 index a8faa3fded..0000000000 --- a/libs/binder/include/binder/IpPrefix.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2015 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 - -#ifndef __ANDROID_VNDK__ - -#include <netinet/in.h> - -#include <binder/Parcelable.h> -#include <utils/String16.h> -#include <utils/StrongPointer.h> - -namespace android { - -namespace net { - -/* - * C++ implementation of the Java class android.net.IpPrefix - */ -class IpPrefix : public Parcelable { -public: - IpPrefix() = default; - virtual ~IpPrefix() = default; - IpPrefix(const IpPrefix& prefix) = default; - - IpPrefix(const struct in6_addr& addr, int32_t plen): - mUnion(addr), mPrefixLength(plen), mIsIpv6(true) { } - - IpPrefix(const struct in_addr& addr, int32_t plen): - mUnion(addr), mPrefixLength(plen), mIsIpv6(false) { } - - bool getAddressAsIn6Addr(struct in6_addr* addr) const; - bool getAddressAsInAddr(struct in_addr* addr) const; - - const struct in6_addr& getAddressAsIn6Addr() const; - const struct in_addr& getAddressAsInAddr() const; - - bool isIpv6() const; - bool isIpv4() const; - - int32_t getPrefixLength() const; - - void setAddress(const struct in6_addr& addr); - void setAddress(const struct in_addr& addr); - - void setPrefixLength(int32_t prefix); - - friend bool operator==(const IpPrefix& lhs, const IpPrefix& rhs); - - friend bool operator!=(const IpPrefix& lhs, const IpPrefix& rhs) { - return !(lhs == rhs); - } - -public: - // Overrides - status_t writeToParcel(Parcel* parcel) const override; - status_t readFromParcel(const Parcel* parcel) override; - -private: - union InternalUnion { - InternalUnion() = default; - explicit InternalUnion(const struct in6_addr &addr):mIn6Addr(addr) { } - explicit InternalUnion(const struct in_addr &addr):mInAddr(addr) { } - struct in6_addr mIn6Addr; - struct in_addr mInAddr; - } mUnion; - int32_t mPrefixLength; - bool mIsIpv6; -}; - -} // namespace net - -} // namespace android - -#else // __ANDROID_VNDK__ -#error "This header is not visible to vendors" -#endif // __ANDROID_VNDK__ diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index 957837233b..211790d14c 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -101,10 +101,6 @@ public: // is for an RPC transaction). void markForBinder(const sp<IBinder>& binder); - // Whenever possible, markForBinder should be preferred. This method is - // called automatically on reply Parcels for RPC transactions. - void markForRpc(const sp<RpcConnection>& connection); - // Whether this Parcel is written for RPC transactions (after calls to // markForBinder or markForRpc). bool isForRpc() const; @@ -540,6 +536,10 @@ private: const binder_size_t* objects, size_t objectsCount, release_func relFunc); + // Whenever possible, markForBinder should be preferred. This method is + // called automatically on reply Parcels for RPC transactions. + void markForRpc(const sp<RpcConnection>& connection); + status_t finishWrite(size_t len); void releaseObjects(); void acquireObjects(); diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h index 2405ab6b9e..ca29440e7c 100644 --- a/libs/binder/include/binder/ProcessState.h +++ b/libs/binder/include/binder/ProcessState.h @@ -124,7 +124,6 @@ private: Vector<handle_entry>mHandleToObject; - String8 mRootDir; bool mThreadPoolStarted; volatile int32_t mThreadPoolSeq; diff --git a/libs/binder/include/binder/RpcConnection.h b/libs/binder/include/binder/RpcConnection.h index 65c5232d46..efa922dbda 100644 --- a/libs/binder/include/binder/RpcConnection.h +++ b/libs/binder/include/binder/RpcConnection.h @@ -61,6 +61,18 @@ public: */ [[nodiscard]] bool addUnixDomainClient(const char* path); +#ifdef __BIONIC__ + /** + * Creates an RPC server at the current port. + */ + [[nodiscard]] bool setupVsockServer(unsigned int port); + + /** + * Connects to an RPC server at the CVD & port. + */ + [[nodiscard]] bool addVsockClient(unsigned int cvd, unsigned int port); +#endif // __BIONIC__ + /** * Query the other side of the connection for the root object hosted by that * process's RpcServer (if one exists) @@ -85,11 +97,21 @@ public: // internal only const std::unique_ptr<RpcState>& state() { return mState; } + class SocketAddress { + public: + virtual ~SocketAddress(); + virtual std::string toString() const = 0; + virtual const sockaddr* addr() const = 0; + virtual size_t addrSize() const = 0; + }; + private: + friend sp<RpcConnection>; RpcConnection(); - void addServer(base::unique_fd&& fd); - void addClient(base::unique_fd&& fd); + bool addServer(const SocketAddress& address); + bool addClient(const SocketAddress& address); + void assignServerToThisThread(base::unique_fd&& fd); struct ConnectionSocket : public RefBase { base::unique_fd fd; diff --git a/libs/binder/include/binder/Stability.h b/libs/binder/include/binder/Stability.h index a09e587f04..f4bfac890a 100644 --- a/libs/binder/include/binder/Stability.h +++ b/libs/binder/include/binder/Stability.h @@ -54,12 +54,37 @@ public: // Given a binder interface at a certain stability, there may be some // requirements associated with that higher stability level. For instance, a // VINTF stability binder is required to be in the VINTF manifest. This API - // can be called to use that same interface within a partition. - static void forceDowngradeCompilationUnit(const sp<IBinder>& binder); + // can be called to use that same interface within the local partition. + static void forceDowngradeToLocalStability(const sp<IBinder>& binder); // WARNING: Below APIs are only ever expected to be called by auto-generated code. // Instead of calling them, you should set the stability of a .aidl interface + // WARNING: The only client of + // - forceDowngradeToSystemStability() and; + // - korceDowngradeToVendorStability() + // should be AIBinder_forceDowngradeToLocalStability(). + // + // getLocalLevel() in libbinder returns Level::SYSTEM when called + // from libbinder_ndk (even on vendor partition). So we explicitly provide + // these methods for use by the NDK API: + // AIBinder_forceDowngradeToLocalStability(). + // + // This allows correctly downgrading the binder's stability to either system/vendor, + // depending on the partition. + + // Given a binder interface at a certain stability, there may be some + // requirements associated with that higher stability level. For instance, a + // VINTF stability binder is required to be in the VINTF manifest. This API + // can be called to use that same interface within the vendor partition. + static void forceDowngradeToVendorStability(const sp<IBinder>& binder); + + // Given a binder interface at a certain stability, there may be some + // requirements associated with that higher stability level. For instance, a + // VINTF stability binder is required to be in the VINTF manifest. This API + // can be called to use that same interface within the system partition. + static void forceDowngradeToSystemStability(const sp<IBinder>& binder); + // WARNING: This is only ever expected to be called by auto-generated code. You likely want to // change or modify the stability class of the interface you are using. // This must be called as soon as the binder in question is constructed. No thread safety @@ -146,6 +171,9 @@ private: // returns the stability according to how this was built static Level getLocalLevel(); + // Downgrades binder stability to the specified level. + static void forceDowngradeToStability(const sp<IBinder>& binder, Level level); + enum { REPR_NONE = 0, REPR_LOG = 1, diff --git a/libs/binder/include/binder/ActivityManager.h b/libs/binder/include_activitymanager/binder/ActivityManager.h index 830971b1e6..b772b80227 100644 --- a/libs/binder/include/binder/ActivityManager.h +++ b/libs/binder/include_activitymanager/binder/ActivityManager.h @@ -41,7 +41,11 @@ public: // Flag for registerUidObserver: report uid has become idle UID_OBSERVER_IDLE = 1<<2, // Flag for registerUidObserver: report uid has become active - UID_OBSERVER_ACTIVE = 1<<3 + UID_OBSERVER_ACTIVE = 1<<3, + // Flag for registerUidObserver: report uid cached state has changed + UID_OBSERVER_CACHED = 1<<4, + // Flag for registerUidObserver: report uid capability has changed + UID_OBSERVER_CAPABILITY = 1<<5, }; // PROCESS_STATE_* must come from frameworks/base/core/java/android/app/ProcessStateEnum.aidl. diff --git a/libs/binder/include/binder/IActivityManager.h b/libs/binder/include_activitymanager/binder/IActivityManager.h index 2d58c462c2..4632b2eb0f 100644 --- a/libs/binder/include/binder/IActivityManager.h +++ b/libs/binder/include_activitymanager/binder/IActivityManager.h @@ -18,8 +18,8 @@ #ifndef __ANDROID_VNDK__ -#include <binder/IInterface.h> #include <binder/IUidObserver.h> +#include <binder/IInterface.h> namespace android { diff --git a/libs/binder/include/binder/IUidObserver.h b/libs/binder/include_activitymanager/binder/IUidObserver.h index 9291c0b45f..9291c0b45f 100644 --- a/libs/binder/include/binder/IUidObserver.h +++ b/libs/binder/include_activitymanager/binder/IUidObserver.h diff --git a/libs/binder/include/binder/IProcessInfoService.h b/libs/binder/include_processinfo/processinfo/IProcessInfoService.h index 622f23162f..622f23162f 100644 --- a/libs/binder/include/binder/IProcessInfoService.h +++ b/libs/binder/include_processinfo/processinfo/IProcessInfoService.h diff --git a/libs/binder/include/binder/ProcessInfoService.h b/libs/binder/include_processinfo/processinfo/ProcessInfoService.h index 6b3b5ce4df..978856dc6a 100644 --- a/libs/binder/include/binder/ProcessInfoService.h +++ b/libs/binder/include_processinfo/processinfo/ProcessInfoService.h @@ -18,7 +18,7 @@ #ifndef __ANDROID_VNDK__ -#include <binder/IProcessInfoService.h> +#include <processinfo/IProcessInfoService.h> #include <utils/Errors.h> #include <utils/Singleton.h> #include <sys/types.h> diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp index 3c906819ff..1dcb41be84 100644 --- a/libs/binder/ndk/ibinder.cpp +++ b/libs/binder/ndk/ibinder.cpp @@ -363,7 +363,8 @@ const char* AIBinder_Class_getDescriptor(const AIBinder_Class* clazz) { } void AIBinder_DeathRecipient::TransferDeathRecipient::binderDied(const wp<IBinder>& who) { - CHECK(who == mWho); + CHECK(who == mWho) << who.unsafe_get() << "(" << who.get_refs() << ") vs " << mWho.unsafe_get() + << " (" << mWho.get_refs() << ")"; mOnDied(mCookie); @@ -598,6 +599,8 @@ binder_status_t AIBinder_prepareTransaction(AIBinder* binder, AParcel** in) { } *in = new AParcel(binder); + (*in)->get()->markForBinder(binder->getBinder()); + status_t status = (*in)->get()->writeInterfaceToken(clazz->getInterfaceDescriptor()); binder_status_t ret = PruneStatusT(status); diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h index 8941e4996c..b9adc9a025 100644 --- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h +++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h @@ -36,6 +36,9 @@ __BEGIN_DECLS +/** + * Flags for AIBinder_transact. + */ typedef uint32_t binder_flags_t; enum { /** @@ -47,7 +50,10 @@ enum { FLAG_ONEWAY = 0x01, }; -// Also see IBinder.h in libbinder +/** + * Codes for AIBinder_transact. This defines the range of codes available for + * usage. Other codes are used or reserved by the Android system. + */ typedef uint32_t transaction_code_t; enum { /** @@ -202,7 +208,8 @@ typedef binder_status_t (*AIBinder_onDump)(AIBinder* binder, int fd, const char* * * Available since API level 29. * - * \param dump function to call when an instance of this binder class is being dumped. + * \param clazz class which should use this dump function + * \param onDump function to call when an instance of this binder class is being dumped. */ void AIBinder_Class_setOnDump(AIBinder_Class* clazz, AIBinder_onDump onDump) __INTRODUCED_IN(29); diff --git a/libs/binder/ndk/include_ndk/android/binder_status.h b/libs/binder/ndk/include_ndk/android/binder_status.h index b4dc08a49b..6f1fdfcd20 100644 --- a/libs/binder/ndk/include_ndk/android/binder_status.h +++ b/libs/binder/ndk/include_ndk/android/binder_status.h @@ -189,7 +189,7 @@ __attribute__((warn_unused_result)) AStatus* AStatus_fromServiceSpecificErrorWit * * Available since API level 29. * - * \param a low-level error to associate with this status object. + * \param status a low-level error to associate with this status object. * * \return a newly constructed status object that the caller owns. */ diff --git a/libs/binder/ndk/include_platform/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h index ce7255e174..f113ba8f21 100644 --- a/libs/binder/ndk/include_platform/android/binder_stability.h +++ b/libs/binder/ndk/include_platform/android/binder_stability.h @@ -45,6 +45,18 @@ static inline void AIBinder_markCompilationUnitStability(AIBinder* binder) { AIBinder_markVendorStability(binder); } +/** + * Given a binder interface at a certain stability, there may be some + * requirements associated with that higher stability level. For instance, a + * VINTF stability binder is required to be in the VINTF manifest. This API + * can be called to use that same interface within the vendor partition. + */ +void AIBinder_forceDowngradeToVendorStability(AIBinder* binder); + +static inline void AIBinder_forceDowngradeToLocalStability(AIBinder* binder) { + AIBinder_forceDowngradeToVendorStability(binder); +} + #else // defined(__ANDROID_VENDOR__) enum { @@ -62,9 +74,27 @@ static inline void AIBinder_markCompilationUnitStability(AIBinder* binder) { AIBinder_markSystemStability(binder); } +/** + * Given a binder interface at a certain stability, there may be some + * requirements associated with that higher stability level. For instance, a + * VINTF stability binder is required to be in the VINTF manifest. This API + * can be called to use that same interface within the system partition. + */ +void AIBinder_forceDowngradeToSystemStability(AIBinder* binder); + +static inline void AIBinder_forceDowngradeToLocalStability(AIBinder* binder) { + AIBinder_forceDowngradeToSystemStability(binder); +} + #endif // defined(__ANDROID_VENDOR__) /** + * WARNING: this is not expected to be used manually. When the build system has + * versioned checks in place for an interface that prevent it being changed year + * over year (specifically like those for @VintfStability stable AIDL + * interfaces), this could be called. Calling this without this or equivalent + * infrastructure will lead to de facto frozen APIs or GSI test failures. + * * This interface has system<->vendor stability */ void AIBinder_markVintfStability(AIBinder* binder); diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt index f1db653e07..67c85b66d4 100644 --- a/libs/binder/ndk/libbinder_ndk.map.txt +++ b/libs/binder/ndk/libbinder_ndk.map.txt @@ -127,6 +127,9 @@ LIBBINDER_NDK31 { # introduced=31 AServiceManager_tryUnregister; # llndk AServiceManager_reRegister; # llndk + AIBinder_forceDowngradeToSystemStability; # apex + AIBinder_forceDowngradeToVendorStability; # llndk + AIBinder_Class_getDescriptor; AIBinder_Weak_clone; AIBinder_Weak_lt; diff --git a/libs/binder/ndk/parcel_internal.h b/libs/binder/ndk/parcel_internal.h index 6b7295e4b9..b4f6358841 100644 --- a/libs/binder/ndk/parcel_internal.h +++ b/libs/binder/ndk/parcel_internal.h @@ -27,9 +27,8 @@ struct AParcel { const ::android::Parcel* get() const { return mParcel; } ::android::Parcel* get() { return mParcel; } - explicit AParcel(const AIBinder* binder) - : AParcel(binder, new ::android::Parcel, true /*owns*/) {} - AParcel(const AIBinder* binder, ::android::Parcel* parcel, bool owns) + explicit AParcel(AIBinder* binder) : AParcel(binder, new ::android::Parcel, true /*owns*/) {} + AParcel(AIBinder* binder, ::android::Parcel* parcel, bool owns) : mBinder(binder), mParcel(parcel), mOwns(owns) {} ~AParcel() { @@ -38,7 +37,7 @@ struct AParcel { } } - static const AParcel readOnly(const AIBinder* binder, const ::android::Parcel* parcel) { + static const AParcel readOnly(AIBinder* binder, const ::android::Parcel* parcel) { return AParcel(binder, const_cast<::android::Parcel*>(parcel), false); } diff --git a/libs/binder/ndk/stability.cpp b/libs/binder/ndk/stability.cpp index a5b3ecea4a..7eafb9c025 100644 --- a/libs/binder/ndk/stability.cpp +++ b/libs/binder/ndk/stability.cpp @@ -31,7 +31,7 @@ using ::android::internal::Stability; #error libbinder_ndk should only be built in a system context #endif -// explicit extern because symbol is only declared in header when __ANDROID_VNDK__ +// explicit extern because symbol is only declared in header when __ANDROID_VENDOR__ extern "C" void AIBinder_markVendorStability(AIBinder* binder) { Stability::markVndk(binder->getBinder().get()); } @@ -43,3 +43,12 @@ void AIBinder_markSystemStability(AIBinder* binder) { void AIBinder_markVintfStability(AIBinder* binder) { Stability::markVintf(binder->getBinder().get()); } + +// explicit extern because symbol is only declared in header when __ANDROID_VENDOR__ +extern "C" void AIBinder_forceDowngradeToVendorStability(AIBinder* binder) { + Stability::forceDowngradeToVendorStability(binder->getBinder()); +} + +void AIBinder_forceDowngradeToSystemStability(AIBinder* binder) { + Stability::forceDowngradeToSystemStability(binder->getBinder()); +} diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index a44cddf761..afc4b1b72c 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -104,22 +104,49 @@ cc_test { require_root: true, } +aidl_interface { + name: "binderRpcTestIface", + host_supported: true, + unstable: true, + srcs: [ + "IBinderRpcSession.aidl", + "IBinderRpcTest.aidl", + ], + backend: { + java: { + enabled: false, + }, + }, +} + cc_test { name: "binderRpcTest", - defaults: ["binder_test_defaults"], + host_supported: true, + target: { + darwin: { + enabled: false, + }, + }, + defaults: [ + "binder_test_defaults", + "libbinder_ndk_host_user", + ], srcs: [ - "IBinderRpcSession.aidl", - "IBinderRpcTest.aidl", "binderRpcTest.cpp", ], shared_libs: [ "libbinder", + "libbinder_ndk", "libbase", "libutils", "libcutils", "liblog", ], + static_libs: [ + "binderRpcTestIface-cpp", + "binderRpcTestIface-ndk_platform", + ], test_suites: ["general-tests"], require_root: true, } @@ -210,6 +237,11 @@ aidl_interface { srcs: [ "IBinderStabilityTest.aidl", ], + backend: { + java: { + enabled: false, + }, + }, } cc_test { diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index 6fa53330ef..a51c98774e 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -14,17 +14,12 @@ * limitations under the License. */ -#include <sys/prctl.h> -#include <unistd.h> - -#include <chrono> -#include <cstdlib> -#include <iostream> -#include <thread> - #include <BnBinderRpcSession.h> #include <BnBinderRpcTest.h> +#include <aidl/IBinderRpcTest.h> #include <android-base/logging.h> +#include <android/binder_auto_utils.h> +#include <android/binder_libbinder.h> #include <binder/Binder.h> #include <binder/BpBinder.h> #include <binder/IServiceManager.h> @@ -33,10 +28,29 @@ #include <binder/RpcServer.h> #include <gtest/gtest.h> +#include <chrono> +#include <cstdlib> +#include <iostream> +#include <thread> + +#ifdef __BIONIC__ +#include <linux/vm_sockets.h> +#endif //__BIONIC__ + +#include <sys/prctl.h> +#include <unistd.h> + #include "../RpcState.h" // for debugging namespace android { +TEST(BinderRpcParcel, EntireParcelFormatted) { + Parcel p; + p.writeInt32(3); + + EXPECT_DEATH(p.markForBinder(sp<BBinder>::make()), ""); +} + using android::binder::Status; #define EXPECT_OK(status) \ @@ -185,8 +199,13 @@ private: static std::string allocateSocketAddress() { static size_t id = 0; + static bool gUseTmp = access("/tmp/", F_OK) != -1; - return "/dev/binderRpcTest_" + std::to_string(id++); + if (gUseTmp) { + return "/tmp/binderRpcTest_" + std::to_string(id++); + } else { + return "/dev/binderRpcTest_" + std::to_string(id++); + } }; struct ProcessConnection { @@ -214,58 +233,6 @@ struct ProcessConnection { } }; -// This creates a new process serving an interface on a certain number of -// threads. -ProcessConnection createRpcTestSocketServerProcess( - size_t numThreads, - const std::function<void(const sp<RpcServer>&, const sp<RpcConnection>&)>& configure) { - CHECK_GT(numThreads, 0); - - std::string addr = allocateSocketAddress(); - unlink(addr.c_str()); - - auto ret = ProcessConnection{ - .host = Process([&] { - sp<RpcServer> server = RpcServer::make(); - - server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction(); - - // server supporting one client on one socket - sp<RpcConnection> connection = server->addClientConnection(); - CHECK(connection->setupUnixDomainServer(addr.c_str())) << addr; - - configure(server, connection); - - // accept 'numThreads' connections - std::vector<std::thread> pool; - for (size_t i = 0; i + 1 < numThreads; i++) { - pool.push_back(std::thread([=] { connection->join(); })); - } - connection->join(); - for (auto& t : pool) t.join(); - }), - .connection = RpcConnection::make(), - }; - - // wait up to 1s for sockets to be created - constexpr useconds_t kMaxWaitUs = 1000000; - constexpr useconds_t kWaitDivision = 100; - for (size_t i = 0; i < kWaitDivision && 0 != access(addr.c_str(), F_OK); i++) { - usleep(kMaxWaitUs / kWaitDivision); - } - - // create remainder of connections - for (size_t i = 0; i < numThreads; i++) { - // Connection refused sometimes after file created but before listening. - CHECK(ret.connection->addUnixDomainClient(addr.c_str()) || - (usleep(10000), ret.connection->addUnixDomainClient(addr.c_str()))) - << i; - } - - ret.rootBinder = ret.connection->getRootObject(); - return ret; -} - // Process connection where the process hosts IBinderRpcTest, the server used // for most testing here struct BinderRpcTestProcessConnection { @@ -290,26 +257,122 @@ struct BinderRpcTestProcessConnection { } }; -BinderRpcTestProcessConnection createRpcTestSocketServerProcess(size_t numThreads) { - BinderRpcTestProcessConnection ret{ - .proc = createRpcTestSocketServerProcess(numThreads, - [&](const sp<RpcServer>& server, - const sp<RpcConnection>& connection) { - sp<MyBinderRpcTest> service = - new MyBinderRpcTest; - server->setRootObject(service); - service->connection = - connection; // for testing only - }), - }; - - ret.rootBinder = ret.proc.rootBinder; - ret.rootIface = interface_cast<IBinderRpcTest>(ret.rootBinder); +enum class SocketType { + UNIX, +#ifdef __BIONIC__ + VSOCK, +#endif // __BIONIC__ +}; +static inline std::string PrintSocketType(const testing::TestParamInfo<SocketType>& info) { + switch (info.param) { + case SocketType::UNIX: + return "unix_domain_socket"; +#ifdef __BIONIC__ + case SocketType::VSOCK: + return "vm_socket"; +#endif // __BIONIC__ + default: + LOG_ALWAYS_FATAL("Unknown socket type"); + return ""; + } +} +class BinderRpc : public ::testing::TestWithParam<SocketType> { +public: + // This creates a new process serving an interface on a certain number of + // threads. + ProcessConnection createRpcTestSocketServerProcess( + size_t numThreads, + const std::function<void(const sp<RpcServer>&, const sp<RpcConnection>&)>& configure) { + CHECK_GT(numThreads, 0); + + SocketType socketType = GetParam(); + + std::string addr = allocateSocketAddress(); + unlink(addr.c_str()); + static unsigned int port = 3456; + port++; + + auto ret = ProcessConnection{ + .host = Process([&] { + sp<RpcServer> server = RpcServer::make(); + + server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction(); + + // server supporting one client on one socket + sp<RpcConnection> connection = server->addClientConnection(); + + switch (socketType) { + case SocketType::UNIX: + CHECK(connection->setupUnixDomainServer(addr.c_str())) << addr; + break; +#ifdef __BIONIC__ + case SocketType::VSOCK: + CHECK(connection->setupVsockServer(port)); + break; +#endif // __BIONIC__ + default: + LOG_ALWAYS_FATAL("Unknown socket type"); + } + + configure(server, connection); + + // accept 'numThreads' connections + std::vector<std::thread> pool; + for (size_t i = 0; i + 1 < numThreads; i++) { + pool.push_back(std::thread([=] { connection->join(); })); + } + connection->join(); + for (auto& t : pool) t.join(); + }), + .connection = RpcConnection::make(), + }; + + // create remainder of connections + for (size_t i = 0; i < numThreads; i++) { + for (size_t tries = 0; tries < 5; tries++) { + usleep(10000); + switch (socketType) { + case SocketType::UNIX: + if (ret.connection->addUnixDomainClient(addr.c_str())) goto success; + break; +#ifdef __BIONIC__ + case SocketType::VSOCK: + if (ret.connection->addVsockClient(VMADDR_CID_LOCAL, port)) goto success; + break; +#endif // __BIONIC__ + default: + LOG_ALWAYS_FATAL("Unknown socket type"); + } + } + LOG_ALWAYS_FATAL("Could not connect"); + success:; + } - return ret; -} + ret.rootBinder = ret.connection->getRootObject(); + return ret; + } + + BinderRpcTestProcessConnection createRpcTestSocketServerProcess(size_t numThreads) { + BinderRpcTestProcessConnection ret{ + .proc = createRpcTestSocketServerProcess(numThreads, + [&](const sp<RpcServer>& server, + const sp<RpcConnection>& connection) { + sp<MyBinderRpcTest> service = + new MyBinderRpcTest; + server->setRootObject(service); + service->connection = + connection; // for testing only + }), + }; + + ret.rootBinder = ret.proc.rootBinder; + ret.rootIface = interface_cast<IBinderRpcTest>(ret.rootBinder); + + return ret; + } +}; -TEST(BinderRpc, RootObjectIsNull) { +TEST_P(BinderRpc, RootObjectIsNull) { auto proc = createRpcTestSocketServerProcess(1, [](const sp<RpcServer>& server, const sp<RpcConnection>&) { @@ -324,20 +387,39 @@ TEST(BinderRpc, RootObjectIsNull) { EXPECT_EQ(nullptr, proc.connection->getRootObject()); } -TEST(BinderRpc, Ping) { +TEST_P(BinderRpc, Ping) { auto proc = createRpcTestSocketServerProcess(1); ASSERT_NE(proc.rootBinder, nullptr); EXPECT_EQ(OK, proc.rootBinder->pingBinder()); } -TEST(BinderRpc, TransactionsMustBeMarkedRpc) { +TEST_P(BinderRpc, GetInterfaceDescriptor) { + auto proc = createRpcTestSocketServerProcess(1); + ASSERT_NE(proc.rootBinder, nullptr); + EXPECT_EQ(IBinderRpcTest::descriptor, proc.rootBinder->getInterfaceDescriptor()); +} + +TEST_P(BinderRpc, TransactionsMustBeMarkedRpc) { auto proc = createRpcTestSocketServerProcess(1); Parcel data; Parcel reply; EXPECT_EQ(BAD_TYPE, proc.rootBinder->transact(IBinder::PING_TRANSACTION, data, &reply, 0)); } -TEST(BinderRpc, UnknownTransaction) { +TEST_P(BinderRpc, AppendSeparateFormats) { + auto proc = createRpcTestSocketServerProcess(1); + + Parcel p1; + p1.markForBinder(proc.rootBinder); + p1.writeInt32(3); + + Parcel p2; + + EXPECT_EQ(BAD_TYPE, p1.appendFrom(&p2, 0, p2.dataSize())); + EXPECT_EQ(BAD_TYPE, p2.appendFrom(&p1, 0, p1.dataSize())); +} + +TEST_P(BinderRpc, UnknownTransaction) { auto proc = createRpcTestSocketServerProcess(1); Parcel data; data.markForBinder(proc.rootBinder); @@ -345,19 +427,19 @@ TEST(BinderRpc, UnknownTransaction) { EXPECT_EQ(UNKNOWN_TRANSACTION, proc.rootBinder->transact(1337, data, &reply, 0)); } -TEST(BinderRpc, SendSomethingOneway) { +TEST_P(BinderRpc, SendSomethingOneway) { auto proc = createRpcTestSocketServerProcess(1); EXPECT_OK(proc.rootIface->sendString("asdf")); } -TEST(BinderRpc, SendAndGetResultBack) { +TEST_P(BinderRpc, SendAndGetResultBack) { auto proc = createRpcTestSocketServerProcess(1); std::string doubled; EXPECT_OK(proc.rootIface->doubleString("cool ", &doubled)); EXPECT_EQ("cool cool ", doubled); } -TEST(BinderRpc, SendAndGetResultBackBig) { +TEST_P(BinderRpc, SendAndGetResultBackBig) { auto proc = createRpcTestSocketServerProcess(1); std::string single = std::string(1024, 'a'); std::string doubled; @@ -365,7 +447,7 @@ TEST(BinderRpc, SendAndGetResultBackBig) { EXPECT_EQ(single + single, doubled); } -TEST(BinderRpc, CallMeBack) { +TEST_P(BinderRpc, CallMeBack) { auto proc = createRpcTestSocketServerProcess(1); int32_t pingResult; @@ -375,7 +457,7 @@ TEST(BinderRpc, CallMeBack) { EXPECT_EQ(0, MyBinderRpcSession::gNum); } -TEST(BinderRpc, RepeatBinder) { +TEST_P(BinderRpc, RepeatBinder) { auto proc = createRpcTestSocketServerProcess(1); sp<IBinder> inBinder = new MyBinderRpcSession("foo"); @@ -397,7 +479,7 @@ TEST(BinderRpc, RepeatBinder) { EXPECT_EQ(0, MyBinderRpcSession::gNum); } -TEST(BinderRpc, RepeatTheirBinder) { +TEST_P(BinderRpc, RepeatTheirBinder) { auto proc = createRpcTestSocketServerProcess(1); sp<IBinderRpcSession> session; @@ -421,7 +503,7 @@ TEST(BinderRpc, RepeatTheirBinder) { EXPECT_EQ(nullptr, weak.promote()); } -TEST(BinderRpc, RepeatBinderNull) { +TEST_P(BinderRpc, RepeatBinderNull) { auto proc = createRpcTestSocketServerProcess(1); sp<IBinder> outBinder; @@ -429,7 +511,7 @@ TEST(BinderRpc, RepeatBinderNull) { EXPECT_EQ(nullptr, outBinder); } -TEST(BinderRpc, HoldBinder) { +TEST_P(BinderRpc, HoldBinder) { auto proc = createRpcTestSocketServerProcess(1); IBinder* ptr = nullptr; @@ -455,7 +537,7 @@ TEST(BinderRpc, HoldBinder) { // These are behavioral differences form regular binder, where certain usecases // aren't supported. -TEST(BinderRpc, CannotMixBindersBetweenUnrelatedSocketConnections) { +TEST_P(BinderRpc, CannotMixBindersBetweenUnrelatedSocketConnections) { auto proc1 = createRpcTestSocketServerProcess(1); auto proc2 = createRpcTestSocketServerProcess(1); @@ -464,7 +546,7 @@ TEST(BinderRpc, CannotMixBindersBetweenUnrelatedSocketConnections) { proc1.rootIface->repeatBinder(proc2.rootBinder, &outBinder).transactionError()); } -TEST(BinderRpc, CannotSendRegularBinderOverSocketBinder) { +TEST_P(BinderRpc, CannotSendRegularBinderOverSocketBinder) { auto proc = createRpcTestSocketServerProcess(1); sp<IBinder> someRealBinder = IInterface::asBinder(defaultServiceManager()); @@ -473,7 +555,7 @@ TEST(BinderRpc, CannotSendRegularBinderOverSocketBinder) { proc.rootIface->repeatBinder(someRealBinder, &outBinder).transactionError()); } -TEST(BinderRpc, CannotSendSocketBinderOverRegularBinder) { +TEST_P(BinderRpc, CannotSendSocketBinderOverRegularBinder) { auto proc = createRpcTestSocketServerProcess(1); // for historical reasons, IServiceManager interface only returns the @@ -484,7 +566,7 @@ TEST(BinderRpc, CannotSendSocketBinderOverRegularBinder) { // END TESTS FOR LIMITATIONS OF SOCKET BINDER -TEST(BinderRpc, RepeatRootObject) { +TEST_P(BinderRpc, RepeatRootObject) { auto proc = createRpcTestSocketServerProcess(1); sp<IBinder> outBinder; @@ -492,7 +574,7 @@ TEST(BinderRpc, RepeatRootObject) { EXPECT_EQ(proc.rootBinder, outBinder); } -TEST(BinderRpc, NestedTransactions) { +TEST_P(BinderRpc, NestedTransactions) { auto proc = createRpcTestSocketServerProcess(1); auto nastyNester = sp<MyBinderRpcTest>::make(); @@ -503,7 +585,7 @@ TEST(BinderRpc, NestedTransactions) { EXPECT_EQ(nullptr, weak.promote()); } -TEST(BinderRpc, SameBinderEquality) { +TEST_P(BinderRpc, SameBinderEquality) { auto proc = createRpcTestSocketServerProcess(1); sp<IBinder> a; @@ -515,7 +597,7 @@ TEST(BinderRpc, SameBinderEquality) { EXPECT_EQ(a, b); } -TEST(BinderRpc, SameBinderEqualityWeak) { +TEST_P(BinderRpc, SameBinderEqualityWeak) { auto proc = createRpcTestSocketServerProcess(1); sp<IBinder> a; @@ -547,7 +629,7 @@ TEST(BinderRpc, SameBinderEqualityWeak) { EXPECT_EQ(expected, session); \ } while (false) -TEST(BinderRpc, SingleSession) { +TEST_P(BinderRpc, SingleSession) { auto proc = createRpcTestSocketServerProcess(1); sp<IBinderRpcSession> session; @@ -561,7 +643,7 @@ TEST(BinderRpc, SingleSession) { expectSessions(0, proc.rootIface); } -TEST(BinderRpc, ManySessions) { +TEST_P(BinderRpc, ManySessions) { auto proc = createRpcTestSocketServerProcess(1); std::vector<sp<IBinderRpcSession>> sessions; @@ -595,7 +677,7 @@ size_t epochMillis() { return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count(); } -TEST(BinderRpc, ThreadPoolGreaterThanEqualRequested) { +TEST_P(BinderRpc, ThreadPoolGreaterThanEqualRequested) { constexpr size_t kNumThreads = 10; auto proc = createRpcTestSocketServerProcess(kNumThreads); @@ -627,7 +709,7 @@ TEST(BinderRpc, ThreadPoolGreaterThanEqualRequested) { for (auto& t : ts) t.join(); } -TEST(BinderRpc, ThreadPoolOverSaturated) { +TEST_P(BinderRpc, ThreadPoolOverSaturated) { constexpr size_t kNumThreads = 10; constexpr size_t kNumCalls = kNumThreads + 3; constexpr size_t kSleepMs = 500; @@ -651,7 +733,7 @@ TEST(BinderRpc, ThreadPoolOverSaturated) { EXPECT_LE(epochMsAfter, epochMsBefore + 3 * kSleepMs); } -TEST(BinderRpc, ThreadingStressTest) { +TEST_P(BinderRpc, ThreadingStressTest) { constexpr size_t kNumClientThreads = 10; constexpr size_t kNumServerThreads = 10; constexpr size_t kNumCalls = 100; @@ -672,7 +754,7 @@ TEST(BinderRpc, ThreadingStressTest) { for (auto& t : threads) t.join(); } -TEST(BinderRpc, OnewayCallDoesNotWait) { +TEST_P(BinderRpc, OnewayCallDoesNotWait) { constexpr size_t kReallyLongTimeMs = 100; constexpr size_t kSleepMs = kReallyLongTimeMs * 5; @@ -687,7 +769,7 @@ TEST(BinderRpc, OnewayCallDoesNotWait) { EXPECT_LT(epochMsAfter, epochMsBefore + kReallyLongTimeMs); } -TEST(BinderRpc, OnewayCallQueueing) { +TEST_P(BinderRpc, OnewayCallQueueing) { constexpr size_t kNumSleeps = 10; constexpr size_t kNumExtraServerThreads = 4; constexpr size_t kSleepMs = 50; @@ -711,10 +793,7 @@ TEST(BinderRpc, OnewayCallQueueing) { EXPECT_GT(epochMsAfter, epochMsBefore + kSleepMs * kNumSleeps); } -TEST(BinderRpc, Die) { - // TODO(b/183141167): handle this in library - signal(SIGPIPE, SIG_IGN); - +TEST_P(BinderRpc, Die) { for (bool doDeathCleanup : {true, false}) { auto proc = createRpcTestSocketServerProcess(1); @@ -733,6 +812,30 @@ TEST(BinderRpc, Die) { } } +TEST_P(BinderRpc, WorksWithLibbinderNdkPing) { + auto proc = createRpcTestSocketServerProcess(1); + + ndk::SpAIBinder binder = ndk::SpAIBinder(AIBinder_fromPlatformBinder(proc.rootBinder)); + ASSERT_NE(binder, nullptr); + + ASSERT_EQ(STATUS_OK, AIBinder_ping(binder.get())); +} + +TEST_P(BinderRpc, WorksWithLibbinderNdkUserTransaction) { + auto proc = createRpcTestSocketServerProcess(1); + + ndk::SpAIBinder binder = ndk::SpAIBinder(AIBinder_fromPlatformBinder(proc.rootBinder)); + ASSERT_NE(binder, nullptr); + + auto ndkBinder = aidl::IBinderRpcTest::fromBinder(binder); + ASSERT_NE(ndkBinder, nullptr); + + std::string out; + ndk::ScopedAStatus status = ndkBinder->doubleString("aoeu", &out); + ASSERT_TRUE(status.isOk()) << status.getDescription(); + ASSERT_EQ("aoeuaoeu", out); +} + ssize_t countFds() { DIR* dir = opendir("/proc/self/fd/"); if (dir == nullptr) return -1; @@ -743,7 +846,7 @@ ssize_t countFds() { return ret; } -TEST(BinderRpc, Fds) { +TEST_P(BinderRpc, Fds) { ssize_t beforeFds = countFds(); ASSERT_GE(beforeFds, 0); { @@ -753,10 +856,19 @@ TEST(BinderRpc, Fds) { ASSERT_EQ(beforeFds, countFds()) << (system("ls -l /proc/self/fd/"), "fd leak?"); } -extern "C" int main(int argc, char** argv) { +INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc, + ::testing::Values(SocketType::UNIX +#ifdef __BIONIC__ + , + SocketType::VSOCK +#endif // __BIONIC__ + ), + PrintSocketType); + +} // namespace android + +int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); android::base::InitLogging(argv, android::base::StderrLogger, android::base::DefaultAborter); return RUN_ALL_TESTS(); } - -} // namespace android diff --git a/libs/binder/tests/binderStabilityTest.cpp b/libs/binder/tests/binderStabilityTest.cpp index 42705401da..cb309bdd81 100644 --- a/libs/binder/tests/binderStabilityTest.cpp +++ b/libs/binder/tests/binderStabilityTest.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include <android/binder_libbinder.h> #include <android/binder_manager.h> #include <android/binder_stability.h> #include <binder/Binder.h> @@ -131,17 +132,55 @@ TEST(BinderStability, OnlyVintfStabilityBinderNeedsVintfDeclaration) { EXPECT_TRUE(Stability::requiresVintfDeclaration(BadStableBinder::vintf())); } -TEST(BinderStability, ForceDowngradeStability) { +TEST(BinderStability, ForceDowngradeToLocalStability) { sp<IBinder> someBinder = BadStableBinder::vintf(); EXPECT_TRUE(Stability::requiresVintfDeclaration(someBinder)); // silly to do this after already using the binder, but it's for the test - Stability::forceDowngradeCompilationUnit(someBinder); + Stability::forceDowngradeToLocalStability(someBinder); EXPECT_FALSE(Stability::requiresVintfDeclaration(someBinder)); } +TEST(BinderStability, NdkForceDowngradeToLocalStability) { + sp<IBinder> someBinder = BadStableBinder::vintf(); + + EXPECT_TRUE(Stability::requiresVintfDeclaration(someBinder)); + + // silly to do this after already using the binder, but it's for the test + AIBinder_forceDowngradeToLocalStability(AIBinder_fromPlatformBinder(someBinder)); + + EXPECT_FALSE(Stability::requiresVintfDeclaration(someBinder)); +} + +TEST(BinderStability, ForceDowngradeToVendorStability) { + sp<IBinder> serverBinder = android::defaultServiceManager()->getService(kSystemStabilityServer); + auto server = interface_cast<IBinderStabilityTest>(serverBinder); + + ASSERT_NE(nullptr, server.get()); + ASSERT_NE(nullptr, IInterface::asBinder(server)->remoteBinder()); + + { + sp<BadStableBinder> binder = BadStableBinder::vintf(); + + EXPECT_TRUE(Stability::requiresVintfDeclaration(binder)); + EXPECT_TRUE(server->sendAndCallBinder(binder).isOk()); + EXPECT_TRUE(binder->gotUserTransaction); + } + { + sp<BadStableBinder> binder = BadStableBinder::vintf(); + + // This method should never be called directly. This is done only for the test. + Stability::forceDowngradeToVendorStability(binder); + + // Binder downgraded to vendor stability, cannot be called from system context + EXPECT_FALSE(Stability::requiresVintfDeclaration(binder)); + EXPECT_EQ(BAD_TYPE, server->sendAndCallBinder(binder).exceptionCode()); + EXPECT_FALSE(binder->gotUserTransaction); + } +} + TEST(BinderStability, VintfStabilityServerMustBeDeclaredInManifest) { sp<IBinder> vintfServer = BadStableBinder::vintf(); diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index c1e3385a7f..454aa9eb7b 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -982,6 +982,34 @@ public: return NO_ERROR; } + status_t addHdrLayerInfoListener(const sp<IBinder>& displayToken, + const sp<gui::IHdrLayerInfoListener>& listener) override { + Parcel data, reply; + SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); + SAFE_PARCEL(data.writeStrongBinder, displayToken); + SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener)); + const status_t error = + remote()->transact(BnSurfaceComposer::ADD_HDR_LAYER_INFO_LISTENER, data, &reply); + if (error != OK) { + ALOGE("addHdrLayerInfoListener: Failed to transact; error = %d", error); + } + return error; + } + + status_t removeHdrLayerInfoListener(const sp<IBinder>& displayToken, + const sp<gui::IHdrLayerInfoListener>& listener) override { + Parcel data, reply; + SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); + SAFE_PARCEL(data.writeStrongBinder, displayToken); + SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener)); + const status_t error = + remote()->transact(BnSurfaceComposer::REMOVE_HDR_LAYER_INFO_LISTENER, data, &reply); + if (error != OK) { + ALOGE("removeHdrLayerInfoListener: Failed to transact; error = %d", error); + } + return error; + } + status_t notifyPowerBoost(int32_t boostId) override { Parcel data, reply; status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); @@ -1838,6 +1866,38 @@ status_t BnSurfaceComposer::onTransact( } return setDisplayBrightness(displayToken, brightness); } + case ADD_HDR_LAYER_INFO_LISTENER: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp<IBinder> displayToken; + status_t error = data.readNullableStrongBinder(&displayToken); + if (error != NO_ERROR) { + ALOGE("addHdrLayerInfoListener: Failed to read display token"); + return error; + } + sp<gui::IHdrLayerInfoListener> listener; + error = data.readNullableStrongBinder(&listener); + if (error != NO_ERROR) { + ALOGE("addHdrLayerInfoListener: Failed to read listener"); + return error; + } + return addHdrLayerInfoListener(displayToken, listener); + } + case REMOVE_HDR_LAYER_INFO_LISTENER: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp<IBinder> displayToken; + status_t error = data.readNullableStrongBinder(&displayToken); + if (error != NO_ERROR) { + ALOGE("removeHdrLayerInfoListener: Failed to read display token"); + return error; + } + sp<gui::IHdrLayerInfoListener> listener; + error = data.readNullableStrongBinder(&listener); + if (error != NO_ERROR) { + ALOGE("removeHdrLayerInfoListener: Failed to read listener"); + return error; + } + return removeHdrLayerInfoListener(displayToken, listener); + } case NOTIFY_POWER_BOOST: { CHECK_INTERFACE(ISurfaceComposer, data, reply); int32_t boostId; diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 2a9a97ed13..5b213ad5c3 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -430,10 +430,6 @@ void layer_state_t::merge(const layer_state_t& other) { barrierSurfaceControl_legacy = other.barrierSurfaceControl_legacy; barrierFrameNumber = other.barrierFrameNumber; } - if (other.what & eReparentChildren) { - what |= eReparentChildren; - reparentSurfaceControl = other.reparentSurfaceControl; - } if (other.what & eRelativeLayerChanged) { what |= eRelativeLayerChanged; what &= ~eLayerChanged; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index cb8028b6f5..e01a5aee32 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1157,20 +1157,6 @@ SurfaceComposerClient::Transaction::deferTransactionUntil_legacy( return *this; } -SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparentChildren( - const sp<SurfaceControl>& sc, const sp<SurfaceControl>& newParent) { - layer_state_t* s = getLayerState(sc); - if (!s) { - mStatus = BAD_INDEX; - return *this; - } - s->what |= layer_state_t::eReparentChildren; - s->reparentSurfaceControl = newParent; - - registerSurfaceControlForCallback(sc); - return *this; -} - SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparent( const sp<SurfaceControl>& sc, const sp<SurfaceControl>& newParent) { layer_state_t* s = getLayerState(sc); @@ -2054,6 +2040,17 @@ status_t SurfaceComposerClient::setDisplayBrightness(const sp<IBinder>& displayT return ComposerService::getComposerService()->setDisplayBrightness(displayToken, brightness); } +status_t SurfaceComposerClient::addHdrLayerInfoListener( + const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) { + return ComposerService::getComposerService()->addHdrLayerInfoListener(displayToken, listener); +} + +status_t SurfaceComposerClient::removeHdrLayerInfoListener( + const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) { + return ComposerService::getComposerService()->removeHdrLayerInfoListener(displayToken, + listener); +} + status_t SurfaceComposerClient::notifyPowerBoost(int32_t boostId) { return ComposerService::getComposerService()->notifyPowerBoost(boostId); } diff --git a/libs/gui/aidl/android/gui/IHdrLayerInfoListener.aidl b/libs/gui/aidl/android/gui/IHdrLayerInfoListener.aidl new file mode 100644 index 0000000000..fc809c4c88 --- /dev/null +++ b/libs/gui/aidl/android/gui/IHdrLayerInfoListener.aidl @@ -0,0 +1,25 @@ +/* + * Copyright 2021 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.gui; + +/** @hide */ +oneway interface IHdrLayerInfoListener { + // Callback with the total number of HDR layers, the dimensions of the largest layer, + // and a placeholder flags + // TODO (b/182312559): Define the flags (likely need an indicator that a UDFPS layer is present) + void onHdrLayerInfoChanged(int numberOfHdrLayers, int maxW, int maxH, int flags); +}
\ No newline at end of file diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index d933514a38..ccd6d4e754 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -18,6 +18,7 @@ #include <android/gui/DisplayBrightness.h> #include <android/gui/IFpsListener.h> +#include <android/gui/IHdrLayerInfoListener.h> #include <android/gui/IScreenCaptureListener.h> #include <android/gui/ITransactionTraceListener.h> #include <binder/IBinder.h> @@ -431,6 +432,25 @@ public: const gui::DisplayBrightness& brightness) = 0; /* + * Adds a listener that receives HDR layer information. This is used in combination + * with setDisplayBrightness to adjust the display brightness depending on factors such + * as whether or not HDR is in use. + * + * Returns NO_ERROR upon success or NAME_NOT_FOUND if the display is invalid. + */ + virtual status_t addHdrLayerInfoListener(const sp<IBinder>& displayToken, + const sp<gui::IHdrLayerInfoListener>& listener) = 0; + /* + * Removes a listener that was added with addHdrLayerInfoListener. + * + * Returns NO_ERROR upon success, NAME_NOT_FOUND if the display is invalid, and BAD_VALUE if + * the listener wasn't registered. + * + */ + virtual status_t removeHdrLayerInfoListener(const sp<IBinder>& displayToken, + const sp<gui::IHdrLayerInfoListener>& listener) = 0; + + /* * Sends a power boost to the composer. This function is asynchronous. * * boostId @@ -578,6 +598,8 @@ public: ADD_FPS_LISTENER, REMOVE_FPS_LISTENER, OVERRIDE_HDR_TYPES, + ADD_HDR_LAYER_INFO_LISTENER, + REMOVE_HDR_LAYER_INFO_LISTENER, // Always append new enum to the end. }; diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 6c265c898a..65d771053b 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -86,7 +86,6 @@ struct layer_state_t { eDeferTransaction_legacy = 0x00000200, eReleaseBufferListenerChanged = 0x00000400, eShadowRadiusChanged = 0x00000800, - eReparentChildren = 0x00001000, /* was eDetachChildren, now available 0x00002000, */ eRelativeLayerChanged = 0x00004000, eReparent = 0x00008000, diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 35f57a2985..2487961426 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -215,6 +215,11 @@ public: static status_t setDisplayBrightness(const sp<IBinder>& displayToken, const gui::DisplayBrightness& brightness); + static status_t addHdrLayerInfoListener(const sp<IBinder>& displayToken, + const sp<gui::IHdrLayerInfoListener>& listener); + static status_t removeHdrLayerInfoListener(const sp<IBinder>& displayToken, + const sp<gui::IHdrLayerInfoListener>& listener); + /* * Sends a power boost to the composer. This function is asynchronous. * @@ -456,13 +461,7 @@ public: Transaction& deferTransactionUntil_legacy(const sp<SurfaceControl>& sc, const sp<SurfaceControl>& barrierSurfaceControl, uint64_t frameNumber); - // Reparents all children of this layer to the new parent handle. - Transaction& reparentChildren(const sp<SurfaceControl>& sc, - const sp<SurfaceControl>& newParent); - /// Reparents the current layer to the new parent handle. The new parent must not be null. - // This can be used instead of reparentChildren if the caller wants to - // only re-parent a specific child. Transaction& reparent(const sp<SurfaceControl>& sc, const sp<SurfaceControl>& newParent); Transaction& setColor(const sp<SurfaceControl>& sc, const half3& color); diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 59e5c13b0b..49c44a78d1 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -47,6 +47,8 @@ using android::os::IInputFlinger; +using android::hardware::graphics::common::V1_1::BufferUsage; + namespace android::test { using Transaction = SurfaceComposerClient::Transaction; @@ -95,15 +97,6 @@ public: return std::make_unique<InputSurface>(surfaceControl, width, height); } - static std::unique_ptr<InputSurface> makeBlastInputSurface(const sp<SurfaceComposerClient> &scc, - int width, int height) { - sp<SurfaceControl> surfaceControl = - scc->createSurface(String8("Test Buffer Surface"), width, height, - PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceBufferState); - return std::make_unique<InputSurface>(surfaceControl, width, height); - } - static std::unique_ptr<InputSurface> makeContainerInputSurface( const sp<SurfaceComposerClient> &scc, int width, int height) { sp<SurfaceControl> surfaceControl = @@ -180,16 +173,19 @@ public: EXPECT_EQ(flags, mev->getFlags() & flags); } - ~InputSurface() { mInputFlinger->removeInputChannel(mClientChannel->getConnectionToken()); } + virtual ~InputSurface() { + mInputFlinger->removeInputChannel(mClientChannel->getConnectionToken()); + } - void doTransaction(std::function<void(SurfaceComposerClient::Transaction&, - const sp<SurfaceControl>&)> transactionBody) { + virtual void doTransaction( + std::function<void(SurfaceComposerClient::Transaction &, const sp<SurfaceControl> &)> + transactionBody) { SurfaceComposerClient::Transaction t; transactionBody(t, mSurfaceControl); t.apply(true); } - void showAt(int x, int y, Rect crop = Rect(0, 0, 100, 100)) { + virtual void showAt(int x, int y, Rect crop = Rect(0, 0, 100, 100)) { SurfaceComposerClient::Transaction t; t.show(mSurfaceControl); t.setInputWindowInfo(mSurfaceControl, mInputInfo); @@ -259,6 +255,57 @@ public: InputConsumer* mInputConsumer; }; +class BlastInputSurface : public InputSurface { +public: + BlastInputSurface(const sp<SurfaceControl> &sc, const sp<SurfaceControl> &parentSc, int width, + int height) + : InputSurface(sc, width, height) { + mParentSurfaceControl = parentSc; + } + + ~BlastInputSurface() = default; + + static std::unique_ptr<BlastInputSurface> makeBlastInputSurface( + const sp<SurfaceComposerClient> &scc, int width, int height) { + sp<SurfaceControl> parentSc = + scc->createSurface(String8("Test Parent Surface"), 0 /* bufHeight */, + 0 /* bufWidth */, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceContainer); + + sp<SurfaceControl> surfaceControl = + scc->createSurface(String8("Test Buffer Surface"), width, height, + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceBufferState, + parentSc->getHandle()); + return std::make_unique<BlastInputSurface>(surfaceControl, parentSc, width, height); + } + + void doTransaction( + std::function<void(SurfaceComposerClient::Transaction &, const sp<SurfaceControl> &)> + transactionBody) override { + SurfaceComposerClient::Transaction t; + transactionBody(t, mParentSurfaceControl); + t.apply(true); + } + + void showAt(int x, int y, Rect crop = Rect(0, 0, 100, 100)) override { + SurfaceComposerClient::Transaction t; + t.show(mParentSurfaceControl); + t.setLayer(mParentSurfaceControl, LAYER_BASE); + t.setPosition(mParentSurfaceControl, x, y); + t.setCrop(mParentSurfaceControl, crop); + + t.show(mSurfaceControl); + t.setInputWindowInfo(mSurfaceControl, mInputInfo); + t.setCrop(mSurfaceControl, crop); + t.setAlpha(mSurfaceControl, 1); + t.apply(true); + } + +private: + sp<SurfaceControl> mParentSurfaceControl; +}; + class InputSurfacesTest : public ::testing::Test { public: InputSurfacesTest() { @@ -289,15 +336,12 @@ public: return InputSurface::makeColorInputSurface(mComposerClient, width, height); } - void postBuffer(const sp<SurfaceControl> &layer) { - // wait for previous transactions (such as setSize) to complete - Transaction().apply(true); - ANativeWindow_Buffer buffer = {}; - EXPECT_EQ(NO_ERROR, layer->getSurface()->lock(&buffer, nullptr)); - ASSERT_EQ(NO_ERROR, layer->getSurface()->unlockAndPost()); - // Request an empty transaction to get applied synchronously to ensure the buffer is - // latched. - Transaction().apply(true); + void postBuffer(const sp<SurfaceControl> &layer, int32_t w, int32_t h) { + int64_t usageFlags = BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_OVERLAY | BufferUsage::GPU_TEXTURE; + sp<GraphicBuffer> buffer = + new GraphicBuffer(w, h, PIXEL_FORMAT_RGBA_8888, 1, usageFlags, "test"); + Transaction().setBuffer(layer, buffer).apply(true); usleep(mBufferPostDelay); } @@ -474,8 +518,8 @@ TEST_F(InputSurfacesTest, input_ignores_transparent_region) { // Original bug ref: b/120839715 TEST_F(InputSurfacesTest, input_ignores_buffer_layer_buffer) { std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100); - std::unique_ptr<InputSurface> bufferSurface = - InputSurface::makeBufferInputSurface(mComposerClient, 100, 100); + std::unique_ptr<BlastInputSurface> bufferSurface = + BlastInputSurface::makeBlastInputSurface(mComposerClient, 100, 100); bgSurface->showAt(10, 10); bufferSurface->showAt(10, 10); @@ -483,16 +527,16 @@ TEST_F(InputSurfacesTest, input_ignores_buffer_layer_buffer) { injectTap(11, 11); bufferSurface->expectTap(1, 1); - postBuffer(bufferSurface->mSurfaceControl); + postBuffer(bufferSurface->mSurfaceControl, 100, 100); injectTap(11, 11); bufferSurface->expectTap(1, 1); } TEST_F(InputSurfacesTest, input_ignores_buffer_layer_alpha) { std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100); - std::unique_ptr<InputSurface> bufferSurface = - InputSurface::makeBufferInputSurface(mComposerClient, 100, 100); - postBuffer(bufferSurface->mSurfaceControl); + std::unique_ptr<BlastInputSurface> bufferSurface = + BlastInputSurface::makeBlastInputSurface(mComposerClient, 100, 100); + postBuffer(bufferSurface->mSurfaceControl, 100, 100); bgSurface->showAt(10, 10); bufferSurface->showAt(10, 10); @@ -720,8 +764,8 @@ TEST_F(InputSurfacesTest, touch_not_obscured_with_zero_sized_bql) { TEST_F(InputSurfacesTest, touch_not_obscured_with_zero_sized_blast) { std::unique_ptr<InputSurface> surface = makeSurface(100, 100); - std::unique_ptr<InputSurface> bufferSurface = - InputSurface::makeBlastInputSurface(mComposerClient, 0, 0); + std::unique_ptr<BlastInputSurface> bufferSurface = + BlastInputSurface::makeBlastInputSurface(mComposerClient, 0, 0); bufferSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE; bufferSurface->mInputInfo.ownerUid = 22222; diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 887603392f..751b95af66 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -819,6 +819,16 @@ public: return NO_ERROR; } + status_t addHdrLayerInfoListener(const sp<IBinder>&, + const sp<gui::IHdrLayerInfoListener>&) override { + return NO_ERROR; + } + + status_t removeHdrLayerInfoListener(const sp<IBinder>&, + const sp<gui::IHdrLayerInfoListener>&) override { + return NO_ERROR; + } + status_t addRegionSamplingListener(const Rect& /*samplingArea*/, const sp<IBinder>& /*stopLayerHandle*/, const sp<IRegionSamplingListener>& /*listener*/) override { diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp index ffcc1cd93a..31027b6476 100644 --- a/libs/input/InputDevice.cpp +++ b/libs/input/InputDevice.cpp @@ -231,6 +231,13 @@ void InputDeviceInfo::addSensorInfo(const InputDeviceSensorInfo& info) { mSensors.insert_or_assign(info.type, info); } +void InputDeviceInfo::addBatteryInfo(const InputDeviceBatteryInfo& info) { + if (mBatteries.find(info.id) != mBatteries.end()) { + ALOGW("Battery id %d already exists, will be replaced by new battery added.", info.id); + } + mBatteries.insert_or_assign(info.id, info); +} + void InputDeviceInfo::addLightInfo(const InputDeviceLightInfo& info) { if (mLights.find(info.id) != mLights.end()) { ALOGW("Light id %d already exists, will be replaced by new light added.", info.id); diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index 06a17220f1..cd7a86bb0e 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -73,6 +73,7 @@ public: bool cleanupPostRender(CleanupMode mode) override; int getContextPriority() override; bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; } + void onPrimaryDisplaySizeChanged(ui::Size size) override {} EGLDisplay getEGLDisplay() const { return mEGLDisplay; } // Creates an output image for rendering to diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index 7c51f1bb20..a69d1f0da0 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -153,6 +153,10 @@ public: virtual bool supportsProtectedContent() const = 0; virtual bool useProtectedContext(bool useProtectedContext) = 0; + // Notify RenderEngine of changes to the dimensions of the primary display + // so that it can configure its internal caches accordingly. + virtual void onPrimaryDisplaySizeChanged(ui::Size size) = 0; + // Renders layers for a particular display via GPU composition. This method // should be called for every display that needs to be rendered via the GPU. // @param display The display-wide settings that should be applied prior to diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index 5f75b81c9a..228553d643 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -55,6 +55,7 @@ public: MOCK_METHOD0(cleanFramebufferCache, void()); MOCK_METHOD0(getContextPriority, int()); MOCK_METHOD0(supportsBackgroundBlur, bool()); + MOCK_METHOD1(onPrimaryDisplaySizeChanged, void(ui::Size)); }; } // namespace mock diff --git a/libs/renderengine/skia/AutoBackendTexture.cpp b/libs/renderengine/skia/AutoBackendTexture.cpp index ae3d88a9fb..c535597aea 100644 --- a/libs/renderengine/skia/AutoBackendTexture.cpp +++ b/libs/renderengine/skia/AutoBackendTexture.cpp @@ -28,19 +28,19 @@ namespace android { namespace renderengine { namespace skia { -AutoBackendTexture::AutoBackendTexture(GrDirectContext* context, AHardwareBuffer* buffer) { +AutoBackendTexture::AutoBackendTexture(GrDirectContext* context, AHardwareBuffer* buffer, + bool isRender) { ATRACE_CALL(); AHardwareBuffer_Desc desc; AHardwareBuffer_describe(buffer, &desc); - const bool createProtectedImage = 0 != (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT); - const bool isRenderable = 0 != (desc.usage & AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER); + bool createProtectedImage = 0 != (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT); GrBackendFormat backendFormat = GrAHardwareBufferUtils::GetBackendFormat(context, buffer, desc.format, false); mBackendTexture = GrAHardwareBufferUtils::MakeBackendTexture(context, buffer, desc.width, desc.height, &mDeleteProc, &mUpdateProc, &mImageCtx, createProtectedImage, backendFormat, - isRenderable); + isRender); mColorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(desc.format); } diff --git a/libs/renderengine/skia/AutoBackendTexture.h b/libs/renderengine/skia/AutoBackendTexture.h index a6f73db3dc..bb758780e1 100644 --- a/libs/renderengine/skia/AutoBackendTexture.h +++ b/libs/renderengine/skia/AutoBackendTexture.h @@ -69,7 +69,7 @@ public: }; // Creates a GrBackendTexture whose contents come from the provided buffer. - AutoBackendTexture(GrDirectContext* context, AHardwareBuffer* buffer); + AutoBackendTexture(GrDirectContext* context, AHardwareBuffer* buffer, bool isRender); void ref() { mUsageCount++; } diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp index 69c6a09076..0cd3b622fa 100644 --- a/libs/renderengine/skia/Cache.cpp +++ b/libs/renderengine/skia/Cache.cpp @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #include "Cache.h" #include "AutoBackendTexture.h" #include "SkiaRenderEngine.h" @@ -26,11 +25,28 @@ #include "ui/Rect.h" #include "utils/Timers.h" +#include <android/hardware_buffer.h> + namespace android::renderengine::skia { +namespace { // Warming shader cache, not framebuffer cache. constexpr bool kUseFrameBufferCache = false; +// clang-format off +// Any non-identity matrix will do. +const auto kScaleAndTranslate = mat4(0.7f, 0.f, 0.f, 0.f, + 0.f, 0.7f, 0.f, 0.f, + 0.f, 0.f, 1.f, 0.f, + 67.3f, 52.2f, 0.f, 1.f); +// clang-format on +// When choosing dataspaces below, whether the match the destination or not determined whether +// a color correction effect is added to the shader. There may be other additional shader details +// for particular color spaces. +// TODO(b/184842383) figure out which color related shaders are necessary +constexpr auto kDestDataSpace = ui::Dataspace::SRGB; +} // namespace + static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display, sp<GraphicBuffer> dstBuffer) { // Somewhat arbitrary dimensions, but on screen and slightly shorter, based @@ -51,23 +67,29 @@ static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettin .lightRadius = 2200.0f, .length = 0.955342f, }, + // important that this matches dest so the general shadow fragment shader doesn't + // have color correction added, and important that it be srgb, so the *vertex* shader + // doesn't have color correction added. + .sourceDataspace = kDestDataSpace, }; auto layers = std::vector<const LayerSettings*>{&layer}; - // The identity matrix will generate the fast shaders, and the second matrix - // (based on one seen while going from dialer to the home screen) will - // generate the slower (more general case) version. If we also need a - // slow version without color correction, we should use this matrix with - // display.outputDataspace set to SRGB. - bool identity = true; - for (const mat4 transform : { mat4(), mat4(0.728872f, 0.f, 0.f, 0.f, - 0.f, 0.727627f, 0.f, 0.f, - 0.f, 0.f, 1.f, 0.f, - 167.355743f, 1852.257812f, 0.f, 1.f) }) { - layer.geometry.positionTransform = transform; + // The identity matrix will generate the fast shader + renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, base::unique_fd(), + nullptr); + // This matrix, which has different scales for x and y, will + // generate the slower (more general case) version, which has variants for translucent + // casters and rounded rects. + // clang-format off + layer.geometry.positionTransform = mat4(0.7f, 0.f, 0.f, 0.f, + 0.f, 0.8f, 0.f, 0.f, + 0.f, 0.f, 1.f, 0.f, + 0.f, 0.f, 0.f, 1.f); + // clang-format on + for (auto translucent : {false, true}) { + layer.shadow.casterIsTranslucent = translucent; renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, base::unique_fd(), nullptr); - identity = false; } } @@ -89,33 +111,25 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting }}, }; - // This matrix is based on actual data seen when opening the dialer. - // translate and scale creates new shaders when combined with rounded corners - // clang-format off - auto scale_and_translate = mat4(.19f, .0f, .0f, .0f, - .0f, .19f, .0f, .0f, - .0f, .0f, 1.f, .0f, - 169.f, 1527.f, .0f, 1.f); - // clang-format on + auto threeCornerRadii = {0.0f, 0.05f, 50.f}; + auto oneCornerRadius = {50.f}; // Test both drawRect and drawRRect auto layers = std::vector<const LayerSettings*>{&layer}; - for (auto transform : {mat4(), scale_and_translate}) { - layer.geometry.positionTransform = transform; - // fractional corner radius creates a shader that is used during home button swipe - for (float roundedCornersRadius : {0.0f, 0.05f, 500.f}) { + for (bool identity : {true, false}) { + layer.geometry.positionTransform = identity ? mat4() : kScaleAndTranslate; + // Corner radii less than 0.5 creates a special shader. This likely occurs in real usage + // due to animating corner radius. + // For the non-idenity matrix, only the large corner radius will create a new shader. + for (float roundedCornersRadius : identity ? threeCornerRadii : oneCornerRadius) { // roundedCornersCrop is always set, but it is this radius that triggers the behavior layer.geometry.roundedCornersRadius = roundedCornersRadius; - // No need to check UNKNOWN, which is treated as SRGB. - for (auto dataspace : {ui::Dataspace::SRGB, ui::Dataspace::DISPLAY_P3}) { - layer.sourceDataspace = dataspace; - for (bool isOpaque : {true, false}) { - layer.source.buffer.isOpaque = isOpaque; - for (auto alpha : {half(.23999f), half(1.0f)}) { - layer.alpha = alpha; - renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, - base::unique_fd(), nullptr); - } + for (bool isOpaque : {true, false}) { + layer.source.buffer.isOpaque = isOpaque; + for (auto alpha : {half(.23999f), half(1.0f)}) { + layer.alpha = alpha; + renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, + base::unique_fd(), nullptr); } } } @@ -139,11 +153,89 @@ static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySetting }; auto layers = std::vector<const LayerSettings*>{&layer}; - renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, base::unique_fd(), - nullptr); + for (auto transform : {mat4(), kScaleAndTranslate}) { + layer.geometry.positionTransform = transform; + for (float roundedCornersRadius : {0.0f, 0.05f, 50.f}) { + layer.geometry.roundedCornersRadius = roundedCornersRadius; + renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, + base::unique_fd(), nullptr); + } + } +} + +static void drawBlurLayers(SkiaRenderEngine* renderengine, const DisplaySettings& display, + sp<GraphicBuffer> dstBuffer) { + const Rect& displayRect = display.physicalDisplay; + FloatRect rect(0, 0, displayRect.width(), displayRect.height()); + LayerSettings layer{ + .geometry = + Geometry{ + .boundaries = rect, + }, + .alpha = 1, + }; + + auto layers = std::vector<const LayerSettings*>{&layer}; + for (int radius : {9, 60}) { + layer.backgroundBlurRadius = radius; + renderengine->drawLayers(display, layers, dstBuffer, kUseFrameBufferCache, + base::unique_fd(), nullptr); + } +} + +namespace { + +struct AHardwareBuffer_deleter { + void operator()(AHardwareBuffer* ahb) const { AHardwareBuffer_release(ahb); } +}; + +std::unique_ptr<AHardwareBuffer, AHardwareBuffer_deleter> makeAHardwareBuffer() { + AHardwareBuffer* buffer = nullptr; + + int w = 32; + int h = 32; + + AHardwareBuffer_Desc hwbDesc; + hwbDesc.width = w; + hwbDesc.height = h; + hwbDesc.layers = 1; + hwbDesc.usage = AHARDWAREBUFFER_USAGE_CPU_READ_NEVER | AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER | + AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; + hwbDesc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM; + // The following three are not used in the allocate + hwbDesc.stride = 0; + hwbDesc.rfu0 = 0; + hwbDesc.rfu1 = 0; + + if (int error = AHardwareBuffer_allocate(&hwbDesc, &buffer)) { + ALOGE("Failed to allocated hardware buffer, error: %d", error); + if (buffer) { + AHardwareBuffer_release(buffer); + } + return nullptr; + } + return std::unique_ptr<AHardwareBuffer, AHardwareBuffer_deleter>(buffer); } +} // namespace +// +// The collection of shaders cached here were found by using perfetto to record shader compiles +// during actions that involve RenderEngine, logging the layer settings, and the shader code +// and reproducing those settings here. +// +// It is helpful when debugging this to turn on +// in SkGLRenderEngine.cpp: +// kPrintLayerSettings = true +// kFlushAfterEveryLayer = true +// in external/skia/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp +// gPrintSKSL = true +// +// TODO(b/184631553) cache the shader involved in youtube pip return. void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { + const int previousCount = renderengine->reportShadersCompiled(); + if (previousCount) { + ALOGD("%d Shaders already compiled before Cache::primeShaderCache ran\n", previousCount); + } const nsecs_t timeBefore = systemTime(); // The dimensions should not matter, so long as we draw inside them. const Rect displayRect(0, 0, 1080, 2340); @@ -151,7 +243,7 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { .physicalDisplay = displayRect, .clip = displayRect, .maxLuminance = 500, - .outputDataspace = ui::Dataspace::DISPLAY_P3, + .outputDataspace = kDestDataSpace, }; const int64_t usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; @@ -166,12 +258,28 @@ void Cache::primeShaderCache(SkiaRenderEngine* renderengine) { sp<GraphicBuffer> srcBuffer = new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888, 1, usage, "drawImageLayer_src"); + drawSolidLayers(renderengine, display, dstBuffer); drawShadowLayers(renderengine, display, srcBuffer); + drawBlurLayers(renderengine, display, dstBuffer); + // The majority of shaders are related to sampling images. drawImageLayers(renderengine, display, dstBuffer, srcBuffer); + + // Draw image layers again sampling from an AHardwareBuffer if it is possible to create one. + if (auto ahb = makeAHardwareBuffer()) { + sp<GraphicBuffer> externalBuffer = GraphicBuffer::fromAHardwareBuffer(ahb.get()); + // TODO(b/184665179) doubles number of image shader compilations, but only somewhere + // between 6 and 8 will occur in real uses. + drawImageLayers(renderengine, display, dstBuffer, externalBuffer); + renderengine->unbindExternalTextureBuffer(externalBuffer->getId()); + } + + renderengine->unbindExternalTextureBuffer(srcBuffer->getId()); + const nsecs_t timeAfter = systemTime(); const float compileTimeMs = static_cast<float>(timeAfter - timeBefore) / 1.0E6; - ALOGD("shader cache generated in %f ms\n", compileTimeMs); + const int shadersCompiled = renderengine->reportShadersCompiled(); + ALOGD("Shader cache generated %d shaders in %f ms\n", shadersCompiled, compileTimeMs); } } // namespace android::renderengine::skia diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index c7001b9851..fb7e2856e4 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -56,6 +56,12 @@ #include "skia/debug/SkiaCapture.h" #include "system/graphics-base-v1.0.h" +namespace { +// Debugging settings +static const bool kPrintLayerSettings = false; +static const bool kFlushAfterEveryLayer = false; +} // namespace + bool checkGlError(const char* op, int lineNumber); namespace android { @@ -285,6 +291,10 @@ void SkiaGLRenderEngine::assertShadersCompiled(int numShaders) { numShaders, cached); } +int SkiaGLRenderEngine::reportShadersCompiled() { + return mSkSLCacheMonitor.shadersCachedSinceLastCall(); +} + SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, EGLContext ctxt, EGLSurface placeholder, EGLContext protectedContext, EGLSurface protectedPlaceholder) @@ -294,12 +304,13 @@ SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGL mPlaceholderSurface(placeholder), mProtectedEGLContext(protectedContext), mProtectedPlaceholderSurface(protectedPlaceholder), + mDefaultPixelFormat(static_cast<PixelFormat>(args.pixelFormat)), mUseColorManagement(args.useColorManagement) { sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface()); LOG_ALWAYS_FATAL_IF(!glInterface.get()); GrContextOptions options; - options.fPreferExternalImagesOverES3 = true; + options.fDisableDriverCorrectnessWorkarounds = true; options.fDisableDistanceFieldPaths = true; options.fPersistentCache = &mSkSLCacheMonitor; mGrContext = GrDirectContext::MakeGL(glInterface, options); @@ -499,7 +510,7 @@ void SkiaGLRenderEngine::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buf std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef = std::make_shared<AutoBackendTexture::LocalRef>(); imageTextureRef->setTexture( - new AutoBackendTexture(grContext.get(), buffer->toAHardwareBuffer())); + new AutoBackendTexture(grContext.get(), buffer->toAHardwareBuffer(), false)); cache.insert({buffer->getId(), imageTextureRef}); } // restore the original state of the protected context if necessary @@ -653,7 +664,7 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, ATRACE_NAME("Cache miss"); surfaceTextureRef = std::make_shared<AutoBackendTexture::LocalRef>(); surfaceTextureRef->setTexture( - new AutoBackendTexture(grContext.get(), buffer->toAHardwareBuffer())); + new AutoBackendTexture(grContext.get(), buffer->toAHardwareBuffer(), true)); if (useFramebufferCache) { ALOGD("Adding to cache"); cache.insert({buffer->getId(), surfaceTextureRef}); @@ -734,6 +745,17 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, for (const auto& layer : layers) { ATRACE_NAME("DrawLayer"); + if (kPrintLayerSettings) { + std::stringstream ls; + PrintTo(*layer, &ls); + auto debugs = ls.str(); + int pos = 0; + while (pos < debugs.size()) { + ALOGD("cache_debug %s", debugs.substr(pos, 1000).c_str()); + pos += 1000; + } + } + sk_sp<SkImage> blurInput; if (blurCompositionLayer == layer) { LOG_ALWAYS_FATAL_IF(activeSurface == dstSurface); @@ -860,8 +882,9 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, imageTextureRef = iter->second; } else { imageTextureRef = std::make_shared<AutoBackendTexture::LocalRef>(); - imageTextureRef->setTexture( - new AutoBackendTexture(grContext.get(), item.buffer->toAHardwareBuffer())); + imageTextureRef->setTexture(new AutoBackendTexture(grContext.get(), + item.buffer->toAHardwareBuffer(), + false)); cache.insert({item.buffer->getId(), imageTextureRef}); } @@ -954,6 +977,10 @@ status_t SkiaGLRenderEngine::drawLayers(const DisplaySettings& display, } else { canvas->drawRect(bounds, paint); } + if (kFlushAfterEveryLayer) { + ATRACE_NAME("flush surface"); + activeSurface->flush(); + } } surfaceAutoSaveRestore.restore(); mCapture->endCapture(); @@ -1186,6 +1213,27 @@ int SkiaGLRenderEngine::getContextPriority() { return value; } +void SkiaGLRenderEngine::onPrimaryDisplaySizeChanged(ui::Size size) { + // This cache multiplier was selected based on review of cache sizes relative + // to the screen resolution. Looking at the worst case memory needed by blur (~1.5x), + // shadows (~1x), and general data structures (e.g. vertex buffers) we selected this as a + // conservative default based on that analysis. + const float SURFACE_SIZE_MULTIPLIER = 3.5f * bytesPerPixel(mDefaultPixelFormat); + const int maxResourceBytes = size.width * size.height * SURFACE_SIZE_MULTIPLIER; + + // start by resizing the current context + auto grContext = mInProtectedContext ? mProtectedGrContext : mGrContext; + grContext->setResourceCacheLimit(maxResourceBytes); + + // if it is possible to switch contexts then we will resize the other context + if (useProtectedContext(!mInProtectedContext)) { + grContext = mInProtectedContext ? mProtectedGrContext : mGrContext; + grContext->setResourceCacheLimit(maxResourceBytes); + // reset back to the initial context that was active when this method was called + useProtectedContext(!mInProtectedContext); + } +} + void SkiaGLRenderEngine::dump(std::string& result) { const gl::GLExtensions& extensions = gl::GLExtensions::getInstance(); diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h index 7605df942c..8e77c16b40 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.h +++ b/libs/renderengine/skia/SkiaGLRenderEngine.h @@ -65,6 +65,8 @@ public: bool useProtectedContext(bool useProtectedContext) override; bool supportsBackgroundBlur() override { return mBlurFilter != nullptr; } void assertShadersCompiled(int numShaders) override; + void onPrimaryDisplaySizeChanged(ui::Size size) override; + int reportShadersCompiled() override; protected: void dump(std::string& result) override; @@ -109,6 +111,7 @@ private: EGLSurface mProtectedPlaceholderSurface; BlurFilter* mBlurFilter = nullptr; + const PixelFormat mDefaultPixelFormat; const bool mUseColorManagement; // Cache of GL textures that we'll store per GraphicBuffer ID diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h index 59d7e2ff89..51ef088a25 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.h +++ b/libs/renderengine/skia/SkiaRenderEngine.h @@ -59,6 +59,7 @@ public: virtual bool cleanupPostRender(CleanupMode) override { return true; }; virtual int getContextPriority() override { return 0; } virtual void assertShadersCompiled(int numShaders) {} + virtual int reportShadersCompiled() { return 0; } }; } // namespace skia diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp index ec710d97c3..6dd416101d 100644 --- a/libs/renderengine/skia/filters/BlurFilter.cpp +++ b/libs/renderengine/skia/filters/BlurFilter.cpp @@ -34,7 +34,7 @@ namespace skia { BlurFilter::BlurFilter() { SkString blurString(R"( - in shader input; + uniform shader input; uniform float2 in_blurOffset; uniform float2 in_maxSizeXY; @@ -60,8 +60,8 @@ BlurFilter::BlurFilter() { mBlurEffect = std::move(blurEffect); SkString mixString(R"( - in shader blurredInput; - in shader originalInput; + uniform shader blurredInput; + uniform shader originalInput; uniform float mixFactor; half4 main(float2 xy) { diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp index 84af016458..8e8e42e75a 100644 --- a/libs/renderengine/skia/filters/LinearEffect.cpp +++ b/libs/renderengine/skia/filters/LinearEffect.cpp @@ -390,7 +390,7 @@ static void generateOETF(ui::Dataspace dataspace, SkString& shader) { static void generateEffectiveOOTF(bool undoPremultipliedAlpha, SkString& shader) { shader.append(R"( - in shader input; + uniform shader input; half4 main(float2 xy) { float4 c = float4(sample(input, xy)); )"); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp index 6a91c7c3a3..783e37fc22 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.cpp +++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp @@ -332,6 +332,21 @@ bool RenderEngineThreaded::supportsBackgroundBlur() { return resultFuture.get(); } +void RenderEngineThreaded::onPrimaryDisplaySizeChanged(ui::Size size) { + std::promise<void> resultPromise; + std::future<void> resultFuture = resultPromise.get_future(); + { + std::lock_guard lock(mThreadMutex); + mFunctionCalls.push([&resultPromise, size](renderengine::RenderEngine& instance) { + ATRACE_NAME("REThreaded::onPrimaryDisplaySizeChanged"); + instance.onPrimaryDisplaySizeChanged(size); + resultPromise.set_value(); + }); + } + mCondition.notify_one(); + resultFuture.wait(); +} + } // namespace threaded } // namespace renderengine } // namespace android diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h index 7694328c84..117257a90e 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.h +++ b/libs/renderengine/threaded/RenderEngineThreaded.h @@ -66,6 +66,7 @@ public: void cleanFramebufferCache() override; int getContextPriority() override; bool supportsBackgroundBlur() override; + void onPrimaryDisplaySizeChanged(ui::Size size) override; private: void threadMain(CreateInstanceFactory factory); diff --git a/libs/ui/FenceTime.cpp b/libs/ui/FenceTime.cpp index bdfe04b0dd..538c1d2a42 100644 --- a/libs/ui/FenceTime.cpp +++ b/libs/ui/FenceTime.cpp @@ -97,6 +97,34 @@ bool FenceTime::isValid() const { return mState != State::INVALID; } +status_t FenceTime::wait(int timeout) { + // See if we already have a cached value we can return. + nsecs_t signalTime = mSignalTime.load(std::memory_order_relaxed); + if (signalTime != Fence::SIGNAL_TIME_PENDING) { + return NO_ERROR; + } + + // Hold a reference to the fence on the stack in case the class' + // reference is removed by another thread. This prevents the + // fence from being destroyed until the end of this method, where + // we conveniently do not have the lock held. + sp<Fence> fence; + { + // With the lock acquired this time, see if we have the cached + // value or if we need to poll the fence. + std::lock_guard<std::mutex> lock(mMutex); + if (!mFence.get()) { + // Another thread set the signal time just before we added the + // reference to mFence. + return NO_ERROR; + } + fence = mFence; + } + + // Make the system call without the lock held. + return fence->wait(timeout); +} + nsecs_t FenceTime::getSignalTime() { // See if we already have a cached value we can return. nsecs_t signalTime = mSignalTime.load(std::memory_order_relaxed); diff --git a/libs/ui/include/ui/FenceTime.h b/libs/ui/include/ui/FenceTime.h index ecba7f73e8..ac75f431a0 100644 --- a/libs/ui/include/ui/FenceTime.h +++ b/libs/ui/include/ui/FenceTime.h @@ -112,6 +112,13 @@ public: // Returns a snapshot of the FenceTime in its current state. Snapshot getSnapshot() const; + // wait waits for up to timeout milliseconds for the fence to signal. If + // the fence signals then NO_ERROR is returned. If the timeout expires + // before the fence signals then -ETIME is returned. A timeout of + // TIMEOUT_NEVER may be used to indicate that the call should wait + // indefinitely for the fence to signal. + status_t wait(int timeout); + void signalForTest(nsecs_t signalTime); private: diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp index 1af70a4fd1..746889409c 100644 --- a/services/inputflinger/reader/Android.bp +++ b/services/inputflinger/reader/Android.bp @@ -24,6 +24,7 @@ package { cc_library_headers { name: "libinputreader_headers", export_include_dirs: [ + "controller", "include", "mapper", "mapper/accumulator", @@ -35,17 +36,16 @@ filegroup { srcs: [ "EventHub.cpp", "InputDevice.cpp", + "controller/InputController.cpp", "mapper/accumulator/CursorButtonAccumulator.cpp", "mapper/accumulator/CursorScrollAccumulator.cpp", "mapper/accumulator/SingleTouchMotionAccumulator.cpp", "mapper/accumulator/TouchButtonAccumulator.cpp", - "mapper/BatteryInputMapper.cpp", "mapper/CursorInputMapper.cpp", "mapper/ExternalStylusInputMapper.cpp", "mapper/InputMapper.cpp", "mapper/JoystickInputMapper.cpp", "mapper/KeyboardInputMapper.cpp", - "mapper/LightInputMapper.cpp", "mapper/MultiTouchInputMapper.cpp", "mapper/RotaryEncoderInputMapper.cpp", "mapper/SensorInputMapper.cpp", diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp index 07011f5ada..045d24cac6 100644 --- a/services/inputflinger/reader/EventHub.cpp +++ b/services/inputflinger/reader/EventHub.cpp @@ -70,6 +70,20 @@ static const char* VIDEO_DEVICE_PATH = "/dev"; static constexpr int32_t FF_STRONG_MAGNITUDE_CHANNEL_IDX = 0; static constexpr int32_t FF_WEAK_MAGNITUDE_CHANNEL_IDX = 1; +// Mapping for input battery class node IDs lookup. +// https://www.kernel.org/doc/Documentation/power/power_supply_class.txt +static const std::unordered_map<std::string, InputBatteryClass> BATTERY_CLASSES = + {{"capacity", InputBatteryClass::CAPACITY}, + {"capacity_level", InputBatteryClass::CAPACITY_LEVEL}, + {"status", InputBatteryClass::STATUS}}; + +// Mapping for input battery class node names lookup. +// https://www.kernel.org/doc/Documentation/power/power_supply_class.txt +static const std::unordered_map<InputBatteryClass, std::string> BATTERY_NODES = + {{InputBatteryClass::CAPACITY, "capacity"}, + {InputBatteryClass::CAPACITY_LEVEL, "capacity_level"}, + {InputBatteryClass::STATUS, "status"}}; + // must be kept in sync with definitions in kernel /drivers/power/supply/power_supply_sysfs.c static const std::unordered_map<std::string, int32_t> BATTERY_STATUS = {{"Unknown", BATTERY_STATUS_UNKNOWN}, @@ -349,7 +363,7 @@ EventHub::Device::Device(int fd, int32_t id, const std::string& path, virtualKeyMap(nullptr), ffEffectPlaying(false), ffEffectId(-1), - nextLightId(0), + miscDevice(nullptr), controllerNumber(0), enabled(true), isVirtual(fd < 0) {} @@ -540,32 +554,36 @@ status_t EventHub::Device::mapLed(int32_t led, int32_t* outScanCode) const { } // Check the sysfs path for any input device batteries, returns true if battery found. -bool EventHub::Device::configureBatteryLocked() { - if (!sysfsRootPath.has_value()) { - return false; - } - // Check if device has any batteries. - std::vector<std::filesystem::path> batteryPaths = - findSysfsNodes(sysfsRootPath.value(), SysfsClass::POWER_SUPPLY); - // We only support single battery for an input device, if multiple batteries exist only the - // first one is supported. - if (batteryPaths.empty()) { - // Set path to be empty - sysfsBatteryPath = std::nullopt; - return false; +bool EventHub::MiscDevice::configureBatteryLocked() { + nextBatteryId = 0; + // Check if device has any battery. + const auto& paths = findSysfsNodes(sysfsRootPath, SysfsClass::POWER_SUPPLY); + for (const auto& nodePath : paths) { + RawBatteryInfo info; + info.id = ++nextBatteryId; + info.path = nodePath; + info.name = nodePath.filename(); + + // Scan the path for all the files + // Refer to https://www.kernel.org/doc/Documentation/leds/leds-class.txt + const auto& files = allFilesInPath(nodePath); + for (const auto& file : files) { + const auto it = BATTERY_CLASSES.find(file.filename().string()); + if (it != BATTERY_CLASSES.end()) { + info.flags |= it->second; + } + } + batteryInfos.insert_or_assign(info.id, info); + ALOGD("configureBatteryLocked rawBatteryId %d name %s", info.id, info.name.c_str()); } - // If a battery exists - sysfsBatteryPath = batteryPaths[0]; - return true; + return !batteryInfos.empty(); } // Check the sysfs path for any input device lights, returns true if lights found. -bool EventHub::Device::configureLightsLocked() { - if (!sysfsRootPath.has_value()) { - return false; - } +bool EventHub::MiscDevice::configureLightsLocked() { + nextLightId = 0; // Check if device has any lights. - const auto& paths = findSysfsNodes(sysfsRootPath.value(), SysfsClass::LEDS); + const auto& paths = findSysfsNodes(sysfsRootPath, SysfsClass::LEDS); for (const auto& nodePath : paths) { RawLightInfo info; info.id = ++nextLightId; @@ -599,6 +617,7 @@ bool EventHub::Device::configureLightsLocked() { } } lightInfos.insert_or_assign(info.id, info); + ALOGD("configureLightsLocked rawLightId %d name %s", info.id, info.name.c_str()); } return !lightInfos.empty(); } @@ -963,42 +982,92 @@ base::Result<std::pair<InputDeviceSensorType, int32_t>> EventHub::mapSensor(int3 return Errorf("Device not found or device has no key layout."); } -const std::vector<int32_t> EventHub::getRawLightIds(int32_t deviceId) { +// Gets the battery info map from battery ID to RawBatteryInfo of the miscellaneous device +// associated with the device ID. Returns an empty map if no miscellaneous device found. +const std::unordered_map<int32_t, RawBatteryInfo>& EventHub::getBatteryInfoLocked( + int32_t deviceId) const { + static const std::unordered_map<int32_t, RawBatteryInfo> EMPTY_BATTERY_INFO = {}; + Device* device = getDeviceLocked(deviceId); + if (device == nullptr) { + return EMPTY_BATTERY_INFO; + } + auto it = mMiscDevices.find(device->identifier.descriptor); + if (it == mMiscDevices.end()) { + return EMPTY_BATTERY_INFO; + } + return it->second->batteryInfos; +} + +const std::vector<int32_t> EventHub::getRawBatteryIds(int32_t deviceId) { std::scoped_lock _l(mLock); + std::vector<int32_t> batteryIds; + + for (const auto [id, info] : getBatteryInfoLocked(deviceId)) { + batteryIds.push_back(id); + } + + return batteryIds; +} + +std::optional<RawBatteryInfo> EventHub::getRawBatteryInfo(int32_t deviceId, int32_t batteryId) { + std::scoped_lock _l(mLock); + + const auto infos = getBatteryInfoLocked(deviceId); + + auto it = infos.find(batteryId); + if (it != infos.end()) { + return it->second; + } + + return std::nullopt; +} + +// Gets the light info map from light ID to RawLightInfo of the miscellaneous device associated +// with the deivice ID. Returns an empty map if no miscellaneous device found. +const std::unordered_map<int32_t, RawLightInfo>& EventHub::getLightInfoLocked( + int32_t deviceId) const { + static const std::unordered_map<int32_t, RawLightInfo> EMPTY_LIGHT_INFO = {}; Device* device = getDeviceLocked(deviceId); + if (device == nullptr) { + return EMPTY_LIGHT_INFO; + } + auto it = mMiscDevices.find(device->identifier.descriptor); + if (it == mMiscDevices.end()) { + return EMPTY_LIGHT_INFO; + } + return it->second->lightInfos; +} + +const std::vector<int32_t> EventHub::getRawLightIds(int32_t deviceId) { + std::scoped_lock _l(mLock); std::vector<int32_t> lightIds; - if (device != nullptr) { - for (const auto [id, info] : device->lightInfos) { - lightIds.push_back(id); - } + for (const auto [id, info] : getLightInfoLocked(deviceId)) { + lightIds.push_back(id); } + return lightIds; } std::optional<RawLightInfo> EventHub::getRawLightInfo(int32_t deviceId, int32_t lightId) { std::scoped_lock _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device != nullptr) { - auto it = device->lightInfos.find(lightId); - if (it != device->lightInfos.end()) { - return it->second; - } + const auto infos = getLightInfoLocked(deviceId); + + auto it = infos.find(lightId); + if (it != infos.end()) { + return it->second; } + return std::nullopt; } std::optional<int32_t> EventHub::getLightBrightness(int32_t deviceId, int32_t lightId) { std::scoped_lock _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device == nullptr) { - return std::nullopt; - } - - auto it = device->lightInfos.find(lightId); - if (it == device->lightInfos.end()) { + const auto infos = getLightInfoLocked(deviceId); + auto it = infos.find(lightId); + if (it == infos.end()) { return std::nullopt; } std::string buffer; @@ -1013,13 +1082,9 @@ std::optional<std::unordered_map<LightColor, int32_t>> EventHub::getLightIntensi int32_t deviceId, int32_t lightId) { std::scoped_lock _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device == nullptr) { - return std::nullopt; - } - - auto lightIt = device->lightInfos.find(lightId); - if (lightIt == device->lightInfos.end()) { + const auto infos = getLightInfoLocked(deviceId); + auto lightIt = infos.find(lightId); + if (lightIt == infos.end()) { return std::nullopt; } @@ -1056,14 +1121,10 @@ std::optional<std::unordered_map<LightColor, int32_t>> EventHub::getLightIntensi void EventHub::setLightBrightness(int32_t deviceId, int32_t lightId, int32_t brightness) { std::scoped_lock _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device == nullptr) { - ALOGE("Device Id %d does not exist", deviceId); - return; - } - auto lightIt = device->lightInfos.find(lightId); - if (lightIt == device->lightInfos.end()) { - ALOGE("Light Id %d does not exist.", lightId); + const auto infos = getLightInfoLocked(deviceId); + auto lightIt = infos.find(lightId); + if (lightIt == infos.end()) { + ALOGE("%s lightId %d not found ", __func__, lightId); return; } @@ -1078,13 +1139,9 @@ void EventHub::setLightIntensities(int32_t deviceId, int32_t lightId, std::unordered_map<LightColor, int32_t> intensities) { std::scoped_lock _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device == nullptr) { - ALOGE("Device Id %d does not exist", deviceId); - return; - } - auto lightIt = device->lightInfos.find(lightId); - if (lightIt == device->lightInfos.end()) { + const auto infos = getLightInfoLocked(deviceId); + auto lightIt = infos.find(lightId); + if (lightIt == infos.end()) { ALOGE("Light Id %d does not exist.", lightId); return; } @@ -1352,51 +1409,56 @@ EventHub::Device* EventHub::getDeviceByFdLocked(int fd) const { return nullptr; } -std::optional<int32_t> EventHub::getBatteryCapacity(int32_t deviceId) const { +std::optional<int32_t> EventHub::getBatteryCapacity(int32_t deviceId, int32_t batteryId) const { std::scoped_lock _l(mLock); - Device* device = getDeviceLocked(deviceId); - std::string buffer; - if (device == nullptr || !device->sysfsBatteryPath.has_value()) { + const auto infos = getBatteryInfoLocked(deviceId); + auto it = infos.find(batteryId); + if (it == infos.end()) { return std::nullopt; } + std::string buffer; // Some devices report battery capacity as an integer through the "capacity" file - if (base::ReadFileToString(device->sysfsBatteryPath.value() / "capacity", &buffer)) { + if (base::ReadFileToString(it->second.path / BATTERY_NODES.at(InputBatteryClass::CAPACITY), + &buffer)) { return std::stoi(base::Trim(buffer)); } // Other devices report capacity as an enum value POWER_SUPPLY_CAPACITY_LEVEL_XXX // These values are taken from kernel source code include/linux/power_supply.h - if (base::ReadFileToString(device->sysfsBatteryPath.value() / "capacity_level", &buffer)) { + if (base::ReadFileToString(it->second.path / + BATTERY_NODES.at(InputBatteryClass::CAPACITY_LEVEL), + &buffer)) { // Remove any white space such as trailing new line - const auto it = BATTERY_LEVEL.find(base::Trim(buffer)); - if (it != BATTERY_LEVEL.end()) { - return it->second; + const auto levelIt = BATTERY_LEVEL.find(base::Trim(buffer)); + if (levelIt != BATTERY_LEVEL.end()) { + return levelIt->second; } } + return std::nullopt; } -std::optional<int32_t> EventHub::getBatteryStatus(int32_t deviceId) const { +std::optional<int32_t> EventHub::getBatteryStatus(int32_t deviceId, int32_t batteryId) const { std::scoped_lock _l(mLock); - Device* device = getDeviceLocked(deviceId); - std::string buffer; - - if (device == nullptr || !device->sysfsBatteryPath.has_value()) { + const auto infos = getBatteryInfoLocked(deviceId); + auto it = infos.find(batteryId); + if (it == infos.end()) { return std::nullopt; } + std::string buffer; - if (!base::ReadFileToString(device->sysfsBatteryPath.value() / "status", &buffer)) { + if (!base::ReadFileToString(it->second.path / BATTERY_NODES.at(InputBatteryClass::STATUS), + &buffer)) { ALOGE("Failed to read sysfs battery info: %s", strerror(errno)); return std::nullopt; } // Remove white space like trailing new line - const auto it = BATTERY_STATUS.find(base::Trim(buffer)); - - if (it != BATTERY_STATUS.end()) { - return it->second; + const auto statusIt = BATTERY_STATUS.find(base::Trim(buffer)); + if (statusIt != BATTERY_STATUS.end()) { + return statusIt->second; } return std::nullopt; @@ -1879,11 +1941,24 @@ void EventHub::openDeviceLocked(const std::string& devicePath) { // Load the configuration file for the device. device->loadConfigurationLocked(); - // Grab the device's sysfs path - device->sysfsRootPath = getSysfsRootPath(devicePath.c_str()); - // find related components - bool hasBattery = device->configureBatteryLocked(); - bool hasLights = device->configureLightsLocked(); + bool hasBattery = false; + bool hasLights = false; + // Check the sysfs root path + std::optional<std::filesystem::path> sysfsRootPath = getSysfsRootPath(devicePath.c_str()); + if (sysfsRootPath.has_value()) { + std::shared_ptr<MiscDevice> miscDevice; + auto it = mMiscDevices.find(device->identifier.descriptor); + if (it == mMiscDevices.end()) { + miscDevice = std::make_shared<MiscDevice>(sysfsRootPath.value()); + } else { + miscDevice = it->second; + } + hasBattery = miscDevice->configureBatteryLocked(); + hasLights = miscDevice->configureLightsLocked(); + + device->miscDevice = miscDevice; + mMiscDevices.insert_or_assign(device->identifier.descriptor, std::move(miscDevice)); + } // Figure out the kinds of events the device reports. device->readDeviceBitMask(EVIOCGBIT(EV_KEY, 0), device->keyBitmask); @@ -2254,6 +2329,12 @@ void EventHub::closeDeviceLocked(Device& device) { mClosingDevices.push_back(std::move(mDevices[device.id])); mDevices.erase(device.id); + // If all devices with the descriptor have been removed then the miscellaneous device should + // be removed too. + std::string descriptor = device.identifier.descriptor; + if (getDeviceByDescriptorLocked(descriptor) == nullptr) { + mMiscDevices.erase(descriptor); + } } status_t EventHub::readNotifyLocked() { diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index dd1abeb7a4..f935c3679f 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -21,13 +21,12 @@ #include <input/Flags.h> #include <algorithm> -#include "BatteryInputMapper.h" #include "CursorInputMapper.h" #include "ExternalStylusInputMapper.h" +#include "InputController.h" #include "InputReaderContext.h" #include "JoystickInputMapper.h" #include "KeyboardInputMapper.h" -#include "LightInputMapper.h" #include "MultiTouchInputMapper.h" #include "RotaryEncoderInputMapper.h" #include "SensorInputMapper.h" @@ -131,6 +130,9 @@ void InputDevice::dump(std::string& dump, const std::string& eventHubDevStr) { } for_each_mapper([&dump](InputMapper& mapper) { mapper.dump(dump); }); + if (mController) { + mController->dump(dump); + } } void InputDevice::addEventHubDevice(int32_t eventHubId, bool populateMappers) { @@ -162,22 +164,10 @@ void InputDevice::addEventHubDevice(int32_t eventHubId, bool populateMappers) { mappers.push_back(std::make_unique<VibratorInputMapper>(*contextPtr)); } - // Battery-like devices. Only one battery mapper for each EventHub device. - if (classes.test(InputDeviceClass::BATTERY)) { - InputDeviceInfo deviceInfo; - getDeviceInfo(&deviceInfo); - if (!deviceInfo.hasBattery()) { - mappers.push_back(std::make_unique<BatteryInputMapper>(*contextPtr)); - } - } - - // Light-containing devices. Only one light mapper for each EventHub device. - if (classes.test(InputDeviceClass::LIGHT)) { - InputDeviceInfo deviceInfo; - getDeviceInfo(&deviceInfo); - if (deviceInfo.getLightIds().empty()) { - mappers.push_back(std::make_unique<LightInputMapper>(*contextPtr)); - } + // Battery-like devices or light-containing devices. + // InputController will be created with associated EventHub device. + if (classes.test(InputDeviceClass::BATTERY) || classes.test(InputDeviceClass::LIGHT)) { + mController = std::make_unique<InputController>(*contextPtr); } // Keyboard-like devices. @@ -409,6 +399,10 @@ void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) { mHasMic); for_each_mapper( [outDeviceInfo](InputMapper& mapper) { mapper.populateDeviceInfo(outDeviceInfo); }); + + if (mController) { + mController->populateDeviceInfo(outDeviceInfo); + } } int32_t InputDevice::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { @@ -510,39 +504,30 @@ void InputDevice::cancelTouch(nsecs_t when, nsecs_t readTime) { for_each_mapper([when, readTime](InputMapper& mapper) { mapper.cancelTouch(when, readTime); }); } +// TODO b/180733860 support multiple battery in API and remove this. +constexpr int32_t DEFAULT_BATTERY_ID = 1; std::optional<int32_t> InputDevice::getBatteryCapacity() { - return first_in_mappers<int32_t>( - [](InputMapper& mapper) { return mapper.getBatteryCapacity(); }); + return mController ? mController->getBatteryCapacity(DEFAULT_BATTERY_ID) : std::nullopt; } std::optional<int32_t> InputDevice::getBatteryStatus() { - return first_in_mappers<int32_t>([](InputMapper& mapper) { return mapper.getBatteryStatus(); }); + return mController ? mController->getBatteryStatus(DEFAULT_BATTERY_ID) : std::nullopt; } bool InputDevice::setLightColor(int32_t lightId, int32_t color) { - bool success = true; - for_each_mapper([&success, lightId, color](InputMapper& mapper) { - success &= mapper.setLightColor(lightId, color); - }); - return success; + return mController ? mController->setLightColor(lightId, color) : false; } bool InputDevice::setLightPlayerId(int32_t lightId, int32_t playerId) { - bool success = true; - for_each_mapper([&success, lightId, playerId](InputMapper& mapper) { - success &= mapper.setLightPlayerId(lightId, playerId); - }); - return success; + return mController ? mController->setLightPlayerId(lightId, playerId) : false; } std::optional<int32_t> InputDevice::getLightColor(int32_t lightId) { - return first_in_mappers<int32_t>( - [lightId](InputMapper& mapper) { return mapper.getLightColor(lightId); }); + return mController ? mController->getLightColor(lightId) : std::nullopt; } std::optional<int32_t> InputDevice::getLightPlayerId(int32_t lightId) { - return first_in_mappers<int32_t>( - [lightId](InputMapper& mapper) { return mapper.getLightPlayerId(lightId); }); + return mController ? mController->getLightPlayerId(lightId) : std::nullopt; } int32_t InputDevice::getMetaState() { diff --git a/services/inputflinger/reader/mapper/LightInputMapper.cpp b/services/inputflinger/reader/controller/InputController.cpp index be1f722e2e..45266fbd2d 100644 --- a/services/inputflinger/reader/mapper/LightInputMapper.cpp +++ b/services/inputflinger/reader/controller/InputController.cpp @@ -19,7 +19,7 @@ #include "../Macros.h" -#include "LightInputMapper.h" +#include "InputController.h" #include "input/NamedEnum.h" // Log detailed debug messages about input device lights. @@ -48,27 +48,31 @@ static inline int32_t toArgb(int32_t brightness, int32_t red, int32_t green, int } /** - * Light input mapper owned by InputReader device, implements the native API for querying input + * Input controller owned by InputReader device, implements the native API for querying input * lights, getting and setting the lights brightness and color, by interacting with EventHub * devices. - * TODO b/180342233: Reconsider the inputflinger design to accommodate the device class - * like lights and battery. */ -LightInputMapper::LightInputMapper(InputDeviceContext& deviceContext) - : InputMapper(deviceContext) {} +InputController::InputController(InputDeviceContext& deviceContext) + : mDeviceContext(deviceContext) { + configureBattries(); + configureLights(); +} -LightInputMapper::~LightInputMapper() {} +InputController::~InputController() {} -std::optional<std::int32_t> LightInputMapper::Light::getRawLightBrightness(int32_t rawLightId) { - std::optional<RawLightInfo> rawInfo = context.getRawLightInfo(rawLightId); - std::optional<int32_t> ret = context.getLightBrightness(rawLightId); - if (!rawInfo.has_value() || !ret.has_value()) { +std::optional<std::int32_t> InputController::Light::getRawLightBrightness(int32_t rawLightId) { + std::optional<RawLightInfo> rawInfoOpt = context.getRawLightInfo(rawLightId); + if (!rawInfoOpt.has_value()) { + return std::nullopt; + } + std::optional<int32_t> brightnessOpt = context.getLightBrightness(rawLightId); + if (!brightnessOpt.has_value()) { return std::nullopt; } - int brightness = ret.value(); + int brightness = brightnessOpt.value(); // If the light node doesn't have max brightness, use the default max brightness. - int rawMaxBrightness = rawInfo->maxBrightness.value_or(MAX_BRIGHTNESS); + int rawMaxBrightness = rawInfoOpt->maxBrightness.value_or(MAX_BRIGHTNESS); float ratio = MAX_BRIGHTNESS / rawMaxBrightness; // Scale the returned brightness in [0, rawMaxBrightness] to [0, 255] if (rawMaxBrightness != MAX_BRIGHTNESS) { @@ -81,7 +85,7 @@ std::optional<std::int32_t> LightInputMapper::Light::getRawLightBrightness(int32 return brightness; } -void LightInputMapper::Light::setRawLightBrightness(int32_t rawLightId, int32_t brightness) { +void InputController::Light::setRawLightBrightness(int32_t rawLightId, int32_t brightness) { std::optional<RawLightInfo> rawInfo = context.getRawLightInfo(rawLightId); if (!rawInfo.has_value()) { return; @@ -100,14 +104,14 @@ void LightInputMapper::Light::setRawLightBrightness(int32_t rawLightId, int32_t context.setLightBrightness(rawLightId, brightness); } -bool LightInputMapper::SingleLight::setLightColor(int32_t color) { +bool InputController::SingleLight::setLightColor(int32_t color) { int32_t brightness = getAlpha(color); setRawLightBrightness(rawId, brightness); return true; } -bool LightInputMapper::RgbLight::setLightColor(int32_t color) { +bool InputController::RgbLight::setLightColor(int32_t color) { // Compose color value as per: // https://developer.android.com/reference/android/graphics/Color?hl=en // int color = (A & 0xff) << 24 | (R & 0xff) << 16 | (G & 0xff) << 8 | (B & 0xff); @@ -133,7 +137,7 @@ bool LightInputMapper::RgbLight::setLightColor(int32_t color) { return true; } -bool LightInputMapper::MultiColorLight::setLightColor(int32_t color) { +bool InputController::MultiColorLight::setLightColor(int32_t color) { std::unordered_map<LightColor, int32_t> intensities; intensities.emplace(LightColor::RED, getRed(color)); intensities.emplace(LightColor::GREEN, getGreen(color)); @@ -144,7 +148,7 @@ bool LightInputMapper::MultiColorLight::setLightColor(int32_t color) { return true; } -std::optional<int32_t> LightInputMapper::SingleLight::getLightColor() { +std::optional<int32_t> InputController::SingleLight::getLightColor() { std::optional<int32_t> brightness = getRawLightBrightness(rawId); if (!brightness.has_value()) { return std::nullopt; @@ -153,7 +157,7 @@ std::optional<int32_t> LightInputMapper::SingleLight::getLightColor() { return toArgb(brightness.value(), 0 /* red */, 0 /* green */, 0 /* blue */); } -std::optional<int32_t> LightInputMapper::RgbLight::getLightColor() { +std::optional<int32_t> InputController::RgbLight::getLightColor() { // If the Alpha component is zero, then return color 0. if (brightness == 0) { return 0; @@ -188,7 +192,7 @@ std::optional<int32_t> LightInputMapper::RgbLight::getLightColor() { return toArgb(brightness, red, green, blue); } -std::optional<int32_t> LightInputMapper::MultiColorLight::getLightColor() { +std::optional<int32_t> InputController::MultiColorLight::getLightColor() { auto ret = context.getLightIntensities(rawId); if (!ret.has_value()) { return std::nullopt; @@ -206,7 +210,7 @@ std::optional<int32_t> LightInputMapper::MultiColorLight::getLightColor() { return std::nullopt; } -bool LightInputMapper::PlayerIdLight::setLightPlayerId(int32_t playerId) { +bool InputController::PlayerIdLight::setLightPlayerId(int32_t playerId) { if (rawLightIds.find(playerId) == rawLightIds.end()) { return false; } @@ -220,7 +224,7 @@ bool LightInputMapper::PlayerIdLight::setLightPlayerId(int32_t playerId) { return true; } -std::optional<int32_t> LightInputMapper::PlayerIdLight::getLightPlayerId() { +std::optional<int32_t> InputController::PlayerIdLight::getLightPlayerId() { for (const auto& [id, rawId] : rawLightIds) { std::optional<int32_t> brightness = getRawLightBrightness(rawId); if (brightness.has_value() && brightness.value() > 0) { @@ -230,11 +234,11 @@ std::optional<int32_t> LightInputMapper::PlayerIdLight::getLightPlayerId() { return std::nullopt; } -void LightInputMapper::SingleLight::dump(std::string& dump) { +void InputController::SingleLight::dump(std::string& dump) { dump += StringPrintf(INDENT4 "Color: 0x%x\n", getLightColor().value_or(0)); } -void LightInputMapper::PlayerIdLight::dump(std::string& dump) { +void InputController::PlayerIdLight::dump(std::string& dump) { dump += StringPrintf(INDENT4 "PlayerId: %d\n", getLightPlayerId().value_or(-1)); dump += StringPrintf(INDENT4 "Raw Player ID LEDs:"); for (const auto& [id, rawId] : rawLightIds) { @@ -243,7 +247,7 @@ void LightInputMapper::PlayerIdLight::dump(std::string& dump) { dump += "\n"; } -void LightInputMapper::RgbLight::dump(std::string& dump) { +void InputController::RgbLight::dump(std::string& dump) { dump += StringPrintf(INDENT4 "Color: 0x%x\n", getLightColor().value_or(0)); dump += StringPrintf(INDENT4 "Raw RGB LEDs: [%d, %d, %d] ", rawRgbIds.at(LightColor::RED), rawRgbIds.at(LightColor::GREEN), rawRgbIds.at(LightColor::BLUE)); @@ -253,32 +257,38 @@ void LightInputMapper::RgbLight::dump(std::string& dump) { dump += "\n"; } -void LightInputMapper::MultiColorLight::dump(std::string& dump) { +void InputController::MultiColorLight::dump(std::string& dump) { dump += StringPrintf(INDENT4 "Color: 0x%x\n", getLightColor().value_or(0)); } -uint32_t LightInputMapper::getSources() { - return AINPUT_SOURCE_UNKNOWN; -} +void InputController::populateDeviceInfo(InputDeviceInfo* deviceInfo) { + // TODO: b/180733860 Remove this after enabling multi-battery + if (!mBatteries.empty()) { + deviceInfo->setHasBattery(true); + } -void LightInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); + for (const auto& [batteryId, battery] : mBatteries) { + InputDeviceBatteryInfo batteryInfo(battery->name, battery->id); + deviceInfo->addBatteryInfo(batteryInfo); + } for (const auto& [lightId, light] : mLights) { // Input device light doesn't support ordinal, always pass 1. InputDeviceLightInfo lightInfo(light->name, light->id, light->type, 1 /* ordinal */); - info->addLightInfo(lightInfo); + deviceInfo->addLightInfo(lightInfo); } } -void LightInputMapper::dump(std::string& dump) { - dump += INDENT2 "Light Input Mapper:\n"; - dump += INDENT3 "Lights:\n"; - for (const auto& [lightId, light] : mLights) { - dump += StringPrintf(INDENT4 "Id: %d", lightId); - dump += StringPrintf(INDENT4 "Name: %s", light->name.c_str()); - dump += StringPrintf(INDENT4 "Type: %s", NamedEnum::string(light->type).c_str()); - light->dump(dump); +void InputController::dump(std::string& dump) { + dump += INDENT2 "Input Controller:\n"; + if (!mLights.empty()) { + dump += INDENT3 "Lights:\n"; + for (const auto& [lightId, light] : mLights) { + dump += StringPrintf(INDENT4 "Id: %d", lightId); + dump += StringPrintf(INDENT4 "Name: %s", light->name.c_str()); + dump += StringPrintf(INDENT4 "Type: %s", NamedEnum::string(light->type).c_str()); + light->dump(dump); + } } // Dump raw lights dump += INDENT3 "RawLights:\n"; @@ -298,139 +308,179 @@ void LightInputMapper::dump(std::string& dump) { dump += StringPrintf(INDENT4 "%d\n", getDeviceContext().getLightBrightness(rawId).value_or(-1)); } -} -void LightInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, - uint32_t changes) { - InputMapper::configure(when, config, changes); - - if (!changes) { // first time only - bool hasRedLed = false; - bool hasGreenLed = false; - bool hasBlueLed = false; - std::optional<int32_t> rawGlobalId = std::nullopt; - // Player ID light common name string - std::string playerIdName; - // Raw RGB color to raw light ID - std::unordered_map<LightColor, int32_t /* rawLightId */> rawRgbIds; - // Map from player Id to raw light Id - std::unordered_map<int32_t, int32_t> playerIdLightIds; - mLights.clear(); - - // Check raw lights - const std::vector<int32_t> rawLightIds = getDeviceContext().getRawLightIds(); - // Map from raw light id to raw light info - std::unordered_map<int32_t, RawLightInfo> rawInfos; - for (const auto& rawId : rawLightIds) { - std::optional<RawLightInfo> rawInfo = getDeviceContext().getRawLightInfo(rawId); - if (!rawInfo.has_value()) { - continue; + if (!mBatteries.empty()) { + dump += INDENT3 "Batteries:\n"; + for (const auto& [batteryId, battery] : mBatteries) { + dump += StringPrintf(INDENT4 "Id: %d", batteryId); + dump += StringPrintf(INDENT4 "Name: %s", battery->name.c_str()); + dump += getBatteryCapacity(batteryId).has_value() + ? StringPrintf(INDENT3 "Capacity: %d\n", getBatteryCapacity(batteryId).value()) + : StringPrintf(INDENT3 "Capacity: Unknown"); + + std::string status; + switch (getBatteryStatus(batteryId).value_or(BATTERY_STATUS_UNKNOWN)) { + case BATTERY_STATUS_CHARGING: + status = "Charging"; + break; + case BATTERY_STATUS_DISCHARGING: + status = "Discharging"; + break; + case BATTERY_STATUS_NOT_CHARGING: + status = "Not charging"; + break; + case BATTERY_STATUS_FULL: + status = "Full"; + break; + default: + status = "Unknown"; } - rawInfos.insert_or_assign(rawId, rawInfo.value()); - // Check if this is a group LEDs for player ID - std::regex lightPattern("([a-z]+)([0-9]+)"); - std::smatch results; - if (std::regex_match(rawInfo->name, results, lightPattern)) { - std::string commonName = results[1].str(); - int32_t playerId = std::stoi(results[2]); - if (playerIdLightIds.empty()) { - playerIdName = commonName; + dump += StringPrintf(INDENT3 "Status: %s\n", status.c_str()); + } + } +} + +void InputController::configureBattries() { + // Check raw batteries + const std::vector<int32_t> rawBatteryIds = getDeviceContext().getRawBatteryIds(); + + for (const auto& rawId : rawBatteryIds) { + std::optional<RawBatteryInfo> rawInfo = getDeviceContext().getRawBatteryInfo(rawId); + if (!rawInfo.has_value()) { + continue; + } + std::unique_ptr<Battery> battery = + std::make_unique<Battery>(getDeviceContext(), rawInfo->name, rawInfo->id); + mBatteries.insert_or_assign(rawId, std::move(battery)); + } +} + +void InputController::configureLights() { + bool hasRedLed = false; + bool hasGreenLed = false; + bool hasBlueLed = false; + std::optional<int32_t> rawGlobalId = std::nullopt; + // Player ID light common name string + std::string playerIdName; + // Raw RGB color to raw light ID + std::unordered_map<LightColor, int32_t /* rawLightId */> rawRgbIds; + // Map from player Id to raw light Id + std::unordered_map<int32_t, int32_t> playerIdLightIds; + + // Check raw lights + const std::vector<int32_t> rawLightIds = getDeviceContext().getRawLightIds(); + // Map from raw light id to raw light info + std::unordered_map<int32_t, RawLightInfo> rawInfos; + for (const auto& rawId : rawLightIds) { + std::optional<RawLightInfo> rawInfo = getDeviceContext().getRawLightInfo(rawId); + if (!rawInfo.has_value()) { + continue; + } + rawInfos.insert_or_assign(rawId, rawInfo.value()); + // Check if this is a group LEDs for player ID + std::regex lightPattern("([a-z]+)([0-9]+)"); + std::smatch results; + if (std::regex_match(rawInfo->name, results, lightPattern)) { + std::string commonName = results[1].str(); + int32_t playerId = std::stoi(results[2]); + if (playerIdLightIds.empty()) { + playerIdName = commonName; + playerIdLightIds.insert_or_assign(playerId, rawId); + } else { + // Make sure the player ID leds have common string name + if (playerIdName.compare(commonName) == 0 && + playerIdLightIds.find(playerId) == playerIdLightIds.end()) { playerIdLightIds.insert_or_assign(playerId, rawId); - } else { - // Make sure the player ID leds have common string name - if (playerIdName.compare(commonName) == 0 && - playerIdLightIds.find(playerId) == playerIdLightIds.end()) { - playerIdLightIds.insert_or_assign(playerId, rawId); - } } } - // Check if this is an LED of RGB light - if (rawInfo->flags.test(InputLightClass::RED)) { - hasRedLed = true; - rawRgbIds.emplace(LightColor::RED, rawId); - } - if (rawInfo->flags.test(InputLightClass::GREEN)) { - hasGreenLed = true; - rawRgbIds.emplace(LightColor::GREEN, rawId); - } - if (rawInfo->flags.test(InputLightClass::BLUE)) { - hasBlueLed = true; - rawRgbIds.emplace(LightColor::BLUE, rawId); - } - if (rawInfo->flags.test(InputLightClass::GLOBAL)) { - rawGlobalId = rawId; - } - if (DEBUG_LIGHT_DETAILS) { - ALOGD("Light rawId %d name %s max %d flags %s \n", rawInfo->id, - rawInfo->name.c_str(), rawInfo->maxBrightness.value_or(MAX_BRIGHTNESS), - rawInfo->flags.string().c_str()); - } } + // Check if this is an LED of RGB light + if (rawInfo->flags.test(InputLightClass::RED)) { + hasRedLed = true; + rawRgbIds.emplace(LightColor::RED, rawId); + } + if (rawInfo->flags.test(InputLightClass::GREEN)) { + hasGreenLed = true; + rawRgbIds.emplace(LightColor::GREEN, rawId); + } + if (rawInfo->flags.test(InputLightClass::BLUE)) { + hasBlueLed = true; + rawRgbIds.emplace(LightColor::BLUE, rawId); + } + if (rawInfo->flags.test(InputLightClass::GLOBAL)) { + rawGlobalId = rawId; + } + if (DEBUG_LIGHT_DETAILS) { + ALOGD("Light rawId %d name %s max %d flags %s \n", rawInfo->id, rawInfo->name.c_str(), + rawInfo->maxBrightness.value_or(MAX_BRIGHTNESS), rawInfo->flags.string().c_str()); + } + } - // Construct a player ID light - if (playerIdLightIds.size() > 1) { - std::unique_ptr<Light> light = - std::make_unique<PlayerIdLight>(getDeviceContext(), playerIdName, ++mNextId, - playerIdLightIds); - mLights.insert_or_assign(light->id, std::move(light)); - // Remove these raw lights from raw light info as they've been used to compose a - // Player ID light, so we do not expose these raw lights as single lights. - for (const auto& [playerId, rawId] : playerIdLightIds) { - rawInfos.erase(rawId); - } + // Construct a player ID light + if (playerIdLightIds.size() > 1) { + std::unique_ptr<Light> light = + std::make_unique<PlayerIdLight>(getDeviceContext(), playerIdName, ++mNextId, + playerIdLightIds); + mLights.insert_or_assign(light->id, std::move(light)); + // Remove these raw lights from raw light info as they've been used to compose a + // Player ID light, so we do not expose these raw lights as single lights. + for (const auto& [playerId, rawId] : playerIdLightIds) { + rawInfos.erase(rawId); } - // Construct a RGB light for composed RGB light - if (hasRedLed && hasGreenLed && hasBlueLed) { - if (DEBUG_LIGHT_DETAILS) { - ALOGD("Rgb light ids [%d, %d, %d] \n", rawRgbIds.at(LightColor::RED), - rawRgbIds.at(LightColor::GREEN), rawRgbIds.at(LightColor::BLUE)); - } - std::unique_ptr<Light> light = std::make_unique<RgbLight>(getDeviceContext(), ++mNextId, - rawRgbIds, rawGlobalId); - mLights.insert_or_assign(light->id, std::move(light)); - // Remove from raw light info as they've been composed a RBG light. - rawInfos.erase(rawRgbIds.at(LightColor::RED)); - rawInfos.erase(rawRgbIds.at(LightColor::GREEN)); - rawInfos.erase(rawRgbIds.at(LightColor::BLUE)); - if (rawGlobalId.has_value()) { - rawInfos.erase(rawGlobalId.value()); - } + } + // Construct a RGB light for composed RGB light + if (hasRedLed && hasGreenLed && hasBlueLed) { + if (DEBUG_LIGHT_DETAILS) { + ALOGD("Rgb light ids [%d, %d, %d] \n", rawRgbIds.at(LightColor::RED), + rawRgbIds.at(LightColor::GREEN), rawRgbIds.at(LightColor::BLUE)); + } + std::unique_ptr<Light> light = + std::make_unique<RgbLight>(getDeviceContext(), ++mNextId, rawRgbIds, rawGlobalId); + mLights.insert_or_assign(light->id, std::move(light)); + // Remove from raw light info as they've been composed a RBG light. + rawInfos.erase(rawRgbIds.at(LightColor::RED)); + rawInfos.erase(rawRgbIds.at(LightColor::GREEN)); + rawInfos.erase(rawRgbIds.at(LightColor::BLUE)); + if (rawGlobalId.has_value()) { + rawInfos.erase(rawGlobalId.value()); } + } - // Check the rest of raw light infos - for (const auto& [rawId, rawInfo] : rawInfos) { - // If the node is multi-color led, construct a MULTI_COLOR light - if (rawInfo.flags.test(InputLightClass::MULTI_INDEX) && - rawInfo.flags.test(InputLightClass::MULTI_INTENSITY)) { - if (DEBUG_LIGHT_DETAILS) { - ALOGD("Multicolor light Id %d name %s \n", rawInfo.id, rawInfo.name.c_str()); - } - std::unique_ptr<Light> light = - std::make_unique<MultiColorLight>(getDeviceContext(), rawInfo.name, - ++mNextId, rawInfo.id); - mLights.insert_or_assign(light->id, std::move(light)); - continue; - } - // Construct a single LED light + // Check the rest of raw light infos + for (const auto& [rawId, rawInfo] : rawInfos) { + // If the node is multi-color led, construct a MULTI_COLOR light + if (rawInfo.flags.test(InputLightClass::MULTI_INDEX) && + rawInfo.flags.test(InputLightClass::MULTI_INTENSITY)) { if (DEBUG_LIGHT_DETAILS) { - ALOGD("Single light Id %d name %s \n", rawInfo.id, rawInfo.name.c_str()); + ALOGD("Multicolor light Id %d name %s \n", rawInfo.id, rawInfo.name.c_str()); } std::unique_ptr<Light> light = - std::make_unique<SingleLight>(getDeviceContext(), rawInfo.name, ++mNextId, - rawInfo.id); - + std::make_unique<MultiColorLight>(getDeviceContext(), rawInfo.name, ++mNextId, + rawInfo.id); mLights.insert_or_assign(light->id, std::move(light)); + continue; } + // Construct a single LED light + if (DEBUG_LIGHT_DETAILS) { + ALOGD("Single light Id %d name %s \n", rawInfo.id, rawInfo.name.c_str()); + } + std::unique_ptr<Light> light = + std::make_unique<SingleLight>(getDeviceContext(), rawInfo.name, ++mNextId, + rawInfo.id); + + mLights.insert_or_assign(light->id, std::move(light)); } } -void LightInputMapper::reset(nsecs_t when) { - InputMapper::reset(when); +std::optional<int32_t> InputController::getBatteryCapacity(int batteryId) { + return getDeviceContext().getBatteryCapacity(batteryId); } -void LightInputMapper::process(const RawEvent* rawEvent) {} +std::optional<int32_t> InputController::getBatteryStatus(int batteryId) { + return getDeviceContext().getBatteryStatus(batteryId); +} -bool LightInputMapper::setLightColor(int32_t lightId, int32_t color) { +bool InputController::setLightColor(int32_t lightId, int32_t color) { auto it = mLights.find(lightId); if (it == mLights.end()) { return false; @@ -443,7 +493,7 @@ bool LightInputMapper::setLightColor(int32_t lightId, int32_t color) { return light->setLightColor(color); } -std::optional<int32_t> LightInputMapper::getLightColor(int32_t lightId) { +std::optional<int32_t> InputController::getLightColor(int32_t lightId) { auto it = mLights.find(lightId); if (it == mLights.end()) { return std::nullopt; @@ -457,7 +507,7 @@ std::optional<int32_t> LightInputMapper::getLightColor(int32_t lightId) { return color; } -bool LightInputMapper::setLightPlayerId(int32_t lightId, int32_t playerId) { +bool InputController::setLightPlayerId(int32_t lightId, int32_t playerId) { auto it = mLights.find(lightId); if (it == mLights.end()) { return false; @@ -466,7 +516,7 @@ bool LightInputMapper::setLightPlayerId(int32_t lightId, int32_t playerId) { return light->setLightPlayerId(playerId); } -std::optional<int32_t> LightInputMapper::getLightPlayerId(int32_t lightId) { +std::optional<int32_t> InputController::getLightPlayerId(int32_t lightId) { auto it = mLights.find(lightId); if (it == mLights.end()) { return std::nullopt; diff --git a/services/inputflinger/reader/mapper/LightInputMapper.h b/services/inputflinger/reader/controller/InputController.h index 43141b87c0..d4222e2804 100644 --- a/services/inputflinger/reader/mapper/LightInputMapper.h +++ b/services/inputflinger/reader/controller/InputController.h @@ -14,35 +14,49 @@ * limitations under the License. */ -#ifndef _UI_INPUTREADER_LIGHT_INPUT_MAPPER_H -#define _UI_INPUTREADER_LIGHT_INPUT_MAPPER_H +#ifndef _UI_INPUTREADER_LIGHT_CONTROLLER_H +#define _UI_INPUTREADER_LIGHT_CONTROLLER_H -#include "InputMapper.h" +#include "InputControllerInterface.h" namespace android { -class LightInputMapper : public InputMapper { +class InputController : public InputControllerInterface { // Refer to https://developer.android.com/reference/kotlin/android/graphics/Color /* Number of colors : {red, green, blue} */ static constexpr size_t COLOR_NUM = 3; static constexpr int32_t MAX_BRIGHTNESS = 0xff; public: - explicit LightInputMapper(InputDeviceContext& deviceContext); - ~LightInputMapper() override; + explicit InputController(InputDeviceContext& deviceContext); + ~InputController() override; - uint32_t getSources() override; void populateDeviceInfo(InputDeviceInfo* deviceInfo) override; void dump(std::string& dump) override; - void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) override; - void reset(nsecs_t when) override; - void process(const RawEvent* rawEvent) override; bool setLightColor(int32_t lightId, int32_t color) override; bool setLightPlayerId(int32_t lightId, int32_t playerId) override; std::optional<int32_t> getLightColor(int32_t lightId) override; std::optional<int32_t> getLightPlayerId(int32_t lightId) override; + std::optional<int32_t> getBatteryCapacity(int32_t batteryId) override; + std::optional<int32_t> getBatteryStatus(int32_t batteryId) override; private: + inline int32_t getDeviceId() { return mDeviceContext.getId(); } + inline InputDeviceContext& getDeviceContext() { return mDeviceContext; } + + InputDeviceContext& mDeviceContext; + void configureLights(); + void configureBattries(); + + struct Battery { + explicit Battery(InputDeviceContext& context, const std::string& name, int32_t id) + : context(context), name(name), id(id) {} + virtual ~Battery() {} + InputDeviceContext& context; + std::string name; + int32_t id; + }; + struct Light { explicit Light(InputDeviceContext& context, const std::string& name, int32_t id, InputDeviceLightType type) @@ -128,8 +142,11 @@ private: // Light map from light ID to Light std::unordered_map<int32_t, std::unique_ptr<Light>> mLights; + + // Battery map from battery ID to battery + std::unordered_map<int32_t, std::unique_ptr<Battery>> mBatteries; }; } // namespace android -#endif // _UI_INPUTREADER_LIGHT_INPUT_MAPPER_H +#endif // _UI_INPUTREADER_LIGHT_CONTROLLER_H diff --git a/services/inputflinger/reader/controller/InputControllerInterface.h b/services/inputflinger/reader/controller/InputControllerInterface.h new file mode 100644 index 0000000000..504ededf9d --- /dev/null +++ b/services/inputflinger/reader/controller/InputControllerInterface.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _UI_INPUTREADER_INPUT_CONTROLLER_H +#define _UI_INPUTREADER_INPUT_CONTROLLER_H + +#include "EventHub.h" +#include "InputDevice.h" +#include "InputListener.h" +#include "InputReaderContext.h" + +namespace android { + +/* An input controller manages the miscellaneous devices associated with the input device, + * like the sysfs based battery and light class devices. + * + */ +class InputControllerInterface { +public: + InputControllerInterface() {} + virtual ~InputControllerInterface() {} + + // Interface methods for Battery + virtual std::optional<int32_t> getBatteryCapacity(int32_t batteryId) = 0; + virtual std::optional<int32_t> getBatteryStatus(int32_t batteryId) = 0; + + // Interface methods for Light + virtual bool setLightColor(int32_t lightId, int32_t color) = 0; + virtual bool setLightPlayerId(int32_t lightId, int32_t playerId) = 0; + virtual std::optional<int32_t> getLightColor(int32_t lightId) = 0; + virtual std::optional<int32_t> getLightPlayerId(int32_t lightId) = 0; + + virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) = 0; + virtual void dump(std::string& dump) = 0; +}; + +} // namespace android + +#endif // _UI_INPUTREADER_INPUT_CONTROLLER_H diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h index 2afaa85e8a..c970c8bcda 100644 --- a/services/inputflinger/reader/include/EventHub.h +++ b/services/inputflinger/reader/include/EventHub.h @@ -173,6 +173,15 @@ enum class InputLightClass : uint32_t { MAX_BRIGHTNESS = 0x00000080, }; +enum class InputBatteryClass : uint32_t { + /* The input device battery has capacity node. */ + CAPACITY = 0x00000001, + /* The input device battery has capacity_level node. */ + CAPACITY_LEVEL = 0x00000002, + /* The input device battery has status node. */ + STATUS = 0x00000004, +}; + /* Describes a raw light. */ struct RawLightInfo { int32_t id; @@ -183,6 +192,14 @@ struct RawLightInfo { std::filesystem::path path; }; +/* Describes a raw battery. */ +struct RawBatteryInfo { + int32_t id; + std::string name; + Flags<InputBatteryClass> flags; + std::filesystem::path path; +}; + /* * Gets the class that owns an axis, in cases where multiple classes might claim * the same axis for different purposes. @@ -263,6 +280,12 @@ public: virtual std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) = 0; virtual base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor(int32_t deviceId, int32_t absCode) = 0; + // Raw batteries are sysfs power_supply nodes we found from the EventHub device sysfs node, + // containing the raw info of the sysfs node structure. + virtual const std::vector<int32_t> getRawBatteryIds(int32_t deviceId) = 0; + virtual std::optional<RawBatteryInfo> getRawBatteryInfo(int32_t deviceId, + int32_t BatteryId) = 0; + // Raw lights are sysfs led light nodes we found from the EventHub device sysfs node, // containing the raw info of the sysfs node structure. virtual const std::vector<int32_t> getRawLightIds(int32_t deviceId) = 0; @@ -307,10 +330,11 @@ public: virtual std::vector<int32_t> getVibratorIds(int32_t deviceId) = 0; /* Query battery level. */ - virtual std::optional<int32_t> getBatteryCapacity(int32_t deviceId) const = 0; + virtual std::optional<int32_t> getBatteryCapacity(int32_t deviceId, + int32_t batteryId) const = 0; /* Query battery status. */ - virtual std::optional<int32_t> getBatteryStatus(int32_t deviceId) const = 0; + virtual std::optional<int32_t> getBatteryStatus(int32_t deviceId, int32_t batteryId) const = 0; /* Requests the EventHub to reopen all input devices on the next call to getEvents(). */ virtual void requestReopenDevices() = 0; @@ -435,6 +459,10 @@ public: base::Result<std::pair<InputDeviceSensorType, int32_t>> mapSensor( int32_t deviceId, int32_t absCode) override final; + const std::vector<int32_t> getRawBatteryIds(int32_t deviceId) override final; + std::optional<RawBatteryInfo> getRawBatteryInfo(int32_t deviceId, + int32_t BatteryId) override final; + const std::vector<int32_t> getRawLightIds(int32_t deviceId) override final; std::optional<RawLightInfo> getRawLightInfo(int32_t deviceId, int32_t lightId) override final; @@ -485,9 +513,11 @@ public: void monitor() override final; - std::optional<int32_t> getBatteryCapacity(int32_t deviceId) const override final; + std::optional<int32_t> getBatteryCapacity(int32_t deviceId, + int32_t batteryId) const override final; - std::optional<int32_t> getBatteryStatus(int32_t deviceId) const override final; + std::optional<int32_t> getBatteryStatus(int32_t deviceId, + int32_t batteryId) const override final; bool isDeviceEnabled(int32_t deviceId) override final; @@ -498,6 +528,22 @@ public: ~EventHub() override; private: + struct MiscDevice { + // The device descriptor from evdev device the misc device associated with. + std::string descriptor; + // The sysfs root path of the misc device. + std::filesystem::path sysfsRootPath; + + int32_t nextBatteryId; + int32_t nextLightId; + std::unordered_map<int32_t, RawBatteryInfo> batteryInfos; + std::unordered_map<int32_t, RawLightInfo> lightInfos; + explicit MiscDevice(std::filesystem::path sysfsRootPath) + : sysfsRootPath(sysfsRootPath), nextBatteryId(0), nextLightId(0) {} + bool configureBatteryLocked(); + bool configureLightsLocked(); + }; + struct Device { int fd; // may be -1 if device is closed const int32_t id; @@ -527,12 +573,7 @@ private: bool ffEffectPlaying; int16_t ffEffectId; // initially -1 - // The paths are invalid when they're std::nullopt - std::optional<std::filesystem::path> sysfsRootPath; - std::optional<std::filesystem::path> sysfsBatteryPath; - // maps from light id to light info - std::unordered_map<int32_t, RawLightInfo> lightInfos; - int32_t nextLightId; + std::shared_ptr<MiscDevice> miscDevice; int32_t controllerNumber; @@ -563,8 +604,6 @@ private: void setLedForControllerLocked(); status_t mapLed(int32_t led, int32_t* outScanCode) const; void setLedStateLocked(int32_t led, bool on); - bool configureBatteryLocked(); - bool configureLightsLocked(); }; /** @@ -616,6 +655,12 @@ private: void reportDeviceAddedForStatisticsLocked(const InputDeviceIdentifier& identifier, Flags<InputDeviceClass> classes) REQUIRES(mLock); + const std::unordered_map<int32_t, RawBatteryInfo>& getBatteryInfoLocked(int32_t deviceId) const + REQUIRES(mLock); + + const std::unordered_map<int32_t, RawLightInfo>& getLightInfoLocked(int32_t deviceId) const + REQUIRES(mLock); + // Protect all internal state. mutable std::mutex mLock; @@ -645,6 +690,11 @@ private: std::vector<std::unique_ptr<Device>> mOpeningDevices; std::vector<std::unique_ptr<Device>> mClosingDevices; + // Map from std::string descriptor, to a shared_ptr of a miscellaneous device associated with + // the input device. The descriptor is the same from the EventHub device which it associates + // with. + std::unordered_map<std::string, std::shared_ptr<MiscDevice>> mMiscDevices; + bool mNeedToSendFinishedDeviceScan; bool mNeedToReopenDevices; bool mNeedToScanDevices; diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h index 863cd41fc9..5d56f5a2ef 100644 --- a/services/inputflinger/reader/include/InputDevice.h +++ b/services/inputflinger/reader/include/InputDevice.h @@ -33,6 +33,8 @@ namespace android { +class InputController; +class InputControllerInterface; class InputDeviceContext; class InputMapper; @@ -131,6 +133,20 @@ public: return *mapper; } + // construct and add a controller to the input device + template <class T> + T& addController(int32_t eventHubId) { + // ensure a device entry exists for this eventHubId + addEventHubDevice(eventHubId, false); + + // create controller + auto& devicePair = mDevices[eventHubId]; + auto& deviceContext = devicePair.first; + + mController = std::make_unique<T>(*deviceContext); + return *(reinterpret_cast<T*>(mController.get())); + } + private: InputReaderContext* mContext; int32_t mId; @@ -143,7 +159,10 @@ private: // map from eventHubId to device context and mappers using MapperVector = std::vector<std::unique_ptr<InputMapper>>; using DevicePair = std::pair<std::unique_ptr<InputDeviceContext>, MapperVector>; + // Map from EventHub ID to pair of device context and vector of mapper. std::unordered_map<int32_t, DevicePair> mDevices; + // Misc devices controller for lights, battery, etc. + std::unique_ptr<InputControllerInterface> mController; uint32_t mSources; bool mIsExternal; @@ -319,11 +338,21 @@ public: inline std::vector<int32_t> getVibratorIds() { return mEventHub->getVibratorIds(mId); } - inline std::optional<int32_t> getBatteryCapacity() { - return mEventHub->getBatteryCapacity(mId); + inline const std::vector<int32_t> getRawBatteryIds() { + return mEventHub->getRawBatteryIds(mId); + } + + inline std::optional<RawBatteryInfo> getRawBatteryInfo(int32_t batteryId) { + return mEventHub->getRawBatteryInfo(mId, batteryId); } - inline std::optional<int32_t> getBatteryStatus() { return mEventHub->getBatteryStatus(mId); } + inline std::optional<int32_t> getBatteryCapacity(int32_t batteryId) { + return mEventHub->getBatteryCapacity(mId, batteryId); + } + + inline std::optional<int32_t> getBatteryStatus(int32_t batteryId) { + return mEventHub->getBatteryStatus(mId, batteryId); + } inline bool hasAbsoluteAxis(int32_t code) const { RawAbsoluteAxisInfo info; diff --git a/services/inputflinger/reader/mapper/BatteryInputMapper.cpp b/services/inputflinger/reader/mapper/BatteryInputMapper.cpp deleted file mode 100644 index e4fb3a6c9f..0000000000 --- a/services/inputflinger/reader/mapper/BatteryInputMapper.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2021 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 "../Macros.h" - -#include "BatteryInputMapper.h" - -namespace android { - -BatteryInputMapper::BatteryInputMapper(InputDeviceContext& deviceContext) - : InputMapper(deviceContext) {} - -uint32_t BatteryInputMapper::getSources() { - return AINPUT_SOURCE_UNKNOWN; -} - -void BatteryInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - info->setHasBattery(true); -} - -void BatteryInputMapper::process(const RawEvent* rawEvent) {} - -std::optional<int32_t> BatteryInputMapper::getBatteryCapacity() { - return getDeviceContext().getBatteryCapacity(); -} - -std::optional<int32_t> BatteryInputMapper::getBatteryStatus() { - return getDeviceContext().getBatteryStatus(); -} - -void BatteryInputMapper::dump(std::string& dump) { - dump += INDENT2 "Battery Input Mapper:\n"; - dump += getBatteryCapacity().has_value() - ? StringPrintf(INDENT3 "Capacity: %d\n", getBatteryCapacity().value()) - : StringPrintf(INDENT3 "Capacity: Unknown"); - - std::string status; - switch (getBatteryStatus().value_or(BATTERY_STATUS_UNKNOWN)) { - case BATTERY_STATUS_CHARGING: - status = "Charging"; - break; - case BATTERY_STATUS_DISCHARGING: - status = "Discharging"; - break; - case BATTERY_STATUS_NOT_CHARGING: - status = "Not charging"; - break; - case BATTERY_STATUS_FULL: - status = "Full"; - break; - default: - status = "Unknown"; - } - dump += StringPrintf(INDENT3 "Status: %s\n", status.c_str()); -} - -} // namespace android diff --git a/services/inputflinger/reader/mapper/BatteryInputMapper.h b/services/inputflinger/reader/mapper/BatteryInputMapper.h deleted file mode 100644 index 4fe373e2ca..0000000000 --- a/services/inputflinger/reader/mapper/BatteryInputMapper.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _UI_INPUTREADER_BATTERY_INPUT_MAPPER_H -#define _UI_INPUTREADER_BATTERY_INPUT_MAPPER_H - -#include "InputMapper.h" - -namespace android { - -class BatteryInputMapper : public InputMapper { -public: - explicit BatteryInputMapper(InputDeviceContext& deviceContext); - virtual ~BatteryInputMapper(){}; - - uint32_t getSources() override; - void populateDeviceInfo(InputDeviceInfo* deviceInfo) override; - void process(const RawEvent* rawEvent) override; - - std::optional<int32_t> getBatteryCapacity() override; - std::optional<int32_t> getBatteryStatus() override; - - void dump(std::string& dump) override; -}; - -} // namespace android - -#endif // _UI_INPUTREADER_BATTERY_INPUT_MAPPER_H diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index d69bb6a303..3d99a6b863 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -14,15 +14,14 @@ * limitations under the License. */ -#include <BatteryInputMapper.h> #include <CursorInputMapper.h> +#include <InputController.h> #include <InputDevice.h> #include <InputMapper.h> #include <InputReader.h> #include <InputReaderBase.h> #include <InputReaderFactory.h> #include <KeyboardInputMapper.h> -#include <LightInputMapper.h> #include <MultiTouchInputMapper.h> #include <SensorInputMapper.h> #include <SingleTouchInputMapper.h> @@ -71,6 +70,7 @@ static constexpr int32_t INVALID_TRACKING_ID = -1; static constexpr int32_t FIRST_TRACKING_ID = 0; static constexpr int32_t SECOND_TRACKING_ID = 1; static constexpr int32_t THIRD_TRACKING_ID = 2; +static constexpr int32_t DEFAULT_BATTERY = 1; static constexpr int32_t BATTERY_STATUS = 4; static constexpr int32_t BATTERY_CAPACITY = 66; static constexpr int32_t LIGHT_BRIGHTNESS = 0x55000000; @@ -895,9 +895,19 @@ private: std::vector<int32_t> getVibratorIds(int32_t deviceId) override { return mVibrators; }; - std::optional<int32_t> getBatteryCapacity(int32_t) const override { return BATTERY_CAPACITY; } + std::optional<int32_t> getBatteryCapacity(int32_t, int32_t) const override { + return BATTERY_CAPACITY; + } + + std::optional<int32_t> getBatteryStatus(int32_t, int32_t) const override { + return BATTERY_STATUS; + } - std::optional<int32_t> getBatteryStatus(int32_t) const override { return BATTERY_STATUS; } + const std::vector<int32_t> getRawBatteryIds(int32_t deviceId) { return {}; } + + std::optional<RawBatteryInfo> getRawBatteryInfo(int32_t deviceId, int32_t batteryId) { + return std::nullopt; + } const std::vector<int32_t> getRawLightIds(int32_t deviceId) override { std::vector<int32_t> ids; @@ -2005,18 +2015,47 @@ TEST_F(InputReaderTest, VibratorGetVibratorIds) { ASSERT_EQ(mReader->getVibratorIds(deviceId).size(), 2U); } -class FakeBatteryInputMapper : public FakeInputMapper { +// --- FakeInputController --- + +class FakeInputController : public InputControllerInterface { public: - FakeBatteryInputMapper(InputDeviceContext& deviceContext, uint32_t sources) - : FakeInputMapper(deviceContext, sources) {} + FakeInputController(InputDeviceContext& deviceContext) : mDeviceContext(deviceContext) {} + + ~FakeInputController() override {} + + void populateDeviceInfo(InputDeviceInfo* deviceInfo) override {} + + void dump(std::string& dump) override {} - std::optional<int32_t> getBatteryCapacity() override { - return getDeviceContext().getBatteryCapacity(); + std::optional<int32_t> getBatteryCapacity(int32_t batteryId) override { + return getDeviceContext().getBatteryCapacity(batteryId); } - std::optional<int32_t> getBatteryStatus() override { - return getDeviceContext().getBatteryStatus(); + std::optional<int32_t> getBatteryStatus(int32_t batteryId) override { + return getDeviceContext().getBatteryStatus(batteryId); } + + bool setLightColor(int32_t lightId, int32_t color) override { + getDeviceContext().setLightBrightness(lightId, color >> 24); + return true; + } + + std::optional<int32_t> getLightColor(int32_t lightId) override { + std::optional<int32_t> result = getDeviceContext().getLightBrightness(lightId); + if (!result.has_value()) { + return std::nullopt; + } + return result.value() << 24; + } + + bool setLightPlayerId(int32_t lightId, int32_t playerId) override { return true; } + + std::optional<int32_t> getLightPlayerId(int32_t lightId) override { return std::nullopt; } + +private: + InputDeviceContext& mDeviceContext; + inline int32_t getDeviceId() { return mDeviceContext.getId(); } + inline InputDeviceContext& getDeviceContext() { return mDeviceContext; } }; TEST_F(InputReaderTest, BatteryGetCapacity) { @@ -2025,13 +2064,12 @@ TEST_F(InputReaderTest, BatteryGetCapacity) { constexpr int32_t eventHubId = 1; const char* DEVICE_LOCATION = "BLUETOOTH"; std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION); - FakeBatteryInputMapper& mapper = - device->addMapper<FakeBatteryInputMapper>(eventHubId, AINPUT_SOURCE_KEYBOARD); + FakeInputController& controller = device->addController<FakeInputController>(eventHubId); mReader->pushNextDevice(device); ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr)); - ASSERT_NO_FATAL_FAILURE(mapper.assertConfigureWasCalled()); + ASSERT_EQ(controller.getBatteryCapacity(DEFAULT_BATTERY), BATTERY_CAPACITY); ASSERT_EQ(mReader->getBatteryCapacity(deviceId), BATTERY_CAPACITY); } @@ -2041,43 +2079,22 @@ TEST_F(InputReaderTest, BatteryGetStatus) { constexpr int32_t eventHubId = 1; const char* DEVICE_LOCATION = "BLUETOOTH"; std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION); - FakeBatteryInputMapper& mapper = - device->addMapper<FakeBatteryInputMapper>(eventHubId, AINPUT_SOURCE_KEYBOARD); + FakeInputController& controller = device->addController<FakeInputController>(eventHubId); mReader->pushNextDevice(device); ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr)); - ASSERT_NO_FATAL_FAILURE(mapper.assertConfigureWasCalled()); + ASSERT_EQ(controller.getBatteryStatus(DEFAULT_BATTERY), BATTERY_STATUS); ASSERT_EQ(mReader->getBatteryStatus(deviceId), BATTERY_STATUS); } -class FakeLightInputMapper : public FakeInputMapper { -public: - FakeLightInputMapper(InputDeviceContext& deviceContext, uint32_t sources) - : FakeInputMapper(deviceContext, sources) {} - - bool setLightColor(int32_t lightId, int32_t color) override { - getDeviceContext().setLightBrightness(lightId, color >> 24); - return true; - } - - std::optional<int32_t> getLightColor(int32_t lightId) override { - std::optional<int32_t> result = getDeviceContext().getLightBrightness(lightId); - if (!result.has_value()) { - return std::nullopt; - } - return result.value() << 24; - } -}; - TEST_F(InputReaderTest, LightGetColor) { constexpr int32_t deviceId = END_RESERVED_ID + 1000; Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::LIGHT; constexpr int32_t eventHubId = 1; const char* DEVICE_LOCATION = "BLUETOOTH"; std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION); - FakeLightInputMapper& mapper = - device->addMapper<FakeLightInputMapper>(eventHubId, AINPUT_SOURCE_KEYBOARD); + FakeInputController& controller = device->addController<FakeInputController>(eventHubId); mReader->pushNextDevice(device); RawLightInfo info = {.id = 1, .name = "Mono", @@ -2088,8 +2105,9 @@ TEST_F(InputReaderTest, LightGetColor) { mFakeEventHub->fakeLightBrightness(1 /* rawId */, 0x55); ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr)); - ASSERT_NO_FATAL_FAILURE(mapper.assertConfigureWasCalled()); + ASSERT_TRUE(controller.setLightColor(1 /* lightId */, LIGHT_BRIGHTNESS)); + ASSERT_EQ(controller.getLightColor(1 /* lightId */), LIGHT_BRIGHTNESS); ASSERT_TRUE(mReader->setLightColor(deviceId, 1 /* lightId */, LIGHT_BRIGHTNESS)); ASSERT_EQ(mReader->getLightColor(deviceId, 1 /* lightId */), LIGHT_BRIGHTNESS); } @@ -2989,154 +3007,6 @@ TEST_F(SensorInputMapperTest, ProcessGyroscopeSensor) { mapper.flushSensor(InputDeviceSensorType::GYROSCOPE); } -// --- BatteryInputMapperTest --- -class BatteryInputMapperTest : public InputMapperTest { -protected: - void SetUp() override { InputMapperTest::SetUp(DEVICE_CLASSES | InputDeviceClass::BATTERY); } -}; - -TEST_F(BatteryInputMapperTest, GetSources) { - BatteryInputMapper& mapper = addMapperAndConfigure<BatteryInputMapper>(); - - ASSERT_EQ(AINPUT_SOURCE_UNKNOWN, mapper.getSources()); -} - -TEST_F(BatteryInputMapperTest, GetBatteryCapacity) { - BatteryInputMapper& mapper = addMapperAndConfigure<BatteryInputMapper>(); - - ASSERT_TRUE(mapper.getBatteryCapacity()); - ASSERT_EQ(mapper.getBatteryCapacity().value_or(-1), BATTERY_CAPACITY); -} - -TEST_F(BatteryInputMapperTest, GetBatteryStatus) { - BatteryInputMapper& mapper = addMapperAndConfigure<BatteryInputMapper>(); - - ASSERT_TRUE(mapper.getBatteryStatus()); - ASSERT_EQ(mapper.getBatteryStatus().value_or(-1), BATTERY_STATUS); -} - -// --- LightInputMapperTest --- -class LightInputMapperTest : public InputMapperTest { -protected: - void SetUp() override { InputMapperTest::SetUp(DEVICE_CLASSES | InputDeviceClass::LIGHT); } -}; - -TEST_F(LightInputMapperTest, GetSources) { - LightInputMapper& mapper = addMapperAndConfigure<LightInputMapper>(); - - ASSERT_EQ(AINPUT_SOURCE_UNKNOWN, mapper.getSources()); -} - -TEST_F(LightInputMapperTest, SingleLight) { - RawLightInfo infoSingle = {.id = 1, - .name = "Mono", - .maxBrightness = 255, - .flags = InputLightClass::BRIGHTNESS, - .path = ""}; - mFakeEventHub->addRawLightInfo(infoSingle.id, std::move(infoSingle)); - - LightInputMapper& mapper = addMapperAndConfigure<LightInputMapper>(); - InputDeviceInfo info; - mapper.populateDeviceInfo(&info); - const auto& ids = info.getLightIds(); - ASSERT_EQ(1UL, ids.size()); - ASSERT_EQ(InputDeviceLightType::SINGLE, info.getLightInfo(ids[0])->type); - - ASSERT_TRUE(mapper.setLightColor(ids[0], LIGHT_BRIGHTNESS)); - ASSERT_EQ(mapper.getLightColor(ids[0]).value_or(-1), LIGHT_BRIGHTNESS); -} - -TEST_F(LightInputMapperTest, RGBLight) { - RawLightInfo infoRed = {.id = 1, - .name = "red", - .maxBrightness = 255, - .flags = InputLightClass::BRIGHTNESS | InputLightClass::RED, - .path = ""}; - RawLightInfo infoGreen = {.id = 2, - .name = "green", - .maxBrightness = 255, - .flags = InputLightClass::BRIGHTNESS | InputLightClass::GREEN, - .path = ""}; - RawLightInfo infoBlue = {.id = 3, - .name = "blue", - .maxBrightness = 255, - .flags = InputLightClass::BRIGHTNESS | InputLightClass::BLUE, - .path = ""}; - mFakeEventHub->addRawLightInfo(infoRed.id, std::move(infoRed)); - mFakeEventHub->addRawLightInfo(infoGreen.id, std::move(infoGreen)); - mFakeEventHub->addRawLightInfo(infoBlue.id, std::move(infoBlue)); - - LightInputMapper& mapper = addMapperAndConfigure<LightInputMapper>(); - InputDeviceInfo info; - mapper.populateDeviceInfo(&info); - const auto& ids = info.getLightIds(); - ASSERT_EQ(1UL, ids.size()); - ASSERT_EQ(InputDeviceLightType::RGB, info.getLightInfo(ids[0])->type); - - ASSERT_TRUE(mapper.setLightColor(ids[0], LIGHT_COLOR)); - ASSERT_EQ(mapper.getLightColor(ids[0]).value_or(-1), LIGHT_COLOR); -} - -TEST_F(LightInputMapperTest, MultiColorRGBLight) { - RawLightInfo infoColor = {.id = 1, - .name = "red", - .maxBrightness = 255, - .flags = InputLightClass::BRIGHTNESS | - InputLightClass::MULTI_INTENSITY | - InputLightClass::MULTI_INDEX, - .path = ""}; - - mFakeEventHub->addRawLightInfo(infoColor.id, std::move(infoColor)); - - LightInputMapper& mapper = addMapperAndConfigure<LightInputMapper>(); - InputDeviceInfo info; - mapper.populateDeviceInfo(&info); - const auto& ids = info.getLightIds(); - ASSERT_EQ(1UL, ids.size()); - ASSERT_EQ(InputDeviceLightType::MULTI_COLOR, info.getLightInfo(ids[0])->type); - - ASSERT_TRUE(mapper.setLightColor(ids[0], LIGHT_COLOR)); - ASSERT_EQ(mapper.getLightColor(ids[0]).value_or(-1), LIGHT_COLOR); -} - -TEST_F(LightInputMapperTest, PlayerIdLight) { - RawLightInfo info1 = {.id = 1, - .name = "player1", - .maxBrightness = 255, - .flags = InputLightClass::BRIGHTNESS, - .path = ""}; - RawLightInfo info2 = {.id = 2, - .name = "player2", - .maxBrightness = 255, - .flags = InputLightClass::BRIGHTNESS, - .path = ""}; - RawLightInfo info3 = {.id = 3, - .name = "player3", - .maxBrightness = 255, - .flags = InputLightClass::BRIGHTNESS, - .path = ""}; - RawLightInfo info4 = {.id = 4, - .name = "player4", - .maxBrightness = 255, - .flags = InputLightClass::BRIGHTNESS, - .path = ""}; - mFakeEventHub->addRawLightInfo(info1.id, std::move(info1)); - mFakeEventHub->addRawLightInfo(info2.id, std::move(info2)); - mFakeEventHub->addRawLightInfo(info3.id, std::move(info3)); - mFakeEventHub->addRawLightInfo(info4.id, std::move(info4)); - - LightInputMapper& mapper = addMapperAndConfigure<LightInputMapper>(); - InputDeviceInfo info; - mapper.populateDeviceInfo(&info); - const auto& ids = info.getLightIds(); - ASSERT_EQ(1UL, ids.size()); - ASSERT_EQ(InputDeviceLightType::PLAYER_ID, info.getLightInfo(ids[0])->type); - - ASSERT_FALSE(mapper.setLightColor(ids[0], LIGHT_COLOR)); - ASSERT_TRUE(mapper.setLightPlayerId(ids[0], LIGHT_PLAYER_ID)); - ASSERT_EQ(mapper.getLightPlayerId(ids[0]).value_or(-1), LIGHT_PLAYER_ID); -} - // --- KeyboardInputMapperTest --- class KeyboardInputMapperTest : public InputMapperTest { @@ -8728,4 +8598,216 @@ TEST_F(MultiTouchInputMapperTest, WhenCapturedAndNotCaptured_GetSources) { ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper.getSources()); } +// --- InputControllerTest --- + +class InputControllerTest : public testing::Test { +protected: + static const char* DEVICE_NAME; + static const char* DEVICE_LOCATION; + static const int32_t DEVICE_ID; + static const int32_t DEVICE_GENERATION; + static const int32_t DEVICE_CONTROLLER_NUMBER; + static const Flags<InputDeviceClass> DEVICE_CLASSES; + static const int32_t EVENTHUB_ID; + + std::shared_ptr<FakeEventHub> mFakeEventHub; + sp<FakeInputReaderPolicy> mFakePolicy; + sp<TestInputListener> mFakeListener; + std::unique_ptr<InstrumentedInputReader> mReader; + std::shared_ptr<InputDevice> mDevice; + + virtual void SetUp(Flags<InputDeviceClass> classes) { + mFakeEventHub = std::make_unique<FakeEventHub>(); + mFakePolicy = new FakeInputReaderPolicy(); + mFakeListener = new TestInputListener(); + mReader = std::make_unique<InstrumentedInputReader>(mFakeEventHub, mFakePolicy, + mFakeListener); + mDevice = newDevice(DEVICE_ID, DEVICE_NAME, DEVICE_LOCATION, EVENTHUB_ID, classes); + } + + void SetUp() override { SetUp(DEVICE_CLASSES); } + + void TearDown() override { + mFakeListener.clear(); + mFakePolicy.clear(); + } + + void configureDevice(uint32_t changes) { + if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { + mReader->requestRefreshConfiguration(changes); + mReader->loopOnce(); + } + mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), changes); + } + + std::shared_ptr<InputDevice> newDevice(int32_t deviceId, const std::string& name, + const std::string& location, int32_t eventHubId, + Flags<InputDeviceClass> classes) { + InputDeviceIdentifier identifier; + identifier.name = name; + identifier.location = location; + std::shared_ptr<InputDevice> device = + std::make_shared<InputDevice>(mReader->getContext(), deviceId, DEVICE_GENERATION, + identifier); + mReader->pushNextDevice(device); + mFakeEventHub->addDevice(eventHubId, name, classes); + mReader->loopOnce(); + return device; + } + + template <class T, typename... Args> + T& addControllerAndConfigure(Args... args) { + T& controller = mDevice->addController<T>(EVENTHUB_ID, args...); + + return controller; + } +}; + +const char* InputControllerTest::DEVICE_NAME = "device"; +const char* InputControllerTest::DEVICE_LOCATION = "BLUETOOTH"; +const int32_t InputControllerTest::DEVICE_ID = END_RESERVED_ID + 1000; +const int32_t InputControllerTest::DEVICE_GENERATION = 2; +const int32_t InputControllerTest::DEVICE_CONTROLLER_NUMBER = 0; +const Flags<InputDeviceClass> InputControllerTest::DEVICE_CLASSES = + Flags<InputDeviceClass>(0); // not needed for current tests +const int32_t InputControllerTest::EVENTHUB_ID = 1; + +// --- BatteryControllerTest --- +class BatteryControllerTest : public InputControllerTest { +protected: + void SetUp() override { + InputControllerTest::SetUp(DEVICE_CLASSES | InputDeviceClass::BATTERY); + } +}; + +TEST_F(BatteryControllerTest, GetBatteryCapacity) { + InputController& controller = addControllerAndConfigure<InputController>(); + + ASSERT_TRUE(controller.getBatteryCapacity(DEFAULT_BATTERY)); + ASSERT_EQ(controller.getBatteryCapacity(DEFAULT_BATTERY).value_or(-1), BATTERY_CAPACITY); +} + +TEST_F(BatteryControllerTest, GetBatteryStatus) { + InputController& controller = addControllerAndConfigure<InputController>(); + + ASSERT_TRUE(controller.getBatteryStatus(DEFAULT_BATTERY)); + ASSERT_EQ(controller.getBatteryStatus(DEFAULT_BATTERY).value_or(-1), BATTERY_STATUS); +} + +// --- LightControllerTest --- +class LightControllerTest : public InputControllerTest { +protected: + void SetUp() override { InputControllerTest::SetUp(DEVICE_CLASSES | InputDeviceClass::LIGHT); } +}; + +TEST_F(LightControllerTest, SingleLight) { + RawLightInfo infoSingle = {.id = 1, + .name = "Mono", + .maxBrightness = 255, + .flags = InputLightClass::BRIGHTNESS, + .path = ""}; + mFakeEventHub->addRawLightInfo(infoSingle.id, std::move(infoSingle)); + + InputController& controller = addControllerAndConfigure<InputController>(); + InputDeviceInfo info; + controller.populateDeviceInfo(&info); + const auto& ids = info.getLightIds(); + ASSERT_EQ(1UL, ids.size()); + ASSERT_EQ(InputDeviceLightType::SINGLE, info.getLightInfo(ids[0])->type); + + ASSERT_TRUE(controller.setLightColor(ids[0], LIGHT_BRIGHTNESS)); + ASSERT_EQ(controller.getLightColor(ids[0]).value_or(-1), LIGHT_BRIGHTNESS); +} + +TEST_F(LightControllerTest, RGBLight) { + RawLightInfo infoRed = {.id = 1, + .name = "red", + .maxBrightness = 255, + .flags = InputLightClass::BRIGHTNESS | InputLightClass::RED, + .path = ""}; + RawLightInfo infoGreen = {.id = 2, + .name = "green", + .maxBrightness = 255, + .flags = InputLightClass::BRIGHTNESS | InputLightClass::GREEN, + .path = ""}; + RawLightInfo infoBlue = {.id = 3, + .name = "blue", + .maxBrightness = 255, + .flags = InputLightClass::BRIGHTNESS | InputLightClass::BLUE, + .path = ""}; + mFakeEventHub->addRawLightInfo(infoRed.id, std::move(infoRed)); + mFakeEventHub->addRawLightInfo(infoGreen.id, std::move(infoGreen)); + mFakeEventHub->addRawLightInfo(infoBlue.id, std::move(infoBlue)); + + InputController& controller = addControllerAndConfigure<InputController>(); + InputDeviceInfo info; + controller.populateDeviceInfo(&info); + const auto& ids = info.getLightIds(); + ASSERT_EQ(1UL, ids.size()); + ASSERT_EQ(InputDeviceLightType::RGB, info.getLightInfo(ids[0])->type); + + ASSERT_TRUE(controller.setLightColor(ids[0], LIGHT_COLOR)); + ASSERT_EQ(controller.getLightColor(ids[0]).value_or(-1), LIGHT_COLOR); +} + +TEST_F(LightControllerTest, MultiColorRGBLight) { + RawLightInfo infoColor = {.id = 1, + .name = "red", + .maxBrightness = 255, + .flags = InputLightClass::BRIGHTNESS | + InputLightClass::MULTI_INTENSITY | + InputLightClass::MULTI_INDEX, + .path = ""}; + + mFakeEventHub->addRawLightInfo(infoColor.id, std::move(infoColor)); + + InputController& controller = addControllerAndConfigure<InputController>(); + InputDeviceInfo info; + controller.populateDeviceInfo(&info); + const auto& ids = info.getLightIds(); + ASSERT_EQ(1UL, ids.size()); + ASSERT_EQ(InputDeviceLightType::MULTI_COLOR, info.getLightInfo(ids[0])->type); + + ASSERT_TRUE(controller.setLightColor(ids[0], LIGHT_COLOR)); + ASSERT_EQ(controller.getLightColor(ids[0]).value_or(-1), LIGHT_COLOR); +} + +TEST_F(LightControllerTest, PlayerIdLight) { + RawLightInfo info1 = {.id = 1, + .name = "player1", + .maxBrightness = 255, + .flags = InputLightClass::BRIGHTNESS, + .path = ""}; + RawLightInfo info2 = {.id = 2, + .name = "player2", + .maxBrightness = 255, + .flags = InputLightClass::BRIGHTNESS, + .path = ""}; + RawLightInfo info3 = {.id = 3, + .name = "player3", + .maxBrightness = 255, + .flags = InputLightClass::BRIGHTNESS, + .path = ""}; + RawLightInfo info4 = {.id = 4, + .name = "player4", + .maxBrightness = 255, + .flags = InputLightClass::BRIGHTNESS, + .path = ""}; + mFakeEventHub->addRawLightInfo(info1.id, std::move(info1)); + mFakeEventHub->addRawLightInfo(info2.id, std::move(info2)); + mFakeEventHub->addRawLightInfo(info3.id, std::move(info3)); + mFakeEventHub->addRawLightInfo(info4.id, std::move(info4)); + + InputController& controller = addControllerAndConfigure<InputController>(); + InputDeviceInfo info; + controller.populateDeviceInfo(&info); + const auto& ids = info.getLightIds(); + ASSERT_EQ(1UL, ids.size()); + ASSERT_EQ(InputDeviceLightType::PLAYER_ID, info.getLightInfo(ids[0])->type); + + ASSERT_FALSE(controller.setLightColor(ids[0], LIGHT_COLOR)); + ASSERT_TRUE(controller.setLightPlayerId(ids[0], LIGHT_PLAYER_ID)); + ASSERT_EQ(controller.getLightPlayerId(ids[0]).value_or(-1), LIGHT_PLAYER_ID); +} + } // namespace android diff --git a/services/memtrackproxy/Android.bp b/services/memtrackproxy/Android.bp new file mode 100644 index 0000000000..7d78f3b2cf --- /dev/null +++ b/services/memtrackproxy/Android.bp @@ -0,0 +1,50 @@ +// Copyright (C) 2021 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 { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + +cc_library_shared { + name: "libmemtrackproxy", + shared_libs: [ + "libbase", + "libbinder_ndk", + "libbinder", + "libhidlbase", + "liblog", + "libcutils", + "libutils", + "android.hardware.memtrack@1.0", + "android.hardware.memtrack-V1-ndk_platform", + ], + srcs: [ + "MemtrackProxy.cpp", + ], + export_include_dirs: [ + "include", + ], + local_include_dirs: [ + "include/memtrackproxy", + ], + export_shared_lib_headers: [ + "android.hardware.memtrack@1.0", + "android.hardware.memtrack-V1-ndk_platform", + ], +} diff --git a/services/memtrackproxy/MemtrackProxy.cpp b/services/memtrackproxy/MemtrackProxy.cpp new file mode 100644 index 0000000000..467616724a --- /dev/null +++ b/services/memtrackproxy/MemtrackProxy.cpp @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2021 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 "MemtrackProxy.h" + +#include <android-base/logging.h> +#include <android/binder_manager.h> +#include <private/android_filesystem_config.h> + +using ::android::hardware::hidl_vec; +using ::android::hardware::Return; + +namespace aidl { +namespace android { +namespace hardware { +namespace memtrack { + +// Check Memtrack Flags +static_assert(static_cast<uint32_t>(V1_0_hidl::MemtrackFlag::SMAPS_ACCOUNTED) == + static_cast<uint32_t>(V1_aidl::MemtrackRecord::FLAG_SMAPS_ACCOUNTED)); +static_assert(static_cast<uint32_t>(V1_0_hidl::MemtrackFlag::SMAPS_UNACCOUNTED) == + static_cast<uint32_t>(V1_aidl::MemtrackRecord::FLAG_SMAPS_UNACCOUNTED)); +static_assert(static_cast<uint32_t>(V1_0_hidl::MemtrackFlag::SHARED) == + static_cast<uint32_t>(V1_aidl::MemtrackRecord::FLAG_SHARED)); +static_assert(static_cast<uint32_t>(V1_0_hidl::MemtrackFlag::SHARED_PSS) == + static_cast<uint32_t>(V1_aidl::MemtrackRecord::FLAG_SHARED_PSS)); +static_assert(static_cast<uint32_t>(V1_0_hidl::MemtrackFlag::PRIVATE) == + static_cast<uint32_t>(V1_aidl::MemtrackRecord::FLAG_PRIVATE)); +static_assert(static_cast<uint32_t>(V1_0_hidl::MemtrackFlag::SYSTEM) == + static_cast<uint32_t>(V1_aidl::MemtrackRecord::FLAG_SYSTEM)); +static_assert(static_cast<uint32_t>(V1_0_hidl::MemtrackFlag::DEDICATED) == + static_cast<uint32_t>(V1_aidl::MemtrackRecord::FLAG_DEDICATED)); +static_assert(static_cast<uint32_t>(V1_0_hidl::MemtrackFlag::NONSECURE) == + static_cast<uint32_t>(V1_aidl::MemtrackRecord::FLAG_NONSECURE)); +static_assert(static_cast<uint32_t>(V1_0_hidl::MemtrackFlag::SECURE) == + static_cast<uint32_t>(V1_aidl::MemtrackRecord::FLAG_SECURE)); + +// Check Memtrack Types +static_assert(static_cast<uint32_t>(V1_0_hidl::MemtrackType::OTHER) == + static_cast<uint32_t>(V1_aidl::MemtrackType::OTHER)); +static_assert(static_cast<uint32_t>(V1_0_hidl::MemtrackType::GL) == + static_cast<uint32_t>(V1_aidl::MemtrackType::GL)); +static_assert(static_cast<uint32_t>(V1_0_hidl::MemtrackType::GRAPHICS) == + static_cast<uint32_t>(V1_aidl::MemtrackType::GRAPHICS)); +static_assert(static_cast<uint32_t>(V1_0_hidl::MemtrackType::MULTIMEDIA) == + static_cast<uint32_t>(V1_aidl::MemtrackType::MULTIMEDIA)); +static_assert(static_cast<uint32_t>(V1_0_hidl::MemtrackType::CAMERA) == + static_cast<uint32_t>(V1_aidl::MemtrackType::CAMERA)); + +__attribute__((warn_unused_result)) bool translate(const V1_0_hidl::MemtrackRecord& in, + V1_aidl::MemtrackRecord* out) { + // Convert uint64_t to int64_t (long in AIDL). AIDL doesn't support unsigned types. + if (in.sizeInBytes > std::numeric_limits<int64_t>::max() || in.sizeInBytes < 0) { + return false; + } + out->sizeInBytes = static_cast<int64_t>(in.sizeInBytes); + + // It's ok to just assign directly, since this is a bitmap. + out->flags = in.flags; + return true; +} + +sp<V1_0_hidl::IMemtrack> MemtrackProxy::MemtrackHidlInstance() { + return V1_0_hidl::IMemtrack::getService(); +} + +std::shared_ptr<V1_aidl::IMemtrack> MemtrackProxy::MemtrackAidlInstance() { + const auto instance = std::string() + V1_aidl::IMemtrack::descriptor + "/default"; + bool declared = AServiceManager_isDeclared(instance.c_str()); + if (!declared) { + return nullptr; + } + ndk::SpAIBinder memtrack_binder = + ndk::SpAIBinder(AServiceManager_waitForService(instance.c_str())); + return V1_aidl::IMemtrack::fromBinder(memtrack_binder); +} + +bool MemtrackProxy::CheckUid(uid_t calling_uid) { + // Allow AID_SHELL for adb shell dumpsys meminfo + return calling_uid == AID_SYSTEM || calling_uid == AID_ROOT || calling_uid == AID_SHELL; +} + +bool MemtrackProxy::CheckPid(pid_t calling_pid, pid_t request_pid) { + return calling_pid == request_pid; +} + +MemtrackProxy::MemtrackProxy() + : memtrack_hidl_instance_(MemtrackProxy::MemtrackHidlInstance()), + memtrack_aidl_instance_(MemtrackProxy::MemtrackAidlInstance()) {} + +ndk::ScopedAStatus MemtrackProxy::getMemory(int pid, MemtrackType type, + std::vector<MemtrackRecord>* _aidl_return) { + if (pid < 0) { + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + + if (!MemtrackProxy::CheckPid(AIBinder_getCallingPid(), pid) && + !MemtrackProxy::CheckUid(AIBinder_getCallingUid())) { + return ndk::ScopedAStatus::fromExceptionCodeWithMessage( + EX_SECURITY, + "Only AID_ROOT, AID_SYSTEM and AID_SHELL can request getMemory() for PIDs other " + "than the calling PID"); + } + + if (type != MemtrackType::OTHER && type != MemtrackType::GL && type != MemtrackType::GRAPHICS && + type != MemtrackType::MULTIMEDIA && type != MemtrackType::CAMERA) { + return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } + + _aidl_return->clear(); + + if (memtrack_aidl_instance_) { + return memtrack_aidl_instance_->getMemory(pid, type, _aidl_return); + } else if (memtrack_hidl_instance_) { + ndk::ScopedAStatus aidl_status; + + Return<void> ret = memtrack_hidl_instance_->getMemory( + pid, static_cast<V1_0_hidl::MemtrackType>(type), + [&_aidl_return, &aidl_status](V1_0_hidl::MemtrackStatus status, + hidl_vec<V1_0_hidl::MemtrackRecord> records) { + switch (status) { + case V1_0_hidl::MemtrackStatus::SUCCESS: + aidl_status = ndk::ScopedAStatus::ok(); + break; + case V1_0_hidl::MemtrackStatus::MEMORY_TRACKING_NOT_SUPPORTED: + [[fallthrough]]; + case V1_0_hidl::MemtrackStatus::TYPE_NOT_SUPPORTED: + [[fallthrough]]; + default: + aidl_status = + ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + return; + } + + _aidl_return->resize(records.size()); + for (size_t i = 0; i < records.size(); i++) { + if (!translate(records[i], &(*_aidl_return)[i])) { + aidl_status = ndk::ScopedAStatus::fromExceptionCodeWithMessage( + EX_SERVICE_SPECIFIC, + "Failed to convert HIDL MemtrackRecord to AIDL"); + return; + } + } + }); + + // Check HIDL return + if (!ret.isOk()) { + const char* err_msg = "HIDL Memtrack::getMemory() failed"; + aidl_status = + ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_SERVICE_SPECIFIC, err_msg); + LOG(ERROR) << err_msg << ": " << ret.description(); + } + + return aidl_status; + } + + return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_NULL_POINTER, + "Memtrack HAL service not available"); +} + +ndk::ScopedAStatus MemtrackProxy::getGpuDeviceInfo(std::vector<DeviceInfo>* _aidl_return) { + if (!MemtrackProxy::CheckUid(AIBinder_getCallingUid())) { + return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_SECURITY, + "Only AID_ROOT, AID_SYSTEM and AID_SHELL can request getGpuDeviceInfo()"); + } + + _aidl_return->clear(); + + if (memtrack_aidl_instance_ || + (memtrack_aidl_instance_ = MemtrackProxy::MemtrackAidlInstance())) { + return memtrack_aidl_instance_->getGpuDeviceInfo(_aidl_return); + } + + return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_NULL_POINTER, + "Memtrack HAL service not available"); +} + +} // namespace memtrack +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/services/memtrackproxy/include/memtrackproxy/MemtrackProxy.h b/services/memtrackproxy/include/memtrackproxy/MemtrackProxy.h new file mode 100644 index 0000000000..5ac1fbf417 --- /dev/null +++ b/services/memtrackproxy/include/memtrackproxy/MemtrackProxy.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2021 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 <aidl/android/hardware/memtrack/BnMemtrack.h> +#include <aidl/android/hardware/memtrack/DeviceInfo.h> +#include <aidl/android/hardware/memtrack/IMemtrack.h> +#include <aidl/android/hardware/memtrack/MemtrackRecord.h> +#include <aidl/android/hardware/memtrack/MemtrackType.h> +#include <android/hardware/memtrack/1.0/IMemtrack.h> + +using ::android::sp; + +namespace V1_0_hidl = ::android::hardware::memtrack::V1_0; +namespace V1_aidl = ::aidl::android::hardware::memtrack; + +namespace aidl { +namespace android { +namespace hardware { +namespace memtrack { + +__attribute__((warn_unused_result)) bool translate(const V1_0_hidl::MemtrackRecord& in, + V1_aidl::MemtrackRecord* out); + +class MemtrackProxy : public BnMemtrack { +public: + MemtrackProxy(); + ndk::ScopedAStatus getMemory(int pid, MemtrackType type, + std::vector<MemtrackRecord>* _aidl_return) override; + ndk::ScopedAStatus getGpuDeviceInfo(std::vector<DeviceInfo>* _aidl_return) override; + +private: + static sp<V1_0_hidl::IMemtrack> MemtrackHidlInstance(); + static std::shared_ptr<V1_aidl::IMemtrack> MemtrackAidlInstance(); + static bool CheckUid(uid_t calling_uid); + static bool CheckPid(pid_t calling_pid, pid_t request_pid); + + sp<V1_0_hidl::IMemtrack> memtrack_hidl_instance_; + std::shared_ptr<V1_aidl::IMemtrack> memtrack_aidl_instance_; +}; + +} // namespace memtrack +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/services/memtrackproxy/test/Android.bp b/services/memtrackproxy/test/Android.bp new file mode 100644 index 0000000000..f943761ee8 --- /dev/null +++ b/services/memtrackproxy/test/Android.bp @@ -0,0 +1,36 @@ +// Copyright (C) 2021 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 { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + +cc_test { + name: "memtrackproxy_test", + srcs: [ + "MemtrackProxyTest.cpp", + ], + shared_libs: [ + "libbinder_ndk", + "libmemtrackproxy", + "android.hardware.memtrack-V1-ndk_platform", + ], + test_suites: ["general-tests"], + require_root: true, +} diff --git a/services/memtrackproxy/test/MemtrackProxyTest.cpp b/services/memtrackproxy/test/MemtrackProxyTest.cpp new file mode 100644 index 0000000000..16dfba025d --- /dev/null +++ b/services/memtrackproxy/test/MemtrackProxyTest.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2021 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 <aidl/android/hardware/memtrack/DeviceInfo.h> +#include <aidl/android/hardware/memtrack/IMemtrack.h> +#include <aidl/android/hardware/memtrack/MemtrackRecord.h> +#include <aidl/android/hardware/memtrack/MemtrackType.h> +#include <android/binder_manager.h> +#include <android/binder_process.h> +#include <gtest/gtest.h> +#include <unistd.h> + +using aidl::android::hardware::memtrack::DeviceInfo; +using aidl::android::hardware::memtrack::IMemtrack; +using aidl::android::hardware::memtrack::MemtrackRecord; +using aidl::android::hardware::memtrack::MemtrackType; + +class MemtrackProxyTest : public ::testing::Test { +public: + virtual void SetUp() override { + const char* kMemtrackProxyService = "memtrack.proxy"; + auto memtrackProxyBinder = + ndk::SpAIBinder(AServiceManager_waitForService(kMemtrackProxyService)); + memtrack_proxy_ = IMemtrack::fromBinder(memtrackProxyBinder); + ASSERT_NE(memtrack_proxy_, nullptr); + } + + std::shared_ptr<IMemtrack> memtrack_proxy_; +}; + +TEST_F(MemtrackProxyTest, GetMemoryForInvalidPid) { + int pid = -1; + + for (MemtrackType type : ndk::enum_range<MemtrackType>()) { + std::vector<MemtrackRecord> records; + + auto status = memtrack_proxy_->getMemory(pid, type, &records); + + EXPECT_EQ(status.getExceptionCode(), EX_ILLEGAL_ARGUMENT); + } +} + +TEST_F(MemtrackProxyTest, GetMemoryForCallingPid) { + int pid = getpid(); + + for (MemtrackType type : ndk::enum_range<MemtrackType>()) { + std::vector<MemtrackRecord> records; + + auto status = memtrack_proxy_->getMemory(pid, type, &records); + + EXPECT_TRUE(status.isOk()); + } +} + +TEST_F(MemtrackProxyTest, GetMemoryForOtherPid) { + int pid = 1; + + for (MemtrackType type : ndk::enum_range<MemtrackType>()) { + std::vector<MemtrackRecord> records; + + auto status = memtrack_proxy_->getMemory(pid, type, &records); + + // Test is run as root + EXPECT_TRUE(status.isOk()); + } +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp index c769e975e3..9aecaff409 100644 --- a/services/sensorservice/Android.bp +++ b/services/sensorservice/Android.bp @@ -49,6 +49,7 @@ cc_library_shared { "libhardware_legacy", "libutils", "liblog", + "libactivitymanager_aidl", "libbatterystats_aidl", "libbinder", "libsensor", @@ -69,8 +70,11 @@ cc_library_shared { generated_headers: ["framework-cppstream-protos"], - // our public headers depend on libsensor and libsensorprivacy - export_shared_lib_headers: ["libsensor", "libsensorprivacy"], + export_shared_lib_headers: [ + "libactivitymanager_aidl", + "libsensor", + "libsensorprivacy", + ], } cc_binary { diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index c0eb277203..98853523f3 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -156,6 +156,7 @@ filegroup { "FpsReporter.cpp", "FrameTracer/FrameTracer.cpp", "FrameTracker.cpp", + "HdrLayerInfoReporter.cpp", "Layer.cpp", "LayerProtoHelper.cpp", "LayerRejecter.cpp", diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index a974dc4488..48a0be2c45 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -432,10 +432,12 @@ bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence } bool BufferStateLayer::setAcquireFence(const sp<Fence>& fence) { + mCurrentState.acquireFence = fence; + mCurrentState.acquireFenceTime = std::make_unique<FenceTime>(fence); + // The acquire fences of BufferStateLayers have already signaled before they are set - mCallbackHandleAcquireTime = fence->getSignalTime(); + mCallbackHandleAcquireTime = mCurrentState.acquireFenceTime->getSignalTime(); - mCurrentState.acquireFence = fence; mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); return true; @@ -691,7 +693,8 @@ status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nse // bufferSurfaceFrame could be seen here if a pending state was applied successfully and we // are processing the next state. addSurfaceFramePresentedForBuffer(bufferSurfaceFrame, - mDrawingState.acquireFence->getSignalTime(), latchTime); + mDrawingState.acquireFenceTime->getSignalTime(), + latchTime); } mCurrentStateModified = false; @@ -928,6 +931,36 @@ void BufferStateLayer::bufferMayChange(sp<GraphicBuffer>& newBuffer) { } } +/* + * We don't want to send the layer's transform to input, but rather the + * parent's transform. This is because BufferStateLayer's transform is + * information about how the buffer is placed on screen. The parent's + * transform makes more sense to send since it's information about how the + * layer is placed on screen. This transform is used by input to determine + * how to go from screen space back to window space. + */ +ui::Transform BufferStateLayer::getInputTransform() const { + sp<Layer> parent = mDrawingParent.promote(); + if (parent == nullptr) { + return ui::Transform(); + } + + return parent->getTransform(); +} + +/** + * Similar to getInputTransform, we need to update the bounds to include the transform. + * This is because bounds for BSL doesn't include buffer transform, where the input assumes + * that's already included. + */ +Rect BufferStateLayer::getInputBounds() const { + Rect bufferBounds = getCroppedBufferSize(getDrawingState()); + if (mDrawingState.transform.getType() == ui::Transform::IDENTITY || !bufferBounds.isValid()) { + return bufferBounds; + } + return mDrawingState.transform.transform(bufferBounds); +} + } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 7a3da6fec1..3878f50776 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -122,6 +122,8 @@ protected: void gatherBufferInfo() override; uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const; void onSurfaceFrameCreated(const std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame); + ui::Transform getInputTransform() const override; + Rect getInputBounds() const override; private: friend class SlotGenerationTest; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h index 8402149c57..a45be8a7a2 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h @@ -55,6 +55,16 @@ struct GenericLayerMetadataEntry { std::vector<uint8_t> value; std::string dumpAsString() const; + + struct Hasher { + size_t operator()(const GenericLayerMetadataEntry& entry) const { + size_t hash = 0; + for (const auto value : entry.value) { + hashCombineSingleHashed(hash, value); + } + return hash; + } + }; }; inline bool operator==(const GenericLayerMetadataEntry& lhs, const GenericLayerMetadataEntry& rhs) { @@ -70,6 +80,8 @@ using GenericLayerMetadataMap = std::unordered_map<std::string, GenericLayerMeta /* * Used by LayerFE::getCompositionState + * Note that fields that affect HW composer state may need to be mirrored into + * android::compositionengine::impl::planner::LayerState */ struct LayerFECompositionState { // If set to true, forces client composition on all output layers until diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h index f113c34ba3..ae88e7839c 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h @@ -55,7 +55,6 @@ public: std::vector<LayerFE::LayerSettings> getOverrideCompositionList() const override; void dump(std::string&) const override; - virtual FloatRect calculateOutputSourceCrop() const; virtual Rect calculateOutputDisplayFrame() const; virtual uint32_t calculateOutputRelativeBufferTransform( diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h index 6c02759bf8..4c065ec112 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h @@ -48,6 +48,8 @@ class HWComposer; namespace compositionengine::impl { +// Note that fields that affect HW composer state may need to be mirrored into +// android::compositionengine::impl::planner::LayerState struct OutputLayerCompositionState { // The portion of the layer that is not obscured by opaque layers on top Region visibleRegion; @@ -92,6 +94,8 @@ struct OutputLayerCompositionState { Rect displayFrame = {}; ui::Dataspace dataspace{ui::Dataspace::UNKNOWN}; ProjectionSpace displaySpace; + Region damageRegion = Region::INVALID_REGION; + Region visibleRegion; } overrideInfo; /* diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h index 056408ebb7..afa02cd0c2 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h @@ -40,6 +40,7 @@ public: const LayerState* getState() const { return mState; } const std::string& getName() const { return mState->getName(); } Rect getDisplayFrame() const { return mState->getDisplayFrame(); } + const Region& getVisibleRegion() const { return mState->getVisibleRegion(); } const sp<GraphicBuffer>& getBuffer() const { return mState->getOutputLayer()->getLayerFE().getCompositionState()->buffer; } @@ -63,6 +64,7 @@ public: size_t getLayerCount() const { return mLayers.size(); } const Layer& getFirstLayer() const { return mLayers[0]; } const Rect& getBounds() const { return mBounds; } + const Region& getVisibleRegion() const { return mVisibleRegion; } size_t getAge() const { return mAge; } const sp<GraphicBuffer>& getBuffer() const { return mTexture.getBuffer(); } const sp<Fence>& getDrawFence() const { return mDrawFence; } @@ -94,6 +96,7 @@ public: boundingRegion.orSelf(mBounds); boundingRegion.orSelf(other.mBounds); mBounds = boundingRegion.getBounds(); + mVisibleRegion.orSelf(other.mVisibleRegion); } void incrementAge() { ++mAge; } @@ -109,6 +112,7 @@ private: std::chrono::steady_clock::time_point mLastUpdate = std::chrono::steady_clock::now(); std::vector<Layer> mLayers; Rect mBounds = Rect::EMPTY_RECT; + Region mVisibleRegion; size_t mAge = 0; class Texture { diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h index d005ca37a9..050e2643e5 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h @@ -57,13 +57,16 @@ enum class LayerStateField : uint32_t { BufferTransform = 1u << 5, BlendMode = 1u << 6, Alpha = 1u << 7, - VisibleRegion = 1u << 8, - Dataspace = 1u << 9, - ColorTransform = 1u << 10, - CompositionType = 1u << 11, - SidebandStream = 1u << 12, - Buffer = 1u << 13, - SolidColor = 1u << 14, + LayerMetadata = 1u << 8, + VisibleRegion = 1u << 9, + Dataspace = 1u << 10, + PixelFormat = 1u << 11, + ColorTransform = 1u << 12, + SurfaceDamage = 1u << 13, + CompositionType = 1u << 14, + SidebandStream = 1u << 15, + Buffer = 1u << 16, + SolidColor = 1u << 17, }; // clang-format on @@ -95,6 +98,7 @@ public: using ReadFromLayerState = std::function<T(const compositionengine::OutputLayer* layer)>; using ToStrings = std::function<std::vector<std::string>(const T&)>; using Equals = std::function<bool(const T&, const T&)>; + using Hashes = std::function<size_t(const T&)>; static ToStrings getDefaultToStrings() { return [](const T& value) { @@ -107,14 +111,38 @@ public: return [](const T& value) { return std::vector<std::string>{toString(value)}; }; } + static ToStrings getRegionToStrings() { + return [](const Region& region) { + using namespace std::string_literals; + std::string dump; + region.dump(dump, ""); + std::vector<std::string> split = base::Split(dump, "\n"s); + split.erase(split.begin()); // Strip the header + split.pop_back(); // Strip the last (empty) line + for (std::string& line : split) { + line.erase(0, 4); // Strip leading padding before each rect + } + return split; + }; + } + static Equals getDefaultEquals() { return [](const T& lhs, const T& rhs) { return lhs == rhs; }; } + static Equals getRegionEquals() { + return [](const Region& lhs, const Region& rhs) { return lhs.hasSameRects(rhs); }; + } + + static Hashes getDefaultHashes() { + return [](const T& value) { return std::hash<T>{}(value); }; + } + OutputLayerState(ReadFromLayerState reader, ToStrings toStrings = OutputLayerState::getDefaultToStrings(), - Equals equals = OutputLayerState::getDefaultEquals()) - : mReader(reader), mToStrings(toStrings), mEquals(equals) {} + Equals equals = OutputLayerState::getDefaultEquals(), + Hashes hashes = OutputLayerState::getDefaultHashes()) + : mReader(reader), mToStrings(toStrings), mEquals(equals), mHashes(hashes) {} ~OutputLayerState() override = default; @@ -138,7 +166,7 @@ public: size_t getHash() const override { if (!mHash) { - mHash = std::hash<T>{}(mValue); + mHash = mHashes(mValue); } return *mHash; } @@ -172,6 +200,7 @@ private: const ReadFromLayerState mReader; const ToStrings mToStrings; const Equals mEquals; + const Hashes mHashes; T mValue = {}; mutable std::optional<size_t> mHash = {}; }; @@ -196,6 +225,7 @@ public: int32_t getId() const { return mId.get(); } const std::string& getName() const { return mName.get(); } Rect getDisplayFrame() const { return mDisplayFrame.get(); } + const Region& getVisibleRegion() const { return mVisibleRegion.get(); } hardware::graphics::composer::hal::Composition getCompositionType() const { return mCompositionType.get(); } @@ -263,39 +293,80 @@ private: OutputLayerState<float, LayerStateField::Alpha> mAlpha{ [](auto layer) { return layer->getLayerFE().getCompositionState()->alpha; }}; - // TODO(b/180638831): Generic layer metadata - - // Output-dependent per-frame state - - OutputLayerState<Region, LayerStateField::VisibleRegion> - mVisibleRegion{[](auto layer) { return layer->getState().visibleRegion; }, - [](const Region& region) { - using namespace std::string_literals; - std::string dump; - region.dump(dump, ""); - std::vector<std::string> split = base::Split(dump, "\n"s); - split.erase(split.begin()); // Strip the header - split.pop_back(); // Strip the last (empty) line - for (std::string& line : split) { - line.erase(0, 4); // Strip leading padding before each rect + using LayerMetadataState = + OutputLayerState<GenericLayerMetadataMap, LayerStateField::LayerMetadata>; + LayerMetadataState + mLayerMetadata{[](auto layer) { + return layer->getLayerFE().getCompositionState()->metadata; + }, + [](const GenericLayerMetadataMap& metadata) { + std::vector<std::string> result; + if (metadata.empty()) { + result.push_back("{}"); + return result; + } + result.push_back("{"); + for (const auto& [key, value] : metadata) { + std::string keyValueDump; + keyValueDump.append(" "); + keyValueDump.append(key); + keyValueDump.append("="); + keyValueDump.append(value.dumpAsString()); + result.push_back(keyValueDump); } - return split; + result.push_back("}"); + return result; }, - [](const Region& lhs, const Region& rhs) { - return lhs.hasSameRects(rhs); + LayerMetadataState::getDefaultEquals(), + [](const GenericLayerMetadataMap& metadata) { + size_t hash = 0; + for (const auto& [key, value] : metadata) { + size_t entryHash = 0; + hashCombineSingleHashed(entryHash, + std::hash<std::string>{}(key)); + hashCombineSingleHashed(entryHash, + GenericLayerMetadataEntry::Hasher{}( + value)); + hash ^= entryHash; + } + return hash; }}; + // Output-dependent per-frame state + + using VisibleRegionState = OutputLayerState<Region, LayerStateField::VisibleRegion>; + VisibleRegionState mVisibleRegion{[](auto layer) { return layer->getState().visibleRegion; }, + VisibleRegionState::getRegionToStrings(), + VisibleRegionState::getRegionEquals()}; + using DataspaceState = OutputLayerState<ui::Dataspace, LayerStateField::Dataspace>; DataspaceState mOutputDataspace{[](auto layer) { return layer->getState().dataspace; }, DataspaceState::getHalToStrings()}; - // TODO(b/180638831): Buffer format - // Output-independent per-frame state + using PixelFormatState = OutputLayerState<hardware::graphics::composer::hal::PixelFormat, + LayerStateField::PixelFormat>; + PixelFormatState + mPixelFormat{[](auto layer) { + return layer->getLayerFE().getCompositionState()->buffer + ? static_cast<hardware::graphics::composer::hal::PixelFormat>( + layer->getLayerFE() + .getCompositionState() + ->buffer->getPixelFormat()) + : hardware::graphics::composer::hal::PixelFormat::RGBA_8888; + }, + PixelFormatState::getHalToStrings()}; + OutputLayerState<mat4, LayerStateField::ColorTransform> mColorTransform; - // TODO(b/180638831): Surface damage + using SurfaceDamageState = OutputLayerState<Region, LayerStateField::SurfaceDamage>; + SurfaceDamageState + mSurfaceDamage{[](auto layer) { + return layer->getLayerFE().getCompositionState()->surfaceDamage; + }, + SurfaceDamageState::getRegionToStrings(), + SurfaceDamageState::getRegionEquals()}; using CompositionTypeState = OutputLayerState<hardware::graphics::composer::hal::Composition, LayerStateField::CompositionType>; @@ -339,10 +410,12 @@ private: return std::vector<std::string>{stream.str()}; }}; - std::array<StateInterface*, 13> getNonUniqueFields() { - std::array<const StateInterface*, 13> constFields = + static const constexpr size_t kNumNonUniqueFields = 16; + + std::array<StateInterface*, kNumNonUniqueFields> getNonUniqueFields() { + std::array<const StateInterface*, kNumNonUniqueFields> constFields = const_cast<const LayerState*>(this)->getNonUniqueFields(); - std::array<StateInterface*, 13> fields; + std::array<StateInterface*, kNumNonUniqueFields> fields; std::transform(constFields.cbegin(), constFields.cend(), fields.begin(), [](const StateInterface* constField) { return const_cast<StateInterface*>(constField); @@ -350,12 +423,12 @@ private: return fields; } - std::array<const StateInterface*, 13> getNonUniqueFields() const { + std::array<const StateInterface*, kNumNonUniqueFields> getNonUniqueFields() const { return { - &mDisplayFrame, &mSourceCrop, &mZOrder, &mBufferTransform, - &mBlendMode, &mAlpha, &mVisibleRegion, &mOutputDataspace, - &mColorTransform, &mCompositionType, &mSidebandStream, &mBuffer, - &mSolidColor, + &mDisplayFrame, &mSourceCrop, &mZOrder, &mBufferTransform, + &mBlendMode, &mAlpha, &mLayerMetadata, &mVisibleRegion, + &mOutputDataspace, &mPixelFormat, &mColorTransform, &mSurfaceDamage, + &mCompositionType, &mSidebandStream, &mBuffer, &mSolidColor, }; } }; diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 48327931db..3f36a8feea 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -355,7 +355,7 @@ void OutputLayer::writeOutputDependentGeometryStateToHWC( Rect displayFrame = outputDependentState.displayFrame; FloatRect sourceCrop = outputDependentState.sourceCrop; - if (outputDependentState.overrideInfo.buffer != nullptr) { // adyabr + if (outputDependentState.overrideInfo.buffer != nullptr) { displayFrame = outputDependentState.overrideInfo.displayFrame; sourceCrop = displayFrame.toFloatRect(); } @@ -397,14 +397,17 @@ void OutputLayer::writeOutputDependentGeometryStateToHWC( void OutputLayer::writeOutputIndependentGeometryStateToHWC( HWC2::Layer* hwcLayer, const LayerFECompositionState& outputIndependentState, bool skipLayer) { - if (auto error = hwcLayer->setBlendMode(outputIndependentState.blendMode); - error != hal::Error::NONE) { + const auto blendMode = getState().overrideInfo.buffer + ? hardware::graphics::composer::hal::BlendMode::PREMULTIPLIED + : outputIndependentState.blendMode; + if (auto error = hwcLayer->setBlendMode(blendMode); error != hal::Error::NONE) { ALOGE("[%s] Failed to set blend mode %s: %s (%d)", getLayerFE().getDebugName(), - toString(outputIndependentState.blendMode).c_str(), to_string(error).c_str(), - static_cast<int32_t>(error)); + toString(blendMode).c_str(), to_string(error).c_str(), static_cast<int32_t>(error)); } - const float alpha = skipLayer ? 0.0f : outputIndependentState.alpha; + const float alpha = skipLayer + ? 0.0f + : (getState().overrideInfo.buffer ? 1.0f : outputIndependentState.alpha); ALOGV("Writing alpha %f", alpha); if (auto error = hwcLayer->setPlaneAlpha(alpha); error != hal::Error::NONE) { @@ -426,8 +429,10 @@ void OutputLayer::writeOutputDependentPerFrameStateToHWC(HWC2::Layer* hwcLayer) // TODO(lpique): b/121291683 outputSpaceVisibleRegion is output-dependent geometry // state and should not change every frame. - if (auto error = hwcLayer->setVisibleRegion(outputDependentState.outputSpaceVisibleRegion); - error != hal::Error::NONE) { + Region visibleRegion = outputDependentState.overrideInfo.buffer + ? Region(outputDependentState.overrideInfo.visibleRegion) + : outputDependentState.outputSpaceVisibleRegion; + if (auto error = hwcLayer->setVisibleRegion(visibleRegion); error != hal::Error::NONE) { ALOGE("[%s] Failed to set visible region: %s (%d)", getLayerFE().getDebugName(), to_string(error).c_str(), static_cast<int32_t>(error)); outputDependentState.outputSpaceVisibleRegion.dump(LOG_TAG); @@ -456,8 +461,11 @@ void OutputLayer::writeOutputIndependentPerFrameStateToHWC( to_string(error).c_str(), static_cast<int32_t>(error)); } - if (auto error = hwcLayer->setSurfaceDamage(outputIndependentState.surfaceDamage); - error != hal::Error::NONE) { + const Region& surfaceDamage = getState().overrideInfo.buffer + ? getState().overrideInfo.damageRegion + : outputIndependentState.surfaceDamage; + + if (auto error = hwcLayer->setSurfaceDamage(surfaceDamage); error != hal::Error::NONE) { ALOGE("[%s] Failed to set surface damage: %s (%d)", getLayerFE().getDebugName(), to_string(error).c_str(), static_cast<int32_t>(error)); outputIndependentState.surfaceDamage.dump(LOG_TAG); diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp index 0f6804d0ab..efd23dce98 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp @@ -73,6 +73,12 @@ void OutputLayerCompositionState::dump(std::string& out) const { dumpVal(out, "override display frame", overrideInfo.displayFrame); dumpVal(out, "override dataspace", toString(overrideInfo.dataspace), overrideInfo.dataspace); dumpVal(out, "override display space", to_string(overrideInfo.displaySpace)); + std::string damageRegionString; + overrideInfo.damageRegion.dump(damageRegionString, ""); + dumpVal(out, "override damage region", damageRegionString); + std::string visibleRegionString; + overrideInfo.visibleRegion.dump(visibleRegionString, ""); + dumpVal(out, "override visible region", visibleRegionString); if (hwc) { dumpHwc(*hwc, out); diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp index f58addb70b..dcb75556e3 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp @@ -61,7 +61,8 @@ CachedSet::CachedSet(const LayerState* layer, std::chrono::steady_clock::time_po CachedSet::CachedSet(Layer layer) : mFingerprint(layer.getHash()), mLastUpdate(layer.getLastUpdate()), - mBounds(layer.getDisplayFrame()) { + mBounds(layer.getDisplayFrame()), + mVisibleRegion(layer.getVisibleRegion()) { mLayers.emplace_back(std::move(layer)); } @@ -73,6 +74,7 @@ void CachedSet::addLayer(const LayerState* layer, boundingRegion.orSelf(mBounds); boundingRegion.orSelf(layer->getDisplayFrame()); mBounds = boundingRegion.getBounds(); + mVisibleRegion.orSelf(layer->getVisibleRegion()); } NonBufferHash CachedSet::getNonBufferHash() const { @@ -178,6 +180,7 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, }; std::vector<renderengine::LayerSettings> layerSettings; + renderengine::LayerSettings highlight; for (const auto& layer : mLayers) { const auto clientCompositionList = layer.getState()->getOutputLayer()->getLayerFE().prepareClientCompositionList( @@ -192,7 +195,7 @@ void CachedSet::render(renderengine::RenderEngine& renderEngine, [](const renderengine::LayerSettings& settings) { return &settings; }); if (sDebugHighlighLayers) { - renderengine::LayerSettings highlight{ + highlight = { .geometry = renderengine::Geometry{ .boundaries = FloatRect(0.0f, 0.0f, diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp index aae49de8b2..ffca5baab7 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp @@ -212,6 +212,8 @@ bool Flattener::mergeWithCachedSets(const std::vector<const LayerState*>& layers .displayFrame = mNewCachedSet->getBounds(), .dataspace = mNewCachedSet->getOutputDataspace(), .displaySpace = mNewCachedSet->getOutputSpace(), + .damageRegion = Region::INVALID_REGION, + .visibleRegion = mNewCachedSet->getVisibleRegion(), }; ++incomingLayerIter; } @@ -244,6 +246,8 @@ bool Flattener::mergeWithCachedSets(const std::vector<const LayerState*>& layers .displayFrame = currentLayerIter->getBounds(), .dataspace = currentLayerIter->getOutputDataspace(), .displaySpace = currentLayerIter->getOutputSpace(), + .damageRegion = Region(), + .visibleRegion = currentLayerIter->getVisibleRegion(), }; ++incomingLayerIter; } diff --git a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp index e976c9b226..7c32e944fc 100644 --- a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp @@ -157,9 +157,11 @@ bool operator==(const LayerState& lhs, const LayerState& rhs) { return lhs.mId == rhs.mId && lhs.mName == rhs.mName && lhs.mDisplayFrame == rhs.mDisplayFrame && lhs.mSourceCrop == rhs.mSourceCrop && lhs.mZOrder == rhs.mZOrder && lhs.mBufferTransform == rhs.mBufferTransform && lhs.mBlendMode == rhs.mBlendMode && - lhs.mAlpha == rhs.mAlpha && lhs.mVisibleRegion == rhs.mVisibleRegion && - lhs.mOutputDataspace == rhs.mOutputDataspace && + lhs.mAlpha == rhs.mAlpha && lhs.mLayerMetadata == rhs.mLayerMetadata && + lhs.mVisibleRegion == rhs.mVisibleRegion && + lhs.mOutputDataspace == rhs.mOutputDataspace && lhs.mPixelFormat == rhs.mPixelFormat && lhs.mColorTransform == rhs.mColorTransform && + lhs.mSurfaceDamage == rhs.mSurfaceDamage && lhs.mCompositionType == rhs.mCompositionType && lhs.mSidebandStream == rhs.mSidebandStream && lhs.mBuffer == rhs.mBuffer && (lhs.mCompositionType.get() != hal::Composition::SOLID_COLOR || diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index cbbc966790..8a4d161289 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -693,7 +693,10 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { static constexpr Hwc2::Transform kOverrideBufferTransform = static_cast<Hwc2::Transform>(0); static constexpr Hwc2::IComposerClient::BlendMode kBlendMode = static_cast<Hwc2::IComposerClient::BlendMode>(41); + static constexpr Hwc2::IComposerClient::BlendMode kOverrideBlendMode = + Hwc2::IComposerClient::BlendMode::PREMULTIPLIED; static constexpr float kAlpha = 51.f; + static constexpr float kOverrideAlpha = 1.f; static constexpr ui::Dataspace kDataspace = static_cast<ui::Dataspace>(71); static constexpr ui::Dataspace kOverrideDataspace = static_cast<ui::Dataspace>(72); static constexpr int kSupportedPerFrameMetadata = 101; @@ -705,8 +708,10 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { static const Rect kDisplayFrame; static const Rect kOverrideDisplayFrame; static const Region kOutputSpaceVisibleRegion; + static const Region kOverrideVisibleRegion; static const mat4 kColorTransform; static const Region kSurfaceDamage; + static const Region kOverrideSurfaceDamage; static const HdrMetadata kHdrMetadata; static native_handle_t* kSidebandStreamHandle; static const sp<GraphicBuffer> kBuffer; @@ -763,31 +768,35 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { overrideInfo.acquireFence = kOverrideFence; overrideInfo.displayFrame = kOverrideDisplayFrame; overrideInfo.dataspace = kOverrideDataspace; + overrideInfo.damageRegion = kOverrideSurfaceDamage; + overrideInfo.visibleRegion = kOverrideVisibleRegion; } void expectGeometryCommonCalls(Rect displayFrame = kDisplayFrame, FloatRect sourceCrop = kSourceCrop, - Hwc2::Transform bufferTransform = kBufferTransform) { + Hwc2::Transform bufferTransform = kBufferTransform, + Hwc2::IComposerClient::BlendMode blendMode = kBlendMode, + float alpha = kAlpha) { EXPECT_CALL(*mHwcLayer, setDisplayFrame(displayFrame)).WillOnce(Return(kError)); EXPECT_CALL(*mHwcLayer, setSourceCrop(sourceCrop)).WillOnce(Return(kError)); EXPECT_CALL(*mHwcLayer, setZOrder(kZOrder)).WillOnce(Return(kError)); EXPECT_CALL(*mHwcLayer, setTransform(bufferTransform)).WillOnce(Return(kError)); - EXPECT_CALL(*mHwcLayer, setBlendMode(kBlendMode)).WillOnce(Return(kError)); - EXPECT_CALL(*mHwcLayer, setPlaneAlpha(kAlpha)).WillOnce(Return(kError)); + EXPECT_CALL(*mHwcLayer, setBlendMode(blendMode)).WillOnce(Return(kError)); + EXPECT_CALL(*mHwcLayer, setPlaneAlpha(alpha)).WillOnce(Return(kError)); } void expectPerFrameCommonCalls(SimulateUnsupported unsupported = SimulateUnsupported::None, - ui::Dataspace dataspace = kDataspace) { - EXPECT_CALL(*mHwcLayer, setVisibleRegion(RegionEq(kOutputSpaceVisibleRegion))) - .WillOnce(Return(kError)); + ui::Dataspace dataspace = kDataspace, + const Region& visibleRegion = kOutputSpaceVisibleRegion, + const Region& surfaceDamage = kSurfaceDamage) { + EXPECT_CALL(*mHwcLayer, setVisibleRegion(RegionEq(visibleRegion))).WillOnce(Return(kError)); EXPECT_CALL(*mHwcLayer, setDataspace(dataspace)).WillOnce(Return(kError)); EXPECT_CALL(*mHwcLayer, setColorTransform(kColorTransform)) .WillOnce(Return(unsupported == SimulateUnsupported::ColorTransform ? hal::Error::UNSUPPORTED : hal::Error::NONE)); - EXPECT_CALL(*mHwcLayer, setSurfaceDamage(RegionEq(kSurfaceDamage))) - .WillOnce(Return(kError)); + EXPECT_CALL(*mHwcLayer, setSurfaceDamage(RegionEq(surfaceDamage))).WillOnce(Return(kError)); } void expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition compositionType) { @@ -838,11 +847,13 @@ const Rect OutputLayerWriteStateToHWCTest::kDisplayFrame{1001, 1002, 1003, 10044 const Rect OutputLayerWriteStateToHWCTest::kOverrideDisplayFrame{1002, 1003, 1004, 20044}; const Region OutputLayerWriteStateToHWCTest::kOutputSpaceVisibleRegion{ Rect{1005, 1006, 1007, 1008}}; +const Region OutputLayerWriteStateToHWCTest::kOverrideVisibleRegion{Rect{1006, 1007, 1008, 1009}}; const mat4 OutputLayerWriteStateToHWCTest::kColorTransform{ 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, }; const Region OutputLayerWriteStateToHWCTest::kSurfaceDamage{Rect{1025, 1026, 1027, 1028}}; +const Region OutputLayerWriteStateToHWCTest::kOverrideSurfaceDamage{Rect{1026, 1027, 1028, 1029}}; const HdrMetadata OutputLayerWriteStateToHWCTest::kHdrMetadata{{/* LightFlattenable */}, 1029}; native_handle_t* OutputLayerWriteStateToHWCTest::kSidebandStreamHandle = reinterpret_cast<native_handle_t*>(1031); @@ -1009,8 +1020,9 @@ TEST_F(OutputLayerWriteStateToHWCTest, includesOverrideInfoIfPresent) { includeOverrideInfo(); expectGeometryCommonCalls(kOverrideDisplayFrame, kOverrideDisplayFrame.toFloatRect(), - kOverrideBufferTransform); - expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace); + kOverrideBufferTransform, kOverrideBlendMode, kOverrideAlpha); + expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion, + kOverrideSurfaceDamage); expectSetHdrMetadataAndBufferCalls(kOverrideBuffer, kOverrideFence); expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE); diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp index d3c4b1f822..f01fe27b38 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp @@ -70,6 +70,8 @@ void CachedSetTest::SetUp() { auto testLayer = std::make_unique<TestLayer>(); auto pos = static_cast<int32_t>(i); testLayer->outputLayerCompositionState.displayFrame = Rect(pos, pos, pos + 1, pos + 1); + testLayer->outputLayerCompositionState.visibleRegion = + Region(Rect(pos + 1, pos + 1, pos + 2, pos + 2)); testLayer->layerFE = sp<mock::LayerFE>::make(); @@ -106,6 +108,7 @@ void expectEqual(const CachedSet& cachedSet, const CachedSet::Layer& layer) { EXPECT_EQ(layer.getHash(), cachedSet.getFingerprint()); EXPECT_EQ(layer.getLastUpdate(), cachedSet.getLastUpdate()); EXPECT_EQ(layer.getDisplayFrame(), cachedSet.getBounds()); + EXPECT_TRUE(layer.getVisibleRegion().hasSameRects(cachedSet.getVisibleRegion())); EXPECT_EQ(1u, cachedSet.getLayerCount()); EXPECT_EQ(layer.getState(), cachedSet.getFirstLayer().getState()); EXPECT_EQ(0u, cachedSet.getAge()); @@ -154,6 +157,10 @@ TEST_F(CachedSetTest, addLayer) { EXPECT_EQ(layer1.getHash(), cachedSet.getFingerprint()); EXPECT_EQ(kStartTime, cachedSet.getLastUpdate()); EXPECT_EQ(Rect(0, 0, 2, 2), cachedSet.getBounds()); + Region expectedRegion; + expectedRegion.orSelf(Rect(1, 1, 2, 2)); + expectedRegion.orSelf(Rect(2, 2, 3, 3)); + EXPECT_TRUE(cachedSet.getVisibleRegion().hasSameRects(expectedRegion)); EXPECT_EQ(2u, cachedSet.getLayerCount()); EXPECT_EQ(0u, cachedSet.getAge()); expectNoBuffer(cachedSet); @@ -239,6 +246,11 @@ TEST_F(CachedSetTest, append) { EXPECT_EQ(layer1.getHash(), cachedSet1.getFingerprint()); EXPECT_EQ(kStartTime, cachedSet1.getLastUpdate()); EXPECT_EQ(Rect(0, 0, 3, 3), cachedSet1.getBounds()); + Region expectedRegion; + expectedRegion.orSelf(Rect(1, 1, 2, 2)); + expectedRegion.orSelf(Rect(2, 2, 3, 3)); + expectedRegion.orSelf(Rect(3, 3, 4, 4)); + EXPECT_TRUE(cachedSet1.getVisibleRegion().hasSameRects(expectedRegion)); EXPECT_EQ(3u, cachedSet1.getLayerCount()); EXPECT_EQ(0u, cachedSet1.getAge()); expectNoBuffer(cachedSet1); diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp index 1bbf11a163..c5280877d5 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp @@ -89,6 +89,8 @@ void FlattenerTest::SetUp() { testLayer->name = ss.str(); testLayer->outputLayerCompositionState.displayFrame = Rect(pos, pos, pos + 1, pos + 1); + testLayer->outputLayerCompositionState.visibleRegion = + Region(Rect(pos + 1, pos + 1, pos + 2, pos + 2)); testLayer->layerFECompositionState.buffer = new GraphicBuffer(100, 100, HAL_PIXEL_FORMAT_RGBA_8888, 1, @@ -272,6 +274,7 @@ TEST_F(FlattenerTest, flattenLayers_FlattenedLayersSetsProjectionSpace) { // make all layers inactive mTime += 200ms; expectAllLayersFlattened(layers); + EXPECT_EQ(overrideDisplaySpace.bounds, Rect(mOutputState.framebufferSpace.bounds.getWidth(), mOutputState.framebufferSpace.bounds.getHeight())); @@ -279,6 +282,55 @@ TEST_F(FlattenerTest, flattenLayers_FlattenedLayersSetsProjectionSpace) { EXPECT_EQ(overrideDisplaySpace.orientation, mOutputState.framebufferSpace.orientation); } +TEST_F(FlattenerTest, flattenLayers_FlattenedLayersSetsDamageRegions) { + auto& layerState1 = mTestLayers[0]->layerState; + const auto& overrideDamageRegion = + layerState1->getOutputLayer()->getState().overrideInfo.damageRegion; + + auto& layerState2 = mTestLayers[1]->layerState; + + const std::vector<const LayerState*> layers = { + layerState1.get(), + layerState2.get(), + }; + + initializeFlattener(layers); + + // make all layers inactive + mTime += 200ms; + expectAllLayersFlattened(layers); + EXPECT_TRUE(overrideDamageRegion.isRect() && + overrideDamageRegion.bounds() == Rect::INVALID_RECT); + + initializeOverrideBuffer(layers); + EXPECT_NE(getNonBufferHash(layers), + mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime)); + EXPECT_TRUE(overrideDamageRegion.isRect() && overrideDamageRegion.bounds() == Rect::EMPTY_RECT); +} + +TEST_F(FlattenerTest, flattenLayers_FlattenedLayersSetsVisibleRegion) { + auto& layerState1 = mTestLayers[0]->layerState; + const auto& overrideVisibleRegion = + layerState1->getOutputLayer()->getState().overrideInfo.visibleRegion; + + auto& layerState2 = mTestLayers[1]->layerState; + + const std::vector<const LayerState*> layers = { + layerState1.get(), + layerState2.get(), + }; + + initializeFlattener(layers); + + // make all layers inactive + mTime += 200ms; + expectAllLayersFlattened(layers); + Region expectedRegion; + expectedRegion.orSelf(Rect(1, 1, 2, 2)); + expectedRegion.orSelf(Rect(2, 2, 3, 3)); + EXPECT_TRUE(overrideVisibleRegion.hasSameRects(expectedRegion)); +} + TEST_F(FlattenerTest, flattenLayers_addLayerToFlattenedCauseReset) { auto& layerState1 = mTestLayers[0]->layerState; const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer; diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp index d5a7234372..47b1ae8959 100644 --- a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp @@ -24,6 +24,9 @@ #include <gtest/gtest.h> #include <log/log.h> +#include "android/hardware_buffer.h" +#include "compositionengine/LayerFECompositionState.h" + namespace android::compositionengine::impl::planner { namespace { @@ -48,7 +51,15 @@ const mat4 sMat4One = mat4::scale(vec4(2.f, 3.f, 1.f, 1.f)); native_handle_t* const sFakeSidebandStreamOne = reinterpret_cast<native_handle_t*>(10); native_handle_t* const sFakeSidebandStreamTwo = reinterpret_cast<native_handle_t*>(11); const half4 sHalf4One = half4(0.2f, 0.3f, 0.4f, 0.5f); -const half4 sHalf4Two = half4(0.5f, 0.4f, 0.43, 0.2f); +const half4 sHalf4Two = half4(0.5f, 0.4f, 0.3f, 0.2f); +const std::string sMetadataKeyOne = std::string("Meta!"); +const std::string sMetadataKeyTwo = std::string("Data!"); +const GenericLayerMetadataEntry sMetadataValueOne = GenericLayerMetadataEntry{ + .value = std::vector<uint8_t>({1, 2}), +}; +const GenericLayerMetadataEntry sMetadataValueTwo = GenericLayerMetadataEntry{ + .value = std::vector<uint8_t>({1, 3}), +}; struct LayerStateTest : public testing::Test { LayerStateTest() { @@ -75,6 +86,21 @@ struct LayerStateTest : public testing::Test { EXPECT_CALL(layerFE, getCompositionState()).WillRepeatedly(Return(&layerFEState)); } + void verifyUniqueDifferingFields(const LayerState& lhs, const LayerState& rhs) { + EXPECT_EQ(lhs.getHash(), rhs.getHash()); + + EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None), lhs.getDifferingFields(rhs)); + EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None), rhs.getDifferingFields(lhs)); + } + + void verifyNonUniqueDifferingFields(const LayerState& lhs, const LayerState& rhs, + Flags<LayerStateField> fields) { + EXPECT_NE(lhs.getHash(), rhs.getHash()); + + EXPECT_EQ(fields, lhs.getDifferingFields(rhs)); + EXPECT_EQ(fields, rhs.getDifferingFields(lhs)); + } + mock::LayerFE mLayerFE; mock::OutputLayer mOutputLayer; std::unique_ptr<LayerState> mLayerState; @@ -129,14 +155,7 @@ TEST_F(LayerStateTest, compareId) { EXPECT_NE(mLayerState->getId(), otherLayerState->getId()); // Id is a unique field, so it's not computed in the hash for a layer state. - EXPECT_EQ(mLayerState->getHash(), otherLayerState->getHash()); - - // Similarly, Id cannot be included in differing fields. - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None), - mLayerState->getDifferingFields(*otherLayerState)); - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None), - otherLayerState->getDifferingFields(*mLayerState)); - + verifyUniqueDifferingFields(*mLayerState, *otherLayerState); EXPECT_FALSE(mLayerState->compare(*otherLayerState)); EXPECT_FALSE(otherLayerState->compare(*mLayerState)); } @@ -181,14 +200,7 @@ TEST_F(LayerStateTest, compareName) { EXPECT_NE(mLayerState->getName(), otherLayerState->getName()); // Name is a unique field, so it's not computed in the hash for a layer state. - EXPECT_EQ(mLayerState->getHash(), otherLayerState->getHash()); - - // Similarly, Name cannot be included in differing fields. - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None), - mLayerState->getDifferingFields(*otherLayerState)); - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None), - otherLayerState->getDifferingFields(*mLayerState)); - + verifyUniqueDifferingFields(*mLayerState, *otherLayerState); EXPECT_FALSE(mLayerState->compare(*otherLayerState)); EXPECT_FALSE(otherLayerState->compare(*mLayerState)); } @@ -239,13 +251,7 @@ TEST_F(LayerStateTest, compareDisplayFrame) { EXPECT_NE(mLayerState->getDisplayFrame(), otherLayerState->getDisplayFrame()); - EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash()); - - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::DisplayFrame), - mLayerState->getDifferingFields(*otherLayerState)); - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::DisplayFrame), - otherLayerState->getDifferingFields(*mLayerState)); - + verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::DisplayFrame); EXPECT_TRUE(mLayerState->compare(*otherLayerState)); EXPECT_TRUE(otherLayerState->compare(*mLayerState)); } @@ -316,13 +322,8 @@ TEST_F(LayerStateTest, compareCompositionType) { EXPECT_NE(mLayerState->getCompositionType(), otherLayerState->getCompositionType()); - EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash()); - - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::CompositionType), - mLayerState->getDifferingFields(*otherLayerState)); - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::CompositionType), - otherLayerState->getDifferingFields(*mLayerState)); - + verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, + LayerStateField::CompositionType); EXPECT_TRUE(mLayerState->compare(*otherLayerState)); EXPECT_TRUE(otherLayerState->compare(*mLayerState)); } @@ -360,12 +361,8 @@ TEST_F(LayerStateTest, compareBuffer) { layerFECompositionStateTwo); auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer); - // Buffers are not included in differing fields or in hashes. - EXPECT_EQ(mLayerState->getHash(), otherLayerState->getHash()); - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None), - mLayerState->getDifferingFields(*otherLayerState)); - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::None), - otherLayerState->getDifferingFields(*mLayerState)); + // A buffer is not a unique field, but the assertions are the same. + verifyUniqueDifferingFields(*mLayerState, *otherLayerState); // Buffers are explicitly excluded from comparison EXPECT_FALSE(mLayerState->compare(*otherLayerState)); @@ -405,12 +402,7 @@ TEST_F(LayerStateTest, compareSourceCrop) { layerFECompositionState); auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer); - EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash()); - - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SourceCrop), - mLayerState->getDifferingFields(*otherLayerState)); - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SourceCrop), - otherLayerState->getDifferingFields(*mLayerState)); + verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::SourceCrop); EXPECT_TRUE(mLayerState->compare(*otherLayerState)); EXPECT_TRUE(otherLayerState->compare(*mLayerState)); @@ -449,12 +441,7 @@ TEST_F(LayerStateTest, compareZOrder) { layerFECompositionState); auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer); - EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash()); - - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::ZOrder), - mLayerState->getDifferingFields(*otherLayerState)); - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::ZOrder), - otherLayerState->getDifferingFields(*mLayerState)); + verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::ZOrder); EXPECT_TRUE(mLayerState->compare(*otherLayerState)); EXPECT_TRUE(otherLayerState->compare(*mLayerState)); @@ -493,12 +480,8 @@ TEST_F(LayerStateTest, compareBufferTransform) { layerFECompositionState); auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer); - EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash()); - - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::BufferTransform), - mLayerState->getDifferingFields(*otherLayerState)); - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::BufferTransform), - otherLayerState->getDifferingFields(*mLayerState)); + verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, + LayerStateField::BufferTransform); EXPECT_TRUE(mLayerState->compare(*otherLayerState)); EXPECT_TRUE(otherLayerState->compare(*mLayerState)); @@ -537,12 +520,7 @@ TEST_F(LayerStateTest, compareBlendMode) { layerFECompositionStateTwo); auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer); - EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash()); - - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::BlendMode), - mLayerState->getDifferingFields(*otherLayerState)); - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::BlendMode), - otherLayerState->getDifferingFields(*mLayerState)); + verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::BlendMode); EXPECT_TRUE(mLayerState->compare(*otherLayerState)); EXPECT_TRUE(otherLayerState->compare(*mLayerState)); @@ -581,17 +559,61 @@ TEST_F(LayerStateTest, compareAlpha) { layerFECompositionStateTwo); auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer); - EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash()); + verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::Alpha); + + EXPECT_TRUE(mLayerState->compare(*otherLayerState)); + EXPECT_TRUE(otherLayerState->compare(*mLayerState)); +} + +TEST_F(LayerStateTest, updateLayerMetadata) { + OutputLayerCompositionState outputLayerCompositionState; + LayerFECompositionState layerFECompositionState; + layerFECompositionState.metadata[sMetadataKeyOne] = sMetadataValueOne; + setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState, + layerFECompositionState); + mLayerState = std::make_unique<LayerState>(&mOutputLayer); + + mock::OutputLayer newOutputLayer; + mock::LayerFE newLayerFE; + LayerFECompositionState layerFECompositionStateTwo; + layerFECompositionStateTwo.metadata[sMetadataKeyTwo] = sMetadataValueTwo; + setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState, + layerFECompositionStateTwo); + Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(Flags<LayerStateField>(LayerStateField::LayerMetadata), updates); +} - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Alpha), - mLayerState->getDifferingFields(*otherLayerState)); - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Alpha), - otherLayerState->getDifferingFields(*mLayerState)); +TEST_F(LayerStateTest, compareLayerMetadata) { + OutputLayerCompositionState outputLayerCompositionState; + LayerFECompositionState layerFECompositionState; + layerFECompositionState.metadata[sMetadataKeyOne] = sMetadataValueOne; + setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState, + layerFECompositionState); + mLayerState = std::make_unique<LayerState>(&mOutputLayer); + mock::OutputLayer newOutputLayer; + mock::LayerFE newLayerFE; + LayerFECompositionState layerFECompositionStateTwo; + layerFECompositionStateTwo.metadata[sMetadataKeyTwo] = sMetadataValueTwo; + setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState, + layerFECompositionStateTwo); + auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer); + + verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::LayerMetadata); EXPECT_TRUE(mLayerState->compare(*otherLayerState)); EXPECT_TRUE(otherLayerState->compare(*mLayerState)); } +TEST_F(LayerStateTest, getVisibleRegion) { + OutputLayerCompositionState outputLayerCompositionState; + outputLayerCompositionState.visibleRegion = sRegionOne; + LayerFECompositionState layerFECompositionState; + setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState, + layerFECompositionState); + mLayerState = std::make_unique<LayerState>(&mOutputLayer); + EXPECT_TRUE(mLayerState->getVisibleRegion().hasSameRects(sRegionOne)); +} + TEST_F(LayerStateTest, updateVisibleRegion) { OutputLayerCompositionState outputLayerCompositionState; outputLayerCompositionState.visibleRegion = sRegionOne; @@ -625,12 +647,7 @@ TEST_F(LayerStateTest, compareVisibleRegion) { layerFECompositionState); auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer); - EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash()); - - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::VisibleRegion), - mLayerState->getDifferingFields(*otherLayerState)); - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::VisibleRegion), - otherLayerState->getDifferingFields(*mLayerState)); + verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::VisibleRegion); EXPECT_TRUE(mLayerState->compare(*otherLayerState)); EXPECT_TRUE(otherLayerState->compare(*mLayerState)); @@ -669,12 +686,65 @@ TEST_F(LayerStateTest, compareDataspace) { layerFECompositionState); auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer); - EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash()); + verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::Dataspace); + + EXPECT_TRUE(mLayerState->compare(*otherLayerState)); + EXPECT_TRUE(otherLayerState->compare(*mLayerState)); +} + +TEST_F(LayerStateTest, updatePixelFormat) { + OutputLayerCompositionState outputLayerCompositionState; + LayerFECompositionState layerFECompositionState; + layerFECompositionState.buffer = + new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBA_8888, + AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | + AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, + "buffer1"); + setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState, + layerFECompositionState); + mLayerState = std::make_unique<LayerState>(&mOutputLayer); - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Dataspace), - mLayerState->getDifferingFields(*otherLayerState)); - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Dataspace), - otherLayerState->getDifferingFields(*mLayerState)); + mock::OutputLayer newOutputLayer; + mock::LayerFE newLayerFE; + LayerFECompositionState layerFECompositionStateTwo; + layerFECompositionStateTwo.buffer = + new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBX_8888, + AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | + AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, + "buffer2"); + setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState, + layerFECompositionStateTwo); + Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(Flags<LayerStateField>(LayerStateField::Buffer) | + Flags<LayerStateField>(LayerStateField::PixelFormat), + updates); +} + +TEST_F(LayerStateTest, comparePixelFormat) { + OutputLayerCompositionState outputLayerCompositionState; + LayerFECompositionState layerFECompositionState; + layerFECompositionState.buffer = + new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBA_8888, + AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | + AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, + "buffer1"); + setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState, + layerFECompositionState); + mLayerState = std::make_unique<LayerState>(&mOutputLayer); + mock::OutputLayer newOutputLayer; + mock::LayerFE newLayerFE; + LayerFECompositionState layerFECompositionStateTwo; + layerFECompositionStateTwo.buffer = + new GraphicBuffer(1, 1, PIXEL_FORMAT_RGBX_8888, + AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | + AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, + "buffer2"); + setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState, + layerFECompositionStateTwo); + auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer); + + verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, + Flags<LayerStateField>(LayerStateField::PixelFormat)); EXPECT_TRUE(mLayerState->compare(*otherLayerState)); EXPECT_TRUE(otherLayerState->compare(*mLayerState)); @@ -717,12 +787,48 @@ TEST_F(LayerStateTest, compareColorTransform) { layerFECompositionStateTwo); auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer); - EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash()); + verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::ColorTransform); + + EXPECT_TRUE(mLayerState->compare(*otherLayerState)); + EXPECT_TRUE(otherLayerState->compare(*mLayerState)); +} + +TEST_F(LayerStateTest, updateSurfaceDamage) { + OutputLayerCompositionState outputLayerCompositionState; + LayerFECompositionState layerFECompositionState; + layerFECompositionState.surfaceDamage = sRegionOne; + setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState, + layerFECompositionState); + mLayerState = std::make_unique<LayerState>(&mOutputLayer); - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::ColorTransform), - mLayerState->getDifferingFields(*otherLayerState)); - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::ColorTransform), - otherLayerState->getDifferingFields(*mLayerState)); + mock::OutputLayer newOutputLayer; + mock::LayerFE newLayerFE; + OutputLayerCompositionState outputLayerCompositionStateTwo; + LayerFECompositionState layerFECompositionStateTwo; + layerFECompositionStateTwo.surfaceDamage = sRegionTwo; + setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionStateTwo, + layerFECompositionStateTwo); + Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer); + EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SurfaceDamage), updates); +} + +TEST_F(LayerStateTest, compareSurfaceDamage) { + OutputLayerCompositionState outputLayerCompositionState; + LayerFECompositionState layerFECompositionState; + layerFECompositionState.surfaceDamage = sRegionOne; + setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState, + layerFECompositionState); + mLayerState = std::make_unique<LayerState>(&mOutputLayer); + mock::OutputLayer newOutputLayer; + mock::LayerFE newLayerFE; + OutputLayerCompositionState outputLayerCompositionStateTwo; + LayerFECompositionState layerFECompositionStateTwo; + layerFECompositionStateTwo.surfaceDamage = sRegionTwo; + setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionStateTwo, + layerFECompositionStateTwo); + auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer); + + verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::SurfaceDamage); EXPECT_TRUE(mLayerState->compare(*otherLayerState)); EXPECT_TRUE(otherLayerState->compare(*mLayerState)); @@ -761,12 +867,7 @@ TEST_F(LayerStateTest, compareSidebandStream) { layerFECompositionStateTwo); auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer); - EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash()); - - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SidebandStream), - mLayerState->getDifferingFields(*otherLayerState)); - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SidebandStream), - otherLayerState->getDifferingFields(*mLayerState)); + verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::SidebandStream); EXPECT_TRUE(mLayerState->compare(*otherLayerState)); EXPECT_TRUE(otherLayerState->compare(*mLayerState)); @@ -805,12 +906,7 @@ TEST_F(LayerStateTest, compareSolidColor) { layerFECompositionStateTwo); auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer); - EXPECT_NE(mLayerState->getHash(), otherLayerState->getHash()); - - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SolidColor), - mLayerState->getDifferingFields(*otherLayerState)); - EXPECT_EQ(Flags<LayerStateField>(LayerStateField::SolidColor), - otherLayerState->getDifferingFields(*mLayerState)); + verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::SolidColor); EXPECT_TRUE(mLayerState->compare(*otherLayerState)); EXPECT_TRUE(otherLayerState->compare(*mLayerState)); diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp index f7fc162884..8d685cfbdd 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp @@ -76,14 +76,14 @@ FramebufferSurface::FramebufferSurface(HWComposer& hwc, PhysicalDisplayId displa mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER); - const auto limitedSize = limitFramebufferSize(size); + const auto limitedSize = limitSize(size); mConsumer->setDefaultBufferSize(limitedSize.width, limitedSize.height); mConsumer->setMaxAcquiredBufferCount( SurfaceFlinger::maxFrameBufferAcquiredBuffers - 1); } void FramebufferSurface::resizeBuffers(const ui::Size& newSize) { - const auto limitedSize = limitFramebufferSize(newSize); + const auto limitedSize = limitSize(newSize); mConsumer->setDefaultBufferSize(limitedSize.width, limitedSize.height); } @@ -179,19 +179,23 @@ void FramebufferSurface::onFrameCommitted() { } } -ui::Size FramebufferSurface::limitFramebufferSize(const ui::Size& size) { +ui::Size FramebufferSurface::limitSize(const ui::Size& size) { + return limitSizeInternal(size, mMaxSize); +} + +ui::Size FramebufferSurface::limitSizeInternal(const ui::Size& size, const ui::Size& maxSize) { ui::Size limitedSize = size; bool wasLimited = false; - if (size.width > mMaxSize.width && mMaxSize.width != 0) { + if (size.width > maxSize.width && maxSize.width != 0) { const float aspectRatio = static_cast<float>(size.width) / size.height; - limitedSize.height = mMaxSize.width / aspectRatio; - limitedSize.width = mMaxSize.width; + limitedSize.height = maxSize.width / aspectRatio; + limitedSize.width = maxSize.width; wasLimited = true; } - if (size.height > mMaxSize.height && mMaxSize.height != 0) { + if (limitedSize.height > maxSize.height && maxSize.height != 0) { const float aspectRatio = static_cast<float>(size.width) / size.height; - limitedSize.height = mMaxSize.height; - limitedSize.width = mMaxSize.height * aspectRatio; + limitedSize.height = maxSize.height; + limitedSize.width = maxSize.height * aspectRatio; wasLimited = true; } ALOGI_IF(wasLimited, "framebuffer size has been limited to [%dx%d] from [%dx%d]", diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h index 5d1e131d69..3123351322 100644 --- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h +++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h @@ -55,15 +55,20 @@ public: virtual const sp<Fence>& getClientTargetAcquireFence() const override; private: + friend class FramebufferSurfaceTest; + + // Limits the width and height by the maximum width specified. + ui::Size limitSize(const ui::Size&); + + // Used for testing purposes. + static ui::Size limitSizeInternal(const ui::Size&, const ui::Size& maxSize); + virtual ~FramebufferSurface() { }; // this class cannot be overloaded virtual void freeBufferLocked(int slotIndex); virtual void dumpLocked(String8& result, const char* prefix) const; - // Limits the width and height by the maximum width specified in the constructor. - ui::Size limitFramebufferSize(const ui::Size&); - // nextBuffer waits for and then latches the next buffer from the // BufferQueue and releases the previously latched buffer to the // BufferQueue. The new buffer is returned in the 'buffer' argument. diff --git a/services/surfaceflinger/FrameTracker.cpp b/services/surfaceflinger/FrameTracker.cpp index 8ad805b1d8..178c531a2a 100644 --- a/services/surfaceflinger/FrameTracker.cpp +++ b/services/surfaceflinger/FrameTracker.cpp @@ -62,10 +62,9 @@ void FrameTracker::setActualPresentTime(nsecs_t presentTime) { mFrameRecords[mOffset].actualPresentTime = presentTime; } -void FrameTracker::setActualPresentFence( - std::shared_ptr<FenceTime>&& readyFence) { +void FrameTracker::setActualPresentFence(const std::shared_ptr<FenceTime>& readyFence) { Mutex::Autolock lock(mMutex); - mFrameRecords[mOffset].actualPresentFence = std::move(readyFence); + mFrameRecords[mOffset].actualPresentFence = readyFence; mNumFences++; } diff --git a/services/surfaceflinger/FrameTracker.h b/services/surfaceflinger/FrameTracker.h index 35382be1c0..bc412aee2f 100644 --- a/services/surfaceflinger/FrameTracker.h +++ b/services/surfaceflinger/FrameTracker.h @@ -66,7 +66,7 @@ public: // setActualPresentFence sets the fence that is used to get the time // at which the current frame became visible to the user. - void setActualPresentFence(std::shared_ptr<FenceTime>&& fence); + void setActualPresentFence(const std::shared_ptr<FenceTime>& fence); // setDisplayRefreshPeriod sets the display refresh period in nanoseconds. // This is used to compute frame presentation duration statistics relative diff --git a/services/surfaceflinger/HdrLayerInfoReporter.cpp b/services/surfaceflinger/HdrLayerInfoReporter.cpp new file mode 100644 index 0000000000..c06e300cdc --- /dev/null +++ b/services/surfaceflinger/HdrLayerInfoReporter.cpp @@ -0,0 +1,64 @@ +/* + * Copyright 2021 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. + */ + +#undef LOG_TAG +#define LOG_TAG "HdrLayerInfoReporter" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include <utils/Trace.h> + +#include "HdrLayerInfoReporter.h" + +namespace android { + +void HdrLayerInfoReporter::dispatchHdrLayerInfo(const HdrLayerInfo& info) { + ATRACE_CALL(); + std::vector<sp<gui::IHdrLayerInfoListener>> toInvoke; + { + std::scoped_lock lock(mMutex); + toInvoke.reserve(mListeners.size()); + for (auto& [key, it] : mListeners) { + if (it.lastInfo != info) { + it.lastInfo = info; + toInvoke.push_back(it.listener); + } + } + } + + for (const auto& listener : toInvoke) { + ATRACE_NAME("invoking onHdrLayerInfoChanged"); + listener->onHdrLayerInfoChanged(info.numberOfHdrLayers, info.maxW, info.maxH, info.flags); + } +} + +void HdrLayerInfoReporter::binderDied(const wp<IBinder>& who) { + std::scoped_lock lock(mMutex); + mListeners.erase(who); +} + +void HdrLayerInfoReporter::addListener(const sp<gui::IHdrLayerInfoListener>& listener) { + sp<IBinder> asBinder = IInterface::asBinder(listener); + asBinder->linkToDeath(this); + std::lock_guard lock(mMutex); + mListeners.emplace(wp<IBinder>(asBinder), TrackedListener{listener, HdrLayerInfo{}}); +} + +void HdrLayerInfoReporter::removeListener(const sp<gui::IHdrLayerInfoListener>& listener) { + std::lock_guard lock(mMutex); + mListeners.erase(wp<IBinder>(IInterface::asBinder(listener))); +} + +} // namespace android
\ No newline at end of file diff --git a/services/surfaceflinger/HdrLayerInfoReporter.h b/services/surfaceflinger/HdrLayerInfoReporter.h new file mode 100644 index 0000000000..671395f8de --- /dev/null +++ b/services/surfaceflinger/HdrLayerInfoReporter.h @@ -0,0 +1,80 @@ +/* + * Copyright 2021 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-base/thread_annotations.h> +#include <android/gui/IHdrLayerInfoListener.h> +#include <binder/IBinder.h> + +#include <unordered_map> + +namespace android { + +class HdrLayerInfoReporter final : public IBinder::DeathRecipient { +public: + struct HdrLayerInfo { + int32_t numberOfHdrLayers = 0; + int32_t maxW = 0; + int32_t maxH = 0; + int32_t flags = 0; + + bool operator==(const HdrLayerInfo& other) const { + return numberOfHdrLayers == other.numberOfHdrLayers && maxW == other.maxW && + maxH == other.maxH && flags == other.flags; + } + + bool operator!=(const HdrLayerInfo& other) const { return !(*this == other); } + }; + + HdrLayerInfoReporter() = default; + ~HdrLayerInfoReporter() final = default; + + // Dispatches updated layer fps values for the registered listeners + // This method promotes Layer weak pointers and performs layer stack traversals, so mStateLock + // must be held when calling this method. + void dispatchHdrLayerInfo(const HdrLayerInfo& info) EXCLUDES(mMutex); + + // Override for IBinder::DeathRecipient + void binderDied(const wp<IBinder>&) override EXCLUDES(mMutex); + + // Registers an Fps listener that listens to fps updates for the provided layer + void addListener(const sp<gui::IHdrLayerInfoListener>& listener) EXCLUDES(mMutex); + // Deregisters an Fps listener + void removeListener(const sp<gui::IHdrLayerInfoListener>& listener) EXCLUDES(mMutex); + + bool hasListeners() const EXCLUDES(mMutex) { + std::scoped_lock lock(mMutex); + return !mListeners.empty(); + } + +private: + mutable std::mutex mMutex; + struct WpHash { + size_t operator()(const wp<IBinder>& p) const { + return std::hash<IBinder*>()(p.unsafe_get()); + } + }; + + struct TrackedListener { + sp<gui::IHdrLayerInfoListener> listener; + HdrLayerInfo lastInfo; + }; + + std::unordered_map<wp<IBinder>, TrackedListener, WpHash> mListeners GUARDED_BY(mMutex); +}; + +} // namespace android
\ No newline at end of file diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index b5410fe295..94fd62fa7a 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -116,7 +116,8 @@ Layer::Layer(const LayerCreationArgs& args) mCurrentState.bufferTransform = 0; mCurrentState.transformToDisplayInverse = false; mCurrentState.crop.makeInvalid(); - mCurrentState.acquireFence = new Fence(-1); + mCurrentState.acquireFence = sp<Fence>::make(-1); + mCurrentState.acquireFenceTime = std::make_shared<FenceTime>(mCurrentState.acquireFence); mCurrentState.dataspace = ui::Dataspace::UNKNOWN; mCurrentState.hdrMetadata.validTypes = 0; mCurrentState.surfaceDamageRegion = Region::INVALID_REGION; @@ -1948,32 +1949,6 @@ ssize_t Layer::removeChild(const sp<Layer>& layer) { return removeResult; } -void Layer::reparentChildren(const sp<Layer>& newParent) { - for (const sp<Layer>& child : mCurrentChildren) { - newParent->addChild(child); - } - mCurrentChildren.clear(); - updateTreeHasFrameRateVote(); -} - -bool Layer::reparentChildren(const sp<IBinder>& newParentHandle) { - sp<Handle> handle = nullptr; - sp<Layer> newParent = nullptr; - if (newParentHandle == nullptr) { - return false; - } - handle = static_cast<Handle*>(newParentHandle.get()); - newParent = handle->owner.promote(); - if (newParent == nullptr) { - ALOGE("Unable to promote Layer handle"); - return false; - } - - reparentChildren(newParent); - - return true; -} - void Layer::setChildrenDrawingParent(const sp<Layer>& newParent) { for (const sp<Layer>& child : mDrawingChildren) { child->mDrawingParent = newParent; @@ -2534,14 +2509,22 @@ bool Layer::isRemovedFromCurrentState() const { return mRemovedFromCurrentState; } +ui::Transform Layer::getInputTransform() const { + return getTransform(); +} + +Rect Layer::getInputBounds() const { + return getCroppedBufferSize(getDrawingState()); +} + void Layer::fillInputFrameInfo(InputWindowInfo& info, const ui::Transform& toPhysicalDisplay) { // Transform layer size to screen space and inset it by surface insets. // If this is a portal window, set the touchableRegion to the layerBounds. Rect layerBounds = info.portalToDisplayId == ADISPLAY_ID_NONE - ? getBufferSize(getDrawingState()) + ? getInputBounds() : info.touchableRegion.getBounds(); if (!layerBounds.isValid()) { - layerBounds = getCroppedBufferSize(getDrawingState()); + layerBounds = getInputBounds(); } if (!layerBounds.isValid()) { @@ -2554,7 +2537,7 @@ void Layer::fillInputFrameInfo(InputWindowInfo& info, const ui::Transform& toPhy return; } - ui::Transform layerToDisplay = getTransform(); + ui::Transform layerToDisplay = getInputTransform(); // Transform that takes window coordinates to unrotated display coordinates ui::Transform t = toPhysicalDisplay * layerToDisplay; int32_t xSurfaceInset = info.surfaceInset; diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 421a10776f..3a45c949a4 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -52,6 +52,7 @@ #include "LayerVector.h" #include "MonitoredProducer.h" #include "RenderArea.h" +#include "Scheduler/LayerInfo.h" #include "Scheduler/Seamlessness.h" #include "SurfaceFlinger.h" #include "SurfaceTracing.h" @@ -141,59 +142,8 @@ public: float radius = 0.0f; }; - // FrameRateCompatibility specifies how we should interpret the frame rate associated with - // the layer. - enum class FrameRateCompatibility { - Default, // Layer didn't specify any specific handling strategy - - Exact, // Layer needs the exact frame rate. - - ExactOrMultiple, // Layer needs the exact frame rate (or a multiple of it) to present the - // content properly. Any other value will result in a pull down. - - NoVote, // Layer doesn't have any requirements for the refresh rate and - // should not be considered when the display refresh rate is determined. - }; - - // Encapsulates the frame rate and compatibility of the layer. This information will be used - // when the display refresh rate is determined. - struct FrameRate { - using Seamlessness = scheduler::Seamlessness; - - Fps rate; - FrameRateCompatibility type; - Seamlessness seamlessness; - - FrameRate() - : rate(0), - type(FrameRateCompatibility::Default), - seamlessness(Seamlessness::Default) {} - FrameRate(Fps rate, FrameRateCompatibility type, - Seamlessness seamlessness = Seamlessness::OnlySeamless) - : rate(rate), type(type), seamlessness(getSeamlessness(rate, seamlessness)) {} - - bool operator==(const FrameRate& other) const { - return rate.equalsWithMargin(other.rate) && type == other.type && - seamlessness == other.seamlessness; - } - - bool operator!=(const FrameRate& other) const { return !(*this == other); } - - // Convert an ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* value to a - // Layer::FrameRateCompatibility. Logs fatal if the compatibility value is invalid. - static FrameRateCompatibility convertCompatibility(int8_t compatibility); - static scheduler::Seamlessness convertChangeFrameRateStrategy(int8_t strategy); - - private: - static Seamlessness getSeamlessness(Fps rate, Seamlessness seamlessness) { - if (!rate.isValid()) { - // Refresh rate of 0 is a special value which should reset the vote to - // its default value. - return Seamlessness::Default; - } - return seamlessness; - } - }; + using FrameRate = scheduler::LayerInfo::FrameRate; + using FrameRateCompatibility = scheduler::LayerInfo::FrameRateCompatibility; struct State { Geometry active_legacy; @@ -261,6 +211,7 @@ public: sp<GraphicBuffer> buffer; client_cache_t clientCacheId; sp<Fence> acquireFence; + std::shared_ptr<FenceTime> acquireFenceTime; HdrMetadata hdrMetadata; Region surfaceDamageRegion; int32_t api; @@ -687,8 +638,6 @@ public: void onLayerDisplayed(const sp<Fence>& releaseFence) override; const char* getDebugName() const override; - bool reparentChildren(const sp<IBinder>& newParentHandle); - void reparentChildren(const sp<Layer>& newParent); bool setShadowRadius(float shadowRadius); // Before color management is introduced, contents on Android have to be @@ -1075,6 +1024,9 @@ protected: compositionengine::OutputLayer* findOutputLayerForDisplay(const DisplayDevice*) const; bool usingRelativeZ(LayerVector::StateSet) const; + virtual ui::Transform getInputTransform() const; + virtual Rect getInputBounds() const; + // SyncPoints which will be signaled when the correct frame is at the head // of the queue and dropped after the frame has been latched. Protected by // mLocalSyncPointMutex. diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index ea92ad88bb..f4bc2a10cb 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -39,13 +39,13 @@ namespace android::scheduler { namespace { -bool isLayerActive(const Layer& layer, const LayerInfo& info, nsecs_t threshold) { +bool isLayerActive(const LayerInfo& info, nsecs_t threshold) { // Layers with an explicit vote are always kept active - if (layer.getFrameRateForLayerTree().rate.isValid()) { + if (info.getSetFrameRateVote().rate.isValid()) { return true; } - return layer.isVisible() && info.getLastUpdatedTime() >= threshold; + return info.isVisible() && info.getLastUpdatedTime() >= threshold; } bool traceEnabled() { @@ -58,11 +58,7 @@ bool useFrameRatePriority() { return atoi(value); } -void trace(const wp<Layer>& weak, const LayerInfo& info, LayerHistory::LayerVoteType type, - int fps) { - const auto layer = weak.promote(); - if (!layer) return; - +void trace(const LayerInfo& info, LayerHistory::LayerVoteType type, int fps) { const auto traceType = [&](LayerHistory::LayerVoteType checkedType, int value) { ATRACE_INT(info.getTraceTag(checkedType), type == checkedType ? value : 0); }; @@ -75,7 +71,7 @@ void trace(const wp<Layer>& weak, const LayerInfo& info, LayerHistory::LayerVote traceType(LayerHistory::LayerVoteType::Min, 1); traceType(LayerHistory::LayerVoteType::Max, 1); - ALOGD("%s: %s @ %d Hz", __FUNCTION__, layer->getName().c_str(), fps); + ALOGD("%s: %s @ %d Hz", __FUNCTION__, info.getName().c_str(), fps); } } // namespace @@ -88,11 +84,27 @@ LayerHistory::LayerHistory(const RefreshRateConfigs& refreshRateConfigs) LayerHistory::~LayerHistory() = default; void LayerHistory::registerLayer(Layer* layer, LayerVoteType type) { - auto info = std::make_unique<LayerInfo>(layer->getName(), type); + auto info = std::make_unique<LayerInfo>(layer->getName(), layer->getOwnerUid(), type); std::lock_guard lock(mLock); mLayerInfos.emplace_back(layer, std::move(info)); } +void LayerHistory::deregisterLayer(Layer* layer) { + std::lock_guard lock(mLock); + + const auto it = std::find_if(mLayerInfos.begin(), mLayerInfos.end(), + [layer](const auto& pair) { return pair.first == layer; }); + LOG_FATAL_IF(it == mLayerInfos.end(), "%s: unknown layer %p", __FUNCTION__, layer); + + const size_t i = static_cast<size_t>(it - mLayerInfos.begin()); + if (i < mActiveLayersEnd) { + mActiveLayersEnd--; + } + const size_t last = mLayerInfos.size() - 1; + std::swap(mLayerInfos[i], mLayerInfos[last]); + mLayerInfos.erase(mLayerInfos.begin() + static_cast<long>(last)); +} + void LayerHistory::record(Layer* layer, nsecs_t presentTime, nsecs_t now, LayerUpdateType updateType) { std::lock_guard lock(mLock); @@ -102,7 +114,15 @@ void LayerHistory::record(Layer* layer, nsecs_t presentTime, nsecs_t now, LOG_FATAL_IF(it == mLayerInfos.end(), "%s: unknown layer %p", __FUNCTION__, layer); const auto& info = it->second; - info->setLastPresentTime(presentTime, now, updateType, mModeChangePending); + const auto layerProps = LayerInfo::LayerProps{ + .visible = layer->isVisible(), + .bounds = layer->getBounds(), + .transform = layer->getTransform(), + .setFrameRateVote = layer->getFrameRateForLayerTree(), + .frameRateSelectionPriority = layer->getFrameRateSelectionPriority(), + }; + + info->setLastPresentTime(presentTime, now, updateType, mModeChangePending, layerProps); // Activate layer if inactive. if (const auto end = activeLayers().end(); it >= end) { @@ -119,15 +139,10 @@ LayerHistory::Summary LayerHistory::summarize(nsecs_t now) { partitionLayers(now); for (const auto& [layer, info] : activeLayers()) { - const auto strong = layer.promote(); - if (!strong) { - continue; - } - - const auto frameRateSelectionPriority = strong->getFrameRateSelectionPriority(); + const auto frameRateSelectionPriority = info->getFrameRateSelectionPriority(); const auto layerFocused = Layer::isLayerFocusedBasedOnPriority(frameRateSelectionPriority); - ALOGV("%s has priority: %d %s focused", strong->getName().c_str(), - frameRateSelectionPriority, layerFocused ? "" : "not"); + ALOGV("%s has priority: %d %s focused", info->getName().c_str(), frameRateSelectionPriority, + layerFocused ? "" : "not"); const auto vote = info->getRefreshRateVote(now); // Skip NoVote layer as those don't have any requirements @@ -136,18 +151,18 @@ LayerHistory::Summary LayerHistory::summarize(nsecs_t now) { } // Compute the layer's position on the screen - const Rect bounds = Rect(strong->getBounds()); - const ui::Transform transform = strong->getTransform(); + const Rect bounds = Rect(info->getBounds()); + const ui::Transform transform = info->getTransform(); constexpr bool roundOutwards = true; Rect transformed = transform.transform(bounds, roundOutwards); const float layerArea = transformed.getWidth() * transformed.getHeight(); float weight = mDisplayArea ? layerArea / mDisplayArea : 0.0f; - summary.push_back({strong->getName(), strong->getOwnerUid(), vote.type, vote.fps, + summary.push_back({info->getName(), info->getOwnerUid(), vote.type, vote.fps, vote.seamlessness, weight, layerFocused}); if (CC_UNLIKELY(mTraceEnabled)) { - trace(layer, *info, vote.type, vote.fps.getIntValue()); + trace(*info, vote.type, vote.fps.getIntValue()); } } @@ -160,11 +175,11 @@ void LayerHistory::partitionLayers(nsecs_t now) { // Collect expired and inactive layers after active layers. size_t i = 0; while (i < mActiveLayersEnd) { - auto& [weak, info] = mLayerInfos[i]; - if (const auto layer = weak.promote(); layer && isLayerActive(*layer, *info, threshold)) { + auto& [layerUnsafe, info] = mLayerInfos[i]; + if (isLayerActive(*info, threshold)) { i++; // Set layer vote if set - const auto frameRate = layer->getFrameRateForLayerTree(); + const auto frameRate = info->getSetFrameRateVote(); const auto voteType = [&]() { switch (frameRate.type) { case Layer::FrameRateCompatibility::Default: @@ -179,7 +194,7 @@ void LayerHistory::partitionLayers(nsecs_t now) { }(); if (frameRate.rate.isValid() || voteType == LayerVoteType::NoVote) { - const auto type = layer->isVisible() ? voteType : LayerVoteType::NoVote; + const auto type = info->isVisible() ? voteType : LayerVoteType::NoVote; info->setLayerVote({type, frameRate.rate, frameRate.seamlessness}); } else { info->resetLayerVote(); @@ -188,24 +203,12 @@ void LayerHistory::partitionLayers(nsecs_t now) { } if (CC_UNLIKELY(mTraceEnabled)) { - trace(weak, *info, LayerHistory::LayerVoteType::NoVote, 0); + trace(*info, LayerHistory::LayerVoteType::NoVote, 0); } info->onLayerInactive(now); std::swap(mLayerInfos[i], mLayerInfos[--mActiveLayersEnd]); } - - // Collect expired layers after inactive layers. - size_t end = mLayerInfos.size(); - while (i < end) { - if (mLayerInfos[i].first.promote()) { - i++; - } else { - std::swap(mLayerInfos[i], mLayerInfos[--end]); - } - } - - mLayerInfos.erase(mLayerInfos.begin() + static_cast<long>(end), mLayerInfos.end()); } void LayerHistory::clear() { diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h index 05ecc705cc..82f6c3907b 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.h +++ b/services/surfaceflinger/Scheduler/LayerHistory.h @@ -70,13 +70,15 @@ public: Summary summarize(nsecs_t now); void clear(); + + void deregisterLayer(Layer*); std::string dump() const; private: friend LayerHistoryTest; friend TestableScheduler; - using LayerPair = std::pair<wp<Layer>, std::unique_ptr<LayerInfo>>; + using LayerPair = std::pair<Layer*, std::unique_ptr<LayerInfo>>; using LayerInfos = std::vector<LayerPair>; struct ActiveLayers { diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp index 4b4cdaea09..989bf4ef19 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp @@ -37,17 +37,20 @@ namespace android::scheduler { const RefreshRateConfigs* LayerInfo::sRefreshRateConfigs = nullptr; bool LayerInfo::sTraceEnabled = false; -LayerInfo::LayerInfo(const std::string& name, LayerHistory::LayerVoteType defaultVote) +LayerInfo::LayerInfo(const std::string& name, uid_t ownerUid, + LayerHistory::LayerVoteType defaultVote) : mName(name), + mOwnerUid(ownerUid), mDefaultVote(defaultVote), mLayerVote({defaultVote, Fps(0.0f)}), mRefreshRateHistory(name) {} void LayerInfo::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now, LayerUpdateType updateType, - bool pendingModeChange) { + bool pendingModeChange, LayerProps props) { lastPresentTime = std::max(lastPresentTime, static_cast<nsecs_t>(0)); mLastUpdatedTime = std::max(lastPresentTime, now); + mLayerProps = props; switch (updateType) { case LayerUpdateType::AnimationTX: mLastAnimationTime = std::max(lastPresentTime, now); @@ -232,6 +235,8 @@ LayerInfo::LayerVote LayerInfo::getRefreshRateVote(nsecs_t now) { if (!isFrequent(now)) { ALOGV("%s is infrequent", mName.c_str()); mLastRefreshRate.animatingOrInfrequent = true; + // Infrequent layers vote for mininal refresh rate for + // battery saving purposes and also to prevent b/135718869. return {LayerHistory::LayerVoteType::Min, Fps(0.0f)}; } diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h index 40c0214408..ba03c89a1d 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.h +++ b/services/surfaceflinger/Scheduler/LayerInfo.h @@ -16,6 +16,7 @@ #pragma once +#include <ui/Transform.h> #include <utils/Timers.h> #include <chrono> @@ -65,22 +66,84 @@ public: Seamlessness seamlessness = Seamlessness::Default; }; + // FrameRateCompatibility specifies how we should interpret the frame rate associated with + // the layer. + enum class FrameRateCompatibility { + Default, // Layer didn't specify any specific handling strategy + + Exact, // Layer needs the exact frame rate. + + ExactOrMultiple, // Layer needs the exact frame rate (or a multiple of it) to present the + // content properly. Any other value will result in a pull down. + + NoVote, // Layer doesn't have any requirements for the refresh rate and + // should not be considered when the display refresh rate is determined. + }; + + // Encapsulates the frame rate and compatibility of the layer. This information will be used + // when the display refresh rate is determined. + struct FrameRate { + using Seamlessness = scheduler::Seamlessness; + + Fps rate; + FrameRateCompatibility type; + Seamlessness seamlessness; + + FrameRate() + : rate(0), + type(FrameRateCompatibility::Default), + seamlessness(Seamlessness::Default) {} + FrameRate(Fps rate, FrameRateCompatibility type, + Seamlessness seamlessness = Seamlessness::OnlySeamless) + : rate(rate), type(type), seamlessness(getSeamlessness(rate, seamlessness)) {} + + bool operator==(const FrameRate& other) const { + return rate.equalsWithMargin(other.rate) && type == other.type && + seamlessness == other.seamlessness; + } + + bool operator!=(const FrameRate& other) const { return !(*this == other); } + + // Convert an ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* value to a + // Layer::FrameRateCompatibility. Logs fatal if the compatibility value is invalid. + static FrameRateCompatibility convertCompatibility(int8_t compatibility); + static scheduler::Seamlessness convertChangeFrameRateStrategy(int8_t strategy); + + private: + static Seamlessness getSeamlessness(Fps rate, Seamlessness seamlessness) { + if (!rate.isValid()) { + // Refresh rate of 0 is a special value which should reset the vote to + // its default value. + return Seamlessness::Default; + } + return seamlessness; + } + }; + static void setTraceEnabled(bool enabled) { sTraceEnabled = enabled; } static void setRefreshRateConfigs(const RefreshRateConfigs& refreshRateConfigs) { sRefreshRateConfigs = &refreshRateConfigs; } - LayerInfo(const std::string& name, LayerHistory::LayerVoteType defaultVote); + LayerInfo(const std::string& name, uid_t ownerUid, LayerHistory::LayerVoteType defaultVote); LayerInfo(const LayerInfo&) = delete; LayerInfo& operator=(const LayerInfo&) = delete; + struct LayerProps { + bool visible = false; + FloatRect bounds; + ui::Transform transform; + FrameRate setFrameRateVote; + int32_t frameRateSelectionPriority = -1; + }; + // Records the last requested present time. It also stores information about when // the layer was last updated. If the present time is farther in the future than the // updated time, the updated time is the present time. void setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now, LayerUpdateType updateType, - bool pendingModeChange); + bool pendingModeChange, LayerProps props); // Sets an explicit layer vote. This usually comes directly from the application via // ANativeWindow_setFrameRate API @@ -94,12 +157,24 @@ public: // Resets the layer vote to its default. void resetLayerVote() { mLayerVote = {mDefaultVote, Fps(0.0f), Seamlessness::Default}; } + std::string getName() const { return mName; } + + uid_t getOwnerUid() const { return mOwnerUid; } + LayerVote getRefreshRateVote(nsecs_t now); // Return the last updated time. If the present time is farther in the future than the // updated time, the updated time is the present time. nsecs_t getLastUpdatedTime() const { return mLastUpdatedTime; } + FrameRate getSetFrameRateVote() const { return mLayerProps.setFrameRateVote; } + bool isVisible() const { return mLayerProps.visible; } + int32_t getFrameRateSelectionPriority() const { return mLayerProps.frameRateSelectionPriority; } + + FloatRect getBounds() const { return mLayerProps.bounds; } + + ui::Transform getTransform() const { return mLayerProps.transform; } + // Returns a C string for tracing a vote const char* getTraceTag(LayerHistory::LayerVoteType type) const; @@ -193,6 +268,7 @@ private: bool isFrameTimeValid(const FrameTimeData&) const; const std::string mName; + const uid_t mOwnerUid; // Used for sanitizing the heuristic data. If two frames are less than // this period apart from each other they'll be considered as duplicates. @@ -217,6 +293,8 @@ private: static constexpr size_t HISTORY_SIZE = RefreshRateHistory::HISTORY_SIZE; static constexpr std::chrono::nanoseconds HISTORY_DURATION = 1s; + LayerProps mLayerProps; + RefreshRateHistory mRefreshRateHistory; mutable std::unordered_map<LayerHistory::LayerVoteType, std::string> mTraceTags; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 4edbdd20db..8426737597 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -580,6 +580,12 @@ void Scheduler::registerLayer(Layer* layer) { mLayerHistory->registerLayer(layer, voteType); } +void Scheduler::deregisterLayer(Layer* layer) { + if (mLayerHistory) { + mLayerHistory->deregisterLayer(layer); + } +} + void Scheduler::recordLayerHistory(Layer* layer, nsecs_t presentTime, LayerHistory::LayerUpdateType updateType) { if (mLayerHistory) { diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 0e9eba731a..d4932e7f8e 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -129,6 +129,7 @@ public: void registerLayer(Layer*); void recordLayerHistory(Layer*, nsecs_t presentTime, LayerHistory::LayerUpdateType updateType); void setModeChangePending(bool pending); + void deregisterLayer(Layer*); // Detects content using layer history, and selects a matching refresh rate. void chooseRefreshRateForContent(); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 605fef042d..9a12dfbe23 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -112,6 +112,7 @@ #include "FpsReporter.h" #include "FrameTimeline/FrameTimeline.h" #include "FrameTracer/FrameTracer.h" +#include "HdrLayerInfoReporter.h" #include "Layer.h" #include "LayerRenderArea.h" #include "LayerVector.h" @@ -285,6 +286,7 @@ const String16 sHardwareTest("android.permission.HARDWARE_TEST"); const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"); const String16 sRotateSurfaceFlinger("android.permission.ROTATE_SURFACE_FLINGER"); const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER"); +const String16 sControlDisplayBrightness("android.permission.CONTROL_DISPLAY_BRIGHTNESS"); const String16 sDump("android.permission.DUMP"); const char* KERNEL_IDLE_TIMER_PROP = "graphics.display.kernel_idle_timer.enabled"; @@ -753,6 +755,8 @@ void SurfaceFlinger::init() { getRenderEngine().primeCache(); } + getRenderEngine().onPrimaryDisplaySizeChanged(display->getSize()); + // Inform native graphics APIs whether the present timestamp is supported: const bool presentFenceReliable = @@ -1492,6 +1496,47 @@ status_t SurfaceFlinger::setDisplayBrightness(const sp<IBinder>& displayToken, .get(); } +status_t SurfaceFlinger::addHdrLayerInfoListener(const sp<IBinder>& displayToken, + const sp<gui::IHdrLayerInfoListener>& listener) { + if (!displayToken) { + return BAD_VALUE; + } + + Mutex::Autolock lock(mStateLock); + + const auto display = getDisplayDeviceLocked(displayToken); + if (!display) { + return NAME_NOT_FOUND; + } + const auto displayId = display->getId(); + sp<HdrLayerInfoReporter>& hdrInfoReporter = mHdrLayerInfoListeners[displayId]; + if (!hdrInfoReporter) { + hdrInfoReporter = sp<HdrLayerInfoReporter>::make(); + } + hdrInfoReporter->addListener(listener); + return OK; +} + +status_t SurfaceFlinger::removeHdrLayerInfoListener( + const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) { + if (!displayToken) { + return BAD_VALUE; + } + + Mutex::Autolock lock(mStateLock); + + const auto display = getDisplayDeviceLocked(displayToken); + if (!display) { + return NAME_NOT_FOUND; + } + const auto displayId = display->getId(); + sp<HdrLayerInfoReporter>& hdrInfoReporter = mHdrLayerInfoListeners[displayId]; + if (hdrInfoReporter) { + hdrInfoReporter->removeListener(listener); + } + return OK; +} + status_t SurfaceFlinger::notifyPowerBoost(int32_t boostId) { Boost powerBoost = static_cast<Boost>(boostId); @@ -1661,7 +1706,7 @@ void SurfaceFlinger::setVsyncEnabled(bool enabled) { })); } -sp<Fence> SurfaceFlinger::previousFrameFence() { +SurfaceFlinger::FenceWithFenceTime SurfaceFlinger::previousFrameFence() { // We are storing the last 2 present fences. If sf's phase offset is to be // woken up before the actual vsync but targeting the next vsync, we need to check // fence N-2 @@ -1671,9 +1716,9 @@ sp<Fence> SurfaceFlinger::previousFrameFence() { bool SurfaceFlinger::previousFramePending(int graceTimeMs) { ATRACE_CALL(); - const sp<Fence>& fence = previousFrameFence(); + const std::shared_ptr<FenceTime>& fence = previousFrameFence().fenceTime; - if (fence == Fence::NO_FENCE) { + if (fence == FenceTime::NO_FENCE) { return false; } @@ -1684,9 +1729,9 @@ bool SurfaceFlinger::previousFramePending(int graceTimeMs) { } nsecs_t SurfaceFlinger::previousFramePresentTime() { - const sp<Fence>& fence = previousFrameFence(); + const std::shared_ptr<FenceTime>& fence = previousFrameFence().fenceTime; - if (fence == Fence::NO_FENCE) { + if (fence == FenceTime::NO_FENCE) { return Fence::SIGNAL_TIME_INVALID; } @@ -2081,16 +2126,17 @@ void SurfaceFlinger::postComposition() { getBE().mDisplayTimeline.updateSignalTimes(); mPreviousPresentFences[1] = mPreviousPresentFences[0]; - mPreviousPresentFences[0] = + mPreviousPresentFences[0].fence = display ? getHwComposer().getPresentFence(display->getPhysicalId()) : Fence::NO_FENCE; - auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFences[0]); - getBE().mDisplayTimeline.push(presentFenceTime); + mPreviousPresentFences[0].fenceTime = + std::make_shared<FenceTime>(mPreviousPresentFences[0].fence); + + getBE().mDisplayTimeline.push(mPreviousPresentFences[0].fenceTime); // Set presentation information before calling Layer::releasePendingBuffer, such that jank // information from previous' frame classification is already available when sending jank info // to clients, so they get jank classification as early as possible. - mFrameTimeline->setSfPresent(systemTime(), - std::make_shared<FenceTime>(mPreviousPresentFences[0]), + mFrameTimeline->setSfPresent(systemTime(), mPreviousPresentFences[0].fenceTime, glCompositionDoneFenceTime != FenceTime::NO_FENCE); nsecs_t dequeueReadyTime = systemTime(); @@ -2104,7 +2150,7 @@ void SurfaceFlinger::postComposition() { // be sampled a little later than when we started doing work for this frame, // but that should be okay since updateCompositorTiming has snapping logic. updateCompositorTiming(stats, mCompositionEngine->getLastFrameRefreshTimestamp(), - presentFenceTime); + mPreviousPresentFences[0].fenceTime); CompositorTiming compositorTiming; { std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock); @@ -2112,26 +2158,74 @@ void SurfaceFlinger::postComposition() { } mDrawingState.traverse([&](Layer* layer) { - const bool frameLatched = layer->onPostComposition(display, glCompositionDoneFenceTime, - presentFenceTime, compositorTiming); + const bool frameLatched = + layer->onPostComposition(display, glCompositionDoneFenceTime, + mPreviousPresentFences[0].fenceTime, compositorTiming); if (frameLatched) { recordBufferingStats(layer->getName(), layer->getOccupancyHistory(false)); } }); + std::vector<std::pair<std::shared_ptr<compositionengine::Display>, sp<HdrLayerInfoReporter>>> + hdrInfoListeners; { Mutex::Autolock lock(mStateLock); if (mFpsReporter) { mFpsReporter->dispatchLayerFps(); } + hdrInfoListeners.reserve(mHdrLayerInfoListeners.size()); + for (auto& [key, value] : mHdrLayerInfoListeners) { + if (value && value->hasListeners()) { + auto listenersDisplay = getDisplayById(key); + if (listenersDisplay) { + hdrInfoListeners.emplace_back(listenersDisplay->getCompositionDisplay(), value); + } + } + } } - mTransactionCallbackInvoker.addPresentFence(mPreviousPresentFences[0]); + for (auto& [compositionDisplay, listener] : hdrInfoListeners) { + HdrLayerInfoReporter::HdrLayerInfo info; + int32_t maxArea = 0; + mDrawingState.traverse([&, compositionDisplay = compositionDisplay](Layer* layer) { + if (layer->isVisible() && + compositionDisplay->belongsInOutput(layer->getCompositionEngineLayerFE())) { + bool isHdr = false; + switch (layer->getDataSpace()) { + case ui::Dataspace::BT2020: + case ui::Dataspace::BT2020_HLG: + case ui::Dataspace::BT2020_PQ: + case ui::Dataspace::BT2020_ITU: + case ui::Dataspace::BT2020_ITU_HLG: + case ui::Dataspace::BT2020_ITU_PQ: + isHdr = true; + break; + default: + isHdr = false; + break; + } + + if (isHdr) { + info.numberOfHdrLayers++; + auto bufferRect = layer->getCompositionState()->geomBufferSize; + int32_t area = bufferRect.width() * bufferRect.height(); + if (area > maxArea) { + maxArea = area; + info.maxW = bufferRect.width(); + info.maxH = bufferRect.height(); + } + } + } + }); + listener->dispatchHdrLayerInfo(info); + } + + mTransactionCallbackInvoker.addPresentFence(mPreviousPresentFences[0].fence); mTransactionCallbackInvoker.sendCallbacks(); if (display && display->isPrimary() && display->getPowerMode() == hal::PowerMode::ON && - presentFenceTime->isValid()) { - mScheduler->addPresentFence(presentFenceTime); + mPreviousPresentFences[0].fenceTime->isValid()) { + mScheduler->addPresentFence(mPreviousPresentFences[0].fenceTime); } const bool isDisplayConnected = @@ -2146,9 +2240,8 @@ void SurfaceFlinger::postComposition() { if (mAnimCompositionPending) { mAnimCompositionPending = false; - if (presentFenceTime->isValid()) { - mAnimFrameTracker.setActualPresentFence( - std::move(presentFenceTime)); + if (mPreviousPresentFences[0].fenceTime->isValid()) { + mAnimFrameTracker.setActualPresentFence(mPreviousPresentFences[0].fenceTime); } else if (isDisplayConnected) { // The HWC doesn't support present fences, so use the refresh // timestamp instead. @@ -2167,7 +2260,7 @@ void SurfaceFlinger::postComposition() { mTimeStats->incrementClientCompositionReusedFrames(); } - mTimeStats->setPresentFenceGlobal(presentFenceTime); + mTimeStats->setPresentFenceGlobal(mPreviousPresentFences[0].fenceTime); const size_t sfConnections = mScheduler->getEventThreadConnectionCount(mSfConnectionHandle); const size_t appConnections = mScheduler->getEventThreadConnectionCount(mAppConnectionHandle); @@ -2590,6 +2683,7 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken, if (display->isPrimary()) { mScheduler->onPrimaryDisplayAreaChanged(display->getWidth() * display->getHeight()); + getRenderEngine().onPrimaryDisplaySizeChanged(display->getSize()); } } @@ -3223,8 +3317,12 @@ status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBind } } - if (const auto display = getDefaultDisplayDeviceLocked()) { - lbc->updateTransformHint(display->getTransformHint()); + if (const auto token = getInternalDisplayTokenLocked()) { + const ssize_t index = mCurrentState.displays.indexOfKey(token); + if (index >= 0) { + const DisplayDeviceState& state = mCurrentState.displays.valueAt(index); + lbc->updateTransformHint(ui::Transform::toRotationFlags(state.orientation)); + } } if (outTransformHint) { *outTransformHint = lbc->getTransformHint(); @@ -3275,7 +3373,7 @@ void SurfaceFlinger::flushTransactionQueues() { // states) around outside the scope of the lock std::vector<const TransactionState> transactions; // Layer handles that have transactions with buffers that are ready to be applied. - std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>> pendingBuffers; + std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>> bufferLayersReadyToPresent; { Mutex::Autolock _l(mStateLock); { @@ -3291,10 +3389,13 @@ void SurfaceFlinger::flushTransactionQueues() { transaction.isAutoTimestamp, transaction.desiredPresentTime, transaction.originUid, transaction.states, - pendingBuffers)) { + bufferLayersReadyToPresent)) { setTransactionFlags(eTransactionFlushNeeded); break; } + transaction.traverseStatesWithBuffers([&](const layer_state_t& state) { + bufferLayersReadyToPresent.insert(state.surface); + }); transactions.emplace_back(std::move(transaction)); transactionQueue.pop(); } @@ -3315,14 +3416,17 @@ void SurfaceFlinger::flushTransactionQueues() { auto& transaction = mTransactionQueue.front(); bool pendingTransactions = mPendingTransactionQueues.find(transaction.applyToken) != mPendingTransactionQueues.end(); - if (!transactionIsReadyToBeApplied(transaction.frameTimelineInfo, + if (pendingTransactions || + !transactionIsReadyToBeApplied(transaction.frameTimelineInfo, transaction.isAutoTimestamp, transaction.desiredPresentTime, transaction.originUid, transaction.states, - pendingBuffers) || - pendingTransactions) { + bufferLayersReadyToPresent)) { mPendingTransactionQueues[transaction.applyToken].push(std::move(transaction)); } else { + transaction.traverseStatesWithBuffers([&](const layer_state_t& state) { + bufferLayersReadyToPresent.insert(state.surface); + }); transactions.emplace_back(std::move(transaction)); } mTransactionQueue.pop(); @@ -3377,28 +3481,28 @@ bool SurfaceFlinger::frameIsEarly(nsecs_t expectedPresentTime, int64_t vsyncId) bool SurfaceFlinger::transactionIsReadyToBeApplied( const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime, uid_t originUid, const Vector<ComposerState>& states, - std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>& pendingBuffers) { + const std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>& + bufferLayersReadyToPresent) const { ATRACE_CALL(); const nsecs_t expectedPresentTime = mExpectedPresentTime.load(); - bool ready = true; // Do not present if the desiredPresentTime has not passed unless it is more than one second // in the future. We ignore timestamps more than 1 second in the future for stability reasons. if (!isAutoTimestamp && desiredPresentTime >= expectedPresentTime && desiredPresentTime < expectedPresentTime + s2ns(1)) { ATRACE_NAME("not current"); - ready = false; + return false; } if (!mScheduler->isVsyncValid(expectedPresentTime, originUid)) { ATRACE_NAME("!isVsyncValid"); - ready = false; + return false; } // If the client didn't specify desiredPresentTime, use the vsyncId to determine the expected // present time of this transaction. if (isAutoTimestamp && frameIsEarly(expectedPresentTime, info.vsyncId)) { ATRACE_NAME("frameIsEarly"); - ready = false; + return false; } for (const ComposerState& state : states) { @@ -3407,7 +3511,7 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied( if (acquireFenceChanged && s.acquireFence && s.acquireFence->getStatus() == Fence::Status::Unsignaled) { ATRACE_NAME("fence unsignaled"); - ready = false; + return false; } sp<Layer> layer = nullptr; @@ -3426,15 +3530,15 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied( if (s.hasBufferChanges()) { // If backpressure is enabled and we already have a buffer to commit, keep the // transaction in the queue. - const bool hasPendingBuffer = pendingBuffers.find(s.surface) != pendingBuffers.end(); + const bool hasPendingBuffer = + bufferLayersReadyToPresent.find(s.surface) != bufferLayersReadyToPresent.end(); if (layer->backpressureEnabled() && hasPendingBuffer && isAutoTimestamp) { ATRACE_NAME("hasPendingBuffer"); - ready = false; + return false; } - pendingBuffers.insert(s.surface); } } - return ready; + return true; } void SurfaceFlinger::queueTransaction(TransactionState& state) { @@ -3504,13 +3608,6 @@ status_t SurfaceFlinger::setTransactionState( const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId) { ATRACE_CALL(); - // Check for incoming buffer updates and increment the pending buffer count. - for (const auto& state : states) { - if (state.state.hasBufferChanges() && (state.state.surface)) { - mBufferCountTracker.increment(state.state.surface->localBinder()); - } - } - uint32_t permissions = callingThreadHasUnscopedSurfaceFlingerAccess() ? Permission::ACCESS_SURFACE_FLINGER : 0; // Avoid checking for rotation permissions if the caller already has ACCESS_SURFACE_FLINGER @@ -3539,6 +3636,11 @@ status_t SurfaceFlinger::setTransactionState( permissions, hasListenerCallbacks, listenerCallbacks, originPid, originUid, transactionId}; + + // Check for incoming buffer updates and increment the pending buffer count. + state.traverseStatesWithBuffers([&](const layer_state_t& state) { + mBufferCountTracker.increment(state.surface->localBinder()); + }); queueTransaction(state); // Check the pending state to make sure the transaction is synchronous. @@ -3877,11 +3979,6 @@ uint32_t SurfaceFlinger::setClientStateLocked( // We don't trigger a traversal here because if no other state is // changed, we don't want this to cause any more work } - if (what & layer_state_t::eReparentChildren) { - if (layer->reparentChildren(s.reparentSurfaceControl->getHandle())) { - flags |= eTransactionNeeded|eTraversalNeeded; - } - } if (what & layer_state_t::eTransformChanged) { if (layer->setTransform(s.transform)) flags |= eTraversalNeeded; } @@ -5069,6 +5166,20 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { // This is not sensitive information, so should not require permission control. return OK; } + case ADD_HDR_LAYER_INFO_LISTENER: + case REMOVE_HDR_LAYER_INFO_LISTENER: { + // TODO (b/183985553): Should getting & setting brightness be part of this...? + // codes that require permission check + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + if ((uid != AID_GRAPHICS) && + !PermissionCache::checkPermission(sControlDisplayBrightness, pid, uid)) { + ALOGE("Permission Denial: can't control brightness pid=%d, uid=%d", pid, uid); + return PERMISSION_DENIED; + } + return OK; + } case ADD_FPS_LISTENER: case REMOVE_FPS_LISTENER: case ADD_REGION_SAMPLING_LISTENER: @@ -5630,6 +5741,15 @@ sp<DisplayDevice> SurfaceFlinger::getDisplayByIdOrLayerStack(uint64_t displayOrL return getDisplayByLayerStack(displayOrLayerStack); } +sp<DisplayDevice> SurfaceFlinger::getDisplayById(DisplayId displayId) const { + for (const auto& [token, display] : mDisplays) { + if (display->getId() == displayId) { + return display; + } + } + return nullptr; +} + sp<DisplayDevice> SurfaceFlinger::getDisplayByLayerStack(uint64_t layerStack) { for (const auto& [token, display] : mDisplays) { if (display->getLayerStack() == layerStack) { @@ -5886,11 +6006,8 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, const status_t bufferStatus = buffer->initCheck(); LOG_ALWAYS_FATAL_IF(bufferStatus != OK, "captureScreenCommon: Buffer failed to allocate: %d", bufferStatus); - getRenderEngine().cacheExternalTextureBuffer(buffer); - status_t result = captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, - false /* regionSampling */, grayscale, captureListener); - getRenderEngine().unbindExternalTextureBuffer(buffer->getId()); - return result; + return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, buffer, + false /* regionSampling */, grayscale, captureListener); } status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, @@ -5930,6 +6047,15 @@ status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture, regionSampling, grayscale, captureResults); }); + // TODO(b/180767535): Remove this once we optimize buffer lifecycle for RenderEngine + // Only do this when we're not doing region sampling, to allow the region sampling thread to + // manage buffer lifecycle itself. + if (!regionSampling && + getRenderEngine().getRenderEngineType() == + renderengine::RenderEngine::RenderEngineType::SKIA_GL_THREADED) { + getRenderEngine().unbindExternalTextureBuffer(buffer->getId()); + } + captureResults.result = result; captureListener->onScreenCaptureCompleted(captureResults); })); @@ -6279,7 +6405,7 @@ wp<Layer> SurfaceFlinger::fromHandle(const sp<IBinder>& handle) { return fromHandleLocked(handle); } -wp<Layer> SurfaceFlinger::fromHandleLocked(const sp<IBinder>& handle) { +wp<Layer> SurfaceFlinger::fromHandleLocked(const sp<IBinder>& handle) const { BBinder* b = nullptr; if (handle) { b = handle->localBinder(); @@ -6300,6 +6426,7 @@ void SurfaceFlinger::onLayerFirstRef(Layer* layer) { } void SurfaceFlinger::onLayerDestroyed(Layer* layer) { + mScheduler->deregisterLayer(layer); mNumLayers--; removeFromOffscreenLayers(layer); } @@ -6524,6 +6651,15 @@ status_t SurfaceFlinger::getExtraBufferCount(int* extraBuffers) const { return NO_ERROR; } +void SurfaceFlinger::TransactionState::traverseStatesWithBuffers( + std::function<void(const layer_state_t&)> visitor) { + for (const auto& state : states) { + if (state.state.hasBufferChanges() && (state.state.surface)) { + visitor(state.state); + } + } +} + } // namespace android #if defined(__gl_h_) diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 8fdad6862b..b3da61e810 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -90,6 +90,7 @@ namespace android { class Client; class EventThread; class FpsReporter; +class HdrLayerInfoReporter; class HWComposer; struct SetInputWindowsListener; class IGraphicBufferProducer; @@ -329,7 +330,7 @@ public: // Otherwise, returns a weak reference so that callers off the main-thread // won't accidentally hold onto the last strong reference. wp<Layer> fromHandle(const sp<IBinder>& handle); - wp<Layer> fromHandleLocked(const sp<IBinder>& handle) REQUIRES(mStateLock); + wp<Layer> fromHandleLocked(const sp<IBinder>& handle) const REQUIRES(mStateLock); // Inherit from ClientCache::ErasedRecipient void bufferErased(const client_cache_t& clientCacheId) override; @@ -536,6 +537,8 @@ private: originUid(originUid), id(transactionId) {} + void traverseStatesWithBuffers(std::function<void(const layer_state_t&)> visitor); + FrameTimelineInfo frameTimelineInfo; Vector<ComposerState> states; Vector<DisplayState> displays; @@ -684,6 +687,10 @@ private: bool* outSupport) const override; status_t setDisplayBrightness(const sp<IBinder>& displayToken, const gui::DisplayBrightness& brightness) override; + status_t addHdrLayerInfoListener(const sp<IBinder>& displayToken, + const sp<gui::IHdrLayerInfoListener>& listener) override; + status_t removeHdrLayerInfoListener(const sp<IBinder>& displayToken, + const sp<gui::IHdrLayerInfoListener>& listener) override; status_t notifyPowerBoost(int32_t boostId) override; status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, float lightPosY, float lightPosZ, float lightRadius) override; @@ -841,8 +848,8 @@ private: bool transactionIsReadyToBeApplied( const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime, uid_t originUid, const Vector<ComposerState>& states, - std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>& pendingBuffers) - REQUIRES(mStateLock); + const std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>& + bufferLayersReadyToPresent) const REQUIRES(mStateLock); uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock); uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands) REQUIRES(mStateLock); @@ -908,6 +915,7 @@ private: bool grayscale, ScreenCaptureResults&); sp<DisplayDevice> getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock); + sp<DisplayDevice> getDisplayById(DisplayId displayId) const REQUIRES(mStateLock); sp<DisplayDevice> getDisplayByLayerStack(uint64_t layerStack) REQUIRES(mStateLock); // If the uid provided is not UNSET_UID, the traverse will skip any layers that don't have a @@ -1013,9 +1021,14 @@ private: bool isDisplayModeAllowed(DisplayModeId) const REQUIRES(mStateLock); + struct FenceWithFenceTime { + sp<Fence> fence = Fence::NO_FENCE; + std::shared_ptr<FenceTime> fenceTime = FenceTime::NO_FENCE; + }; + // Gets the fence for the previous frame. // Must be called on the main thread. - sp<Fence> previousFrameFence(); + FenceWithFenceTime previousFrameFence(); // Whether the previous frame has not yet been presented to the display. // If graceTimeMs is positive, this method waits for at most the provided @@ -1193,7 +1206,7 @@ private: std::unordered_set<sp<Layer>, ISurfaceComposer::SpHash<Layer>> mLayersWithQueuedFrames; // Tracks layers that need to update a display's dirty region. std::vector<sp<Layer>> mLayersPendingRefresh; - std::array<sp<Fence>, 2> mPreviousPresentFences = {Fence::NO_FENCE, Fence::NO_FENCE}; + std::array<FenceWithFenceTime, 2> mPreviousPresentFences; // True if in the previous frame at least one layer was composed via the GPU. bool mHadClientComposition = false; // True if in the previous frame at least one layer was composed via HW Composer. @@ -1379,6 +1392,9 @@ private: sp<IBinder> mDebugFrameRateFlexibilityToken; BufferCountTracker mBufferCountTracker; + + std::unordered_map<DisplayId, sp<HdrLayerInfoReporter>> mHdrLayerInfoListeners + GUARDED_BY(mStateLock); }; } // namespace android diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp index 8a3be9f4ed..b49562a0a5 100644 --- a/services/surfaceflinger/SurfaceInterceptor.cpp +++ b/services/surfaceflinger/SurfaceInterceptor.cpp @@ -401,13 +401,6 @@ void SurfaceInterceptor::addReparentLocked(Transaction* transaction, int32_t lay overrideChange->set_parent_id(parentId); } -void SurfaceInterceptor::addReparentChildrenLocked(Transaction* transaction, int32_t layerId, - int32_t parentId) { - SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId)); - ReparentChildrenChange* overrideChange(change->mutable_reparent_children()); - overrideChange->set_parent_id(parentId); -} - void SurfaceInterceptor::addRelativeParentLocked(Transaction* transaction, int32_t layerId, int32_t parentId, int z) { SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId)); @@ -486,10 +479,6 @@ void SurfaceInterceptor::addSurfaceChangesLocked(Transaction* transaction, : nullptr; addReparentLocked(transaction, layerId, getLayerIdFromHandle(parentHandle)); } - if (state.what & layer_state_t::eReparentChildren) { - addReparentChildrenLocked(transaction, layerId, - getLayerIdFromHandle(state.reparentSurfaceControl->getHandle())); - } if (state.what & layer_state_t::eRelativeLayerChanged) { addRelativeParentLocked(transaction, layerId, getLayerIdFromHandle( diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h index 3e27e83b02..d2cbf40426 100644 --- a/services/surfaceflinger/SurfaceInterceptor.h +++ b/services/surfaceflinger/SurfaceInterceptor.h @@ -176,7 +176,6 @@ private: uint32_t transactionFlags, int originPid, int originUid, uint64_t transactionId); void addReparentLocked(Transaction* transaction, int32_t layerId, int32_t parentId); - void addReparentChildrenLocked(Transaction* transaction, int32_t layerId, int32_t parentId); void addRelativeParentLocked(Transaction* transaction, int32_t layerId, int32_t parentId, int z); void addShadowRadiusLocked(Transaction* transaction, int32_t layerId, float shadowRadius); diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp index e5c2ec8bfb..39d9206e1a 100644 --- a/services/surfaceflinger/tests/LayerUpdate_test.cpp +++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp @@ -462,38 +462,6 @@ TEST_F(ChildLayerTest, ChildLayerAlpha) { } } -TEST_F(ChildLayerTest, ReparentChildren) { - asTransaction([&](Transaction& t) { - t.show(mChild); - t.setPosition(mChild, 10, 10); - t.setPosition(mFGSurfaceControl, 64, 64); - }); - - { - mCapture = screenshot(); - // Top left of foreground must now be visible - mCapture->expectFGColor(64, 64); - // But 10 pixels in we should see the child surface - mCapture->expectChildColor(74, 74); - // And 10 more pixels we should be back to the foreground surface - mCapture->expectFGColor(84, 84); - } - - asTransaction( - [&](Transaction& t) { t.reparentChildren(mFGSurfaceControl, mBGSurfaceControl); }); - - { - mCapture = screenshot(); - mCapture->expectFGColor(64, 64); - // In reparenting we should have exposed the entire foreground surface. - mCapture->expectFGColor(74, 74); - // And the child layer should now begin at 10, 10 (since the BG - // layer is at (0, 0)). - mCapture->expectBGColor(9, 9); - mCapture->expectChildColor(10, 10); - } -} - TEST_F(ChildLayerTest, ChildrenSurviveParentDestruction) { sp<SurfaceControl> mGrandChild = createSurface(mClient, "Grand Child", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mChild.get()); @@ -539,7 +507,7 @@ TEST_F(ChildLayerTest, ChildrenRelativeZSurvivesParentDestruction) { asTransaction([&](Transaction& t) { t.reparent(mChild, nullptr); - t.reparentChildren(mChild, mFGSurfaceControl); + t.reparent(mGrandChild, mFGSurfaceControl); }); { diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp index d9cab42aae..09bd775872 100644 --- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp +++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp @@ -194,7 +194,6 @@ public: bool deferredTransactionUpdateFound(const SurfaceChange& change, bool foundDeferred); bool reparentUpdateFound(const SurfaceChange& change, bool found); bool relativeParentUpdateFound(const SurfaceChange& change, bool found); - bool reparentChildrenUpdateFound(const SurfaceChange& change, bool found); bool shadowRadiusUpdateFound(const SurfaceChange& change, bool found); bool surfaceUpdateFound(const Trace& trace, SurfaceChange::SurfaceChangeCase changeCase); @@ -231,7 +230,6 @@ public: void deferredTransactionUpdate(Transaction&); void reparentUpdate(Transaction&); void relativeParentUpdate(Transaction&); - void reparentChildrenUpdate(Transaction&); void shadowRadiusUpdate(Transaction&); void surfaceCreation(Transaction&); void displayCreation(Transaction&); @@ -410,10 +408,6 @@ void SurfaceInterceptorTest::relativeParentUpdate(Transaction& t) { t.setRelativeLayer(mBGSurfaceControl, mFGSurfaceControl, RELATIVE_Z); } -void SurfaceInterceptorTest::reparentChildrenUpdate(Transaction& t) { - t.reparentChildren(mBGSurfaceControl, mFGSurfaceControl); -} - void SurfaceInterceptorTest::shadowRadiusUpdate(Transaction& t) { t.setShadowRadius(mBGSurfaceControl, SHADOW_RADIUS_UPDATE); } @@ -445,7 +439,6 @@ void SurfaceInterceptorTest::runAllUpdates() { runInTransaction(&SurfaceInterceptorTest::secureFlagUpdate); runInTransaction(&SurfaceInterceptorTest::deferredTransactionUpdate); runInTransaction(&SurfaceInterceptorTest::reparentUpdate); - runInTransaction(&SurfaceInterceptorTest::reparentChildrenUpdate); runInTransaction(&SurfaceInterceptorTest::relativeParentUpdate); runInTransaction(&SurfaceInterceptorTest::shadowRadiusUpdate); } @@ -660,16 +653,6 @@ bool SurfaceInterceptorTest::relativeParentUpdateFound(const SurfaceChange& chan return found; } -bool SurfaceInterceptorTest::reparentChildrenUpdateFound(const SurfaceChange& change, bool found) { - bool hasId(change.reparent_children().parent_id() == mFGLayerId); - if (hasId && !found) { - found = true; - } else if (hasId && found) { - []() { FAIL(); }(); - } - return found; -} - bool SurfaceInterceptorTest::shadowRadiusUpdateFound(const SurfaceChange& change, bool foundShadowRadius) { bool hasShadowRadius(change.shadow_radius().radius() == SHADOW_RADIUS_UPDATE); @@ -738,9 +721,6 @@ bool SurfaceInterceptorTest::surfaceUpdateFound(const Trace& trace, case SurfaceChange::SurfaceChangeCase::kReparent: foundUpdate = reparentUpdateFound(change, foundUpdate); break; - case SurfaceChange::SurfaceChangeCase::kReparentChildren: - foundUpdate = reparentChildrenUpdateFound(change, foundUpdate); - break; case SurfaceChange::SurfaceChangeCase::kRelativeParent: foundUpdate = relativeParentUpdateFound(change, foundUpdate); break; @@ -771,7 +751,6 @@ void SurfaceInterceptorTest::assertAllUpdatesFound(const Trace& trace) { ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kSecureFlag)); ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kDeferredTransaction)); ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kReparent)); - ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kReparentChildren)); ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kRelativeParent)); } @@ -937,11 +916,6 @@ TEST_F(SurfaceInterceptorTest, InterceptReparentUpdateWorks) { SurfaceChange::SurfaceChangeCase::kReparent); } -TEST_F(SurfaceInterceptorTest, InterceptReparentChildrenUpdateWorks) { - captureTest(&SurfaceInterceptorTest::reparentChildrenUpdate, - SurfaceChange::SurfaceChangeCase::kReparentChildren); -} - TEST_F(SurfaceInterceptorTest, InterceptRelativeParentUpdateWorks) { captureTest(&SurfaceInterceptorTest::relativeParentUpdate, SurfaceChange::SurfaceChangeCase::kRelativeParent); diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp index 820f248dbb..c081f9b642 100644 --- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp +++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp @@ -1766,30 +1766,6 @@ protected: EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame())); } - void Test_ReparentChildren() { - { - TransactionScope ts(*Base::sFakeComposer); - ts.show(mChild); - ts.setPosition(mChild, 10, 10); - ts.setPosition(Base::mFGSurfaceControl, 64, 64); - } - auto referenceFrame = Base::mBaseFrame; - referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64}; - referenceFrame[CHILD_LAYER].mDisplayFrame = - hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10}; - EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame())); - - { - TransactionScope ts(*Base::sFakeComposer); - ts.reparentChildren(Base::mFGSurfaceControl, Base::mBGSurfaceControl); - } - - auto referenceFrame2 = referenceFrame; - referenceFrame2[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64}; - referenceFrame2[CHILD_LAYER].mDisplayFrame = hwc_rect_t{10, 10, 10 + 10, 10 + 10}; - EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame())); - } - // Regression test for b/37673612 void Test_ChildrenWithParentBufferTransform() { { @@ -1886,10 +1862,6 @@ TEST_F(ChildLayerTest_2_1, DISABLED_LayerAlpha) { Test_LayerAlpha(); } -TEST_F(ChildLayerTest_2_1, DISABLED_ReparentChildren) { - Test_ReparentChildren(); -} - // Regression test for b/37673612 TEST_F(ChildLayerTest_2_1, DISABLED_ChildrenWithParentBufferTransform) { Test_ChildrenWithParentBufferTransform(); diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 3c1b9d8c80..9f94c73907 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -55,6 +55,7 @@ cc_test { "EventThreadTest.cpp", "FpsReporterTest.cpp", "FpsTest.cpp", + "FramebufferSurfaceTest.cpp", "FrameTimelineTest.cpp", "HWComposerTest.cpp", "OneShotTimerTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/FramebufferSurfaceTest.cpp b/services/surfaceflinger/tests/unittests/FramebufferSurfaceTest.cpp new file mode 100644 index 0000000000..b8df640c0f --- /dev/null +++ b/services/surfaceflinger/tests/unittests/FramebufferSurfaceTest.cpp @@ -0,0 +1,40 @@ +/* + * Copyright 2021 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 "DisplayHardware/FramebufferSurface.h" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +namespace android { + +class FramebufferSurfaceTest : public testing::Test { +public: + ui::Size limitSize(const ui::Size& size, const ui::Size maxSize) { + return FramebufferSurface::limitSizeInternal(size, maxSize); + } +}; + +TEST_F(FramebufferSurfaceTest, limitSize) { + const ui::Size kMaxSize(1920, 1080); + EXPECT_EQ(ui::Size(1920, 1080), limitSize({3840, 2160}, kMaxSize)); + EXPECT_EQ(ui::Size(1920, 1080), limitSize({1920, 1080}, kMaxSize)); + EXPECT_EQ(ui::Size(1920, 1012), limitSize({4096, 2160}, kMaxSize)); + EXPECT_EQ(ui::Size(1080, 1080), limitSize({3840, 3840}, kMaxSize)); + EXPECT_EQ(ui::Size(1280, 720), limitSize({1280, 720}, kMaxSize)); +} + +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index fec590ee4c..b67ebcaa49 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -81,8 +81,8 @@ protected: void setDefaultLayerVote(Layer* layer, LayerHistory::LayerVoteType vote) NO_THREAD_SAFETY_ANALYSIS { - for (auto& [weak, info] : history().mLayerInfos) { - if (auto strong = weak.promote(); strong && strong.get() == layer) { + for (auto& [layerUnsafe, info] : history().mLayerInfos) { + if (layerUnsafe == layer) { info->setDefaultLayerVote(vote); return; } @@ -180,6 +180,7 @@ TEST_F(LayerHistoryTest, oneInvisibleLayer) { EXPECT_EQ(1, activeLayerCount()); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(false)); + history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer); summary = history().summarize(time); EXPECT_TRUE(history().summarize(time).empty()); diff --git a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp index be76e8fd2f..325fb8f680 100644 --- a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp @@ -40,7 +40,7 @@ protected: auto calculateAverageFrameTime() { return layerInfo.calculateAverageFrameTime(); } - LayerInfo layerInfo{"TestLayerInfo", LayerHistory::LayerVoteType::Heuristic}; + LayerInfo layerInfo{"TestLayerInfo", 0, LayerHistory::LayerVoteType::Heuristic}; }; namespace { diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index 7ef1f2b378..0bb7e31194 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -122,7 +122,6 @@ protected: void addChild(sp<Layer> layer, sp<Layer> child); void removeChild(sp<Layer> layer, sp<Layer> child); - void reparentChildren(sp<Layer> layer, sp<Layer> child); void commitTransaction(); TestableSurfaceFlinger mFlinger; @@ -152,10 +151,6 @@ void SetFrameRateTest::removeChild(sp<Layer> layer, sp<Layer> child) { layer.get()->removeChild(child.get()); } -void SetFrameRateTest::reparentChildren(sp<Layer> parent, sp<Layer> newParent) { - parent.get()->reparentChildren(newParent); -} - void SetFrameRateTest::commitTransaction() { for (auto layer : mLayers) { layer->pushPendingState(); @@ -433,41 +428,6 @@ TEST_P(SetFrameRateTest, SetAndGetParentNotInTree) { EXPECT_EQ(FRAME_RATE_NO_VOTE, child2_1->getFrameRateForLayerTree()); } -TEST_P(SetFrameRateTest, SetAndGetReparentChildren) { - EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); - - const auto& layerFactory = GetParam(); - - auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); - auto parent2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); - auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); - auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger)); - - addChild(parent, child1); - addChild(child1, child2); - - child2->setFrameRate(FRAME_RATE_VOTE1); - commitTransaction(); - EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree()); - EXPECT_EQ(FRAME_RATE_NO_VOTE, parent2->getFrameRateForLayerTree()); - EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); - EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); - - reparentChildren(parent, parent2); - commitTransaction(); - EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); - EXPECT_EQ(FRAME_RATE_TREE, parent2->getFrameRateForLayerTree()); - EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree()); - EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree()); - - child2->setFrameRate(FRAME_RATE_NO_VOTE); - commitTransaction(); - EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree()); - EXPECT_EQ(FRAME_RATE_NO_VOTE, parent2->getFrameRateForLayerTree()); - EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree()); - EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree()); -} - INSTANTIATE_TEST_SUITE_P(PerLayerType, SetFrameRateTest, testing::Values(std::make_shared<BufferQueueLayerFactory>(), std::make_shared<BufferStateLayerFactory>(), @@ -523,6 +483,13 @@ TEST_P(SetFrameRateTest, SetOnParentActivatesTree) { parent->setFrameRate(FRAME_RATE_VOTE1); commitTransaction(); + mFlinger.mutableScheduler() + .mutableLayerHistory() + ->record(parent.get(), 0, 0, LayerHistory::LayerUpdateType::Buffer); + mFlinger.mutableScheduler() + .mutableLayerHistory() + ->record(child.get(), 0, 0, LayerHistory::LayerUpdateType::Buffer); + const auto layerHistorySummary = mFlinger.mutableScheduler().mutableLayerHistory()->summarize(0); ASSERT_EQ(2u, layerHistorySummary.size()); diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp index 866007e188..eb24a22719 100644 --- a/services/vr/hardware_composer/Android.bp +++ b/services/vr/hardware_composer/Android.bp @@ -108,6 +108,7 @@ cc_library_static { cc_binary { name: "vr_hwc", + enabled: false, system_ext_specific: true, vintf_fragments: ["manifest_vr_hwc.xml"], srcs: [ diff --git a/vulkan/vkjson/vkjson_instance.cc b/vulkan/vkjson/vkjson_instance.cc index eb0fcc3443..587249539f 100644 --- a/vulkan/vkjson/vkjson_instance.cc +++ b/vulkan/vkjson/vkjson_instance.cc @@ -363,6 +363,10 @@ VkJsonInstance VkJsonGetInstance() { VkJsonDeviceGroup device_group; std::vector<VkPhysicalDeviceGroupProperties> group_properties; group_properties.resize(count); + for (auto& properties : group_properties) { + properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES; + properties.pNext = nullptr; + } result = vkEnumeratePhysicalDeviceGroups(vkinstance, &count, group_properties.data()); if (result != VK_SUCCESS) { |