diff --git a/Android.bp b/Android.bp index 2520a71968d84e76836bcbb1fe0c1ccef7732f93..72311f026354b2838c825546c4bdff72655e4df7 100644 --- a/Android.bp +++ b/Android.bp @@ -38,7 +38,13 @@ license { cc_library_headers { name: "native_headers", + vendor_available: true, host_supported: true, + target: { + windows: { + enabled: true, + }, + }, export_include_dirs: [ "include/", ], diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index 2ce3fb05ccfcb3b02c0b3525e1ecc8e7d9332f4d..df1ef297bf814690b06a1b99d98b3ea03f56e927 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -24,6 +24,7 @@ clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp libs/nativewindow/ libs/renderengine/ libs/ui/ + libs/vibrator/ libs/vr/ opengl/libs/ services/bufferhub/ diff --git a/cmds/atrace/Android.bp b/cmds/atrace/Android.bp index 1c4e63e323af3e008802670ae49a3349ed5b2f7b..bc69b35aaa72acad19e77cc95c98d5f7d0e9a3af 100644 --- a/cmds/atrace/Android.bp +++ b/cmds/atrace/Android.bp @@ -33,7 +33,6 @@ cc_binary { "libcutils", "libz", "libbase", - "libpdx_default_transport", "android.hardware.atrace@1.0", ], diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp index cd4926ad5027febfce24c6b644ac05ed38332334..888dc4ec0db398f39682037ea44fac39c1204008 100644 --- a/cmds/atrace/atrace.cpp +++ b/cmds/atrace/atrace.cpp @@ -41,7 +41,6 @@ #include #include -#include #include #include #include @@ -53,7 +52,6 @@ #include using namespace android; -using pdx::default_transport::ServiceUtility; using hardware::hidl_vec; using hardware::hidl_string; using hardware::Return; @@ -68,10 +66,10 @@ using std::string; const char* k_traceTagsProperty = "debug.atrace.tags.enableflags"; const char* k_userInitiatedTraceProperty = "debug.atrace.user_initiated"; +const char* k_tracePreferSdkProperty = "debug.atrace.prefer_sdk"; const char* k_traceAppsNumberProperty = "debug.atrace.app_number"; const char* k_traceAppsPropertyTemplate = "debug.atrace.app_%d"; const char* k_coreServiceCategory = "core_services"; -const char* k_pdxServiceCategory = "pdx"; const char* k_coreServicesProp = "ro.atrace.core.services"; const char* kVendorCategoriesPath = "/vendor/etc/atrace/atrace_categories.txt"; @@ -130,7 +128,6 @@ static const TracingCategory k_categories[] = { { "nnapi", "NNAPI", ATRACE_TAG_NNAPI, { } }, { "rro", "Runtime Resource Overlay", ATRACE_TAG_RRO, { } }, { k_coreServiceCategory, "Core services", 0, { } }, - { k_pdxServiceCategory, "PDX services", 0, { } }, { "sched", "CPU Scheduling", 0, { { REQ, "events/sched/sched_switch/enable" }, { REQ, "events/sched/sched_wakeup/enable" }, @@ -298,7 +295,6 @@ static const char* g_debugAppCmdLine = ""; static const char* g_outputFile = nullptr; /* Global state */ -static bool g_tracePdx = false; static bool g_traceAborted = false; static bool g_categoryEnables[arraysize(k_categories)] = {}; static std::string g_traceFolder; @@ -455,10 +451,6 @@ static bool isCategorySupported(const TracingCategory& category) return !android::base::GetProperty(k_coreServicesProp, "").empty(); } - if (strcmp(category.name, k_pdxServiceCategory) == 0) { - return true; - } - bool ok = category.tags != 0; for (int i = 0; i < MAX_SYS_FILES; i++) { const char* path = category.sysfiles[i].path; @@ -600,6 +592,17 @@ static void clearAppProperties() } } +// Set the property that's read by userspace to prefer the perfetto SDK. +static bool setPreferSdkProperty(uint64_t tags) +{ + std::string value = android::base::StringPrintf("%#" PRIx64, tags); + if (!android::base::SetProperty(k_tracePreferSdkProperty, value)) { + fprintf(stderr, "error setting prefer_sdk system property\n"); + return false; + } + return true; +} + // Set the system property that indicates which apps should perform // application-level tracing. static bool setAppCmdlineProperty(char* cmdline) @@ -806,11 +809,6 @@ static bool setUpUserspaceTracing() if (strcmp(k_categories[i].name, k_coreServiceCategory) == 0) { coreServicesTagEnabled = g_categoryEnables[i]; } - - // Set whether to poke PDX services in this session. - if (strcmp(k_categories[i].name, k_pdxServiceCategory) == 0) { - g_tracePdx = g_categoryEnables[i]; - } } std::string packageList(g_debugAppCmdLine); @@ -822,9 +820,6 @@ static bool setUpUserspaceTracing() } ok &= setAppCmdlineProperty(&packageList[0]); ok &= setTagsProperty(tags); - if (g_tracePdx) { - ok &= ServiceUtility::PokeServices(); - } return ok; } @@ -833,10 +828,6 @@ static void cleanUpUserspaceTracing() { setTagsProperty(0); clearAppProperties(); - - if (g_tracePdx) { - ServiceUtility::PokeServices(); - } } @@ -918,6 +909,17 @@ static void stopTrace() setTracingEnabled(false); } +static bool preferSdkCategories() { + uint64_t tags = 0; + for (size_t i = 0; i < arraysize(k_categories); i++) { + if (g_categoryEnables[i]) { + const TracingCategory& c = k_categories[i]; + tags |= c.tags; + } + } + return setPreferSdkProperty(tags); +} + // Read data from the tracing pipe and forward to stdout static void streamTrace() { @@ -1108,6 +1110,9 @@ static void showHelp(const char *cmd) " CPU performance, like pagecache usage.\n" " --list_categories\n" " list the available tracing categories\n" + " --prefer_sdk\n" + " prefer the perfetto sdk over legacy atrace for\n" + " categories and exits immediately\n" " -o filename write the trace to the specified file instead\n" " of stdout.\n" ); @@ -1252,6 +1257,7 @@ int main(int argc, char **argv) bool traceStop = true; bool traceDump = true; bool traceStream = false; + bool preferSdk = false; bool onlyUserspace = false; if (argc == 2 && 0 == strcmp(argv[1], "--help")) { @@ -1276,6 +1282,7 @@ int main(int argc, char **argv) {"only_userspace", no_argument, nullptr, 0 }, {"list_categories", no_argument, nullptr, 0 }, {"stream", no_argument, nullptr, 0 }, + {"prefer_sdk", no_argument, nullptr, 0 }, {nullptr, 0, nullptr, 0 } }; @@ -1348,6 +1355,8 @@ int main(int argc, char **argv) } else if (!strcmp(long_options[option_index].name, "stream")) { traceStream = true; traceDump = false; + } else if (!strcmp(long_options[option_index].name, "prefer_sdk")) { + preferSdk = true; } else if (!strcmp(long_options[option_index].name, "list_categories")) { listSupportedCategories(); exit(0); @@ -1362,6 +1371,11 @@ int main(int argc, char **argv) } } + if (preferSdk) { + bool res = preferSdkCategories(); + exit(res ? 0 : 1); + } + if (onlyUserspace) { if (!async || !(traceStart || traceStop)) { fprintf(stderr, "--only_userspace can only be used with " diff --git a/cmds/atrace/atrace_userdebug.rc b/cmds/atrace/atrace_userdebug.rc index fa7be1816a394301a56efa25eae98ab051c03d91..041ffe1c10237833633604b24fcbcf4da865806a 100644 --- a/cmds/atrace/atrace_userdebug.rc +++ b/cmds/atrace/atrace_userdebug.rc @@ -24,3 +24,7 @@ on post-fs chmod 0666 /sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/filter chmod 0666 /sys/kernel/tracing/events/raw_syscalls/sys_exit/filter chmod 0666 /sys/kernel/debug/tracing/events/raw_syscalls/sys_exit/filter + + # Allow traced_probes to use the kprobe interface + chmod 0666 /sys/kernel/debug/tracing/kprobe_events + chmod 0666 /sys/kernel/tracing/kprobe_events diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp index a1c10f59ad3b6acb7cc862313d0a81e6c506af01..b22cc2a508079a17a2d7540589824f4daf31758e 100644 --- a/cmds/dumpstate/Android.bp +++ b/cmds/dumpstate/Android.bp @@ -159,7 +159,6 @@ cc_test { "tests/dumpstate_test.cpp", ], static_libs: [ - "libc++fs", "libgmock", ], test_config: "dumpstate_test.xml", diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index 6576ffdc54ddea167edde262219476037e82117b..4e3889af61bf902b3bb2113fa3dd5dcc948034e9 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -170,6 +170,7 @@ void add_mountinfo(); #define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0" #define BLK_DEV_SYS_DIR "/sys/block" +#define AFLAGS "/system/bin/aflags" #define RECOVERY_DIR "/cache/recovery" #define RECOVERY_DATA_DIR "/data/misc/recovery" #define UPDATE_ENGINE_LOG_DIR "/data/misc/update_engine_log" @@ -1558,6 +1559,13 @@ static void DumpstateLimitedOnly() { RunDumpsys("DUMPSYS CONNECTIVITY REQUESTS", {"connectivity", "requests"}, CommandOptions::WithTimeout(90).Build(), SEC_TO_MSEC(10)); + printf("========================================================\n"); + printf("== Networking Policy\n"); + printf("========================================================\n"); + + RunDumpsys("DUMPSYS NETWORK POLICY", {"netpolicy"}, CommandOptions::WithTimeout(90).Build(), + SEC_TO_MSEC(10)); + printf("========================================================\n"); printf("== Dropbox crashes\n"); printf("========================================================\n"); @@ -1785,6 +1793,10 @@ Dumpstate::RunStatus Dumpstate::dumpstate() { RunCommand("ACONFIG FLAGS", {PRINT_FLAGS}, CommandOptions::WithTimeout(10).Always().DropRoot().Build()); + RunCommand("ACONFIG FLAGS DUMP", {AFLAGS, "list"}, + CommandOptions::WithTimeout(10).Always().AsRootIfAvailable().Build()); + RunCommand("WHICH ACONFIG FLAG STORAGE", {AFLAGS, "which-backing"}, + CommandOptions::WithTimeout(10).Always().AsRootIfAvailable().Build()); RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"}); diff --git a/cmds/evemu-record/main.rs b/cmds/evemu-record/main.rs index db3fd77520f150a657f365bd6c8559e4e8810e36..e91e5daec48dd78c14a13c85bdf2458b38b6df5e 100644 --- a/cmds/evemu-record/main.rs +++ b/cmds/evemu-record/main.rs @@ -50,8 +50,10 @@ enum TimestampBase { /// The first event received from the device. FirstEvent, - /// The time when the system booted. - Boot, + /// The Unix epoch (00:00:00 UTC on 1st January 1970), so that all timestamps are Unix + /// timestamps. This makes the events in the recording easier to match up with those from other + /// log sources. + Epoch, } fn get_choice(max: u32) -> u32 { @@ -188,7 +190,7 @@ fn print_events( // // [0]: https://gitlab.freedesktop.org/libevdev/evemu/-/commit/eba96a4d2be7260b5843e65c4b99c8b06a1f4c9d TimestampBase::FirstEvent => event.time - TimeVal::new(0, 1), - TimestampBase::Boot => TimeVal::new(0, 0), + TimestampBase::Epoch => TimeVal::new(0, 0), }; print_event(output, &event.offset_time_by(start_time))?; loop { diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp index c163095c50a72791d34513718ca72cc1adfdf553..77e732805ea4078d83c8a664a23eabdf268c2475 100644 --- a/cmds/flatland/GLHelper.cpp +++ b/cmds/flatland/GLHelper.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -202,6 +203,14 @@ bool GLHelper::getShaderProgram(const char* name, GLuint* outPgm) { bool GLHelper::createNamedSurfaceTexture(GLuint name, uint32_t w, uint32_t h, sp* glConsumer, EGLSurface* surface) { +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + sp glc = new GLConsumer(name, GL_TEXTURE_EXTERNAL_OES, false, true); + glc->setDefaultBufferSize(w, h); + glc->getSurface()->setMaxDequeuedBufferCount(2); + glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER); + + sp anw = glc->getSurface(); +#else sp producer; sp consumer; BufferQueue::createBufferQueue(&producer, &consumer); @@ -212,6 +221,7 @@ bool GLHelper::createNamedSurfaceTexture(GLuint name, uint32_t w, uint32_t h, glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER); sp anw = new Surface(producer); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), nullptr); if (s == EGL_NO_SURFACE) { fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError()); diff --git a/cmds/idlcli/Android.bp b/cmds/idlcli/Android.bp index c18d3f502191736223ddb3dd7c1004445bba4c71..50c2cd8be2d2c41d1352c85c963a2ec733acde02 100644 --- a/cmds/idlcli/Android.bp +++ b/cmds/idlcli/Android.bp @@ -24,7 +24,7 @@ package { cc_defaults { name: "idlcli-defaults", shared_libs: [ - "android.hardware.vibrator-V2-ndk", + "android.hardware.vibrator-V3-ndk", "android.hardware.vibrator@1.0", "android.hardware.vibrator@1.1", "android.hardware.vibrator@1.2", diff --git a/cmds/idlcli/vibrator.h b/cmds/idlcli/vibrator.h index e100eacdd5904bba81b795421b2561a6d8b8342d..b9434950f6a402a73a45fcdf8828da570a7a338e 100644 --- a/cmds/idlcli/vibrator.h +++ b/cmds/idlcli/vibrator.h @@ -49,7 +49,7 @@ inline ndk::ScopedAStatus NullptrStatus() { template inline auto getService(std::string name) { const auto instance = std::string() + I::descriptor + "/" + name; - auto vibBinder = ndk::SpAIBinder(AServiceManager_getService(instance.c_str())); + auto vibBinder = ndk::SpAIBinder(AServiceManager_checkService(instance.c_str())); return I::fromBinder(vibBinder); } diff --git a/cmds/installd/otapreopt_script.sh b/cmds/installd/otapreopt_script.sh index 9384926e296255f043ecef1e0bf408b36c22590d..b7ad33144be4aa39b3152044591da7f8da5faf4c 100644 --- a/cmds/installd/otapreopt_script.sh +++ b/cmds/installd/otapreopt_script.sh @@ -60,7 +60,7 @@ function infinite_source { } PR_DEXOPT_JOB_VERSION="$(pm art pr-dexopt-job --version)" -if (( $? == 0 )) && (( $PR_DEXOPT_JOB_VERSION >= 2 )); then +if (( $? == 0 )) && (( $PR_DEXOPT_JOB_VERSION >= 3 )); then # Delegate to Pre-reboot Dexopt, a feature of ART Service. # ART Service decides what to do with this request: # - If Pre-reboot Dexopt is disabled or unsupported, the command returns diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-0 b/cmds/installd/tests/corpus/seed-2024-08-29-0 new file mode 100644 index 0000000000000000000000000000000000000000..a09fc84fc59db6072c3c7ca9ef88c25a9ddc0bc2 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-0 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-1 b/cmds/installd/tests/corpus/seed-2024-08-29-1 new file mode 100644 index 0000000000000000000000000000000000000000..c96616aa29ed62c502203c0d3052a108fd8c85ef Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-1 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-10 b/cmds/installd/tests/corpus/seed-2024-08-29-10 new file mode 100644 index 0000000000000000000000000000000000000000..0b21bd157d5e4803765c434b110cbcd14dd65822 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-10 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-100 b/cmds/installd/tests/corpus/seed-2024-08-29-100 new file mode 100644 index 0000000000000000000000000000000000000000..225d123966bc4a2a93f8cd35513ae72ac1b5e9e7 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-100 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-101 b/cmds/installd/tests/corpus/seed-2024-08-29-101 new file mode 100644 index 0000000000000000000000000000000000000000..c507b576cc84b7e90a0a9c9803e85c02839b5d87 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-101 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-102 b/cmds/installd/tests/corpus/seed-2024-08-29-102 new file mode 100644 index 0000000000000000000000000000000000000000..e75ef89ad3a7dfe7ba6953e1e2555c1ac0df6e94 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-102 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-103 b/cmds/installd/tests/corpus/seed-2024-08-29-103 new file mode 100644 index 0000000000000000000000000000000000000000..fb28f4d7120f1fdd1f475c35f4040809d9be31eb Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-103 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-104 b/cmds/installd/tests/corpus/seed-2024-08-29-104 new file mode 100644 index 0000000000000000000000000000000000000000..b5a22222e0bf8405571baa00c5024c42598528e9 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-104 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-105 b/cmds/installd/tests/corpus/seed-2024-08-29-105 new file mode 100644 index 0000000000000000000000000000000000000000..a126c0eb6ac74876cf189d81e735d76445d0d8fe Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-105 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-106 b/cmds/installd/tests/corpus/seed-2024-08-29-106 new file mode 100644 index 0000000000000000000000000000000000000000..ad84e5788ea86d3b3c6cd6bef0c2f5818f2bb316 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-106 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-107 b/cmds/installd/tests/corpus/seed-2024-08-29-107 new file mode 100644 index 0000000000000000000000000000000000000000..6a2bc6f35ab5da915a1f00efcc40d309c96d17c8 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-107 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-108 b/cmds/installd/tests/corpus/seed-2024-08-29-108 new file mode 100644 index 0000000000000000000000000000000000000000..578b55ad171549c1d9f36c92213c65a92a2085f9 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-108 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-109 b/cmds/installd/tests/corpus/seed-2024-08-29-109 new file mode 100644 index 0000000000000000000000000000000000000000..44f853d01454cd42e1a6838a51b261381d2d5541 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-109 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-11 b/cmds/installd/tests/corpus/seed-2024-08-29-11 new file mode 100644 index 0000000000000000000000000000000000000000..28fd841c636327aae590969b9dcf797b315028ae Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-11 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-110 b/cmds/installd/tests/corpus/seed-2024-08-29-110 new file mode 100644 index 0000000000000000000000000000000000000000..a013ee89977deaf0b7283d68684d6bab75ba286c Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-110 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-111 b/cmds/installd/tests/corpus/seed-2024-08-29-111 new file mode 100644 index 0000000000000000000000000000000000000000..1bb618596569b444b542eb432c54eca27e908203 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-111 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-112 b/cmds/installd/tests/corpus/seed-2024-08-29-112 new file mode 100644 index 0000000000000000000000000000000000000000..83008e956dde9d105e96e20936338f929973c178 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-112 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-113 b/cmds/installd/tests/corpus/seed-2024-08-29-113 new file mode 100644 index 0000000000000000000000000000000000000000..c9460cbbc6f12bd965cad1e81aec2011c9a12000 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-113 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-114 b/cmds/installd/tests/corpus/seed-2024-08-29-114 new file mode 100644 index 0000000000000000000000000000000000000000..feb0384a928a394374619fe393af0a8459b14aa2 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-114 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-115 b/cmds/installd/tests/corpus/seed-2024-08-29-115 new file mode 100644 index 0000000000000000000000000000000000000000..cd28076566c1169957b6be719af5f723f9a59ac8 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-115 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-116 b/cmds/installd/tests/corpus/seed-2024-08-29-116 new file mode 100644 index 0000000000000000000000000000000000000000..c48730ee762a150171e4250176d037992070f682 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-116 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-117 b/cmds/installd/tests/corpus/seed-2024-08-29-117 new file mode 100644 index 0000000000000000000000000000000000000000..bde1be0c10ea024a33881115a662ad1aa08ed097 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-117 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-118 b/cmds/installd/tests/corpus/seed-2024-08-29-118 new file mode 100644 index 0000000000000000000000000000000000000000..0d86d18c97cc1ae217a10ead53f2ef54b8f397e5 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-118 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-119 b/cmds/installd/tests/corpus/seed-2024-08-29-119 new file mode 100644 index 0000000000000000000000000000000000000000..de358941febe96d27b5288c7f1256cc2e96cec9a Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-119 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-12 b/cmds/installd/tests/corpus/seed-2024-08-29-12 new file mode 100644 index 0000000000000000000000000000000000000000..5565f811bb943a7cb64637f8f92a46df7e8514ef Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-12 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-120 b/cmds/installd/tests/corpus/seed-2024-08-29-120 new file mode 100644 index 0000000000000000000000000000000000000000..51c05261f94cb8dc2721c82a6fe5e3bd2e0963b3 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-120 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-121 b/cmds/installd/tests/corpus/seed-2024-08-29-121 new file mode 100644 index 0000000000000000000000000000000000000000..2d84c76377789c816996f5dd0f249f60b712031b Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-121 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-122 b/cmds/installd/tests/corpus/seed-2024-08-29-122 new file mode 100644 index 0000000000000000000000000000000000000000..f25a7c48e4883309d2c6ac0a5070f850562610f0 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-122 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-123 b/cmds/installd/tests/corpus/seed-2024-08-29-123 new file mode 100644 index 0000000000000000000000000000000000000000..fe8eb342bf7f75fdb101aaaba72dbffdf8c9472c Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-123 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-124 b/cmds/installd/tests/corpus/seed-2024-08-29-124 new file mode 100644 index 0000000000000000000000000000000000000000..170e8ec1a2738c22f5fbd6b115cf172957f698c3 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-124 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-125 b/cmds/installd/tests/corpus/seed-2024-08-29-125 new file mode 100644 index 0000000000000000000000000000000000000000..24e8bb8b7262c6111443eb08b130283e1354d34b Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-125 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-126 b/cmds/installd/tests/corpus/seed-2024-08-29-126 new file mode 100644 index 0000000000000000000000000000000000000000..92536a351554281d9bf9b7ff38437c2ec4d6e477 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-126 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-127 b/cmds/installd/tests/corpus/seed-2024-08-29-127 new file mode 100644 index 0000000000000000000000000000000000000000..3a5436a0e7d7cd57531ddd228905bf7de11660e6 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-127 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-128 b/cmds/installd/tests/corpus/seed-2024-08-29-128 new file mode 100644 index 0000000000000000000000000000000000000000..93d131da9e6291e5db2ecc0e0fb3a5d595c12c0a Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-128 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-129 b/cmds/installd/tests/corpus/seed-2024-08-29-129 new file mode 100644 index 0000000000000000000000000000000000000000..842dae41c35e2378d35e0484b830d9fdfeae9645 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-129 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-13 b/cmds/installd/tests/corpus/seed-2024-08-29-13 new file mode 100644 index 0000000000000000000000000000000000000000..bc0ec3d94f26c0f01f5303c7ad4b839c3df937c1 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-13 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-130 b/cmds/installd/tests/corpus/seed-2024-08-29-130 new file mode 100644 index 0000000000000000000000000000000000000000..9b6ed599028abea6d774a3b803c40969e85a7372 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-130 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-131 b/cmds/installd/tests/corpus/seed-2024-08-29-131 new file mode 100644 index 0000000000000000000000000000000000000000..82a5d2f34f88c1def06810af80db204363eacc40 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-131 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-132 b/cmds/installd/tests/corpus/seed-2024-08-29-132 new file mode 100644 index 0000000000000000000000000000000000000000..445fdc588061975f96ebb98afa9db23c7dfa627e Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-132 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-133 b/cmds/installd/tests/corpus/seed-2024-08-29-133 new file mode 100644 index 0000000000000000000000000000000000000000..0a6e9caac7123e5ceca2ce74c44a6a75b95619b6 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-133 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-134 b/cmds/installd/tests/corpus/seed-2024-08-29-134 new file mode 100644 index 0000000000000000000000000000000000000000..a359603e95de2181d71c6281364764298a263a79 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-134 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-135 b/cmds/installd/tests/corpus/seed-2024-08-29-135 new file mode 100644 index 0000000000000000000000000000000000000000..c16b303dba5b7b9ba4fd63175ae1fc68c1321d53 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-135 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-136 b/cmds/installd/tests/corpus/seed-2024-08-29-136 new file mode 100644 index 0000000000000000000000000000000000000000..f7a360ffb9b6b7a2ef6e22556fecf5bb3b96153f Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-136 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-137 b/cmds/installd/tests/corpus/seed-2024-08-29-137 new file mode 100644 index 0000000000000000000000000000000000000000..38a113486b7925ec44e42460d2d95a7a19155451 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-137 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-138 b/cmds/installd/tests/corpus/seed-2024-08-29-138 new file mode 100644 index 0000000000000000000000000000000000000000..b9db4a7d098122023d872ebc206fb830b51f52bd Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-138 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-139 b/cmds/installd/tests/corpus/seed-2024-08-29-139 new file mode 100644 index 0000000000000000000000000000000000000000..eb1cf938f31d2aa159c5712c8db53d5fa1e3e08f Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-139 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-14 b/cmds/installd/tests/corpus/seed-2024-08-29-14 new file mode 100644 index 0000000000000000000000000000000000000000..74f9ad04408f7fa61615600691a6e70504ecd3b3 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-14 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-140 b/cmds/installd/tests/corpus/seed-2024-08-29-140 new file mode 100644 index 0000000000000000000000000000000000000000..0cf217c041db98c7539e069a798dd4164035ba1b Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-140 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-141 b/cmds/installd/tests/corpus/seed-2024-08-29-141 new file mode 100644 index 0000000000000000000000000000000000000000..82763f0b3c3e6c8f137aa2780b98c3d3094e75c2 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-141 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-142 b/cmds/installd/tests/corpus/seed-2024-08-29-142 new file mode 100644 index 0000000000000000000000000000000000000000..fa1d65665f833e803481ae721c4c0728a5ec2917 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-142 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-15 b/cmds/installd/tests/corpus/seed-2024-08-29-15 new file mode 100644 index 0000000000000000000000000000000000000000..729c60423092c824e078d2e32693045ec97ed3ba Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-15 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-16 b/cmds/installd/tests/corpus/seed-2024-08-29-16 new file mode 100644 index 0000000000000000000000000000000000000000..4dc08793c28df5e1f99014c827c9d63836e96c4d Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-16 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-17 b/cmds/installd/tests/corpus/seed-2024-08-29-17 new file mode 100644 index 0000000000000000000000000000000000000000..ac7ff13e52ecd1f00a4eb8ee4edc2bd44504a32c Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-17 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-18 b/cmds/installd/tests/corpus/seed-2024-08-29-18 new file mode 100644 index 0000000000000000000000000000000000000000..2b240f46fbbca581041730d7a6ddbaaeb7524483 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-18 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-19 b/cmds/installd/tests/corpus/seed-2024-08-29-19 new file mode 100644 index 0000000000000000000000000000000000000000..a0c881b37fddeed004225bd3ae089cc0eb516227 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-19 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-2 b/cmds/installd/tests/corpus/seed-2024-08-29-2 new file mode 100644 index 0000000000000000000000000000000000000000..2593acb6e407a60207269bef65ddbcc94c188c4e Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-2 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-20 b/cmds/installd/tests/corpus/seed-2024-08-29-20 new file mode 100644 index 0000000000000000000000000000000000000000..c55dc7f2454aa657b27ce306020fc72cea2c59ab Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-20 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-21 b/cmds/installd/tests/corpus/seed-2024-08-29-21 new file mode 100644 index 0000000000000000000000000000000000000000..63d7a1455b37f2fb6fdf81607ad140374489879c Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-21 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-22 b/cmds/installd/tests/corpus/seed-2024-08-29-22 new file mode 100644 index 0000000000000000000000000000000000000000..209f426a013dc6c2b23d2c162b5c75744a9553bb Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-22 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-23 b/cmds/installd/tests/corpus/seed-2024-08-29-23 new file mode 100644 index 0000000000000000000000000000000000000000..8e1775f38202cff3d7d95e32d5077097db4b7780 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-23 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-24 b/cmds/installd/tests/corpus/seed-2024-08-29-24 new file mode 100644 index 0000000000000000000000000000000000000000..4c40f3cffa4dd6b8f89c0b25fabf3501b71226a4 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-24 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-25 b/cmds/installd/tests/corpus/seed-2024-08-29-25 new file mode 100644 index 0000000000000000000000000000000000000000..d006b202f623502e63b838b2b2e4320ebacf0c66 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-25 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-26 b/cmds/installd/tests/corpus/seed-2024-08-29-26 new file mode 100644 index 0000000000000000000000000000000000000000..26893b0118e185426f9d4b3530714bae0f0b38f5 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-26 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-27 b/cmds/installd/tests/corpus/seed-2024-08-29-27 new file mode 100644 index 0000000000000000000000000000000000000000..ac81138dfa467be0b33ae9ac36ea5988ec16439e Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-27 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-28 b/cmds/installd/tests/corpus/seed-2024-08-29-28 new file mode 100644 index 0000000000000000000000000000000000000000..71f074b7a09b9c733a53ce98d727cc54edd9f413 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-28 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-29 b/cmds/installd/tests/corpus/seed-2024-08-29-29 new file mode 100644 index 0000000000000000000000000000000000000000..65dbb6dff7a6b05c4ee0ad49ae00ddbd92a46809 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-29 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-3 b/cmds/installd/tests/corpus/seed-2024-08-29-3 new file mode 100644 index 0000000000000000000000000000000000000000..28ab83fbfdbd5325f30034964aef6fc5e73a3464 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-3 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-30 b/cmds/installd/tests/corpus/seed-2024-08-29-30 new file mode 100644 index 0000000000000000000000000000000000000000..3b96286573faa3490ede14b747f34c2a034975d4 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-30 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-31 b/cmds/installd/tests/corpus/seed-2024-08-29-31 new file mode 100644 index 0000000000000000000000000000000000000000..76101b36ecc06786eaecf456f7f28e6d8d08ec39 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-31 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-32 b/cmds/installd/tests/corpus/seed-2024-08-29-32 new file mode 100644 index 0000000000000000000000000000000000000000..79a44523e09c4dd4a8db8e2f61ed01e112e722c5 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-32 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-33 b/cmds/installd/tests/corpus/seed-2024-08-29-33 new file mode 100644 index 0000000000000000000000000000000000000000..e6a130683865ac23b90b5f540465e765b39d2a55 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-33 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-34 b/cmds/installd/tests/corpus/seed-2024-08-29-34 new file mode 100644 index 0000000000000000000000000000000000000000..4a7247f8880241d880efd41b00c696126edf8749 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-34 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-35 b/cmds/installd/tests/corpus/seed-2024-08-29-35 new file mode 100644 index 0000000000000000000000000000000000000000..f420b34fce91c593b9560ae2eab42b187e839516 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-35 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-36 b/cmds/installd/tests/corpus/seed-2024-08-29-36 new file mode 100644 index 0000000000000000000000000000000000000000..83a33acecbca2b23b797e0b97717c26419d85cd0 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-36 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-37 b/cmds/installd/tests/corpus/seed-2024-08-29-37 new file mode 100644 index 0000000000000000000000000000000000000000..687bf06ea72ed70a0750dcd2f074460f8e796eb7 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-37 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-38 b/cmds/installd/tests/corpus/seed-2024-08-29-38 new file mode 100644 index 0000000000000000000000000000000000000000..40ab0ad5917c4de5242de9efd37754ca13dbb788 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-38 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-39 b/cmds/installd/tests/corpus/seed-2024-08-29-39 new file mode 100644 index 0000000000000000000000000000000000000000..3e13978d874d4c4c5642d9d26412895b96846cc4 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-39 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-4 b/cmds/installd/tests/corpus/seed-2024-08-29-4 new file mode 100644 index 0000000000000000000000000000000000000000..8c47ea3f96fbaa3188ed8482aed5b685c8636cb8 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-4 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-40 b/cmds/installd/tests/corpus/seed-2024-08-29-40 new file mode 100644 index 0000000000000000000000000000000000000000..f71791862acf3fa2412327b84ecb9ee4b4c0a10b Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-40 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-41 b/cmds/installd/tests/corpus/seed-2024-08-29-41 new file mode 100644 index 0000000000000000000000000000000000000000..d9c51b93d669c52e0d143d8dd257ee12a4b29b9b Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-41 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-42 b/cmds/installd/tests/corpus/seed-2024-08-29-42 new file mode 100644 index 0000000000000000000000000000000000000000..d806e5ee399d305a09496974b1dd35ab933b7cbd Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-42 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-43 b/cmds/installd/tests/corpus/seed-2024-08-29-43 new file mode 100644 index 0000000000000000000000000000000000000000..3bc2708f125939765894207170f64874d6a743a9 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-43 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-44 b/cmds/installd/tests/corpus/seed-2024-08-29-44 new file mode 100644 index 0000000000000000000000000000000000000000..230839af3643bf535a31be8080be687d961c3449 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-44 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-45 b/cmds/installd/tests/corpus/seed-2024-08-29-45 new file mode 100644 index 0000000000000000000000000000000000000000..40726b9f5dac8b86908d7a191332244e002e790f Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-45 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-46 b/cmds/installd/tests/corpus/seed-2024-08-29-46 new file mode 100644 index 0000000000000000000000000000000000000000..bf56bd4a4709e025e7fe2238244571b60ba222f3 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-46 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-47 b/cmds/installd/tests/corpus/seed-2024-08-29-47 new file mode 100644 index 0000000000000000000000000000000000000000..80cabaf62b2b043305241aed6e0e87eb6aa0f597 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-47 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-48 b/cmds/installd/tests/corpus/seed-2024-08-29-48 new file mode 100644 index 0000000000000000000000000000000000000000..8f2c5f5dd6e806f6310730ab746130d73a6ae361 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-48 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-49 b/cmds/installd/tests/corpus/seed-2024-08-29-49 new file mode 100644 index 0000000000000000000000000000000000000000..f93fbcdfc536c94f602237246df103fd80d81674 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-49 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-5 b/cmds/installd/tests/corpus/seed-2024-08-29-5 new file mode 100644 index 0000000000000000000000000000000000000000..b3f49d1659b746613cd01dc5f841862bde79825a Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-5 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-50 b/cmds/installd/tests/corpus/seed-2024-08-29-50 new file mode 100644 index 0000000000000000000000000000000000000000..68912aeb9433464f3ae6f8d92dd1a94f068cbd43 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-50 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-51 b/cmds/installd/tests/corpus/seed-2024-08-29-51 new file mode 100644 index 0000000000000000000000000000000000000000..27b315dec6841a8033321621957181157eb70560 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-51 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-52 b/cmds/installd/tests/corpus/seed-2024-08-29-52 new file mode 100644 index 0000000000000000000000000000000000000000..159eee6ac0cd493b0ec96621393d4a36c581c5e6 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-52 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-53 b/cmds/installd/tests/corpus/seed-2024-08-29-53 new file mode 100644 index 0000000000000000000000000000000000000000..b07cb3c699035a936a8c017d16478fb857802ab6 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-53 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-54 b/cmds/installd/tests/corpus/seed-2024-08-29-54 new file mode 100644 index 0000000000000000000000000000000000000000..a5e7f2cc4dc75d773f3459d957e7ce8cc6097ba0 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-54 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-55 b/cmds/installd/tests/corpus/seed-2024-08-29-55 new file mode 100644 index 0000000000000000000000000000000000000000..bd038adc841bfb5088b1a8d6a875c92c5c389335 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-55 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-56 b/cmds/installd/tests/corpus/seed-2024-08-29-56 new file mode 100644 index 0000000000000000000000000000000000000000..8166cb8cb322450b2cc7438dc064eb5fd2321a95 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-56 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-57 b/cmds/installd/tests/corpus/seed-2024-08-29-57 new file mode 100644 index 0000000000000000000000000000000000000000..fba1e2f35fe8559574f439aad33fdcae2d5a4e5f Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-57 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-58 b/cmds/installd/tests/corpus/seed-2024-08-29-58 new file mode 100644 index 0000000000000000000000000000000000000000..f7af8f8e1266895d1fdc134ba87bcef7bacb92a4 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-58 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-59 b/cmds/installd/tests/corpus/seed-2024-08-29-59 new file mode 100644 index 0000000000000000000000000000000000000000..2fd68d7c400d853f302143a114e2b09b9fcca81a Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-59 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-6 b/cmds/installd/tests/corpus/seed-2024-08-29-6 new file mode 100644 index 0000000000000000000000000000000000000000..9b02a47877e85afea237ceff4aaad3fb60ba9f45 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-6 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-60 b/cmds/installd/tests/corpus/seed-2024-08-29-60 new file mode 100644 index 0000000000000000000000000000000000000000..b4c11292ef0a61f25e0be52f472b56fa91a850d6 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-60 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-61 b/cmds/installd/tests/corpus/seed-2024-08-29-61 new file mode 100644 index 0000000000000000000000000000000000000000..46989aa11aef31c63dc1778cc06c0e5bca29c49e Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-61 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-62 b/cmds/installd/tests/corpus/seed-2024-08-29-62 new file mode 100644 index 0000000000000000000000000000000000000000..9298d0c33d6b4a8d81a33e5c2f02612a3a5e8532 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-62 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-63 b/cmds/installd/tests/corpus/seed-2024-08-29-63 new file mode 100644 index 0000000000000000000000000000000000000000..326098c31e0f31f51fa8b67cdc03b6e6e869158d Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-63 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-64 b/cmds/installd/tests/corpus/seed-2024-08-29-64 new file mode 100644 index 0000000000000000000000000000000000000000..61daf4facb37722fc7424605a52ff8ad76292203 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-64 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-65 b/cmds/installd/tests/corpus/seed-2024-08-29-65 new file mode 100644 index 0000000000000000000000000000000000000000..a993900ff5d35e228ac3658092c9d4e189ee6fd1 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-65 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-66 b/cmds/installd/tests/corpus/seed-2024-08-29-66 new file mode 100644 index 0000000000000000000000000000000000000000..85e857bae8e359f2ebda8a91bc93630e3fa4e388 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-66 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-67 b/cmds/installd/tests/corpus/seed-2024-08-29-67 new file mode 100644 index 0000000000000000000000000000000000000000..b7754838fc068119a63f9f0aeabb11eec1f3e562 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-67 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-68 b/cmds/installd/tests/corpus/seed-2024-08-29-68 new file mode 100644 index 0000000000000000000000000000000000000000..161e7ab41a375c2a23d5087e09e330e61ab922e1 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-68 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-69 b/cmds/installd/tests/corpus/seed-2024-08-29-69 new file mode 100644 index 0000000000000000000000000000000000000000..6a45dfe0ffe50c3773fc1cafa6f11e15ab307c43 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-69 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-7 b/cmds/installd/tests/corpus/seed-2024-08-29-7 new file mode 100644 index 0000000000000000000000000000000000000000..33f61b0fbc7f4bd4944ef1431216c75d0ac4d756 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-7 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-70 b/cmds/installd/tests/corpus/seed-2024-08-29-70 new file mode 100644 index 0000000000000000000000000000000000000000..4c16b4915116f67b73392489c0e662cf3e9ecce8 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-70 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-71 b/cmds/installd/tests/corpus/seed-2024-08-29-71 new file mode 100644 index 0000000000000000000000000000000000000000..1534ce12d19dd9c911e4d7e05d5bc4d64972abb4 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-71 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-72 b/cmds/installd/tests/corpus/seed-2024-08-29-72 new file mode 100644 index 0000000000000000000000000000000000000000..eaa5831917d89b3003a88db22280a77b7e266b79 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-72 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-73 b/cmds/installd/tests/corpus/seed-2024-08-29-73 new file mode 100644 index 0000000000000000000000000000000000000000..9df4a75b8830fc5aa620c2c37a599ab247f508e6 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-73 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-74 b/cmds/installd/tests/corpus/seed-2024-08-29-74 new file mode 100644 index 0000000000000000000000000000000000000000..9558ac019dca59e7a132ca7e7175981bb65da346 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-74 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-75 b/cmds/installd/tests/corpus/seed-2024-08-29-75 new file mode 100644 index 0000000000000000000000000000000000000000..a399271250d637a4c3ff5ce31098bba437ac6b91 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-75 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-76 b/cmds/installd/tests/corpus/seed-2024-08-29-76 new file mode 100644 index 0000000000000000000000000000000000000000..866541d038b82276aa184d3cde53af73db0dff58 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-76 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-77 b/cmds/installd/tests/corpus/seed-2024-08-29-77 new file mode 100644 index 0000000000000000000000000000000000000000..e3940d9af68662584a9fde82ae4bcce8437d4d03 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-77 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-78 b/cmds/installd/tests/corpus/seed-2024-08-29-78 new file mode 100644 index 0000000000000000000000000000000000000000..8122306d161b7392d01e53a30c15ba0fc80b0410 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-78 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-79 b/cmds/installd/tests/corpus/seed-2024-08-29-79 new file mode 100644 index 0000000000000000000000000000000000000000..0f23dfd2f9d725c24eb9ca16a88ac182b24e9c92 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-79 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-8 b/cmds/installd/tests/corpus/seed-2024-08-29-8 new file mode 100644 index 0000000000000000000000000000000000000000..7390735a938675804681c0073d4b24fc66e4fd59 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-8 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-80 b/cmds/installd/tests/corpus/seed-2024-08-29-80 new file mode 100644 index 0000000000000000000000000000000000000000..e3c36405e72a5541d179e83fa69ca6b1a5a93285 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-80 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-81 b/cmds/installd/tests/corpus/seed-2024-08-29-81 new file mode 100644 index 0000000000000000000000000000000000000000..6c42b9e72f0c46105458f45428b537f3c88a8d54 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-81 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-82 b/cmds/installd/tests/corpus/seed-2024-08-29-82 new file mode 100644 index 0000000000000000000000000000000000000000..09184c98d09aa536fd570426492056b4d8af94a7 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-82 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-83 b/cmds/installd/tests/corpus/seed-2024-08-29-83 new file mode 100644 index 0000000000000000000000000000000000000000..734570af845fed1314b16975d40a35cf61fe9e98 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-83 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-84 b/cmds/installd/tests/corpus/seed-2024-08-29-84 new file mode 100644 index 0000000000000000000000000000000000000000..1a32561b372fbfd362788a91a3e0e0b6a3a2ad3f Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-84 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-85 b/cmds/installd/tests/corpus/seed-2024-08-29-85 new file mode 100644 index 0000000000000000000000000000000000000000..5315dfcab3b3794aa8d1e228e9a5ab1e5a35ba68 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-85 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-86 b/cmds/installd/tests/corpus/seed-2024-08-29-86 new file mode 100644 index 0000000000000000000000000000000000000000..5f798b9a154f0ce7c9fbb98612d43856ccd50c90 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-86 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-87 b/cmds/installd/tests/corpus/seed-2024-08-29-87 new file mode 100644 index 0000000000000000000000000000000000000000..dd1ebe16bbebf9ae57a5ee419a0aa40fbf29d5b3 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-87 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-88 b/cmds/installd/tests/corpus/seed-2024-08-29-88 new file mode 100644 index 0000000000000000000000000000000000000000..45cf7136289b3b1e4985f293a32e676a5022eb39 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-88 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-89 b/cmds/installd/tests/corpus/seed-2024-08-29-89 new file mode 100644 index 0000000000000000000000000000000000000000..1053b71f9eb884e22af016de87eb74330e69ba74 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-89 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-9 b/cmds/installd/tests/corpus/seed-2024-08-29-9 new file mode 100644 index 0000000000000000000000000000000000000000..86d511df98f878daf491d0d15927b88fe498967f Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-9 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-90 b/cmds/installd/tests/corpus/seed-2024-08-29-90 new file mode 100644 index 0000000000000000000000000000000000000000..7ce82a08d072335dad9bd30d5e7d398abd0ca837 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-90 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-91 b/cmds/installd/tests/corpus/seed-2024-08-29-91 new file mode 100644 index 0000000000000000000000000000000000000000..57c43d0803144bf4d3fa0d9c478d5c45312c9bae Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-91 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-92 b/cmds/installd/tests/corpus/seed-2024-08-29-92 new file mode 100644 index 0000000000000000000000000000000000000000..32a0f3a72c50b492a3a8c8ae9e7db6b0541beee4 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-92 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-93 b/cmds/installd/tests/corpus/seed-2024-08-29-93 new file mode 100644 index 0000000000000000000000000000000000000000..56dcb665219a56ea301a649e129e0b18f5ebd3dc Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-93 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-94 b/cmds/installd/tests/corpus/seed-2024-08-29-94 new file mode 100644 index 0000000000000000000000000000000000000000..17b5a651e173d54710d4fb873256c5df1181694e Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-94 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-95 b/cmds/installd/tests/corpus/seed-2024-08-29-95 new file mode 100644 index 0000000000000000000000000000000000000000..09630392b070b086326595c436b8673d0b62b3cb Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-95 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-96 b/cmds/installd/tests/corpus/seed-2024-08-29-96 new file mode 100644 index 0000000000000000000000000000000000000000..1c9590579f8f1408b4b2cf535009daf3031379ab Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-96 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-97 b/cmds/installd/tests/corpus/seed-2024-08-29-97 new file mode 100644 index 0000000000000000000000000000000000000000..518910e7ef90f78261e7e9b502a83dbf8500ca8f Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-97 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-98 b/cmds/installd/tests/corpus/seed-2024-08-29-98 new file mode 100644 index 0000000000000000000000000000000000000000..520feb29f2ae35f9e00e272f75e5d663b793bee2 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-98 differ diff --git a/cmds/installd/tests/corpus/seed-2024-08-29-99 b/cmds/installd/tests/corpus/seed-2024-08-29-99 new file mode 100644 index 0000000000000000000000000000000000000000..c1da923585742d45e1edb3802deebefc9704e919 Binary files /dev/null and b/cmds/installd/tests/corpus/seed-2024-08-29-99 differ diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp index ee91d80a3b8c56dc7bad38ae8dad3d7aa32b3d47..e89543e46f94047eeca5cf8712ea1cce3b028922 100644 --- a/cmds/installd/tests/installd_dexopt_test.cpp +++ b/cmds/installd/tests/installd_dexopt_test.cpp @@ -1449,7 +1449,7 @@ TEST_F(ProfileTest, CopySystemProfileFailWrongProfileName) { class BootProfileTest : public ProfileTest { public: - std::vector extra_apps_; + std::vector extra_apps_; std::vector extra_ce_data_inodes_; virtual void SetUp() { diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp index 910cd630f31d1f1f7f4ac9ba85b59c06bbd7e22e..19201b2c8900642e4d6aa17e09fcc43bb58a4b7a 100644 --- a/cmds/installd/tests/installd_utils_test.cpp +++ b/cmds/installd/tests/installd_utils_test.cpp @@ -101,6 +101,9 @@ TEST_F(UtilsTest, IsValidApkPath_Internal) { EXPECT_EQ(0, validate_apk_path(path2)) << path2 << " should be allowed as a valid path"; + const char* path3 = TEST_APP_DIR "..example..com../example.apk"; + EXPECT_EQ(0, validate_apk_path(path3)) << path3 << " should be allowed as a valid path"; + const char *badint1 = TEST_APP_DIR "../example.apk"; EXPECT_EQ(-1, validate_apk_path(badint1)) << badint1 << " should be rejected as a invalid path"; diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp index ffc082d5b260b21e3f38715c5b13b124f150610e..b05c6555178aa098ddf025af2b0f32272792b5bf 100644 --- a/cmds/installd/utils.cpp +++ b/cmds/installd/utils.cpp @@ -1040,25 +1040,30 @@ static int validate_path(const std::string& dir, const std::string& path, int ma LOG(ERROR) << "Invalid directory " << dir; return -1; } - if (path.find("..") != std::string::npos) { - LOG(ERROR) << "Invalid path " << path; - return -1; - } if (path.compare(0, dir.size(), dir) != 0) { // Common case, path isn't under directory return -1; } - // Count number of subdirectories - auto pos = path.find('/', dir.size()); + // Count number of subdirectories and invalidate ".." subdirectories + auto last = dir.size(); + auto pos = path.find('/', last); int count = 0; while (pos != std::string::npos) { - auto next = path.find('/', pos + 1); - if (next > pos + 1) { + if (pos > last + 1) { count++; } - pos = next; + if (path.substr(last, pos - last) == "..") { + LOG(ERROR) << "Invalid path " << path; + return -1; + } + last = pos + 1; + pos = path.find('/', last); + } + if (path.substr(last, path.size() - last) == "..") { + LOG(ERROR) << "Invalid path " << path; + return -1; } if (count > maxSubdirs) { diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp index 3897197bd552f1a97d45fb5712885ce40009fcad..e5d7b7456b4a63682e00c717348e27c866fe35a7 100644 --- a/cmds/servicemanager/Android.bp +++ b/cmds/servicemanager/Android.bp @@ -29,6 +29,7 @@ cc_defaults { "liblog", "libutils", "libselinux", + "libperfetto_c", ], target: { @@ -48,7 +49,13 @@ cc_defaults { enabled: false, }, vendor: { - exclude_shared_libs: ["libvintf"], + exclude_shared_libs: [ + "libvintf", + "libperfetto_c", + ], + }, + recovery: { + exclude_shared_libs: ["libperfetto_c"], }, }, } diff --git a/cmds/servicemanager/NameUtil.h b/cmds/servicemanager/NameUtil.h index b08093960ded6e107bd2f67e558a58c87d071d2c..4b10c2bc5c774d7527dafe5001b6840ad6dda658 100644 --- a/cmds/servicemanager/NameUtil.h +++ b/cmds/servicemanager/NameUtil.h @@ -19,8 +19,6 @@ #include #include -#include - namespace android { #ifndef VENDORSERVICEMANAGER diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp index 95a05cdcdec0e672032d4f10f801e3db9f7e8d27..fa7cb64f3a7ba5ee747f14fc2e4b19e9f9264052 100644 --- a/cmds/servicemanager/ServiceManager.cpp +++ b/cmds/servicemanager/ServiceManager.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -27,6 +28,12 @@ #include #include +#if !defined(VENDORSERVICEMANAGER) && !defined(__ANDROID_RECOVERY__) +#include "perfetto/public/protos/trace/android/android_track_event.pzc.h" +#include "perfetto/public/te_category_macros.h" +#include "perfetto/public/te_macros.h" +#endif // !defined(VENDORSERVICEMANAGER) && !defined(__ANDROID_RECOVERY__) + #ifndef VENDORSERVICEMANAGER #include #ifdef __ANDROID_RECOVERY__ @@ -42,6 +49,23 @@ using ::android::internal::Stability; namespace android { +#if defined(VENDORSERVICEMANAGER) || defined(__ANDROID_RECOVERY__) +#define SM_PERFETTO_TRACE_FUNC(...) +#else + +PERFETTO_TE_CATEGORIES_DEFINE(PERFETTO_SM_CATEGORIES); + +#define SM_PERFETTO_TRACE_FUNC(...) \ + PERFETTO_TE_SCOPED(servicemanager, PERFETTO_TE_SLICE_BEGIN(__func__) __VA_OPT__(, ) __VA_ARGS__) + +constexpr uint32_t kProtoServiceName = + perfetto_protos_AndroidTrackEvent_binder_service_name_field_number; +constexpr uint32_t kProtoInterfaceName = + perfetto_protos_AndroidTrackEvent_binder_interface_name_field_number; +constexpr uint32_t kProtoApexName = perfetto_protos_AndroidTrackEvent_apex_name_field_number; + +#endif // !(defined(VENDORSERVICEMANAGER) || defined(__ANDROID_RECOVERY__)) + bool is_multiuser_uid_isolated(uid_t uid) { uid_t appid = multiuser_get_app_id(uid); return appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END; @@ -95,13 +119,15 @@ struct AidlName { std::string iface; std::string instance; - static bool fill(const std::string& name, AidlName* aname) { + static bool fill(const std::string& name, AidlName* aname, bool logError) { size_t firstSlash = name.find('/'); size_t lastDot = name.rfind('.', firstSlash); if (firstSlash == std::string::npos || lastDot == std::string::npos) { - ALOGE("VINTF HALs require names in the format type/instance (e.g. " - "some.package.foo.IFoo/default) but got: %s", - name.c_str()); + if (logError) { + ALOGE("VINTF HALs require names in the format type/instance (e.g. " + "some.package.foo.IFoo/default) but got: %s", + name.c_str()); + } return false; } aname->package = name.substr(0, lastDot); @@ -134,7 +160,7 @@ static bool isVintfDeclared(const Access::CallingContext& ctx, const std::string } AidlName aname; - if (!AidlName::fill(name, &aname)) return false; + if (!AidlName::fill(name, &aname, true)) return false; bool found = forEachManifest([&](const ManifestWithDescription& mwd) { if (mwd.manifest->hasAidlInstance(aname.package, aname.iface, aname.instance)) { @@ -192,7 +218,7 @@ static std::optional getVintfUpdatableApex(const std::string& name) } AidlName aname; - if (!AidlName::fill(name, &aname)) return std::nullopt; + if (!AidlName::fill(name, &aname, true)) return std::nullopt; std::optional updatableViaApex; @@ -232,9 +258,28 @@ static std::vector getVintfUpdatableNames(const std::string& apexNa return names; } +static std::optional getVintfAccessorName(const std::string& name) { + AidlName aname; + if (!AidlName::fill(name, &aname, false)) return std::nullopt; + + std::optional accessor; + forEachManifest([&](const ManifestWithDescription& mwd) { + mwd.manifest->forEachInstance([&](const auto& manifestInstance) { + if (manifestInstance.format() != vintf::HalFormat::AIDL) return true; + if (manifestInstance.package() != aname.package) return true; + if (manifestInstance.interface() != aname.iface) return true; + if (manifestInstance.instance() != aname.instance) return true; + accessor = manifestInstance.accessor(); + return false; // break (libvintf uses opposite convention) + }); + return false; // continue + }); + return accessor; +} + static std::optional getVintfConnectionInfo(const std::string& name) { AidlName aname; - if (!AidlName::fill(name, &aname)) return std::nullopt; + if (!AidlName::fill(name, &aname, true)) return std::nullopt; std::optional ip; std::optional port; @@ -348,18 +393,53 @@ ServiceManager::~ServiceManager() { } Status ServiceManager::getService(const std::string& name, sp* outBinder) { - *outBinder = tryGetService(name, true); + SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS( + PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str()))); + + *outBinder = tryGetBinder(name, true); // returns ok regardless of result for legacy reasons return Status::ok(); } -Status ServiceManager::checkService(const std::string& name, sp* outBinder) { - *outBinder = tryGetService(name, false); +Status ServiceManager::getService2(const std::string& name, os::Service* outService) { + SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS( + PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str()))); + + *outService = tryGetService(name, true); // returns ok regardless of result for legacy reasons return Status::ok(); } -sp ServiceManager::tryGetService(const std::string& name, bool startIfNotFound) { +Status ServiceManager::checkService(const std::string& name, os::Service* outService) { + SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS( + PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str()))); + + *outService = tryGetService(name, false); + // returns ok regardless of result for legacy reasons + return Status::ok(); +} + +os::Service ServiceManager::tryGetService(const std::string& name, bool startIfNotFound) { + std::optional accessorName; +#ifndef VENDORSERVICEMANAGER + accessorName = getVintfAccessorName(name); +#endif + if (accessorName.has_value()) { + auto ctx = mAccess->getCallingContext(); + if (!mAccess->canFind(ctx, name)) { + return os::Service::make(nullptr); + } + return os::Service::make( + tryGetBinder(*accessorName, startIfNotFound)); + } else { + return os::Service::make(tryGetBinder(name, startIfNotFound)); + } +} + +sp ServiceManager::tryGetBinder(const std::string& name, bool startIfNotFound) { + SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS( + PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str()))); + auto ctx = mAccess->getCallingContext(); sp out; @@ -398,6 +478,9 @@ sp ServiceManager::tryGetService(const std::string& name, bool startIfN } bool isValidServiceName(const std::string& name) { + SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS( + PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str()))); + if (name.size() == 0) return false; if (name.size() > 127) return false; @@ -413,14 +496,18 @@ bool isValidServiceName(const std::string& name) { } Status ServiceManager::addService(const std::string& name, const sp& binder, bool allowIsolated, int32_t dumpPriority) { + SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS( + PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str()))); + auto ctx = mAccess->getCallingContext(); if (multiuser_get_app_id(ctx.uid) >= AID_APP) { return Status::fromExceptionCode(Status::EX_SECURITY, "App UIDs cannot add services."); } - if (!mAccess->canAdd(ctx, name)) { - return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied."); + std::optional accessorName; + if (auto status = canAddService(ctx, name, &accessorName); !status.isOk()) { + return status; } if (binder == nullptr) { @@ -505,6 +592,8 @@ Status ServiceManager::addService(const std::string& name, const sp& bi } Status ServiceManager::listServices(int32_t dumpPriority, std::vector* outList) { + SM_PERFETTO_TRACE_FUNC(); + if (!mAccess->canList(mAccess->getCallingContext())) { return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied."); } @@ -532,10 +621,16 @@ Status ServiceManager::listServices(int32_t dumpPriority, std::vector& callback) { + SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS( + PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str()))); + auto ctx = mAccess->getCallingContext(); - if (!mAccess->canFind(ctx, name)) { - return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux"); + // TODO(b/338541373): Implement the notification mechanism for services accessed via + // IAccessor. + std::optional accessorName; + if (auto status = canFindService(ctx, name, &accessorName); !status.isOk()) { + return status; } // note - we could allow isolated apps to get notifications if we @@ -578,10 +673,14 @@ Status ServiceManager::registerForNotifications( } Status ServiceManager::unregisterForNotifications( const std::string& name, const sp& callback) { + SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS( + PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str()))); + auto ctx = mAccess->getCallingContext(); - if (!mAccess->canFind(ctx, name)) { - return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied."); + std::optional accessorName; + if (auto status = canFindService(ctx, name, &accessorName); !status.isOk()) { + return status; } bool found = false; @@ -601,10 +700,14 @@ Status ServiceManager::unregisterForNotifications( } Status ServiceManager::isDeclared(const std::string& name, bool* outReturn) { + SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS( + PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str()))); + auto ctx = mAccess->getCallingContext(); - if (!mAccess->canFind(ctx, name)) { - return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied."); + std::optional accessorName; + if (auto status = canFindService(ctx, name, &accessorName); !status.isOk()) { + return status; } *outReturn = false; @@ -616,6 +719,9 @@ Status ServiceManager::isDeclared(const std::string& name, bool* outReturn) { } binder::Status ServiceManager::getDeclaredInstances(const std::string& interface, std::vector* outReturn) { + SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS( + PERFETTO_TE_PROTO_FIELD_CSTR(kProtoInterfaceName, interface.c_str()))); + auto ctx = mAccess->getCallingContext(); std::vector allInstances; @@ -625,8 +731,10 @@ binder::Status ServiceManager::getDeclaredInstances(const std::string& interface outReturn->clear(); + std::optional _accessorName; for (const std::string& instance : allInstances) { - if (mAccess->canFind(ctx, interface + "/" + instance)) { + if (auto status = canFindService(ctx, interface + "/" + instance, &_accessorName); + status.isOk()) { outReturn->push_back(instance); } } @@ -640,10 +748,14 @@ binder::Status ServiceManager::getDeclaredInstances(const std::string& interface Status ServiceManager::updatableViaApex(const std::string& name, std::optional* outReturn) { + SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS( + PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str()))); + auto ctx = mAccess->getCallingContext(); - if (!mAccess->canFind(ctx, name)) { - return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied."); + std::optional _accessorName; + if (auto status = canFindService(ctx, name, &_accessorName); !status.isOk()) { + return status; } *outReturn = std::nullopt; @@ -656,6 +768,9 @@ Status ServiceManager::updatableViaApex(const std::string& name, Status ServiceManager::getUpdatableNames([[maybe_unused]] const std::string& apexName, std::vector* outReturn) { + SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS( + PERFETTO_TE_PROTO_FIELD_CSTR(kProtoApexName, apexName.c_str()))); + auto ctx = mAccess->getCallingContext(); std::vector apexUpdatableNames; @@ -665,8 +780,9 @@ Status ServiceManager::getUpdatableNames([[maybe_unused]] const std::string& ape outReturn->clear(); + std::optional _accessorName; for (const std::string& name : apexUpdatableNames) { - if (mAccess->canFind(ctx, name)) { + if (auto status = canFindService(ctx, name, &_accessorName); status.isOk()) { outReturn->push_back(name); } } @@ -674,16 +790,19 @@ Status ServiceManager::getUpdatableNames([[maybe_unused]] const std::string& ape if (outReturn->size() == 0 && apexUpdatableNames.size() != 0) { return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied."); } - return Status::ok(); } Status ServiceManager::getConnectionInfo(const std::string& name, std::optional* outReturn) { + SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS( + PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str()))); + auto ctx = mAccess->getCallingContext(); - if (!mAccess->canFind(ctx, name)) { - return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied."); + std::optional _accessorName; + if (auto status = canFindService(ctx, name, &_accessorName); !status.isOk()) { + return status; } *outReturn = std::nullopt; @@ -697,6 +816,8 @@ Status ServiceManager::getConnectionInfo(const std::string& name, void ServiceManager::removeRegistrationCallback(const wp& who, ServiceCallbackMap::iterator* it, bool* found) { + SM_PERFETTO_TRACE_FUNC(); + std::vector>& listeners = (*it)->second; for (auto lit = listeners.begin(); lit != listeners.end();) { @@ -716,6 +837,8 @@ void ServiceManager::removeRegistrationCallback(const wp& who, } void ServiceManager::binderDied(const wp& who) { + SM_PERFETTO_TRACE_FUNC(); + for (auto it = mNameToService.begin(); it != mNameToService.end();) { if (who == it->second.binder) { // TODO: currently, this entry contains the state also @@ -758,13 +881,17 @@ void ServiceManager::tryStartService(const Access::CallingContext& ctx, const st Status ServiceManager::registerClientCallback(const std::string& name, const sp& service, const sp& cb) { + SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS( + PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str()))); + if (cb == nullptr) { return Status::fromExceptionCode(Status::EX_NULL_POINTER, "Callback null."); } auto ctx = mAccess->getCallingContext(); - if (!mAccess->canAdd(ctx, name)) { - return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied."); + std::optional accessorName; + if (auto status = canAddService(ctx, name, &accessorName); !status.isOk()) { + return status; } auto serviceIt = mNameToService.find(name); @@ -918,13 +1045,17 @@ void ServiceManager::sendClientCallbackNotifications(const std::string& serviceN } Status ServiceManager::tryUnregisterService(const std::string& name, const sp& binder) { + SM_PERFETTO_TRACE_FUNC(PERFETTO_TE_PROTO_FIELDS( + PERFETTO_TE_PROTO_FIELD_CSTR(kProtoServiceName, name.c_str()))); + if (binder == nullptr) { return Status::fromExceptionCode(Status::EX_NULL_POINTER, "Null service."); } auto ctx = mAccess->getCallingContext(); - if (!mAccess->canAdd(ctx, name)) { - return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied."); + std::optional accessorName; + if (auto status = canAddService(ctx, name, &accessorName); !status.isOk()) { + return status; } auto serviceIt = mNameToService.find(name); @@ -982,7 +1113,42 @@ Status ServiceManager::tryUnregisterService(const std::string& name, const sp* accessor) { + if (!mAccess->canAdd(ctx, name)) { + return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied for service."); + } +#ifndef VENDORSERVICEMANAGER + *accessor = getVintfAccessorName(name); +#endif + if (accessor->has_value()) { + if (!mAccess->canAdd(ctx, accessor->value())) { + return Status::fromExceptionCode(Status::EX_SECURITY, + "SELinux denied for the accessor of the service."); + } + } + return Status::ok(); +} + +Status ServiceManager::canFindService(const Access::CallingContext& ctx, const std::string& name, + std::optional* accessor) { + if (!mAccess->canFind(ctx, name)) { + return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied for service."); + } +#ifndef VENDORSERVICEMANAGER + *accessor = getVintfAccessorName(name); +#endif + if (accessor->has_value()) { + if (!mAccess->canFind(ctx, accessor->value())) { + return Status::fromExceptionCode(Status::EX_SECURITY, + "SELinux denied for the accessor of the service."); + } + } + return Status::ok(); +} + Status ServiceManager::getServiceDebugInfo(std::vector* outReturn) { + SM_PERFETTO_TRACE_FUNC(); if (!mAccess->canList(mAccess->getCallingContext())) { return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied."); } diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h index 3b925a48cb5172f5dfb7d11cc32e7bba47e46066..c92141b39356a7e5b12c9f6a51c383738f1ddd2e 100644 --- a/cmds/servicemanager/ServiceManager.h +++ b/cmds/servicemanager/ServiceManager.h @@ -20,6 +20,10 @@ #include #include +#if !defined(VENDORSERVICEMANAGER) && !defined(__ANDROID_RECOVERY__) +#include "perfetto/public/te_category_macros.h" +#endif // !defined(VENDORSERVICEMANAGER) && !defined(__ANDROID_RECOVERY__) + #include "Access.h" namespace android { @@ -29,6 +33,11 @@ using os::IClientCallback; using os::IServiceCallback; using os::ServiceDebugInfo; +#if !defined(VENDORSERVICEMANAGER) && !defined(__ANDROID_RECOVERY__) +#define PERFETTO_SM_CATEGORIES(C) C(servicemanager, "servicemanager", "Service Manager category") +PERFETTO_TE_CATEGORIES_DECLARE(PERFETTO_SM_CATEGORIES); +#endif // !defined(VENDORSERVICEMANAGER) && !defined(__ANDROID_RECOVERY__) + class ServiceManager : public os::BnServiceManager, public IBinder::DeathRecipient { public: ServiceManager(std::unique_ptr&& access); @@ -36,7 +45,8 @@ public: // getService will try to start any services it cannot find binder::Status getService(const std::string& name, sp* outBinder) override; - binder::Status checkService(const std::string& name, sp* outBinder) override; + binder::Status getService2(const std::string& name, os::Service* outService) override; + binder::Status checkService(const std::string& name, os::Service* outService) override; binder::Status addService(const std::string& name, const sp& binder, bool allowIsolated, int32_t dumpPriority) override; binder::Status listServices(int32_t dumpPriority, std::vector* outList) override; @@ -103,7 +113,12 @@ private: // this updates the iterator to the next location void removeClientCallback(const wp& who, ClientCallbackMap::iterator* it); - sp tryGetService(const std::string& name, bool startIfNotFound); + os::Service tryGetService(const std::string& name, bool startIfNotFound); + sp tryGetBinder(const std::string& name, bool startIfNotFound); + binder::Status canAddService(const Access::CallingContext& ctx, const std::string& name, + std::optional* accessor); + binder::Status canFindService(const Access::CallingContext& ctx, const std::string& name, + std::optional* accessor); ServiceMap mNameToService; ServiceCallbackMap mNameToRegistrationCallback; diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-0 b/cmds/servicemanager/corpus/seed-2024-08-29-0 new file mode 100644 index 0000000000000000000000000000000000000000..fe4942e53c95677225e4b45a35239ede10e29de8 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-0 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-1 b/cmds/servicemanager/corpus/seed-2024-08-29-1 new file mode 100644 index 0000000000000000000000000000000000000000..05c8be2f8aede116a27712195b4cf79224a08acb Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-1 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-10 b/cmds/servicemanager/corpus/seed-2024-08-29-10 new file mode 100644 index 0000000000000000000000000000000000000000..427dc45ddd8340c75d875c83ba593f85c7466266 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-10 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-100 b/cmds/servicemanager/corpus/seed-2024-08-29-100 new file mode 100644 index 0000000000000000000000000000000000000000..92584e3ac6dee8232f367daf62a9b4af0cdab323 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-100 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-101 b/cmds/servicemanager/corpus/seed-2024-08-29-101 new file mode 100644 index 0000000000000000000000000000000000000000..4dd73ac5921db866c4eb39f943416ac38c3261b2 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-101 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-102 b/cmds/servicemanager/corpus/seed-2024-08-29-102 new file mode 100644 index 0000000000000000000000000000000000000000..30c37a0d0e27ce2dca751d078af15d5afb28c761 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-102 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-103 b/cmds/servicemanager/corpus/seed-2024-08-29-103 new file mode 100644 index 0000000000000000000000000000000000000000..76ae112ef315e61e8c8f49b8cb95d3e3c3ddd64a Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-103 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-104 b/cmds/servicemanager/corpus/seed-2024-08-29-104 new file mode 100644 index 0000000000000000000000000000000000000000..8ca22015ab47862d71b95fa7ae5b746001651d87 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-104 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-105 b/cmds/servicemanager/corpus/seed-2024-08-29-105 new file mode 100644 index 0000000000000000000000000000000000000000..987fcc1969949b74d1a1eb817058cca2e770a317 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-105 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-106 b/cmds/servicemanager/corpus/seed-2024-08-29-106 new file mode 100644 index 0000000000000000000000000000000000000000..9f09e29cd164e67775ccabd0e8bf18e907d7d2e6 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-106 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-107 b/cmds/servicemanager/corpus/seed-2024-08-29-107 new file mode 100644 index 0000000000000000000000000000000000000000..8f9518d1e411478843cb9549294c66b6fe8e27fe Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-107 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-108 b/cmds/servicemanager/corpus/seed-2024-08-29-108 new file mode 100644 index 0000000000000000000000000000000000000000..decb38a8be561ff03d54855aab9d58c7d9da6cc2 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-108 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-109 b/cmds/servicemanager/corpus/seed-2024-08-29-109 new file mode 100644 index 0000000000000000000000000000000000000000..e3b4426d4e9afe00017db53369bfb7082ad120d6 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-109 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-11 b/cmds/servicemanager/corpus/seed-2024-08-29-11 new file mode 100644 index 0000000000000000000000000000000000000000..177a1cdedd17037922504ca35dcd2f3d4a222b7f Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-11 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-110 b/cmds/servicemanager/corpus/seed-2024-08-29-110 new file mode 100644 index 0000000000000000000000000000000000000000..35de9ca395a033dea512622ac8e7c62d07dd0d74 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-110 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-111 b/cmds/servicemanager/corpus/seed-2024-08-29-111 new file mode 100644 index 0000000000000000000000000000000000000000..ae6076fc146fa1e2dfe327e352a58bf61bca77f1 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-111 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-112 b/cmds/servicemanager/corpus/seed-2024-08-29-112 new file mode 100644 index 0000000000000000000000000000000000000000..3d64f371392b2eb89cf76dd26cfab320d42526cd Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-112 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-113 b/cmds/servicemanager/corpus/seed-2024-08-29-113 new file mode 100644 index 0000000000000000000000000000000000000000..2b14f1d91f333a1c43bb1cc9f96b4886465e1687 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-113 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-114 b/cmds/servicemanager/corpus/seed-2024-08-29-114 new file mode 100644 index 0000000000000000000000000000000000000000..180831f25c66a3e58312cf27244ab8f36d671dfa Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-114 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-115 b/cmds/servicemanager/corpus/seed-2024-08-29-115 new file mode 100644 index 0000000000000000000000000000000000000000..71184d205dfdcf320fc3d9d9bd52c6903ba8f976 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-115 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-116 b/cmds/servicemanager/corpus/seed-2024-08-29-116 new file mode 100644 index 0000000000000000000000000000000000000000..98c6163e2d1cc8d90bd522555e567639b1bc79c6 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-116 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-117 b/cmds/servicemanager/corpus/seed-2024-08-29-117 new file mode 100644 index 0000000000000000000000000000000000000000..e6dd7bbdfb9e4fa6ad38d1dcf34c98868bfd9e84 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-117 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-118 b/cmds/servicemanager/corpus/seed-2024-08-29-118 new file mode 100644 index 0000000000000000000000000000000000000000..dd181ae4a4731a9ce646d65c399bf1fb12e78ef5 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-118 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-119 b/cmds/servicemanager/corpus/seed-2024-08-29-119 new file mode 100644 index 0000000000000000000000000000000000000000..25de1b262f9637aa0798c0cf32cda1c149d1c5ca Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-119 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-12 b/cmds/servicemanager/corpus/seed-2024-08-29-12 new file mode 100644 index 0000000000000000000000000000000000000000..1312d2c9bea345cd7ad532969947e32d70f3927e Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-12 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-120 b/cmds/servicemanager/corpus/seed-2024-08-29-120 new file mode 100644 index 0000000000000000000000000000000000000000..cef973d8e9040fd466e0982a16377c41f1c39f7a Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-120 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-121 b/cmds/servicemanager/corpus/seed-2024-08-29-121 new file mode 100644 index 0000000000000000000000000000000000000000..7fd1df26200dd204cd1e64587e0f3aa0355ce901 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-121 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-122 b/cmds/servicemanager/corpus/seed-2024-08-29-122 new file mode 100644 index 0000000000000000000000000000000000000000..5fefc4b95e8533f900092d0a78a0df1c4feeef91 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-122 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-123 b/cmds/servicemanager/corpus/seed-2024-08-29-123 new file mode 100644 index 0000000000000000000000000000000000000000..714b6b5f10c8cf86d475794bf68f4526aaacabe4 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-123 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-124 b/cmds/servicemanager/corpus/seed-2024-08-29-124 new file mode 100644 index 0000000000000000000000000000000000000000..925bfcc657216cc979d6fd00fbaaadf102e2b3f0 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-124 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-125 b/cmds/servicemanager/corpus/seed-2024-08-29-125 new file mode 100644 index 0000000000000000000000000000000000000000..6dbec24c189dd6aad4b2e3b8cb9f09f14c64edd1 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-125 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-126 b/cmds/servicemanager/corpus/seed-2024-08-29-126 new file mode 100644 index 0000000000000000000000000000000000000000..d5cdcaa6ab202f25d89bb18d1107992666a7a379 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-126 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-127 b/cmds/servicemanager/corpus/seed-2024-08-29-127 new file mode 100644 index 0000000000000000000000000000000000000000..13d0eb544a79297d529d69a978d220f832eb0b54 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-127 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-128 b/cmds/servicemanager/corpus/seed-2024-08-29-128 new file mode 100644 index 0000000000000000000000000000000000000000..471371c657d6e8fa0d1334fb26d6471bb3e688d5 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-128 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-129 b/cmds/servicemanager/corpus/seed-2024-08-29-129 new file mode 100644 index 0000000000000000000000000000000000000000..29087958c4fed4709972f4da03ff8b885606e2b7 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-129 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-13 b/cmds/servicemanager/corpus/seed-2024-08-29-13 new file mode 100644 index 0000000000000000000000000000000000000000..6c8bd0ac60eca94a5bf831378ab26d02822297b8 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-13 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-130 b/cmds/servicemanager/corpus/seed-2024-08-29-130 new file mode 100644 index 0000000000000000000000000000000000000000..3a64ac5eb4fffaec8bd9bb8d57a1b3fe2034fa11 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-130 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-131 b/cmds/servicemanager/corpus/seed-2024-08-29-131 new file mode 100644 index 0000000000000000000000000000000000000000..d1da2ea61d6b354ae9831c9a588b47d3c0d0fe7a Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-131 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-132 b/cmds/servicemanager/corpus/seed-2024-08-29-132 new file mode 100644 index 0000000000000000000000000000000000000000..6de377e760ef3e9a6544585cc4fb6b2c20cab491 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-132 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-133 b/cmds/servicemanager/corpus/seed-2024-08-29-133 new file mode 100644 index 0000000000000000000000000000000000000000..38ffcb922d6e099a578f4a75f5d68e63bf49cd56 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-133 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-134 b/cmds/servicemanager/corpus/seed-2024-08-29-134 new file mode 100644 index 0000000000000000000000000000000000000000..6e828ae599135b5fe88ee4a25b46e55a2217be3a Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-134 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-135 b/cmds/servicemanager/corpus/seed-2024-08-29-135 new file mode 100644 index 0000000000000000000000000000000000000000..c3eb8275aae7ad87d13349698ad6240af743764e Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-135 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-136 b/cmds/servicemanager/corpus/seed-2024-08-29-136 new file mode 100644 index 0000000000000000000000000000000000000000..9b1fafb22ae48542b2cd5b8390e38270d9dcc76e Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-136 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-137 b/cmds/servicemanager/corpus/seed-2024-08-29-137 new file mode 100644 index 0000000000000000000000000000000000000000..059b55ba8be8bf755834a170d3e17524904fcc02 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-137 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-138 b/cmds/servicemanager/corpus/seed-2024-08-29-138 new file mode 100644 index 0000000000000000000000000000000000000000..391bd8c2c5e8e1e562e4dfa6cab8410dc54734d2 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-138 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-139 b/cmds/servicemanager/corpus/seed-2024-08-29-139 new file mode 100644 index 0000000000000000000000000000000000000000..8ea28db180c1c840c7ae7acc836bd06547fc0c9b Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-139 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-14 b/cmds/servicemanager/corpus/seed-2024-08-29-14 new file mode 100644 index 0000000000000000000000000000000000000000..2c704b4f47590a2b86b70b7cb7e6e8ede1d4d53c Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-14 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-140 b/cmds/servicemanager/corpus/seed-2024-08-29-140 new file mode 100644 index 0000000000000000000000000000000000000000..621c5365b7098f681547a4ee841b6072567c6190 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-140 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-141 b/cmds/servicemanager/corpus/seed-2024-08-29-141 new file mode 100644 index 0000000000000000000000000000000000000000..1d8532475fdb1c33c5fdc5c16a607419f42a2cf0 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-141 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-142 b/cmds/servicemanager/corpus/seed-2024-08-29-142 new file mode 100644 index 0000000000000000000000000000000000000000..1df0205b6d5fe937b3e6dbeb63a3383b732695b5 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-142 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-143 b/cmds/servicemanager/corpus/seed-2024-08-29-143 new file mode 100644 index 0000000000000000000000000000000000000000..be5ddea45ec511263ba88a8dc341a3727d252136 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-143 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-144 b/cmds/servicemanager/corpus/seed-2024-08-29-144 new file mode 100644 index 0000000000000000000000000000000000000000..dd7eedfecf3c4685ad9345a652cbed940f35fcd6 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-144 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-145 b/cmds/servicemanager/corpus/seed-2024-08-29-145 new file mode 100644 index 0000000000000000000000000000000000000000..a9c28f91db2c0a9d82b9ade7fe3ae51d9ea90a9c Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-145 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-146 b/cmds/servicemanager/corpus/seed-2024-08-29-146 new file mode 100644 index 0000000000000000000000000000000000000000..8e64a65134d08869dc462272768c584585ca9c2c Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-146 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-147 b/cmds/servicemanager/corpus/seed-2024-08-29-147 new file mode 100644 index 0000000000000000000000000000000000000000..f65abe0cf65aae81c7a8498992e3766a3ce1437d Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-147 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-148 b/cmds/servicemanager/corpus/seed-2024-08-29-148 new file mode 100644 index 0000000000000000000000000000000000000000..174e50a2f873081fc5d549a554f599d55ae74f36 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-148 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-149 b/cmds/servicemanager/corpus/seed-2024-08-29-149 new file mode 100644 index 0000000000000000000000000000000000000000..3d58671f16357f7a0f7ffd8a1fa4c938ab04aec5 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-149 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-15 b/cmds/servicemanager/corpus/seed-2024-08-29-15 new file mode 100644 index 0000000000000000000000000000000000000000..a1c47d31d56001ac727911f946d0eb9025b41d28 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-15 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-150 b/cmds/servicemanager/corpus/seed-2024-08-29-150 new file mode 100644 index 0000000000000000000000000000000000000000..a41c9c84b4fc3341570ea2707dd254b1e452a64e Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-150 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-151 b/cmds/servicemanager/corpus/seed-2024-08-29-151 new file mode 100644 index 0000000000000000000000000000000000000000..013f84d92a9ee0bdadabdb9f66177b3e40707624 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-151 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-152 b/cmds/servicemanager/corpus/seed-2024-08-29-152 new file mode 100644 index 0000000000000000000000000000000000000000..ada2ead1e206091704f9719ae850e79ccdcd0ef5 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-152 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-153 b/cmds/servicemanager/corpus/seed-2024-08-29-153 new file mode 100644 index 0000000000000000000000000000000000000000..1b565618e9e10a716e0c0088856dbb52db76ac44 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-153 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-154 b/cmds/servicemanager/corpus/seed-2024-08-29-154 new file mode 100644 index 0000000000000000000000000000000000000000..8fea50f9a33ecc389ea449f58b500470006ffba6 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-154 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-155 b/cmds/servicemanager/corpus/seed-2024-08-29-155 new file mode 100644 index 0000000000000000000000000000000000000000..ddcd8f31c16ab631c42e6c46cdb6dcf3c1aefc27 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-155 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-156 b/cmds/servicemanager/corpus/seed-2024-08-29-156 new file mode 100644 index 0000000000000000000000000000000000000000..19ab7aec2c3e4caf77c7e2918c6cdd73149c357e Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-156 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-157 b/cmds/servicemanager/corpus/seed-2024-08-29-157 new file mode 100644 index 0000000000000000000000000000000000000000..bc89bf5b6843a642b6868ba5631af0a271baf26f Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-157 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-158 b/cmds/servicemanager/corpus/seed-2024-08-29-158 new file mode 100644 index 0000000000000000000000000000000000000000..64867f1c2ae0dc1095925d0637affaf850b0f370 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-158 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-159 b/cmds/servicemanager/corpus/seed-2024-08-29-159 new file mode 100644 index 0000000000000000000000000000000000000000..fe77d0b3f86ac74acf06e5408c30452c150d2dae Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-159 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-16 b/cmds/servicemanager/corpus/seed-2024-08-29-16 new file mode 100644 index 0000000000000000000000000000000000000000..f1002d7d0685945ac335383aaa2a845754f66476 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-16 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-160 b/cmds/servicemanager/corpus/seed-2024-08-29-160 new file mode 100644 index 0000000000000000000000000000000000000000..9c2123f2b9be178558b687cff57ccbad61b3424c Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-160 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-161 b/cmds/servicemanager/corpus/seed-2024-08-29-161 new file mode 100644 index 0000000000000000000000000000000000000000..0fc8e863c5c5a4f0236496a58ea04cdab00cdc80 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-161 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-162 b/cmds/servicemanager/corpus/seed-2024-08-29-162 new file mode 100644 index 0000000000000000000000000000000000000000..a13408506cda2844e2549e995621b2c57e40ceaf Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-162 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-163 b/cmds/servicemanager/corpus/seed-2024-08-29-163 new file mode 100644 index 0000000000000000000000000000000000000000..c23e78c02fb46a19c83ebf05e23d690a7d12d555 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-163 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-164 b/cmds/servicemanager/corpus/seed-2024-08-29-164 new file mode 100644 index 0000000000000000000000000000000000000000..d4feab065101646d54fb7463fe262ade5308ff72 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-164 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-165 b/cmds/servicemanager/corpus/seed-2024-08-29-165 new file mode 100644 index 0000000000000000000000000000000000000000..9cbdc4f4cbe85499392863d04cd3c1419fa040d0 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-165 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-166 b/cmds/servicemanager/corpus/seed-2024-08-29-166 new file mode 100644 index 0000000000000000000000000000000000000000..d4cf647d8e73504b1c33c4dd91530bacf6cc4783 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-166 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-167 b/cmds/servicemanager/corpus/seed-2024-08-29-167 new file mode 100644 index 0000000000000000000000000000000000000000..50239095392aab5082d37a5850fc7293ea6fa90a Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-167 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-168 b/cmds/servicemanager/corpus/seed-2024-08-29-168 new file mode 100644 index 0000000000000000000000000000000000000000..846d0ec5bc67f906bf21a5680d52a92c191abdb7 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-168 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-169 b/cmds/servicemanager/corpus/seed-2024-08-29-169 new file mode 100644 index 0000000000000000000000000000000000000000..cf6d882330a9d6c254d5491052d6ec4fdf4cb36e Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-169 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-17 b/cmds/servicemanager/corpus/seed-2024-08-29-17 new file mode 100644 index 0000000000000000000000000000000000000000..6c21de860e6bec358f45f766ccc0650b58c809ab Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-17 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-170 b/cmds/servicemanager/corpus/seed-2024-08-29-170 new file mode 100644 index 0000000000000000000000000000000000000000..d9707cb12914983d71a74ce1e52b000b5491bb99 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-170 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-171 b/cmds/servicemanager/corpus/seed-2024-08-29-171 new file mode 100644 index 0000000000000000000000000000000000000000..ea947f6b3fac0e1cd3195c572fdc22a3e2a0ddd1 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-171 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-172 b/cmds/servicemanager/corpus/seed-2024-08-29-172 new file mode 100644 index 0000000000000000000000000000000000000000..2754437308dcfef7a82f124c74a321feb14e1a54 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-172 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-173 b/cmds/servicemanager/corpus/seed-2024-08-29-173 new file mode 100644 index 0000000000000000000000000000000000000000..96e8d563a21c759383f72a848a722af19003fbb6 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-173 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-174 b/cmds/servicemanager/corpus/seed-2024-08-29-174 new file mode 100644 index 0000000000000000000000000000000000000000..aa6472e7e5a0b008d0af8a7748a462031f31fed7 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-174 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-175 b/cmds/servicemanager/corpus/seed-2024-08-29-175 new file mode 100644 index 0000000000000000000000000000000000000000..41e789479b253ba013a7b11b3903d9c36f22a996 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-175 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-176 b/cmds/servicemanager/corpus/seed-2024-08-29-176 new file mode 100644 index 0000000000000000000000000000000000000000..b94712aefe2df346277d8fd65ad3102482daacb7 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-176 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-177 b/cmds/servicemanager/corpus/seed-2024-08-29-177 new file mode 100644 index 0000000000000000000000000000000000000000..4925e6254affe118370c57c60cbf4d2e7c71703f Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-177 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-178 b/cmds/servicemanager/corpus/seed-2024-08-29-178 new file mode 100644 index 0000000000000000000000000000000000000000..9ec943d9fe48d12baba9912230be4928fad6e902 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-178 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-179 b/cmds/servicemanager/corpus/seed-2024-08-29-179 new file mode 100644 index 0000000000000000000000000000000000000000..e173bd3331b4f33e0fda7f6ca47a21e4682bc2ea Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-179 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-18 b/cmds/servicemanager/corpus/seed-2024-08-29-18 new file mode 100644 index 0000000000000000000000000000000000000000..aa0b101ecddf17e1649e55d225d817c949994121 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-18 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-180 b/cmds/servicemanager/corpus/seed-2024-08-29-180 new file mode 100644 index 0000000000000000000000000000000000000000..f6f4ba780b969efe2cb374e412e483087ea86d8f Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-180 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-181 b/cmds/servicemanager/corpus/seed-2024-08-29-181 new file mode 100644 index 0000000000000000000000000000000000000000..2ca01e693d7e93a87fa967ac58ceec7e6a460859 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-181 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-182 b/cmds/servicemanager/corpus/seed-2024-08-29-182 new file mode 100644 index 0000000000000000000000000000000000000000..18966c0ad7792ab2ca5ca281b0421ee6f927b556 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-182 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-183 b/cmds/servicemanager/corpus/seed-2024-08-29-183 new file mode 100644 index 0000000000000000000000000000000000000000..887de1013d20593c6d6359e87db375ef888c91d1 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-183 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-184 b/cmds/servicemanager/corpus/seed-2024-08-29-184 new file mode 100644 index 0000000000000000000000000000000000000000..fee8cdb6a3b979557d4508808bf00d1eb3278878 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-184 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-185 b/cmds/servicemanager/corpus/seed-2024-08-29-185 new file mode 100644 index 0000000000000000000000000000000000000000..10dd34d8eb13af6885991c3c3634115155eb6e8c Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-185 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-186 b/cmds/servicemanager/corpus/seed-2024-08-29-186 new file mode 100644 index 0000000000000000000000000000000000000000..6ad247bec0042a483cf772937cfbf2bffb1ea740 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-186 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-187 b/cmds/servicemanager/corpus/seed-2024-08-29-187 new file mode 100644 index 0000000000000000000000000000000000000000..613456daefd591c1ce634e6ec41891c3a6f7bba7 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-187 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-188 b/cmds/servicemanager/corpus/seed-2024-08-29-188 new file mode 100644 index 0000000000000000000000000000000000000000..851b25fee7dc9839f5678afc819fcf2936098a3b Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-188 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-189 b/cmds/servicemanager/corpus/seed-2024-08-29-189 new file mode 100644 index 0000000000000000000000000000000000000000..c4cebe91fd2a0180ab793d767f70c649083cb81f Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-189 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-19 b/cmds/servicemanager/corpus/seed-2024-08-29-19 new file mode 100644 index 0000000000000000000000000000000000000000..c0792c09c3be4b0e51dbb7c2f521e83a8aaf5675 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-19 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-190 b/cmds/servicemanager/corpus/seed-2024-08-29-190 new file mode 100644 index 0000000000000000000000000000000000000000..4370a318b4619de04fb040c0882654ae4ad85328 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-190 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-191 b/cmds/servicemanager/corpus/seed-2024-08-29-191 new file mode 100644 index 0000000000000000000000000000000000000000..09704284ee07adbc3078c35849404a1f40f9f6c6 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-191 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-192 b/cmds/servicemanager/corpus/seed-2024-08-29-192 new file mode 100644 index 0000000000000000000000000000000000000000..6cec4004da17f16c4b99e2974fdf892d0f272d17 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-192 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-193 b/cmds/servicemanager/corpus/seed-2024-08-29-193 new file mode 100644 index 0000000000000000000000000000000000000000..15a766167d44233676630bc82fb7f4f54d30a259 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-193 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-194 b/cmds/servicemanager/corpus/seed-2024-08-29-194 new file mode 100644 index 0000000000000000000000000000000000000000..3cabe77e6d85ca8e10032674c7830ef3098bb400 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-194 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-195 b/cmds/servicemanager/corpus/seed-2024-08-29-195 new file mode 100644 index 0000000000000000000000000000000000000000..4c5274bca9ba280de7f98e1067b53afda44c2b6a Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-195 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-196 b/cmds/servicemanager/corpus/seed-2024-08-29-196 new file mode 100644 index 0000000000000000000000000000000000000000..9d7a3d6a76dd84dd9ab55cf60c53d61a92678877 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-196 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-197 b/cmds/servicemanager/corpus/seed-2024-08-29-197 new file mode 100644 index 0000000000000000000000000000000000000000..4e69238bf31366ce3851bb4049569ec631759324 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-197 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-198 b/cmds/servicemanager/corpus/seed-2024-08-29-198 new file mode 100644 index 0000000000000000000000000000000000000000..5f6df994be25e4ee979379aefa94bd2e586f2d80 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-198 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-199 b/cmds/servicemanager/corpus/seed-2024-08-29-199 new file mode 100644 index 0000000000000000000000000000000000000000..a902bba2053247ca05ccee22387d95c5fcf1e300 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-199 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-2 b/cmds/servicemanager/corpus/seed-2024-08-29-2 new file mode 100644 index 0000000000000000000000000000000000000000..ffa97196a9b4487bfca50af484c3a8d26370758c Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-2 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-20 b/cmds/servicemanager/corpus/seed-2024-08-29-20 new file mode 100644 index 0000000000000000000000000000000000000000..2090ef620ac3586a5d7a00fa2bb6f04e0716a01b Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-20 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-200 b/cmds/servicemanager/corpus/seed-2024-08-29-200 new file mode 100644 index 0000000000000000000000000000000000000000..2c91da6f3e32d2a60de550c5ee683c3c6ffb0489 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-200 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-201 b/cmds/servicemanager/corpus/seed-2024-08-29-201 new file mode 100644 index 0000000000000000000000000000000000000000..eb77655ce19b1d6757f398bf4598850195d0c697 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-201 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-202 b/cmds/servicemanager/corpus/seed-2024-08-29-202 new file mode 100644 index 0000000000000000000000000000000000000000..bcbe3b761979d3a93dfd630871b15e5259377420 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-202 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-203 b/cmds/servicemanager/corpus/seed-2024-08-29-203 new file mode 100644 index 0000000000000000000000000000000000000000..7c3dc94e428985ebe8ccd46908061a1aba31ed9c Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-203 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-204 b/cmds/servicemanager/corpus/seed-2024-08-29-204 new file mode 100644 index 0000000000000000000000000000000000000000..a4b660e5f7d1dc8a18c8787d7f38b3aec0dac106 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-204 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-205 b/cmds/servicemanager/corpus/seed-2024-08-29-205 new file mode 100644 index 0000000000000000000000000000000000000000..aee1c21faeff74dbc2376e857ab7fb0d08d61e91 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-205 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-206 b/cmds/servicemanager/corpus/seed-2024-08-29-206 new file mode 100644 index 0000000000000000000000000000000000000000..6863c2ef0a398fa2f09b875f5da522eda6143113 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-206 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-207 b/cmds/servicemanager/corpus/seed-2024-08-29-207 new file mode 100644 index 0000000000000000000000000000000000000000..bf2c59f0842761f8e2fc107aeb5d2f23d12a820a Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-207 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-208 b/cmds/servicemanager/corpus/seed-2024-08-29-208 new file mode 100644 index 0000000000000000000000000000000000000000..78081b969eec665787c15129082d852260d83ec6 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-208 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-209 b/cmds/servicemanager/corpus/seed-2024-08-29-209 new file mode 100644 index 0000000000000000000000000000000000000000..76df969df6d19215ce7339f6f86ef48f16b6b50b Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-209 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-21 b/cmds/servicemanager/corpus/seed-2024-08-29-21 new file mode 100644 index 0000000000000000000000000000000000000000..510b9cf36521f62316022d49205e270c371700e6 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-21 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-210 b/cmds/servicemanager/corpus/seed-2024-08-29-210 new file mode 100644 index 0000000000000000000000000000000000000000..b5174e0966c8b64802a95ce63d43f3692365935c Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-210 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-211 b/cmds/servicemanager/corpus/seed-2024-08-29-211 new file mode 100644 index 0000000000000000000000000000000000000000..51af47191645d630f91bce22ce1d7a070343f526 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-211 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-212 b/cmds/servicemanager/corpus/seed-2024-08-29-212 new file mode 100644 index 0000000000000000000000000000000000000000..f260df4564053789bf55d114c203ec4f5af0b9d9 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-212 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-213 b/cmds/servicemanager/corpus/seed-2024-08-29-213 new file mode 100644 index 0000000000000000000000000000000000000000..2d322b958404a1703c500f2f2bcd6873f1e8b01f Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-213 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-214 b/cmds/servicemanager/corpus/seed-2024-08-29-214 new file mode 100644 index 0000000000000000000000000000000000000000..8df3af4716231fc2a3b41f7b387e7ca8ee023e6c Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-214 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-215 b/cmds/servicemanager/corpus/seed-2024-08-29-215 new file mode 100644 index 0000000000000000000000000000000000000000..b82d03b17152f80adbcd609051338fedb1230d16 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-215 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-216 b/cmds/servicemanager/corpus/seed-2024-08-29-216 new file mode 100644 index 0000000000000000000000000000000000000000..16f6d4d6aedc687cba15b7965b7e526f633e4da1 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-216 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-217 b/cmds/servicemanager/corpus/seed-2024-08-29-217 new file mode 100644 index 0000000000000000000000000000000000000000..d4c2bb36c6e879ac0e502b30058085f35a748b19 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-217 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-218 b/cmds/servicemanager/corpus/seed-2024-08-29-218 new file mode 100644 index 0000000000000000000000000000000000000000..d0c19701465688c102c9f2468da336e9d4844ff9 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-218 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-219 b/cmds/servicemanager/corpus/seed-2024-08-29-219 new file mode 100644 index 0000000000000000000000000000000000000000..75edd86eefb02c4ccc17f36259354c78d6c6af20 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-219 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-22 b/cmds/servicemanager/corpus/seed-2024-08-29-22 new file mode 100644 index 0000000000000000000000000000000000000000..aa87441e0d43c641bcecefcd391587344b55d204 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-22 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-220 b/cmds/servicemanager/corpus/seed-2024-08-29-220 new file mode 100644 index 0000000000000000000000000000000000000000..b3b6788f9d1c073058351227aba0a9c3bb1929e4 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-220 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-221 b/cmds/servicemanager/corpus/seed-2024-08-29-221 new file mode 100644 index 0000000000000000000000000000000000000000..429da0ef058c962c8997facfa53fda0865e6d38f Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-221 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-222 b/cmds/servicemanager/corpus/seed-2024-08-29-222 new file mode 100644 index 0000000000000000000000000000000000000000..be8e3f30fd6ad5b1c9746a8f3a7091c12462f880 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-222 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-223 b/cmds/servicemanager/corpus/seed-2024-08-29-223 new file mode 100644 index 0000000000000000000000000000000000000000..a5a6d9c9dab3415c2c60e7e219b2a495e20941a4 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-223 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-224 b/cmds/servicemanager/corpus/seed-2024-08-29-224 new file mode 100644 index 0000000000000000000000000000000000000000..9a7d07e60c038cf5102ea44a6d636cd0243c3e77 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-224 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-225 b/cmds/servicemanager/corpus/seed-2024-08-29-225 new file mode 100644 index 0000000000000000000000000000000000000000..39a5644d71b3477d06183d8b8a4e942455cbdd65 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-225 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-226 b/cmds/servicemanager/corpus/seed-2024-08-29-226 new file mode 100644 index 0000000000000000000000000000000000000000..c32f26ad65fc484a1afa2363f6e18dbcff26a0bf Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-226 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-227 b/cmds/servicemanager/corpus/seed-2024-08-29-227 new file mode 100644 index 0000000000000000000000000000000000000000..5af105be86a5c1ddcdde560e670838a48a39a373 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-227 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-23 b/cmds/servicemanager/corpus/seed-2024-08-29-23 new file mode 100644 index 0000000000000000000000000000000000000000..4399c39593734d846689a1d6029a68ea53968f93 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-23 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-24 b/cmds/servicemanager/corpus/seed-2024-08-29-24 new file mode 100644 index 0000000000000000000000000000000000000000..133c59a8ae79fac23dcb344823479b19d8563547 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-24 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-25 b/cmds/servicemanager/corpus/seed-2024-08-29-25 new file mode 100644 index 0000000000000000000000000000000000000000..ec1ac02447cc7f54199900c6e54418a75a22f906 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-25 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-26 b/cmds/servicemanager/corpus/seed-2024-08-29-26 new file mode 100644 index 0000000000000000000000000000000000000000..55397b96d598a85fdc96c9502a403d1300b60bcb Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-26 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-27 b/cmds/servicemanager/corpus/seed-2024-08-29-27 new file mode 100644 index 0000000000000000000000000000000000000000..517af0b887ed411351f8dd5ce96f879794e8d804 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-27 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-28 b/cmds/servicemanager/corpus/seed-2024-08-29-28 new file mode 100644 index 0000000000000000000000000000000000000000..0401668a6516d25c99e4ac0ebffef5deaab794d4 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-28 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-29 b/cmds/servicemanager/corpus/seed-2024-08-29-29 new file mode 100644 index 0000000000000000000000000000000000000000..05ad4ecbb53d53669fa76b7e81feeedaad4c92ad Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-29 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-3 b/cmds/servicemanager/corpus/seed-2024-08-29-3 new file mode 100644 index 0000000000000000000000000000000000000000..14dcdd0c0dfc6e45cfa54a9cee9add25f6ded0c5 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-3 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-30 b/cmds/servicemanager/corpus/seed-2024-08-29-30 new file mode 100644 index 0000000000000000000000000000000000000000..d941024dab66fb80c3b511d3d522ddd0fa3a7f19 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-30 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-31 b/cmds/servicemanager/corpus/seed-2024-08-29-31 new file mode 100644 index 0000000000000000000000000000000000000000..e93a19271eab8c528b49f11a249bf72c82ad0354 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-31 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-32 b/cmds/servicemanager/corpus/seed-2024-08-29-32 new file mode 100644 index 0000000000000000000000000000000000000000..36f82dd1e8e183ab04662f541c6a29fb329bd2f4 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-32 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-33 b/cmds/servicemanager/corpus/seed-2024-08-29-33 new file mode 100644 index 0000000000000000000000000000000000000000..5f64227f41f866e82475177d070dbf6e717773dc Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-33 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-34 b/cmds/servicemanager/corpus/seed-2024-08-29-34 new file mode 100644 index 0000000000000000000000000000000000000000..13f76344b402639a9324e261a68269dde48a35b8 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-34 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-35 b/cmds/servicemanager/corpus/seed-2024-08-29-35 new file mode 100644 index 0000000000000000000000000000000000000000..3a4476e55c740cc5d2dc8fdaa20cc4e2b21d5a54 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-35 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-36 b/cmds/servicemanager/corpus/seed-2024-08-29-36 new file mode 100644 index 0000000000000000000000000000000000000000..da9c20870fb8064f07843f1bdc190a70c20b2e82 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-36 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-37 b/cmds/servicemanager/corpus/seed-2024-08-29-37 new file mode 100644 index 0000000000000000000000000000000000000000..969a957c35abfdf5d5082ef5992631e8925bbe59 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-37 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-38 b/cmds/servicemanager/corpus/seed-2024-08-29-38 new file mode 100644 index 0000000000000000000000000000000000000000..ab6f1061ede937f59ec9b3a6ddda60e1636e7497 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-38 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-39 b/cmds/servicemanager/corpus/seed-2024-08-29-39 new file mode 100644 index 0000000000000000000000000000000000000000..248a5498116a9fd67cd4e34a14eac382e7417221 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-39 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-4 b/cmds/servicemanager/corpus/seed-2024-08-29-4 new file mode 100644 index 0000000000000000000000000000000000000000..0bd7cd581309c8153c0dd08ad4a254dd85cfefd9 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-4 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-40 b/cmds/servicemanager/corpus/seed-2024-08-29-40 new file mode 100644 index 0000000000000000000000000000000000000000..7031a918fc9e2069c73a7d01fc25b7235762bc2c Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-40 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-41 b/cmds/servicemanager/corpus/seed-2024-08-29-41 new file mode 100644 index 0000000000000000000000000000000000000000..8b8925c6e205f4b4ffe1d31762d7166103112b58 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-41 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-42 b/cmds/servicemanager/corpus/seed-2024-08-29-42 new file mode 100644 index 0000000000000000000000000000000000000000..c6e2167d1200f53b3cb701c95e250b19c4e92eb0 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-42 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-43 b/cmds/servicemanager/corpus/seed-2024-08-29-43 new file mode 100644 index 0000000000000000000000000000000000000000..671a82172c93b7988de377ca04b8e76275155cc8 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-43 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-44 b/cmds/servicemanager/corpus/seed-2024-08-29-44 new file mode 100644 index 0000000000000000000000000000000000000000..7c365b06c329aca1ffb025c43af42d2e5e1e952e Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-44 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-45 b/cmds/servicemanager/corpus/seed-2024-08-29-45 new file mode 100644 index 0000000000000000000000000000000000000000..a38d1382d85af5cedbe7b6c38a9921f70fc713d8 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-45 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-46 b/cmds/servicemanager/corpus/seed-2024-08-29-46 new file mode 100644 index 0000000000000000000000000000000000000000..62acb777dc55f2b95233bec03a33c9f8ce2577cb Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-46 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-47 b/cmds/servicemanager/corpus/seed-2024-08-29-47 new file mode 100644 index 0000000000000000000000000000000000000000..aea84c6dedf6d8fc7146458727208bdc52949797 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-47 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-48 b/cmds/servicemanager/corpus/seed-2024-08-29-48 new file mode 100644 index 0000000000000000000000000000000000000000..a5bab7c63b008c67cd9cbb7ff3070a675894ee5d Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-48 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-49 b/cmds/servicemanager/corpus/seed-2024-08-29-49 new file mode 100644 index 0000000000000000000000000000000000000000..4f19f09a0283f9d473de206651f86b7752d3f051 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-49 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-5 b/cmds/servicemanager/corpus/seed-2024-08-29-5 new file mode 100644 index 0000000000000000000000000000000000000000..4e8a8534cf145c8e4af3bf96e63401905a033c1f Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-5 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-50 b/cmds/servicemanager/corpus/seed-2024-08-29-50 new file mode 100644 index 0000000000000000000000000000000000000000..2f1d78b4ffe062d0a6cf7f0258e1594b24775764 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-50 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-51 b/cmds/servicemanager/corpus/seed-2024-08-29-51 new file mode 100644 index 0000000000000000000000000000000000000000..7a44b4a5c730ae9dce309ffd8cf779cae26cb0ff Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-51 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-52 b/cmds/servicemanager/corpus/seed-2024-08-29-52 new file mode 100644 index 0000000000000000000000000000000000000000..3da177b3dff9561330bbfb53548879008c51cc8e Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-52 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-53 b/cmds/servicemanager/corpus/seed-2024-08-29-53 new file mode 100644 index 0000000000000000000000000000000000000000..c67df718ba4badcb70c7cd3565be636ddd8576f2 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-53 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-54 b/cmds/servicemanager/corpus/seed-2024-08-29-54 new file mode 100644 index 0000000000000000000000000000000000000000..b1e8fec0108514b673c14eda9110cff878bce73b Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-54 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-55 b/cmds/servicemanager/corpus/seed-2024-08-29-55 new file mode 100644 index 0000000000000000000000000000000000000000..20b268a3c15c9ecb905c5004e11444efc456029f Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-55 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-56 b/cmds/servicemanager/corpus/seed-2024-08-29-56 new file mode 100644 index 0000000000000000000000000000000000000000..146192696c34d57660f2f2c4995e5fa89f5d37fe Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-56 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-57 b/cmds/servicemanager/corpus/seed-2024-08-29-57 new file mode 100644 index 0000000000000000000000000000000000000000..fab8065815da0bed417f8ee61201ed69df5df606 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-57 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-58 b/cmds/servicemanager/corpus/seed-2024-08-29-58 new file mode 100644 index 0000000000000000000000000000000000000000..676f9e46d3e6664966092ba02e82fdf2bac42e91 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-58 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-59 b/cmds/servicemanager/corpus/seed-2024-08-29-59 new file mode 100644 index 0000000000000000000000000000000000000000..a8e2c7220f2f3b062c146b955b612f747486bf8a Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-59 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-6 b/cmds/servicemanager/corpus/seed-2024-08-29-6 new file mode 100644 index 0000000000000000000000000000000000000000..585f1f0c04f708d7cda5d032984ca07b313ff598 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-6 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-60 b/cmds/servicemanager/corpus/seed-2024-08-29-60 new file mode 100644 index 0000000000000000000000000000000000000000..ef4b098b58261eefc155b2c722a76a7fdfed22c1 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-60 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-61 b/cmds/servicemanager/corpus/seed-2024-08-29-61 new file mode 100644 index 0000000000000000000000000000000000000000..5f45443fd4ba7b8eb24c9c0765e1fe8616143723 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-61 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-62 b/cmds/servicemanager/corpus/seed-2024-08-29-62 new file mode 100644 index 0000000000000000000000000000000000000000..7ffd7769486d0dda563746d3465ac0f93d3878d1 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-62 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-63 b/cmds/servicemanager/corpus/seed-2024-08-29-63 new file mode 100644 index 0000000000000000000000000000000000000000..fa026cd45212bdd24cc98f28524a32ee38a6bc0d Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-63 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-64 b/cmds/servicemanager/corpus/seed-2024-08-29-64 new file mode 100644 index 0000000000000000000000000000000000000000..422c823386f678526ba3ed1a85096ccb289040dd Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-64 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-65 b/cmds/servicemanager/corpus/seed-2024-08-29-65 new file mode 100644 index 0000000000000000000000000000000000000000..c811c44438e7259d27877e7f95e359bea9d9fba7 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-65 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-66 b/cmds/servicemanager/corpus/seed-2024-08-29-66 new file mode 100644 index 0000000000000000000000000000000000000000..8407da200687a31b30c382a80632f85beea20881 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-66 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-67 b/cmds/servicemanager/corpus/seed-2024-08-29-67 new file mode 100644 index 0000000000000000000000000000000000000000..76dfdc3c954850edbf1b548cd13a2142d79b663e Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-67 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-68 b/cmds/servicemanager/corpus/seed-2024-08-29-68 new file mode 100644 index 0000000000000000000000000000000000000000..d93e0e3a5a2175b038ee5209c40db01ebeb226e8 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-68 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-69 b/cmds/servicemanager/corpus/seed-2024-08-29-69 new file mode 100644 index 0000000000000000000000000000000000000000..12b501b7daa1c247f527ef49eee377127f899821 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-69 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-7 b/cmds/servicemanager/corpus/seed-2024-08-29-7 new file mode 100644 index 0000000000000000000000000000000000000000..647836362d32ccfa4c66001cefebedbd46f49510 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-7 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-70 b/cmds/servicemanager/corpus/seed-2024-08-29-70 new file mode 100644 index 0000000000000000000000000000000000000000..e6206230ccf4887cde920b6492944c06a5ade193 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-70 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-71 b/cmds/servicemanager/corpus/seed-2024-08-29-71 new file mode 100644 index 0000000000000000000000000000000000000000..dc32a5f830ad627ea2cf89ec62e3679f6ca25faa Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-71 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-72 b/cmds/servicemanager/corpus/seed-2024-08-29-72 new file mode 100644 index 0000000000000000000000000000000000000000..24217c62c677e9db1302d0d7eae9d220291d00a4 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-72 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-73 b/cmds/servicemanager/corpus/seed-2024-08-29-73 new file mode 100644 index 0000000000000000000000000000000000000000..a9a0b2be58ad19e45ec4e816425bee7cadeabb5b Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-73 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-74 b/cmds/servicemanager/corpus/seed-2024-08-29-74 new file mode 100644 index 0000000000000000000000000000000000000000..fd8a429232421c015ecddd366d368bc4c5cc53b6 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-74 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-75 b/cmds/servicemanager/corpus/seed-2024-08-29-75 new file mode 100644 index 0000000000000000000000000000000000000000..090b4894b033d3049a8f8e6a69ca5baaab171a0c Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-75 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-76 b/cmds/servicemanager/corpus/seed-2024-08-29-76 new file mode 100644 index 0000000000000000000000000000000000000000..c92c45f97cd106d273f95509d85ee55c63a513f6 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-76 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-77 b/cmds/servicemanager/corpus/seed-2024-08-29-77 new file mode 100644 index 0000000000000000000000000000000000000000..002a2336d0f064c4f02de7d4d4a97c7313be2822 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-77 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-78 b/cmds/servicemanager/corpus/seed-2024-08-29-78 new file mode 100644 index 0000000000000000000000000000000000000000..633f93734123dab5cabaa77931c9e14e0d583def Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-78 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-79 b/cmds/servicemanager/corpus/seed-2024-08-29-79 new file mode 100644 index 0000000000000000000000000000000000000000..77782404bb2ba2232400536c506b8134816df65c Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-79 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-8 b/cmds/servicemanager/corpus/seed-2024-08-29-8 new file mode 100644 index 0000000000000000000000000000000000000000..580e20005a5ce99e840fb82cac7f5e1611ff6b97 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-8 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-80 b/cmds/servicemanager/corpus/seed-2024-08-29-80 new file mode 100644 index 0000000000000000000000000000000000000000..90d74e44fdf934ff5a764927d3ac5498e7e57e6c Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-80 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-81 b/cmds/servicemanager/corpus/seed-2024-08-29-81 new file mode 100644 index 0000000000000000000000000000000000000000..1fd76686f7a09d2da9379f24f80595fc7e5c9bee Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-81 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-82 b/cmds/servicemanager/corpus/seed-2024-08-29-82 new file mode 100644 index 0000000000000000000000000000000000000000..d7715015085c0b0832e561273c47e96d8df7ebe7 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-82 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-83 b/cmds/servicemanager/corpus/seed-2024-08-29-83 new file mode 100644 index 0000000000000000000000000000000000000000..6a4a1ca2510898bef3be8df0fa8b7779e4f739dd Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-83 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-84 b/cmds/servicemanager/corpus/seed-2024-08-29-84 new file mode 100644 index 0000000000000000000000000000000000000000..bf8459b34c1c3a8ba5e916ebdbf8e4f8419e57f9 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-84 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-85 b/cmds/servicemanager/corpus/seed-2024-08-29-85 new file mode 100644 index 0000000000000000000000000000000000000000..8c88cacdc1fdebed8303a882d391000f8c7a2a09 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-85 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-86 b/cmds/servicemanager/corpus/seed-2024-08-29-86 new file mode 100644 index 0000000000000000000000000000000000000000..62f676585a4f23bb4983d13ccd1bc59b7330be05 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-86 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-87 b/cmds/servicemanager/corpus/seed-2024-08-29-87 new file mode 100644 index 0000000000000000000000000000000000000000..eb54dcbca2240a0dbb58992fd5742795359433a2 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-87 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-88 b/cmds/servicemanager/corpus/seed-2024-08-29-88 new file mode 100644 index 0000000000000000000000000000000000000000..f38aaba211c02474e4b45603487a925c556c4243 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-88 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-89 b/cmds/servicemanager/corpus/seed-2024-08-29-89 new file mode 100644 index 0000000000000000000000000000000000000000..b4154aeeea31a39dfe279fb30c13e4aa2f03a777 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-89 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-9 b/cmds/servicemanager/corpus/seed-2024-08-29-9 new file mode 100644 index 0000000000000000000000000000000000000000..5dca38a5a2bd3e660c288f76c68fb48772a74d97 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-9 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-90 b/cmds/servicemanager/corpus/seed-2024-08-29-90 new file mode 100644 index 0000000000000000000000000000000000000000..2725a79022016807e25339fc26763d6d0a079283 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-90 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-91 b/cmds/servicemanager/corpus/seed-2024-08-29-91 new file mode 100644 index 0000000000000000000000000000000000000000..9140e28e10758ca9c90dc677fe4e07337492495e Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-91 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-92 b/cmds/servicemanager/corpus/seed-2024-08-29-92 new file mode 100644 index 0000000000000000000000000000000000000000..88dda1e85c26bc78144222bff755a933530d725d Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-92 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-93 b/cmds/servicemanager/corpus/seed-2024-08-29-93 new file mode 100644 index 0000000000000000000000000000000000000000..6dd114e84d28d8acb579647bb8531c1b6694a655 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-93 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-94 b/cmds/servicemanager/corpus/seed-2024-08-29-94 new file mode 100644 index 0000000000000000000000000000000000000000..462c185d0733ea42495b617de78e21d5ea3792e8 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-94 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-95 b/cmds/servicemanager/corpus/seed-2024-08-29-95 new file mode 100644 index 0000000000000000000000000000000000000000..4472deb9b1793aa11d3eb0c15a0456ff90139895 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-95 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-96 b/cmds/servicemanager/corpus/seed-2024-08-29-96 new file mode 100644 index 0000000000000000000000000000000000000000..875efc5b2b78a6a0c1821d7951a00d59d3da5350 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-96 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-97 b/cmds/servicemanager/corpus/seed-2024-08-29-97 new file mode 100644 index 0000000000000000000000000000000000000000..3f0277e129962b661dbe50bbbb3c93960e045cde Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-97 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-98 b/cmds/servicemanager/corpus/seed-2024-08-29-98 new file mode 100644 index 0000000000000000000000000000000000000000..2c6643617245e24be39c4f76433a0d7a28d8c0ad Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-98 differ diff --git a/cmds/servicemanager/corpus/seed-2024-08-29-99 b/cmds/servicemanager/corpus/seed-2024-08-29-99 new file mode 100644 index 0000000000000000000000000000000000000000..9a6ff1dff0bbac534b15269e69e820fb52b6ccd6 Binary files /dev/null and b/cmds/servicemanager/corpus/seed-2024-08-29-99 differ diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp index 07908ba5b30272b8e3ad796700f0f4a53970f646..c126e913737c1d848b8c46bb0094df3b07ef9ef2 100644 --- a/cmds/servicemanager/main.cpp +++ b/cmds/servicemanager/main.cpp @@ -26,6 +26,26 @@ #include "Access.h" #include "ServiceManager.h" +#if !defined(VENDORSERVICEMANAGER) && !defined(__ANDROID_RECOVERY__) + +#include +#include +#include +#include + +namespace android { + +static void register_perfetto_te_categories() { + struct PerfettoProducerInitArgs perfetto_args = PERFETTO_PRODUCER_INIT_ARGS_INIT(); + perfetto_args.backends = PERFETTO_BACKEND_SYSTEM; + PerfettoProducerInit(perfetto_args); + PerfettoTeInit(); + PERFETTO_TE_REGISTER_CATEGORIES(PERFETTO_SM_CATEGORIES); +} +} // namespace android + +#endif // !defined(VENDORSERVICEMANAGER) && !defined(__ANDROID_RECOVERY__) + using ::android::Access; using ::android::IPCThreadState; using ::android::Looper; @@ -132,6 +152,10 @@ int main(int argc, char** argv) { const char* driver = argc == 2 ? argv[1] : "/dev/binder"; +#if !defined(VENDORSERVICEMANAGER) && !defined(__ANDROID_RECOVERY__) + android::register_perfetto_te_categories(); +#endif // !defined(VENDORSERVICEMANAGER) && !defined(__ANDROID_RECOVERY__) + LOG(INFO) << "Starting sm instance on " << driver; sp ps = ProcessState::initWithDriver(driver); diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp index b57505302cc82fe8944bae8e6701b874102cec20..95f459f7f06ef52eccf304cbd1f47065dd47d29a 100644 --- a/cmds/servicemanager/test_sm.cpp +++ b/cmds/servicemanager/test_sm.cpp @@ -38,6 +38,7 @@ using android::base::StartsWith; using android::binder::Status; using android::os::BnServiceCallback; using android::os::IServiceManager; +using android::os::Service; using testing::_; using testing::ElementsAre; using testing::NiceMock; @@ -153,18 +154,24 @@ TEST(AddService, OverwriteExistingService) { EXPECT_TRUE(sm->addService("foo", serviceA, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); - sp outA; - EXPECT_TRUE(sm->getService("foo", &outA).isOk()); - EXPECT_EQ(serviceA, outA); + Service outA; + EXPECT_TRUE(sm->getService2("foo", &outA).isOk()); + EXPECT_EQ(serviceA, outA.get()); + sp outBinderA; + EXPECT_TRUE(sm->getService("foo", &outBinderA).isOk()); + EXPECT_EQ(serviceA, outBinderA); // serviceA should be overwritten by serviceB sp serviceB = getBinder(); EXPECT_TRUE(sm->addService("foo", serviceB, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); - sp outB; - EXPECT_TRUE(sm->getService("foo", &outB).isOk()); - EXPECT_EQ(serviceB, outB); + Service outB; + EXPECT_TRUE(sm->getService2("foo", &outB).isOk()); + EXPECT_EQ(serviceB, outB.get()); + sp outBinderB; + EXPECT_TRUE(sm->getService("foo", &outBinderB).isOk()); + EXPECT_EQ(serviceB, outBinderB); } TEST(AddService, NoPermissions) { @@ -186,17 +193,23 @@ TEST(GetService, HappyHappy) { EXPECT_TRUE(sm->addService("foo", service, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); - sp out; - EXPECT_TRUE(sm->getService("foo", &out).isOk()); - EXPECT_EQ(service, out); + Service out; + EXPECT_TRUE(sm->getService2("foo", &out).isOk()); + EXPECT_EQ(service, out.get()); + sp outBinder; + EXPECT_TRUE(sm->getService("foo", &outBinder).isOk()); + EXPECT_EQ(service, outBinder); } TEST(GetService, NonExistant) { auto sm = getPermissiveServiceManager(); - sp out; - EXPECT_TRUE(sm->getService("foo", &out).isOk()); - EXPECT_EQ(nullptr, out.get()); + Service out; + EXPECT_TRUE(sm->getService2("foo", &out).isOk()); + EXPECT_EQ(nullptr, out.get()); + sp outBinder; + EXPECT_TRUE(sm->getService("foo", &outBinder).isOk()); + EXPECT_EQ(nullptr, outBinder); } TEST(GetService, NoPermissionsForGettingService) { @@ -204,31 +217,37 @@ TEST(GetService, NoPermissionsForGettingService) { EXPECT_CALL(*access, getCallingContext()).WillRepeatedly(Return(Access::CallingContext{})); EXPECT_CALL(*access, canAdd(_, _)).WillOnce(Return(true)); - EXPECT_CALL(*access, canFind(_, _)).WillOnce(Return(false)); + EXPECT_CALL(*access, canFind(_, _)).WillRepeatedly(Return(false)); sp sm = sp>::make(std::move(access)); EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); - sp out; + Service out; // returns nullptr but has OK status for legacy compatibility - EXPECT_TRUE(sm->getService("foo", &out).isOk()); - EXPECT_EQ(nullptr, out.get()); + EXPECT_TRUE(sm->getService2("foo", &out).isOk()); + EXPECT_EQ(nullptr, out.get()); + sp outBinder; + EXPECT_TRUE(sm->getService("foo", &outBinder).isOk()); + EXPECT_EQ(nullptr, outBinder); } TEST(GetService, AllowedFromIsolated) { std::unique_ptr access = std::make_unique>(); EXPECT_CALL(*access, getCallingContext()) - // something adds it - .WillOnce(Return(Access::CallingContext{})) - // next call is from isolated app - .WillOnce(Return(Access::CallingContext{ - .uid = AID_ISOLATED_START, - })); + // something adds it + .WillOnce(Return(Access::CallingContext{})) + // next calls is from isolated app + .WillOnce(Return(Access::CallingContext{ + .uid = AID_ISOLATED_START, + })) + .WillOnce(Return(Access::CallingContext{ + .uid = AID_ISOLATED_START, + })); EXPECT_CALL(*access, canAdd(_, _)).WillOnce(Return(true)); - EXPECT_CALL(*access, canFind(_, _)).WillOnce(Return(true)); + EXPECT_CALL(*access, canFind(_, _)).WillRepeatedly(Return(true)); sp sm = sp>::make(std::move(access)); @@ -236,21 +255,27 @@ TEST(GetService, AllowedFromIsolated) { EXPECT_TRUE(sm->addService("foo", service, true /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); - sp out; - EXPECT_TRUE(sm->getService("foo", &out).isOk()); - EXPECT_EQ(service, out.get()); + Service out; + EXPECT_TRUE(sm->getService2("foo", &out).isOk()); + EXPECT_EQ(service, out.get()); + sp outBinder; + EXPECT_TRUE(sm->getService("foo", &outBinder).isOk()); + EXPECT_EQ(service, outBinder); } TEST(GetService, NotAllowedFromIsolated) { std::unique_ptr access = std::make_unique>(); EXPECT_CALL(*access, getCallingContext()) - // something adds it - .WillOnce(Return(Access::CallingContext{})) - // next call is from isolated app - .WillOnce(Return(Access::CallingContext{ - .uid = AID_ISOLATED_START, - })); + // something adds it + .WillOnce(Return(Access::CallingContext{})) + // next calls is from isolated app + .WillOnce(Return(Access::CallingContext{ + .uid = AID_ISOLATED_START, + })) + .WillOnce(Return(Access::CallingContext{ + .uid = AID_ISOLATED_START, + })); EXPECT_CALL(*access, canAdd(_, _)).WillOnce(Return(true)); // TODO(b/136023468): when security check is first, this should be called first @@ -261,10 +286,13 @@ TEST(GetService, NotAllowedFromIsolated) { EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()); - sp out; + Service out; // returns nullptr but has OK status for legacy compatibility - EXPECT_TRUE(sm->getService("foo", &out).isOk()); - EXPECT_EQ(nullptr, out.get()); + EXPECT_TRUE(sm->getService2("foo", &out).isOk()); + EXPECT_EQ(nullptr, out.get()); + sp outBinder; + EXPECT_TRUE(sm->getService("foo", &outBinder).isOk()); + EXPECT_EQ(nullptr, outBinder); } TEST(ListServices, NoPermissions) { diff --git a/data/etc/Android.bp b/data/etc/Android.bp index 4a66c88dccba8b8dad2602e1c76616ed328e5f8a..64ef8278e4e309f14fa6d06fd8a69a46dd001a20 100644 --- a/data/etc/Android.bp +++ b/data/etc/Android.bp @@ -426,6 +426,14 @@ prebuilt_etc { defaults: ["frameworks_native_data_etc_defaults"], } +// installed in system +prebuilt_etc { + name: "android.software.preview_sdk.prebuilt.xml", + relative_install_path: "permissions", + src: "android.software.preview_sdk.xml", + filename_from_src: true, +} + prebuilt_etc { name: "android.software.sip.voip.prebuilt.xml", src: "android.software.sip.voip.xml", @@ -468,6 +476,22 @@ prebuilt_etc { defaults: ["frameworks_native_data_etc_defaults"], } +// installed in system +prebuilt_etc { + name: "android.software.webview.prebuilt.xml", + relative_install_path: "permissions", + src: "android.software.webview.xml", + filename_from_src: true, +} + +// installed in system +prebuilt_etc { + name: "android.software.window_magnification.prebuilt.xml", + relative_install_path: "permissions", + src: "android.software.window_magnification.xml", + filename_from_src: true, +} + prebuilt_etc { name: "aosp_excluded_hardware.prebuilt.xml", src: "aosp_excluded_hardware.xml", diff --git a/data/etc/input/motion_predictor_config.xml b/data/etc/input/motion_predictor_config.xml index c3f2fedc71a0f28eb190fef2fb95fe126618afe4..f593eda42ddeb89e17727a3c090660cc6bf2cf2f 100644 --- a/data/etc/input/motion_predictor_config.xml +++ b/data/etc/input/motion_predictor_config.xml @@ -35,7 +35,11 @@ The jerk thresholds are based on normalized dt = 1 calculations. --> - 1.0 - 1.1 + 1.5 + 2.0 + + + 0.25 diff --git a/include/android/performance_hint.h b/include/android/performance_hint.h index 97e4dc05dd541ca5696e66cae2df0ec2c7541d32..3f32a5abb36b9cb9917cb9bc322d403e80688c6e 100644 --- a/include/android/performance_hint.h +++ b/include/android/performance_hint.h @@ -53,6 +53,7 @@ */ #include +#include #include #include @@ -84,7 +85,6 @@ typedef struct AWorkDuration AWorkDuration; /** * An opaque type representing a handle to a performance hint manager. - * It must be released after use. * * To use:
    *
  • Obtain the performance hint manager instance by calling diff --git a/include/android/surface_control.h b/include/android/surface_control.h index 099a2bc6aff5dc1de275c34fe5a2aafb36f61baa..bf9acb37daa05a3936c063fc44531b776b3704de 100644 --- a/include/android/surface_control.h +++ b/include/android/surface_control.h @@ -145,6 +145,9 @@ typedef struct ASurfaceTransactionStats ASurfaceTransactionStats; * Buffers which are replaced or removed from the scene in the transaction invoking * this callback may be reused after this point. * + * Starting with API level 36, prefer using \a ASurfaceTransaction_OnBufferRelease to listen + * to when a buffer is ready to be reused. + * * \param context Optional context provided by the client that is passed into * the callback. * @@ -157,8 +160,7 @@ typedef struct ASurfaceTransactionStats ASurfaceTransactionStats; * Available since API level 29. */ typedef void (*ASurfaceTransaction_OnComplete)(void* _Null_unspecified context, - ASurfaceTransactionStats* _Nonnull stats) - __INTRODUCED_IN(29); + ASurfaceTransactionStats* _Nonnull stats); /** * The ASurfaceTransaction_OnCommit callback is invoked when transaction is applied and the updates @@ -186,8 +188,36 @@ typedef void (*ASurfaceTransaction_OnComplete)(void* _Null_unspecified context, * Available since API level 31. */ typedef void (*ASurfaceTransaction_OnCommit)(void* _Null_unspecified context, - ASurfaceTransactionStats* _Nonnull stats) - __INTRODUCED_IN(31); + ASurfaceTransactionStats* _Nonnull stats); + +/** + * The ASurfaceTransaction_OnBufferRelease callback is invoked when a buffer that was passed in + * ASurfaceTransaction_setBuffer is ready to be reused. + * + * This callback is guaranteed to be invoked if ASurfaceTransaction_setBuffer is called with a non + * null buffer. If the buffer in the transaction is replaced via another call to + * ASurfaceTransaction_setBuffer, the callback will be invoked immediately. Otherwise the callback + * will be invoked before the ASurfaceTransaction_OnComplete callback after the buffer was + * presented. + * + * If this callback is set, caller should not release the buffer using the + * ASurfaceTransaction_OnComplete. + * + * \param context Optional context provided by the client that is passed into the callback. + * + * \param release_fence_fd Returns the fence file descriptor used to signal the release of buffer + * associated with this callback. If this fence is valid (>=0), the buffer has not yet been released + * and the fence will signal when the buffer has been released. If the fence is -1 , the buffer is + * already released. The recipient of the callback takes ownership of the fence fd and is + * responsible for closing it. + * + * THREADING + * The callback can be invoked on any thread. + * + * Available since API level 36. + */ +typedef void (*ASurfaceTransaction_OnBufferRelease)(void* _Null_unspecified context, + int release_fence_fd); /** * Returns the timestamp of when the frame was latched by the framework. Once a frame is @@ -251,7 +281,7 @@ int64_t ASurfaceTransactionStats_getAcquireTime( /** * The returns the fence used to signal the release of the PREVIOUS buffer set on * this surface. If this fence is valid (>=0), the PREVIOUS buffer has not yet been released and the - * fence will signal when the PREVIOUS buffer has been released. If the fence is -1 , the PREVIOUS + * fence will signal when the PREVIOUS buffer has been released. If the fence is -1, the PREVIOUS * buffer is already released. The recipient of the callback takes ownership of the * previousReleaseFenceFd and is responsible for closing it. * @@ -353,6 +383,9 @@ void ASurfaceTransaction_setZOrder(ASurfaceTransaction* _Nonnull transaction, * Note that the buffer must be allocated with AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE * as the surface control might be composited using the GPU. * + * Starting with API level 36, prefer using \a ASurfaceTransaction_setBufferWithRelease to + * set a buffer and a callback which will be invoked when the buffer is ready to be reused. + * * Available since API level 29. */ void ASurfaceTransaction_setBuffer(ASurfaceTransaction* _Nonnull transaction, @@ -360,6 +393,29 @@ void ASurfaceTransaction_setBuffer(ASurfaceTransaction* _Nonnull transaction, AHardwareBuffer* _Nonnull buffer, int acquire_fence_fd) __INTRODUCED_IN(29); +/** + * Updates the AHardwareBuffer displayed for \a surface_control. If not -1, the + * acquire_fence_fd should be a file descriptor that is signaled when all pending work + * for the buffer is complete and the buffer can be safely read. + * + * The frameworks takes ownership of the \a acquire_fence_fd passed and is responsible + * for closing it. + * + * Note that the buffer must be allocated with AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE + * as the surface control might be composited using the GPU. + * + * When the buffer is ready to be reused, the ASurfaceTransaction_OnBufferRelease + * callback will be invoked. If the buffer is null, the callback will not be invoked. + * + * Available since API level 36. + */ +void ASurfaceTransaction_setBufferWithRelease(ASurfaceTransaction* _Nonnull transaction, + ASurfaceControl* _Nonnull surface_control, + AHardwareBuffer* _Nonnull buffer, + int acquire_fence_fd, void* _Null_unspecified context, + ASurfaceTransaction_OnBufferRelease _Nonnull func) + __INTRODUCED_IN(36); + /** * Updates the color for \a surface_control. This will make the background color for the * ASurfaceControl visible in transparent regions of the surface. Colors \a r, \a g, @@ -373,6 +429,28 @@ void ASurfaceTransaction_setColor(ASurfaceTransaction* _Nonnull transaction, float b, float alpha, enum ADataSpace dataspace) __INTRODUCED_IN(29); +// These APIs (setGeometry and setCrop) were originally written in a +// C-incompatible form using references instead of pointers, and the OS shipped +// that version for years before it was noticed. Fortunately the compiled code +// for callers is the same regardless of whether it's a pointer or a reference, +// so we can declare this as a nonnull pointer for C and keep the existing C++ +// decl and definition. +// +// We could alternatively change the decl and the definition to both be a +// pointer (with an inline definition using references to preserve source compat +// for existing C++ callers), but that requires changing the definition of an +// API that has been in the OS for years. It's theoretically a safe change, but +// without being able to prove it that's a very big risk to take. By keeping the +// C-compatibility hack in the header, we can be sure that we haven't changed +// anything for existing callers. By definition there were no C users of the +// reference-based decl; if there were any C callers of the API at all, they were +// using the same workaround that is now used below. +// +// Even if this workaround turns out to not work for C, there's no permanent +// damage done to the platform (unlike if we were to change the definition). At +// worst it continues to work for C++ (since the preprocessed header as seen by +// C++ hasn't changed, nor has the definition) and continues to not work for C. + /** * \param source The sub-rect within the buffer's content to be rendered inside the surface's area * The surface's source rect is clipped by the bounds of its current buffer. The source rect's width @@ -383,7 +461,7 @@ void ASurfaceTransaction_setColor(ASurfaceTransaction* _Nonnull transaction, * clipped by the bounds of its parent. The destination rect's width and height must be > 0. * * \param transform The transform applied after the source rect is applied to the buffer. This - * parameter should be set to 0 for no transform. To specify a transfrom use the + * parameter should be set to 0 for no transform. To specify a transform use the * NATIVE_WINDOW_TRANSFORM_* enum. * * Available since API level 29. @@ -394,9 +472,14 @@ void ASurfaceTransaction_setColor(ASurfaceTransaction* _Nonnull transaction, * properties at once. */ void ASurfaceTransaction_setGeometry(ASurfaceTransaction* _Nonnull transaction, - ASurfaceControl* _Nonnull surface_control, const ARect& source, - const ARect& destination, int32_t transform) - __INTRODUCED_IN(29); + ASurfaceControl* _Nonnull surface_control, +#if defined(__cplusplus) + const ARect& source, const ARect& destination, +#else + const ARect* _Nonnull source, + const ARect* _Nonnull destination, +#endif + int32_t transform) __INTRODUCED_IN(29); /** * Bounds the surface and its children to the bounds specified. The crop and buffer size will be @@ -408,7 +491,12 @@ void ASurfaceTransaction_setGeometry(ASurfaceTransaction* _Nonnull transaction, * Available since API level 31. */ void ASurfaceTransaction_setCrop(ASurfaceTransaction* _Nonnull transaction, - ASurfaceControl* _Nonnull surface_control, const ARect& crop) + ASurfaceControl* _Nonnull surface_control, +#if defined(__cplusplus) + const ARect& crop) +#else + const ARect* _Nonnull crop) +#endif __INTRODUCED_IN(31); /** diff --git a/include/android/surface_control_input_receiver.h b/include/android/surface_control_input_receiver.h index bdc52490d5a2fc2fabff61b4a734bcb6f57dd07d..f0503f6324cfe3b6227e1743e745ec9e3a94ab95 100644 --- a/include/android/surface_control_input_receiver.h +++ b/include/android/surface_control_input_receiver.h @@ -59,17 +59,13 @@ typedef bool (*AInputReceiver_onKeyEvent)(void *_Null_unspecified context, AInputEvent *_Nonnull keyEvent) __INTRODUCED_IN(__ANDROID_API_V__); -struct AInputReceiverCallbacks; - -struct AInputReceiver; +typedef struct AInputReceiverCallbacks AInputReceiverCallbacks; /** * The InputReceiver that holds the reference to the registered input channel. This must be released * using AInputReceiver_release - * - * Available since API level 35. */ -typedef struct AInputReceiver AInputReceiver __INTRODUCED_IN(__ANDROID_API_V__); +typedef struct AInputReceiver AInputReceiver; /** * Registers an input receiver for an ASurfaceControl that will receive batched input event. For diff --git a/include/android/system_fonts.h b/include/android/system_fonts.h index 94484eaf54cef1c06702137919aec78a5592cdd0..2d3a2148ae3797025f1bd7108ca60aa8db441fd9 100644 --- a/include/android/system_fonts.h +++ b/include/android/system_fonts.h @@ -31,27 +31,27 @@ * * \code{.cpp} * ASystemFontIterator* iterator = ASystemFontIterator_open(); - * ASystemFont* font = NULL; + * AFont* font = NULL; * * while ((font = ASystemFontIterator_next(iterator)) != nullptr) { * // Look if the font is your desired one. - * if (ASystemFont_getWeight(font) == 400 && !ASystemFont_isItalic(font) - * && ASystemFont_getLocale(font) == NULL) { + * if (AFont_getWeight(font) == 400 && !AFont_isItalic(font) + * && AFont_getLocale(font) == NULL) { * break; * } - * ASystemFont_close(font); + * AFont_close(font); * } * ASystemFontIterator_close(iterator); * - * int fd = open(ASystemFont_getFontFilePath(font), O_RDONLY); - * int collectionIndex = ASystemFont_getCollectionINdex(font); + * int fd = open(AFont_getFontFilePath(font), O_RDONLY | O_CLOEXEC); + * int collectionIndex = AFont_getCollectionIndex(font); * std::vector> variationSettings; - * for (size_t i = 0; i < ASystemFont_getAxisCount(font); ++i) { + * for (size_t i = 0; i < AFont_getAxisCount(font); ++i) { * variationSettings.push_back(std::make_pair( - * ASystemFont_getAxisTag(font, i), - * ASystemFont_getAxisValue(font, i))); + * AFont_getAxisTag(font, i), + * AFont_getAxisValue(font, i))); * } - * ASystemFont_close(font); + * AFont_close(font); * * // Use this font for your text rendering engine. * @@ -99,7 +99,7 @@ typedef struct ASystemFontIterator ASystemFontIterator; /** * Create a system font iterator. * - * Use ASystemFont_close() to close the iterator. + * Use ASystemFontIterator_close() to close the iterator. * * Available since API level 29. * @@ -123,7 +123,7 @@ void ASystemFontIterator_close(ASystemFontIterator* _Nullable iterator) __INTROD * * \param iterator an iterator for the system fonts. Passing NULL is not allowed. * \return a font. If no more font is available, returns nullptr. You need to release the returned - * font by ASystemFont_close when it is no longer needed. + * font with AFont_close() when it is no longer needed. */ AFont* _Nullable ASystemFontIterator_next(ASystemFontIterator* _Nonnull iterator) __INTRODUCED_IN(29); diff --git a/include/android/thermal.h b/include/android/thermal.h index fa168cdecb316f883f9f6cfba212b07493effe8e..7f9d2edfc77d25bc25686b5e041aa931f01c49fd 100644 --- a/include/android/thermal.h +++ b/include/android/thermal.h @@ -85,6 +85,7 @@ enum AThermalStatus { /** Need shutdown immediately. */ ATHERMAL_STATUS_SHUTDOWN = 6, }; +typedef enum AThermalStatus AThermalStatus; /** * An opaque type representing a handle to a thermal manager. @@ -240,6 +241,7 @@ struct AThermalHeadroomThreshold { float headroom; AThermalStatus thermalStatus; }; +typedef struct AThermalHeadroomThreshold AThermalHeadroomThreshold; /** * Gets the thermal headroom thresholds for all available thermal status. diff --git a/include/audiomanager/IAudioManager.h b/include/audiomanager/IAudioManager.h index 769670ea99cc21bee55a18825622ef53f4c4b54e..0b7e16bc7db5d1126ee18b18e69f05403a03a545 100644 --- a/include/audiomanager/IAudioManager.h +++ b/include/audiomanager/IAudioManager.h @@ -27,7 +27,7 @@ namespace android { // ---------------------------------------------------------------------------- - +// TODO(b/309532236) replace this class with AIDL generated parcelable class IAudioManager : public IInterface { public: @@ -43,6 +43,7 @@ public: RELEASE_RECORDER = IBinder::FIRST_CALL_TRANSACTION + 6, PLAYER_SESSION_ID = IBinder::FIRST_CALL_TRANSACTION + 7, PORT_EVENT = IBinder::FIRST_CALL_TRANSACTION + 8, + PERMISSION_UPDATE_BARRIER = IBinder::FIRST_CALL_TRANSACTION + 9, }; DECLARE_META_INTERFACE(AudioManager) @@ -63,6 +64,7 @@ public: /*oneway*/ virtual status_t playerSessionId(audio_unique_id_t piid, audio_session_t sessionId) = 0; /*oneway*/ virtual status_t portEvent(audio_port_handle_t portId, player_state_t event, const std::unique_ptr& extras) = 0; + virtual status_t permissionUpdateBarrier() = 0; }; // ---------------------------------------------------------------------------- diff --git a/include/ftl/fake_guard.h b/include/ftl/fake_guard.h index e6012516fc6f8e8bcbc6d451c9c565ed12c358a2..0bf2870b69ecd89affe37ab14c5b6f2a9a048f41 100644 --- a/include/ftl/fake_guard.h +++ b/include/ftl/fake_guard.h @@ -76,12 +76,8 @@ struct [[clang::scoped_lockable]] FakeGuard final { FTL_ATTRIBUTE(release_capability(mutex)) #endif -// The parentheses around `expr` are needed to deduce an lvalue or rvalue reference. -#define FTL_FAKE_GUARD2(mutex, expr) \ - [&]() -> decltype(auto) { \ - const android::ftl::FakeGuard guard(mutex); \ - return (expr); \ - }() +#define FTL_FAKE_GUARD2(mutex, expr) \ + (android::ftl::FakeGuard(mutex), expr) #define FTL_MAKE_FAKE_GUARD(arg1, arg2, guard, ...) guard diff --git a/include/ftl/small_vector.h b/include/ftl/small_vector.h index 43e9fac5e27882c0070df618238a4f5e313a0d47..3d5d52e80cfbb86625a77f1cc930567ce62e3a4e 100644 --- a/include/ftl/small_vector.h +++ b/include/ftl/small_vector.h @@ -234,7 +234,7 @@ class SmallVector final : details::ArrayTraits, details::ArrayComparators promote() && { + std::vector> promote() && { if (dynamic()) { return std::get(std::move(vector_)).promote(); } else { @@ -290,11 +290,11 @@ template class SmallVector final : details::ArrayTraits, details::ArrayComparators, details::ArrayIterators, T>, - std::vector { + std::vector> { using details::ArrayTraits::replace_at; using Iter = details::ArrayIterators; - using Impl = std::vector; + using Impl = std::vector>; friend Iter; @@ -394,12 +394,12 @@ class SmallVector final : details::ArrayTraits, pop_back(); } - std::vector promote() && { return std::move(*this); } + std::vector> promote() && { return std::move(*this); } private: template static Impl convert(SmallVector&& other) { - if constexpr (std::is_constructible_v&&>) { + if constexpr (std::is_constructible_v>&&>) { return std::move(other).promote(); } else { SmallVector vector(other.size()); diff --git a/include/input/Input.h b/include/input/Input.h index ec08cdd1632f69d7365bca3d2efdcc1b7ca93115..a8684bd19b43bc6b28d10498a2d05df2e40c82ba 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -25,6 +25,7 @@ #include #ifdef __linux__ #include +#include #endif #include #include @@ -69,15 +70,17 @@ enum { * actual intent. */ AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED = - android::os::IInputConstants::MOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED, + static_cast(android::os::MotionEventFlag::WINDOW_IS_PARTIALLY_OBSCURED), + AMOTION_EVENT_FLAG_HOVER_EXIT_PENDING = - android::os::IInputConstants::MOTION_EVENT_FLAG_HOVER_EXIT_PENDING, + static_cast(android::os::MotionEventFlag::HOVER_EXIT_PENDING), + /** * This flag indicates that the event has been generated by a gesture generator. It * provides a hint to the GestureDetector to not apply any touch slop. */ AMOTION_EVENT_FLAG_IS_GENERATED_GESTURE = - android::os::IInputConstants::MOTION_EVENT_FLAG_IS_GENERATED_GESTURE, + static_cast(android::os::MotionEventFlag::IS_GENERATED_GESTURE), /** * This flag indicates that the event will not cause a focus change if it is directed to an @@ -86,27 +89,27 @@ enum { * into focus. */ AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE = - android::os::IInputConstants::MOTION_EVENT_FLAG_NO_FOCUS_CHANGE, + static_cast(android::os::MotionEventFlag::NO_FOCUS_CHANGE), /** * This event was generated or modified by accessibility service. */ AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT = - android::os::IInputConstants::INPUT_EVENT_FLAG_IS_ACCESSIBILITY_EVENT, + static_cast(android::os::MotionEventFlag::IS_ACCESSIBILITY_EVENT), AMOTION_EVENT_FLAG_TARGET_ACCESSIBILITY_FOCUS = - android::os::IInputConstants::MOTION_EVENT_FLAG_TARGET_ACCESSIBILITY_FOCUS, + static_cast(android::os::MotionEventFlag::TARGET_ACCESSIBILITY_FOCUS), /* Motion event is inconsistent with previously sent motion events. */ - AMOTION_EVENT_FLAG_TAINTED = android::os::IInputConstants::INPUT_EVENT_FLAG_TAINTED, + AMOTION_EVENT_FLAG_TAINTED = static_cast(android::os::MotionEventFlag::TAINTED), /** Private flag, not used in Java. */ AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_ORIENTATION = - android::os::IInputConstants::MOTION_EVENT_PRIVATE_FLAG_SUPPORTS_ORIENTATION, + static_cast(android::os::MotionEventFlag::PRIVATE_FLAG_SUPPORTS_ORIENTATION), /** Private flag, not used in Java. */ - AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_DIRECTIONAL_ORIENTATION = android::os::IInputConstants:: - MOTION_EVENT_PRIVATE_FLAG_SUPPORTS_DIRECTIONAL_ORIENTATION, + AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_DIRECTIONAL_ORIENTATION = static_cast( + android::os::MotionEventFlag::PRIVATE_FLAG_SUPPORTS_DIRECTIONAL_ORIENTATION), /** Mask for all private flags that are not used in Java. */ AMOTION_EVENT_PRIVATE_FLAG_MASK = AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_ORIENTATION | @@ -192,6 +195,13 @@ static constexpr size_t MAX_POINTERS = 16; */ #define MAX_POINTER_ID 31 +/* + * Number of high resolution scroll units for one detent (scroll wheel click), as defined in + * evdev. This is relevant when an input device is emitting REL_WHEEL_HI_RES or REL_HWHEEL_HI_RES + * events. + */ +constexpr int32_t kEvdevHighResScrollUnitsPerDetent = 120; + /* * Declare a concrete type for the NDK's input event forward declaration. */ @@ -241,6 +251,8 @@ enum class InputEventType { TOUCH_MODE = AINPUT_EVENT_TYPE_TOUCH_MODE, ftl_first = KEY, ftl_last = TOUCH_MODE, + // Used by LatencyTracker fuzzer + kMaxValue = ftl_last }; std::string inputEventSourceToString(int32_t source); @@ -890,9 +902,7 @@ public: void splitFrom(const MotionEvent& other, std::bitset splitPointerIds, int32_t newEventId); - void addSample( - nsecs_t eventTime, - const PointerCoords* pointerCoords); + void addSample(nsecs_t eventTime, const PointerCoords* pointerCoords, int32_t eventId); void offsetLocation(float xOffset, float yOffset); diff --git a/include/input/InputConsumerNoResampling.h b/include/input/InputConsumerNoResampling.h index 9e48b0872dbbc31632e43c04842b2671b66ab57c..c98b9cf8c1f463b6b1a7ae19b3b4c8259f24ace1 100644 --- a/include/input/InputConsumerNoResampling.h +++ b/include/input/InputConsumerNoResampling.h @@ -16,15 +16,21 @@ #pragma once +#include +#include +#include + +#include +#include +#include #include -#include "InputTransport.h" namespace android { /** * An interface to receive batched input events. Even if you don't want batching, you still have to * use this interface, and some of the events will be batched if your implementation is slow to - * handle the incoming input. + * handle the incoming input. The events received by these callbacks are never null. */ class InputConsumerCallbacks { public: @@ -34,7 +40,7 @@ public: /** * When you receive this callback, you must (eventually) call "consumeBatchedInputEvents". * If you don't want batching, then call "consumeBatchedInputEvents" immediately with - * std::nullopt frameTime to receive the pending motion event(s). + * std::nullopt requestedFrameTime to receive the pending motion event(s). * @param pendingBatchSource the source of the pending batch. */ virtual void onBatchedInputEventPending(int32_t pendingBatchSource) = 0; @@ -47,13 +53,13 @@ public: /** * Consumes input events from an input channel. * - * This is a re-implementation of InputConsumer that does not have resampling at the current moment. - * A lot of the higher-level logic has been folded into this class, to make it easier to use. - * In the legacy class, InputConsumer, the consumption logic was partially handled in the jni layer, - * as well as various actions like adding the fd to the Choreographer. + * This is a re-implementation of InputConsumer. At the moment it only supports resampling for + * single pointer events. A lot of the higher-level logic has been folded into this class, to make + * it easier to use. In the legacy class, InputConsumer, the consumption logic was partially handled + * in the jni layer, as well as various actions like adding the fd to the Choreographer. * * TODO(b/297226446): use this instead of "InputConsumer": - * - Add resampling to this class + * - Add resampling for multiple pointer events. * - Allow various resampling strategies to be specified * - Delete the old "InputConsumer" and use this class instead, renaming it to "InputConsumer". * - Add tracing @@ -64,8 +70,18 @@ public: */ class InputConsumerNoResampling final { public: + /** + * @param callbacks are used to interact with InputConsumerNoResampling. They're called whenever + * the event is ready to consume. + * @param looper needs to be sp and not shared_ptr because it inherits from + * RefBase + * @param resampler the resampling strategy to use. If null, no resampling will be + * performed. + */ explicit InputConsumerNoResampling(const std::shared_ptr& channel, - sp looper, InputConsumerCallbacks& callbacks); + sp looper, InputConsumerCallbacks& callbacks, + std::unique_ptr resampler); + ~InputConsumerNoResampling(); /** @@ -74,15 +90,17 @@ public: void finishInputEvent(uint32_t seq, bool handled); void reportTimeline(int32_t inputEventId, nsecs_t gpuCompletedTime, nsecs_t presentTime); /** - * If you want to consume all events immediately (disable batching), the you still must call - * this. For frameTime, use a std::nullopt. - * @param frameTime the time up to which consume the events. When there's double (or triple) - * buffering, you may want to not consume all events currently available, because you could be - * still working on an older frame, but there could already have been events that arrived that - * are more recent. + * If you want to consume all events immediately (disable batching), then you still must call + * this. For requestedFrameTime, use a std::nullopt. It is not guaranteed that the consumption + * will occur at requestedFrameTime. The resampling strategy may modify it. + * @param requestedFrameTime the time up to which consume the events. When there's double (or + * triple) buffering, you may want to not consume all events currently available, because you + * could be still working on an older frame, but there could already have been events that + * arrived that are more recent. * @return whether any events were actually consumed */ - bool consumeBatchedInputEvents(std::optional frameTime); + bool consumeBatchedInputEvents(std::optional requestedFrameTime); + /** * Returns true when there is *likely* a pending batch or a pending event in the channel. * @@ -99,6 +117,7 @@ private: std::shared_ptr mChannel; sp mLooper; InputConsumerCallbacks& mCallbacks; + std::unique_ptr mResampler; // Looper-related infrastructure /** @@ -177,10 +196,33 @@ private: /** * Batched InputMessages, per deviceId. * For each device, we are storing a queue of batched messages. These will all be collapsed into - * a single MotionEvent (up to a specific frameTime) when the consumer calls + * a single MotionEvent (up to a specific requestedFrameTime) when the consumer calls * `consumeBatchedInputEvents`. */ std::map> mBatches; + /** + * Creates a MotionEvent by consuming samples from the provided queue. If one message has + * eventTime > adjustedFrameTime, all subsequent messages in the queue will be skipped. It is + * assumed that messages are queued in chronological order. In other words, only events that + * occurred prior to the adjustedFrameTime will be consumed. + * @param requestedFrameTime the time up to which to consume events. + * @param messages the queue of messages to consume from + */ + std::pair, std::optional> createBatchedMotionEvent( + const nsecs_t requestedFrameTime, std::queue& messages); + + /** + * Consumes the batched input events, optionally allowing the caller to specify a device id + * and/or requestedFrameTime threshold. It is not guaranteed that consumption will occur at + * requestedFrameTime. + * @param deviceId The device id from which to consume events. If std::nullopt, consumes events + * from any device id. + * @param requestedFrameTime The time up to which consume the events. If std::nullopt, consumes + * input events with any timestamp. + * @return Whether or not any events were consumed. + */ + bool consumeBatchedInputEvents(std::optional deviceId, + std::optional requestedFrameTime); /** * A map from a single sequence number to several sequence numbers. This is needed because of * batching. When batching is enabled, a single MotionEvent will contain several samples. Each diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h index 7d8c19e7025166158b50e45c28416c5e8f901e27..1a482396ee89e19e990db86fbe5514ae0084016d 100644 --- a/include/input/InputDevice.h +++ b/include/input/InputDevice.h @@ -389,6 +389,7 @@ enum class InputDeviceConfigurationFileType : int32_t { CONFIGURATION = 0, /* .idc file */ KEY_LAYOUT = 1, /* .kl file */ KEY_CHARACTER_MAP = 2, /* .kcm file */ + ftl_last = KEY_CHARACTER_MAP, }; /* diff --git a/include/input/InputEventBuilders.h b/include/input/InputEventBuilders.h index 25d35e9fe7d8c21f56b0725c6fb16af38f3b7e3d..5bd5070488c5c3baca23b31698fc4232892e9fde 100644 --- a/include/input/InputEventBuilders.h +++ b/include/input/InputEventBuilders.h @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include // for nsecs_t, systemTime #include @@ -44,6 +46,11 @@ public: PointerBuilder& y(float y) { return axis(AMOTION_EVENT_AXIS_Y, y); } + PointerBuilder& isResampled(bool isResampled) { + mCoords.isResampled = isResampled; + return *this; + } + PointerBuilder& axis(int32_t axis, float value) { mCoords.setAxisValue(axis, value); return *this; @@ -58,6 +65,87 @@ private: PointerCoords mCoords; }; +class InputMessageBuilder { +public: + InputMessageBuilder(InputMessage::Type type, uint32_t seq) : mType{type}, mSeq{seq} {} + + InputMessageBuilder& eventId(int32_t eventId) { + mEventId = eventId; + return *this; + } + + InputMessageBuilder& eventTime(nsecs_t eventTime) { + mEventTime = eventTime; + return *this; + } + + InputMessageBuilder& deviceId(DeviceId deviceId) { + mDeviceId = deviceId; + return *this; + } + + InputMessageBuilder& source(int32_t source) { + mSource = source; + return *this; + } + + InputMessageBuilder& displayId(ui::LogicalDisplayId displayId) { + mDisplayId = displayId; + return *this; + } + + InputMessageBuilder& action(int32_t action) { + mAction = action; + return *this; + } + + InputMessageBuilder& downTime(nsecs_t downTime) { + mDownTime = downTime; + return *this; + } + + InputMessageBuilder& pointer(PointerBuilder pointerBuilder) { + mPointers.push_back(pointerBuilder); + return *this; + } + + InputMessage build() const { + InputMessage message{}; + // Header + message.header.type = mType; + message.header.seq = mSeq; + // Body + message.body.motion.eventId = mEventId; + message.body.motion.pointerCount = mPointers.size(); + message.body.motion.eventTime = mEventTime; + message.body.motion.deviceId = mDeviceId; + message.body.motion.source = mSource; + message.body.motion.displayId = mDisplayId.val(); + message.body.motion.action = mAction; + message.body.motion.downTime = mDownTime; + + for (size_t i = 0; i < mPointers.size(); ++i) { + message.body.motion.pointers[i].properties = mPointers[i].buildProperties(); + message.body.motion.pointers[i].coords = mPointers[i].buildCoords(); + } + return message; + } + +private: + const InputMessage::Type mType; + const uint32_t mSeq; + + int32_t mEventId{InputEvent::nextId()}; + nsecs_t mEventTime{systemTime(SYSTEM_TIME_MONOTONIC)}; + DeviceId mDeviceId{DEFAULT_DEVICE_ID}; + int32_t mSource{AINPUT_SOURCE_TOUCHSCREEN}; + ui::LogicalDisplayId mDisplayId{ui::LogicalDisplayId::DEFAULT}; + int32_t mAction{AMOTION_EVENT_ACTION_MOVE}; + nsecs_t mDownTime{mEventTime}; + + std::vector mPointers; +}; + class MotionEventBuilder { public: MotionEventBuilder(int32_t action, int32_t source) { @@ -127,7 +215,7 @@ public: return *this; } - MotionEvent build() { + MotionEvent build() const { std::vector pointerProperties; std::vector pointerCoords; for (const PointerBuilder& pointer : mPointers) { @@ -135,20 +223,22 @@ public: pointerCoords.push_back(pointer.buildCoords()); } + auto [xCursorPosition, yCursorPosition] = + std::make_pair(mRawXCursorPosition, mRawYCursorPosition); // Set mouse cursor position for the most common cases to avoid boilerplate. if (mSource == AINPUT_SOURCE_MOUSE && - !MotionEvent::isValidCursorPosition(mRawXCursorPosition, mRawYCursorPosition)) { - mRawXCursorPosition = pointerCoords[0].getX(); - mRawYCursorPosition = pointerCoords[0].getY(); + !MotionEvent::isValidCursorPosition(xCursorPosition, yCursorPosition)) { + xCursorPosition = pointerCoords[0].getX(); + yCursorPosition = pointerCoords[0].getY(); } MotionEvent event; event.initialize(InputEvent::nextId(), mDeviceId, mSource, mDisplayId, INVALID_HMAC, mAction, mActionButton, mFlags, /*edgeFlags=*/0, AMETA_NONE, mButtonState, MotionClassification::NONE, mTransform, - /*xPrecision=*/0, /*yPrecision=*/0, mRawXCursorPosition, - mRawYCursorPosition, mRawTransform, mDownTime, mEventTime, - mPointers.size(), pointerProperties.data(), pointerCoords.data()); + /*xPrecision=*/0, /*yPrecision=*/0, xCursorPosition, yCursorPosition, + mRawTransform, mDownTime, mEventTime, mPointers.size(), + pointerProperties.data(), pointerCoords.data()); return event; } diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index 6548810ca8ac299c633a3208202c589f363aee58..0cd87201fb5c41a4ef3e77ab9af27e70eeb1965b 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -263,7 +263,7 @@ public: * Return DEAD_OBJECT if the channel's peer has been closed. * Other errors probably indicate that the channel is broken. */ - status_t sendMessage(const InputMessage* msg); + virtual status_t sendMessage(const InputMessage* msg); /* Receive a message sent by the other endpoint. * @@ -275,14 +275,14 @@ public: * Return DEAD_OBJECT if the channel's peer has been closed. * Other errors probably indicate that the channel is broken. */ - status_t receiveMessage(InputMessage* msg); + virtual android::base::Result receiveMessage(); /* Tells whether there is a message in the channel available to be received. * * This is only a performance hint and may return false negative results. Clients should not * rely on availability of the message based on the return value. */ - bool probablyHasInput() const; + virtual bool probablyHasInput() const; /* Wait until there is a message in the channel. * @@ -323,11 +323,12 @@ public: */ sp getConnectionToken() const; +protected: + InputChannel(const std::string name, android::base::unique_fd fd, sp token); + private: static std::unique_ptr create(const std::string& name, android::base::unique_fd fd, sp token); - - InputChannel(const std::string name, android::base::unique_fd fd, sp token); }; /* @@ -363,7 +364,8 @@ public: * Returns OK on success. * Returns WOULD_BLOCK if the channel is full. * Returns DEAD_OBJECT if the channel's peer has been closed. - * Returns BAD_VALUE if seq is 0 or if pointerCount is less than 1 or greater than MAX_POINTERS. + * Returns BAD_VALUE if seq is 0 or if pointerCount is less than 1 or greater than MAX_POINTERS, + * or if the verifier is enabled and the event failed verification upon publishing. * Other errors probably indicate that the channel is broken. */ status_t publishMotionEvent(uint32_t seq, int32_t eventId, int32_t deviceId, int32_t source, diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h index 92d5ec4d4ef4c5b46f5f794ad734f7bbfb72fa82..67b37b12133de472ee1333990a31240a3491a47a 100644 --- a/include/input/KeyCharacterMap.h +++ b/include/input/KeyCharacterMap.h @@ -126,9 +126,9 @@ public: bool getEvents(int32_t deviceId, const char16_t* chars, size_t numChars, Vector& outEvents) const; - /* Maps an Android key code to another Android key code. This mapping is applied after scanCode - * and usageCodes are mapped to corresponding Android Keycode */ - void addKeyRemapping(int32_t fromKeyCode, int32_t toKeyCode); + /* Maps some Android key code to another Android key code. This mapping is applied after + * scanCode and usageCodes are mapped to corresponding Android Keycode */ + void setKeyRemapping(const std::map& keyRemapping); /* Maps a scan code and usage code to a key code, in case this key map overrides * the mapping in some way. */ diff --git a/include/input/MotionPredictor.h b/include/input/MotionPredictor.h index f71503988ff1b4065850dec33418d8b8396489f9..200c301ffebaa4821ad6f3fc1b8b43fc8eb94c3b 100644 --- a/include/input/MotionPredictor.h +++ b/include/input/MotionPredictor.h @@ -43,7 +43,9 @@ static inline bool isMotionPredictionEnabled() { class JerkTracker { public: // Initialize the tracker. If normalizedDt is true, assume that each sample pushed has dt=1. - JerkTracker(bool normalizedDt); + // alpha is the coefficient of the first-order IIR filter for jerk. A factor of 1 results + // in no smoothing. + JerkTracker(bool normalizedDt, float alpha); // Add a position to the tracker and update derivative estimates. void pushSample(int64_t timestamp, float xPos, float yPos); @@ -58,10 +60,13 @@ public: private: const bool mNormalizedDt; + // Coefficient of first-order IIR filter to smooth jerk calculation. + const float mAlpha; RingBuffer mTimestamps{4}; std::array mXDerivatives{}; // [x, x', x'', x'''] std::array mYDerivatives{}; // [y, y', y'', y'''] + float mJerkMagnitude; }; /** @@ -124,15 +129,17 @@ private: std::unique_ptr mBuffers; std::optional mLastEvent; - // mJerkTracker assumes normalized dt = 1 between recorded samples because - // the underlying mModel input also assumes fixed-interval samples. - // Normalized dt as 1 is also used to correspond with the similar Jank - // implementation from the JetPack MotionPredictor implementation. - JerkTracker mJerkTracker{true}; - std::optional mMetricsManager; + std::unique_ptr mJerkTracker; + + std::unique_ptr mMetricsManager; const ReportAtomFunction mReportAtomFunction; + + // Initialize prediction model and associated objects. + // Called during lazy initialization. + // TODO: b/210158587 Consider removing lazy initialization. + void initializeObjects(); }; } // namespace android diff --git a/include/input/OWNERS b/include/input/OWNERS index c88bfe97cab9d6c272648703390956510906d003..21d208f5771068af379d73ace732952294af4439 100644 --- a/include/input/OWNERS +++ b/include/input/OWNERS @@ -1 +1,2 @@ +# Bug component: 136048 include platform/frameworks/base:/INPUT_OWNERS diff --git a/include/input/Resampler.h b/include/input/Resampler.h new file mode 100644 index 0000000000000000000000000000000000000000..dcb25b729f04345a39caa7552db01f895cfffb19 --- /dev/null +++ b/include/input/Resampler.h @@ -0,0 +1,154 @@ +/** + * Copyright 2024 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 +#include +#include + +#include +#include +#include +#include + +namespace android { + +/** + * Resampler is an interface for resampling MotionEvents. Every resampling implementation + * must use this interface to enable resampling inside InputConsumer's logic. + */ +struct Resampler { + virtual ~Resampler() = default; + + /** + * Tries to resample motionEvent at frameTime. The provided frameTime must be greater than + * the latest sample time of motionEvent. It is not guaranteed that resampling occurs at + * frameTime. Interpolation may occur is futureSample is available. Otherwise, motionEvent + * may be resampled by another method, or not resampled at all. Furthermore, it is the + * implementer's responsibility to guarantee the following: + * - If resampling occurs, a single additional sample should be added to motionEvent. That is, + * if motionEvent had N samples before being passed to Resampler, then it will have N + 1 + * samples by the end of the resampling. No other field of motionEvent should be modified. + * - If resampling does not occur, then motionEvent must not be modified in any way. + */ + virtual void resampleMotionEvent(std::chrono::nanoseconds frameTime, MotionEvent& motionEvent, + const InputMessage* futureSample) = 0; + + /** + * Returns resample latency. Resample latency is the time difference between frame time and + * resample time. More precisely, let frameTime and resampleTime be two timestamps, and + * frameTime > resampleTime. Resample latency is defined as frameTime - resampleTime. + */ + virtual std::chrono::nanoseconds getResampleLatency() const = 0; +}; + +class LegacyResampler final : public Resampler { +public: + /** + * Tries to resample `motionEvent` at `frameTime` by adding a resampled sample at the end of + * `motionEvent` with eventTime equal to `resampleTime` and pointer coordinates determined by + * linear interpolation or linear extrapolation. An earlier `resampleTime` will be used if + * extrapolation takes place and `resampleTime` is too far in the future. If `futureSample` is + * not null, interpolation will occur. If `futureSample` is null and there is enough historical + * data, LegacyResampler will extrapolate. Otherwise, no resampling takes place and + * `motionEvent` is unmodified. + */ + void resampleMotionEvent(std::chrono::nanoseconds frameTime, MotionEvent& motionEvent, + const InputMessage* futureSample) override; + + std::chrono::nanoseconds getResampleLatency() const override; + +private: + struct Pointer { + PointerProperties properties; + PointerCoords coords; + }; + + struct Sample { + std::chrono::nanoseconds eventTime; + std::vector pointers; + + std::vector asPointerCoords() const { + std::vector pointersCoords; + for (const Pointer& pointer : pointers) { + pointersCoords.push_back(pointer.coords); + } + return pointersCoords; + } + }; + + /** + * Keeps track of the previous MotionEvent deviceId to enable comparison between the previous + * and the current deviceId. + */ + std::optional mPreviousDeviceId; + + /** + * Up to two latest samples from MotionEvent. Updated every time resampleMotionEvent is called. + * Note: We store up to two samples in order to simplify the implementation. Although, + * calculations are possible with only one previous sample. + */ + RingBuffer mLatestSamples{/*capacity=*/2}; + + /** + * Adds up to mLatestSamples.capacity() of motionEvent's latest samples to mLatestSamples. If + * motionEvent has fewer samples than mLatestSamples.capacity(), then the available samples are + * added to mLatestSamples. + */ + void updateLatestSamples(const MotionEvent& motionEvent); + + static Sample messageToSample(const InputMessage& message); + + /** + * Checks if auxiliary sample has the same pointer properties of target sample. That is, + * auxiliary pointer IDs must appear in the same order as target pointer IDs, their toolType + * must match and be resampleable. + */ + static bool pointerPropertiesResampleable(const Sample& target, const Sample& auxiliary); + + /** + * Checks if there are necessary conditions to interpolate. For example, interpolation cannot + * take place if samples are too far apart in time. mLatestSamples must have at least one sample + * when canInterpolate is invoked. + */ + bool canInterpolate(const InputMessage& futureSample) const; + + /** + * Returns a sample interpolated between the latest sample of mLatestSamples and futureSample, + * if the conditions from canInterpolate are satisfied. Otherwise, returns nullopt. + * mLatestSamples must have at least one sample when attemptInterpolation is called. + */ + std::optional attemptInterpolation(std::chrono::nanoseconds resampleTime, + const InputMessage& futureSample) const; + + /** + * Checks if there are necessary conditions to extrapolate. That is, there are at least two + * samples in mLatestSamples, and delta is bounded within a time interval. + */ + bool canExtrapolate() const; + + /** + * Returns a sample extrapolated from the two samples of mLatestSamples, if the conditions from + * canExtrapolate are satisfied. The returned sample either has eventTime equal to resampleTime, + * or an earlier time if resampleTime is too far in the future. If canExtrapolate returns false, + * this function returns nullopt. + */ + std::optional attemptExtrapolation(std::chrono::nanoseconds resampleTime) const; + + inline static void addSampleToMotionEvent(const Sample& sample, MotionEvent& motionEvent); +}; +} // namespace android diff --git a/include/input/TfLiteMotionPredictor.h b/include/input/TfLiteMotionPredictor.h index 728a8e1e39c4be4c3d9026bda5dfabccc4f7fe48..49e909ea551717c7ce18d122ee0f594217216e08 100644 --- a/include/input/TfLiteMotionPredictor.h +++ b/include/input/TfLiteMotionPredictor.h @@ -110,6 +110,9 @@ public: // High jerk means more predictions will be pruned, vice versa for low. float lowJerk = 0; float highJerk = 0; + + // Coefficient for the first-order IIR filter for jerk calculation. + float jerkAlpha = 1; }; // Creates a model from an encoded Flatbuffer model. diff --git a/include/input/VirtualInputDevice.h b/include/input/VirtualInputDevice.h index 222dac8557392e2859557cc6e7b7533b4341af83..b6c630529c7daf7d273393351f8b3061749157a0 100644 --- a/include/input/VirtualInputDevice.h +++ b/include/input/VirtualInputDevice.h @@ -17,14 +17,30 @@ #pragma once #include +#include +#include namespace android { +enum class DeviceType { + KEYBOARD, + MOUSE, + TOUCHSCREEN, + DPAD, + STYLUS, + ROTARY_ENCODER, +}; + +android::base::unique_fd openUinput(const char* readableName, int32_t vendorId, int32_t productId, + const char* phys, DeviceType deviceType, int32_t screenHeight, + int32_t screenWidth); + enum class UinputAction { RELEASE = 0, PRESS = 1, MOVE = 2, CANCEL = 3, + ftl_last = CANCEL, }; class VirtualInputDevice { @@ -77,6 +93,8 @@ public: private: static const std::map BUTTON_CODE_MAPPING; + int32_t mAccumulatedHighResScrollX; + int32_t mAccumulatedHighResScrollY; }; class VirtualTouchscreen : public VirtualInputDevice { @@ -122,4 +140,14 @@ private: bool handleStylusUp(uint16_t tool, std::chrono::nanoseconds eventTime); }; +class VirtualRotaryEncoder : public VirtualInputDevice { +public: + VirtualRotaryEncoder(android::base::unique_fd fd); + virtual ~VirtualRotaryEncoder() override; + bool writeScrollEvent(float scrollAmount, std::chrono::nanoseconds eventTime); + +private: + int32_t mAccumulatedHighResScrollAmount; +}; + } // namespace android diff --git a/include/private/performance_hint_private.h b/include/private/performance_hint_private.h index 8c356d0140f6969fb2dc029ab37d5af96a178d26..e5eee340cab1c7e99888edf05041f3011c026e4a 100644 --- a/include/private/performance_hint_private.h +++ b/include/private/performance_hint_private.h @@ -108,6 +108,10 @@ APerformanceHintSession* APerformanceHint_createSessionInternal(APerformanceHint const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos, SessionTag tag); +/** + * Forces FMQ to be enabled or disabled, for testing only. + */ +void APerformanceHint_setUseFMQForTesting(bool enabled); __END_DECLS diff --git a/libs/adbd_auth/adbd_auth.cpp b/libs/adbd_auth/adbd_auth.cpp index ebc74fb3d8094f3b0940a2c8ce0cd29ee599c322..d31cb3dff08e8fdfd67108dbfee3bb7d86dba85f 100644 --- a/libs/adbd_auth/adbd_auth.cpp +++ b/libs/adbd_auth/adbd_auth.cpp @@ -365,7 +365,7 @@ public: if (event.events & EPOLLIN) { int rc = TEMP_FAILURE_RETRY(read(framework_fd_.get(), buf, sizeof(buf))); if (rc == -1) { - LOG(FATAL) << "adbd_auth: failed to read from framework fd"; + PLOG(FATAL) << "adbd_auth: failed to read from framework fd"; } else if (rc == 0) { LOG(INFO) << "adbd_auth: hit EOF on framework fd"; std::lock_guard lock(mutex_); @@ -390,13 +390,16 @@ public: } } - static constexpr const char* key_paths[] = {"/adb_keys", "/data/misc/adb/adb_keys"}; + static constexpr std::pair key_paths[] = { + {"/adb_keys", true /* follow symlinks */ }, + {"/data/misc/adb/adb_keys", false /* don't follow symlinks */ }, + }; void IteratePublicKeys(bool (*callback)(void*, const char*, size_t), void* opaque) { - for (const auto& path : key_paths) { + for (const auto& [path, follow_symlinks] : key_paths) { if (access(path, R_OK) == 0) { LOG(INFO) << "adbd_auth: loading keys from " << path; std::string content; - if (!android::base::ReadFileToString(path, &content)) { + if (!android::base::ReadFileToString(path, &content, follow_symlinks)) { PLOG(ERROR) << "adbd_auth: couldn't read " << path; continue; } diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp index 319716ec81eb149041bb336892151c8fdecc3603..cbba7118b66291733bd6f702103722bb35e6495f 100644 --- a/libs/arect/Android.bp +++ b/libs/arect/Android.bp @@ -40,6 +40,7 @@ ndk_headers { cc_library_headers { name: "libarect_headers", + host_supported: true, vendor_available: true, min_sdk_version: "29", // TODO(b/153609531): remove when no longer needed. diff --git a/libs/binder/ActivityManager.cpp b/libs/binder/ActivityManager.cpp index 526427663b0017439f60fac47294965f7ff9b02e..98349c6ab376caf220725f2816f3be2a1f9cd685 100644 --- a/libs/binder/ActivityManager.cpp +++ b/libs/binder/ActivityManager.cpp @@ -23,10 +23,10 @@ #include #include -#include - namespace android { +using namespace std::chrono_literals; + ActivityManager::ActivityManager() { } @@ -43,15 +43,16 @@ sp ActivityManager::getService() } } else { ALOGI("Thread pool not started. Polling for activity service."); - int64_t startTime = 0; + auto startTime = std::chrono::steady_clock::now().min(); while (service == nullptr || !IInterface::asBinder(service)->isBinderAlive()) { sp binder = defaultServiceManager()->checkService(String16("activity")); if (binder == nullptr) { // Wait for the activity service to come back... - if (startTime == 0) { - startTime = uptimeMillis(); + if (startTime == startTime.min()) { + startTime = std::chrono::steady_clock::now(); ALOGI("Waiting for activity service"); - } else if ((uptimeMillis() - startTime) > 1000000) { + } else if (std::chrono::steady_clock::now() - startTime > 1000s) { + // TODO(b/342453147): timeout of 1000s = 16min and 40s doesn't seem intended ALOGW("Waiting too long for activity service, giving up"); service = nullptr; break; diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 7d1535065c1bf234d5b2c26e4f00dc1fcc5ee016..379b609e9fe3f5e66e0fe38ce8398854aea56a13 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -19,6 +19,7 @@ package { // to get the below license kinds: // SPDX-license-identifier-Apache-2.0 default_applicable_licenses: ["frameworks_native_license"], + default_team: "trendy_team_virtualization", } cc_library_headers { @@ -86,16 +87,24 @@ cc_library_headers { cc_cmake_snapshot { name: "binder_sdk", - modules: [ + dist: { + targets: ["binder_sdk"], + dest: "binder_sdk.zip", + }, + + modules_host: [ "libbinder_sdk", "libbinder_sdk_single_threaded", "libbinder_ndk_sdk", + "googletest_cmake", + "binderRpcTestNoKernel", + "binderRpcTestSingleThreadedNoKernel", + "binderRpcWireProtocolTest", ], prebuilts: [ // to enable arm64 host support, build with musl - e.g. on aosp_cf_arm64_phone "aidl", - "libc++", ], include_sources: true, cflags: [ @@ -133,12 +142,16 @@ cc_cmake_snapshot { { android_name: "libgtest", mapped_name: "GTest::gtest", - package_system: "GTest", + package_pregenerated: "external/googletest", }, { android_name: "libgtest_main", - mapped_name: "GTest::gtest", - package_system: "GTest", + mapped_name: "GTest::gtest_main", + package_pregenerated: "external/googletest", + }, + { + android_name: "googletest_cmake", + package_pregenerated: "external/googletest", }, // use libbinder_sdk and friends instead of full Android's libbinder @@ -258,7 +271,20 @@ cc_defaults { "-Wunused-const-variable", "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION", "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION", + // Hide symbols by default and set the BUILDING_LIBBINDER macro so that + // the code knows to export them. + "-fvisibility=hidden", + "-DBUILDING_LIBBINDER", ], + + target: { + vendor: { + // Trimming the exported symbols reveals a bug in vendor code, so + // disable it for the vendor variant for now. http://b/349657329 + // TODO: Fix the issue and remove this override. + cflags: ["-fvisibility=default"], + }, + }, } cc_defaults { @@ -429,12 +455,37 @@ cc_library_shared { ], } +soong_config_module_type { + name: "libbinder_client_cache_config", + module_type: "cc_defaults", + config_namespace: "libbinder", + bool_variables: ["release_libbinder_client_cache"], + properties: [ + "cflags", + ], +} + +libbinder_client_cache_config { + name: "libbinder_client_cache_flag", + soong_config_variables: { + release_libbinder_client_cache: { + cflags: ["-DLIBBINDER_CLIENT_CACHE"], + conditions_default: { + cflags: ["-DNO_LIBBINDER_CLIENT_CACHE"], + }, + }, + }, +} + cc_defaults { name: "libbinder_kernel_defaults", + defaults: ["libbinder_client_cache_flag"], srcs: [ "BufferedTextOutput.cpp", + "BackendUnifiedServiceManager.cpp", "IPCThreadState.cpp", "IServiceManager.cpp", + "IServiceManagerFFI.cpp", "ProcessState.cpp", "Static.cpp", ":libbinder_aidl", @@ -510,7 +561,6 @@ cc_library { "ParcelableHolder.cpp", "PersistableBundle.cpp", ], - target: { android: { // NOT static to keep the wire protocol unfrozen @@ -749,11 +799,41 @@ filegroup { "aidl/android/os/IClientCallback.aidl", "aidl/android/os/IServiceCallback.aidl", "aidl/android/os/IServiceManager.aidl", + "aidl/android/os/Service.aidl", "aidl/android/os/ServiceDebugInfo.aidl", + ":libbinder_accessor_aidl", ], path: "aidl", } +filegroup { + name: "libbinder_accessor_aidl", + srcs: [ + "aidl/android/os/IAccessor.aidl", + ], + path: "aidl", +} + +// TODO(b/353492849): Make this interface private to libbinder. +aidl_interface { + name: "android.os.accessor", + srcs: [":libbinder_accessor_aidl"], + unstable: true, + backend: { + rust: { + enabled: true, + apex_available: [ + "com.android.virt", + ], + }, + }, + visibility: [ + ":__subpackages__", + "//system/tools/aidl:__subpackages__", + "//packages/modules/Virtualization:__subpackages__", + ], +} + aidl_interface { name: "packagemanager_aidl", unstable: true, diff --git a/libs/binder/BackendUnifiedServiceManager.cpp b/libs/binder/BackendUnifiedServiceManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..52b485a6f64b9485a24dce33e905a03476dea39c --- /dev/null +++ b/libs/binder/BackendUnifiedServiceManager.cpp @@ -0,0 +1,337 @@ +/* + * Copyright (C) 2024 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 "BackendUnifiedServiceManager.h" + +#include +#include + +#if defined(__BIONIC__) && !defined(__ANDROID_VNDK__) +#include +#endif + +namespace android { + +#ifdef LIBBINDER_CLIENT_CACHE +constexpr bool kUseCache = true; +#else +constexpr bool kUseCache = false; +#endif + +using AidlServiceManager = android::os::IServiceManager; +using IAccessor = android::os::IAccessor; + +static const char* kStaticCachableList[] = { + // go/keep-sorted start + "accessibility", + "account", + "activity", + "alarm", + "android.system.keystore2.IKeystoreService/default", + "appops", + "audio", + "batterystats", + "carrier_config", + "connectivity", + "content", + "content_capture", + "device_policy", + "display", + "dropbox", + "econtroller", + "graphicsstats", + "input", + "input_method", + "isub", + "jobscheduler", + "legacy_permission", + "location", + "media.extractor", + "media.metrics", + "media.player", + "media.resource_manager", + "media_resource_monitor", + "mount", + "netd_listener", + "netstats", + "network_management", + "nfc", + "notification", + "package", + "package_native", + "performance_hint", + "permission", + "permission_checker", + "permissionmgr", + "phone", + "platform_compat", + "power", + "role", + "sensorservice", + "statscompanion", + "telephony.registry", + "thermalservice", + "time_detector", + "trust", + "uimode", + "user", + "virtualdevice", + "virtualdevice_native", + "webviewupdate", + "window", + // go/keep-sorted end +}; + +bool BinderCacheWithInvalidation::isClientSideCachingEnabled(const std::string& serviceName) { + if (ProcessState::self()->getThreadPoolMaxTotalThreadCount() <= 0) { + ALOGW("Thread Pool max thread count is 0. Cannot cache binder as linkToDeath cannot be " + "implemented. serviceName: %s", + serviceName.c_str()); + return false; + } + for (const char* name : kStaticCachableList) { + if (name == serviceName) { + return true; + } + } + return false; +} + +binder::Status BackendUnifiedServiceManager::updateCache(const std::string& serviceName, + const os::Service& service) { + if (!kUseCache) { + return binder::Status::ok(); + } + if (service.getTag() == os::Service::Tag::binder) { + sp binder = service.get(); + if (binder && mCacheForGetService->isClientSideCachingEnabled(serviceName) && + binder->isBinderAlive()) { + return mCacheForGetService->setItem(serviceName, binder); + } + } + return binder::Status::ok(); +} + +bool BackendUnifiedServiceManager::returnIfCached(const std::string& serviceName, + os::Service* _out) { + if (!kUseCache) { + return false; + } + sp item = mCacheForGetService->getItem(serviceName); + // TODO(b/363177618): Enable caching for binders which are always null. + if (item != nullptr && item->isBinderAlive()) { + *_out = os::Service::make(item); + return true; + } + return false; +} + +BackendUnifiedServiceManager::BackendUnifiedServiceManager(const sp& impl) + : mTheRealServiceManager(impl) { + mCacheForGetService = std::make_shared(); +} + +sp BackendUnifiedServiceManager::getImpl() { + return mTheRealServiceManager; +} + +binder::Status BackendUnifiedServiceManager::getService(const ::std::string& name, + sp* _aidl_return) { + os::Service service; + binder::Status status = getService2(name, &service); + *_aidl_return = service.get(); + return status; +} + +binder::Status BackendUnifiedServiceManager::getService2(const ::std::string& name, + os::Service* _out) { + if (returnIfCached(name, _out)) { + return binder::Status::ok(); + } + os::Service service; + binder::Status status = mTheRealServiceManager->getService2(name, &service); + + if (status.isOk()) { + status = toBinderService(name, service, _out); + if (status.isOk()) { + return updateCache(name, service); + } + } + return status; +} + +binder::Status BackendUnifiedServiceManager::checkService(const ::std::string& name, + os::Service* _out) { + os::Service service; + if (returnIfCached(name, _out)) { + return binder::Status::ok(); + } + + binder::Status status = mTheRealServiceManager->checkService(name, &service); + if (status.isOk()) { + status = toBinderService(name, service, _out); + if (status.isOk()) { + return updateCache(name, service); + } + } + return status; +} + +binder::Status BackendUnifiedServiceManager::toBinderService(const ::std::string& name, + const os::Service& in, + os::Service* _out) { + switch (in.getTag()) { + case os::Service::Tag::binder: { + if (in.get() == nullptr) { + // failed to find a service. Check to see if we have any local + // injected Accessors for this service. + os::Service accessor; + binder::Status status = getInjectedAccessor(name, &accessor); + if (!status.isOk()) { + *_out = os::Service::make(nullptr); + return status; + } + if (accessor.getTag() == os::Service::Tag::accessor && + accessor.get() != nullptr) { + ALOGI("Found local injected service for %s, will attempt to create connection", + name.c_str()); + // Call this again using the accessor Service to get the real + // service's binder into _out + return toBinderService(name, accessor, _out); + } + } + + *_out = in; + return binder::Status::ok(); + } + case os::Service::Tag::accessor: { + sp accessorBinder = in.get(); + sp accessor = interface_cast(accessorBinder); + if (accessor == nullptr) { + ALOGE("Service#accessor doesn't have accessor. VM is maybe starting..."); + *_out = os::Service::make(nullptr); + return binder::Status::ok(); + } + auto request = [=] { + os::ParcelFileDescriptor fd; + binder::Status ret = accessor->addConnection(&fd); + if (ret.isOk()) { + return base::unique_fd(fd.release()); + } else { + ALOGE("Failed to connect to RpcSession: %s", ret.toString8().c_str()); + return base::unique_fd(-1); + } + }; + auto session = RpcSession::make(); + status_t status = session->setupPreconnectedClient(base::unique_fd{}, request); + if (status != OK) { + ALOGE("Failed to set up preconnected binder RPC client: %s", + statusToString(status).c_str()); + return binder::Status::fromStatusT(status); + } + session->setSessionSpecificRoot(accessorBinder); + *_out = os::Service::make(session->getRootObject()); + return binder::Status::ok(); + } + default: { + LOG_ALWAYS_FATAL("Unknown service type: %d", in.getTag()); + } + } +} + +binder::Status BackendUnifiedServiceManager::addService(const ::std::string& name, + const sp& service, + bool allowIsolated, int32_t dumpPriority) { + return mTheRealServiceManager->addService(name, service, allowIsolated, dumpPriority); +} +binder::Status BackendUnifiedServiceManager::listServices( + int32_t dumpPriority, ::std::vector<::std::string>* _aidl_return) { + return mTheRealServiceManager->listServices(dumpPriority, _aidl_return); +} +binder::Status BackendUnifiedServiceManager::registerForNotifications( + const ::std::string& name, const sp& callback) { + return mTheRealServiceManager->registerForNotifications(name, callback); +} +binder::Status BackendUnifiedServiceManager::unregisterForNotifications( + const ::std::string& name, const sp& callback) { + return mTheRealServiceManager->unregisterForNotifications(name, callback); +} +binder::Status BackendUnifiedServiceManager::isDeclared(const ::std::string& name, + bool* _aidl_return) { + return mTheRealServiceManager->isDeclared(name, _aidl_return); +} +binder::Status BackendUnifiedServiceManager::getDeclaredInstances( + const ::std::string& iface, ::std::vector<::std::string>* _aidl_return) { + return mTheRealServiceManager->getDeclaredInstances(iface, _aidl_return); +} +binder::Status BackendUnifiedServiceManager::updatableViaApex( + const ::std::string& name, ::std::optional<::std::string>* _aidl_return) { + return mTheRealServiceManager->updatableViaApex(name, _aidl_return); +} +binder::Status BackendUnifiedServiceManager::getUpdatableNames( + const ::std::string& apexName, ::std::vector<::std::string>* _aidl_return) { + return mTheRealServiceManager->getUpdatableNames(apexName, _aidl_return); +} +binder::Status BackendUnifiedServiceManager::getConnectionInfo( + const ::std::string& name, ::std::optional* _aidl_return) { + return mTheRealServiceManager->getConnectionInfo(name, _aidl_return); +} +binder::Status BackendUnifiedServiceManager::registerClientCallback( + const ::std::string& name, const sp& service, + const sp& callback) { + return mTheRealServiceManager->registerClientCallback(name, service, callback); +} +binder::Status BackendUnifiedServiceManager::tryUnregisterService(const ::std::string& name, + const sp& service) { + return mTheRealServiceManager->tryUnregisterService(name, service); +} +binder::Status BackendUnifiedServiceManager::getServiceDebugInfo( + ::std::vector* _aidl_return) { + return mTheRealServiceManager->getServiceDebugInfo(_aidl_return); +} + +[[clang::no_destroy]] static std::once_flag gUSmOnce; +[[clang::no_destroy]] static sp gUnifiedServiceManager; + +sp getBackendUnifiedServiceManager() { + std::call_once(gUSmOnce, []() { +#if defined(__BIONIC__) && !defined(__ANDROID_VNDK__) + /* wait for service manager */ { + using std::literals::chrono_literals::operator""s; + using android::base::WaitForProperty; + while (!WaitForProperty("servicemanager.ready", "true", 1s)) { + ALOGE("Waited for servicemanager.ready for a second, waiting another..."); + } + } +#endif + + sp sm = nullptr; + while (sm == nullptr) { + sm = interface_cast( + ProcessState::self()->getContextObject(nullptr)); + if (sm == nullptr) { + ALOGE("Waiting 1s on context object on %s.", + ProcessState::self()->getDriverName().c_str()); + sleep(1); + } + } + + gUnifiedServiceManager = sp::make(sm); + }); + + return gUnifiedServiceManager; +} + +} // namespace android diff --git a/libs/binder/BackendUnifiedServiceManager.h b/libs/binder/BackendUnifiedServiceManager.h new file mode 100644 index 0000000000000000000000000000000000000000..47b2ec9f2ceb7029b78875b3f612b37de611150d --- /dev/null +++ b/libs/binder/BackendUnifiedServiceManager.h @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2024 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 +#include +#include +#include +#include + +namespace android { + +class BinderCacheWithInvalidation + : public std::enable_shared_from_this { + class BinderInvalidation : public IBinder::DeathRecipient { + public: + BinderInvalidation(std::weak_ptr cache, const std::string& key) + : mCache(cache), mKey(key) {} + + void binderDied(const wp& who) override { + sp binder = who.promote(); + if (std::shared_ptr cache = mCache.lock()) { + cache->removeItem(mKey, binder); + } else { + ALOGI("Binder Cache pointer expired: %s", mKey.c_str()); + } + } + + private: + std::weak_ptr mCache; + std::string mKey; + }; + struct Entry { + sp service; + sp deathRecipient; + }; + +public: + sp getItem(const std::string& key) const { + std::lock_guard lock(mCacheMutex); + + if (auto it = mCache.find(key); it != mCache.end()) { + return it->second.service; + } + return nullptr; + } + + bool removeItem(const std::string& key, const sp& who) { + std::lock_guard lock(mCacheMutex); + if (auto it = mCache.find(key); it != mCache.end()) { + if (it->second.service == who) { + status_t result = who->unlinkToDeath(it->second.deathRecipient); + if (result != DEAD_OBJECT) { + ALOGW("Unlinking to dead binder resulted in: %d", result); + } + mCache.erase(key); + return true; + } + } + return false; + } + + binder::Status setItem(const std::string& key, const sp& item) { + sp deathRecipient = + sp::make(shared_from_this(), key); + + // linkToDeath if binder is a remote binder. + if (item->localBinder() == nullptr) { + status_t status = item->linkToDeath(deathRecipient); + if (status != android::OK) { + ALOGE("Failed to linkToDeath binder for service %s. Error: %d", key.c_str(), + status); + return binder::Status::fromStatusT(status); + } + } + std::lock_guard lock(mCacheMutex); + Entry entry = {.service = item, .deathRecipient = deathRecipient}; + mCache[key] = entry; + return binder::Status::ok(); + } + + bool isClientSideCachingEnabled(const std::string& serviceName); + +private: + std::map mCache; + mutable std::mutex mCacheMutex; +}; + +class BackendUnifiedServiceManager : public android::os::BnServiceManager { +public: + explicit BackendUnifiedServiceManager(const sp& impl); + + sp getImpl(); + binder::Status getService(const ::std::string& name, sp* _aidl_return) override; + binder::Status getService2(const ::std::string& name, os::Service* out) override; + binder::Status checkService(const ::std::string& name, os::Service* out) override; + binder::Status addService(const ::std::string& name, const sp& service, + bool allowIsolated, int32_t dumpPriority) override; + binder::Status listServices(int32_t dumpPriority, + ::std::vector<::std::string>* _aidl_return) override; + binder::Status registerForNotifications(const ::std::string& name, + const sp& callback) override; + binder::Status unregisterForNotifications(const ::std::string& name, + const sp& callback) override; + binder::Status isDeclared(const ::std::string& name, bool* _aidl_return) override; + binder::Status getDeclaredInstances(const ::std::string& iface, + ::std::vector<::std::string>* _aidl_return) override; + binder::Status updatableViaApex(const ::std::string& name, + ::std::optional<::std::string>* _aidl_return) override; + binder::Status getUpdatableNames(const ::std::string& apexName, + ::std::vector<::std::string>* _aidl_return) override; + binder::Status getConnectionInfo(const ::std::string& name, + ::std::optional* _aidl_return) override; + binder::Status registerClientCallback(const ::std::string& name, const sp& service, + const sp& callback) override; + binder::Status tryUnregisterService(const ::std::string& name, + const sp& service) override; + binder::Status getServiceDebugInfo(::std::vector* _aidl_return) override; + + // for legacy ABI + const String16& getInterfaceDescriptor() const override { + return mTheRealServiceManager->getInterfaceDescriptor(); + } + +private: + std::shared_ptr mCacheForGetService; + sp mTheRealServiceManager; + binder::Status toBinderService(const ::std::string& name, const os::Service& in, + os::Service* _out); + binder::Status updateCache(const std::string& serviceName, const os::Service& service); + bool returnIfCached(const std::string& serviceName, os::Service* _out); +}; + +sp getBackendUnifiedServiceManager(); + +android::binder::Status getInjectedAccessor(const std::string& name, android::os::Service* service); + +} // namespace android diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp index c57c9cdd62d734265661aec87eb662bdc544722c..53bd08d42004fa63e6964ebeb4bcf6fe2ebc6229 100644 --- a/libs/binder/Binder.cpp +++ b/libs/binder/Binder.cpp @@ -143,6 +143,22 @@ status_t IBinder::getExtension(sp* out) { return reply.readNullableStrongBinder(out); } +status_t IBinder::addFrozenStateChangeCallback(const wp& callback) { + BpBinder* proxy = this->remoteBinder(); + if (proxy != nullptr) { + return proxy->addFrozenStateChangeCallback(callback); + } + return INVALID_OPERATION; +} + +status_t IBinder::removeFrozenStateChangeCallback(const wp& callback) { + BpBinder* proxy = this->remoteBinder(); + if (proxy != nullptr) { + return proxy->removeFrozenStateChangeCallback(callback); + } + return INVALID_OPERATION; +} + status_t IBinder::getDebugPid(pid_t* out) { BBinder* local = this->localBinder(); if (local != nullptr) { diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp index 6594aa63090f12a68584acde8e0d149b81de2309..eae844ca03f3ef30748d61b153f82fe1f58d9ca3 100644 --- a/libs/binder/BpBinder.cpp +++ b/libs/binder/BpBinder.cpp @@ -160,11 +160,12 @@ void BpBinder::ObjectManager::kill() // --------------------------------------------------------------------------- -sp BpBinder::create(int32_t handle) { +sp BpBinder::create(int32_t handle, std::function* postTask) { if constexpr (!kEnableKernelIpc) { LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time"); return nullptr; } + LOG_ALWAYS_FATAL_IF(postTask == nullptr, "BAD STATE"); int32_t trackedUid = -1; if (sCountByUidEnabled) { @@ -183,7 +184,11 @@ sp BpBinder::create(int32_t handle) { ALOGE("Still too many binder proxy objects sent to uid %d from uid %d (%d proxies " "held)", getuid(), trackedUid, trackedValue); - if (sLimitCallback) sLimitCallback(trackedUid); + + if (sLimitCallback) { + *postTask = [=]() { sLimitCallback(trackedUid); }; + } + sLastLimitCallbackMap[trackedUid] = trackedValue; } } else { @@ -197,7 +202,11 @@ sp BpBinder::create(int32_t handle) { ALOGE("Too many binder proxy objects sent to uid %d from uid %d (%d proxies held)", getuid(), trackedUid, trackedValue); sTrackingMap[trackedUid] |= LIMIT_REACHED_MASK; - if (sLimitCallback) sLimitCallback(trackedUid); + + if (sLimitCallback) { + *postTask = [=]() { sLimitCallback(trackedUid); }; + } + sLastLimitCallbackMap[trackedUid] = trackedValue & COUNTING_VALUE_MASK; if (sBinderProxyThrottleCreate) { ALOGI("Throttling binder proxy creates from uid %d in uid %d until binder proxy" @@ -557,6 +566,123 @@ void BpBinder::sendObituary() } } +status_t BpBinder::addFrozenStateChangeCallback(const wp& callback) { + LOG_ALWAYS_FATAL_IF(isRpcBinder(), + "addFrozenStateChangeCallback() is not supported for RPC Binder."); + LOG_ALWAYS_FATAL_IF(!kEnableKernelIpc, "Binder kernel driver disabled at build time"); + LOG_ALWAYS_FATAL_IF(ProcessState::self()->getThreadPoolMaxTotalThreadCount() == 0, + "addFrozenStateChangeCallback on %s but there are no threads " + "(yet?) listening to incoming transactions. See " + "ProcessState::startThreadPool " + "and ProcessState::setThreadPoolMaxThreadCount. Generally you should " + "setup the binder threadpool before other initialization steps.", + String8(getInterfaceDescriptor()).c_str()); + LOG_ALWAYS_FATAL_IF(callback == nullptr, + "addFrozenStateChangeCallback(): callback must be non-NULL"); + + const sp strongCallback = callback.promote(); + if (strongCallback == nullptr) { + return BAD_VALUE; + } + + { + RpcMutexUniqueLock _l(mLock); + if (!mFrozen) { + ALOGV("Requesting freeze notification: %p handle %d\n", this, binderHandle()); + IPCThreadState* self = IPCThreadState::self(); + status_t status = self->addFrozenStateChangeCallback(binderHandle(), this); + if (status != NO_ERROR) { + // Avoids logspam if kernel does not support freeze + // notification. + if (status != INVALID_OPERATION) { + ALOGE("IPCThreadState.addFrozenStateChangeCallback " + "failed with %s. %p handle %d\n", + statusToString(status).c_str(), this, binderHandle()); + } + return status; + } + mFrozen = std::make_unique(); + if (!mFrozen) { + std::ignore = + IPCThreadState::self()->removeFrozenStateChangeCallback(binderHandle(), + this); + return NO_MEMORY; + } + } + if (mFrozen->initialStateReceived) { + strongCallback->onStateChanged(wp::fromExisting(this), + mFrozen->isFrozen + ? FrozenStateChangeCallback::State::FROZEN + : FrozenStateChangeCallback::State::UNFROZEN); + } + ssize_t res = mFrozen->callbacks.add(callback); + if (res < 0) { + return res; + } + return NO_ERROR; + } +} + +status_t BpBinder::removeFrozenStateChangeCallback(const wp& callback) { + LOG_ALWAYS_FATAL_IF(isRpcBinder(), + "removeFrozenStateChangeCallback() is not supported for RPC Binder."); + LOG_ALWAYS_FATAL_IF(!kEnableKernelIpc, "Binder kernel driver disabled at build time"); + + RpcMutexUniqueLock _l(mLock); + + const size_t N = mFrozen ? mFrozen->callbacks.size() : 0; + for (size_t i = 0; i < N; i++) { + if (mFrozen->callbacks.itemAt(i) == callback) { + mFrozen->callbacks.removeAt(i); + if (mFrozen->callbacks.size() == 0) { + ALOGV("Clearing freeze notification: %p handle %d\n", this, binderHandle()); + status_t status = + IPCThreadState::self()->removeFrozenStateChangeCallback(binderHandle(), + this); + if (status != NO_ERROR) { + ALOGE("Unexpected error from " + "IPCThreadState.removeFrozenStateChangeCallback: %s. " + "%p handle %d\n", + statusToString(status).c_str(), this, binderHandle()); + } + mFrozen.reset(); + } + return NO_ERROR; + } + } + + return NAME_NOT_FOUND; +} + +void BpBinder::onFrozenStateChanged(bool isFrozen) { + LOG_ALWAYS_FATAL_IF(isRpcBinder(), "onFrozenStateChanged is not supported for RPC Binder."); + LOG_ALWAYS_FATAL_IF(!kEnableKernelIpc, "Binder kernel driver disabled at build time"); + + ALOGV("Sending frozen state change notification for proxy %p handle %d, isFrozen=%s\n", this, + binderHandle(), isFrozen ? "true" : "false"); + + RpcMutexUniqueLock _l(mLock); + if (!mFrozen) { + return; + } + bool stateChanged = !mFrozen->initialStateReceived || mFrozen->isFrozen != isFrozen; + if (stateChanged) { + mFrozen->isFrozen = isFrozen; + mFrozen->initialStateReceived = true; + for (size_t i = 0; i < mFrozen->callbacks.size();) { + sp callback = mFrozen->callbacks.itemAt(i).promote(); + if (callback != nullptr) { + callback->onStateChanged(wp::fromExisting(this), + isFrozen ? FrozenStateChangeCallback::State::FROZEN + : FrozenStateChangeCallback::State::UNFROZEN); + i++; + } else { + mFrozen->callbacks.removeItemsAt(i); + } + } + } +} + void BpBinder::reportOneDeath(const Obituary& obit) { sp recipient = obit.recipient.promote(); @@ -686,6 +812,10 @@ void BpBinder::onLastStrongRef(const void* /*id*/) { if (ipc) ipc->clearDeathNotification(binderHandle(), this); mObituaries = nullptr; } + if (mFrozen != nullptr) { + std::ignore = IPCThreadState::self()->removeFrozenStateChangeCallback(binderHandle(), this); + mFrozen.reset(); + } mLock.unlock(); if (obits != nullptr) { diff --git a/libs/binder/FdTrigger.cpp b/libs/binder/FdTrigger.cpp index 455a4338e5b892c4c1bfb04a4fdb86976e1a0ef2..7263e236fc9282003545a4f83daadaa47eb9fa44 100644 --- a/libs/binder/FdTrigger.cpp +++ b/libs/binder/FdTrigger.cpp @@ -82,7 +82,9 @@ status_t FdTrigger::triggerablePoll(const android::RpcTransportFd& transportFd, int ret = TEMP_FAILURE_RETRY(poll(pfd, countof(pfd), -1)); if (ret < 0) { - return -errno; + int saved_errno = errno; + ALOGE("FdTrigger poll returned error: %d, with error: %s", ret, strerror(saved_errno)); + return -saved_errno; } LOG_ALWAYS_FATAL_IF(ret == 0, "poll(%d) returns 0 with infinite timeout", transportFd.fd.get()); @@ -106,6 +108,7 @@ status_t FdTrigger::triggerablePoll(const android::RpcTransportFd& transportFd, // POLLNVAL: invalid FD number, e.g. not opened. if (pfd[0].revents & POLLNVAL) { + LOG_ALWAYS_FATAL("Invalid FD number (%d) in FdTrigger (POLLNVAL)", pfd[0].fd); return BAD_VALUE; } diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index fbc812571a276a1e8b22a8d9ca4be27837ab8da8..6698d0c0cd1a446b5461252b14ac8189781b523e 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -22,10 +22,7 @@ #include #include -#include #include -#include -#include #include #include @@ -38,6 +35,7 @@ #include #include +#include "Utils.h" #include "binder_module.h" #if LOG_NDEBUG @@ -65,6 +63,8 @@ namespace android { +using namespace std::chrono_literals; + // Static const and functions will be optimized out if not used, // when LOG_NDEBUG and references in IF_LOG_COMMANDS() are optimized out. static const char* kReturnStrings[] = { @@ -89,26 +89,33 @@ static const char* kReturnStrings[] = { "BR_FROZEN_REPLY", "BR_ONEWAY_SPAM_SUSPECT", "BR_TRANSACTION_PENDING_FROZEN", + "BR_FROZEN_BINDER", + "BR_CLEAR_FREEZE_NOTIFICATION_DONE", }; -static const char *kCommandStrings[] = { - "BC_TRANSACTION", - "BC_REPLY", - "BC_ACQUIRE_RESULT", - "BC_FREE_BUFFER", - "BC_INCREFS", - "BC_ACQUIRE", - "BC_RELEASE", - "BC_DECREFS", - "BC_INCREFS_DONE", - "BC_ACQUIRE_DONE", - "BC_ATTEMPT_ACQUIRE", - "BC_REGISTER_LOOPER", - "BC_ENTER_LOOPER", - "BC_EXIT_LOOPER", - "BC_REQUEST_DEATH_NOTIFICATION", - "BC_CLEAR_DEATH_NOTIFICATION", - "BC_DEAD_BINDER_DONE" +static const char* kCommandStrings[] = { + "BC_TRANSACTION", + "BC_REPLY", + "BC_ACQUIRE_RESULT", + "BC_FREE_BUFFER", + "BC_INCREFS", + "BC_ACQUIRE", + "BC_RELEASE", + "BC_DECREFS", + "BC_INCREFS_DONE", + "BC_ACQUIRE_DONE", + "BC_ATTEMPT_ACQUIRE", + "BC_REGISTER_LOOPER", + "BC_ENTER_LOOPER", + "BC_EXIT_LOOPER", + "BC_REQUEST_DEATH_NOTIFICATION", + "BC_CLEAR_DEATH_NOTIFICATION", + "BC_DEAD_BINDER_DONE", + "BC_TRANSACTION_SG", + "BC_REPLY_SG", + "BC_REQUEST_FREEZE_NOTIFICATION", + "BC_CLEAR_FREEZE_NOTIFICATION", + "BC_FREEZE_NOTIFICATION_DONE", }; static const int64_t kWorkSourcePropagatedBitIndex = 32; @@ -203,6 +210,18 @@ static const void* printReturnCommand(std::ostream& out, const void* _cmd) { out << ": death cookie " << (void*)(uint64_t)c; } break; + case BR_FROZEN_BINDER: { + const int32_t c = *cmd++; + const int32_t h = *cmd++; + const int32_t isFrozen = *cmd++; + out << ": freeze cookie " << (void*)(uint64_t)c << " isFrozen: " << isFrozen; + } break; + + case BR_CLEAR_FREEZE_NOTIFICATION_DONE: { + const int32_t c = *cmd++; + out << ": freeze cookie " << (void*)(uint64_t)c; + } break; + default: // no details to show for: BR_OK, BR_DEAD_REPLY, // BR_TRANSACTION_COMPLETE, BR_FINISHED @@ -213,6 +232,15 @@ static const void* printReturnCommand(std::ostream& out, const void* _cmd) { return cmd; } +static void printReturnCommandParcel(std::ostream& out, const Parcel& parcel) { + const void* cmds = parcel.data(); + out << "\t" << HexDump(cmds, parcel.dataSize()) << "\n"; + IF_LOG_COMMANDS() { + const void* end = parcel.data() + parcel.dataSize(); + while (cmds < end) cmds = printReturnCommand(out, cmds); + } +} + static const void* printCommand(std::ostream& out, const void* _cmd) { static const size_t N = sizeof(kCommandStrings)/sizeof(kCommandStrings[0]); const int32_t* cmd = (const int32_t*)_cmd; @@ -270,11 +298,23 @@ static const void* printCommand(std::ostream& out, const void* _cmd) { out << ": handle=" << h << " (death cookie " << (void*)(uint64_t)c << ")"; } break; + case BC_REQUEST_FREEZE_NOTIFICATION: + case BC_CLEAR_FREEZE_NOTIFICATION: { + const int32_t h = *cmd++; + const int32_t c = *cmd++; + out << ": handle=" << h << " (freeze cookie " << (void*)(uint64_t)c << ")"; + } break; + case BC_DEAD_BINDER_DONE: { const int32_t c = *cmd++; out << ": death cookie " << (void*)(uint64_t)c; } break; + case BC_FREEZE_NOTIFICATION_DONE: { + const int32_t c = *cmd++; + out << ": freeze cookie " << (void*)(uint64_t)c; + } break; + default: // no details to show for: BC_REGISTER_LOOPER, BC_ENTER_LOOPER, // BC_EXIT_LOOPER @@ -285,7 +325,9 @@ static const void* printCommand(std::ostream& out, const void* _cmd) { return cmd; } +LIBBINDER_IGNORE("-Wzero-as-null-pointer-constant") static pthread_mutex_t gTLSMutex = PTHREAD_MUTEX_INITIALIZER; +LIBBINDER_IGNORE_END() static std::atomic gHaveTLS(false); static pthread_key_t gTLS = 0; static std::atomic gShutdown = false; @@ -613,16 +655,19 @@ bool IPCThreadState::flushIfNeeded() void IPCThreadState::blockUntilThreadAvailable() { - pthread_mutex_lock(&mProcess->mThreadCountLock); - mProcess->mWaitingForThreads++; - while (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads) { - ALOGW("Waiting for thread to be free. mExecutingThreadsCount=%lu mMaxThreads=%lu\n", - static_cast(mProcess->mExecutingThreadsCount), - static_cast(mProcess->mMaxThreads)); - pthread_cond_wait(&mProcess->mThreadCountDecrement, &mProcess->mThreadCountLock); - } - mProcess->mWaitingForThreads--; - pthread_mutex_unlock(&mProcess->mThreadCountLock); + std::unique_lock lock_guard_(mProcess->mOnThreadAvailableLock); + mProcess->mOnThreadAvailableWaiting++; + mProcess->mOnThreadAvailableCondVar.wait(lock_guard_, [&] { + size_t max = mProcess->mMaxThreads; + size_t cur = mProcess->mExecutingThreadsCount; + if (cur < max) { + return true; + } + ALOGW("Waiting for thread to be free. mExecutingThreadsCount=%zu mMaxThreads=%zu\n", cur, + max); + return false; + }); + mProcess->mOnThreadAvailableWaiting--; } status_t IPCThreadState::getAndExecuteCommand() @@ -642,34 +687,35 @@ status_t IPCThreadState::getAndExecuteCommand() ALOGI("%s", message.c_str()); } - pthread_mutex_lock(&mProcess->mThreadCountLock); - mProcess->mExecutingThreadsCount++; - if (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads && - mProcess->mStarvationStartTimeMs == 0) { - mProcess->mStarvationStartTimeMs = uptimeMillis(); + size_t newThreadsCount = mProcess->mExecutingThreadsCount.fetch_add(1) + 1; + if (newThreadsCount >= mProcess->mMaxThreads) { + auto expected = ProcessState::never(); + mProcess->mStarvationStartTime + .compare_exchange_strong(expected, std::chrono::steady_clock::now()); } - pthread_mutex_unlock(&mProcess->mThreadCountLock); result = executeCommand(cmd); - pthread_mutex_lock(&mProcess->mThreadCountLock); - mProcess->mExecutingThreadsCount--; - if (mProcess->mExecutingThreadsCount < mProcess->mMaxThreads && - mProcess->mStarvationStartTimeMs != 0) { - int64_t starvationTimeMs = uptimeMillis() - mProcess->mStarvationStartTimeMs; - if (starvationTimeMs > 100) { - ALOGE("binder thread pool (%zu threads) starved for %" PRId64 " ms", - mProcess->mMaxThreads, starvationTimeMs); + size_t maxThreads = mProcess->mMaxThreads; + newThreadsCount = mProcess->mExecutingThreadsCount.fetch_sub(1) - 1; + if (newThreadsCount < maxThreads) { + auto starvationStartTime = + mProcess->mStarvationStartTime.exchange(ProcessState::never()); + if (starvationStartTime != ProcessState::never()) { + auto starvationTime = std::chrono::steady_clock::now() - starvationStartTime; + if (starvationTime > 100ms) { + ALOGE("binder thread pool (%zu threads) starved for %" PRId64 " ms", maxThreads, + to_ms(starvationTime)); + } } - mProcess->mStarvationStartTimeMs = 0; } // Cond broadcast can be expensive, so don't send it every time a binder // call is processed. b/168806193 - if (mProcess->mWaitingForThreads > 0) { - pthread_cond_broadcast(&mProcess->mThreadCountDecrement); + if (mProcess->mOnThreadAvailableWaiting > 0) { + std::lock_guard lock_guard_(mProcess->mOnThreadAvailableLock); + mProcess->mOnThreadAvailableCondVar.notify_all(); } - pthread_mutex_unlock(&mProcess->mThreadCountLock); } return result; @@ -727,10 +773,9 @@ void IPCThreadState::processPostWriteDerefs() void IPCThreadState::joinThreadPool(bool isMain) { - LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid()); - pthread_mutex_lock(&mProcess->mThreadCountLock); + LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), + getpid()); mProcess->mCurrentThreads++; - pthread_mutex_unlock(&mProcess->mThreadCountLock); mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER); mIsLooper = true; @@ -758,13 +803,11 @@ void IPCThreadState::joinThreadPool(bool isMain) mOut.writeInt32(BC_EXIT_LOOPER); mIsLooper = false; talkWithDriver(false); - pthread_mutex_lock(&mProcess->mThreadCountLock); - LOG_ALWAYS_FATAL_IF(mProcess->mCurrentThreads == 0, - "Threadpool thread count = 0. Thread cannot exist and exit in empty " - "threadpool\n" + size_t oldCount = mProcess->mCurrentThreads.fetch_sub(1); + LOG_ALWAYS_FATAL_IF(oldCount == 0, + "Threadpool thread count underflowed. Thread cannot exist and exit in " + "empty threadpool\n" "Misconfiguration. Increase threadpool max threads configuration\n"); - mProcess->mCurrentThreads--; - pthread_mutex_unlock(&mProcess->mThreadCountLock); } status_t IPCThreadState::setupPolling(int* fd) @@ -776,9 +819,7 @@ status_t IPCThreadState::setupPolling(int* fd) mOut.writeInt32(BC_ENTER_LOOPER); flushCommands(); *fd = mProcess->mDriverFD; - pthread_mutex_lock(&mProcess->mThreadCountLock); mProcess->mCurrentThreads++; - pthread_mutex_unlock(&mProcess->mThreadCountLock); return 0; } @@ -952,6 +993,33 @@ status_t IPCThreadState::clearDeathNotification(int32_t handle, BpBinder* proxy) return NO_ERROR; } +status_t IPCThreadState::addFrozenStateChangeCallback(int32_t handle, BpBinder* proxy) { + static bool isSupported = + ProcessState::isDriverFeatureEnabled(ProcessState::DriverFeature::FREEZE_NOTIFICATION); + if (!isSupported) { + return INVALID_OPERATION; + } + proxy->getWeakRefs()->incWeak(proxy); + mOut.writeInt32(BC_REQUEST_FREEZE_NOTIFICATION); + mOut.writeInt32((int32_t)handle); + mOut.writePointer((uintptr_t)proxy); + flushCommands(); + return NO_ERROR; +} + +status_t IPCThreadState::removeFrozenStateChangeCallback(int32_t handle, BpBinder* proxy) { + static bool isSupported = + ProcessState::isDriverFeatureEnabled(ProcessState::DriverFeature::FREEZE_NOTIFICATION); + if (!isSupported) { + return INVALID_OPERATION; + } + mOut.writeInt32(BC_CLEAR_FREEZE_NOTIFICATION); + mOut.writeInt32((int32_t)handle); + mOut.writePointer((uintptr_t)proxy); + flushCommands(); + return NO_ERROR; +} + IPCThreadState::IPCThreadState() : mProcess(ProcessState::self()), mServingStackPointer(nullptr), @@ -1176,13 +1244,15 @@ status_t IPCThreadState::talkWithDriver(bool doReceive) if (err >= NO_ERROR) { if (bwr.write_consumed > 0) { - if (bwr.write_consumed < mOut.dataSize()) + if (bwr.write_consumed < mOut.dataSize()) { + std::ostringstream logStream; + printReturnCommandParcel(logStream, mIn); LOG_ALWAYS_FATAL("Driver did not consume write buffer. " - "err: %s consumed: %zu of %zu", - statusToString(err).c_str(), - (size_t)bwr.write_consumed, - mOut.dataSize()); - else { + "err: %s consumed: %zu of %zu.\n" + "Return command: %s", + statusToString(err).c_str(), (size_t)bwr.write_consumed, + mOut.dataSize(), logStream.str().c_str()); + } else { mOut.setDataSize(0); processPostWriteDerefs(); } @@ -1193,14 +1263,8 @@ status_t IPCThreadState::talkWithDriver(bool doReceive) } IF_LOG_COMMANDS() { std::ostringstream logStream; - logStream << "Remaining data size: " << mOut.dataSize() << "\n"; - logStream << "Received commands from driver: "; - const void* cmds = mIn.data(); - const void* end = mIn.data() + mIn.dataSize(); - logStream << "\t" << HexDump(cmds, mIn.dataSize()) << "\n"; - while (cmds < end) cmds = printReturnCommand(logStream, cmds); - std::string message = logStream.str(); - ALOGI("%s", message.c_str()); + printReturnCommandParcel(logStream, mIn); + ALOGI("%s", logStream.str().c_str()); } return NO_ERROR; } @@ -1486,6 +1550,26 @@ status_t IPCThreadState::executeCommand(int32_t cmd) proxy->getWeakRefs()->decWeak(proxy); } break; + case BR_FROZEN_BINDER: { + const struct binder_frozen_state_info* data = + reinterpret_cast( + mIn.readInplace(sizeof(struct binder_frozen_state_info))); + if (data == nullptr) { + result = UNKNOWN_ERROR; + break; + } + BpBinder* proxy = (BpBinder*)data->cookie; + bool isFrozen = mIn.readInt32() > 0; + proxy->getPrivateAccessor().onFrozenStateChanged(data->is_frozen); + mOut.writeInt32(BC_FREEZE_NOTIFICATION_DONE); + mOut.writePointer(data->cookie); + } break; + + case BR_CLEAR_FREEZE_NOTIFICATION_DONE: { + BpBinder* proxy = (BpBinder*)mIn.readPointer(); + proxy->getWeakRefs()->decWeak(proxy); + } break; + case BR_FINISHED: result = TIMED_OUT; break; diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp index fbcf823045c8c60b3210a7642f20b59e70f4dbaf..88761d772f54968413fb931befc4a99b6fcfa10b 100644 --- a/libs/binder/IServiceManager.cpp +++ b/libs/binder/IServiceManager.cpp @@ -14,23 +14,31 @@ * limitations under the License. */ +#include #define LOG_TAG "ServiceManagerCppClient" #include +#include +#include "BackendUnifiedServiceManager.h" #include #include +#include #include +#include +#include #include +#include #include +#include +#include #include #include #include -#include +#include #include -#include - +#include #ifndef __ANDROID_VNDK__ #include #endif @@ -47,13 +55,18 @@ #endif #include "Static.h" +#include "Utils.h" namespace android { +using namespace std::chrono_literals; + using AidlRegistrationCallback = IServiceManager::LocalRegistrationCallback; using AidlServiceManager = android::os::IServiceManager; using android::binder::Status; +using android::os::IAccessor; +using android::os::Service; // libbinder's IServiceManager.h can't rely on the values generated by AIDL // because many places use its headers via include_dirs (meaning, without @@ -73,10 +86,9 @@ IServiceManager::IServiceManager() {} IServiceManager::~IServiceManager() {} // From the old libbinder IServiceManager interface to IServiceManager. -class ServiceManagerShim : public IServiceManager -{ +class CppBackendShim : public IServiceManager { public: - explicit ServiceManagerShim (const sp& impl); + explicit CppBackendShim(const sp& impl); sp getService(const String16& name) const override; sp checkService(const String16& name) const override; @@ -111,14 +123,12 @@ public: std::vector getServiceDebugInfo() override; // for legacy ABI const String16& getInterfaceDescriptor() const override { - return mTheRealServiceManager->getInterfaceDescriptor(); - } - IBinder* onAsBinder() override { - return IInterface::asBinder(mTheRealServiceManager).get(); + return mUnifiedServiceManager->getInterfaceDescriptor(); } + IBinder* onAsBinder() override { return IInterface::asBinder(mUnifiedServiceManager).get(); } protected: - sp mTheRealServiceManager; + sp mUnifiedServiceManager; // AidlRegistrationCallback -> services that its been registered for // notifications. using LocalRegistrationAndWaiter = @@ -132,42 +142,160 @@ protected: sp* waiter); // Directly get the service in a way that, for lazy services, requests the service to be started - // if it is not currently started. This way, calls directly to ServiceManagerShim::getService + // if it is not currently started. This way, calls directly to CppBackendShim::getService // will still have the 5s delay that is expected by a large amount of Android code. // - // When implementing ServiceManagerShim, use realGetService instead of - // mTheRealServiceManager->getService so that it can be overridden in ServiceManagerHostShim. + // When implementing CppBackendShim, use realGetService instead of + // mUnifiedServiceManager->getService so that it can be overridden in CppServiceManagerHostShim. virtual Status realGetService(const std::string& name, sp* _aidl_return) { - return mTheRealServiceManager->getService(name, _aidl_return); + Service service; + Status status = mUnifiedServiceManager->getService2(name, &service); + *_aidl_return = service.get(); + return status; } }; +class AccessorProvider { +public: + AccessorProvider(RpcAccessorProvider&& provider) : mProvider(std::move(provider)) {} + sp provide(const String16& name) { return mProvider(name); } + +private: + AccessorProvider() = delete; + + RpcAccessorProvider mProvider; +}; + +class AccessorProviderEntry { +public: + AccessorProviderEntry(std::shared_ptr&& provider) + : mProvider(std::move(provider)) {} + std::shared_ptr mProvider; + +private: + AccessorProviderEntry() = delete; +}; + [[clang::no_destroy]] static std::once_flag gSmOnce; [[clang::no_destroy]] static sp gDefaultServiceManager; +[[clang::no_destroy]] static std::mutex gAccessorProvidersMutex; +[[clang::no_destroy]] static std::vector gAccessorProviders; -sp defaultServiceManager() -{ - std::call_once(gSmOnce, []() { -#if defined(__BIONIC__) && !defined(__ANDROID_VNDK__) - /* wait for service manager */ { - using std::literals::chrono_literals::operator""s; - using android::base::WaitForProperty; - while (!WaitForProperty("servicemanager.ready", "true", 1s)) { - ALOGE("Waited for servicemanager.ready for a second, waiting another..."); +class LocalAccessor : public android::os::BnAccessor { +public: + LocalAccessor(const String16& instance, RpcSocketAddressProvider&& connectionInfoProvider) + : mInstance(instance), mConnectionInfoProvider(std::move(connectionInfoProvider)) { + LOG_ALWAYS_FATAL_IF(!mConnectionInfoProvider, + "LocalAccessor object needs a valid connection info provider"); + } + + ~LocalAccessor() { + if (mOnDelete) mOnDelete(); + } + + ::android::binder::Status addConnection(::android::os::ParcelFileDescriptor* outFd) { + using android::os::IAccessor; + sockaddr_storage addrStorage; + std::unique_ptr trigger = FdTrigger::make(); + RpcTransportFd fd; + status_t status = + mConnectionInfoProvider(mInstance, reinterpret_cast(&addrStorage), + sizeof(addrStorage)); + if (status != OK) { + const std::string error = "The connection info provider was unable to provide " + "connection info for instance " + + std::string(String8(mInstance).c_str()) + + " with status: " + statusToString(status); + ALOGE("%s", error.c_str()); + return Status::fromServiceSpecificError(IAccessor::ERROR_CONNECTION_INFO_NOT_FOUND, + error.c_str()); + } + if (addrStorage.ss_family == AF_VSOCK) { + sockaddr_vm* addr = reinterpret_cast(&addrStorage); + status = singleSocketConnection(VsockSocketAddress(addr->svm_cid, addr->svm_port), + trigger, &fd); + } else if (addrStorage.ss_family == AF_UNIX) { + sockaddr_un* addr = reinterpret_cast(&addrStorage); + status = singleSocketConnection(UnixSocketAddress(addr->sun_path), trigger, &fd); + } else if (addrStorage.ss_family == AF_INET) { + sockaddr_in* addr = reinterpret_cast(&addrStorage); + status = singleSocketConnection(InetSocketAddress(reinterpret_cast(addr), + sizeof(sockaddr_in), + inet_ntoa(addr->sin_addr), + ntohs(addr->sin_port)), + trigger, &fd); + } else { + const std::string error = + "Unsupported socket family type or the ConnectionInfoProvider failed to find a " + "valid address. Family type: " + + std::to_string(addrStorage.ss_family); + ALOGE("%s", error.c_str()); + return Status::fromServiceSpecificError(IAccessor::ERROR_UNSUPPORTED_SOCKET_FAMILY, + error.c_str()); + } + if (status != OK) { + const std::string error = "Failed to connect to socket for " + + std::string(String8(mInstance).c_str()) + + " with status: " + statusToString(status); + ALOGE("%s", error.c_str()); + int err = 0; + if (status == -EACCES) { + err = IAccessor::ERROR_FAILED_TO_CONNECT_EACCES; + } else { + err = IAccessor::ERROR_FAILED_TO_CONNECT_TO_SOCKET; } + return Status::fromServiceSpecificError(err, error.c_str()); } -#endif + *outFd = os::ParcelFileDescriptor(std::move(fd.fd)); + return Status::ok(); + } - sp sm = nullptr; - while (sm == nullptr) { - sm = interface_cast(ProcessState::self()->getContextObject(nullptr)); - if (sm == nullptr) { - ALOGE("Waiting 1s on context object on %s.", ProcessState::self()->getDriverName().c_str()); - sleep(1); - } + ::android::binder::Status getInstanceName(String16* instance) { + *instance = mInstance; + return Status::ok(); + } + +private: + LocalAccessor() = delete; + String16 mInstance; + RpcSocketAddressProvider mConnectionInfoProvider; + std::function mOnDelete; +}; + +android::binder::Status getInjectedAccessor(const std::string& name, + android::os::Service* service) { + std::vector copiedProviders; + { + std::lock_guard lock(gAccessorProvidersMutex); + copiedProviders.insert(copiedProviders.begin(), gAccessorProviders.begin(), + gAccessorProviders.end()); + } + + // Unlocked to call the providers. This requires the providers to be + // threadsafe and not contain any references to objects that could be + // deleted. + for (const auto& provider : copiedProviders) { + sp binder = provider.mProvider->provide(String16(name.c_str())); + if (binder == nullptr) continue; + status_t status = validateAccessor(String16(name.c_str()), binder); + if (status != OK) { + ALOGE("A provider returned a binder that is not an IAccessor for instance %s. Status: " + "%s", + name.c_str(), statusToString(status).c_str()); + return android::binder::Status::fromStatusT(android::INVALID_OPERATION); } + *service = os::Service::make(binder); + return android::binder::Status::ok(); + } - gDefaultServiceManager = sp::make(sm); + *service = os::Service::make(nullptr); + return android::binder::Status::ok(); +} + +sp defaultServiceManager() +{ + std::call_once(gSmOnce, []() { + gDefaultServiceManager = sp::make(getBackendUnifiedServiceManager()); }); return gDefaultServiceManager; @@ -185,6 +313,81 @@ void setDefaultServiceManager(const sp& sm) { } } +sp getServiceManagerShimFromAidlServiceManagerForTests( + const sp& sm) { + return sp::make(sp::make(sm)); +} + +std::weak_ptr addAccessorProvider(RpcAccessorProvider&& providerCallback) { + std::lock_guard lock(gAccessorProvidersMutex); + std::shared_ptr provider = + std::make_shared(std::move(providerCallback)); + std::weak_ptr receipt = provider; + gAccessorProviders.push_back(AccessorProviderEntry(std::move(provider))); + + return receipt; +} + +status_t removeAccessorProvider(std::weak_ptr wProvider) { + std::shared_ptr provider = wProvider.lock(); + if (provider == nullptr) { + ALOGE("The provider supplied to removeAccessorProvider has already been removed."); + return NAME_NOT_FOUND; + } + std::lock_guard lock(gAccessorProvidersMutex); + size_t sizeBefore = gAccessorProviders.size(); + gAccessorProviders.erase(std::remove_if(gAccessorProviders.begin(), gAccessorProviders.end(), + [&](AccessorProviderEntry entry) { + return entry.mProvider == provider; + }), + gAccessorProviders.end()); + if (sizeBefore == gAccessorProviders.size()) { + ALOGE("Failed to find an AccessorProvider for removeAccessorProvider"); + return NAME_NOT_FOUND; + } + + return OK; +} + +status_t validateAccessor(const String16& instance, const sp& binder) { + if (binder == nullptr) { + ALOGE("Binder is null"); + return BAD_VALUE; + } + sp accessor = interface_cast(binder); + if (accessor == nullptr) { + ALOGE("This binder for %s is not an IAccessor binder", String8(instance).c_str()); + return BAD_TYPE; + } + String16 reportedInstance; + Status status = accessor->getInstanceName(&reportedInstance); + if (!status.isOk()) { + ALOGE("Failed to validate the binder being used to create a new ARpc_Accessor for %s with " + "status: %s", + String8(instance).c_str(), status.toString8().c_str()); + return NAME_NOT_FOUND; + } + if (reportedInstance != instance) { + ALOGE("Instance %s doesn't match the Accessor's instance of %s", String8(instance).c_str(), + String8(reportedInstance).c_str()); + return NAME_NOT_FOUND; + } + return OK; +} + +sp createAccessor(const String16& instance, + RpcSocketAddressProvider&& connectionInfoProvider) { + // Try to create a new accessor + if (!connectionInfoProvider) { + ALOGE("Could not find an Accessor for %s and no ConnectionInfoProvider provided to " + "create a new one", + String8(instance).c_str()); + return nullptr; + } + sp binder = sp::make(instance, std::move(connectionInfoProvider)); + return binder; +} + #if !defined(__ANDROID_VNDK__) // IPermissionController is not accessible to vendors @@ -214,16 +417,16 @@ bool checkPermission(const String16& permission, pid_t pid, uid_t uid, bool logP pc = gPermissionController; gPermissionControllerLock.unlock(); - int64_t startTime = 0; + auto startTime = std::chrono::steady_clock::now().min(); while (true) { if (pc != nullptr) { bool res = pc->checkPermission(permission, pid, uid); if (res) { - if (startTime != 0) { - ALOGI("Check passed after %d seconds for %s from uid=%d pid=%d", - (int)((uptimeMillis() - startTime) / 1000), String8(permission).c_str(), - uid, pid); + if (startTime != startTime.min()) { + const auto waitTime = std::chrono::steady_clock::now() - startTime; + ALOGI("Check passed after %" PRIu64 "ms for %s from uid=%d pid=%d", + to_ms(waitTime), String8(permission).c_str(), uid, pid); } return res; } @@ -249,8 +452,8 @@ bool checkPermission(const String16& permission, pid_t pid, uid_t uid, bool logP sp binder = defaultServiceManager()->checkService(_permission); if (binder == nullptr) { // Wait for the permission controller to come back... - if (startTime == 0) { - startTime = uptimeMillis(); + if (startTime == startTime.min()) { + startTime = std::chrono::steady_clock::now(); ALOGI("Waiting to check permission %s from uid=%d pid=%d", String8(permission).c_str(), uid, pid); } @@ -265,8 +468,11 @@ bool checkPermission(const String16& permission, pid_t pid, uid_t uid, bool logP } } +#endif //__ANDROID_VNDK__ + void* openDeclaredPassthroughHal(const String16& interface, const String16& instance, int flag) { -#if defined(__ANDROID__) && !defined(__ANDROID_RECOVERY__) && !defined(__ANDROID_NATIVE_BRIDGE__) +#if defined(__ANDROID__) && !defined(__ANDROID_VENDOR__) && !defined(__ANDROID_RECOVERY__) && \ + !defined(__ANDROID_NATIVE_BRIDGE__) sp sm = defaultServiceManager(); String16 name = interface + String16("/") + instance; if (!sm->isDeclared(name)) { @@ -286,20 +492,16 @@ void* openDeclaredPassthroughHal(const String16& interface, const String16& inst #endif } -#endif //__ANDROID_VNDK__ - // ---------------------------------------------------------------------- -ServiceManagerShim::ServiceManagerShim(const sp& impl) - : mTheRealServiceManager(impl) -{} +CppBackendShim::CppBackendShim(const sp& impl) + : mUnifiedServiceManager(impl) {} // This implementation could be simplified and made more efficient by delegating // to waitForService. However, this changes the threading structure in some // cases and could potentially break prebuilts. Once we have higher logistical // complexity, this could be attempted. -sp ServiceManagerShim::getService(const String16& name) const -{ +sp CppBackendShim::getService(const String16& name) const { static bool gSystemBootCompleted = false; sp svc = checkService(name); @@ -307,8 +509,8 @@ sp ServiceManagerShim::getService(const String16& name) const const bool isVendorService = strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder") == 0; - constexpr int64_t timeout = 5000; - int64_t startTime = uptimeMillis(); + constexpr auto timeout = 5s; + const auto startTime = std::chrono::steady_clock::now(); // Vendor code can't access system properties if (!gSystemBootCompleted && !isVendorService) { #ifdef __ANDROID__ @@ -326,15 +528,16 @@ sp ServiceManagerShim::getService(const String16& name) const ProcessState::self()->getDriverName().c_str()); int n = 0; - while (uptimeMillis() - startTime < timeout) { + while (std::chrono::steady_clock::now() - startTime < timeout) { n++; usleep(1000*sleepTime); sp svc = checkService(name); if (svc != nullptr) { - ALOGI("Waiting for service '%s' on '%s' successful after waiting %" PRIi64 "ms", + const auto waitTime = std::chrono::steady_clock::now() - startTime; + ALOGI("Waiting for service '%s' on '%s' successful after waiting %" PRIu64 "ms", String8(name).c_str(), ProcessState::self()->getDriverName().c_str(), - uptimeMillis() - startTime); + to_ms(waitTime)); return svc; } } @@ -342,27 +545,24 @@ sp ServiceManagerShim::getService(const String16& name) const return nullptr; } -sp ServiceManagerShim::checkService(const String16& name) const -{ - sp ret; - if (!mTheRealServiceManager->checkService(String8(name).c_str(), &ret).isOk()) { +sp CppBackendShim::checkService(const String16& name) const { + Service ret; + if (!mUnifiedServiceManager->checkService(String8(name).c_str(), &ret).isOk()) { return nullptr; } - return ret; + return ret.get(); } -status_t ServiceManagerShim::addService(const String16& name, const sp& service, - bool allowIsolated, int dumpsysPriority) -{ - Status status = mTheRealServiceManager->addService( - String8(name).c_str(), service, allowIsolated, dumpsysPriority); +status_t CppBackendShim::addService(const String16& name, const sp& service, + bool allowIsolated, int dumpsysPriority) { + Status status = mUnifiedServiceManager->addService(String8(name).c_str(), service, + allowIsolated, dumpsysPriority); return status.exceptionCode(); } -Vector ServiceManagerShim::listServices(int dumpsysPriority) -{ +Vector CppBackendShim::listServices(int dumpsysPriority) { std::vector ret; - if (!mTheRealServiceManager->listServices(dumpsysPriority, &ret).isOk()) { + if (!mUnifiedServiceManager->listServices(dumpsysPriority, &ret).isOk()) { return {}; } @@ -374,8 +574,7 @@ Vector ServiceManagerShim::listServices(int dumpsysPriority) return res; } -sp ServiceManagerShim::waitForService(const String16& name16) -{ +sp CppBackendShim::waitForService(const String16& name16) { class Waiter : public android::os::BnServiceCallback { Status onRegistration(const std::string& /*name*/, const sp& binder) override { @@ -420,15 +619,13 @@ sp ServiceManagerShim::waitForService(const String16& name16) if (out != nullptr) return out; sp waiter = sp::make(); - if (Status status = mTheRealServiceManager->registerForNotifications(name, waiter); + if (Status status = mUnifiedServiceManager->registerForNotifications(name, waiter); !status.isOk()) { ALOGW("Failed to registerForNotifications in waitForService for %s: %s", name.c_str(), status.toString8().c_str()); return nullptr; } - Defer unregister ([&] { - mTheRealServiceManager->unregisterForNotifications(name, waiter); - }); + Defer unregister([&] { mUnifiedServiceManager->unregisterForNotifications(name, waiter); }); while(true) { { @@ -438,7 +635,6 @@ sp ServiceManagerShim::waitForService(const String16& name16) // that another thread serves the callback, and we never get a // command, so we hang indefinitely. std::unique_lock lock(waiter->mMutex); - using std::literals::chrono_literals::operator""s; waiter->mCv.wait_for(lock, 1s, [&] { return waiter->mBinder != nullptr; }); @@ -467,9 +663,9 @@ sp ServiceManagerShim::waitForService(const String16& name16) } } -bool ServiceManagerShim::isDeclared(const String16& name) { +bool CppBackendShim::isDeclared(const String16& name) { bool declared; - if (Status status = mTheRealServiceManager->isDeclared(String8(name).c_str(), &declared); + if (Status status = mUnifiedServiceManager->isDeclared(String8(name).c_str(), &declared); !status.isOk()) { ALOGW("Failed to get isDeclared for %s: %s", String8(name).c_str(), status.toString8().c_str()); @@ -478,10 +674,10 @@ bool ServiceManagerShim::isDeclared(const String16& name) { return declared; } -Vector ServiceManagerShim::getDeclaredInstances(const String16& interface) { +Vector CppBackendShim::getDeclaredInstances(const String16& interface) { std::vector out; if (Status status = - mTheRealServiceManager->getDeclaredInstances(String8(interface).c_str(), &out); + mUnifiedServiceManager->getDeclaredInstances(String8(interface).c_str(), &out); !status.isOk()) { ALOGW("Failed to getDeclaredInstances for %s: %s", String8(interface).c_str(), status.toString8().c_str()); @@ -496,9 +692,9 @@ Vector ServiceManagerShim::getDeclaredInstances(const String16& interf return res; } -std::optional ServiceManagerShim::updatableViaApex(const String16& name) { +std::optional CppBackendShim::updatableViaApex(const String16& name) { std::optional declared; - if (Status status = mTheRealServiceManager->updatableViaApex(String8(name).c_str(), &declared); + if (Status status = mUnifiedServiceManager->updatableViaApex(String8(name).c_str(), &declared); !status.isOk()) { ALOGW("Failed to get updatableViaApex for %s: %s", String8(name).c_str(), status.toString8().c_str()); @@ -507,9 +703,9 @@ std::optional ServiceManagerShim::updatableViaApex(const String16& nam return declared ? std::optional(String16(declared.value().c_str())) : std::nullopt; } -Vector ServiceManagerShim::getUpdatableNames(const String16& apexName) { +Vector CppBackendShim::getUpdatableNames(const String16& apexName) { std::vector out; - if (Status status = mTheRealServiceManager->getUpdatableNames(String8(apexName).c_str(), &out); + if (Status status = mUnifiedServiceManager->getUpdatableNames(String8(apexName).c_str(), &out); !status.isOk()) { ALOGW("Failed to getUpdatableNames for %s: %s", String8(apexName).c_str(), status.toString8().c_str()); @@ -524,11 +720,11 @@ Vector ServiceManagerShim::getUpdatableNames(const String16& apexName) return res; } -std::optional ServiceManagerShim::getConnectionInfo( +std::optional CppBackendShim::getConnectionInfo( const String16& name) { std::optional connectionInfo; if (Status status = - mTheRealServiceManager->getConnectionInfo(String8(name).c_str(), &connectionInfo); + mUnifiedServiceManager->getConnectionInfo(String8(name).c_str(), &connectionInfo); !status.isOk()) { ALOGW("Failed to get ConnectionInfo for %s: %s", String8(name).c_str(), status.toString8().c_str()); @@ -539,8 +735,8 @@ std::optional ServiceManagerShim::getConnection : std::nullopt; } -status_t ServiceManagerShim::registerForNotifications(const String16& name, - const sp& cb) { +status_t CppBackendShim::registerForNotifications(const String16& name, + const sp& cb) { if (cb == nullptr) { ALOGE("%s: null cb passed", __FUNCTION__); return BAD_VALUE; @@ -549,7 +745,7 @@ status_t ServiceManagerShim::registerForNotifications(const String16& name, sp registrationWaiter = sp::make(cb); std::lock_guard lock(mNameToRegistrationLock); if (Status status = - mTheRealServiceManager->registerForNotifications(nameStr, registrationWaiter); + mUnifiedServiceManager->registerForNotifications(nameStr, registrationWaiter); !status.isOk()) { ALOGW("Failed to registerForNotifications for %s: %s", nameStr.c_str(), status.toString8().c_str()); @@ -559,9 +755,9 @@ status_t ServiceManagerShim::registerForNotifications(const String16& name, return OK; } -void ServiceManagerShim::removeRegistrationCallbackLocked(const sp& cb, - ServiceCallbackMap::iterator* it, - sp* waiter) { +void CppBackendShim::removeRegistrationCallbackLocked(const sp& cb, + ServiceCallbackMap::iterator* it, + sp* waiter) { std::vector& localRegistrationAndWaiters = (*it)->second; for (auto lit = localRegistrationAndWaiters.begin(); lit != localRegistrationAndWaiters.end();) { @@ -580,8 +776,8 @@ void ServiceManagerShim::removeRegistrationCallbackLocked(const sp& cb) { +status_t CppBackendShim::unregisterForNotifications(const String16& name, + const sp& cb) { if (cb == nullptr) { ALOGE("%s: null cb passed", __FUNCTION__); return BAD_VALUE; @@ -600,7 +796,7 @@ status_t ServiceManagerShim::unregisterForNotifications(const String16& name, ALOGE("%s Callback passed wasn't used to register for notifications", __FUNCTION__); return BAD_VALUE; } - if (Status status = mTheRealServiceManager->unregisterForNotifications(String8(name).c_str(), + if (Status status = mUnifiedServiceManager->unregisterForNotifications(String8(name).c_str(), registrationWaiter); !status.isOk()) { ALOGW("Failed to get service manager to unregisterForNotifications for %s: %s", @@ -610,10 +806,10 @@ status_t ServiceManagerShim::unregisterForNotifications(const String16& name, return OK; } -std::vector ServiceManagerShim::getServiceDebugInfo() { +std::vector CppBackendShim::getServiceDebugInfo() { std::vector serviceDebugInfos; std::vector ret; - if (Status status = mTheRealServiceManager->getServiceDebugInfo(&serviceDebugInfos); + if (Status status = mUnifiedServiceManager->getServiceDebugInfo(&serviceDebugInfos); !status.isOk()) { ALOGW("%s Failed to get ServiceDebugInfo", __FUNCTION__); return ret; @@ -628,21 +824,21 @@ std::vector ServiceManagerShim::getServiceDeb } #ifndef __ANDROID__ -// ServiceManagerShim for host. Implements the old libbinder android::IServiceManager API. +// CppBackendShim for host. Implements the old libbinder android::IServiceManager API. // The internal implementation of the AIDL interface android::os::IServiceManager calls into // on-device service manager. -class ServiceManagerHostShim : public ServiceManagerShim { +class CppServiceManagerHostShim : public CppBackendShim { public: - ServiceManagerHostShim(const sp& impl, - const RpcDelegateServiceManagerOptions& options) - : ServiceManagerShim(impl), mOptions(options) {} - // ServiceManagerShim::getService is based on checkService, so no need to override it. + CppServiceManagerHostShim(const sp& impl, + const RpcDelegateServiceManagerOptions& options) + : CppBackendShim(sp::make(impl)), mOptions(options) {} + // CppBackendShim::getService is based on checkService, so no need to override it. sp checkService(const String16& name) const override { return getDeviceService({String8(name).c_str()}, mOptions); } protected: - // Override realGetService for ServiceManagerShim::waitForService. + // Override realGetService for CppBackendShim::waitForService. Status realGetService(const std::string& name, sp* _aidl_return) override { *_aidl_return = getDeviceService({"-g", name}, mOptions); return Status::ok(); @@ -663,7 +859,7 @@ sp createRpcDelegateServiceManager( ALOGE("getDeviceService(\"manager\") returns non service manager"); return nullptr; } - return sp::make(interface, options); + return sp::make(interface, options); } #endif diff --git a/libs/binder/IServiceManagerFFI.cpp b/libs/binder/IServiceManagerFFI.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7d4d7dc063cb58693bc8e57515a059c68fb182ab --- /dev/null +++ b/libs/binder/IServiceManagerFFI.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2024 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 + +#include +#include + +namespace android::impl { +sp +getJavaServicemanagerImplPrivateDoNotUseExceptInTheOnePlaceItIsUsed() { + return getBackendUnifiedServiceManager(); +} + +} // namespace android::impl diff --git a/libs/binder/IShellCallback.cpp b/libs/binder/IShellCallback.cpp index 86dd5c4f4b3c73703a3a683a5e4bb3f380de7b3c..1d6852a9e42f5a003c4679bdec6f22cdc6a25197 100644 --- a/libs/binder/IShellCallback.cpp +++ b/libs/binder/IShellCallback.cpp @@ -21,7 +21,6 @@ #include -#include #include #include diff --git a/libs/binder/LazyServiceRegistrar.cpp b/libs/binder/LazyServiceRegistrar.cpp index 7644806e2b1493bebfd369640efcb7d035065b6c..0f0af0b1428f5c7092f94e306a3412a4225b5700 100644 --- a/libs/binder/LazyServiceRegistrar.cpp +++ b/libs/binder/LazyServiceRegistrar.cpp @@ -14,15 +14,13 @@ * limitations under the License. */ -#include "log/log_main.h" #define LOG_TAG "AidlLazyServiceRegistrar" -#include -#include -#include #include #include -#include +#include +#include +#include namespace android { namespace binder { diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 3f70e8c104fe8af9c0ed158a694c927f4637c30e..4b7af4573976d2bff05778824c6435f9e43f1998 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -1585,10 +1585,15 @@ status_t Parcel::writeFileDescriptor(int fd, bool takeOwnership) { fdVariant = borrowed_fd(fd); } if (!mAllowFds) { + ALOGE("FDs are not allowed in this parcel. Both the service and the client must set " + "the FileDescriptorTransportMode and agree on the support."); return FDS_NOT_ALLOWED; } switch (rpcFields->mSession->getFileDescriptorTransportMode()) { case RpcSession::FileDescriptorTransportMode::NONE: { + ALOGE("FDs are not allowed in this RpcSession. Both the service and the client " + "must set " + "the FileDescriptorTransportMode and agree on the support."); return FDS_NOT_ALLOWED; } case RpcSession::FileDescriptorTransportMode::UNIX: @@ -1720,7 +1725,9 @@ status_t Parcel::writeBlob(size_t len, bool mutableCopy, WritableBlob* outBlob) } } } - ::munmap(ptr, len); + if (::munmap(ptr, len) == -1) { + ALOGW("munmap() failed: %s", strerror(errno)); + } } ::close(fd); return status; @@ -3327,7 +3334,9 @@ Parcel::Blob::~Blob() { void Parcel::Blob::release() { if (mFd != -1 && mData) { - ::munmap(mData, mSize); + if (::munmap(mData, mSize) == -1) { + ALOGW("munmap() failed: %s", strerror(errno)); + } } clear(); } diff --git a/libs/binder/PermissionController.cpp b/libs/binder/PermissionController.cpp index 0c8924503d29e6e1024144a42c8f7fc6d905fa52..c11eb7df4237cc891527801b1a799f42cc63bffe 100644 --- a/libs/binder/PermissionController.cpp +++ b/libs/binder/PermissionController.cpp @@ -19,10 +19,10 @@ #include #include -#include - namespace android { +using namespace std::chrono_literals; + PermissionController::PermissionController() { } @@ -30,16 +30,16 @@ PermissionController::PermissionController() sp PermissionController::getService() { std::lock_guard scoped_lock(mLock); - int64_t startTime = 0; + auto startTime = std::chrono::steady_clock::now().min(); sp service = mService; while (service == nullptr || !IInterface::asBinder(service)->isBinderAlive()) { sp binder = defaultServiceManager()->checkService(String16("permission")); if (binder == nullptr) { // Wait for the activity service to come back... - if (startTime == 0) { - startTime = uptimeMillis(); + if (startTime == startTime.min()) { + startTime = std::chrono::steady_clock::now(); ALOGI("Waiting for permission service"); - } else if ((uptimeMillis() - startTime) > 10000) { + } else if (std::chrono::steady_clock::now() - startTime > 10s) { ALOGW("Waiting too long for permission service, giving up"); service = nullptr; break; diff --git a/libs/binder/PersistableBundle.cpp b/libs/binder/PersistableBundle.cpp index 5b157cc7c384d6d32513d92ab2c18eb9c837c37b..abb6612a1c272b3b8b94500bef9f3c287f4ccab7 100644 --- a/libs/binder/PersistableBundle.cpp +++ b/libs/binder/PersistableBundle.cpp @@ -113,7 +113,7 @@ status_t PersistableBundle::writeToParcel(Parcel* parcel) const { // Backpatch length. This length value includes the length header. parcel->setDataPosition(length_pos); size_t length = end_pos - start_pos; - if (length > std::numeric_limits::max()) { + if (length > static_cast(std::numeric_limits::max())) { ALOGE("Parcel length (%zu) too large to store in 32-bit signed int", length); return BAD_VALUE; } @@ -319,7 +319,7 @@ status_t PersistableBundle::writeToParcelInner(Parcel* parcel) const { * pairs themselves. */ size_t num_entries = size(); - if (num_entries > std::numeric_limits::max()) { + if (num_entries > static_cast(std::numeric_limits::max())) { ALOGE("The size of this PersistableBundle (%zu) too large to store in 32-bit signed int", num_entries); return BAD_VALUE; diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp index 8485ecd8354004abff44ac6e1776c5b8fddb94db..5e7f1510bcb497d6d3efff7ecc734504f45fccfd 100644 --- a/libs/binder/ProcessState.cpp +++ b/libs/binder/ProcessState.cpp @@ -24,9 +24,7 @@ #include #include #include -#include #include -#include #include #include @@ -58,6 +56,25 @@ const char* kDefaultDriver = "/dev/binder"; // ------------------------------------------------------------------------- +namespace { +bool readDriverFeatureFile(const char* filename) { + int fd = open(filename, O_RDONLY | O_CLOEXEC); + char on; + if (fd == -1) { + ALOGE_IF(errno != ENOENT, "%s: cannot open %s: %s", __func__, filename, strerror(errno)); + return false; + } + if (read(fd, &on, sizeof(on)) == -1) { + ALOGE("%s: error reading to %s: %s", __func__, filename, strerror(errno)); + close(fd); + return false; + } + close(fd); + return on == '1'; +} + +} // namespace + namespace android { using namespace android::binder::impl; @@ -312,6 +329,7 @@ extern sp the_context_object; sp ProcessState::getStrongProxyForHandle(int32_t handle) { sp result; + std::function postTask; std::unique_lock _l(mLock); @@ -359,7 +377,7 @@ sp ProcessState::getStrongProxyForHandle(int32_t handle) return nullptr; } - sp b = BpBinder::PrivateAccessor::create(handle); + sp b = BpBinder::PrivateAccessor::create(handle, &postTask); e->binder = b.get(); if (b) e->refs = b->getWeakRefs(); result = b; @@ -372,6 +390,10 @@ sp ProcessState::getStrongProxyForHandle(int32_t handle) } } + _l.unlock(); + + if (postTask) postTask(); + return result; } @@ -388,7 +410,7 @@ void ProcessState::expungeHandle(int32_t handle, IBinder* binder) } String8 ProcessState::makeBinderThreadName() { - int32_t s = android_atomic_add(1, &mThreadPoolSeq); + int32_t s = mThreadPoolSeq.fetch_add(1, std::memory_order_release); pid_t pid = getpid(); std::string_view driverName = mDriverName.c_str(); @@ -407,9 +429,7 @@ void ProcessState::spawnPooledThread(bool isMain) ALOGV("Spawning new pooled thread, name=%s\n", name.c_str()); sp t = sp::make(isMain); t->run(name.c_str()); - pthread_mutex_lock(&mThreadCountLock); mKernelStartedThreads++; - pthread_mutex_unlock(&mThreadCountLock); } // TODO: if startThreadPool is called on another thread after the process // starts up, the kernel might think that it already requested those @@ -432,19 +452,28 @@ status_t ProcessState::setThreadPoolMaxThreadCount(size_t maxThreads) { } size_t ProcessState::getThreadPoolMaxTotalThreadCount() const { - pthread_mutex_lock(&mThreadCountLock); - auto detachGuard = make_scope_guard([&]() { pthread_mutex_unlock(&mThreadCountLock); }); + // Need to read `mKernelStartedThreads` before `mThreadPoolStarted` (with + // non-relaxed memory ordering) to avoid a race like the following: + // + // thread A: if (mThreadPoolStarted) { // evaluates false + // thread B: mThreadPoolStarted = true; + // thread B: mKernelStartedThreads++; + // thread A: size_t kernelStarted = mKernelStartedThreads; + // thread A: LOG_ALWAYS_FATAL_IF(kernelStarted != 0, ...); + size_t kernelStarted = mKernelStartedThreads; if (mThreadPoolStarted) { - LOG_ALWAYS_FATAL_IF(mKernelStartedThreads > mMaxThreads + 1, - "too many kernel-started threads: %zu > %zu + 1", mKernelStartedThreads, - mMaxThreads); + size_t max = mMaxThreads; + size_t current = mCurrentThreads; + + LOG_ALWAYS_FATAL_IF(kernelStarted > max + 1, + "too many kernel-started threads: %zu > %zu + 1", kernelStarted, max); // calling startThreadPool starts a thread size_t threads = 1; // the kernel is configured to start up to mMaxThreads more threads - threads += mMaxThreads; + threads += max; // Users may call IPCThreadState::joinThreadPool directly. We don't // currently have a way to count this directly (it could be added by @@ -454,8 +483,8 @@ size_t ProcessState::getThreadPoolMaxTotalThreadCount() const { // in IPCThreadState, temporarily forget about the extra join threads. // This is okay, because most callers of this method only care about // having 0, 1, or more threads. - if (mCurrentThreads > mKernelStartedThreads) { - threads += mCurrentThreads - mKernelStartedThreads; + if (current > kernelStarted) { + threads += current - kernelStarted; } return threads; @@ -463,10 +492,8 @@ size_t ProcessState::getThreadPoolMaxTotalThreadCount() const { // must not be initialized or maybe has poll thread setup, we // currently don't track this in libbinder - LOG_ALWAYS_FATAL_IF(mKernelStartedThreads != 0, - "Expecting 0 kernel started threads but have" - " %zu", - mKernelStartedThreads); + LOG_ALWAYS_FATAL_IF(kernelStarted != 0, "Expecting 0 kernel started threads but have %zu", + kernelStarted); return mCurrentThreads; } @@ -476,27 +503,20 @@ bool ProcessState::isThreadPoolStarted() const { #define DRIVER_FEATURES_PATH "/dev/binderfs/features/" bool ProcessState::isDriverFeatureEnabled(const DriverFeature feature) { - static const char* const names[] = { - [static_cast(DriverFeature::ONEWAY_SPAM_DETECTION)] = - DRIVER_FEATURES_PATH "oneway_spam_detection", - [static_cast(DriverFeature::EXTENDED_ERROR)] = - DRIVER_FEATURES_PATH "extended_error", - }; - int fd = open(names[static_cast(feature)], O_RDONLY | O_CLOEXEC); - char on; - if (fd == -1) { - ALOGE_IF(errno != ENOENT, "%s: cannot open %s: %s", __func__, - names[static_cast(feature)], strerror(errno)); - return false; + // Use static variable to cache the results. + if (feature == DriverFeature::ONEWAY_SPAM_DETECTION) { + static bool enabled = readDriverFeatureFile(DRIVER_FEATURES_PATH "oneway_spam_detection"); + return enabled; } - if (read(fd, &on, sizeof(on)) == -1) { - ALOGE("%s: error reading to %s: %s", __func__, - names[static_cast(feature)], strerror(errno)); - close(fd); - return false; + if (feature == DriverFeature::EXTENDED_ERROR) { + static bool enabled = readDriverFeatureFile(DRIVER_FEATURES_PATH "extended_error"); + return enabled; } - close(fd); - return on == '1'; + if (feature == DriverFeature::FREEZE_NOTIFICATION) { + static bool enabled = readDriverFeatureFile(DRIVER_FEATURES_PATH "freeze_notification"); + return enabled; + } + return false; } status_t ProcessState::enableOnewaySpamDetection(bool enable) { @@ -554,14 +574,11 @@ ProcessState::ProcessState(const char* driver) : mDriverName(String8(driver)), mDriverFD(-1), mVMStart(MAP_FAILED), - mThreadCountLock(PTHREAD_MUTEX_INITIALIZER), - mThreadCountDecrement(PTHREAD_COND_INITIALIZER), mExecutingThreadsCount(0), - mWaitingForThreads(0), mMaxThreads(DEFAULT_MAX_BINDER_THREADS), mCurrentThreads(0), mKernelStartedThreads(0), - mStarvationStartTimeMs(0), + mStarvationStartTime(never()), mForked(false), mThreadPoolStarted(false), mThreadPoolSeq(1), @@ -584,7 +601,7 @@ ProcessState::ProcessState(const char* driver) #ifdef __ANDROID__ LOG_ALWAYS_FATAL_IF(!opened.ok(), "Binder driver '%s' could not be opened. Error: %s. Terminating.", - error.c_str(), driver); + driver, error.c_str()); #endif if (opened.ok()) { diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp index d9e926a9d5c4a641903d2f2428f217b88de85487..b8742af1f91a3dfaede24b9f67072e94446b05cc 100644 --- a/libs/binder/RpcServer.cpp +++ b/libs/binder/RpcServer.cpp @@ -71,8 +71,23 @@ status_t RpcServer::setupUnixDomainServer(const char* path) { return setupSocketServer(UnixSocketAddress(path)); } -status_t RpcServer::setupVsockServer(unsigned int bindCid, unsigned int port) { - return setupSocketServer(VsockSocketAddress(bindCid, port)); +status_t RpcServer::setupVsockServer(unsigned bindCid, unsigned port, unsigned* assignedPort) { + auto status = setupSocketServer(VsockSocketAddress(bindCid, port)); + if (status != OK) return status; + + if (assignedPort == nullptr) return OK; + sockaddr_vm addr; + socklen_t len = sizeof(addr); + if (0 != getsockname(mServer.fd.get(), reinterpret_cast(&addr), &len)) { + status = -errno; + ALOGE("setupVsockServer: Failed to getsockname: %s", strerror(-status)); + return status; + } + + LOG_ALWAYS_FATAL_IF(len != sizeof(addr), "Wrong socket type: len %zu vs len %zu", + static_cast(len), sizeof(addr)); + *assignedPort = addr.svm_port; + return OK; } status_t RpcServer::setupInetServer(const char* address, unsigned int port, diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp index 16a7f9fd489d261ddbc2a2a5d52935e2371472bb..cd21a91d2cdf30adb6ad74b1ae8cbdbd1ca55eca 100644 --- a/libs/binder/RpcSession.cpp +++ b/libs/binder/RpcSession.cpp @@ -589,6 +589,21 @@ status_t RpcSession::setupSocketClient(const RpcSocketAddress& addr) { status_t RpcSession::setupOneSocketConnection(const RpcSocketAddress& addr, const std::vector& sessionId, bool incoming) { + RpcTransportFd transportFd; + status_t status = singleSocketConnection(addr, mShutdownTrigger, &transportFd); + if (status != OK) return status; + + return initAndAddConnection(std::move(transportFd), sessionId, incoming); +} + +status_t singleSocketConnection(const RpcSocketAddress& addr, + const std::unique_ptr& shutdownTrigger, + RpcTransportFd* outFd) { + LOG_ALWAYS_FATAL_IF(outFd == nullptr, + "There is no reason to call this function without an outFd"); + LOG_ALWAYS_FATAL_IF(shutdownTrigger == nullptr, + "FdTrigger argument is required so we don't get stuck in the connect call " + "if the server process shuts down."); for (size_t tries = 0; tries < 5; tries++) { if (tries > 0) usleep(10000); @@ -620,7 +635,7 @@ status_t RpcSession::setupOneSocketConnection(const RpcSocketAddress& addr, if (connErrno == EAGAIN || connErrno == EINPROGRESS) { // For non-blocking sockets, connect() may return EAGAIN (for unix domain socket) or // EINPROGRESS (for others). Call poll() and getsockopt() to get the error. - status_t pollStatus = mShutdownTrigger->triggerablePoll(transportFd, POLLOUT); + status_t pollStatus = shutdownTrigger->triggerablePoll(transportFd, POLLOUT); if (pollStatus != OK) { ALOGE("Could not POLLOUT after connect() on non-blocking socket: %s", statusToString(pollStatus).c_str()); @@ -654,7 +669,8 @@ status_t RpcSession::setupOneSocketConnection(const RpcSocketAddress& addr, LOG_RPC_DETAIL("Socket at %s client with fd %d", addr.toString().c_str(), transportFd.fd.get()); - return initAndAddConnection(std::move(transportFd), sessionId, incoming); + *outFd = std::move(transportFd); + return OK; } ALOGE("Ran out of retries to connect to %s", addr.toString().c_str()); @@ -801,6 +817,14 @@ bool RpcSession::setForServer(const wp& server, const wp& sessionSpecificRoot) { + LOG_ALWAYS_FATAL_IF(mSessionSpecificRootObject != nullptr, + "Session specific root object already set"); + LOG_ALWAYS_FATAL_IF(mForServer != nullptr, + "Session specific root object cannot be set for a server"); + mSessionSpecificRootObject = sessionSpecificRoot; +} + sp RpcSession::assignIncomingConnectionToThisThread( std::unique_ptr rpcTransport) { RpcMutexLockGuard _l(mMutex); diff --git a/libs/binder/RpcSocketAddress.h b/libs/binder/RpcSocketAddress.h index c7ba5d96a798a2dfde8b42e24f13d39495852363..ee7d448c43ac6f32fba58897e57176d165be0f6c 100644 --- a/libs/binder/RpcSocketAddress.h +++ b/libs/binder/RpcSocketAddress.h @@ -113,4 +113,11 @@ private: unsigned int mPort; }; +/** + * Connects to a single socket and produces a RpcTransportFd. + */ +status_t singleSocketConnection(const RpcSocketAddress& address, + const std::unique_ptr& shutdownTrigger, + RpcTransportFd* outFd); + } // namespace android diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING index 2b3ff4407a1ff0783fdc8784148b375e8db01029..95a5da20aeaaa44458a7335135821df742825c99 100644 --- a/libs/binder/TEST_MAPPING +++ b/libs/binder/TEST_MAPPING @@ -129,6 +129,15 @@ "name": "memunreachable_binder_test" } ], + "postsubmit": [ + { + "name": "binder_sdk_test", + "host": true + }, + { + "name": "binderCacheUnitTest" + } + ], "imports": [ { "path": "packages/modules/Virtualization" diff --git a/libs/binder/Utils.h b/libs/binder/Utils.h index df8a4ce1f1476dbbaa468a182d13d2b82eead374..881cdf3f4c122ebf1e071656852091e235c8c109 100644 --- a/libs/binder/Utils.h +++ b/libs/binder/Utils.h @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -57,6 +58,19 @@ } \ } while (0) +#define LIBBINDER_PRAGMA(arg) _Pragma(#arg) +#if defined(__clang__) +#define LIBBINDER_PRAGMA_FOR_COMPILER(arg) LIBBINDER_PRAGMA(clang arg) +#elif defined(__GNUC__) +#define LIBBINDER_PRAGMA_FOR_COMPILER(arg) LIBBINDER_PRAGMA(GCC arg) +#else +#define LIBBINDER_PRAGMA_FOR_COMPILER(arg) +#endif +#define LIBBINDER_IGNORE(warning_flag) \ + LIBBINDER_PRAGMA_FOR_COMPILER(diagnostic push) \ + LIBBINDER_PRAGMA_FOR_COMPILER(diagnostic ignored warning_flag) +#define LIBBINDER_IGNORE_END() LIBBINDER_PRAGMA_FOR_COMPILER(diagnostic pop) + namespace android { /** @@ -114,4 +128,10 @@ struct Span { // Android is little-endian. LIBBINDER_INTERNAL_EXPORTED std::string HexString(const void* bytes, size_t len); +// Converts any std::chrono duration to the number of milliseconds +template +uint64_t to_ms(std::chrono::duration duration) { + return std::chrono::duration_cast(duration).count(); +} + } // namespace android diff --git a/libs/binder/aidl/android/os/IAccessor.aidl b/libs/binder/aidl/android/os/IAccessor.aidl new file mode 100644 index 0000000000000000000000000000000000000000..c06e05c444fa1215f63701a0dd48e4b60d1a92fc --- /dev/null +++ b/libs/binder/aidl/android/os/IAccessor.aidl @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +import android.os.ParcelFileDescriptor; + +/** + * Interface for accessing the RPC server of a service. + * + * @hide + */ +interface IAccessor { + /** + * The connection info was not available for this service. + * This happens when the user-supplied callback fails to produce + * valid connection info. + * Depending on the implementation of the callback, it might be helpful + * to retry. + */ + const int ERROR_CONNECTION_INFO_NOT_FOUND = 0; + /** + * Failed to create the socket. Often happens when the process trying to create + * the socket lacks the permissions to do so. + * This may be a temporary issue, so retrying the operation is OK. + */ + const int ERROR_FAILED_TO_CREATE_SOCKET = 1; + /** + * Failed to connect to the socket. This can happen for many reasons, so be sure + * log the error message and check it. + * This may be a temporary issue, so retrying the operation is OK. + */ + const int ERROR_FAILED_TO_CONNECT_TO_SOCKET = 2; + /** + * Failed to connect to the socket with EACCES because this process does not + * have perimssions to connect. + * There is no need to retry the connection as this access will not be granted + * upon retry. + */ + const int ERROR_FAILED_TO_CONNECT_EACCES = 3; + /** + * Unsupported socket family type returned. + * There is no need to retry the connection as this socket family is not + * supported. + */ + const int ERROR_UNSUPPORTED_SOCKET_FAMILY = 4; + + /** + * Adds a connection to the RPC server of the service managed by the IAccessor. + * + * This method can be called multiple times to establish multiple distinct + * connections to the same RPC server. + * + * @throws ServiceSpecificError with message and one of the IAccessor::ERROR_ values. + * + * @return A file descriptor connected to the RPC session of the service managed + * by IAccessor. + */ + ParcelFileDescriptor addConnection(); + + /** + * Get the instance name for the service this accessor is responsible for. + * + * This is used to verify the proxy binder is associated with the expected instance name. + */ + String getInstanceName(); +} diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl index 0fb1615391453581b761748d53dc8cfe9e51ccef..1d1f84fc011ec3a499b15f5d31e85846bdf18873 100644 --- a/libs/binder/aidl/android/os/IServiceManager.aidl +++ b/libs/binder/aidl/android/os/IServiceManager.aidl @@ -18,6 +18,7 @@ package android.os; import android.os.IClientCallback; import android.os.IServiceCallback; +import android.os.Service; import android.os.ServiceDebugInfo; import android.os.ConnectionInfo; @@ -59,17 +60,31 @@ interface IServiceManager { * exists for legacy purposes. * * Returns null if the service does not exist. + * + * @deprecated TODO(b/355394904): Use getService2 instead. */ @UnsupportedAppUsage @nullable IBinder getService(@utf8InCpp String name); + /** + * Retrieve an existing service called @a name from the + * service manager. + * + * This is the same as checkService (returns immediately) but + * exists for legacy purposes. + * + * Returns an enum Service that can be of different types. The + * enum value is null if the service does not exist. + */ + Service getService2(@utf8InCpp String name); + /** * Retrieve an existing service called @a name from the service * manager. Non-blocking. Returns null if the service does not * exist. */ @UnsupportedAppUsage - @nullable IBinder checkService(@utf8InCpp String name); + Service checkService(@utf8InCpp String name); /** * Place a new @a service called @a name into the service diff --git a/libs/binder/aidl/android/os/Service.aidl b/libs/binder/aidl/android/os/Service.aidl new file mode 100644 index 0000000000000000000000000000000000000000..4c5210911cbd7e8b8b41cae7d5f65a779739f532 --- /dev/null +++ b/libs/binder/aidl/android/os/Service.aidl @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +/** + * Service is a union of different service types that can be returned + * by the internal {@link ServiceManager#getService(name)} API. + * + * @hide + */ +union Service { + @nullable IBinder binder; + @nullable IBinder accessor; +} \ No newline at end of file diff --git a/libs/binder/binder_module.h b/libs/binder/binder_module.h index b3a2d9ec2830f61ac4b26773f93a01c7c0d283d1..65cdcd77353a8b9fba9b88d0c508af88d3bbba2f 100644 --- a/libs/binder/binder_module.h +++ b/libs/binder/binder_module.h @@ -32,4 +32,34 @@ #include #include +struct binder_frozen_state_info { + binder_uintptr_t cookie; + __u32 is_frozen; +}; + +#ifndef BR_FROZEN_BINDER +// Temporary definition of BR_FROZEN_BINDER until UAPI binder.h includes it. +#define BR_FROZEN_BINDER _IOR('r', 21, struct binder_frozen_state_info) +#endif // BR_FROZEN_BINDER + +#ifndef BR_CLEAR_FREEZE_NOTIFICATION_DONE +// Temporary definition of BR_CLEAR_FREEZE_NOTIFICATION_DONE until UAPI binder.h includes it. +#define BR_CLEAR_FREEZE_NOTIFICATION_DONE _IOR('r', 22, binder_uintptr_t) +#endif // BR_CLEAR_FREEZE_NOTIFICATION_DONE + +#ifndef BC_REQUEST_FREEZE_NOTIFICATION +// Temporary definition of BC_REQUEST_FREEZE_NOTIFICATION until UAPI binder.h includes it. +#define BC_REQUEST_FREEZE_NOTIFICATION _IOW('c', 19, struct binder_handle_cookie) +#endif // BC_REQUEST_FREEZE_NOTIFICATION + +#ifndef BC_CLEAR_FREEZE_NOTIFICATION +// Temporary definition of BC_CLEAR_FREEZE_NOTIFICATION until UAPI binder.h includes it. +#define BC_CLEAR_FREEZE_NOTIFICATION _IOW('c', 20, struct binder_handle_cookie) +#endif // BC_CLEAR_FREEZE_NOTIFICATION + +#ifndef BC_FREEZE_NOTIFICATION_DONE +// Temporary definition of BC_FREEZE_NOTIFICATION_DONE until UAPI binder.h includes it. +#define BC_FREEZE_NOTIFICATION_DONE _IOW('c', 21, binder_uintptr_t) +#endif // BC_FREEZE_NOTIFICATION_DONE + #endif // _BINDER_MODULE_H_ diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h index 8ac30ba02fd6dd63c29a11cc34d02451dde97d55..7518044ce66a8b2eb62597378874f108cf0e0ea4 100644 --- a/libs/binder/include/binder/BpBinder.h +++ b/libs/binder/include/binder/BpBinder.h @@ -29,6 +29,7 @@ // --------------------------------------------------------------------------- namespace android { +class IPCThreadState; class RpcSession; class RpcState; namespace internal { @@ -66,6 +67,12 @@ public: void* cookie = nullptr, uint32_t flags = 0, wp* outRecipient = nullptr); + [[nodiscard]] status_t addFrozenStateChangeCallback( + const wp& recipient); + + [[nodiscard]] status_t removeFrozenStateChangeCallback( + const wp& recipient); + LIBBINDER_EXPORTED virtual void* attachObject(const void* objectID, void* object, void* cleanupCookie, object_cleanup_func func) final; @@ -75,7 +82,6 @@ public: LIBBINDER_EXPORTED sp lookupOrCreateWeak(const void* objectID, IBinder::object_make_func make, const void* makeArgs); - LIBBINDER_EXPORTED virtual BpBinder* remoteBinder(); LIBBINDER_EXPORTED void sendObituary(); @@ -132,9 +138,14 @@ public: friend class ::android::ProcessState; friend class ::android::RpcSession; friend class ::android::RpcState; - explicit PrivateAccessor(const BpBinder* binder) : mBinder(binder) {} + friend class ::android::IPCThreadState; + explicit PrivateAccessor(const BpBinder* binder) + : mBinder(binder), mMutableBinder(nullptr) {} + explicit PrivateAccessor(BpBinder* binder) : mBinder(binder), mMutableBinder(binder) {} - static sp create(int32_t handle) { return BpBinder::create(handle); } + static sp create(int32_t handle, std::function* postTask) { + return BpBinder::create(handle, postTask); + } static sp create(const sp& session, uint64_t address) { return BpBinder::create(session, address); } @@ -146,17 +157,22 @@ public: uint64_t rpcAddress() const { return mBinder->rpcAddress(); } const sp& rpcSession() const { return mBinder->rpcSession(); } + void onFrozenStateChanged(bool isFrozen) { mMutableBinder->onFrozenStateChanged(isFrozen); } const BpBinder* mBinder; + BpBinder* mMutableBinder; }; + LIBBINDER_EXPORTED const PrivateAccessor getPrivateAccessor() const { return PrivateAccessor(this); } + PrivateAccessor getPrivateAccessor() { return PrivateAccessor(this); } + private: friend PrivateAccessor; friend class sp; - static sp create(int32_t handle); + static sp create(int32_t handle, std::function* postTask); static sp create(const sp& session, uint64_t address); struct BinderHandle { @@ -176,10 +192,10 @@ private: BpBinder(BinderHandle&& handle, int32_t trackedUid); explicit BpBinder(RpcHandle&& handle); - virtual ~BpBinder(); - virtual void onFirstRef(); - virtual void onLastStrongRef(const void* id); - virtual bool onIncStrongAttempted(uint32_t flags, const void* id); + virtual ~BpBinder(); + virtual void onFirstRef(); + virtual void onLastStrongRef(const void* id); + virtual bool onIncStrongAttempted(uint32_t flags, const void* id); friend ::android::internal::Stability; @@ -192,30 +208,39 @@ private: uint32_t flags; }; - void reportOneDeath(const Obituary& obit); - bool isDescriptorCached() const; - - mutable RpcMutex mLock; - volatile int32_t mAlive; - volatile int32_t mObitsSent; - Vector* mObituaries; - ObjectManager mObjects; - mutable String16 mDescriptorCache; - int32_t mTrackedUid; - - static RpcMutex sTrackingLock; - static std::unordered_map sTrackingMap; - static int sNumTrackedUids; - static std::atomic_bool sCountByUidEnabled; - static binder_proxy_limit_callback sLimitCallback; - static uint32_t sBinderProxyCountHighWatermark; - static uint32_t sBinderProxyCountLowWatermark; - static bool sBinderProxyThrottleCreate; - static std::unordered_map sLastLimitCallbackMap; - static std::atomic sBinderProxyCount; - static std::atomic sBinderProxyCountWarned; - static binder_proxy_warning_callback sWarningCallback; - static uint32_t sBinderProxyCountWarningWatermark; + void onFrozenStateChanged(bool isFrozen); + + struct FrozenStateChange { + bool isFrozen = false; + Vector> callbacks; + bool initialStateReceived = false; + }; + + void reportOneDeath(const Obituary& obit); + bool isDescriptorCached() const; + + mutable RpcMutex mLock; + volatile int32_t mAlive; + volatile int32_t mObitsSent; + Vector* mObituaries; + std::unique_ptr mFrozen; + ObjectManager mObjects; + mutable String16 mDescriptorCache; + int32_t mTrackedUid; + + static RpcMutex sTrackingLock; + static std::unordered_map sTrackingMap; + static int sNumTrackedUids; + static std::atomic_bool sCountByUidEnabled; + static binder_proxy_limit_callback sLimitCallback; + static uint32_t sBinderProxyCountHighWatermark; + static uint32_t sBinderProxyCountLowWatermark; + static bool sBinderProxyThrottleCreate; + static std::unordered_map sLastLimitCallbackMap; + static std::atomic sBinderProxyCount; + static std::atomic sBinderProxyCountWarned; + static binder_proxy_warning_callback sWarningCallback; + static uint32_t sBinderProxyCountWarningWatermark; }; } // namespace android diff --git a/libs/binder/include/binder/Functional.h b/libs/binder/include/binder/Functional.h index 08e3b214da1e8a932d0f1e9f65e4f9aa76197be7..e153969963012fbcec4d4afca2587a517ee329d8 100644 --- a/libs/binder/include/binder/Functional.h +++ b/libs/binder/include/binder/Functional.h @@ -17,10 +17,37 @@ #pragma once #include -#include +#include namespace android::binder::impl { +template +class scope_guard; + +template +scope_guard make_scope_guard(F f); + +template +class scope_guard { +public: + inline ~scope_guard() { + if (f_.has_value()) std::move(f_.value())(); + } + inline void release() { f_.reset(); } + +private: + friend scope_guard android::binder::impl::make_scope_guard<>(F); + + inline scope_guard(F&& f) : f_(std::move(f)) {} + + std::optional f_; +}; + +template +inline scope_guard make_scope_guard(F f) { + return scope_guard(std::move(f)); +} + template constexpr void assert_small_callable() { // While this buffer (std::function::__func::__buf_) is an implementation detail generally not @@ -32,12 +59,6 @@ constexpr void assert_small_callable() { "Try using std::ref, but make sure lambda lives long enough to be called."); } -template -std::unique_ptr> make_scope_guard(F&& f) { - assert_small_callable(); - return {reinterpret_cast(true), std::bind(f)}; -} - template class SmallFunction : public std::function { public: diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h index 17248ce2894b2d24a4431c71bdab9b2e5a6435c5..1ed7c91de63ed82b5818c8447e24b20c6e340f9a 100644 --- a/libs/binder/include/binder/IBinder.h +++ b/libs/binder/include/binder/IBinder.h @@ -102,6 +102,10 @@ public: */ virtual const String16& getInterfaceDescriptor() const = 0; + /** + * Last known alive status, from last call. May be arbitrarily stale. + * May be incorrect if a service returns an incorrect status code. + */ virtual bool isBinderAlive() const = 0; virtual status_t pingBinder() = 0; virtual status_t dump(int fd, const Vector& args) = 0; @@ -198,9 +202,18 @@ public: virtual void binderDied(const wp& who) = 0; }; - #if defined(__clang__) - #pragma clang diagnostic pop - #endif + class FrozenStateChangeCallback : public virtual RefBase { + public: + enum class State { + FROZEN, + UNFROZEN, + }; + virtual void onStateChanged(const wp& who, State state) = 0; + }; + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif /** * Register the @a recipient for a notification if this binder @@ -249,6 +262,48 @@ public: uint32_t flags = 0, wp* outRecipient = nullptr) = 0; + /** + * addFrozenStateChangeCallback provides a callback mechanism to notify + * about process frozen/unfrozen events. Upon registration and any + * subsequent state changes, the callback is invoked with the latest process + * frozen state. + * + * If the listener process (the one using this API) is itself frozen, state + * change events might be combined into a single one with the latest state. + * (meaning 'frozen, unfrozen' might just be 'unfrozen'). This single event + * would then be delivered when the listener process becomes unfrozen. + * Similarly, if an event happens before the previous event is consumed, + * they might be combined. This means the callback might not be called for + * every single state change, so don't rely on this API to count how many + * times the state has changed. + * + * @note When all references to the binder are dropped, the callback is + * automatically removed. So, you must hold onto a binder in order to + * receive notifications about it. + * + * @note You will only receive freeze notifications for remote binders, as + * local binders by definition can't be frozen without you being frozen as + * well. Trying to use this function on a local binder will result in an + * INVALID_OPERATION code being returned and nothing happening. + * + * @note This binder always holds a weak reference to the callback. + * + * @note You will only receive a weak reference to the binder object. You + * should not try to promote this to a strong reference. (Nor should you + * need to, as there is nothing useful you can directly do with it now that + * it has passed on.) + */ + [[nodiscard]] status_t addFrozenStateChangeCallback( + const wp& callback); + + /** + * Remove a previously registered freeze callback. + * The @a callback will no longer be called if this object + * changes its frozen state. + */ + [[nodiscard]] status_t removeFrozenStateChangeCallback( + const wp& callback); + virtual bool checkSubclass(const void* subclassID) const; typedef void (*object_cleanup_func)(const void* id, void* obj, void* cleanupCookie); diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h index 09ab442c7d51bb6c62d72f4af7247100987daa37..9ef4e694dd0981bb6859c82de3690d05c0e79023 100644 --- a/libs/binder/include/binder/IPCThreadState.h +++ b/libs/binder/include/binder/IPCThreadState.h @@ -174,6 +174,8 @@ public: LIBBINDER_EXPORTED static void expungeHandle(int32_t handle, IBinder* binder); LIBBINDER_EXPORTED status_t requestDeathNotification(int32_t handle, BpBinder* proxy); LIBBINDER_EXPORTED status_t clearDeathNotification(int32_t handle, BpBinder* proxy); + [[nodiscard]] status_t addFrozenStateChangeCallback(int32_t handle, BpBinder* proxy); + [[nodiscard]] status_t removeFrozenStateChangeCallback(int32_t handle, BpBinder* proxy); LIBBINDER_EXPORTED static void shutdown(); @@ -210,13 +212,14 @@ private: IPCThreadState(); ~IPCThreadState(); - status_t sendReply(const Parcel& reply, uint32_t flags); - status_t waitForResponse(Parcel* reply, status_t* acquireResult = nullptr); - status_t talkWithDriver(bool doReceive = true); - status_t writeTransactionData(int32_t cmd, uint32_t binderFlags, int32_t handle, uint32_t code, - const Parcel& data, status_t* statusBuffer); - status_t getAndExecuteCommand(); - status_t executeCommand(int32_t command); + [[nodiscard]] status_t sendReply(const Parcel& reply, uint32_t flags); + [[nodiscard]] status_t waitForResponse(Parcel* reply, status_t* acquireResult = nullptr); + [[nodiscard]] status_t talkWithDriver(bool doReceive = true); + [[nodiscard]] status_t writeTransactionData(int32_t cmd, uint32_t binderFlags, int32_t handle, + uint32_t code, const Parcel& data, + status_t* statusBuffer); + [[nodiscard]] status_t getAndExecuteCommand(); + [[nodiscard]] status_t executeCommand(int32_t command); void processPendingDerefs(); void processPostWriteDerefs(); diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h index 5fb73079cbfc80361015b636cc7ade2a2a27a062..879f319c5ea5e6fb5a0b0fddf0f000f7bdeaca5b 100644 --- a/libs/binder/include/binder/IServiceManager.h +++ b/libs/binder/include/binder/IServiceManager.h @@ -17,14 +17,16 @@ #pragma once #include #include -#include +// Trusty has its own definition of socket APIs from trusty_ipc.h +#ifndef __TRUSTY__ +#include +#endif // __TRUSTY__ #include +#include #include namespace android { -// ---------------------------------------------------------------------- - /** * Service manager for C++ services. * @@ -216,6 +218,64 @@ LIBBINDER_EXPORTED bool checkCallingPermission(const String16& permission, int32 LIBBINDER_EXPORTED bool checkPermission(const String16& permission, pid_t pid, uid_t uid, bool logPermissionFailure = true); +// ---------------------------------------------------------------------- +// Trusty's definition of the socket APIs does not include sockaddr types +#ifndef __TRUSTY__ +typedef std::function + RpcSocketAddressProvider; + +typedef std::function(const String16& name)> RpcAccessorProvider; + +class AccessorProvider; + +/** + * Register an accessor provider for the service manager APIs. + * + * \param provider callback that generates Accessors. + * + * \return A pointer used as a recept for the successful addition of the + * AccessorProvider. This is needed to unregister it later. + */ +[[nodiscard]] LIBBINDER_EXPORTED std::weak_ptr addAccessorProvider( + RpcAccessorProvider&& providerCallback); + +/** + * Remove an accessor provider using the pointer provided by addAccessorProvider + * along with the cookie pointer that was used. + * + * \param provider cookie that was returned by addAccessorProvider to keep track + * of this instance. + */ +[[nodiscard]] LIBBINDER_EXPORTED status_t +removeAccessorProvider(std::weak_ptr provider); + +/** + * Create an Accessor associated with a service that can create a socket connection based + * on the connection info from the supplied RpcSocketAddressProvider. + * + * \param instance name of the service that this Accessor is associated with + * \param connectionInfoProvider a callback that returns connection info for + * connecting to the service. + * \return the binder of the IAccessor implementation from libbinder + */ +LIBBINDER_EXPORTED sp createAccessor(const String16& instance, + RpcSocketAddressProvider&& connectionInfoProvider); + +/** + * Check to make sure this binder is the expected binder that is an IAccessor + * associated with a specific instance. + * + * This helper function exists to avoid adding the IAccessor type to + * libbinder_ndk. + * + * \param instance name of the service that this Accessor should be associated with + * \param binder to validate + * + * \return OK if the binder is an IAccessor for `instance` + */ +LIBBINDER_EXPORTED status_t validateAccessor(const String16& instance, const sp& binder); +#endif // __TRUSTY__ + #ifndef __ANDROID__ // Create an IServiceManager that delegates the service manager on the device via adb. // This is can be set as the default service manager at program start, so that diff --git a/libs/gui/include/gui/LayerCaptureArgs.h b/libs/binder/include/binder/IServiceManagerFFI.h similarity index 58% rename from libs/gui/include/gui/LayerCaptureArgs.h rename to libs/binder/include/binder/IServiceManagerFFI.h index fae2bcc78725752dbff2f52a065be854aa5d5235..753735506ca2ff18b1f2c482492978d2b78b88b2 100644 --- a/libs/gui/include/gui/LayerCaptureArgs.h +++ b/libs/binder/include/binder/IServiceManagerFFI.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 The Android Open Source Project + * Copyright (C) 2024 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. @@ -13,22 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #pragma once -#include -#include - -#include - -namespace android::gui { +#include -struct LayerCaptureArgs : CaptureArgs { - sp layerHandle; - bool childrenOnly{false}; +namespace android::impl { - status_t writeToParcel(Parcel* output) const override; - status_t readFromParcel(const Parcel* input) override; -}; +LIBBINDER_EXPORTED sp +getJavaServicemanagerImplPrivateDoNotUseExceptInTheOnePlaceItIsUsed(); -}; // namespace android::gui +} // namespace android::impl diff --git a/libs/binder/include/binder/IServiceManagerUnitTestHelper.h b/libs/binder/include/binder/IServiceManagerUnitTestHelper.h new file mode 100644 index 0000000000000000000000000000000000000000..ff25163ddc5f1b5b540f003a94d3adbd0f29ba6a --- /dev/null +++ b/libs/binder/include/binder/IServiceManagerUnitTestHelper.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2024 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 +#include "IServiceManager.h" +namespace android { + +/** + * Encapsulate an AidlServiceManager in a CppBackendShim. Only used for testing. + */ +LIBBINDER_EXPORTED sp getServiceManagerShimFromAidlServiceManagerForTests( + const sp& sm); + +} // namespace android \ No newline at end of file diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h index a46663867c58176b6df86edd7a3f330f94582e7b..21bfd42fcc7343580accab212b660828db048d60 100644 --- a/libs/binder/include/binder/ProcessState.h +++ b/libs/binder/include/binder/ProcessState.h @@ -23,6 +23,9 @@ #include +#include +#include +#include #include // --------------------------------------------------------------------------- @@ -130,6 +133,7 @@ public: enum class DriverFeature { ONEWAY_SPAM_DETECTION, EXTENDED_ERROR, + FREEZE_NOTIFICATION, }; // Determine whether a feature is supported by the binder driver. LIBBINDER_EXPORTED static bool isDriverFeatureEnabled(const DriverFeature feature); @@ -162,30 +166,31 @@ private: int mDriverFD; void* mVMStart; - // Protects thread count and wait variables below. - mutable pthread_mutex_t mThreadCountLock; - // Broadcast whenever mWaitingForThreads > 0 - pthread_cond_t mThreadCountDecrement; + mutable std::mutex mOnThreadAvailableLock; + std::condition_variable mOnThreadAvailableCondVar; + // Number of threads waiting on `mOnThreadAvailableCondVar`. + std::atomic_int64_t mOnThreadAvailableWaiting = 0; + // Number of binder threads current executing a command. - size_t mExecutingThreadsCount; - // Number of threads calling IPCThreadState::blockUntilThreadAvailable() - size_t mWaitingForThreads; + std::atomic_size_t mExecutingThreadsCount; // Maximum number of lazy threads to be started in the threadpool by the kernel. - size_t mMaxThreads; + std::atomic_size_t mMaxThreads; // Current number of threads inside the thread pool. - size_t mCurrentThreads; + std::atomic_size_t mCurrentThreads; // Current number of pooled threads inside the thread pool. - size_t mKernelStartedThreads; + std::atomic_size_t mKernelStartedThreads; // Time when thread pool was emptied - int64_t mStarvationStartTimeMs; + std::atomic mStarvationStartTime; + + static constexpr auto never = &std::chrono::steady_clock::time_point::min; mutable std::mutex mLock; // protects everything below. Vector mHandleToObject; bool mForked; - bool mThreadPoolStarted; - volatile int32_t mThreadPoolSeq; + std::atomic_bool mThreadPoolStarted; + std::atomic_int32_t mThreadPoolSeq; CallRestriction mCallRestriction; }; diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h index abea0fb40cbb8438947ab099de242368a467150e..c241d31623fec0477a2712be2eb9b8564e72be01 100644 --- a/libs/binder/include/binder/RpcServer.h +++ b/libs/binder/include/binder/RpcServer.h @@ -85,9 +85,12 @@ public: /** * Creates an RPC server binding to the given CID at the given port. + * + * Set |port| to VMADDR_PORT_ANY to pick an ephemeral port. In this case, |assignedPort| + * will be set to the picked port number, if it is not null. */ - [[nodiscard]] LIBBINDER_EXPORTED status_t setupVsockServer(unsigned int bindCid, - unsigned int port); + [[nodiscard]] LIBBINDER_EXPORTED status_t setupVsockServer(unsigned bindCid, unsigned port, + unsigned* assignedPort = nullptr); /** * Creates an RPC server at the current port using IPv4. diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h index 40102bb9f0223d9c75446ab825a011a8ca23c57e..af37bf29a407cc3e12e6790f4cba773a354e35cb 100644 --- a/libs/binder/include/binder/RpcSession.h +++ b/libs/binder/include/binder/RpcSession.h @@ -220,6 +220,12 @@ public: // internal only LIBBINDER_EXPORTED const std::unique_ptr& state() { return mRpcBinderState; } + /** + * Sets the session-specific root object. This is the object that will be used to attach + * the IAccessor binder to the RpcSession when a binder is set up via accessor. + */ + LIBBINDER_EXPORTED void setSessionSpecificRoot(const sp& sessionSpecificRoot); + private: friend sp; friend RpcServer; diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp index 26c228d9a44bbfa1896b18dd1c71ea9cf2dfe4bd..5f45cb2f07c641fd84b116e8ba6f7b12ef0f9d7c 100644 --- a/libs/binder/ndk/Android.bp +++ b/libs/binder/ndk/Android.bp @@ -230,12 +230,24 @@ cc_library_headers { }, apex_available: [ "//apex_available:platform", + "//apex_available:anyapex", "com.android.media", "com.android.media.swcodec", ], min_sdk_version: "29", } +// TODO: if you try to export libbinder_headers_platform_shared from libbinder_ndk.ndk, it will +// not select the NDK variant of libbinder_headers_platform_shared and instead, it will error +// that the NDK can't depend on glibc C++. +cc_library_headers { + name: "libbinder_headers_platform_shared_ndk", + export_include_dirs: ["include_cpp"], + sdk_version: "29", + min_sdk_version: "29", + visibility: [":__subpackages__"], +} + ndk_headers { name: "libbinder_ndk_headers", from: "include_ndk/android", @@ -246,23 +258,14 @@ ndk_headers { license: "NOTICE", } -// TODO(b/160624671): package with the aidl compiler -ndk_headers { - name: "libbinder_ndk_helper_headers", - from: "include_cpp/android", - to: "android", - srcs: [ - "include_cpp/android/*.h", - ], - license: "NOTICE", -} +// include_cpp are packaged in development/build/sdk.atree with the AIDL compiler ndk_library { name: "libbinder_ndk", symbol_file: "libbinder_ndk.map.txt", first_version: "29", export_header_libs: [ - "libbinder_ndk_headers", - "libbinder_ndk_helper_headers", + // used to be part of the NDK, platform things depend on it + "libbinder_headers_platform_shared_ndk", ], } diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h index 62738041bab2203d7e7e955dff9515782bd4fcd0..af56bf0da1c52dc0267983cbf143f082a6877881 100644 --- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h +++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h @@ -225,6 +225,8 @@ class BpCInterface : public INTERFACE { SpAIBinder asBinder() override final; + const SpAIBinder& asBinderReference() { return mBinder; } + bool isRemote() override final { return AIBinder_isRemote(mBinder.get()); } binder_status_t dump(int fd, const char** args, uint32_t numArgs) override { diff --git a/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h b/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h index d570eab9765459ed96236c4a383ec48f2c46d536..c1d0e9f9fe447b5a9638c81f675fbf3b2c476631 100644 --- a/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h +++ b/libs/binder/ndk/include_cpp/android/persistable_bundle_aidl.h @@ -25,14 +25,13 @@ // Include llndk-versioning.h only for vendor build as it is not available for NDK headers. #if defined(__ANDROID_VENDOR__) #include -#else // __ANDROID_VENDOR__ -#if defined(API_LEVEL_AT_LEAST) -// Redefine API_LEVEL_AT_LEAST here to replace the version to __ANDROID_API_FUTURE__ as a workaround -#undef API_LEVEL_AT_LEAST -#endif -// TODO(b/322384429) switch this __ANDROID_API_FUTURE__ to sdk_api_level when V is finalized +#elif !defined(API_LEVEL_AT_LEAST) +#if defined(__BIONIC__) #define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) \ - (__builtin_available(android __ANDROID_API_FUTURE__, *)) + (__builtin_available(android sdk_api_level, *)) +#else +#define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) (true) +#endif // __BIONIC__ #endif // __ANDROID_VENDOR__ namespace aidl::android::os { @@ -267,7 +266,7 @@ class PersistableBundle { } } - bool getBoolean(const std::string& key, bool* _Nonnull val) { + bool getBoolean(const std::string& key, bool* _Nonnull val) const { if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { return APersistableBundle_getBoolean(mPBundle, key.c_str(), val); } else { @@ -275,7 +274,7 @@ class PersistableBundle { } } - bool getInt(const std::string& key, int32_t* _Nonnull val) { + bool getInt(const std::string& key, int32_t* _Nonnull val) const { if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { return APersistableBundle_getInt(mPBundle, key.c_str(), val); } else { @@ -283,7 +282,7 @@ class PersistableBundle { } } - bool getLong(const std::string& key, int64_t* _Nonnull val) { + bool getLong(const std::string& key, int64_t* _Nonnull val) const { if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { return APersistableBundle_getLong(mPBundle, key.c_str(), val); } else { @@ -291,7 +290,7 @@ class PersistableBundle { } } - bool getDouble(const std::string& key, double* _Nonnull val) { + bool getDouble(const std::string& key, double* _Nonnull val) const { if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { return APersistableBundle_getDouble(mPBundle, key.c_str(), val); } else { @@ -303,7 +302,7 @@ class PersistableBundle { return (char*)malloc(bufferSizeBytes); } - bool getString(const std::string& key, std::string* _Nonnull val) { + bool getString(const std::string& key, std::string* _Nonnull val) const { if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { char* outString = nullptr; bool ret = APersistableBundle_getString(mPBundle, key.c_str(), &outString, @@ -321,7 +320,7 @@ class PersistableBundle { bool getVecInternal(int32_t (*_Nonnull getVec)(const APersistableBundle* _Nonnull, const char* _Nonnull, T* _Nullable, int32_t), const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, - std::vector* _Nonnull vec) { + std::vector* _Nonnull vec) const { if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { int32_t bytes = 0; // call first with nullptr to get required size in bytes @@ -343,28 +342,28 @@ class PersistableBundle { return false; } - bool getBooleanVector(const std::string& key, std::vector* _Nonnull vec) { + bool getBooleanVector(const std::string& key, std::vector* _Nonnull vec) const { if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { return getVecInternal(&APersistableBundle_getBooleanVector, mPBundle, key.c_str(), vec); } return false; } - bool getIntVector(const std::string& key, std::vector* _Nonnull vec) { + bool getIntVector(const std::string& key, std::vector* _Nonnull vec) const { if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { return getVecInternal(&APersistableBundle_getIntVector, mPBundle, key.c_str(), vec); } return false; } - bool getLongVector(const std::string& key, std::vector* _Nonnull vec) { + bool getLongVector(const std::string& key, std::vector* _Nonnull vec) const { if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { return getVecInternal(&APersistableBundle_getLongVector, mPBundle, key.c_str(), vec); } return false; } - bool getDoubleVector(const std::string& key, std::vector* _Nonnull vec) { + bool getDoubleVector(const std::string& key, std::vector* _Nonnull vec) const { if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { return getVecInternal(&APersistableBundle_getDoubleVector, mPBundle, key.c_str(), vec); @@ -375,7 +374,7 @@ class PersistableBundle { // Takes ownership of and frees the char** and its elements. // Creates a new set or vector based on the array of char*. template - T moveStringsInternal(char* _Nullable* _Nonnull strings, int32_t bufferSizeBytes) { + T moveStringsInternal(char* _Nullable* _Nonnull strings, int32_t bufferSizeBytes) const { if (strings && bufferSizeBytes > 0) { int32_t num = bufferSizeBytes / sizeof(char*); T ret; @@ -389,7 +388,7 @@ class PersistableBundle { return T(); } - bool getStringVector(const std::string& key, std::vector* _Nonnull vec) { + bool getStringVector(const std::string& key, std::vector* _Nonnull vec) const { if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { int32_t bytes = APersistableBundle_getStringVector(mPBundle, key.c_str(), nullptr, 0, &stringAllocator, nullptr); @@ -406,7 +405,7 @@ class PersistableBundle { return false; } - bool getPersistableBundle(const std::string& key, PersistableBundle* _Nonnull val) { + bool getPersistableBundle(const std::string& key, PersistableBundle* _Nonnull val) const { if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { APersistableBundle* bundle = nullptr; bool ret = APersistableBundle_getPersistableBundle(mPBundle, key.c_str(), &bundle); @@ -425,7 +424,7 @@ class PersistableBundle { int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, void* _Nullable), - const APersistableBundle* _Nonnull pBundle) { + const APersistableBundle* _Nonnull pBundle) const { // call first with nullptr to get required size in bytes int32_t bytes = getTypedKeys(pBundle, nullptr, 0, &stringAllocator, nullptr); if (bytes > 0) { @@ -438,84 +437,84 @@ class PersistableBundle { return {}; } - std::set getBooleanKeys() { + std::set getBooleanKeys() const { if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { return getKeys(&APersistableBundle_getBooleanKeys, mPBundle); } else { return {}; } } - std::set getIntKeys() { + std::set getIntKeys() const { if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { return getKeys(&APersistableBundle_getIntKeys, mPBundle); } else { return {}; } } - std::set getLongKeys() { + std::set getLongKeys() const { if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { return getKeys(&APersistableBundle_getLongKeys, mPBundle); } else { return {}; } } - std::set getDoubleKeys() { + std::set getDoubleKeys() const { if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { return getKeys(&APersistableBundle_getDoubleKeys, mPBundle); } else { return {}; } } - std::set getStringKeys() { + std::set getStringKeys() const { if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { return getKeys(&APersistableBundle_getStringKeys, mPBundle); } else { return {}; } } - std::set getBooleanVectorKeys() { + std::set getBooleanVectorKeys() const { if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { return getKeys(&APersistableBundle_getBooleanVectorKeys, mPBundle); } else { return {}; } } - std::set getIntVectorKeys() { + std::set getIntVectorKeys() const { if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { return getKeys(&APersistableBundle_getIntVectorKeys, mPBundle); } else { return {}; } } - std::set getLongVectorKeys() { + std::set getLongVectorKeys() const { if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { return getKeys(&APersistableBundle_getLongVectorKeys, mPBundle); } else { return {}; } } - std::set getDoubleVectorKeys() { + std::set getDoubleVectorKeys() const { if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { return getKeys(&APersistableBundle_getDoubleVectorKeys, mPBundle); } else { return {}; } } - std::set getStringVectorKeys() { + std::set getStringVectorKeys() const { if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { return getKeys(&APersistableBundle_getStringVectorKeys, mPBundle); } else { return {}; } } - std::set getPersistableBundleKeys() { + std::set getPersistableBundleKeys() const { if API_LEVEL_AT_LEAST(__ANDROID_API_V__, 202404) { return getKeys(&APersistableBundle_getPersistableBundleKeys, mPBundle); } else { return {}; } } - std::set getMonKeys() { + std::set getMonKeys() const { // :P return {"c(o,o)b", "c(o,o)b"}; } diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h index 2929bce89736672975d03c0aff32bdb1a8da9bed..72d255e816f33f4ecb8bffdf36c249a41a1d01b4 100644 --- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h +++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h @@ -771,7 +771,7 @@ const char* AIBinder_Class_getDescriptor(const AIBinder_Class* clazz) __INTRODUC * This provides a per-process-unique total ordering of binders where a null * AIBinder* object is considered to be before all other binder objects. * For instance, two binders refer to the same object in a local or remote - * process when both AIBinder_lt(a, b) and AIBinder(b, a) are false. This API + * process when both AIBinder_lt(a, b) and AIBinder_lt(b, a) are false. This API * might be used to insert and lookup binders in binary search trees. * * AIBinder* pointers themselves actually also create a per-process-unique total diff --git a/libs/binder/ndk/include_ndk/android/binder_status.h b/libs/binder/ndk/include_ndk/android/binder_status.h index 14edf2bfb6c486d1c130bb5c036d2d212aeebd48..e968bac5397acfd0ba7a1575086d864a2ba9b724 100644 --- a/libs/binder/ndk/include_ndk/android/binder_status.h +++ b/libs/binder/ndk/include_ndk/android/binder_status.h @@ -117,9 +117,9 @@ enum { }; /** - * One of the EXCEPTION_* types. + * One of the EX_* enumerators. * - * All unrecognized values are coerced into EXCEPTION_TRANSACTION_FAILED. + * All unrecognized values are coerced into EX_TRANSACTION_FAILED. * * These exceptions values are used by the SDK for parcelables. Also see Parcel.java. */ diff --git a/libs/binder/ndk/include_ndk/android/persistable_bundle.h b/libs/binder/ndk/include_ndk/android/persistable_bundle.h index 42ae15ae61fa2a3c56a18135d2328fd39219f247..1d516aea9db2445954fa856db0cec3658c2ef8eb 100644 --- a/libs/binder/ndk/include_ndk/android/persistable_bundle.h +++ b/libs/binder/ndk/include_ndk/android/persistable_bundle.h @@ -17,18 +17,16 @@ #pragma once #include -#if defined(__ANDROID_VENDOR__) -#include -#else -#if !defined(__INTRODUCED_IN_LLNDK) -#define __INTRODUCED_IN_LLNDK(level) __attribute__((annotate("introduced_in_llndk=" #level))) -#endif -#endif // __ANDROID_VENDOR__ #include #include #include #include +#ifndef __clang__ +#define _Nullable +#define _Nonnull +#endif + __BEGIN_DECLS /* @@ -78,8 +76,7 @@ typedef char* _Nullable (*_Nonnull APersistableBundle_stringAllocator)(int32_t s * * \return Pointer to a new APersistableBundle */ -APersistableBundle* _Nullable APersistableBundle_new() __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); +APersistableBundle* _Nullable APersistableBundle_new() __INTRODUCED_IN(__ANDROID_API_V__); /** * Create a new APersistableBundle based off an existing APersistableBundle. @@ -93,7 +90,7 @@ APersistableBundle* _Nullable APersistableBundle_new() __INTRODUCED_IN(__ANDROID * \return Pointer to a new APersistableBundle */ APersistableBundle* _Nullable APersistableBundle_dup(const APersistableBundle* _Nonnull pBundle) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Delete an APersistableBundle. This must always be called when finished using @@ -104,7 +101,7 @@ APersistableBundle* _Nullable APersistableBundle_dup(const APersistableBundle* _ * Available since API level 202404. */ void APersistableBundle_delete(APersistableBundle* _Nullable pBundle) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Check for equality of APersistableBundles. @@ -118,7 +115,7 @@ void APersistableBundle_delete(APersistableBundle* _Nullable pBundle) */ bool APersistableBundle_isEqual(const APersistableBundle* _Nonnull lhs, const APersistableBundle* _Nonnull rhs) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Read an APersistableBundle from an AParcel. @@ -137,7 +134,7 @@ bool APersistableBundle_isEqual(const APersistableBundle* _Nonnull lhs, */ binder_status_t APersistableBundle_readFromParcel( const AParcel* _Nonnull parcel, APersistableBundle* _Nullable* _Nonnull outPBundle) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Write an APersistableBundle to an AParcel. @@ -157,7 +154,7 @@ binder_status_t APersistableBundle_readFromParcel( */ binder_status_t APersistableBundle_writeToParcel(const APersistableBundle* _Nonnull pBundle, AParcel* _Nonnull parcel) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get the size of an APersistableBundle. This is the number of mappings in the @@ -170,7 +167,7 @@ binder_status_t APersistableBundle_writeToParcel(const APersistableBundle* _Nonn * \return number of mappings in the object */ int32_t APersistableBundle_size(const APersistableBundle* _Nonnull pBundle) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Erase any entries added with the provided key. @@ -183,7 +180,7 @@ int32_t APersistableBundle_size(const APersistableBundle* _Nonnull pBundle) * \return number of entries erased. Either 0 or 1. */ int32_t APersistableBundle_erase(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Put a boolean associated with the provided key. @@ -196,8 +193,7 @@ int32_t APersistableBundle_erase(APersistableBundle* _Nonnull pBundle, const cha * Available since API level 202404. */ void APersistableBundle_putBoolean(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, - bool val) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + bool val) __INTRODUCED_IN(__ANDROID_API_V__); /** * Put an int32_t associated with the provided key. @@ -210,8 +206,7 @@ void APersistableBundle_putBoolean(APersistableBundle* _Nonnull pBundle, const c * Available since API level 202404. */ void APersistableBundle_putInt(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, - int32_t val) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + int32_t val) __INTRODUCED_IN(__ANDROID_API_V__); /** * Put an int64_t associated with the provided key. @@ -224,8 +219,7 @@ void APersistableBundle_putInt(APersistableBundle* _Nonnull pBundle, const char* * Available since API level 202404. */ void APersistableBundle_putLong(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, - int64_t val) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + int64_t val) __INTRODUCED_IN(__ANDROID_API_V__); /** * Put a double associated with the provided key. @@ -238,8 +232,7 @@ void APersistableBundle_putLong(APersistableBundle* _Nonnull pBundle, const char * Available since API level 202404. */ void APersistableBundle_putDouble(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, - double val) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + double val) __INTRODUCED_IN(__ANDROID_API_V__); /** * Put a string associated with the provided key. @@ -253,8 +246,7 @@ void APersistableBundle_putDouble(APersistableBundle* _Nonnull pBundle, const ch * Available since API level 202404. */ void APersistableBundle_putString(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, - const char* _Nonnull val) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + const char* _Nonnull val) __INTRODUCED_IN(__ANDROID_API_V__); /** * Put a boolean vector associated with the provided key. @@ -270,8 +262,7 @@ void APersistableBundle_putString(APersistableBundle* _Nonnull pBundle, const ch */ void APersistableBundle_putBooleanVector(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, const bool* _Nonnull vec, - int32_t num) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + int32_t num) __INTRODUCED_IN(__ANDROID_API_V__); /** * Put an int32_t vector associated with the provided key. @@ -287,7 +278,7 @@ void APersistableBundle_putBooleanVector(APersistableBundle* _Nonnull pBundle, */ void APersistableBundle_putIntVector(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, const int32_t* _Nonnull vec, int32_t num) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Put an int64_t vector associated with the provided key. @@ -303,8 +294,7 @@ void APersistableBundle_putIntVector(APersistableBundle* _Nonnull pBundle, const */ void APersistableBundle_putLongVector(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, const int64_t* _Nonnull vec, - int32_t num) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + int32_t num) __INTRODUCED_IN(__ANDROID_API_V__); /** * Put a double vector associated with the provided key. @@ -320,8 +310,7 @@ void APersistableBundle_putLongVector(APersistableBundle* _Nonnull pBundle, */ void APersistableBundle_putDoubleVector(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, const double* _Nonnull vec, - int32_t num) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + int32_t num) __INTRODUCED_IN(__ANDROID_API_V__); /** * Put a string vector associated with the provided key. @@ -338,7 +327,7 @@ void APersistableBundle_putDoubleVector(APersistableBundle* _Nonnull pBundle, void APersistableBundle_putStringVector(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, const char* _Nullable const* _Nullable vec, int32_t num) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Put an APersistableBundle associated with the provided key. @@ -354,7 +343,7 @@ void APersistableBundle_putStringVector(APersistableBundle* _Nonnull pBundle, void APersistableBundle_putPersistableBundle(APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, const APersistableBundle* _Nonnull val) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get a boolean associated with the provided key. @@ -369,7 +358,7 @@ void APersistableBundle_putPersistableBundle(APersistableBundle* _Nonnull pBundl */ bool APersistableBundle_getBoolean(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, bool* _Nonnull val) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get an int32_t associated with the provided key. @@ -383,8 +372,7 @@ bool APersistableBundle_getBoolean(const APersistableBundle* _Nonnull pBundle, * \return true if a value exists for the provided key */ bool APersistableBundle_getInt(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, - int32_t* _Nonnull val) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + int32_t* _Nonnull val) __INTRODUCED_IN(__ANDROID_API_V__); /** * Get an int64_t associated with the provided key. @@ -399,7 +387,7 @@ bool APersistableBundle_getInt(const APersistableBundle* _Nonnull pBundle, const */ bool APersistableBundle_getLong(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, int64_t* _Nonnull val) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get a double associated with the provided key. @@ -414,7 +402,7 @@ bool APersistableBundle_getLong(const APersistableBundle* _Nonnull pBundle, */ bool APersistableBundle_getDouble(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, double* _Nonnull val) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get a string associated with the provided key. @@ -435,8 +423,7 @@ bool APersistableBundle_getDouble(const APersistableBundle* _Nonnull pBundle, int32_t APersistableBundle_getString(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, char* _Nullable* _Nonnull val, APersistableBundle_stringAllocator stringAllocator, - void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__); /** * Get a boolean vector associated with the provided key and place it in the @@ -463,7 +450,7 @@ int32_t APersistableBundle_getString(const APersistableBundle* _Nonnull pBundle, int32_t APersistableBundle_getBooleanVector(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, bool* _Nullable buffer, int32_t bufferSizeBytes) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get an int32_t vector associated with the provided key and place it in the @@ -489,8 +476,7 @@ int32_t APersistableBundle_getBooleanVector(const APersistableBundle* _Nonnull p */ int32_t APersistableBundle_getIntVector(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, int32_t* _Nullable buffer, - int32_t bufferSizeBytes) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + int32_t bufferSizeBytes) __INTRODUCED_IN(__ANDROID_API_V__); /** * Get an int64_t vector associated with the provided key and place it in the @@ -516,8 +502,8 @@ int32_t APersistableBundle_getIntVector(const APersistableBundle* _Nonnull pBund */ int32_t APersistableBundle_getLongVector(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, int64_t* _Nullable buffer, - int32_t bufferSizeBytes) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + int32_t bufferSizeBytes) + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get a double vector associated with the provided key and place it in the @@ -544,7 +530,7 @@ int32_t APersistableBundle_getLongVector(const APersistableBundle* _Nonnull pBun int32_t APersistableBundle_getDoubleVector(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, double* _Nullable buffer, int32_t bufferSizeBytes) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get a string vector associated with the provided key and place it in the @@ -581,7 +567,7 @@ int32_t APersistableBundle_getStringVector(const APersistableBundle* _Nonnull pB int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, void* _Nullable context) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get an APersistableBundle* associated with the provided key. @@ -600,7 +586,7 @@ int32_t APersistableBundle_getStringVector(const APersistableBundle* _Nonnull pB bool APersistableBundle_getPersistableBundle(const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key, APersistableBundle* _Nullable* _Nonnull outBundle) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -633,7 +619,7 @@ int32_t APersistableBundle_getBooleanKeys(const APersistableBundle* _Nonnull pBu int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, void* _Nullable context) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -664,8 +650,7 @@ int32_t APersistableBundle_getBooleanKeys(const APersistableBundle* _Nonnull pBu int32_t APersistableBundle_getIntKeys(const APersistableBundle* _Nonnull pBundle, char* _Nullable* _Nullable outKeys, int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, - void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -696,8 +681,7 @@ int32_t APersistableBundle_getIntKeys(const APersistableBundle* _Nonnull pBundle int32_t APersistableBundle_getLongKeys(const APersistableBundle* _Nonnull pBundle, char* _Nullable* _Nullable outKeys, int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, - void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -729,8 +713,8 @@ int32_t APersistableBundle_getDoubleKeys(const APersistableBundle* _Nonnull pBun char* _Nullable* _Nullable outKeys, int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, - void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + void* _Nullable context) + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -762,8 +746,8 @@ int32_t APersistableBundle_getStringKeys(const APersistableBundle* _Nonnull pBun char* _Nullable* _Nullable outKeys, int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, - void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + void* _Nullable context) + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -796,7 +780,7 @@ int32_t APersistableBundle_getBooleanVectorKeys(const APersistableBundle* _Nonnu int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, void* _Nullable context) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -829,7 +813,7 @@ int32_t APersistableBundle_getIntVectorKeys(const APersistableBundle* _Nonnull p int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, void* _Nullable context) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -862,7 +846,7 @@ int32_t APersistableBundle_getLongVectorKeys(const APersistableBundle* _Nonnull int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, void* _Nullable context) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -894,7 +878,7 @@ int32_t APersistableBundle_getDoubleVectorKeys(const APersistableBundle* _Nonnul int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, void* _Nullable context) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -927,7 +911,7 @@ int32_t APersistableBundle_getStringVectorKeys(const APersistableBundle* _Nonnul int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, void* _Nullable context) - __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + __INTRODUCED_IN(__ANDROID_API_V__); /** * Get all of the keys associated with this specific type and place it in the @@ -958,6 +942,6 @@ int32_t APersistableBundle_getStringVectorKeys(const APersistableBundle* _Nonnul int32_t APersistableBundle_getPersistableBundleKeys( const APersistableBundle* _Nonnull pBundle, char* _Nullable* _Nullable outKeys, int32_t bufferSizeBytes, APersistableBundle_stringAllocator stringAllocator, - void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__) __INTRODUCED_IN_LLNDK(202404); + void* _Nullable context) __INTRODUCED_IN(__ANDROID_API_V__); __END_DECLS diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h index 41b30a0a0f6c159c617c93a49c77bd91382a78a2..cc4943b9c340de7c27afca4538c9193f5ab11a56 100644 --- a/libs/binder/ndk/include_platform/android/binder_manager.h +++ b/libs/binder/ndk/include_platform/android/binder_manager.h @@ -18,7 +18,6 @@ #include #include -#include #include __BEGIN_DECLS @@ -257,8 +256,7 @@ void AServiceManager_getUpdatableApexName(const char* instance, void* context, * \return the result of dlopen of the specified HAL */ void* AServiceManager_openDeclaredPassthroughHal(const char* interface, const char* instance, - int flag) __INTRODUCED_IN(__ANDROID_API_V__) - __INTRODUCED_IN_LLNDK(202404); + int flag) __INTRODUCED_IN(__ANDROID_API_V__); /** * Prevent lazy services without client from shutting down their process diff --git a/libs/binder/ndk/include_platform/android/binder_process.h b/libs/binder/ndk/include_platform/android/binder_process.h index 68528e100417b34b66ea821927361f2f32787dc8..6aff994a155308db947afa993bc92e3e5285c456 100644 --- a/libs/binder/ndk/include_platform/android/binder_process.h +++ b/libs/binder/ndk/include_platform/android/binder_process.h @@ -47,8 +47,11 @@ void ABinderProcess_startThreadPool(void); * be called once before startThreadPool. The number of threads can never decrease. * * This count refers to the number of threads that will be created lazily by the kernel, in - * addition to the threads created by ABinderProcess_startThreadPool or - * ABinderProcess_joinThreadPool. + * addition to the single threads created by ABinderProcess_startThreadPool (+1) or + * ABinderProcess_joinThreadPool (+1). Note: ABinderProcess_startThreadPool starts a thread + * itself, but it also enables up to the number of threads passed to this function to start. + * This function does not start any threads itself; it only configures + * ABinderProcess_startThreadPool. * * Do not use this from a library. Apps setup their own threadpools, and otherwise, the main * function should be responsible for configuring the threadpool for the entire application. @@ -63,8 +66,8 @@ bool ABinderProcess_setThreadPoolMaxThreadCount(uint32_t numThreads); bool ABinderProcess_isThreadPoolStarted(void); /** * This adds the current thread to the threadpool. This thread will be in addition to the thread - * started by ABinderProcess_startThreadPool and the lazy kernel-started threads specified by - * ABinderProcess_setThreadPoolMaxThreadCount. + * configured with ABinderProcess_setThreadPoolMaxThreadCount and started with + * ABinderProcess_startThreadPool. * * Do not use this from a library. Apps setup their own threadpools, and otherwise, the main * function should be responsible for configuring the threadpool for the entire application. diff --git a/libs/binder/ndk/persistable_bundle.cpp b/libs/binder/ndk/persistable_bundle.cpp index 9b6877daed8384765253ab1f78e5f6add843f181..afa032ecfa2609a47f443322cbcddd2995bdbff7 100644 --- a/libs/binder/ndk/persistable_bundle.cpp +++ b/libs/binder/ndk/persistable_bundle.cpp @@ -17,11 +17,12 @@ #include #include #include -#include #include #include +#include "persistable_bundle_internal.h" + __BEGIN_DECLS struct APersistableBundle { diff --git a/libs/binder/ndk/service_manager.cpp b/libs/binder/ndk/service_manager.cpp index 4436dbeed7bad27b57bc42b064a1924639738f3d..d6ac4acc2949d5f6af7cc288022249665b3bbde1 100644 --- a/libs/binder/ndk/service_manager.cpp +++ b/libs/binder/ndk/service_manager.cpp @@ -18,6 +18,7 @@ #include #include +#include "../Utils.h" #include "ibinder_internal.h" #include "status_internal.h" @@ -89,7 +90,9 @@ AIBinder* AServiceManager_getService(const char* instance) { } sp sm = defaultServiceManager(); + LIBBINDER_IGNORE("-Wdeprecated-declarations") sp binder = sm->getService(String16(instance)); + LIBBINDER_IGNORE_END() sp ret = ABpBinder::lookupOrCreateFromBinder(binder); AIBinder_incStrong(ret.get()); diff --git a/libs/binder/ndk/tests/Android.bp b/libs/binder/ndk/tests/Android.bp index 8fb755cdac563dd31e1eceab59576424b7aedeae..c61a16413b50f0a157e945f4c5182b5f09eb44cd 100644 --- a/libs/binder/ndk/tests/Android.bp +++ b/libs/binder/ndk/tests/Android.bp @@ -34,6 +34,11 @@ cc_defaults { cflags: [ "-O0", "-g", + "-Wall", + "-Wextra", + "-Wextra-semi", + "-Werror", + "-Winconsistent-missing-override", ], } diff --git a/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp b/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp index 43b2cb8577c2ca34d84cff20f41cdd0c4581f176..66be94f5b5671d5975fdc0f55211dd88294743b8 100644 --- a/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp +++ b/libs/binder/ndk/tests/binderVendorDoubleLoadTest.cpp @@ -18,8 +18,6 @@ #include #include #include -#include -#include #include #include #include @@ -30,13 +28,9 @@ #include #include #include - #include using namespace android; -using ::android::base::EndsWith; -using ::android::base::GetProperty; -using ::android::base::Split; using ::android::binder::Status; using ::android::internal::Stability; using ::ndk::ScopedAStatus; diff --git a/libs/binder/ndk/tests/iface.cpp b/libs/binder/ndk/tests/iface.cpp index ca927272f8f62f867a05634d683e060b26ad6190..08b857fab2832964db22297e047d32b4ffbaa748 100644 --- a/libs/binder/ndk/tests/iface.cpp +++ b/libs/binder/ndk/tests/iface.cpp @@ -20,6 +20,8 @@ #include +#include "../../Utils.h" + using ::android::sp; using ::android::wp; @@ -157,10 +159,9 @@ binder_status_t IFoo::addService(const char* instance) { } sp IFoo::getService(const char* instance, AIBinder** outBinder) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" + LIBBINDER_IGNORE("-Wdeprecated-declarations") AIBinder* binder = AServiceManager_getService(instance); // maybe nullptr -#pragma clang diagnostic pop + LIBBINDER_IGNORE_END() if (binder == nullptr) { return nullptr; } diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp index 471ab0cb563ebe4776e88142dfe464db38d4a701..3cd2b9a89107196b772acc745ae386e7ac86d7ad 100644 --- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -41,9 +42,11 @@ #include #include +#include "../Utils.h" #include "android/binder_ibinder.h" using namespace android; +using namespace std::chrono_literals; constexpr char kExistingNonNdkService[] = "SurfaceFlinger"; constexpr char kBinderNdkUnitTestService[] = "BinderNdkUnitTest"; @@ -52,7 +55,7 @@ constexpr char kForcePersistNdkUnitTestService[] = "ForcePersistNdkUnitTestServi constexpr char kActiveServicesNdkUnitTestService[] = "ActiveServicesNdkUnitTestService"; constexpr char kBinderNdkUnitTestServiceFlagged[] = "BinderNdkUnitTestFlagged"; -constexpr unsigned int kShutdownWaitTime = 11; +constexpr auto kShutdownWaitTime = 30s; constexpr uint64_t kContextTestValue = 0xb4e42fb4d9a1d715; class MyTestFoo : public IFoo { @@ -68,21 +71,21 @@ class MyTestFoo : public IFoo { }; class MyBinderNdkUnitTest : public aidl::BnBinderNdkUnitTest { - ndk::ScopedAStatus repeatInt(int32_t in, int32_t* out) { + ndk::ScopedAStatus repeatInt(int32_t in, int32_t* out) override { *out = in; return ndk::ScopedAStatus::ok(); } - ndk::ScopedAStatus takeInterface(const std::shared_ptr& empty) { + ndk::ScopedAStatus takeInterface(const std::shared_ptr& empty) override { (void)empty; return ndk::ScopedAStatus::ok(); } - ndk::ScopedAStatus forceFlushCommands() { + ndk::ScopedAStatus forceFlushCommands() override { // warning: this is assuming that libbinder_ndk is using the same copy // of libbinder that we are. android::IPCThreadState::self()->flushCommands(); return ndk::ScopedAStatus::ok(); } - ndk::ScopedAStatus getsRequestedSid(bool* out) { + ndk::ScopedAStatus getsRequestedSid(bool* out) override { const char* sid = AIBinder_getCallingSid(); std::cout << "Got security context: " << (sid ?: "null") << std::endl; *out = sid != nullptr; @@ -96,11 +99,11 @@ class MyBinderNdkUnitTest : public aidl::BnBinderNdkUnitTest { fsync(out); return STATUS_OK; } - ndk::ScopedAStatus forcePersist(bool persist) { + ndk::ScopedAStatus forcePersist(bool persist) override { AServiceManager_forceLazyServicesPersist(persist); return ndk::ScopedAStatus::ok(); } - ndk::ScopedAStatus setCustomActiveServicesCallback() { + ndk::ScopedAStatus setCustomActiveServicesCallback() override { AServiceManager_setActiveServicesCallback(activeServicesCallback, this); return ndk::ScopedAStatus::ok(); } @@ -251,12 +254,22 @@ int lazyService(const char* instance) { } bool isServiceRunning(const char* serviceName) { - AIBinder* binder = AServiceManager_checkService(serviceName); - if (binder == nullptr) { - return false; + static const sp sm(android::defaultServiceManager()); + const Vector services = sm->listServices(); + for (const auto service : services) { + if (service == String16(serviceName)) return true; } - AIBinder_decStrong(binder); + return false; +} +bool isServiceShutdownWithWait(const char* serviceName) { + LOG(INFO) << "About to check and wait for shutdown of " << std::string(serviceName); + const auto before = std::chrono::steady_clock::now(); + while (isServiceRunning(serviceName)) { + sleep(1); + const auto after = std::chrono::steady_clock::now(); + if (after - before >= kShutdownWaitTime) return false; + } return true; } @@ -341,10 +354,9 @@ TEST(NdkBinder, UnimplementedShell) { // libbinder across processes to the NDK service which doesn't implement // shell static const sp sm(android::defaultServiceManager()); -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" + LIBBINDER_IGNORE("-Wdeprecated-declarations") sp testService = sm->getService(String16(IFoo::kSomeInstanceName)); -#pragma clang diagnostic pop + LIBBINDER_IGNORE_END() Vector argsVec; EXPECT_EQ(OK, IBinder::shellCommand(testService, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, @@ -387,10 +399,9 @@ TEST(NdkBinder, GetTestServiceStressTest) { // checkService on it, since the other process serving it might not be started yet. { // getService, not waitForService, to take advantage of timeout -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" + LIBBINDER_IGNORE("-Wdeprecated-declarations") auto binder = ndk::SpAIBinder(AServiceManager_getService(IFoo::kSomeInstanceName)); -#pragma clang diagnostic pop + LIBBINDER_IGNORE_END() ASSERT_NE(nullptr, binder.get()); } @@ -424,7 +435,7 @@ TEST(NdkBinder, GetDeclaredInstances) { // At the time of writing this test, there is no good interface guaranteed // to be on all devices. Cuttlefish has light, so this will generally test // things. - EXPECT_EQ(count, hasLight ? 1 : 0); + EXPECT_EQ(count, hasLight ? 1u : 0u); } TEST(NdkBinder, GetLazyService) { @@ -450,8 +461,8 @@ TEST(NdkBinder, CheckLazyServiceShutDown) { service = nullptr; IPCThreadState::self()->flushCommands(); // Make sure the service is dead after some time of no use - sleep(kShutdownWaitTime); - ASSERT_EQ(nullptr, AServiceManager_checkService(kLazyBinderNdkUnitTestService)); + ASSERT_TRUE(isServiceShutdownWithWait(kLazyBinderNdkUnitTestService)) + << "Service failed to shut down"; } TEST(NdkBinder, ForcedPersistenceTest) { @@ -466,14 +477,12 @@ TEST(NdkBinder, ForcedPersistenceTest) { service = nullptr; IPCThreadState::self()->flushCommands(); - sleep(kShutdownWaitTime); - - bool isRunning = isServiceRunning(kForcePersistNdkUnitTestService); - if (i == 0) { - ASSERT_TRUE(isRunning) << "Service shut down when it shouldn't have."; + ASSERT_TRUE(isServiceRunning(kForcePersistNdkUnitTestService)) + << "Service shut down when it shouldn't have."; } else { - ASSERT_FALSE(isRunning) << "Service failed to shut down."; + ASSERT_TRUE(isServiceShutdownWithWait(kForcePersistNdkUnitTestService)) + << "Service failed to shut down"; } } } @@ -491,10 +500,7 @@ TEST(NdkBinder, ActiveServicesCallbackTest) { service = nullptr; IPCThreadState::self()->flushCommands(); - LOG(INFO) << "ActiveServicesCallbackTest about to sleep"; - sleep(kShutdownWaitTime); - - ASSERT_FALSE(isServiceRunning(kActiveServicesNdkUnitTestService)) + ASSERT_TRUE(isServiceShutdownWithWait(kActiveServicesNdkUnitTestService)) << "Service failed to shut down."; } @@ -514,7 +520,7 @@ void LambdaOnDeath(void* cookie) { // may reference other cookie members (*funcs->onDeath)(); -}; +} void LambdaOnUnlink(void* cookie) { auto funcs = static_cast(cookie); (*funcs->onUnlink)(); @@ -522,7 +528,7 @@ void LambdaOnUnlink(void* cookie) { // may reference other cookie members delete funcs; -}; +} TEST(NdkBinder, DeathRecipient) { using namespace std::chrono_literals; @@ -700,7 +706,7 @@ TEST(NdkBinder, DeathRecipientDropBinderOnDied) { void LambdaOnUnlinkMultiple(void* cookie) { auto funcs = static_cast(cookie); (*funcs->onUnlink)(); -}; +} TEST(NdkBinder, DeathRecipientMultipleLinks) { using namespace std::chrono_literals; @@ -732,7 +738,7 @@ TEST(NdkBinder, DeathRecipientMultipleLinks) { ndk::ScopedAIBinder_DeathRecipient recipient(AIBinder_DeathRecipient_new(LambdaOnDeath)); AIBinder_DeathRecipient_setOnUnlinked(recipient.get(), LambdaOnUnlinkMultiple); - for (int32_t i = 0; i < kNumberOfLinksToDeath; i++) { + for (uint32_t i = 0; i < kNumberOfLinksToDeath; i++) { EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder.get(), recipient.get(), static_cast(cookie))); } @@ -744,14 +750,13 @@ TEST(NdkBinder, DeathRecipientMultipleLinks) { EXPECT_TRUE(unlinkCv.wait_for(lockUnlink, 5s, [&] { return unlinkReceived; })) << "countdown: " << countdown; EXPECT_TRUE(unlinkReceived); - EXPECT_EQ(countdown, 0); + EXPECT_EQ(countdown, 0u); } TEST(NdkBinder, RetrieveNonNdkService) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" + LIBBINDER_IGNORE("-Wdeprecated-declarations") AIBinder* binder = AServiceManager_getService(kExistingNonNdkService); -#pragma clang diagnostic pop + LIBBINDER_IGNORE_END() ASSERT_NE(nullptr, binder); EXPECT_TRUE(AIBinder_isRemote(binder)); EXPECT_TRUE(AIBinder_isAlive(binder)); @@ -765,10 +770,9 @@ void OnBinderDeath(void* cookie) { } TEST(NdkBinder, LinkToDeath) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" + LIBBINDER_IGNORE("-Wdeprecated-declarations") AIBinder* binder = AServiceManager_getService(kExistingNonNdkService); -#pragma clang diagnostic pop + LIBBINDER_IGNORE_END() ASSERT_NE(nullptr, binder); AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(OnBinderDeath); @@ -798,10 +802,9 @@ TEST(NdkBinder, SetInheritRt) { } TEST(NdkBinder, SetInheritRtNonLocal) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" + LIBBINDER_IGNORE("-Wdeprecated-declarations") AIBinder* binder = AServiceManager_getService(kExistingNonNdkService); -#pragma clang diagnostic pop + LIBBINDER_IGNORE_END() ASSERT_NE(binder, nullptr); ASSERT_TRUE(AIBinder_isRemote(binder)); @@ -837,14 +840,13 @@ TEST(NdkBinder, GetServiceInProcess) { } TEST(NdkBinder, EqualityOfRemoteBinderPointer) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" + LIBBINDER_IGNORE("-Wdeprecated-declarations") AIBinder* binderA = AServiceManager_getService(kExistingNonNdkService); ASSERT_NE(nullptr, binderA); AIBinder* binderB = AServiceManager_getService(kExistingNonNdkService); ASSERT_NE(nullptr, binderB); -#pragma clang diagnostic pop + LIBBINDER_IGNORE_END() EXPECT_EQ(binderA, binderB); @@ -858,10 +860,9 @@ TEST(NdkBinder, ToFromJavaNullptr) { } TEST(NdkBinder, ABpBinderRefCount) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" + LIBBINDER_IGNORE("-Wdeprecated-declarations") AIBinder* binder = AServiceManager_getService(kExistingNonNdkService); -#pragma clang diagnostic pop + LIBBINDER_IGNORE_END() AIBinder_Weak* wBinder = AIBinder_Weak_new(binder); ASSERT_NE(nullptr, binder); @@ -884,10 +885,9 @@ TEST(NdkBinder, AddServiceMultipleTimes) { } TEST(NdkBinder, RequestedSidWorks) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" + LIBBINDER_IGNORE("-Wdeprecated-declarations") ndk::SpAIBinder binder(AServiceManager_getService(kBinderNdkUnitTestService)); -#pragma clang diagnostic pop + LIBBINDER_IGNORE_END() std::shared_ptr service = aidl::IBinderNdkUnitTest::fromBinder(binder); @@ -910,10 +910,9 @@ TEST(NdkBinder, SentAidlBinderCanBeDestroyed) { std::shared_ptr empty = ndk::SharedRefBase::make(); -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" + LIBBINDER_IGNORE("-Wdeprecated-declarations") ndk::SpAIBinder binder(AServiceManager_getService(kBinderNdkUnitTestService)); -#pragma clang diagnostic pop + LIBBINDER_IGNORE_END() std::shared_ptr service = aidl::IBinderNdkUnitTest::fromBinder(binder); @@ -934,14 +933,11 @@ TEST(NdkBinder, SentAidlBinderCanBeDestroyed) { } TEST(NdkBinder, ConvertToPlatformBinder) { - for (const ndk::SpAIBinder& binder : - {// remote -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - ndk::SpAIBinder(AServiceManager_getService(kBinderNdkUnitTestService)), -#pragma clang diagnostic pop - // local - ndk::SharedRefBase::make()->asBinder()}) { + LIBBINDER_IGNORE("-Wdeprecated-declarations") + ndk::SpAIBinder remoteBinder(AServiceManager_getService(kBinderNdkUnitTestService)); + LIBBINDER_IGNORE_END() + auto localBinder = ndk::SharedRefBase::make()->asBinder(); + for (const ndk::SpAIBinder& binder : {remoteBinder, localBinder}) { // convert to platform binder EXPECT_NE(binder, nullptr); sp platformBinder = AIBinder_toPlatformBinder(binder.get()); @@ -970,14 +966,11 @@ TEST(NdkBinder, ConvertToPlatformParcel) { } TEST(NdkBinder, GetAndVerifyScopedAIBinder_Weak) { - for (const ndk::SpAIBinder& binder : - {// remote -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - ndk::SpAIBinder(AServiceManager_getService(kBinderNdkUnitTestService)), -#pragma clang diagnostic pop - // local - ndk::SharedRefBase::make()->asBinder()}) { + LIBBINDER_IGNORE("-Wdeprecated-declarations") + ndk::SpAIBinder remoteBinder(AServiceManager_getService(kBinderNdkUnitTestService)); + LIBBINDER_IGNORE_END() + auto localBinder = ndk::SharedRefBase::make()->asBinder(); + for (const ndk::SpAIBinder& binder : {remoteBinder, localBinder}) { // get a const ScopedAIBinder_Weak and verify promote EXPECT_NE(binder.get(), nullptr); const ndk::ScopedAIBinder_Weak wkAIBinder = @@ -994,22 +987,22 @@ TEST(NdkBinder, GetAndVerifyScopedAIBinder_Weak) { class MyResultReceiver : public BnResultReceiver { public: - Mutex mMutex; - Condition mCondition; + std::mutex mMutex; + std::condition_variable mCondition; bool mHaveResult = false; int32_t mResult = 0; virtual void send(int32_t resultCode) { - AutoMutex _l(mMutex); + std::unique_lock _l(mMutex); mResult = resultCode; mHaveResult = true; - mCondition.signal(); + mCondition.notify_one(); } int32_t waitForResult() { - AutoMutex _l(mMutex); + std::unique_lock _l(mMutex); while (!mHaveResult) { - mCondition.wait(mMutex); + mCondition.wait(_l); } return mResult; } @@ -1046,7 +1039,7 @@ std::string shellCmdToString(sp unitTestService, const std::vector resultReceiver = new MyResultReceiver(); Vector argsVec; - for (int i = 0; i < args.size(); i++) { + for (size_t i = 0; i < args.size(); i++) { argsVec.add(String16(args[i])); } status_t error = IBinder::shellCommand(unitTestService, inFd[0], outFd[0], errFd[0], argsVec, @@ -1070,10 +1063,9 @@ std::string shellCmdToString(sp unitTestService, const std::vector sm(android::defaultServiceManager()); -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" + LIBBINDER_IGNORE("-Wdeprecated-declarations") sp testService = sm->getService(String16(kBinderNdkUnitTestService)); -#pragma clang diagnostic pop + LIBBINDER_IGNORE_END() EXPECT_EQ("", shellCmdToString(testService, {})); EXPECT_EQ("", shellCmdToString(testService, {"", ""})); @@ -1083,10 +1075,9 @@ TEST(NdkBinder, UseHandleShellCommand) { TEST(NdkBinder, FlaggedServiceAccessible) { static const sp sm(android::defaultServiceManager()); -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" + LIBBINDER_IGNORE("-Wdeprecated-declarations") sp testService = sm->getService(String16(kBinderNdkUnitTestServiceFlagged)); -#pragma clang diagnostic pop + LIBBINDER_IGNORE_END() ASSERT_NE(nullptr, testService); } diff --git a/libs/binder/rust/rpcbinder/Android.bp b/libs/binder/rust/rpcbinder/Android.bp index 2e463451f9f5241f87a86289f7eb6702ba0064cc..174fe8aba83ba352b5dd83e906608da4721eca02 100644 --- a/libs/binder/rust/rpcbinder/Android.bp +++ b/libs/binder/rust/rpcbinder/Android.bp @@ -32,6 +32,7 @@ rust_library { apex_available: [ "//apex_available:platform", "com.android.compos", + "com.android.microfuchsia", "com.android.uwb", "com.android.virt", ], @@ -60,6 +61,7 @@ rust_library { apex_available: [ "//apex_available:platform", "com.android.compos", + "com.android.microfuchsia", "com.android.uwb", "com.android.virt", ], @@ -93,6 +95,7 @@ rust_bindgen { apex_available: [ "//apex_available:platform", "com.android.compos", + "com.android.microfuchsia", "com.android.uwb", "com.android.virt", ], diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs index e34d31e58f8ffe8609dd58f48f9d09fe7e9a268d..9a252b853b342f0b0ad9ff80f40aba299f5ea6c9 100644 --- a/libs/binder/rust/src/binder.rs +++ b/libs/binder/rust/src/binder.rs @@ -768,14 +768,14 @@ macro_rules! declare_binder_interface { $interface:path[$descriptor:expr] { native: $native:ident($on_transact:path), proxy: $proxy:ident, - $(async: $async_interface:ident,)? + $(async: $async_interface:ident $(($try_into_local_async:ident))?,)? } } => { $crate::declare_binder_interface! { $interface[$descriptor] { native: $native($on_transact), proxy: $proxy {}, - $(async: $async_interface,)? + $(async: $async_interface $(($try_into_local_async))?,)? stability: $crate::binder_impl::Stability::default(), } } @@ -785,7 +785,7 @@ macro_rules! declare_binder_interface { $interface:path[$descriptor:expr] { native: $native:ident($on_transact:path), proxy: $proxy:ident, - $(async: $async_interface:ident,)? + $(async: $async_interface:ident $(($try_into_local_async:ident))?,)? stability: $stability:expr, } } => { @@ -793,7 +793,7 @@ macro_rules! declare_binder_interface { $interface[$descriptor] { native: $native($on_transact), proxy: $proxy {}, - $(async: $async_interface,)? + $(async: $async_interface $(($try_into_local_async))?,)? stability: $stability, } } @@ -805,7 +805,7 @@ macro_rules! declare_binder_interface { proxy: $proxy:ident { $($fname:ident: $fty:ty = $finit:expr),* }, - $(async: $async_interface:ident,)? + $(async: $async_interface:ident $(($try_into_local_async:ident))?,)? } } => { $crate::declare_binder_interface! { @@ -814,7 +814,7 @@ macro_rules! declare_binder_interface { proxy: $proxy { $($fname: $fty = $finit),* }, - $(async: $async_interface,)? + $(async: $async_interface $(($try_into_local_async))?,)? stability: $crate::binder_impl::Stability::default(), } } @@ -826,7 +826,7 @@ macro_rules! declare_binder_interface { proxy: $proxy:ident { $($fname:ident: $fty:ty = $finit:expr),* }, - $(async: $async_interface:ident,)? + $(async: $async_interface:ident $(($try_into_local_async:ident))?,)? stability: $stability:expr, } } => { @@ -838,7 +838,7 @@ macro_rules! declare_binder_interface { proxy: $proxy { $($fname: $fty = $finit),* }, - $(async: $async_interface,)? + $(async: $async_interface $(($try_into_local_async))?,)? stability: $stability, } } @@ -854,7 +854,7 @@ macro_rules! declare_binder_interface { $($fname:ident: $fty:ty = $finit:expr),* }, - $( async: $async_interface:ident, )? + $(async: $async_interface:ident $(($try_into_local_async:ident))?,)? stability: $stability:expr, } @@ -1043,6 +1043,24 @@ macro_rules! declare_binder_interface { } if ibinder.associate_class(<$native as $crate::binder_impl::Remotable>::get_class()) { + let service: std::result::Result<$crate::binder_impl::Binder<$native>, $crate::StatusCode> = + std::convert::TryFrom::try_from(ibinder.clone()); + $( + // This part is only generated if the user of the macro specifies that the + // trait has an `try_into_local_async` implementation. + if let Ok(service) = service { + if let Some(async_service) = $native::$try_into_local_async(service) { + // We were able to associate with our expected class, + // the service is local, and the local service is async. + return Ok(async_service); + } + // The service is local but not async. Fall back to treating it as a + // remote service. This means that calls to this local service have an + // extra performance cost due to serialization, but async handle to + // non-async server is considered a rare case, so this is okay. + } + )? + // Treat service as remote. return Ok($crate::Strong::new(Box::new(<$proxy as $crate::binder_impl::Proxy>::from_binder(ibinder)?))); } diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs index 33dfe19fe9e94122f9e999c6fd17dc22d6da8f39..7f70396882aa05977307c788e6d4238f22c9d2fa 100644 --- a/libs/binder/rust/src/parcel/parcelable.rs +++ b/libs/binder/rust/src/parcel/parcelable.rs @@ -1333,7 +1333,7 @@ mod tests { let vec = Vec::::deserialize(parcel.borrowed_ref()).unwrap(); assert_eq!(vec, [-128i8 as u8, 127, 42, -117i8 as u8]); - let u16s = [u16::max_value(), 12_345, 42, 117]; + let u16s = [u16::MAX, 12_345, 42, 117]; // SAFETY: start is less than the current size of the parcel data buffer, because we haven't // made it any shorter since we got the position. @@ -1348,7 +1348,7 @@ mod tests { } assert_eq!(parcel.read::().unwrap(), 4); // 4 items - assert_eq!(parcel.read::().unwrap(), 0xffff); // u16::max_value() + assert_eq!(parcel.read::().unwrap(), 0xffff); // u16::MAX assert_eq!(parcel.read::().unwrap(), 12345); // 12,345 assert_eq!(parcel.read::().unwrap(), 42); // 42 assert_eq!(parcel.read::().unwrap(), 117); // 117 @@ -1361,9 +1361,9 @@ mod tests { let vec = Vec::::deserialize(parcel.borrowed_ref()).unwrap(); - assert_eq!(vec, [u16::max_value(), 12_345, 42, 117]); + assert_eq!(vec, [u16::MAX, 12_345, 42, 117]); - let i16s = [i16::max_value(), i16::min_value(), 42, -117]; + let i16s = [i16::MAX, i16::MIN, 42, -117]; // SAFETY: start is less than the current size of the parcel data buffer, because we haven't // made it any shorter since we got the position. @@ -1378,8 +1378,8 @@ mod tests { } assert_eq!(parcel.read::().unwrap(), 4); // 4 items - assert_eq!(parcel.read::().unwrap(), 0x7fff); // i16::max_value() - assert_eq!(parcel.read::().unwrap(), 0x8000); // i16::min_value() + assert_eq!(parcel.read::().unwrap(), 0x7fff); // i16::MAX + assert_eq!(parcel.read::().unwrap(), 0x8000); // i16::MIN assert_eq!(parcel.read::().unwrap(), 42); // 42 assert_eq!(parcel.read::().unwrap(), 0xff8b); // -117 @@ -1391,9 +1391,9 @@ mod tests { let vec = Vec::::deserialize(parcel.borrowed_ref()).unwrap(); - assert_eq!(vec, [i16::max_value(), i16::min_value(), 42, -117]); + assert_eq!(vec, [i16::MAX, i16::MIN, 42, -117]); - let u32s = [u32::max_value(), 12_345, 42, 117]; + let u32s = [u32::MAX, 12_345, 42, 117]; // SAFETY: start is less than the current size of the parcel data buffer, because we haven't // made it any shorter since we got the position. @@ -1408,7 +1408,7 @@ mod tests { } assert_eq!(parcel.read::().unwrap(), 4); // 4 items - assert_eq!(parcel.read::().unwrap(), 0xffffffff); // u32::max_value() + assert_eq!(parcel.read::().unwrap(), 0xffffffff); // u32::MAX assert_eq!(parcel.read::().unwrap(), 12345); // 12,345 assert_eq!(parcel.read::().unwrap(), 42); // 42 assert_eq!(parcel.read::().unwrap(), 117); // 117 @@ -1421,9 +1421,9 @@ mod tests { let vec = Vec::::deserialize(parcel.borrowed_ref()).unwrap(); - assert_eq!(vec, [u32::max_value(), 12_345, 42, 117]); + assert_eq!(vec, [u32::MAX, 12_345, 42, 117]); - let i32s = [i32::max_value(), i32::min_value(), 42, -117]; + let i32s = [i32::MAX, i32::MIN, 42, -117]; // SAFETY: start is less than the current size of the parcel data buffer, because we haven't // made it any shorter since we got the position. @@ -1438,8 +1438,8 @@ mod tests { } assert_eq!(parcel.read::().unwrap(), 4); // 4 items - assert_eq!(parcel.read::().unwrap(), 0x7fffffff); // i32::max_value() - assert_eq!(parcel.read::().unwrap(), 0x80000000); // i32::min_value() + assert_eq!(parcel.read::().unwrap(), 0x7fffffff); // i32::MAX + assert_eq!(parcel.read::().unwrap(), 0x80000000); // i32::MIN assert_eq!(parcel.read::().unwrap(), 42); // 42 assert_eq!(parcel.read::().unwrap(), 0xffffff8b); // -117 @@ -1451,9 +1451,9 @@ mod tests { let vec = Vec::::deserialize(parcel.borrowed_ref()).unwrap(); - assert_eq!(vec, [i32::max_value(), i32::min_value(), 42, -117]); + assert_eq!(vec, [i32::MAX, i32::MIN, 42, -117]); - let u64s = [u64::max_value(), 12_345, 42, 117]; + let u64s = [u64::MAX, 12_345, 42, 117]; // SAFETY: start is less than the current size of the parcel data buffer, because we haven't // made it any shorter since we got the position. @@ -1469,9 +1469,9 @@ mod tests { let vec = Vec::::deserialize(parcel.borrowed_ref()).unwrap(); - assert_eq!(vec, [u64::max_value(), 12_345, 42, 117]); + assert_eq!(vec, [u64::MAX, 12_345, 42, 117]); - let i64s = [i64::max_value(), i64::min_value(), 42, -117]; + let i64s = [i64::MAX, i64::MIN, 42, -117]; // SAFETY: start is less than the current size of the parcel data buffer, because we haven't // made it any shorter since we got the position. @@ -1487,9 +1487,9 @@ mod tests { let vec = Vec::::deserialize(parcel.borrowed_ref()).unwrap(); - assert_eq!(vec, [i64::max_value(), i64::min_value(), 42, -117]); + assert_eq!(vec, [i64::MAX, i64::MIN, 42, -117]); - let f32s = [std::f32::NAN, std::f32::INFINITY, 1.23456789, std::f32::EPSILON]; + let f32s = [f32::NAN, f32::INFINITY, 1.23456789, f32::EPSILON]; // SAFETY: start is less than the current size of the parcel data buffer, because we haven't // made it any shorter since we got the position. @@ -1509,7 +1509,7 @@ mod tests { assert!(vec[0].is_nan()); assert_eq!(vec[1..], f32s[1..]); - let f64s = [std::f64::NAN, std::f64::INFINITY, 1.234567890123456789, std::f64::EPSILON]; + let f64s = [f64::NAN, f64::INFINITY, 1.234567890123456789, f64::EPSILON]; // SAFETY: start is less than the current size of the parcel data buffer, because we haven't // made it any shorter since we got the position. diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs index 340014aeaa8575ef07561b4f4b8246bfcd3b55ce..04f151755619eb045cc2c5fe6878881f41c03917 100644 --- a/libs/binder/rust/src/proxy.rs +++ b/libs/binder/rust/src/proxy.rs @@ -195,7 +195,7 @@ impl PartialOrd for SpIBinder { impl PartialEq for SpIBinder { fn eq(&self, other: &Self) -> bool { - ptr::eq(self.0.as_ptr(), other.0.as_ptr()) + self.cmp(other) == Ordering::Equal } } diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs index 15ae56fdd74001320d19ef08a93fd16fa5952159..5359832da18085da08b7db7c4f8d77a32f0d01de 100644 --- a/libs/binder/rust/tests/integration.rs +++ b/libs/binder/rust/tests/integration.rs @@ -182,7 +182,7 @@ declare_binder_interface! { proxy: BpTest { x: i32 = 100 }, - async: IATest, + async: IATest(try_into_local_async), } } @@ -323,6 +323,14 @@ impl IATest

    for Binder { } } +impl BnTest { + fn try_into_local_async( + me: Binder, + ) -> Option>> { + Some(binder::Strong::new(Box::new(me) as _)) + } +} + /// Trivial testing binder interface pub trait ITestSameDescriptor: Interface {} @@ -900,6 +908,19 @@ mod tests { assert_eq!(service.test().unwrap(), service_name); } + #[tokio::test] + async fn reassociate_rust_binder_async() { + let service_name = "testing_service"; + let service_ibinder = + BnTest::new_binder(TestService::new(service_name), BinderFeatures::default()) + .as_binder(); + + let service: Strong> = + service_ibinder.into_interface().expect("Could not reassociate the generic ibinder"); + + assert_eq!(service.test().await.unwrap(), service_name); + } + #[test] fn weak_binder_upgrade() { let service_name = "testing_service"; diff --git a/libs/binder/rust/tests/serialization.rs b/libs/binder/rust/tests/serialization.rs index 2b6c282530df14f0d1763865c633d93c04d60025..a902e967392e01e8d814f21794c5008618b6a0b2 100644 --- a/libs/binder/rust/tests/serialization.rs +++ b/libs/binder/rust/tests/serialization.rs @@ -124,7 +124,7 @@ fn on_transact( bindings::Transaction_TEST_BYTE => { assert_eq!(parcel.read::()?, 0); assert_eq!(parcel.read::()?, 1); - assert_eq!(parcel.read::()?, i8::max_value()); + assert_eq!(parcel.read::()?, i8::MAX); // SAFETY: Just reading an extern constant. assert_eq!(parcel.read::>()?, unsafe { bindings::TESTDATA_I8 }); // SAFETY: Just reading an extern constant. @@ -133,7 +133,7 @@ fn on_transact( reply.write(&0i8)?; reply.write(&1i8)?; - reply.write(&i8::max_value())?; + reply.write(&i8::MAX)?; // SAFETY: Just reading an extern constant. reply.write(&unsafe { bindings::TESTDATA_I8 }[..])?; // SAFETY: Just reading an extern constant. @@ -143,14 +143,14 @@ fn on_transact( bindings::Transaction_TEST_U16 => { assert_eq!(parcel.read::()?, 0); assert_eq!(parcel.read::()?, 1); - assert_eq!(parcel.read::()?, u16::max_value()); + assert_eq!(parcel.read::()?, u16::MAX); // SAFETY: Just reading an extern constant. assert_eq!(parcel.read::>()?, unsafe { bindings::TESTDATA_CHARS }); assert_eq!(parcel.read::>>()?, None); reply.write(&0u16)?; reply.write(&1u16)?; - reply.write(&u16::max_value())?; + reply.write(&u16::MAX)?; // SAFETY: Just reading an extern constant. reply.write(&unsafe { bindings::TESTDATA_CHARS }[..])?; reply.write(&(None as Option>))?; @@ -158,14 +158,14 @@ fn on_transact( bindings::Transaction_TEST_I32 => { assert_eq!(parcel.read::()?, 0); assert_eq!(parcel.read::()?, 1); - assert_eq!(parcel.read::()?, i32::max_value()); + assert_eq!(parcel.read::()?, i32::MAX); // SAFETY: Just reading an extern constant. assert_eq!(parcel.read::>()?, unsafe { bindings::TESTDATA_I32 }); assert_eq!(parcel.read::>>()?, None); reply.write(&0i32)?; reply.write(&1i32)?; - reply.write(&i32::max_value())?; + reply.write(&i32::MAX)?; // SAFETY: Just reading an extern constant. reply.write(&unsafe { bindings::TESTDATA_I32 }[..])?; reply.write(&(None as Option>))?; @@ -173,14 +173,14 @@ fn on_transact( bindings::Transaction_TEST_I64 => { assert_eq!(parcel.read::()?, 0); assert_eq!(parcel.read::()?, 1); - assert_eq!(parcel.read::()?, i64::max_value()); + assert_eq!(parcel.read::()?, i64::MAX); // SAFETY: Just reading an extern constant. assert_eq!(parcel.read::>()?, unsafe { bindings::TESTDATA_I64 }); assert_eq!(parcel.read::>>()?, None); reply.write(&0i64)?; reply.write(&1i64)?; - reply.write(&i64::max_value())?; + reply.write(&i64::MAX)?; // SAFETY: Just reading an extern constant. reply.write(&unsafe { bindings::TESTDATA_I64 }[..])?; reply.write(&(None as Option>))?; @@ -188,14 +188,14 @@ fn on_transact( bindings::Transaction_TEST_U64 => { assert_eq!(parcel.read::()?, 0); assert_eq!(parcel.read::()?, 1); - assert_eq!(parcel.read::()?, u64::max_value()); + assert_eq!(parcel.read::()?, u64::MAX); // SAFETY: Just reading an extern constant. assert_eq!(parcel.read::>()?, unsafe { bindings::TESTDATA_U64 }); assert_eq!(parcel.read::>>()?, None); reply.write(&0u64)?; reply.write(&1u64)?; - reply.write(&u64::max_value())?; + reply.write(&u64::MAX)?; // SAFETY: Just reading an extern constant. reply.write(&unsafe { bindings::TESTDATA_U64 }[..])?; reply.write(&(None as Option>))?; diff --git a/libs/binder/servicedispatcher.cpp b/libs/binder/servicedispatcher.cpp index 18b178b9b1b089d03d5101cccce72af617d712bb..be990657d5a61ec65cfb4a77fc02f0e69efb9f66 100644 --- a/libs/binder/servicedispatcher.cpp +++ b/libs/binder/servicedispatcher.cpp @@ -123,8 +123,11 @@ public: // We can't send BpBinder for regular binder over RPC. return android::binder::Status::fromStatusT(android::INVALID_OPERATION); } - android::binder::Status checkService(const std::string&, - android::sp*) override { + android::binder::Status getService2(const std::string&, android::os::Service*) override { + // We can't send BpBinder for regular binder over RPC. + return android::binder::Status::fromStatusT(android::INVALID_OPERATION); + } + android::binder::Status checkService(const std::string&, android::os::Service*) override { // We can't send BpBinder for regular binder over RPC. return android::binder::Status::fromStatusT(android::INVALID_OPERATION); } diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp index 4c7684ccb77e2aa9ac4880d41cf50b01fe49d6a8..0e653af707da554445a63d56f8d7694103b3264f 100644 --- a/libs/binder/tests/Android.bp +++ b/libs/binder/tests/Android.bp @@ -42,12 +42,39 @@ cc_test { defaults: ["binder_test_defaults"], header_libs: ["libbinder_headers"], srcs: ["binderDriverInterfaceTest.cpp"], + shared_libs: [ + "libbinder", + ], test_suites: [ - "device-tests", + "general-tests", "vts", ], } +cc_test { + name: "binderCacheUnitTest", + target: { + darwin: { + enabled: false, + }, + }, + srcs: [ + "binderCacheUnitTest.cpp", + ], + shared_libs: [ + "liblog", + "libbinder", + "libcutils", + "libutils", + ], + static_libs: [ + "libfakeservicemanager", + ], + defaults: ["libbinder_client_cache_flag"], + test_suites: ["general-tests"], + require_root: true, +} + // unit test only, which can run on host and doesn't use /dev/binder cc_test { name: "binderUnitTest", @@ -127,13 +154,14 @@ cc_test { "libbase", "libbinder", "liblog", + "libprocessgroup", "libutils", ], static_libs: [ "libgmock", ], test_suites: [ - "device-tests", + "general-tests", "vts", ], require_root: true, @@ -235,6 +263,16 @@ cc_defaults { "binder_test_defaults", ], + compile_multilib: "both", + multilib: { + lib32: { + suffix: "32", + }, + lib64: { + suffix: "64", + }, + }, + static_libs: [ "libbinder_test_utils", "libbinder_tls_static", @@ -267,7 +305,6 @@ cc_defaults { defaults: [ "binderRpcTest_common_defaults", ], - compile_multilib: "first", srcs: [ "binderRpcTest.cpp", @@ -692,7 +729,7 @@ cc_test { "libutils", ], test_suites: [ - "device-tests", + "general-tests", "vts", ], require_root: true, @@ -749,7 +786,7 @@ cc_test { ], test_suites: [ - "device-tests", + "general-tests", "vts", ], require_root: true, @@ -875,6 +912,7 @@ cc_defaults { enabled: false, }, }, + corpus: ["corpus/*"], fuzz_config: { cc: [ "smoreland@google.com", diff --git a/libs/binder/tests/BinderRpcTestServerConfig.aidl b/libs/binder/tests/BinderRpcTestServerConfig.aidl index b2e0ef21c75f627c051ff202fc8b7876abf98425..96550bca6bcc74de80239449c3305f1e9244ccdb 100644 --- a/libs/binder/tests/BinderRpcTestServerConfig.aidl +++ b/libs/binder/tests/BinderRpcTestServerConfig.aidl @@ -20,7 +20,6 @@ parcelable BinderRpcTestServerConfig { int socketType; int rpcSecurity; int serverVersion; - int vsockPort; int socketFd; // Inherited from the parent process. @utf8InCpp String addr; } diff --git a/libs/binder/tests/binderCacheUnitTest.cpp b/libs/binder/tests/binderCacheUnitTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..482d197688e8d9610e42e29854dd7c0b8b053819 --- /dev/null +++ b/libs/binder/tests/binderCacheUnitTest.cpp @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2024 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 + +#include +#include +#include +#include +#include +#include +#include "fakeservicemanager/FakeServiceManager.h" + +#include +#include + +using namespace android; + +#ifdef LIBBINDER_CLIENT_CACHE +constexpr bool kUseLibbinderCache = true; +#else +constexpr bool kUseLibbinderCache = false; +#endif + +// A service name which is in the static list of cachable services +const String16 kCachedServiceName = String16("isub"); + +#define EXPECT_OK(status) \ + do { \ + binder::Status stat = (status); \ + EXPECT_TRUE(stat.isOk()) << stat; \ + } while (false) + +const String16 kServerName = String16("binderCacheUnitTest"); + +class FooBar : public BBinder { +public: + status_t onTransact(uint32_t, const Parcel&, Parcel*, uint32_t) { + // exit the server + std::thread([] { exit(EXIT_FAILURE); }).detach(); + return OK; + } + void killServer(sp binder) { + Parcel data, reply; + binder->transact(0, data, &reply, 0); + } +}; + +class MockAidlServiceManager : public os::IServiceManagerDefault { +public: + MockAidlServiceManager() : innerSm() {} + + binder::Status checkService(const ::std::string& name, os::Service* _out) override { + sp binder = innerSm.getService(String16(name.c_str())); + *_out = os::Service::make(binder); + return binder::Status::ok(); + } + + binder::Status addService(const std::string& name, const sp& service, + bool allowIsolated, int32_t dumpPriority) override { + return binder::Status::fromStatusT( + innerSm.addService(String16(name.c_str()), service, allowIsolated, dumpPriority)); + } + + FakeServiceManager innerSm; +}; + +class LibbinderCacheTest : public ::testing::Test { +protected: + void SetUp() override { + sp sm = sp::make(); + mServiceManager = getServiceManagerShimFromAidlServiceManagerForTests(sm); + } + + void TearDown() override {} + +public: + void cacheAndConfirmCacheHit(const sp& binder1, const sp& binder2) { + // Add a service + EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder1)); + // Get the service. This caches it. + sp result = mServiceManager->checkService(kCachedServiceName); + ASSERT_EQ(binder1, result); + + // Add the different binder and replace the service. + // The cache should still hold the original binder. + EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder2)); + + result = mServiceManager->checkService(kCachedServiceName); + if (kUseLibbinderCache) { + // If cache is enabled, we should get the binder to Service Manager. + EXPECT_EQ(binder1, result); + } else { + // If cache is disabled, then we should get the newer binder + EXPECT_EQ(binder2, result); + } + } + + sp mServiceManager; +}; + +TEST_F(LibbinderCacheTest, AddLocalServiceAndConfirmCacheHit) { + sp binder1 = sp::make(); + sp binder2 = sp::make(); + + cacheAndConfirmCacheHit(binder1, binder2); +} + +TEST_F(LibbinderCacheTest, AddRemoteServiceAndConfirmCacheHit) { + sp binder1 = defaultServiceManager()->checkService(kServerName); + ASSERT_NE(binder1, nullptr); + sp binder2 = IInterface::asBinder(mServiceManager); + + cacheAndConfirmCacheHit(binder1, binder2); +} + +TEST_F(LibbinderCacheTest, RemoveFromCacheOnServerDeath) { + sp binder1 = defaultServiceManager()->checkService(kServerName); + FooBar foo = FooBar(); + + EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder1)); + + // Check Service, this caches the binder + sp result = mServiceManager->checkService(kCachedServiceName); + ASSERT_EQ(binder1, result); + + // Kill the server, this should remove from cache. + pid_t pid; + ASSERT_EQ(OK, binder1->getDebugPid(&pid)); + foo.killServer(binder1); + system(("kill -9 " + std::to_string(pid)).c_str()); + + sp binder2 = sp::make(); + + // Add new service with the same name. + // This will replace the service in FakeServiceManager. + EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder2)); + + // Confirm that new service is returned instead of old. + sp result2 = mServiceManager->checkService(kCachedServiceName); + ASSERT_EQ(binder2, result2); +} + +TEST_F(LibbinderCacheTest, NullBinderNotCached) { + sp binder1 = nullptr; + sp binder2 = sp::make(); + + // Check for a cacheble service which isn't registered. + // FakeServiceManager should return nullptr. + // This shouldn't be cached. + sp result = mServiceManager->checkService(kCachedServiceName); + ASSERT_EQ(binder1, result); + + // Add the same service + EXPECT_EQ(OK, mServiceManager->addService(kCachedServiceName, binder2)); + + // This should return the newly added service. + result = mServiceManager->checkService(kCachedServiceName); + EXPECT_EQ(binder2, result); +} + +TEST_F(LibbinderCacheTest, DoNotCacheServiceNotInList) { + sp binder1 = sp::make(); + sp binder2 = sp::make(); + String16 serviceName = String16("NewLibbinderCacheTest"); + // Add a service + EXPECT_EQ(OK, mServiceManager->addService(serviceName, binder1)); + // Get the service. This shouldn't caches it. + sp result = mServiceManager->checkService(serviceName); + ASSERT_EQ(binder1, result); + + // Add the different binder and replace the service. + EXPECT_EQ(OK, mServiceManager->addService(serviceName, binder2)); + + // Confirm that we get the new service + result = mServiceManager->checkService(serviceName); + EXPECT_EQ(binder2, result); +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + + if (fork() == 0) { + prctl(PR_SET_PDEATHSIG, SIGHUP); + + // Start a FooBar service and add it to the servicemanager. + sp server = new FooBar(); + defaultServiceManager()->addService(kServerName, server); + + IPCThreadState::self()->joinThreadPool(true); + exit(1); // should not reach + } + + status_t err = ProcessState::self()->setThreadPoolMaxThreadCount(3); + ProcessState::self()->startThreadPool(); + CHECK_EQ(ProcessState::self()->isThreadPoolStarted(), true); + CHECK_GT(ProcessState::self()->getThreadPoolMaxTotalThreadCount(), 0); + + auto binder = defaultServiceManager()->waitForService(kServerName); + CHECK_NE(nullptr, binder.get()); + return RUN_ALL_TESTS(); +} diff --git a/libs/binder/tests/binderClearBufTest.cpp b/libs/binder/tests/binderClearBufTest.cpp index 3230a3f90419547a55c88d9797fef55313e1df3e..63254cddd98e15cca885c87d087225d6ecf474a5 100644 --- a/libs/binder/tests/binderClearBufTest.cpp +++ b/libs/binder/tests/binderClearBufTest.cpp @@ -75,10 +75,9 @@ class FooBar : public BBinder { }; TEST(BinderClearBuf, ClearKernelBuffer) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" + LIBBINDER_IGNORE("-Wdeprecated-declarations") sp binder = defaultServiceManager()->getService(kServerName); -#pragma clang diagnostic pop + LIBBINDER_IGNORE_END() ASSERT_NE(nullptr, binder); std::string replyBuffer; diff --git a/libs/binder/tests/binderDriverInterfaceTest.cpp b/libs/binder/tests/binderDriverInterfaceTest.cpp index cf23a4658c5dd86ee86f697c915d1c9aac1688a5..af8286008f4f91012e4a630f6dd38d887543c3d8 100644 --- a/libs/binder/tests/binderDriverInterfaceTest.cpp +++ b/libs/binder/tests/binderDriverInterfaceTest.cpp @@ -19,11 +19,15 @@ #include #include +#include +#include #include #include -#include -#include #include +#include +#include + +#include "../binder_module.h" #define BINDER_DEV_NAME "/dev/binder" @@ -93,8 +97,9 @@ class BinderDriverInterfaceTest : public ::testing::Test { ret = ioctl(m_binderFd, cmd, arg); EXPECT_EQ(expect_ret, ret); if (ret < 0) { - if (errno != accept_errno) + if (errno != accept_errno) { EXPECT_EQ(expect_errno, errno); + } } } void binderTestIoctlErr2(int cmd, void *arg, int expect_errno, int accept_errno) { @@ -274,12 +279,15 @@ TEST_F(BinderDriverInterfaceTest, Transaction) { binderTestIoctl(BINDER_WRITE_READ, &bwr); } EXPECT_EQ(offsetof(typeof(br), pad), bwr.read_consumed); - if (bwr.read_consumed > offsetof(typeof(br), cmd0)) + if (bwr.read_consumed > offsetof(typeof(br), cmd0)) { EXPECT_EQ(BR_NOOP, br.cmd0); - if (bwr.read_consumed > offsetof(typeof(br), cmd1)) + } + if (bwr.read_consumed > offsetof(typeof(br), cmd1)) { EXPECT_EQ(BR_TRANSACTION_COMPLETE, br.cmd1); - if (bwr.read_consumed > offsetof(typeof(br), cmd2)) + } + if (bwr.read_consumed > offsetof(typeof(br), cmd2)) { EXPECT_EQ(BR_REPLY, br.cmd2); + } if (bwr.read_consumed >= offsetof(typeof(br), pad)) { EXPECT_EQ(0u, br.arg2.target.ptr); EXPECT_EQ(0u, br.arg2.cookie); @@ -360,6 +368,251 @@ TEST_F(BinderDriverInterfaceTest, RequestDeathNotification) { binderTestReadEmpty(); } +TEST_F(BinderDriverInterfaceTest, RequestFrozenNotification) { + if (!android::ProcessState::isDriverFeatureEnabled( + android::ProcessState::DriverFeature::FREEZE_NOTIFICATION)) { + GTEST_SKIP() << "Skipping test for kernels that support freeze notification"; + return; + } + binder_uintptr_t cookie = 1234; + struct { + uint32_t cmd0; + uint32_t arg0; + uint32_t cmd1; + struct binder_handle_cookie arg1; + } __attribute__((packed)) bc1 = { + .cmd0 = BC_INCREFS, + .arg0 = 0, + .cmd1 = BC_REQUEST_FREEZE_NOTIFICATION, + .arg1 = + { + .handle = 0, + .cookie = cookie, + }, + }; + struct { + uint32_t cmd0; + // Expecting a BR_FROZEN_BINDER since BC_REQUEST_FREEZE_NOTIFICATION + // above should lead to an immediate notification of the current state. + uint32_t cmd1; + struct binder_frozen_state_info arg1; + uint32_t pad[16]; + } __attribute__((packed)) br1; + struct { + uint32_t cmd2; + binder_uintptr_t arg2; + uint32_t cmd3; + struct binder_handle_cookie arg3; + uint32_t cmd4; + uint32_t arg4; + } __attribute__((packed)) bc2 = { + // Tell kernel that userspace has done handling BR_FROZEN_BINDER. + .cmd2 = BC_FREEZE_NOTIFICATION_DONE, + .arg2 = cookie, + .cmd3 = BC_CLEAR_FREEZE_NOTIFICATION, + .arg3 = + { + .handle = 0, + .cookie = cookie, + }, + .cmd4 = BC_DECREFS, + .arg4 = 0, + }; + struct { + uint32_t cmd2; + uint32_t cmd3; + binder_uintptr_t arg3; + uint32_t pad[16]; + } __attribute__((packed)) br2; + + struct binder_write_read bwr1 = binder_write_read(); + bwr1.write_buffer = (uintptr_t)&bc1; + bwr1.write_size = sizeof(bc1); + bwr1.read_buffer = (uintptr_t)&br1; + bwr1.read_size = sizeof(br1); + binderTestIoctl(BINDER_WRITE_READ, &bwr1); + EXPECT_EQ(sizeof(bc1), bwr1.write_consumed); + EXPECT_EQ(sizeof(br1) - sizeof(br1.pad), bwr1.read_consumed); + EXPECT_EQ(BR_NOOP, br1.cmd0); + ASSERT_EQ(BR_FROZEN_BINDER, br1.cmd1); + EXPECT_FALSE(br1.arg1.is_frozen); + + struct binder_write_read bwr2 = binder_write_read(); + bwr2.write_buffer = (uintptr_t)&bc2; + bwr2.write_size = sizeof(bc2); + bwr2.read_buffer = (uintptr_t)&br2; + bwr2.read_size = sizeof(br2); + binderTestIoctl(BINDER_WRITE_READ, &bwr2); + EXPECT_EQ(sizeof(bc2), bwr2.write_consumed); + EXPECT_EQ(sizeof(br2) - sizeof(br2.pad), bwr2.read_consumed); + EXPECT_EQ(BR_NOOP, br2.cmd2); + EXPECT_EQ(BR_CLEAR_FREEZE_NOTIFICATION_DONE, br2.cmd3); + EXPECT_EQ(cookie, br2.arg3); + + binderTestReadEmpty(); +} + +TEST_F(BinderDriverInterfaceTest, OverwritePendingFrozenNotification) { + if (!android::ProcessState::isDriverFeatureEnabled( + android::ProcessState::DriverFeature::FREEZE_NOTIFICATION)) { + GTEST_SKIP() << "Skipping test for kernels that support freeze notification"; + return; + } + binder_uintptr_t cookie = 1234; + struct { + uint32_t cmd0; + uint32_t arg0; + uint32_t cmd1; + struct binder_handle_cookie arg1; + uint32_t cmd2; + struct binder_handle_cookie arg2; + uint32_t cmd3; + uint32_t arg3; + } __attribute__((packed)) bc = { + .cmd0 = BC_INCREFS, + .arg0 = 0, + .cmd1 = BC_REQUEST_FREEZE_NOTIFICATION, + // This BC_REQUEST_FREEZE_NOTIFICATION should lead to a pending + // frozen notification inserted into the queue. + .arg1 = + { + .handle = 0, + .cookie = cookie, + }, + // Send BC_CLEAR_FREEZE_NOTIFICATION before the above frozen + // notification has a chance of being sent. The notification should + // be overwritten. Userspace is expected to only receive + // BR_CLEAR_FREEZE_NOTIFICATION_DONE. + .cmd2 = BC_CLEAR_FREEZE_NOTIFICATION, + .arg2 = + { + .handle = 0, + .cookie = cookie, + }, + .cmd3 = BC_DECREFS, + .arg3 = 0, + }; + struct { + uint32_t cmd0; + uint32_t cmd1; + binder_uintptr_t arg1; + uint32_t pad[16]; + } __attribute__((packed)) br; + struct binder_write_read bwr = binder_write_read(); + + bwr.write_buffer = (uintptr_t)&bc; + bwr.write_size = sizeof(bc); + bwr.read_buffer = (uintptr_t)&br; + bwr.read_size = sizeof(br); + + binderTestIoctl(BINDER_WRITE_READ, &bwr); + EXPECT_EQ(sizeof(bc), bwr.write_consumed); + EXPECT_EQ(sizeof(br) - sizeof(br.pad), bwr.read_consumed); + EXPECT_EQ(BR_NOOP, br.cmd0); + EXPECT_EQ(BR_CLEAR_FREEZE_NOTIFICATION_DONE, br.cmd1); + EXPECT_EQ(cookie, br.arg1); + binderTestReadEmpty(); +} + +TEST_F(BinderDriverInterfaceTest, ResendFrozenNotification) { + if (!android::ProcessState::isDriverFeatureEnabled( + android::ProcessState::DriverFeature::FREEZE_NOTIFICATION)) { + GTEST_SKIP() << "Skipping test for kernels that support freeze notification"; + return; + } + binder_uintptr_t cookie = 1234; + struct { + uint32_t cmd0; + uint32_t arg0; + uint32_t cmd1; + struct binder_handle_cookie arg1; + } __attribute__((packed)) bc1 = { + .cmd0 = BC_INCREFS, + .arg0 = 0, + .cmd1 = BC_REQUEST_FREEZE_NOTIFICATION, + .arg1 = + { + .handle = 0, + .cookie = cookie, + }, + }; + struct { + uint32_t cmd0; + uint32_t cmd1; + struct binder_frozen_state_info arg1; + uint32_t pad[16]; + } __attribute__((packed)) br1; + struct { + uint32_t cmd2; + struct binder_handle_cookie arg2; + } __attribute__((packed)) bc2 = { + // Clear the notification before acknowledging the in-flight + // BR_FROZEN_BINDER. Kernel should hold off sending + // BR_CLEAR_FREEZE_NOTIFICATION_DONE until the acknowledgement + // reaches kernel. + .cmd2 = BC_CLEAR_FREEZE_NOTIFICATION, + .arg2 = + { + .handle = 0, + .cookie = cookie, + }, + }; + struct { + uint32_t pad[16]; + } __attribute__((packed)) br2; + struct { + uint32_t cmd3; + binder_uintptr_t arg3; + uint32_t cmd4; + uint32_t arg4; + } __attribute__((packed)) bc3 = { + // Send the acknowledgement. Now the kernel should send out + // BR_CLEAR_FREEZE_NOTIFICATION_DONE. + .cmd3 = BC_FREEZE_NOTIFICATION_DONE, + .arg3 = cookie, + .cmd4 = BC_DECREFS, + .arg4 = 0, + }; + struct { + uint32_t cmd2; + uint32_t cmd3; + binder_uintptr_t arg3; + uint32_t pad[16]; + } __attribute__((packed)) br3; + + struct binder_write_read bwr1 = binder_write_read(); + bwr1.write_buffer = (uintptr_t)&bc1; + bwr1.write_size = sizeof(bc1); + bwr1.read_buffer = (uintptr_t)&br1; + bwr1.read_size = sizeof(br1); + binderTestIoctl(BINDER_WRITE_READ, &bwr1); + EXPECT_EQ(sizeof(bc1), bwr1.write_consumed); + EXPECT_EQ(sizeof(br1) - sizeof(br1.pad), bwr1.read_consumed); + EXPECT_EQ(BR_NOOP, br1.cmd0); + ASSERT_EQ(BR_FROZEN_BINDER, br1.cmd1); + EXPECT_FALSE(br1.arg1.is_frozen); + + struct binder_write_read bwr2 = binder_write_read(); + bwr2.write_buffer = (uintptr_t)&bc2; + bwr2.write_size = sizeof(bc2); + bwr2.read_buffer = (uintptr_t)&br2; + bwr2.read_size = sizeof(br2); + binderTestIoctlSuccessOrError(BINDER_WRITE_READ, &bwr2, EAGAIN); + binderTestReadEmpty(); + + struct binder_write_read bwr3 = binder_write_read(); + bwr3.write_buffer = (uintptr_t)&bc3; + bwr3.write_size = sizeof(bc3); + bwr3.read_buffer = (uintptr_t)&br3; + bwr3.read_size = sizeof(br3); + binderTestIoctl(BINDER_WRITE_READ, &bwr3); + EXPECT_EQ(sizeof(bc3), bwr3.write_consumed); + EXPECT_EQ(sizeof(br3) - sizeof(br3.pad), bwr3.read_consumed); + EXPECT_EQ(BR_CLEAR_FREEZE_NOTIFICATION_DONE, br3.cmd3); + EXPECT_EQ(cookie, br3.arg3); + binderTestReadEmpty(); +} + int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp index 00406edcf2bf48a73f9bcf204186ca1da3cb9b5a..bcab6decca28553801785f6025a00172b8517017 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -27,9 +27,9 @@ #include #include +#include #include #include -#include #include #include #include @@ -40,6 +40,8 @@ #include #include #include +#include +#include #include #include @@ -48,18 +50,17 @@ #include #include +#include "../Utils.h" #include "../binder_module.h" -#define ARRAY_SIZE(array) (sizeof array / sizeof array[0]) - using namespace android; using namespace android::binder::impl; using namespace std::string_literals; using namespace std::chrono_literals; using android::base::testing::HasValue; -using android::base::testing::Ok; using android::binder::Status; using android::binder::unique_fd; +using std::chrono_literals::operator""ms; using testing::ExplainMatchResult; using testing::Matcher; using testing::Not; @@ -118,6 +119,8 @@ enum BinderLibTestTranscationCode { BINDER_LIB_TEST_NOP_TRANSACTION_WAIT, BINDER_LIB_TEST_GETPID, BINDER_LIB_TEST_GETUID, + BINDER_LIB_TEST_LISTEN_FOR_FROZEN_STATE_CHANGE, + BINDER_LIB_TEST_CONSUME_STATE_CHANGE_EVENTS, BINDER_LIB_TEST_ECHO_VECTOR, BINDER_LIB_TEST_GET_NON_BLOCKING_FD, BINDER_LIB_TEST_REJECT_OBJECTS, @@ -218,10 +221,9 @@ class BinderLibTestEnv : public ::testing::Environment { sp sm = defaultServiceManager(); //printf("%s: pid %d, get service\n", __func__, m_pid); -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" + LIBBINDER_IGNORE("-Wdeprecated-declarations") m_server = sm->getService(binderLibTestServiceName); -#pragma clang diagnostic pop + LIBBINDER_IGNORE_END() ASSERT_TRUE(m_server != nullptr); //printf("%s: pid %d, get service done\n", __func__, m_pid); } @@ -251,6 +253,43 @@ class BinderLibTestEnv : public ::testing::Environment { sp m_server; }; +class TestFrozenStateChangeCallback : public IBinder::FrozenStateChangeCallback { +public: + BlockingQueue, State>> events; + + virtual void onStateChanged(const wp& who, State state) { + events.push(std::make_pair(who, state)); + } + + void ensureFrozenEventReceived() { + auto event = events.popWithTimeout(500ms); + ASSERT_TRUE(event.has_value()); + EXPECT_EQ(State::FROZEN, event->second); // isFrozen should be true + EXPECT_EQ(0u, events.size()); + } + + void ensureUnfrozenEventReceived() { + auto event = events.popWithTimeout(500ms); + ASSERT_TRUE(event.has_value()); + EXPECT_EQ(State::UNFROZEN, event->second); // isFrozen should be false + EXPECT_EQ(0u, events.size()); + } + + std::vector getAllAndClear() { + std::vector results; + while (true) { + auto event = events.popWithTimeout(0ms); + if (!event.has_value()) { + break; + } + results.push_back(event->second == State::FROZEN); + } + return results; + } + + sp binder; +}; + class BinderLibTest : public ::testing::Test { public: virtual void SetUp() { @@ -295,6 +334,51 @@ class BinderLibTest : public ::testing::Test { EXPECT_EQ(1, ret); } + bool checkFreezeSupport() { + std::ifstream freezer_file("/sys/fs/cgroup/uid_0/cgroup.freeze"); + // Pass test on devices where the cgroup v2 freezer is not supported + if (freezer_file.fail()) { + return false; + } + return IPCThreadState::self()->freeze(getpid(), false, 0) == NO_ERROR; + } + + bool checkFreezeAndNotificationSupport() { + if (!checkFreezeSupport()) { + return false; + } + return ProcessState::isDriverFeatureEnabled( + ProcessState::DriverFeature::FREEZE_NOTIFICATION); + } + + bool getBinderPid(int32_t* pid, sp server) { + Parcel data, replypid; + if (server->transact(BINDER_LIB_TEST_GETPID, data, &replypid) != NO_ERROR) { + ALOGE("BINDER_LIB_TEST_GETPID failed"); + return false; + } + *pid = replypid.readInt32(); + if (*pid <= 0) { + ALOGE("pid should be greater than zero"); + return false; + } + return true; + } + + void freezeProcess(int32_t pid) { + EXPECT_EQ(NO_ERROR, IPCThreadState::self()->freeze(pid, true, 1000)); + } + + void unfreezeProcess(int32_t pid) { + EXPECT_EQ(NO_ERROR, IPCThreadState::self()->freeze(pid, false, 0)); + } + + void removeCallbackAndValidateNoEvent(sp binder, + sp callback) { + EXPECT_THAT(binder->removeFrozenStateChangeCallback(callback), StatusEq(NO_ERROR)); + EXPECT_EQ(0u, callback->events.size()); + } + sp m_server; }; @@ -520,29 +604,18 @@ TEST_F(BinderLibTest, NopTransactionClear) { } TEST_F(BinderLibTest, Freeze) { - Parcel data, reply, replypid; - std::ifstream freezer_file("/sys/fs/cgroup/uid_0/cgroup.freeze"); - - // Pass test on devices where the cgroup v2 freezer is not supported - if (freezer_file.fail()) { - GTEST_SKIP(); + if (!checkFreezeSupport()) { + GTEST_SKIP() << "Skipping test for kernels that do not support proceess freezing"; return; } - + Parcel data, reply, replypid; EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_GETPID, data, &replypid), StatusEq(NO_ERROR)); int32_t pid = replypid.readInt32(); for (int i = 0; i < 10; i++) { EXPECT_EQ(NO_ERROR, m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION_WAIT, data, &reply, TF_ONE_WAY)); } - // Pass test on devices where BINDER_FREEZE ioctl is not supported - int ret = IPCThreadState::self()->freeze(pid, false, 0); - if (ret == -EINVAL) { - GTEST_SKIP(); - return; - } - EXPECT_EQ(NO_ERROR, ret); - + EXPECT_EQ(NO_ERROR, IPCThreadState::self()->freeze(pid, false, 0)); EXPECT_EQ(-EAGAIN, IPCThreadState::self()->freeze(pid, true, 0)); // b/268232063 - succeeds ~0.08% of the time @@ -568,7 +641,7 @@ TEST_F(BinderLibTest, Freeze) { TEST_F(BinderLibTest, SetError) { int32_t testValue[] = { 0, -123, 123 }; - for (size_t i = 0; i < ARRAY_SIZE(testValue); i++) { + for (size_t i = 0; i < countof(testValue); i++) { Parcel data, reply; data.writeInt32(testValue[i]); EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_SET_ERROR_TRANSACTION, data, &reply), @@ -599,8 +672,8 @@ TEST_F(BinderLibTest, IndirectGetId2) Parcel data, reply; int32_t serverId[3]; - data.writeInt32(ARRAY_SIZE(serverId)); - for (size_t i = 0; i < ARRAY_SIZE(serverId); i++) { + data.writeInt32(countof(serverId)); + for (size_t i = 0; i < countof(serverId); i++) { sp server; BinderLibTestBundle datai; @@ -618,7 +691,7 @@ TEST_F(BinderLibTest, IndirectGetId2) EXPECT_EQ(0, id); ASSERT_THAT(reply.readInt32(&count), StatusEq(NO_ERROR)); - EXPECT_EQ(ARRAY_SIZE(serverId), (size_t)count); + EXPECT_EQ(countof(serverId), (size_t)count); for (size_t i = 0; i < (size_t)count; i++) { BinderLibTestBundle replyi(&reply); @@ -638,8 +711,8 @@ TEST_F(BinderLibTest, IndirectGetId3) Parcel data, reply; int32_t serverId[3]; - data.writeInt32(ARRAY_SIZE(serverId)); - for (size_t i = 0; i < ARRAY_SIZE(serverId); i++) { + data.writeInt32(countof(serverId)); + for (size_t i = 0; i < countof(serverId); i++) { sp server; BinderLibTestBundle datai; BinderLibTestBundle datai2; @@ -664,7 +737,7 @@ TEST_F(BinderLibTest, IndirectGetId3) EXPECT_EQ(0, id); ASSERT_THAT(reply.readInt32(&count), StatusEq(NO_ERROR)); - EXPECT_EQ(ARRAY_SIZE(serverId), (size_t)count); + EXPECT_EQ(countof(serverId), (size_t)count); for (size_t i = 0; i < (size_t)count; i++) { int32_t counti; @@ -839,6 +912,199 @@ TEST_F(BinderLibTest, DeathNotificationThread) EXPECT_THAT(callback->getResult(), StatusEq(NO_ERROR)); } +TEST_F(BinderLibTest, ReturnErrorIfKernelDoesNotSupportFreezeNotification) { + if (ProcessState::isDriverFeatureEnabled(ProcessState::DriverFeature::FREEZE_NOTIFICATION)) { + GTEST_SKIP() << "Skipping test for kernels that support FREEZE_NOTIFICATION"; + return; + } + sp callback = sp::make(); + sp binder = addServer(); + ASSERT_NE(nullptr, binder); + ASSERT_EQ(nullptr, binder->localBinder()); + EXPECT_THAT(binder->addFrozenStateChangeCallback(callback), StatusEq(INVALID_OPERATION)); +} + +TEST_F(BinderLibTest, FrozenStateChangeNotificatiion) { + if (!checkFreezeAndNotificationSupport()) { + GTEST_SKIP() << "Skipping test for kernels that do not support FREEZE_NOTIFICATION"; + return; + } + sp callback = sp::make(); + sp binder = addServer(); + ASSERT_NE(nullptr, binder); + int32_t pid; + ASSERT_TRUE(getBinderPid(&pid, binder)); + + EXPECT_THAT(binder->addFrozenStateChangeCallback(callback), StatusEq(NO_ERROR)); + // Expect current state (unfrozen) to be delivered immediately. + callback->ensureUnfrozenEventReceived(); + // Check that the process hasn't died otherwise there's a risk of freezing + // the wrong process. + EXPECT_EQ(OK, binder->pingBinder()); + freezeProcess(pid); + callback->ensureFrozenEventReceived(); + unfreezeProcess(pid); + callback->ensureUnfrozenEventReceived(); + removeCallbackAndValidateNoEvent(binder, callback); +} + +TEST_F(BinderLibTest, AddFrozenCallbackWhenFrozen) { + if (!checkFreezeAndNotificationSupport()) { + GTEST_SKIP() << "Skipping test for kernels that do not support FREEZE_NOTIFICATION"; + return; + } + sp callback = sp::make(); + sp binder = addServer(); + ASSERT_NE(nullptr, binder); + int32_t pid; + ASSERT_TRUE(getBinderPid(&pid, binder)); + + // Check that the process hasn't died otherwise there's a risk of freezing + // the wrong process. + EXPECT_EQ(OK, binder->pingBinder()); + freezeProcess(pid); + // Add the callback while the target process is frozen. + EXPECT_THAT(binder->addFrozenStateChangeCallback(callback), StatusEq(NO_ERROR)); + callback->ensureFrozenEventReceived(); + unfreezeProcess(pid); + callback->ensureUnfrozenEventReceived(); + removeCallbackAndValidateNoEvent(binder, callback); + + // Check that the process hasn't died otherwise there's a risk of freezing + // the wrong process. + EXPECT_EQ(OK, binder->pingBinder()); + freezeProcess(pid); + unfreezeProcess(pid); + // Make sure no callback happens since the listener has been removed. + EXPECT_EQ(0u, callback->events.size()); +} + +TEST_F(BinderLibTest, NoFrozenNotificationAfterCallbackRemoval) { + if (!checkFreezeAndNotificationSupport()) { + GTEST_SKIP() << "Skipping test for kernels that do not support FREEZE_NOTIFICATION"; + return; + } + sp callback = sp::make(); + sp binder = addServer(); + ASSERT_NE(nullptr, binder); + int32_t pid; + ASSERT_TRUE(getBinderPid(&pid, binder)); + + EXPECT_THAT(binder->addFrozenStateChangeCallback(callback), StatusEq(NO_ERROR)); + callback->ensureUnfrozenEventReceived(); + removeCallbackAndValidateNoEvent(binder, callback); + + // Make sure no callback happens after the listener is removed. + freezeProcess(pid); + unfreezeProcess(pid); + EXPECT_EQ(0u, callback->events.size()); +} + +TEST_F(BinderLibTest, MultipleFrozenStateChangeCallbacks) { + if (!checkFreezeAndNotificationSupport()) { + GTEST_SKIP() << "Skipping test for kernels that do not support FREEZE_NOTIFICATION"; + return; + } + sp callback1 = sp::make(); + sp callback2 = sp::make(); + sp binder = addServer(); + ASSERT_NE(nullptr, binder); + int32_t pid; + ASSERT_TRUE(getBinderPid(&pid, binder)); + + EXPECT_THAT(binder->addFrozenStateChangeCallback(callback1), StatusEq(NO_ERROR)); + // Expect current state (unfrozen) to be delivered immediately. + callback1->ensureUnfrozenEventReceived(); + + EXPECT_THAT(binder->addFrozenStateChangeCallback(callback2), StatusEq(NO_ERROR)); + // Expect current state (unfrozen) to be delivered immediately. + callback2->ensureUnfrozenEventReceived(); + + freezeProcess(pid); + callback1->ensureFrozenEventReceived(); + callback2->ensureFrozenEventReceived(); + + removeCallbackAndValidateNoEvent(binder, callback1); + unfreezeProcess(pid); + EXPECT_EQ(0u, callback1->events.size()); + callback2->ensureUnfrozenEventReceived(); + removeCallbackAndValidateNoEvent(binder, callback2); + + freezeProcess(pid); + EXPECT_EQ(0u, callback2->events.size()); +} + +TEST_F(BinderLibTest, RemoveThenAddFrozenStateChangeCallbacks) { + if (!checkFreezeAndNotificationSupport()) { + GTEST_SKIP() << "Skipping test for kernels that do not support FREEZE_NOTIFICATION"; + return; + } + sp callback = sp::make(); + sp binder = addServer(); + ASSERT_NE(nullptr, binder); + int32_t pid; + ASSERT_TRUE(getBinderPid(&pid, binder)); + + EXPECT_THAT(binder->addFrozenStateChangeCallback(callback), StatusEq(NO_ERROR)); + // Expect current state (unfrozen) to be delivered immediately. + callback->ensureUnfrozenEventReceived(); + removeCallbackAndValidateNoEvent(binder, callback); + + EXPECT_THAT(binder->addFrozenStateChangeCallback(callback), StatusEq(NO_ERROR)); + callback->ensureUnfrozenEventReceived(); +} + +TEST_F(BinderLibTest, CoalesceFreezeCallbacksWhenListenerIsFrozen) { + if (!checkFreezeAndNotificationSupport()) { + GTEST_SKIP() << "Skipping test for kernels that do not support FREEZE_NOTIFICATION"; + return; + } + sp binder = addServer(); + sp listener = addServer(); + ASSERT_NE(nullptr, binder); + ASSERT_NE(nullptr, listener); + int32_t pid, listenerPid; + ASSERT_TRUE(getBinderPid(&pid, binder)); + ASSERT_TRUE(getBinderPid(&listenerPid, listener)); + + // Ask the listener process to register for state change callbacks. + { + Parcel data, reply; + data.writeStrongBinder(binder); + ASSERT_THAT(listener->transact(BINDER_LIB_TEST_LISTEN_FOR_FROZEN_STATE_CHANGE, data, + &reply), + StatusEq(NO_ERROR)); + } + // Freeze the listener process. + freezeProcess(listenerPid); + createProcessGroup(getuid(), listenerPid); + ASSERT_TRUE(SetProcessProfiles(getuid(), listenerPid, {"Frozen"})); + // Repeatedly flip the target process between frozen and unfrozen states. + for (int i = 0; i < 1000; i++) { + usleep(50); + unfreezeProcess(pid); + usleep(50); + freezeProcess(pid); + } + // Unfreeze the listener process. Now it should receive the frozen state + // change notifications. + ASSERT_TRUE(SetProcessProfiles(getuid(), listenerPid, {"Unfrozen"})); + unfreezeProcess(listenerPid); + // Wait for 500ms to give the process enough time to wake up and handle + // notifications. + usleep(500 * 1000); + { + std::vector events; + Parcel data, reply; + ASSERT_THAT(listener->transact(BINDER_LIB_TEST_CONSUME_STATE_CHANGE_EVENTS, data, &reply), + StatusEq(NO_ERROR)); + reply.readBoolVector(&events); + // There should only be one single state change notifications delievered. + ASSERT_EQ(1u, events.size()); + EXPECT_TRUE(events[0]); + } +} + TEST_F(BinderLibTest, PassFile) { int ret; int pipefd[2]; @@ -1985,6 +2251,26 @@ public: reply->writeInt32(param.sched_priority); return NO_ERROR; } + case BINDER_LIB_TEST_LISTEN_FOR_FROZEN_STATE_CHANGE: { + sp binder = data.readStrongBinder(); + frozenStateChangeCallback = sp::make(); + // Hold an strong pointer to the binder object so it doesn't go + // away. + frozenStateChangeCallback->binder = binder; + int ret = binder->addFrozenStateChangeCallback(frozenStateChangeCallback); + if (ret != NO_ERROR) { + return ret; + } + auto event = frozenStateChangeCallback->events.popWithTimeout(10ms); + if (!event.has_value()) { + return NOT_ENOUGH_DATA; + } + return NO_ERROR; + } + case BINDER_LIB_TEST_CONSUME_STATE_CHANGE_EVENTS: { + reply->writeBoolVector(frozenStateChangeCallback->getAllAndClear()); + return NO_ERROR; + } case BINDER_LIB_TEST_ECHO_VECTOR: { std::vector vector; auto err = data.readUint64Vector(&vector); @@ -2071,6 +2357,7 @@ private: sp m_callback; bool m_exitOnDestroy; std::mutex m_blockMutex; + sp frozenStateChangeCallback; }; int run_server(int index, int readypipefd, bool usePoll) @@ -2114,10 +2401,9 @@ int run_server(int index, int readypipefd, bool usePoll) if (index == 0) { ret = sm->addService(binderLibTestServiceName, testService); } else { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" + LIBBINDER_IGNORE("-Wdeprecated-declarations") sp server = sm->getService(binderLibTestServiceName); -#pragma clang diagnostic pop + LIBBINDER_IGNORE_END() Parcel data, reply; data.writeInt32(index); data.writeStrongBinder(testService); diff --git a/libs/binder/tests/binderRecordReplayTest.cpp b/libs/binder/tests/binderRecordReplayTest.cpp index b975fad2c969310f40d94602eed71923db73fed3..f867b42b1c683d7102a8793b4df02c5aaba8f422 100644 --- a/libs/binder/tests/binderRecordReplayTest.cpp +++ b/libs/binder/tests/binderRecordReplayTest.cpp @@ -99,12 +99,12 @@ public: GENERATE_GETTER_SETTER(SingleDataParcelableArray, std::vector); Status setFileDescriptor(unique_fd input) { - mFd = std::move(unique_fd(dup(input))); + mFd = unique_fd(dup(input)); return Status::ok(); } Status getFileDescriptor(unique_fd* output) { - *output = std::move(unique_fd(dup(mFd))); + *output = unique_fd(dup(mFd)); return Status::ok(); } unique_fd mFd; @@ -117,7 +117,7 @@ std::vector retrieveData(borrowed_fd fd) { std::vector buffer(fdStat.st_size); auto readResult = android::base::ReadFully(fd, buffer.data(), fdStat.st_size); EXPECT_TRUE(readResult != 0); - return std::move(buffer); + return buffer; } void replayFuzzService(const sp& binder, const RecordedTransaction& transaction) { @@ -387,8 +387,8 @@ TEST_F(BinderRecordReplayTest, ReplayFd) { // When fds are replayed, it will be replaced by /dev/null..reading from it should yield // null data - recordReplay(&IBinderRecordReplayTest::setFileDescriptor, std::move(unique_fd(dup(saved))), - &IBinderRecordReplayTest::getFileDescriptor, std::move(unique_fd(dup(changed)))); + recordReplay(&IBinderRecordReplayTest::setFileDescriptor, unique_fd(dup(saved)), + &IBinderRecordReplayTest::getFileDescriptor, unique_fd(dup(changed))); } int main(int argc, char** argv) { diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp index 19882ea1a9c6e64da90b99bfcc71a79b42897bbe..0ef200bcbe1ca7aa458733cb843b139766d4b7fd 100644 --- a/libs/binder/tests/binderRpcTest.cpp +++ b/libs/binder/tests/binderRpcTest.cpp @@ -19,6 +19,12 @@ #include #endif +#if defined(__LP64__) +#define TEST_FILE_SUFFIX "64" +#else +#define TEST_FILE_SUFFIX "32" +#endif + #include #include #include @@ -141,11 +147,6 @@ static std::string allocateSocketAddress() { return ret; }; -static unsigned int allocateVsockPort() { - static unsigned int vsockPort = 34567; - return vsockPort++; -} - static unique_fd initUnixSocket(std::string addr) { auto socket_addr = UnixSocketAddress(addr.c_str()); unique_fd fd(TEMP_FAILURE_RETRY(socket(socket_addr.addr()->sa_family, SOCK_STREAM, AF_UNIX))); @@ -264,7 +265,8 @@ std::unique_ptr BinderRpc::createRpcTestSocketServerProcessEtc( std::string path = GetExecutableDirectory(); auto servicePath = path + "/binder_rpc_test_service" + - (singleThreaded ? "_single_threaded" : "") + (noKernel ? "_no_kernel" : ""); + (singleThreaded ? "_single_threaded" : "") + (noKernel ? "_no_kernel" : "") + + TEST_FILE_SUFFIX; unique_fd bootstrapClientFd, socketFd; @@ -300,7 +302,6 @@ std::unique_ptr BinderRpc::createRpcTestSocketServerProcessEtc( serverConfig.socketType = static_cast(socketType); serverConfig.rpcSecurity = static_cast(rpcSecurity); serverConfig.serverVersion = serverVersion; - serverConfig.vsockPort = allocateVsockPort(); serverConfig.addr = addr; serverConfig.socketFd = socketFd.get(); for (auto mode : options.serverSupportedFileDescriptorTransportModes) { @@ -364,26 +365,57 @@ std::unique_ptr BinderRpc::createRpcTestSocketServerProcessEtc( session->setMaxOutgoingConnections(options.numOutgoingConnections); session->setFileDescriptorTransportMode(options.clientFileDescriptorTransportMode); + sockaddr_storage addr{}; + socklen_t addrLen = 0; + switch (socketType) { - case SocketType::PRECONNECTED: + case SocketType::PRECONNECTED: { + sockaddr_un addr_un{}; + addr_un.sun_family = AF_UNIX; + strcpy(addr_un.sun_path, serverConfig.addr.c_str()); + addr = *reinterpret_cast(&addr_un); + addrLen = sizeof(sockaddr_un); + status = session->setupPreconnectedClient({}, [=]() { return connectTo(UnixSocketAddress(serverConfig.addr.c_str())); }); - break; + } break; case SocketType::UNIX_RAW: - case SocketType::UNIX: + case SocketType::UNIX: { + sockaddr_un addr_un{}; + addr_un.sun_family = AF_UNIX; + strcpy(addr_un.sun_path, serverConfig.addr.c_str()); + addr = *reinterpret_cast(&addr_un); + addrLen = sizeof(sockaddr_un); + status = session->setupUnixDomainClient(serverConfig.addr.c_str()); - break; + } break; case SocketType::UNIX_BOOTSTRAP: status = session->setupUnixDomainSocketBootstrapClient( unique_fd(dup(bootstrapClientFd.get()))); break; - case SocketType::VSOCK: - status = session->setupVsockClient(VMADDR_CID_LOCAL, serverConfig.vsockPort); - break; - case SocketType::INET: - status = session->setupInetClient("127.0.0.1", serverInfo.port); - break; + case SocketType::VSOCK: { + sockaddr_vm addr_vm{ + .svm_family = AF_VSOCK, + .svm_port = static_cast(serverInfo.port), + .svm_cid = VMADDR_CID_LOCAL, + }; + addr = *reinterpret_cast(&addr_vm); + addrLen = sizeof(sockaddr_vm); + + status = session->setupVsockClient(VMADDR_CID_LOCAL, serverInfo.port); + } break; + case SocketType::INET: { + const std::string ip_addr = "127.0.0.1"; + sockaddr_in addr_in{}; + addr_in.sin_family = AF_INET; + addr_in.sin_port = htons(serverInfo.port); + inet_aton(ip_addr.c_str(), &addr_in.sin_addr); + addr = *reinterpret_cast(&addr_in); + addrLen = sizeof(sockaddr_in); + + status = session->setupInetClient(ip_addr.c_str(), serverInfo.port); + } break; case SocketType::TIPC: status = session->setupPreconnectedClient({}, [=]() { #ifdef BINDER_RPC_TO_TRUSTY_TEST @@ -412,7 +444,7 @@ std::unique_ptr BinderRpc::createRpcTestSocketServerProcessEtc( break; } LOG_ALWAYS_FATAL_IF(status != OK, "Could not connect: %s", statusToString(status).c_str()); - ret->sessions.push_back({session, session->getRootObject()}); + ret->sessions.push_back({session, session->getRootObject(), addr, addrLen}); } return ret; } @@ -422,7 +454,7 @@ TEST_P(BinderRpc, ThreadPoolGreaterThanEqualRequested) { GTEST_SKIP() << "This test requires multiple threads"; } - constexpr size_t kNumThreads = 10; + constexpr size_t kNumThreads = 5; auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads}); @@ -467,11 +499,11 @@ static void testThreadPoolOverSaturated(sp iface, size_t numCall EXPECT_GE(epochMsAfter, epochMsBefore + 2 * sleepMs); - // Potential flake, but make sure calls are handled in parallel. Due - // to past flakes, this only checks that the amount of time taken has - // some parallelism. Other tests such as ThreadPoolGreaterThanEqualRequested - // check this more exactly. - EXPECT_LE(epochMsAfter, epochMsBefore + (numCalls - 1) * sleepMs); + // b/272429574, b/365294257 + // This flakes too much to test. Parallelization is tested + // in ThreadPoolGreaterThanEqualRequested and other tests. + // Test to make sure calls are handled in parallel. + // EXPECT_LE(epochMsAfter, epochMsBefore + (numCalls - 1) * sleepMs); } TEST_P(BinderRpc, ThreadPoolOverSaturated) { @@ -483,8 +515,7 @@ TEST_P(BinderRpc, ThreadPoolOverSaturated) { constexpr size_t kNumCalls = kNumThreads + 3; auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads}); - // b/272429574 - below 500ms, the test fails - testThreadPoolOverSaturated(proc.rootIface, kNumCalls, 500 /*ms*/); + testThreadPoolOverSaturated(proc.rootIface, kNumCalls, 200 /*ms*/); } TEST_P(BinderRpc, ThreadPoolLimitOutgoing) { @@ -498,8 +529,7 @@ TEST_P(BinderRpc, ThreadPoolLimitOutgoing) { auto proc = createRpcTestSocketServerProcess( {.numThreads = kNumThreads, .numOutgoingConnections = kNumOutgoingConnections}); - // b/272429574 - below 500ms, the test fails - testThreadPoolOverSaturated(proc.rootIface, kNumCalls, 500 /*ms*/); + testThreadPoolOverSaturated(proc.rootIface, kNumCalls, 200 /*ms*/); } TEST_P(BinderRpc, ThreadingStressTest) { @@ -1126,6 +1156,139 @@ TEST_P(BinderRpc, Fds) { ASSERT_EQ(beforeFds, countFds()) << (system("ls -l /proc/self/fd/"), "fd leak?"); } +// TODO need to add IServiceManager.cpp/.h to libbinder_no_kernel +#ifdef BINDER_WITH_KERNEL_IPC + +class BinderRpcAccessor : public BinderRpc { + void SetUp() override { + if (serverSingleThreaded()) { + // This blocks on android::FdTrigger::triggerablePoll when attempting to set + // up the client RpcSession + GTEST_SKIP() << "Accessors are not supported for single threaded libbinder"; + } + if (rpcSecurity() == RpcSecurity::TLS) { + GTEST_SKIP() << "Accessors are not supported with TLS"; + // ... for now + } + + if (socketType() == SocketType::UNIX_BOOTSTRAP) { + GTEST_SKIP() << "Accessors do not support UNIX_BOOTSTRAP because no connection " + "information is known"; + } + if (socketType() == SocketType::TIPC) { + GTEST_SKIP() << "Accessors do not support TIPC because the socket transport is not " + "known in libbinder"; + } + BinderRpc::SetUp(); + } +}; + +inline void waitForExtraSessionCleanup(const BinderRpcTestProcessSession& proc) { + // Need to give the server some time to delete its RpcSession after our last + // reference is dropped, closing the connection. Check for up to 1 second, + // every 10 ms. + for (size_t i = 0; i < 100; i++) { + std::vector remoteCounts; + EXPECT_OK(proc.rootIface->countBinders(&remoteCounts)); + // We exect the original binder to still be alive, we just want to wait + // for this extra session to be cleaned up. + if (remoteCounts.size() == proc.proc->sessions.size()) break; + usleep(10000); + } +} + +TEST_P(BinderRpcAccessor, InjectAndGetServiceHappyPath) { + constexpr size_t kNumThreads = 10; + const String16 kInstanceName("super.cool.service/better_than_default"); + + auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads}); + EXPECT_EQ(OK, proc.rootBinder->pingBinder()); + + auto receipt = addAccessorProvider([&](const String16& name) -> sp { + return createAccessor(name, + [&](const String16& name, sockaddr* outAddr, + socklen_t addrSize) -> status_t { + if (outAddr == nullptr || + addrSize < proc.proc->sessions[0].addrLen) { + return BAD_VALUE; + } + if (name == kInstanceName) { + if (proc.proc->sessions[0].addr.ss_family == AF_UNIX) { + sockaddr_un* un = reinterpret_cast( + &proc.proc->sessions[0].addr); + ALOGE("inside callback: %s", un->sun_path); + } + std::memcpy(outAddr, &proc.proc->sessions[0].addr, + proc.proc->sessions[0].addrLen); + return OK; + } + return NAME_NOT_FOUND; + }); + }); + + EXPECT_FALSE(receipt.expired()); + + sp binder = defaultServiceManager()->checkService(kInstanceName); + sp service = checked_interface_cast(binder); + EXPECT_NE(service, nullptr); + + sp out; + EXPECT_OK(service->repeatBinder(binder, &out)); + EXPECT_EQ(binder, out); + + out.clear(); + binder.clear(); + service.clear(); + + status_t status = removeAccessorProvider(receipt); + EXPECT_EQ(status, OK); + + waitForExtraSessionCleanup(proc); +} + +TEST_P(BinderRpcAccessor, InjectNoAccessorProvided) { + const String16 kInstanceName("doesnt_matter_nothing_checks"); + + bool isProviderDeleted = false; + + auto receipt = addAccessorProvider([&](const String16&) -> sp { return nullptr; }); + EXPECT_FALSE(receipt.expired()); + + sp binder = defaultServiceManager()->checkService(kInstanceName); + EXPECT_EQ(binder, nullptr); + + status_t status = removeAccessorProvider(receipt); + EXPECT_EQ(status, OK); +} + +TEST_P(BinderRpcAccessor, InjectNoSockaddrProvided) { + constexpr size_t kNumThreads = 10; + const String16 kInstanceName("super.cool.service/better_than_default"); + + auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads}); + EXPECT_EQ(OK, proc.rootBinder->pingBinder()); + + bool isProviderDeleted = false; + bool isAccessorDeleted = false; + + auto receipt = addAccessorProvider([&](const String16& name) -> sp { + return createAccessor(name, [&](const String16&, sockaddr*, socklen_t) -> status_t { + // don't fill in outAddr + return NAME_NOT_FOUND; + }); + }); + + EXPECT_FALSE(receipt.expired()); + + sp binder = defaultServiceManager()->checkService(kInstanceName); + EXPECT_EQ(binder, nullptr); + + status_t status = removeAccessorProvider(receipt); + EXPECT_EQ(status, OK); +} + +#endif // BINDER_WITH_KERNEL_IPC + #ifdef BINDER_RPC_TO_TRUSTY_TEST static std::vector getTrustyBinderRpcParams() { @@ -1152,8 +1315,6 @@ INSTANTIATE_TEST_SUITE_P(Trusty, BinderRpc, ::testing::ValuesIn(getTrustyBinderR #else // BINDER_RPC_TO_TRUSTY_TEST bool testSupportVsockLoopback() { // We don't need to enable TLS to know if vsock is supported. - unsigned int vsockPort = allocateVsockPort(); - unique_fd serverFd( TEMP_FAILURE_RETRY(socket(AF_VSOCK, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0))); @@ -1165,16 +1326,22 @@ bool testSupportVsockLoopback() { sockaddr_vm serverAddr{ .svm_family = AF_VSOCK, - .svm_port = vsockPort, + .svm_port = VMADDR_PORT_ANY, .svm_cid = VMADDR_CID_ANY, }; int ret = TEMP_FAILURE_RETRY( bind(serverFd.get(), reinterpret_cast(&serverAddr), sizeof(serverAddr))); - LOG_ALWAYS_FATAL_IF(0 != ret, "Could not bind socket to port %u: %s", vsockPort, + LOG_ALWAYS_FATAL_IF(0 != ret, "Could not bind socket to port VMADDR_PORT_ANY: %s", strerror(errno)); + socklen_t len = sizeof(serverAddr); + ret = getsockname(serverFd.get(), reinterpret_cast(&serverAddr), &len); + LOG_ALWAYS_FATAL_IF(0 != ret, "Failed to getsockname: %s", strerror(errno)); + LOG_ALWAYS_FATAL_IF(len < static_cast(sizeof(serverAddr)), + "getsockname didn't read the full addr struct"); + ret = TEMP_FAILURE_RETRY(listen(serverFd.get(), 1 /*backlog*/)); - LOG_ALWAYS_FATAL_IF(0 != ret, "Could not listen socket on port %u: %s", vsockPort, + LOG_ALWAYS_FATAL_IF(0 != ret, "Could not listen socket on port %u: %s", serverAddr.svm_port, strerror(errno)); // Try to connect to the server using the VMADDR_CID_LOCAL cid @@ -1183,13 +1350,13 @@ bool testSupportVsockLoopback() { // and they return ETIMEDOUT after that. unique_fd connectFd( TEMP_FAILURE_RETRY(socket(AF_VSOCK, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0))); - LOG_ALWAYS_FATAL_IF(!connectFd.ok(), "Could not create socket for port %u: %s", vsockPort, - strerror(errno)); + LOG_ALWAYS_FATAL_IF(!connectFd.ok(), "Could not create socket for port %u: %s", + serverAddr.svm_port, strerror(errno)); bool success = false; sockaddr_vm connectAddr{ .svm_family = AF_VSOCK, - .svm_port = vsockPort, + .svm_port = serverAddr.svm_port, .svm_cid = VMADDR_CID_LOCAL, }; ret = TEMP_FAILURE_RETRY(connect(connectFd.get(), reinterpret_cast(&connectAddr), @@ -1310,6 +1477,11 @@ static std::vector getBinderRpcParams() { INSTANTIATE_TEST_SUITE_P(PerSocket, BinderRpc, ::testing::ValuesIn(getBinderRpcParams()), BinderRpc::PrintParamInfo); +#ifdef BINDER_WITH_KERNEL_IPC +INSTANTIATE_TEST_SUITE_P(PerSocket, BinderRpcAccessor, ::testing::ValuesIn(getBinderRpcParams()), + BinderRpc::PrintParamInfo); +#endif // BINDER_WITH_KERNEL_IPC + class BinderRpcServerRootObject : public ::testing::TestWithParam> {}; @@ -1379,8 +1551,8 @@ TEST(BinderRpc, Java) { sp sm = defaultServiceManager(); ASSERT_NE(nullptr, sm); // Any Java service with non-empty getInterfaceDescriptor() would do. - // Let's pick batteryproperties. - auto binder = sm->checkService(String16("batteryproperties")); + // Let's pick activity. + auto binder = sm->checkService(String16("activity")); ASSERT_NE(nullptr, binder); auto descriptor = binder->getInterfaceDescriptor(); ASSERT_GE(descriptor.size(), 0u); @@ -1538,8 +1710,9 @@ public: }; } break; case SocketType::VSOCK: { - auto port = allocateVsockPort(); - auto status = rpcServer->setupVsockServer(VMADDR_CID_LOCAL, port); + unsigned port; + auto status = + rpcServer->setupVsockServer(VMADDR_CID_LOCAL, VMADDR_PORT_ANY, &port); if (status != OK) { return AssertionFailure() << "setupVsockServer: " << statusToString(status); } diff --git a/libs/binder/tests/binderRpcTestFixture.h b/libs/binder/tests/binderRpcTestFixture.h index 2c9646b30e433ecf6e1e88781c137a029b07d6c5..c8a8acc0a0ee8411ecef23d685f5e3013a9c3c9e 100644 --- a/libs/binder/tests/binderRpcTestFixture.h +++ b/libs/binder/tests/binderRpcTestFixture.h @@ -35,6 +35,12 @@ public: struct SessionInfo { sp session; sp root; +// Trusty defines its own socket APIs in trusty_ipc.h but doesn't include +// sockaddr types. +#ifndef __TRUSTY__ + sockaddr_storage addr; + socklen_t addrLen; +#endif }; // client session objects associated with other process diff --git a/libs/binder/tests/binderRpcTestService.cpp b/libs/binder/tests/binderRpcTestService.cpp index 28125f169ca94ee277801f45b871e561a85e8a92..aef946481feb75dff38e85f945ce0b8ee664ab06 100644 --- a/libs/binder/tests/binderRpcTestService.cpp +++ b/libs/binder/tests/binderRpcTestService.cpp @@ -143,8 +143,8 @@ int main(int argc, char* argv[]) { break; case SocketType::VSOCK: LOG_ALWAYS_FATAL_IF(OK != - server->setupVsockServer(VMADDR_CID_LOCAL, - serverConfig.vsockPort), + server->setupVsockServer(VMADDR_CID_LOCAL, VMADDR_PORT_ANY, + &outPort), "Need `sudo modprobe vsock_loopback`?"); break; case SocketType::INET: { diff --git a/libs/binder/tests/binderRpcUniversalTests.cpp b/libs/binder/tests/binderRpcUniversalTests.cpp index f4807806adc4883a0ddf18ea4e03d25cf61695a9..c6fd4870a007168abf5720ccc0239cfba4ff9558 100644 --- a/libs/binder/tests/binderRpcUniversalTests.cpp +++ b/libs/binder/tests/binderRpcUniversalTests.cpp @@ -301,7 +301,8 @@ TEST_P(BinderRpc, CannotSendRegularBinderOverSocketBinder) { auto proc = createRpcTestSocketServerProcess({}); - sp someRealBinder = IInterface::asBinder(defaultServiceManager()); + sp someRealBinder = defaultServiceManager()->getService(String16("activity")); + ASSERT_NE(someRealBinder, nullptr); sp outBinder; EXPECT_EQ(INVALID_OPERATION, proc.rootIface->repeatBinder(someRealBinder, &outBinder).transactionError()); @@ -323,6 +324,22 @@ TEST_P(BinderRpc, CannotSendSocketBinderOverRegularBinder) { // END TESTS FOR LIMITATIONS OF SOCKET BINDER +class TestFrozenStateChangeCallback : public IBinder::FrozenStateChangeCallback { +public: + virtual void onStateChanged(const wp&, State) {} +}; + +TEST_P(BinderRpc, RpcBinderShouldFailOnFrozenStateCallbacks) { + auto proc = createRpcTestSocketServerProcess({}); + + sp a; + sp callback = sp::make(); + EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&a)); + EXPECT_DEATH_IF_SUPPORTED( + { std::ignore = a->addFrozenStateChangeCallback(callback); }, + "addFrozenStateChangeCallback\\(\\) is not supported for RPC Binder."); +} + TEST_P(BinderRpc, RepeatRootObject) { auto proc = createRpcTestSocketServerProcess({}); diff --git a/libs/binder/tests/binderStabilityTest.cpp b/libs/binder/tests/binderStabilityTest.cpp index 3d993588a426ac0958edf864235dadbf79fae4ac..7a8f48e0eb8924978283c4f7160d79a58c0e243b 100644 --- a/libs/binder/tests/binderStabilityTest.cpp +++ b/libs/binder/tests/binderStabilityTest.cpp @@ -27,8 +27,9 @@ #include -#include "aidl/BnBinderStabilityTest.h" +#include "../Utils.h" #include "BnBinderStabilityTest.h" +#include "aidl/BnBinderStabilityTest.h" using namespace android; using namespace ndk; @@ -155,10 +156,9 @@ TEST(BinderStability, NdkForceDowngradeToLocalStability) { } TEST(BinderStability, ForceDowngradeToVendorStability) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" + LIBBINDER_IGNORE("-Wdeprecated-declarations") sp serverBinder = android::defaultServiceManager()->getService(kSystemStabilityServer); -#pragma clang diagnostic pop + LIBBINDER_IGNORE_END() auto server = interface_cast(serverBinder); ASSERT_NE(nullptr, server.get()); @@ -209,10 +209,9 @@ TEST(BinderStability, ConnectionInfoRequiresManifestEntries) { EXPECT_EQ(connectionInfo, std::nullopt); } TEST(BinderStability, CantCallVendorBinderInSystemContext) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" + LIBBINDER_IGNORE("-Wdeprecated-declarations") sp serverBinder = android::defaultServiceManager()->getService(kSystemStabilityServer); -#pragma clang diagnostic pop + LIBBINDER_IGNORE_END() auto server = interface_cast(serverBinder); ASSERT_NE(nullptr, server.get()); @@ -316,11 +315,10 @@ static AIBinder_Class* kNdkBadStableBinder = extern "C" void AIBinder_markVendorStability(AIBinder* binder); // <- BAD DO NOT COPY TEST(BinderStability, NdkCantCallVendorBinderInSystemContext) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" + LIBBINDER_IGNORE("-Wdeprecated-declarations") SpAIBinder binder = SpAIBinder(AServiceManager_getService( String8(kSystemStabilityServer).c_str())); -#pragma clang diagnostic pop + LIBBINDER_IGNORE_END() std::shared_ptr remoteServer = aidl::IBinderStabilityTest::fromBinder(binder); diff --git a/libs/binder/tests/binder_sdk/Android.bp b/libs/binder/tests/binder_sdk/Android.bp new file mode 100644 index 0000000000000000000000000000000000000000..4e884ad319682a405077a6849315723db10af32d --- /dev/null +++ b/libs/binder/tests/binder_sdk/Android.bp @@ -0,0 +1,84 @@ +// +// Copyright (C) 2024 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"], +} + +sh_test_host { + name: "binder_sdk_test", + src: "binder_sdk_test.sh", + test_suites: ["general-tests"], + test_options: { + unit_test: false, + }, + + data: [ + ":binder_sdk", + ":cmake_root", + ], + data_bins: [ + "cmake", + "ctest", + ], +} + +sh_test_host { + name: "binder_sdk_docker_test_gcc", + src: "binder_sdk_docker_test.sh", + test_suites: ["general-tests"], + test_options: { + unit_test: false, + }, + + data: [ + ":binder_sdk", + "gcc.Dockerfile", + ], +} + +sh_test_host { + name: "binder_sdk_docker_test_clang", + src: "binder_sdk_docker_test.sh", + test_suites: ["general-tests"], + test_options: { + unit_test: false, + }, + + data: [ + ":binder_sdk", + "clang.Dockerfile", + ], +} + +sh_test_host { + name: "binder_sdk_docker_test_gnumake", + src: "binder_sdk_docker_test.sh", + test_suites: ["general-tests"], + test_options: { + unit_test: false, + }, + + data: [ + ":binder_sdk", + "gnumake.Dockerfile", + ], +} diff --git a/libs/binder/tests/binder_sdk/binder_sdk_docker_test.sh b/libs/binder/tests/binder_sdk/binder_sdk_docker_test.sh new file mode 100755 index 0000000000000000000000000000000000000000..9ea8cb3a7cc8226fceacd2b30eaba6fea7ca5c3e --- /dev/null +++ b/libs/binder/tests/binder_sdk/binder_sdk_docker_test.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +# +# Copyright (C) 2024 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. +# + +set -ex + +TEST_NAME="$(basename "$0")" +DOCKER_TAG="${TEST_NAME}-${RANDOM}${RANDOM}" +DOCKER_FILE=*.Dockerfile +DOCKER_RUN_FLAGS= + +# Guess if we're running as an Android test or directly +if [ "$(ls -1 ${DOCKER_FILE} | wc -l)" == "1" ]; then + # likely running as `atest binder_sdk_docker_test_XYZ` + DOCKER_PATH="$(dirname $(readlink --canonicalize --no-newline binder_sdk.zip))" +else + # likely running directly as `./binder_sdk_docker_test.sh` - provide mode for easy testing + RED='\033[1;31m' + NO_COLOR='\033[0m' + + if ! modinfo vsock_loopback &>/dev/null ; then + echo -e "${RED}Module vsock_loopback is not installed.${NO_COLOR}" + exit 1 + fi + if modprobe --dry-run --first-time vsock_loopback &>/dev/null ; then + echo "Module vsock_loopback is not loaded. Attempting to load..." + if ! sudo modprobe vsock_loopback ; then + echo -e "${RED}Module vsock_loopback is not loaded and attempt to load failed.${NO_COLOR}" + exit 1 + fi + fi + + DOCKER_RUN_FLAGS="--interactive --tty" + + DOCKER_FILE="$1" + if [ ! -f "${DOCKER_FILE}" ]; then + echo -e "${RED}Docker file '${DOCKER_FILE}' doesn't exist. Please provide one as an argument.${NO_COLOR}" + exit 1 + fi + + if [ ! -d "${ANDROID_BUILD_TOP}" ]; then + echo -e "${RED}ANDROID_BUILD_TOP doesn't exist. Please lunch some target.${NO_COLOR}" + exit 1 + fi + ${ANDROID_BUILD_TOP}/build/soong/soong_ui.bash --make-mode binder_sdk + BINDER_SDK_ZIP="${ANDROID_BUILD_TOP}/out/soong/.intermediates/frameworks/native/libs/binder/binder_sdk/linux_glibc_x86_64/binder_sdk.zip" + DOCKER_PATH="$(dirname $(ls -1 ${BINDER_SDK_ZIP} | head --lines=1))" +fi + +function cleanup { + docker rmi --force "${DOCKER_TAG}" 2>/dev/null || true +} +trap cleanup EXIT + +docker build --force-rm --tag "${DOCKER_TAG}" --file ${DOCKER_FILE} ${DOCKER_PATH} +docker run ${DOCKER_RUN_FLAGS} --rm "${DOCKER_TAG}" diff --git a/libs/binder/tests/binder_sdk/binder_sdk_test.sh b/libs/binder/tests/binder_sdk/binder_sdk_test.sh new file mode 100644 index 0000000000000000000000000000000000000000..1881acef5ec0c143e69cc17199ab7f3cdb84c03d --- /dev/null +++ b/libs/binder/tests/binder_sdk/binder_sdk_test.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +# +# Copyright (C) 2024 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. +# + +set -ex + +RED='\033[1;31m' +NO_COLOR='\033[0m' + +if [ ! -f "binder_sdk.zip" ]; then + echo -e "${RED}binder_sdk.zip doesn't exist. Are you running this test through 'atest binder_sdk_test'?${NO_COLOR}" + exit 1 +fi + +mkdir -p bin +cp `pwd`/cmake bin/cmake +cp `pwd`/ctest bin/ctest +export PATH="`pwd`/bin:$PATH" + +WORKDIR=workdir_$RANDOM$RANDOM$RANDOM +unzip -q -d $WORKDIR binder_sdk.zip +cd $WORKDIR + +cmake . +make -j +make test ARGS="--parallel 32 --output-on-failure" diff --git a/libs/binder/tests/binder_sdk/clang.Dockerfile b/libs/binder/tests/binder_sdk/clang.Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..aa1fec2d3cc66bc1fae0dffeb2aa4dd1624395dd --- /dev/null +++ b/libs/binder/tests/binder_sdk/clang.Dockerfile @@ -0,0 +1,32 @@ +# +# Copyright (C) 2024 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. +# + +FROM debian:bookworm + +RUN echo 'deb http://deb.debian.org/debian bookworm-backports main' >> /etc/apt/sources.list && \ + apt-get update -y && \ + apt-get install -y clang cmake ninja-build unzip + +ADD binder_sdk.zip / +RUN unzip -q -d binder_sdk binder_sdk.zip + +WORKDIR /binder_sdk +RUN CC=clang CXX=clang++ cmake -G Ninja -B build . +RUN cmake --build build + +WORKDIR /binder_sdk/build +# Alternatively: `ninja test`, but it won't pass parallel argument +ENTRYPOINT [ "ctest", "--parallel", "32", "--output-on-failure" ] diff --git a/libs/binder/tests/binder_sdk/gcc.Dockerfile b/libs/binder/tests/binder_sdk/gcc.Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..fb2ee2ce7df720417173c5218c0b70a0da579667 --- /dev/null +++ b/libs/binder/tests/binder_sdk/gcc.Dockerfile @@ -0,0 +1,32 @@ +# +# Copyright (C) 2024 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. +# + +FROM gcc:9 + +RUN echo 'deb http://deb.debian.org/debian bullseye-backports main' >> /etc/apt/sources.list && \ + apt-get update -y && \ + apt-get install -y cmake ninja-build + +ADD binder_sdk.zip / +RUN unzip -q -d binder_sdk binder_sdk.zip + +WORKDIR /binder_sdk +RUN CC=gcc CXX=g++ cmake -G Ninja -B build . +RUN cmake --build build + +WORKDIR /binder_sdk/build +# Alternatively: `ninja test`, but it won't pass parallel argument +ENTRYPOINT [ "ctest", "--parallel", "32", "--output-on-failure" ] diff --git a/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-0.idc b/libs/binder/tests/binder_sdk/gnumake.Dockerfile similarity index 58% rename from services/vr/virtual_touchpad/idc/vr-virtual-touchpad-0.idc rename to libs/binder/tests/binder_sdk/gnumake.Dockerfile index 205e8b901f9eb37c4b8d8c5e67ed4c4da8044b5d..abe12fb9d18a794ab3c9ae2b359475ce84289700 100644 --- a/services/vr/virtual_touchpad/idc/vr-virtual-touchpad-0.idc +++ b/libs/binder/tests/binder_sdk/gnumake.Dockerfile @@ -1,4 +1,5 @@ -# Copyright (C) 2017 The Android Open Source Project +# +# Copyright (C) 2024 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. @@ -11,16 +12,19 @@ # 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. - # -# Virtual touchpad for the primary display -device.internal = 1 -touch.deviceType = touchScreen +FROM gcc:9 + +RUN echo 'deb http://deb.debian.org/debian bullseye-backports main' >> /etc/apt/sources.list && \ + apt-get update -y && \ + apt-get install -y cmake + +ADD binder_sdk.zip / +RUN unzip -q -d binder_sdk binder_sdk.zip + +WORKDIR /binder_sdk +RUN cmake . +RUN make -j -# Have input flinger treat injected scroll events like a G1 ball -# rather than the default mouse wheel, because the latter requires -# a visible pointer for targeting. -device.type = rotaryEncoder -device.res = 1.0e+2 -device.scalingFactor = 1.0e-2 +ENTRYPOINT make test ARGS="--parallel 32 --output-on-failure" diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp index 62b84330cd05cd719bb0a3b6fb0c224bdc85d093..7c196142e8c39b5368910e5a4aba5cc50b219193 100644 --- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp +++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp @@ -111,7 +111,9 @@ void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, RandomParcelOpti } else { binder = getRandomBinder(&provider); } - CHECK(OK == p->writeStrongBinder(binder)); + + // may fail if mixing kernel binder and RPC binder + (void) p->writeStrongBinder(binder); }, }); diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp index fd9777a916e5d77dedb0f994be1485fc84604f6f..0ed8a554acb0251a8c8c51eabf3d62d82fac37ba 100644 --- a/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp +++ b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp @@ -55,7 +55,7 @@ std::vector reverseBytes(T min, T max, T val) { offset += CHAR_BIT; } - return std::move(reverseData); + return reverseData; } template diff --git a/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp b/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp index a6fd487fe57aa8c2a4102b0bdda8de3fdcca7fdb..bc0d5af66f76954b67c96e15e705510b06c96d78 100644 --- a/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp +++ b/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp @@ -36,7 +36,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { FuzzedDataProvider fdp(data, size); std::string addr = std::string(getenv("TMPDIR") ?: "/tmp") + "/binderRpcBenchmark"; - (void)unlink(addr.c_str()); + if (0 != unlink(addr.c_str()) && errno != ENOENT) { + LOG(WARNING) << "Could not unlink: " << strerror(errno); + } sp server = RpcServer::make(); diff --git a/libs/binder/trusty/include/binder/RpcServerTrusty.h b/libs/binder/trusty/include/binder/RpcServerTrusty.h index fe44ea5e286231baf698c4bced4c780cfb5fbc58..583ad015e1867cad65fb53d8988aef083fdb16f7 100644 --- a/libs/binder/trusty/include/binder/RpcServerTrusty.h +++ b/libs/binder/trusty/include/binder/RpcServerTrusty.h @@ -42,7 +42,7 @@ public: // equivalent. struct PortAcl { uint32_t flags; - std::vector uuids; + std::vector uuids; const void* extraData; }; diff --git a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferDemosAppBar.kt b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferDemosAppBar.kt index ff3ae5a090427e4640c08ca9624a3b3b2780a829..4f293b9b5e5d1a6d56d4e5fdc43dcd44558e11de 100644 --- a/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferDemosAppBar.kt +++ b/libs/bufferstreams/examples/app/java/com/android/graphics/bufferstreamsdemoapp/BufferDemosAppBar.kt @@ -1,7 +1,5 @@ package com.android.graphics.bufferstreamsdemoapp -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme @@ -29,10 +27,11 @@ fun BufferDemosAppBar( navigationIcon = { if (canNavigateBack) { IconButton(onClick = navigateUp) { - Icon( - imageVector = Icons.AutoMirrored.Filled.ArrowBack, - contentDescription = stringResource(R.string.back_button) - ) + // b/355293776 + // Icon( + // imageVector = Icons.AutoMirrored.Filled.ArrowBack, + // contentDescription = stringResource(R.string.back_button) + // ) } } } diff --git a/libs/bufferstreams/rust/src/lib.rs b/libs/bufferstreams/rust/src/lib.rs index 17d4d8767f613cd1cab7ccea6832fed9eca3c6b4..9c48b498128d84e0df67342a5e978a007940cb9d 100644 --- a/libs/bufferstreams/rust/src/lib.rs +++ b/libs/bufferstreams/rust/src/lib.rs @@ -37,23 +37,23 @@ pub extern "C" fn hello() -> bool { /// BufferPublishers are required to adhere to the following, based on the /// reactive streams specification: /// * The total number of on_next´s signalled by a Publisher to a Subscriber -/// MUST be less than or equal to the total number of elements requested by that -/// Subscriber´s Subscription at all times. +/// MUST be less than or equal to the total number of elements requested by that +/// Subscriber´s Subscription at all times. /// * A Publisher MAY signal fewer on_next than requested and terminate the -/// Subscription by calling on_complete or on_error. +/// Subscription by calling on_complete or on_error. /// * on_subscribe, on_next, on_error and on_complete signaled to a Subscriber -/// MUST be signaled serially. +/// MUST be signaled serially. /// * If a Publisher fails it MUST signal an on_error. /// * If a Publisher terminates successfully (finite stream) it MUST signal an -/// on_complete. +/// on_complete. /// * If a Publisher signals either on_error or on_complete on a Subscriber, -/// that Subscriber’s Subscription MUST be considered cancelled. +/// that Subscriber’s Subscription MUST be considered cancelled. /// * Once a terminal state has been signaled (on_error, on_complete) it is -/// REQUIRED that no further signals occur. +/// REQUIRED that no further signals occur. /// * If a Subscription is cancelled its Subscriber MUST eventually stop being -/// signaled. +/// signaled. /// * A Publisher MAY support multiple Subscribers and decides whether each -/// Subscription is unicast or multicast. +/// Subscription is unicast or multicast. pub trait BufferPublisher { /// Returns the StreamConfig of buffers that publisher creates. fn get_publisher_stream_config(&self) -> StreamConfig; @@ -69,25 +69,25 @@ pub trait BufferPublisher { /// BufferSubcribers are required to adhere to the following, based on the /// reactive streams specification: /// * The total number of on_next´s signalled by a Publisher to a Subscriber -/// MUST be less than or equal to the total number of elements requested by that -/// Subscriber´s Subscription at all times. +/// MUST be less than or equal to the total number of elements requested by that +/// Subscriber´s Subscription at all times. /// * A Publisher MAY signal fewer on_next than requested and terminate the -/// Subscription by calling on_complete or on_error. +/// Subscription by calling on_complete or on_error. /// * on_subscribe, on_next, on_error and on_complete signaled to a Subscriber -/// MUST be signaled serially. +/// MUST be signaled serially. /// * If a Publisher fails it MUST signal an on_error. /// * If a Publisher terminates successfully (finite stream) it MUST signal an -/// on_complete. +/// on_complete. /// * If a Publisher signals either on_error or on_complete on a Subscriber, -/// that Subscriber’s Subscription MUST be considered cancelled. +/// that Subscriber’s Subscription MUST be considered cancelled. /// * Once a terminal state has been signaled (on_error, on_complete) it is -/// REQUIRED that no further signals occur. +/// REQUIRED that no further signals occur. /// * If a Subscription is cancelled its Subscriber MUST eventually stop being -/// signaled. +/// signaled. /// * Publisher.subscribe MAY be called as many times as wanted but MUST be -/// with a different Subscriber each time. +/// with a different Subscriber each time. /// * A Publisher MAY support multiple Subscribers and decides whether each -/// Subscription is unicast or multicast. +/// Subscription is unicast or multicast. pub trait BufferSubscriber { /// The StreamConfig of buffers that this subscriber expects. fn get_subscriber_stream_config(&self) -> StreamConfig; @@ -111,39 +111,39 @@ pub trait BufferSubscriber { /// BufferSubcriptions are required to adhere to the following, based on the /// reactive streams specification: /// * Subscription.request and Subscription.cancel MUST only be called inside -/// of its Subscriber context. +/// of its Subscriber context. /// * The Subscription MUST allow the Subscriber to call Subscription.request -/// synchronously from within on_next or on_subscribe. +/// synchronously from within on_next or on_subscribe. /// * Subscription.request MUST place an upper bound on possible synchronous -/// recursion between Publisher and Subscriber. +/// recursion between Publisher and Subscriber. /// * Subscription.request SHOULD respect the responsivity of its caller by -/// returning in a timely manner. +/// returning in a timely manner. /// * Subscription.cancel MUST respect the responsivity of its caller by -/// returning in a timely manner, MUST be idempotent and MUST be thread-safe. +/// returning in a timely manner, MUST be idempotent and MUST be thread-safe. /// * After the Subscription is cancelled, additional -/// Subscription.request(n: u64) MUST be NOPs. +/// Subscription.request(n: u64) MUST be NOPs. /// * After the Subscription is cancelled, additional Subscription.cancel() -/// MUST be NOPs. +/// MUST be NOPs. /// * While the Subscription is not cancelled, Subscription.request(n: u64) -/// MUST register the given number of additional elements to be produced to the -/// respective subscriber. +/// MUST register the given number of additional elements to be produced to the +/// respective subscriber. /// * While the Subscription is not cancelled, Subscription.request(n: u64) -/// MUST signal on_error if the argument is <= 0. The cause message SHOULD -/// explain that non-positive request signals are illegal. +/// MUST signal on_error if the argument is <= 0. The cause message SHOULD +/// explain that non-positive request signals are illegal. /// * While the Subscription is not cancelled, Subscription.request(n: u64) -/// MAY synchronously call on_next on this (or other) subscriber(s). +/// MAY synchronously call on_next on this (or other) subscriber(s). /// * While the Subscription is not cancelled, Subscription.request(n: u64) -/// MAY synchronously call on_complete or on_error on this (or other) -/// subscriber(s). +/// MAY synchronously call on_complete or on_error on this (or other) +/// subscriber(s). /// * While the Subscription is not cancelled, Subscription.cancel() MUST -/// request the Publisher to eventually stop signaling its Subscriber. The -/// operation is NOT REQUIRED to affect the Subscription immediately. +/// request the Publisher to eventually stop signaling its Subscriber. The +/// operation is NOT REQUIRED to affect the Subscription immediately. /// * While the Subscription is not cancelled, Subscription.cancel() MUST -/// request the Publisher to eventually drop any references to the corresponding -/// subscriber. +/// request the Publisher to eventually drop any references to the corresponding +/// subscriber. /// * While the Subscription is not cancelled, calling Subscription.cancel MAY -/// cause the Publisher, if stateful, to transition into the shut-down state if -/// no other Subscription exists at this point. +/// cause the Publisher, if stateful, to transition into the shut-down state if +/// no other Subscription exists at this point. /// * Calling Subscription.cancel MUST return normally. /// * Calling Subscription.request MUST return normally. pub trait BufferSubscription: Send + Sync + 'static { diff --git a/libs/bufferstreams/rust/src/stream_config.rs b/libs/bufferstreams/rust/src/stream_config.rs index 454bdf144eb1f8ee17ab8f2b995fcd5c541caeed..8288f9f3cfc420f1b338a9cf3af04b217a2d604f 100644 --- a/libs/bufferstreams/rust/src/stream_config.rs +++ b/libs/bufferstreams/rust/src/stream_config.rs @@ -32,10 +32,23 @@ pub struct StreamConfig { pub stride: u32, } +impl From for HardwareBufferDescription { + fn from(config: StreamConfig) -> Self { + HardwareBufferDescription::new( + config.width, + config.height, + config.layers, + config.format, + config.usage, + config.stride, + ) + } +} + impl StreamConfig { /// Tries to create a new HardwareBuffer from settings in a [StreamConfig]. pub fn create_hardware_buffer(&self) -> Option { - HardwareBuffer::new(self.width, self.height, self.layers, self.format, self.usage) + HardwareBuffer::new(&(*self).into()) } } @@ -59,9 +72,10 @@ mod test { assert!(maybe_buffer.is_some()); let buffer = maybe_buffer.unwrap(); - assert_eq!(config.width, buffer.width()); - assert_eq!(config.height, buffer.height()); - assert_eq!(config.format, buffer.format()); - assert_eq!(config.usage, buffer.usage()); + let description = buffer.description(); + assert_eq!(config.width, description.width()); + assert_eq!(config.height, description.height()); + assert_eq!(config.format, description.format()); + assert_eq!(config.usage, description.usage()); } } diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp index 81f6a585abbcbb821aabcd45e3cc051c3a3c67b2..44cdc02c0ebbe5f75637622b869d2cc603a95666 100644 --- a/libs/cputimeinstate/testtimeinstate.cpp +++ b/libs/cputimeinstate/testtimeinstate.cpp @@ -41,7 +41,7 @@ static constexpr uint64_t NSEC_PER_SEC = 1000000000; static constexpr uint64_t NSEC_PER_YEAR = NSEC_PER_SEC * 60 * 60 * 24 * 365; // Declare busy loop variable globally to prevent removal during optimization -static long sum __attribute__((used)) = 0; +static volatile long sum __attribute__((used)) = 1; using std::vector; @@ -579,8 +579,8 @@ uint64_t timeNanos() { // Keeps CPU busy with some number crunching void useCpu() { - sum = 0; - for (int i = 0; i < 100000; i++) { + sum = 1; + for (int i = 1; i < 100000; i++) { sum *= i; } } diff --git a/libs/debugstore/OWNERS b/libs/debugstore/OWNERS index 428a1a2215c105ce360ff4d40af9e30c06d15e63..c8e22b70ff77f44caff867daf0b5c2381a5ba3aa 100644 --- a/libs/debugstore/OWNERS +++ b/libs/debugstore/OWNERS @@ -1,3 +1,2 @@ benmiles@google.com -gaillard@google.com mohamadmahmoud@google.com diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp index f4cf11edb6bacbe2c7460f88129986bae53eaf37..a9bd11e41daf5266fd7e66e4e841187045acec98 100644 --- a/libs/dumputils/dump_utils.cpp +++ b/libs/dumputils/dump_utils.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ #include +#include #include #include @@ -115,7 +116,7 @@ static const std::vector aidl_interfaces_to_dump { /* list of extra hal interfaces to dump containing process during native dumps */ // This is filled when dumpstate is called. -static std::set extra_hal_interfaces_to_dump; +static std::set extra_hal_interfaces_to_dump; static void read_extra_hals_to_dump_from_property() { // extra hals to dump are already filled @@ -129,7 +130,7 @@ static void read_extra_hals_to_dump_from_property() { if (trimmed_token.length() == 0) { continue; } - extra_hal_interfaces_to_dump.insert(trimmed_token); + extra_hal_interfaces_to_dump.insert(std::move(trimmed_token)); } } diff --git a/libs/gralloc/types/fuzzer/Android.bp b/libs/gralloc/types/fuzzer/Android.bp index 833718213a8962905e305dcb1a4775db80d28b4a..d9cdb59dfe9c7524d6a73580b62d2cbf24653a3c 100644 --- a/libs/gralloc/types/fuzzer/Android.bp +++ b/libs/gralloc/types/fuzzer/Android.bp @@ -28,14 +28,10 @@ cc_fuzz { ], static_libs: [ "libbase", - "libcgrouprc", - "libcgrouprc_format", "libcutils", "libgralloctypes", "libhidlbase", "liblog", - "libprocessgroup", - "libjsoncpp", "libutils", ], diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 52383acb34bc0fb06f2be2b85bb9d7eadc96fb26..d1a56635f5371936ccd954aa55d2eba6ee3c8a26 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -83,6 +83,55 @@ static constexpr const char* kNativeLibrariesSystemConfigPath[] = static const char* kLlndkLibrariesTxtPath = "/system/etc/llndk.libraries.txt"; +// List of libraries that were previously available via VNDK-SP, +// and are now available via SPHAL. +// On modern devices that lack the VNDK APEX, the device no longer +// contains a helpful list of these libraries on the filesystem as above. +// See system/sepolicy/vendor/file_contexts +static const char* kFormerlyVndkspLibrariesList = + "android.hardware.common-V2-ndk.so:" + "android.hardware.common.fmq-V1-ndk.so:" + "android.hardware.graphics.allocator-V2-ndk.so:" + "android.hardware.graphics.common-V5-ndk.so:" + "android.hardware.graphics.common@1.0.so:" + "android.hardware.graphics.common@1.1.so:" + "android.hardware.graphics.common@1.2.so:" + "android.hardware.graphics.composer3-V1-ndk.so:" + "android.hardware.graphics.mapper@2.0.so:" + "android.hardware.graphics.mapper@2.1.so:" + "android.hardware.graphics.mapper@3.0.so:" + "android.hardware.graphics.mapper@4.0.so:" + "android.hardware.renderscript@1.0.so:" + "android.hidl.memory.token@1.0.so:" + "android.hidl.memory@1.0-impl.so:" + "android.hidl.memory@1.0.so:" + "android.hidl.safe_union@1.0.so:" + "libRSCpuRef.so:" + "libRSDriver.so:" + "libRS_internal.so:" + "libbacktrace.so:" + "libbase.so:" + "libbcinfo.so:" + "libblas.so:" + "libc++.so:" + "libcompiler_rt.so:" + "libcutils.so:" + "libdmabufheap.so:" + "libft2.so:" + "libgralloctypes.so:" + "libhardware.so:" + "libhidlbase.so:" + "libhidlmemory.so:" + "libion.so:" + "libjsoncpp.so:" + "liblzma.so:" + "libpng.so:" + "libprocessgroup.so:" + "libunwindstack.so:" + "libutils.so:" + "libutilscallstack.so:" + "libz.so"; + static std::string vndkVersionStr() { #ifdef __BIONIC__ return base::GetProperty("ro.vndk.version", ""); @@ -122,8 +171,12 @@ static bool readConfig(const std::string& configFile, std::vector* static const std::string getSystemNativeLibraries(NativeLibrary type) { std::string nativeLibrariesSystemConfig = ""; - if (!isVndkEnabled() && type == NativeLibrary::LLNDK) { - nativeLibrariesSystemConfig = kLlndkLibrariesTxtPath; + if (!isVndkEnabled()) { + if (type == NativeLibrary::VNDKSP) { + return kFormerlyVndkspLibrariesList; + } else { + nativeLibrariesSystemConfig = kLlndkLibrariesTxtPath; + } } else { nativeLibrariesSystemConfig = kNativeLibrariesSystemConfigPath[type]; insertVndkVersionStr(&nativeLibrariesSystemConfig); @@ -263,7 +316,7 @@ android_namespace_t* GraphicsEnv::getDriverNamespace() { ALOGI("Driver path is setup via UPDATABLE_GFX_DRIVER: %s", mDriverPath.c_str()); } - auto vndkNamespace = android_get_exported_namespace("vndk"); + auto vndkNamespace = android_get_exported_namespace(isVndkEnabled() ? "vndk" : "sphal"); if (!vndkNamespace) { mDriverNamespace = nullptr; return mDriverNamespace; @@ -348,18 +401,10 @@ void GraphicsEnv::setDriverToLoad(GpuStatsInfo::Driver driver) { switch (driver) { case GpuStatsInfo::Driver::GL: case GpuStatsInfo::Driver::GL_UPDATED: - case GpuStatsInfo::Driver::ANGLE: { - if (mGpuStats.glDriverToLoad == GpuStatsInfo::Driver::NONE || - mGpuStats.glDriverToLoad == GpuStatsInfo::Driver::GL) { - mGpuStats.glDriverToLoad = driver; - break; - } - - if (mGpuStats.glDriverFallback == GpuStatsInfo::Driver::NONE) { - mGpuStats.glDriverFallback = driver; - } + case GpuStatsInfo::Driver::ANGLE: + mGpuStats.glDriverToLoad = driver; break; - } + case GpuStatsInfo::Driver::VULKAN: case GpuStatsInfo::Driver::VULKAN_UPDATED: { if (mGpuStats.vkDriverToLoad == GpuStatsInfo::Driver::NONE || @@ -508,8 +553,7 @@ void GraphicsEnv::sendGpuStatsLocked(GpuStatsInfo::Api api, bool isDriverLoaded, bool isIntendedDriverLoaded = false; if (api == GpuStatsInfo::Api::API_GL) { driver = mGpuStats.glDriverToLoad; - isIntendedDriverLoaded = - isDriverLoaded && (mGpuStats.glDriverFallback == GpuStatsInfo::Driver::NONE); + isIntendedDriverLoaded = isDriverLoaded; } else { driver = mGpuStats.vkDriverToLoad; isIntendedDriverLoaded = @@ -631,7 +675,7 @@ android_namespace_t* GraphicsEnv::getAngleNamespace() { return mAngleNamespace; } - auto vndkNamespace = android_get_exported_namespace("vndk"); + auto vndkNamespace = android_get_exported_namespace(isVndkEnabled() ? "vndk" : "sphal"); if (!vndkNamespace) { mAngleNamespace = nullptr; return mAngleNamespace; diff --git a/libs/graphicsenv/OWNERS b/libs/graphicsenv/OWNERS index 1db8cbe52fa55e8533c8dc26d67ab44fbc7f822a..4aa8fff1e2e6782c39ecf3541c035d4fc60528df 100644 --- a/libs/graphicsenv/OWNERS +++ b/libs/graphicsenv/OWNERS @@ -1,4 +1,11 @@ chrisforbes@google.com -cnorthrop@google.com ianelliott@google.com -lpy@google.com + +abdolrashidi@google.com +cclao@google.com +cnorthrop@google.com +hibrian@google.com +mathias@google.com +romanl@google.com +solti@google.com +yuxinhu@google.com diff --git a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h index 23f583bda0f42afed4474db0fa73ac596720bd2f..72f29c6b0b2312f6a8f4898f86477cae009c92ff 100644 --- a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h +++ b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h @@ -125,6 +125,11 @@ public: VULKAN_DEVICE_EXTENSION = 9, }; + enum GLTelemetryHints { + NO_HINT = 0, + SKIP_TELEMETRY = 1, + }; + GpuStatsInfo() = default; GpuStatsInfo(const GpuStatsInfo&) = default; virtual ~GpuStatsInfo() = default; @@ -136,7 +141,6 @@ public: std::string appPackageName = ""; int32_t vulkanVersion = 0; Driver glDriverToLoad = Driver::NONE; - Driver glDriverFallback = Driver::NONE; Driver vkDriverToLoad = Driver::NONE; Driver vkDriverFallback = Driver::NONE; bool glDriverToSend = false; diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 82a61c0a71e40847abc045eab931dd5c42c4c635..4a2ee208123ef4ada0f920a5808acb433b737b7e 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -255,6 +255,7 @@ filegroup { "BitTube.cpp", "BLASTBufferQueue.cpp", "BufferItemConsumer.cpp", + "BufferReleaseChannel.cpp", "Choreographer.cpp", "CompositorTiming.cpp", "ConsumerBase.cpp", @@ -335,9 +336,7 @@ cc_defaults { header_libs: [ "jni_headers", - "libdvr_headers", "libgui_aidl_headers", - "libpdx_headers", ], afdo: true, diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 739c3c2a411ed08fe71bfaea0023ab9aef9283ae..25e6a52ed10c54632e005d0820feefa02309b842 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -20,12 +20,16 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 +#include #include +#include #include #include #include #include #include +#include +#include #include #include @@ -39,7 +43,6 @@ #include #include -#include #include @@ -74,6 +77,12 @@ namespace android { std::unique_lock _lock{mutex}; \ base::ScopedLockAssertion assumeLocked(mutex); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) +static ReleaseBufferCallback EMPTY_RELEASE_CALLBACK = + [](const ReleaseCallbackId&, const sp& /*releaseFence*/, + std::optional /*currentMaxAcquiredBufferCount*/) {}; +#endif + void BLASTBufferItemConsumer::onDisconnect() { Mutex::Autolock lock(mMutex); mPreviouslyConnected = mCurrentlyConnected; @@ -175,16 +184,21 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, bool updateDestinati mSyncTransaction(nullptr), mUpdateDestinationFrame(updateDestinationFrame) { createBufferQueue(&mProducer, &mConsumer); - // since the adapter is in the client process, set dequeue timeout - // explicitly so that dequeueBuffer will block - mProducer->setDequeueTimeout(std::numeric_limits::max()); - - // safe default, most producers are expected to override this - mProducer->setMaxDequeuedBufferCount(2); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + mBufferItemConsumer = new BLASTBufferItemConsumer(mProducer, mConsumer, + GraphicBuffer::USAGE_HW_COMPOSER | + GraphicBuffer::USAGE_HW_TEXTURE, + 1, false, this); +#else mBufferItemConsumer = new BLASTBufferItemConsumer(mConsumer, GraphicBuffer::USAGE_HW_COMPOSER | GraphicBuffer::USAGE_HW_TEXTURE, 1, false, this); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + // since the adapter is in the client process, set dequeue timeout + // explicitly so that dequeueBuffer will block + mProducer->setDequeueTimeout(std::numeric_limits::max()); + static std::atomic nextId = 0; mProducerId = nextId++; mName = name + "#" + std::to_string(mProducerId); @@ -210,6 +224,12 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, bool updateDestinati }, this); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) + std::unique_ptr bufferReleaseConsumer; + gui::BufferReleaseChannel::open(mName, bufferReleaseConsumer, mBufferReleaseProducer); + mBufferReleaseReader = std::make_shared(std::move(bufferReleaseConsumer)); +#endif + BQA_LOGV("BLASTBufferQueue created"); } @@ -236,6 +256,14 @@ BLASTBufferQueue::~BLASTBufferQueue() { } } +void BLASTBufferQueue::onFirstRef() { + // safe default, most producers are expected to override this + mProducer->setMaxDequeuedBufferCount(2); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) + mBufferReleaseThread.start(sp::fromExisting(this)); +#endif +} + void BLASTBufferQueue::update(const sp& surface, uint32_t width, uint32_t height, int32_t format) { LOG_ALWAYS_FATAL_IF(surface == nullptr, "BLASTBufferQueue: mSurfaceControl must not be NULL"); @@ -259,6 +287,9 @@ void BLASTBufferQueue::update(const sp& surface, uint32_t width, if (surfaceControlChanged) { t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure, layer_state_t::eEnableBackpressure); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) + t.setBufferReleaseChannel(mSurfaceControl, mBufferReleaseProducer); +#endif applyTransaction = true; } mTransformHint = mSurfaceControl->getTransformHint(); @@ -296,14 +327,12 @@ static std::optional findMatchingStat( return std::nullopt; } -static void transactionCommittedCallbackThunk(void* context, nsecs_t latchTime, - const sp& presentFence, - const std::vector& stats) { - if (context == nullptr) { - return; - } - sp bq = static_cast(context); - bq->transactionCommittedCallback(latchTime, presentFence, stats); +TransactionCompletedCallbackTakesContext BLASTBufferQueue::makeTransactionCommittedCallbackThunk() { + return [bbq = sp::fromExisting( + this)](void* /*context*/, nsecs_t latchTime, const sp& presentFence, + const std::vector& stats) { + bbq->transactionCommittedCallback(latchTime, presentFence, stats); + }; } void BLASTBufferQueue::transactionCommittedCallback(nsecs_t /*latchTime*/, @@ -336,18 +365,15 @@ void BLASTBufferQueue::transactionCommittedCallback(nsecs_t /*latchTime*/, BQA_LOGE("No matching SurfaceControls found: mSurfaceControlsWithPendingCallback was " "empty."); } - decStrong((void*)transactionCommittedCallbackThunk); } } -static void transactionCallbackThunk(void* context, nsecs_t latchTime, - const sp& presentFence, - const std::vector& stats) { - if (context == nullptr) { - return; - } - sp bq = static_cast(context); - bq->transactionCallback(latchTime, presentFence, stats); +TransactionCompletedCallbackTakesContext BLASTBufferQueue::makeTransactionCallbackThunk() { + return [bbq = sp::fromExisting( + this)](void* /*context*/, nsecs_t latchTime, const sp& presentFence, + const std::vector& stats) { + bbq->transactionCallback(latchTime, presentFence, stats); + }; } void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp& /*presentFence*/, @@ -381,6 +407,7 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp staleReleases; for (const auto& [key, value]: mSubmitted) { @@ -396,6 +423,7 @@ void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp context, const ReleaseCallbackId& id, - const sp& releaseFence, - std::optional currentMaxAcquiredBufferCount) { - sp blastBufferQueue = context.promote(); - if (blastBufferQueue) { - blastBufferQueue->releaseBufferCallback(id, releaseFence, currentMaxAcquiredBufferCount); - } else { - ALOGV("releaseBufferCallbackThunk %s blastBufferQueue is dead", id.to_string().c_str()); } } @@ -432,6 +443,23 @@ void BLASTBufferQueue::flushShadowQueue() { } } +// Unlike transactionCallbackThunk the release buffer callback does not extend the life of the +// BBQ. This is because if the BBQ is destroyed, then the buffers will be released by the client. +// So we pass in a weak pointer to the BBQ and if it still alive, then we release the buffer. +// Otherwise, this is a no-op. +ReleaseBufferCallback BLASTBufferQueue::makeReleaseBufferCallbackThunk() { + return [weakBbq = wp::fromExisting( + this)](const ReleaseCallbackId& id, const sp& releaseFence, + std::optional currentMaxAcquiredBufferCount) { + sp bbq = weakBbq.promote(); + if (!bbq) { + ALOGV("releaseBufferCallbackThunk %s blastBufferQueue is dead", id.to_string().c_str()); + return; + } + bbq->releaseBufferCallback(id, releaseFence, currentMaxAcquiredBufferCount); + }; +} + void BLASTBufferQueue::releaseBufferCallback( const ReleaseCallbackId& id, const sp& releaseFence, std::optional currentMaxAcquiredBufferCount) { @@ -594,9 +622,6 @@ status_t BLASTBufferQueue::acquireNextBufferLocked( t->notifyProducerDisconnect(mSurfaceControl); } - // Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback. - incStrong((void*)transactionCallbackThunk); - // Only update mSize for destination bounds if the incoming buffer matches the requested size. // Otherwise, it could cause stretching since the destination bounds will update before the // buffer with the new size is acquired. @@ -609,9 +634,12 @@ status_t BLASTBufferQueue::acquireNextBufferLocked( bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform, bufferItem.mScalingMode, crop); - auto releaseBufferCallback = - std::bind(releaseBufferCallbackThunk, wp(this) /* callbackContext */, - std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) + ReleaseBufferCallback releaseBufferCallback = + applyTransaction ? EMPTY_RELEASE_CALLBACK : makeReleaseBufferCallbackThunk(); +#else + auto releaseBufferCallback = makeReleaseBufferCallbackThunk(); +#endif sp fence = bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE; nsecs_t dequeueTime = -1; @@ -629,7 +657,7 @@ status_t BLASTBufferQueue::acquireNextBufferLocked( t->setDataspace(mSurfaceControl, static_cast(bufferItem.mDataSpace)); t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata); t->setSurfaceDamageRegion(mSurfaceControl, bufferItem.mSurfaceDamage); - t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast(this)); + t->addTransactionCompletedCallback(makeTransactionCallbackThunk(), nullptr); mSurfaceControlsWithPendingCallback.push(mSurfaceControl); @@ -786,9 +814,9 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { // Only need a commit callback when syncing to ensure the buffer that's synced has been // sent to SF - incStrong((void*)transactionCommittedCallbackThunk); - mSyncTransaction->addTransactionCommittedCallback(transactionCommittedCallbackThunk, - static_cast(this)); + mSyncTransaction + ->addTransactionCommittedCallback(makeTransactionCommittedCallbackThunk(), + nullptr); if (mAcquireSingleBuffer) { prevCallback = mTransactionReadyCallback; prevTransaction = mSyncTransaction; @@ -817,7 +845,7 @@ void BLASTBufferQueue::onFrameDequeued(const uint64_t bufferId) { void BLASTBufferQueue::onFrameCancelled(const uint64_t bufferId) { std::lock_guard _lock{mTimestampMutex}; mDequeueTimestamps.erase(bufferId); -}; +} bool BLASTBufferQueue::syncNextTransaction( std::function callback, @@ -1096,15 +1124,26 @@ public: AsyncWorker::getInstance().post( [listener = mListener, slots = slots]() { listener->onBuffersDiscarded(slots); }); } + + void onBufferDetached(int slot) override { + AsyncWorker::getInstance().post( + [listener = mListener, slot = slot]() { listener->onBufferDetached(slot); }); + } + +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK) + void onBufferAttached() override { + AsyncWorker::getInstance().post([listener = mListener]() { listener->onBufferAttached(); }); + } +#endif }; // Extends the BufferQueueProducer to create a wrapper around the listener so the listener calls // can be non-blocking when the producer is in the client process. class BBQBufferQueueProducer : public BufferQueueProducer { public: - BBQBufferQueueProducer(const sp& core, wp bbq) + BBQBufferQueueProducer(const sp& core, const wp& bbq) : BufferQueueProducer(core, false /* consumerIsSurfaceFlinger*/), - mBLASTBufferQueue(std::move(bbq)) {} + mBLASTBufferQueue(bbq) {} status_t connect(const sp& listener, int api, bool producerControlledByApp, QueueBufferOutput* output) override { @@ -1119,27 +1158,32 @@ public: // We want to resize the frame history when changing the size of the buffer queue status_t setMaxDequeuedBufferCount(int maxDequeuedBufferCount) override { int maxBufferCount; - status_t status = BufferQueueProducer::setMaxDequeuedBufferCount(maxDequeuedBufferCount, - &maxBufferCount); + if (status_t status = BufferQueueProducer::setMaxDequeuedBufferCount(maxDequeuedBufferCount, + &maxBufferCount); + status != OK) { + return status; + } + + sp bbq = mBLASTBufferQueue.promote(); + if (!bbq) { + return OK; + } + // if we can't determine the max buffer count, then just skip growing the history size - if (status == OK) { - size_t newFrameHistorySize = maxBufferCount + 2; // +2 because triple buffer rendering - // optimize away resizing the frame history unless it will grow - if (newFrameHistorySize > FrameEventHistory::INITIAL_MAX_FRAME_HISTORY) { - sp bbq = mBLASTBufferQueue.promote(); - if (bbq != nullptr) { - ALOGV("increasing frame history size to %zu", newFrameHistorySize); - bbq->resizeFrameEventHistory(newFrameHistorySize); - } - } + size_t newFrameHistorySize = maxBufferCount + 2; // +2 because triple buffer rendering + // optimize away resizing the frame history unless it will grow + if (newFrameHistorySize > FrameEventHistory::INITIAL_MAX_FRAME_HISTORY) { + ALOGV("increasing frame history size to %zu", newFrameHistorySize); + bbq->resizeFrameEventHistory(newFrameHistorySize); } - return status; + + return OK; } int query(int what, int* value) override { if (what == NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER) { *value = 1; - return NO_ERROR; + return OK; } return BufferQueueProducer::query(what, value); } @@ -1219,7 +1263,125 @@ bool BLASTBufferQueue::isSameSurfaceControl(const sp& surfaceCon void BLASTBufferQueue::setTransactionHangCallback( std::function callback) { std::lock_guard _lock{mMutex}; - mTransactionHangCallback = callback; + mTransactionHangCallback = std::move(callback); +} + +void BLASTBufferQueue::setApplyToken(sp applyToken) { + std::lock_guard _lock{mMutex}; + mApplyToken = std::move(applyToken); +} + +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) + +BLASTBufferQueue::BufferReleaseReader::BufferReleaseReader( + std::unique_ptr endpoint) + : mEndpoint{std::move(endpoint)} { + mEpollFd = android::base::unique_fd{epoll_create1(0)}; + LOG_ALWAYS_FATAL_IF(!mEpollFd.ok(), + "Failed to create buffer release epoll file descriptor. errno=%d " + "message='%s'", + errno, strerror(errno)); + + epoll_event registerEndpointFd{}; + registerEndpointFd.events = EPOLLIN; + registerEndpointFd.data.fd = mEndpoint->getFd(); + status_t status = + epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mEndpoint->getFd(), ®isterEndpointFd); + LOG_ALWAYS_FATAL_IF(status == -1, + "Failed to register buffer release consumer file descriptor with epoll. " + "errno=%d message='%s'", + errno, strerror(errno)); + + mEventFd = android::base::unique_fd(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK)); + LOG_ALWAYS_FATAL_IF(!mEventFd.ok(), + "Failed to create buffer release event file descriptor. errno=%d " + "message='%s'", + errno, strerror(errno)); + + epoll_event registerEventFd{}; + registerEventFd.events = EPOLLIN; + registerEventFd.data.fd = mEventFd.get(); + status = epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, mEventFd.get(), ®isterEventFd); + LOG_ALWAYS_FATAL_IF(status == -1, + "Failed to register buffer release event file descriptor with epoll. " + "errno=%d message='%s'", + errno, strerror(errno)); +} + +BLASTBufferQueue::BufferReleaseReader& BLASTBufferQueue::BufferReleaseReader::operator=( + BufferReleaseReader&& other) { + if (this != &other) { + ftl::FakeGuard guard{mMutex}; + ftl::FakeGuard otherGuard{other.mMutex}; + mEndpoint = std::move(other.mEndpoint); + mEpollFd = std::move(other.mEpollFd); + mEventFd = std::move(other.mEventFd); + } + return *this; +} + +status_t BLASTBufferQueue::BufferReleaseReader::readBlocking(ReleaseCallbackId& outId, + sp& outFence, + uint32_t& outMaxAcquiredBufferCount) { + epoll_event event{}; + while (true) { + int eventCount = epoll_wait(mEpollFd.get(), &event, 1 /* maxevents */, -1 /* timeout */); + if (eventCount == 1) { + break; + } + if (eventCount == -1 && errno != EINTR) { + ALOGE("epoll_wait error while waiting for buffer release. errno=%d message='%s'", errno, + strerror(errno)); + } + } + + if (event.data.fd == mEventFd.get()) { + uint64_t value; + if (read(mEventFd.get(), &value, sizeof(uint64_t)) == -1 && errno != EWOULDBLOCK) { + ALOGE("error while reading from eventfd. errno=%d message='%s'", errno, + strerror(errno)); + } + return WOULD_BLOCK; + } + + std::lock_guard lock{mMutex}; + return mEndpoint->readReleaseFence(outId, outFence, outMaxAcquiredBufferCount); } +void BLASTBufferQueue::BufferReleaseReader::interruptBlockingRead() { + uint64_t value = 1; + if (write(mEventFd.get(), &value, sizeof(uint64_t)) == -1) { + ALOGE("failed to notify dequeue event. errno=%d message='%s'", errno, strerror(errno)); + } +} + +void BLASTBufferQueue::BufferReleaseThread::start(const sp& bbq) { + mRunning = std::make_shared(true); + mReader = bbq->mBufferReleaseReader; + std::thread([running = mRunning, reader = mReader, weakBbq = wp(bbq)]() { + pthread_setname_np(pthread_self(), "BufferReleaseThread"); + while (*running) { + ReleaseCallbackId id; + sp fence; + uint32_t maxAcquiredBufferCount; + if (status_t status = reader->readBlocking(id, fence, maxAcquiredBufferCount); + status != OK) { + continue; + } + sp bbq = weakBbq.promote(); + if (!bbq) { + return; + } + bbq->releaseBufferCallback(id, fence, maxAcquiredBufferCount); + } + }).detach(); +} + +BLASTBufferQueue::BufferReleaseThread::~BufferReleaseThread() { + *mRunning = false; + mReader->interruptBlockingRead(); +} + +#endif + } // namespace android diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp index e6331e7282b84be61387351dfd3109ea73af28e1..bfe3d6e02350139267c4f29800977951c7d48e7d 100644 --- a/libs/gui/BufferItemConsumer.cpp +++ b/libs/gui/BufferItemConsumer.cpp @@ -21,8 +21,11 @@ #include +#include #include #include +#include +#include #define BI_LOGV(x, ...) ALOGV("[%s] " x, mName.c_str(), ##__VA_ARGS__) // #define BI_LOGD(x, ...) ALOGD("[%s] " x, mName.c_str(), ##__VA_ARGS__) @@ -32,18 +35,37 @@ namespace android { +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) +BufferItemConsumer::BufferItemConsumer(uint64_t consumerUsage, int bufferCount, + bool controlledByApp, bool isConsumerSurfaceFlinger) + : ConsumerBase(controlledByApp, isConsumerSurfaceFlinger) { + initialize(consumerUsage, bufferCount); +} + +BufferItemConsumer::BufferItemConsumer(const sp& producer, + const sp& consumer, + uint64_t consumerUsage, int bufferCount, + bool controlledByApp) + : ConsumerBase(producer, consumer, controlledByApp) { + initialize(consumerUsage, bufferCount); +} +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + BufferItemConsumer::BufferItemConsumer( const sp& consumer, uint64_t consumerUsage, int bufferCount, bool controlledByApp) : ConsumerBase(consumer, controlledByApp) { + initialize(consumerUsage, bufferCount); +} + +void BufferItemConsumer::initialize(uint64_t consumerUsage, int bufferCount) { status_t err = mConsumer->setConsumerUsageBits(consumerUsage); - LOG_ALWAYS_FATAL_IF(err != OK, - "Failed to set consumer usage bits to %#" PRIx64, consumerUsage); + LOG_ALWAYS_FATAL_IF(err != OK, "Failed to set consumer usage bits to %#" PRIx64, consumerUsage); if (bufferCount != DEFAULT_MAX_BUFFERS) { err = mConsumer->setMaxAcquiredBufferCount(bufferCount); - LOG_ALWAYS_FATAL_IF(err != OK, - "Failed to set max acquired buffer count to %d", bufferCount); + LOG_ALWAYS_FATAL_IF(err != OK, "Failed to set max acquired buffer count to %d", + bufferCount); } } @@ -87,17 +109,38 @@ status_t BufferItemConsumer::acquireBuffer(BufferItem *item, status_t BufferItemConsumer::releaseBuffer(const BufferItem &item, const sp& releaseFence) { - status_t err; + Mutex::Autolock _l(mMutex); + return releaseBufferSlotLocked(item.mSlot, item.mGraphicBuffer, releaseFence); +} +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) +status_t BufferItemConsumer::releaseBuffer(const sp& buffer, + const sp& releaseFence) { Mutex::Autolock _l(mMutex); - err = addReleaseFenceLocked(item.mSlot, item.mGraphicBuffer, releaseFence); + if (buffer == nullptr) { + return BAD_VALUE; + } + + int slotIndex = getSlotForBufferLocked(buffer); + if (slotIndex == INVALID_BUFFER_SLOT) { + return BAD_VALUE; + } + + return releaseBufferSlotLocked(slotIndex, buffer, releaseFence); +} +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + +status_t BufferItemConsumer::releaseBufferSlotLocked(int slotIndex, const sp& buffer, + const sp& releaseFence) { + status_t err; + + err = addReleaseFenceLocked(slotIndex, buffer, releaseFence); if (err != OK) { BI_LOGE("Failed to addReleaseFenceLocked"); } - err = releaseBufferLocked(item.mSlot, item.mGraphicBuffer, EGL_NO_DISPLAY, - EGL_NO_SYNC_KHR); + err = releaseBufferLocked(slotIndex, buffer, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); if (err != OK && err != IGraphicBufferConsumer::STALE_BUFFER_SLOT) { BI_LOGE("Failed to release buffer: %s (%d)", strerror(-err), err); diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index 11f5174d7629e60a39a32dc0433a83672db398f2..69d25be0066c1d7f8f6abb23284942923922d188 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -42,6 +42,8 @@ #include +#include + namespace android { // Macros for include BufferQueueCore information in log messages @@ -370,79 +372,94 @@ status_t BufferQueueConsumer::attachBuffer(int* outSlot, return BAD_VALUE; } - std::lock_guard lock(mCore->mMutex); + sp listener; + { + std::lock_guard lock(mCore->mMutex); - if (mCore->mSharedBufferMode) { - BQ_LOGE("attachBuffer: cannot attach a buffer in shared buffer mode"); - return BAD_VALUE; - } + if (mCore->mSharedBufferMode) { + BQ_LOGE("attachBuffer: cannot attach a buffer in shared buffer mode"); + return BAD_VALUE; + } - // Make sure we don't have too many acquired buffers - int numAcquiredBuffers = 0; - for (int s : mCore->mActiveBuffers) { - if (mSlots[s].mBufferState.isAcquired()) { - ++numAcquiredBuffers; + // Make sure we don't have too many acquired buffers + int numAcquiredBuffers = 0; + for (int s : mCore->mActiveBuffers) { + if (mSlots[s].mBufferState.isAcquired()) { + ++numAcquiredBuffers; + } } - } - if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) { - BQ_LOGE("attachBuffer: max acquired buffer count reached: %d " - "(max %d)", numAcquiredBuffers, - mCore->mMaxAcquiredBufferCount); - return INVALID_OPERATION; - } + if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) { + BQ_LOGE("attachBuffer: max acquired buffer count reached: %d " + "(max %d)", numAcquiredBuffers, + mCore->mMaxAcquiredBufferCount); + return INVALID_OPERATION; + } - if (buffer->getGenerationNumber() != mCore->mGenerationNumber) { - BQ_LOGE("attachBuffer: generation number mismatch [buffer %u] " - "[queue %u]", buffer->getGenerationNumber(), - mCore->mGenerationNumber); - return BAD_VALUE; - } + if (buffer->getGenerationNumber() != mCore->mGenerationNumber) { + BQ_LOGE("attachBuffer: generation number mismatch [buffer %u] " + "[queue %u]", buffer->getGenerationNumber(), + mCore->mGenerationNumber); + return BAD_VALUE; + } - // Find a free slot to put the buffer into - int found = BufferQueueCore::INVALID_BUFFER_SLOT; - if (!mCore->mFreeSlots.empty()) { - auto slot = mCore->mFreeSlots.begin(); - found = *slot; - mCore->mFreeSlots.erase(slot); - } else if (!mCore->mFreeBuffers.empty()) { - found = mCore->mFreeBuffers.front(); - mCore->mFreeBuffers.remove(found); - } - if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { - BQ_LOGE("attachBuffer: could not find free buffer slot"); - return NO_MEMORY; + // Find a free slot to put the buffer into + int found = BufferQueueCore::INVALID_BUFFER_SLOT; + if (!mCore->mFreeSlots.empty()) { + auto slot = mCore->mFreeSlots.begin(); + found = *slot; + mCore->mFreeSlots.erase(slot); + } else if (!mCore->mFreeBuffers.empty()) { + found = mCore->mFreeBuffers.front(); + mCore->mFreeBuffers.remove(found); + } + if (found == BufferQueueCore::INVALID_BUFFER_SLOT) { + BQ_LOGE("attachBuffer: could not find free buffer slot"); + return NO_MEMORY; + } + +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK) + if (mCore->mBufferAttachedCbEnabled) { + listener = mCore->mConnectedProducerListener; + } +#endif + + mCore->mActiveBuffers.insert(found); + *outSlot = found; + ATRACE_BUFFER_INDEX(*outSlot); + BQ_LOGV("attachBuffer: returning slot %d", *outSlot); + + mSlots[*outSlot].mGraphicBuffer = buffer; + mSlots[*outSlot].mBufferState.attachConsumer(); + mSlots[*outSlot].mNeedsReallocation = true; + mSlots[*outSlot].mFence = Fence::NO_FENCE; + mSlots[*outSlot].mFrameNumber = 0; + + // mAcquireCalled tells BufferQueue that it doesn't need to send a valid + // GraphicBuffer pointer on the next acquireBuffer call, which decreases + // Binder traffic by not un/flattening the GraphicBuffer. However, it + // requires that the consumer maintain a cached copy of the slot <--> buffer + // mappings, which is why the consumer doesn't need the valid pointer on + // acquire. + // + // The StreamSplitter is one of the primary users of the attach/detach + // logic, and while it is running, all buffers it acquires are immediately + // detached, and all buffers it eventually releases are ones that were + // attached (as opposed to having been obtained from acquireBuffer), so it + // doesn't make sense to maintain the slot/buffer mappings, which would + // become invalid for every buffer during detach/attach. By setting this to + // false, the valid GraphicBuffer pointer will always be sent with acquire + // for attached buffers. + mSlots[*outSlot].mAcquireCalled = false; + + VALIDATE_CONSISTENCY(); } - mCore->mActiveBuffers.insert(found); - *outSlot = found; - ATRACE_BUFFER_INDEX(*outSlot); - BQ_LOGV("attachBuffer: returning slot %d", *outSlot); - - mSlots[*outSlot].mGraphicBuffer = buffer; - mSlots[*outSlot].mBufferState.attachConsumer(); - mSlots[*outSlot].mNeedsReallocation = true; - mSlots[*outSlot].mFence = Fence::NO_FENCE; - mSlots[*outSlot].mFrameNumber = 0; - - // mAcquireCalled tells BufferQueue that it doesn't need to send a valid - // GraphicBuffer pointer on the next acquireBuffer call, which decreases - // Binder traffic by not un/flattening the GraphicBuffer. However, it - // requires that the consumer maintain a cached copy of the slot <--> buffer - // mappings, which is why the consumer doesn't need the valid pointer on - // acquire. - // - // The StreamSplitter is one of the primary users of the attach/detach - // logic, and while it is running, all buffers it acquires are immediately - // detached, and all buffers it eventually releases are ones that were - // attached (as opposed to having been obtained from acquireBuffer), so it - // doesn't make sense to maintain the slot/buffer mappings, which would - // become invalid for every buffer during detach/attach. By setting this to - // false, the valid GraphicBuffer pointer will always be sent with acquire - // for attached buffers. - mSlots[*outSlot].mAcquireCalled = false; - - VALIDATE_CONSISTENCY(); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK) + if (listener != nullptr) { + listener->onBufferAttached(); + } +#endif return NO_ERROR; } diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index 648db67fc163989fdaa94653bfd946036a5e5d35..e0c5b1f7d111d00a1351df9d5f94fdf0a00e9e66 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -96,6 +96,7 @@ BufferQueueCore::BufferQueueCore() mLinkedToDeath(), mConnectedProducerListener(), mBufferReleasedCbEnabled(false), + mBufferAttachedCbEnabled(false), mSlots(), mQueue(), mFreeSlots(), diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 6600c2ca80b7f73e5ba6133a6bd5a6549a15224e..f1e5eb7c896fe97021c38466c6d7d534c2597863 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -45,7 +45,10 @@ #include +#include + namespace android { +using namespace com::android::graphics::libgui; // Macros for include BufferQueueCore information in log messages #define BQ_LOGV(x, ...) \ @@ -925,6 +928,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, uint64_t currentFrameNumber = 0; BufferItem item; int connectedApi; + bool enableEglCpuThrottling = true; sp lastQueuedFence; { // Autolock scope @@ -1098,6 +1102,9 @@ status_t BufferQueueProducer::queueBuffer(int slot, VALIDATE_CONSISTENCY(); connectedApi = mCore->mConnectedApi; + if (flags::bq_producer_throttles_only_async_mode()) { + enableEglCpuThrottling = mCore->mAsyncMode || mCore->mDequeueBufferCannotBlock; + } lastQueuedFence = std::move(mLastQueueBufferFence); mLastQueueBufferFence = std::move(acquireFence); @@ -1143,7 +1150,7 @@ status_t BufferQueueProducer::queueBuffer(int slot, } // Wait without lock held - if (connectedApi == NATIVE_WINDOW_API_EGL) { + if (connectedApi == NATIVE_WINDOW_API_EGL && enableEglCpuThrottling) { // Waiting here allows for two full buffers to be queued but not a // third. In the event that frames take varying time, this makes a // small trade-off in favor of latency rather than throughput. @@ -1361,6 +1368,9 @@ status_t BufferQueueProducer::connect(const sp& listener, #endif mCore->mConnectedProducerListener = listener; mCore->mBufferReleasedCbEnabled = listener->needsReleaseNotify(); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK) + mCore->mBufferAttachedCbEnabled = listener->needsAttachNotify(); +#endif } break; default: diff --git a/libs/gui/BufferReleaseChannel.cpp b/libs/gui/BufferReleaseChannel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..27367aa83f3089ec47338b2858cd111f557e4599 --- /dev/null +++ b/libs/gui/BufferReleaseChannel.cpp @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2024 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 "BufferReleaseChannel" + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +using android::base::Result; + +namespace android::gui { + +namespace { + +template +static void readAligned(const void*& buffer, size_t& size, T& value) { + size -= FlattenableUtils::align(buffer); + FlattenableUtils::read(buffer, size, value); +} + +template +static void writeAligned(void*& buffer, size_t& size, T value) { + size -= FlattenableUtils::align(buffer); + FlattenableUtils::write(buffer, size, value); +} + +template +static void addAligned(size_t& size, T /* value */) { + size = FlattenableUtils::align(size); + size += sizeof(T); +} + +template +static inline constexpr uint32_t low32(const T n) { + return static_cast(static_cast(n)); +} + +template +static inline constexpr uint32_t high32(const T n) { + return static_cast(static_cast(n) >> 32); +} + +template +static inline constexpr T to64(const uint32_t lo, const uint32_t hi) { + return static_cast(static_cast(hi) << 32 | lo); +} + +} // namespace + +size_t BufferReleaseChannel::Message::getPodSize() const { + size_t size = 0; + addAligned(size, low32(releaseCallbackId.bufferId)); + addAligned(size, high32(releaseCallbackId.bufferId)); + addAligned(size, low32(releaseCallbackId.framenumber)); + addAligned(size, high32(releaseCallbackId.framenumber)); + addAligned(size, maxAcquiredBufferCount); + return size; +} + +size_t BufferReleaseChannel::Message::getFlattenedSize() const { + size_t size = releaseFence->getFlattenedSize(); + size = FlattenableUtils::align<4>(size); + size += getPodSize(); + return size; +} + +status_t BufferReleaseChannel::Message::flatten(void*& buffer, size_t& size, int*& fds, + size_t& count) const { + if (status_t err = releaseFence->flatten(buffer, size, fds, count); err != OK) { + return err; + } + size -= FlattenableUtils::align<4>(buffer); + + // Check we still have enough space + if (size < getPodSize()) { + return NO_MEMORY; + } + + writeAligned(buffer, size, low32(releaseCallbackId.bufferId)); + writeAligned(buffer, size, high32(releaseCallbackId.bufferId)); + writeAligned(buffer, size, low32(releaseCallbackId.framenumber)); + writeAligned(buffer, size, high32(releaseCallbackId.framenumber)); + writeAligned(buffer, size, maxAcquiredBufferCount); + return OK; +} + +status_t BufferReleaseChannel::Message::unflatten(void const*& buffer, size_t& size, + int const*& fds, size_t& count) { + releaseFence = new Fence(); + if (status_t err = releaseFence->unflatten(buffer, size, fds, count); err != OK) { + return err; + } + size -= FlattenableUtils::align<4>(buffer); + + // Check we still have enough space + if (size < getPodSize()) { + return OK; + } + + uint32_t bufferIdLo = 0, bufferIdHi = 0; + uint32_t frameNumberLo = 0, frameNumberHi = 0; + + readAligned(buffer, size, bufferIdLo); + readAligned(buffer, size, bufferIdHi); + releaseCallbackId.bufferId = to64(bufferIdLo, bufferIdHi); + readAligned(buffer, size, frameNumberLo); + readAligned(buffer, size, frameNumberHi); + releaseCallbackId.framenumber = to64(frameNumberLo, frameNumberHi); + readAligned(buffer, size, maxAcquiredBufferCount); + + return OK; +} + +status_t BufferReleaseChannel::ConsumerEndpoint::readReleaseFence( + ReleaseCallbackId& outReleaseCallbackId, sp& outReleaseFence, + uint32_t& outMaxAcquiredBufferCount) { + Message message; + mFlattenedBuffer.resize(message.getFlattenedSize()); + std::array controlMessageBuffer; + + iovec iov{ + .iov_base = mFlattenedBuffer.data(), + .iov_len = mFlattenedBuffer.size(), + }; + + msghdr msg{ + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_control = controlMessageBuffer.data(), + .msg_controllen = controlMessageBuffer.size(), + }; + + int result; + do { + result = recvmsg(mFd, &msg, 0); + } while (result == -1 && errno == EINTR); + if (result == -1) { + if (errno == EWOULDBLOCK || errno == EAGAIN) { + return WOULD_BLOCK; + } + ALOGE("Error reading release fence from socket: error %#x (%s)", errno, strerror(errno)); + return UNKNOWN_ERROR; + } + + if (msg.msg_iovlen != 1) { + ALOGE("Error reading release fence from socket: bad data length"); + return UNKNOWN_ERROR; + } + + if (msg.msg_controllen % sizeof(int) != 0) { + ALOGE("Error reading release fence from socket: bad fd length"); + return UNKNOWN_ERROR; + } + + size_t dataLen = msg.msg_iov->iov_len; + const void* data = static_cast(msg.msg_iov->iov_base); + if (!data) { + ALOGE("Error reading release fence from socket: no buffer data"); + return UNKNOWN_ERROR; + } + + size_t fdCount = 0; + const int* fdData = nullptr; + if (cmsghdr* cmsg = CMSG_FIRSTHDR(&msg)) { + fdData = reinterpret_cast(CMSG_DATA(cmsg)); + fdCount = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); + } + + if (status_t err = message.unflatten(data, dataLen, fdData, fdCount); err != OK) { + return err; + } + + outReleaseCallbackId = message.releaseCallbackId; + outReleaseFence = std::move(message.releaseFence); + outMaxAcquiredBufferCount = message.maxAcquiredBufferCount; + + return OK; +} + +int BufferReleaseChannel::ProducerEndpoint::writeReleaseFence(const ReleaseCallbackId& callbackId, + const sp& fence, + uint32_t maxAcquiredBufferCount) { + Message message{callbackId, fence ? fence : Fence::NO_FENCE, maxAcquiredBufferCount}; + mFlattenedBuffer.resize(message.getFlattenedSize()); + int flattenedFd; + { + // Make copies of needed items since flatten modifies them, and we don't + // want to send anything if there's an error during flatten. + void* flattenedBufferPtr = mFlattenedBuffer.data(); + size_t flattenedBufferSize = mFlattenedBuffer.size(); + int* flattenedFdPtr = &flattenedFd; + size_t flattenedFdCount = 1; + if (status_t err = message.flatten(flattenedBufferPtr, flattenedBufferSize, flattenedFdPtr, + flattenedFdCount); + err != OK) { + ALOGE("Failed to flatten BufferReleaseChannel message."); + return err; + } + } + + iovec iov{ + .iov_base = mFlattenedBuffer.data(), + .iov_len = mFlattenedBuffer.size(), + }; + + msghdr msg{ + .msg_iov = &iov, + .msg_iovlen = 1, + }; + + std::array controlMessageBuffer; + if (fence && fence->isValid()) { + msg.msg_control = controlMessageBuffer.data(); + msg.msg_controllen = controlMessageBuffer.size(); + + cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + memcpy(CMSG_DATA(cmsg), &flattenedFd, sizeof(int)); + } + + int result; + do { + result = sendmsg(mFd, &msg, 0); + } while (result == -1 && errno == EINTR); + if (result == -1) { + ALOGD("Error writing release fence to socket: error %#x (%s)", errno, strerror(errno)); + return -errno; + } + + return OK; +} + +status_t BufferReleaseChannel::ProducerEndpoint::readFromParcel(const android::Parcel* parcel) { + if (!parcel) return STATUS_BAD_VALUE; + SAFE_PARCEL(parcel->readUtf8FromUtf16, &mName); + SAFE_PARCEL(parcel->readUniqueFileDescriptor, &mFd); + return STATUS_OK; +} + +status_t BufferReleaseChannel::ProducerEndpoint::writeToParcel(android::Parcel* parcel) const { + if (!parcel) return STATUS_BAD_VALUE; + SAFE_PARCEL(parcel->writeUtf8AsUtf16, mName); + SAFE_PARCEL(parcel->writeUniqueFileDescriptor, mFd); + return STATUS_OK; +} + +status_t BufferReleaseChannel::open(std::string name, + std::unique_ptr& outConsumer, + std::shared_ptr& outProducer) { + outConsumer.reset(); + outProducer.reset(); + + int sockets[2]; + if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) { + ALOGE("[%s] Failed to create socket pair. errorno=%d message='%s'", name.c_str(), errno, + strerror(errno)); + return -errno; + } + + android::base::unique_fd consumerFd(sockets[0]); + android::base::unique_fd producerFd(sockets[1]); + + // Socket buffer size. The default is typically about 128KB, which is much larger than + // we really need. + size_t bufferSize = 32 * 1024; + if (setsockopt(consumerFd.get(), SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)) == + -1) { + ALOGE("[%s] Failed to set consumer socket send buffer size. errno=%d message='%s'", + name.c_str(), errno, strerror(errno)); + return -errno; + } + if (setsockopt(consumerFd.get(), SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)) == + -1) { + ALOGE("[%s] Failed to set consumer socket receive buffer size. errno=%d " + "message='%s'", + name.c_str(), errno, strerror(errno)); + return -errno; + } + if (setsockopt(producerFd.get(), SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)) == + -1) { + ALOGE("[%s] Failed to set producer socket send buffer size. errno=%d message='%s'", + name.c_str(), errno, strerror(errno)); + return -errno; + } + if (setsockopt(producerFd.get(), SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)) == + -1) { + ALOGE("[%s] Failed to set producer socket receive buffer size. errno=%d " + "message='%s'", + name.c_str(), errno, strerror(errno)); + return -errno; + } + + // Configure the consumer socket to be non-blocking. + int flags = fcntl(consumerFd.get(), F_GETFL, 0); + if (flags == -1) { + ALOGE("[%s] Failed to get consumer socket flags. errno=%d message='%s'", name.c_str(), + errno, strerror(errno)); + return -errno; + } + if (fcntl(consumerFd.get(), F_SETFL, flags | O_NONBLOCK) == -1) { + ALOGE("[%s] Failed to set consumer socket to non-blocking mode. errno=%d " + "message='%s'", + name.c_str(), errno, strerror(errno)); + return -errno; + } + + // Configure a timeout for the producer socket. + const timeval timeout{.tv_sec = 1, .tv_usec = 0}; + if (setsockopt(producerFd.get(), SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeval)) == -1) { + ALOGE("[%s] Failed to set producer socket timeout. errno=%d message='%s'", name.c_str(), + errno, strerror(errno)); + return -errno; + } + + // Make the consumer read-only + if (shutdown(consumerFd.get(), SHUT_WR) == -1) { + ALOGE("[%s] Failed to shutdown writing on consumer socket. errno=%d message='%s'", + name.c_str(), errno, strerror(errno)); + return -errno; + } + + // Make the producer write-only + if (shutdown(producerFd.get(), SHUT_RD) == -1) { + ALOGE("[%s] Failed to shutdown reading on producer socket. errno=%d message='%s'", + name.c_str(), errno, strerror(errno)); + return -errno; + } + + outConsumer = std::make_unique(name, std::move(consumerFd)); + outProducer = std::make_shared(std::move(name), std::move(producerFd)); + return STATUS_OK; +} + +} // namespace android::gui \ No newline at end of file diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index b625c3f75ea5fae1279aa1f81e2bec1518a0c3e9..602bba8daba864205db97e3c83e0bc41ec0eeac4 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -14,8 +14,6 @@ * limitations under the License. */ -#include - #define LOG_TAG "ConsumerBase" #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 @@ -29,17 +27,23 @@ #include +#include #include +#include +#include #include +#include #include -#include #include +#include #include #include #include +#include + // Macros for including the ConsumerBase name in log messages #define CB_LOGV(x, ...) ALOGV("[%s] " x, mName.c_str(), ##__VA_ARGS__) // #define CB_LOGD(x, ...) ALOGD("[%s] " x, mName.c_str(), ##__VA_ARGS__) @@ -59,6 +63,30 @@ ConsumerBase::ConsumerBase(const sp& bufferQueue, bool c mAbandoned(false), mConsumer(bufferQueue), mPrevFinalReleaseFence(Fence::NO_FENCE) { + initialize(controlledByApp); +} + +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) +ConsumerBase::ConsumerBase(bool controlledByApp, bool consumerIsSurfaceFlinger) + : mAbandoned(false), mPrevFinalReleaseFence(Fence::NO_FENCE) { + sp producer; + BufferQueue::createBufferQueue(&producer, &mConsumer, consumerIsSurfaceFlinger); + mSurface = sp::make(producer, controlledByApp); + initialize(controlledByApp); +} + +ConsumerBase::ConsumerBase(const sp& producer, + const sp& consumer, bool controlledByApp) + : mAbandoned(false), + mConsumer(consumer), + mSurface(sp::make(producer, controlledByApp)), + mPrevFinalReleaseFence(Fence::NO_FENCE) { + initialize(controlledByApp); +} + +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + +void ConsumerBase::initialize(bool controlledByApp) { // Choose a name using the PID and a process-unique ID. mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); @@ -96,6 +124,35 @@ void ConsumerBase::onLastStrongRef(const void* id __attribute__((unused))) { abandon(); } +int ConsumerBase::getSlotForBufferLocked(const sp& buffer) { + if (!buffer) { + return BufferQueue::INVALID_BUFFER_SLOT; + } + + uint64_t id = buffer->getId(); + for (int i = 0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; i++) { + auto& slot = mSlots[i]; + if (slot.mGraphicBuffer && slot.mGraphicBuffer->getId() == id) { + return i; + } + } + + return BufferQueue::INVALID_BUFFER_SLOT; +} + +status_t ConsumerBase::detachBufferLocked(int slotIndex) { + status_t result = mConsumer->detachBuffer(slotIndex); + + if (result != NO_ERROR) { + CB_LOGE("Failed to detach buffer: %d", result); + return result; + } + + freeBufferLocked(slotIndex); + + return result; +} + void ConsumerBase::freeBufferLocked(int slotIndex) { CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); mSlots[slotIndex].mGraphicBuffer = nullptr; @@ -252,16 +309,30 @@ status_t ConsumerBase::detachBuffer(int slot) { return NO_INIT; } - status_t result = mConsumer->detachBuffer(slot); - if (result != NO_ERROR) { - CB_LOGE("Failed to detach buffer: %d", result); - return result; + return detachBufferLocked(slot); +} + +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) +status_t ConsumerBase::detachBuffer(const sp& buffer) { + CB_LOGV("detachBuffer"); + Mutex::Autolock lock(mMutex); + + if (mAbandoned) { + CB_LOGE("detachBuffer: ConsumerBase is abandoned!"); + return NO_INIT; + } + if (buffer == nullptr) { + return BAD_VALUE; } - freeBufferLocked(slot); + int slotIndex = getSlotForBufferLocked(buffer); + if (slotIndex == BufferQueue::INVALID_BUFFER_SLOT) { + return BAD_VALUE; + } - return result; + return detachBufferLocked(slotIndex); } +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) status_t ConsumerBase::setDefaultBufferSize(uint32_t width, uint32_t height) { Mutex::Autolock _l(mMutex); @@ -309,6 +380,17 @@ status_t ConsumerBase::setTransformHint(uint32_t hint) { return mConsumer->setTransformHint(hint); } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) +status_t ConsumerBase::setMaxBufferCount(int bufferCount) { + Mutex::Autolock lock(mMutex); + if (mAbandoned) { + CB_LOGE("setMaxBufferCount: ConsumerBase is abandoned!"); + return NO_INIT; + } + return mConsumer->setMaxBufferCount(bufferCount); +} +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + status_t ConsumerBase::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { Mutex::Autolock lock(mMutex); if (mAbandoned) { @@ -318,6 +400,17 @@ status_t ConsumerBase::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers); } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) +status_t ConsumerBase::setConsumerIsProtected(bool isProtected) { + Mutex::Autolock lock(mMutex); + if (mAbandoned) { + CB_LOGE("setConsumerIsProtected: ConsumerBase is abandoned!"); + return NO_INIT; + } + return mConsumer->setConsumerIsProtected(isProtected); +} +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + sp ConsumerBase::getSidebandStream() const { Mutex::Autolock _l(mMutex); if (mAbandoned) { @@ -384,6 +477,19 @@ void ConsumerBase::dumpLocked(String8& result, const char* prefix) const { } } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) +sp ConsumerBase::getSurface() const { + LOG_ALWAYS_FATAL_IF(mSurface == nullptr, + "It's illegal to get the surface of a Consumer that does not own it. This " + "should be impossible once the old CTOR is removed."); + return mSurface; +} + +sp ConsumerBase::getIGraphicBufferConsumer() const { + return mConsumer; +} +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + status_t ConsumerBase::acquireBufferLocked(BufferItem *item, nsecs_t presentWhen, uint64_t maxFrameNumber) { if (mAbandoned) { diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp index 3031fa11fce95869566961fb8898805baa9c3c17..23b432e1f4359ac676f9eebabcc95e9b66536516 100644 --- a/libs/gui/CpuConsumer.cpp +++ b/libs/gui/CpuConsumer.cpp @@ -18,9 +18,9 @@ #define LOG_TAG "CpuConsumer" //#define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include - +#include #include +#include #include #define CC_LOGV(x, ...) ALOGV("[%s] " x, mName.c_str(), ##__VA_ARGS__) @@ -31,12 +31,25 @@ namespace android { -CpuConsumer::CpuConsumer(const sp& bq, - size_t maxLockedBuffers, bool controlledByApp) : - ConsumerBase(bq, controlledByApp), - mMaxLockedBuffers(maxLockedBuffers), - mCurrentLockedBuffers(0) -{ +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) +CpuConsumer::CpuConsumer(size_t maxLockedBuffers, bool controlledByApp, + bool isConsumerSurfaceFlinger) + : ConsumerBase(controlledByApp, isConsumerSurfaceFlinger), + mMaxLockedBuffers(maxLockedBuffers), + mCurrentLockedBuffers(0) { + // Create tracking entries for locked buffers + mAcquiredBuffers.insertAt(0, maxLockedBuffers); + + mConsumer->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN); + mConsumer->setMaxAcquiredBufferCount(static_cast(maxLockedBuffers)); +} +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + +CpuConsumer::CpuConsumer(const sp& bq, size_t maxLockedBuffers, + bool controlledByApp) + : ConsumerBase(bq, controlledByApp), + mMaxLockedBuffers(maxLockedBuffers), + mCurrentLockedBuffers(0) { // Create tracking entries for locked buffers mAcquiredBuffers.insertAt(0, maxLockedBuffers); diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp index d49489c5a8ea0b5dd2bcacb62b955de19191ef11..95cce5c1df0c02532d60a47728302ba933186545 100644 --- a/libs/gui/GLConsumer.cpp +++ b/libs/gui/GLConsumer.cpp @@ -101,6 +101,34 @@ static bool hasEglProtectedContent() { return hasIt; } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) +GLConsumer::GLConsumer(uint32_t tex, uint32_t texTarget, bool useFenceSync, bool isControlledByApp) + : ConsumerBase(isControlledByApp, /* isConsumerSurfaceFlinger */ false), + mCurrentCrop(Rect::EMPTY_RECT), + mCurrentTransform(0), + mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), + mCurrentFence(Fence::NO_FENCE), + mCurrentTimestamp(0), + mCurrentDataSpace(HAL_DATASPACE_UNKNOWN), + mCurrentFrameNumber(0), + mDefaultWidth(1), + mDefaultHeight(1), + mFilteringEnabled(true), + mTexName(tex), + mUseFenceSync(useFenceSync), + mTexTarget(texTarget), + mEglDisplay(EGL_NO_DISPLAY), + mEglContext(EGL_NO_CONTEXT), + mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT), + mAttached(true) { + GLC_LOGV("GLConsumer"); + + memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix)); + + mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); +} +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + GLConsumer::GLConsumer(const sp& bq, uint32_t tex, uint32_t texTarget, bool useFenceSync, bool isControlledByApp) : ConsumerBase(bq, isControlledByApp), @@ -130,27 +158,54 @@ GLConsumer::GLConsumer(const sp& bq, uint32_t tex, mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); } -GLConsumer::GLConsumer(const sp& bq, uint32_t texTarget, - bool useFenceSync, bool isControlledByApp) : - ConsumerBase(bq, isControlledByApp), - mCurrentCrop(Rect::EMPTY_RECT), - mCurrentTransform(0), - mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), - mCurrentFence(Fence::NO_FENCE), - mCurrentTimestamp(0), - mCurrentDataSpace(HAL_DATASPACE_UNKNOWN), - mCurrentFrameNumber(0), - mDefaultWidth(1), - mDefaultHeight(1), - mFilteringEnabled(true), - mTexName(0), - mUseFenceSync(useFenceSync), - mTexTarget(texTarget), - mEglDisplay(EGL_NO_DISPLAY), - mEglContext(EGL_NO_CONTEXT), - mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT), - mAttached(false) -{ +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) +GLConsumer::GLConsumer(uint32_t texTarget, bool useFenceSync, bool isControlledByApp) + : ConsumerBase(isControlledByApp, /* isConsumerSurfaceFlinger */ false), + mCurrentCrop(Rect::EMPTY_RECT), + mCurrentTransform(0), + mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), + mCurrentFence(Fence::NO_FENCE), + mCurrentTimestamp(0), + mCurrentDataSpace(HAL_DATASPACE_UNKNOWN), + mCurrentFrameNumber(0), + mDefaultWidth(1), + mDefaultHeight(1), + mFilteringEnabled(true), + mTexName(0), + mUseFenceSync(useFenceSync), + mTexTarget(texTarget), + mEglDisplay(EGL_NO_DISPLAY), + mEglContext(EGL_NO_CONTEXT), + mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT), + mAttached(false) { + GLC_LOGV("GLConsumer"); + + memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix)); + + mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); +} +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + +GLConsumer::GLConsumer(const sp& bq, uint32_t texTarget, bool useFenceSync, + bool isControlledByApp) + : ConsumerBase(bq, isControlledByApp), + mCurrentCrop(Rect::EMPTY_RECT), + mCurrentTransform(0), + mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), + mCurrentFence(Fence::NO_FENCE), + mCurrentTimestamp(0), + mCurrentDataSpace(HAL_DATASPACE_UNKNOWN), + mCurrentFrameNumber(0), + mDefaultWidth(1), + mDefaultHeight(1), + mFilteringEnabled(true), + mTexName(0), + mUseFenceSync(useFenceSync), + mTexTarget(texTarget), + mEglDisplay(EGL_NO_DISPLAY), + mEglContext(EGL_NO_CONTEXT), + mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT), + mAttached(false) { GLC_LOGV("GLConsumer"); memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp index 0683087211207c13cab7d12316fc2bb433a19754..8b9b090496fb6273d683ec149bfa34e5ae92d859 100644 --- a/libs/gui/IProducerListener.cpp +++ b/libs/gui/IProducerListener.cpp @@ -25,6 +25,9 @@ enum { ON_BUFFER_RELEASED = IBinder::FIRST_CALL_TRANSACTION, NEEDS_RELEASE_NOTIFY, ON_BUFFERS_DISCARDED, + ON_BUFFER_DETACHED, + ON_BUFFER_ATTACHED, + NEEDS_ATTACH_NOTIFY, }; class BpProducerListener : public BpInterface @@ -64,6 +67,38 @@ public: data.writeInt32Vector(discardedSlots); remote()->transact(ON_BUFFERS_DISCARDED, data, &reply, IBinder::FLAG_ONEWAY); } + +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK) + virtual void onBufferDetached(int slot) { + Parcel data, reply; + data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor()); + data.writeInt32(slot); + remote()->transact(ON_BUFFER_DETACHED, data, &reply, IBinder::FLAG_ONEWAY); + } + + virtual void onBufferAttached() { + Parcel data, reply; + data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor()); + remote()->transact(ON_BUFFER_ATTACHED, data, &reply, IBinder::FLAG_ONEWAY); + } + + virtual bool needsAttachNotify() { + bool result; + Parcel data, reply; + data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor()); + status_t err = remote()->transact(NEEDS_ATTACH_NOTIFY, data, &reply); + if (err != NO_ERROR) { + ALOGE("IProducerListener: binder call \'needsAttachNotify\' failed"); + return true; + } + err = reply.readBool(&result); + if (err != NO_ERROR) { + ALOGE("IProducerListener: malformed binder reply"); + return true; + } + return result; + } +#endif }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -115,6 +150,27 @@ status_t BnProducerListener::onTransact(uint32_t code, const Parcel& data, onBuffersDiscarded(discardedSlots); return NO_ERROR; } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK) + case ON_BUFFER_DETACHED: { + CHECK_INTERFACE(IProducerListener, data, reply); + int slot; + status_t result = data.readInt32(&slot); + if (result != NO_ERROR) { + ALOGE("ON_BUFFER_DETACHED failed to read slot: %d", result); + return result; + } + onBufferDetached(slot); + return NO_ERROR; + } + case ON_BUFFER_ATTACHED: + CHECK_INTERFACE(IProducerListener, data, reply); + onBufferAttached(); + return NO_ERROR; + case NEEDS_ATTACH_NOTIFY: + CHECK_INTERFACE(IProducerListener, data, reply); + reply->writeBool(needsAttachNotify()); + return NO_ERROR; +#endif } return BBinder::onTransact(code, data, reply, flags); } @@ -128,4 +184,10 @@ bool BnProducerListener::needsReleaseNotify() { void BnProducerListener::onBuffersDiscarded(const std::vector& /*discardedSlots*/) { } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK) +bool BnProducerListener::needsAttachNotify() { + return true; +} +#endif + } // namespace android diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp index f5d19aac785acc36f253b5cebe71e34eb06e03a3..83fc827c5f7fb0061df682731763810848188578 100644 --- a/libs/gui/ITransactionCompletedListener.cpp +++ b/libs/gui/ITransactionCompletedListener.cpp @@ -43,12 +43,6 @@ enum class Tag : uint32_t { } // Anonymous namespace -namespace { // Anonymous - -constexpr int32_t kSerializedCallbackTypeOnCompelteWithJankData = 2; - -} // Anonymous namespace - status_t FrameEventHistoryStats::writeToParcel(Parcel* output) const { status_t err = output->writeUint64(frameNumber); if (err != NO_ERROR) return err; @@ -119,23 +113,6 @@ status_t FrameEventHistoryStats::readFromParcel(const Parcel* input) { return err; } -JankData::JankData() - : frameVsyncId(FrameTimelineInfo::INVALID_VSYNC_ID), jankType(JankType::None) {} - -status_t JankData::writeToParcel(Parcel* output) const { - SAFE_PARCEL(output->writeInt64, frameVsyncId); - SAFE_PARCEL(output->writeInt32, jankType); - SAFE_PARCEL(output->writeInt64, frameIntervalNs); - return NO_ERROR; -} - -status_t JankData::readFromParcel(const Parcel* input) { - SAFE_PARCEL(input->readInt64, &frameVsyncId); - SAFE_PARCEL(input->readInt32, &jankType); - SAFE_PARCEL(input->readInt64, &frameIntervalNs); - return NO_ERROR; -} - status_t SurfaceStats::writeToParcel(Parcel* output) const { SAFE_PARCEL(output->writeStrongBinder, surfaceControl); if (const auto* acquireFence = std::get_if>(&acquireTimeOrFence)) { @@ -160,10 +137,6 @@ status_t SurfaceStats::writeToParcel(Parcel* output) const { SAFE_PARCEL(output->writeUint32, currentMaxAcquiredBufferCount); SAFE_PARCEL(output->writeParcelable, eventStats); - SAFE_PARCEL(output->writeInt32, static_cast(jankData.size())); - for (const auto& data : jankData) { - SAFE_PARCEL(output->writeParcelable, data); - } SAFE_PARCEL(output->writeParcelable, previousReleaseCallbackId); return NO_ERROR; } @@ -200,13 +173,6 @@ status_t SurfaceStats::readFromParcel(const Parcel* input) { SAFE_PARCEL(input->readUint32, ¤tMaxAcquiredBufferCount); SAFE_PARCEL(input->readParcelable, &eventStats); - int32_t jankData_size = 0; - SAFE_PARCEL_READ_SIZE(input->readInt32, &jankData_size, input->dataSize()); - for (int i = 0; i < jankData_size; i++) { - JankData data; - SAFE_PARCEL(input->readParcelable, &data); - jankData.push_back(data); - } SAFE_PARCEL(input->readParcelable, &previousReleaseCallbackId); return NO_ERROR; } @@ -371,11 +337,7 @@ ListenerCallbacks ListenerCallbacks::filter(CallbackId::Type type) const { status_t CallbackId::writeToParcel(Parcel* output) const { SAFE_PARCEL(output->writeInt64, id); - if (type == Type::ON_COMPLETE && includeJankData) { - SAFE_PARCEL(output->writeInt32, kSerializedCallbackTypeOnCompelteWithJankData); - } else { - SAFE_PARCEL(output->writeInt32, static_cast(type)); - } + SAFE_PARCEL(output->writeInt32, static_cast(type)); return NO_ERROR; } @@ -383,13 +345,7 @@ status_t CallbackId::readFromParcel(const Parcel* input) { SAFE_PARCEL(input->readInt64, &id); int32_t typeAsInt; SAFE_PARCEL(input->readInt32, &typeAsInt); - if (typeAsInt == kSerializedCallbackTypeOnCompelteWithJankData) { - type = Type::ON_COMPLETE; - includeJankData = true; - } else { - type = static_cast(typeAsInt); - includeJankData = false; - } + type = static_cast(typeAsInt); return NO_ERROR; } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 3745805aa3cbfeb942e00a89e7e4608204ea8a25..b10996951b85ee5ac673be06742c64578797d0ee 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -17,7 +17,6 @@ #define LOG_TAG "LayerState" #include -#include #include #include @@ -177,6 +176,7 @@ status_t layer_state_t::write(Parcel& output) const } SAFE_PARCEL(output.write, stretchEffect); + SAFE_PARCEL(output.writeParcelable, edgeExtensionParameters); SAFE_PARCEL(output.write, bufferCrop); SAFE_PARCEL(output.write, destinationFrame); SAFE_PARCEL(output.writeInt32, static_cast(trustedOverlay)); @@ -193,6 +193,13 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeFloat, currentHdrSdrRatio); SAFE_PARCEL(output.writeFloat, desiredHdrSdrRatio); SAFE_PARCEL(output.writeInt32, static_cast(cachingHint)); + + const bool hasBufferReleaseChannel = (bufferReleaseChannel != nullptr); + SAFE_PARCEL(output.writeBool, hasBufferReleaseChannel); + if (hasBufferReleaseChannel) { + SAFE_PARCEL(output.writeParcelable, *bufferReleaseChannel); + } + return NO_ERROR; } @@ -306,6 +313,7 @@ status_t layer_state_t::read(const Parcel& input) } SAFE_PARCEL(input.read, stretchEffect); + SAFE_PARCEL(input.readParcelable, &edgeExtensionParameters); SAFE_PARCEL(input.read, bufferCrop); SAFE_PARCEL(input.read, destinationFrame); uint32_t trustedOverlayInt; @@ -337,6 +345,13 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readInt32, &tmpInt32); cachingHint = static_cast(tmpInt32); + bool hasBufferReleaseChannel; + SAFE_PARCEL(input.readBool, &hasBufferReleaseChannel); + if (hasBufferReleaseChannel) { + bufferReleaseChannel = std::make_shared(); + SAFE_PARCEL(input.readParcelable, bufferReleaseChannel.get()); + } + return NO_ERROR; } @@ -682,6 +697,10 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eStretchChanged; stretchEffect = other.stretchEffect; } + if (other.what & eEdgeExtensionChanged) { + what |= eEdgeExtensionChanged; + edgeExtensionParameters = other.edgeExtensionParameters; + } if (other.what & eBufferCropChanged) { what |= eBufferCropChanged; bufferCrop = other.bufferCrop; @@ -712,6 +731,10 @@ void layer_state_t::merge(const layer_state_t& other) { if (other.what & eFlushJankData) { what |= eFlushJankData; } + if (other.what & eBufferReleaseChannelChanged) { + what |= eBufferReleaseChannelChanged; + bufferReleaseChannel = other.bufferReleaseChannel; + } if ((other.what & what) != other.what) { ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? " "other.what=0x%" PRIX64 " what=0x%" PRIX64 " unmerged flags=0x%" PRIX64, @@ -783,6 +806,7 @@ uint64_t layer_state_t::diff(const layer_state_t& other) const { CHECK_DIFF(diff, eAutoRefreshChanged, other, autoRefresh); CHECK_DIFF(diff, eTrustedOverlayChanged, other, trustedOverlay); CHECK_DIFF(diff, eStretchChanged, other, stretchEffect); + CHECK_DIFF(diff, eEdgeExtensionChanged, other, edgeExtensionParameters); CHECK_DIFF(diff, eBufferCropChanged, other, bufferCrop); CHECK_DIFF(diff, eDestinationFrameChanged, other, destinationFrame); if (other.what & eProducerDisconnect) diff |= eProducerDisconnect; @@ -790,6 +814,7 @@ uint64_t layer_state_t::diff(const layer_state_t& other) const { CHECK_DIFF(diff, eColorChanged, other, color.rgb); CHECK_DIFF(diff, eColorSpaceAgnosticChanged, other, colorSpaceAgnostic); CHECK_DIFF(diff, eDimmingEnabledChanged, other, dimmingEnabled); + if (other.what & eBufferReleaseChannelChanged) diff |= eBufferReleaseChannelChanged; return diff; } @@ -867,88 +892,6 @@ status_t InputWindowCommands::read(const Parcel& input) { // ---------------------------------------------------------------------------- -namespace gui { - -status_t CaptureArgs::writeToParcel(Parcel* output) const { - SAFE_PARCEL(output->writeInt32, static_cast(pixelFormat)); - SAFE_PARCEL(output->write, sourceCrop); - SAFE_PARCEL(output->writeFloat, frameScaleX); - SAFE_PARCEL(output->writeFloat, frameScaleY); - SAFE_PARCEL(output->writeBool, captureSecureLayers); - SAFE_PARCEL(output->writeInt32, uid); - SAFE_PARCEL(output->writeInt32, static_cast(dataspace)); - SAFE_PARCEL(output->writeBool, allowProtected); - SAFE_PARCEL(output->writeBool, grayscale); - SAFE_PARCEL(output->writeInt32, excludeHandles.size()); - for (auto& excludeHandle : excludeHandles) { - SAFE_PARCEL(output->writeStrongBinder, excludeHandle); - } - SAFE_PARCEL(output->writeBool, hintForSeamlessTransition); - return NO_ERROR; -} - -status_t CaptureArgs::readFromParcel(const Parcel* input) { - int32_t value = 0; - SAFE_PARCEL(input->readInt32, &value); - pixelFormat = static_cast(value); - SAFE_PARCEL(input->read, sourceCrop); - SAFE_PARCEL(input->readFloat, &frameScaleX); - SAFE_PARCEL(input->readFloat, &frameScaleY); - SAFE_PARCEL(input->readBool, &captureSecureLayers); - SAFE_PARCEL(input->readInt32, &uid); - SAFE_PARCEL(input->readInt32, &value); - dataspace = static_cast(value); - SAFE_PARCEL(input->readBool, &allowProtected); - SAFE_PARCEL(input->readBool, &grayscale); - int32_t numExcludeHandles = 0; - SAFE_PARCEL_READ_SIZE(input->readInt32, &numExcludeHandles, input->dataSize()); - excludeHandles.reserve(numExcludeHandles); - for (int i = 0; i < numExcludeHandles; i++) { - sp binder; - SAFE_PARCEL(input->readStrongBinder, &binder); - excludeHandles.emplace(binder); - } - SAFE_PARCEL(input->readBool, &hintForSeamlessTransition); - return NO_ERROR; -} - -status_t DisplayCaptureArgs::writeToParcel(Parcel* output) const { - SAFE_PARCEL(CaptureArgs::writeToParcel, output); - - SAFE_PARCEL(output->writeStrongBinder, displayToken); - SAFE_PARCEL(output->writeUint32, width); - SAFE_PARCEL(output->writeUint32, height); - return NO_ERROR; -} - -status_t DisplayCaptureArgs::readFromParcel(const Parcel* input) { - SAFE_PARCEL(CaptureArgs::readFromParcel, input); - - SAFE_PARCEL(input->readStrongBinder, &displayToken); - SAFE_PARCEL(input->readUint32, &width); - SAFE_PARCEL(input->readUint32, &height); - return NO_ERROR; -} - -status_t LayerCaptureArgs::writeToParcel(Parcel* output) const { - SAFE_PARCEL(CaptureArgs::writeToParcel, output); - - SAFE_PARCEL(output->writeStrongBinder, layerHandle); - SAFE_PARCEL(output->writeBool, childrenOnly); - return NO_ERROR; -} - -status_t LayerCaptureArgs::readFromParcel(const Parcel* input) { - SAFE_PARCEL(CaptureArgs::readFromParcel, input); - - SAFE_PARCEL(input->readStrongBinder, &layerHandle); - - SAFE_PARCEL(input->readBool, &childrenOnly); - return NO_ERROR; -} - -}; // namespace gui - ReleaseCallbackId BufferData::generateReleaseCallbackId() const { uint64_t bufferId; if (buffer) { diff --git a/libs/gui/OWNERS b/libs/gui/OWNERS index 070f6bf5326a6e80c2c5a00b6ae35408b3bdb2f5..b97cee3c209443fd9938092e3e8061c54d2c873e 100644 --- a/libs/gui/OWNERS +++ b/libs/gui/OWNERS @@ -1,6 +1,8 @@ # Bug component: 1075131 +carlosmr@google.com chrisforbes@google.com +jshargo@google.com jreck@google.com file:/services/surfaceflinger/OWNERS @@ -9,10 +11,10 @@ per-file EndToEndNativeInputTest.cpp = svv@google.com # BufferQueue is feature-frozen per-file BufferQueue* = set noparent -per-file BufferQueue* = jreck@google.com, sumir@google.com, alecmouri@google.com +per-file BufferQueue* = jreck@google.com, sumir@google.com, alecmouri@google.com, jshargo@google.com, carlosmr@google.com per-file IGraphicBuffer* = set noparent -per-file IGraphicBuffer* = jreck@google.com, sumir@google.com, alecmouri@google.com +per-file IGraphicBuffer* = jreck@google.com, sumir@google.com, alecmouri@google.com, jshargo@google.com, carlosmr@google.com per-file include/gui/BufferQueue* = set noparent -per-file include/gui/BufferQueue* = jreck@google.com, sumir@google.com, alecmouri@google.com +per-file include/gui/BufferQueue* = jreck@google.com, sumir@google.com, alecmouri@google.com, jshargo@google.com, carlosmr@google.com per-file include/gui/IGraphicBuffer* = set noparent -per-file include/gui/IGraphicBuffer* = jreck@google.com, sumir@google.com, alecmouri@google.com +per-file include/gui/IGraphicBuffer* = jreck@google.com, sumir@google.com, alecmouri@google.com, jshargo@google.com, carlosmr@google.com diff --git a/libs/gui/ScreenCaptureResults.cpp b/libs/gui/ScreenCaptureResults.cpp index 601a5f9b333c6b0ab616df2ba35bff331b5b9419..2de023e5b285f42fb44db7c8c8003b904d32a829 100644 --- a/libs/gui/ScreenCaptureResults.cpp +++ b/libs/gui/ScreenCaptureResults.cpp @@ -40,6 +40,13 @@ status_t ScreenCaptureResults::writeToParcel(android::Parcel* parcel) const { SAFE_PARCEL(parcel->writeBool, capturedSecureLayers); SAFE_PARCEL(parcel->writeBool, capturedHdrLayers); SAFE_PARCEL(parcel->writeUint32, static_cast(capturedDataspace)); + if (optionalGainMap != nullptr) { + SAFE_PARCEL(parcel->writeBool, true); + SAFE_PARCEL(parcel->write, *optionalGainMap); + } else { + SAFE_PARCEL(parcel->writeBool, false); + } + SAFE_PARCEL(parcel->writeFloat, hdrSdrRatio); return NO_ERROR; } @@ -68,6 +75,14 @@ status_t ScreenCaptureResults::readFromParcel(const android::Parcel* parcel) { uint32_t dataspace = 0; SAFE_PARCEL(parcel->readUint32, &dataspace); capturedDataspace = static_cast(dataspace); + + bool hasGainmap; + SAFE_PARCEL(parcel->readBool, &hasGainmap); + if (hasGainmap) { + optionalGainMap = new GraphicBuffer(); + SAFE_PARCEL(parcel->read, *optionalGainMap); + } + SAFE_PARCEL(parcel->readFloat, &hdrSdrRatio); return NO_ERROR; } diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 87fd448f0c793761bd9d501ec9efe29b5c243eb0..66e7ddd9154d95548b3e0cf76e69b3e95df44d27 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -21,6 +21,8 @@ #include #include +#include +#include #include #include #include @@ -41,11 +43,9 @@ #include #include -#include +#include #include -#include - #include #include #include @@ -77,9 +77,28 @@ bool isInterceptorRegistrationOp(int op) { } // namespace +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) +Surface::ProducerDeathListenerProxy::ProducerDeathListenerProxy(wp surfaceListener) + : mSurfaceListener(surfaceListener) {} + +void Surface::ProducerDeathListenerProxy::binderDied(const wp&) { + sp surfaceListener = mSurfaceListener.promote(); + if (!surfaceListener) { + return; + } + + if (surfaceListener->needsDeathNotify()) { + surfaceListener->onRemoteDied(); + } +} +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + Surface::Surface(const sp& bufferProducer, bool controlledByApp, const sp& surfaceControlHandle) : mGraphicBufferProducer(bufferProducer), +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + mSurfaceDeathListener(nullptr), +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) mCrop(Rect::EMPTY_RECT), mBufferAge(0), mGenerationNumber(0), @@ -134,6 +153,12 @@ Surface::~Surface() { if (mConnectedToCpu) { Surface::disconnect(NATIVE_WINDOW_API_CPU); } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + if (mSurfaceDeathListener != nullptr) { + IInterface::asBinder(mGraphicBufferProducer)->unlinkToDeath(mSurfaceDeathListener); + mSurfaceDeathListener = nullptr; + } +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) } sp Surface::composerService() const { @@ -163,6 +188,12 @@ void Surface::allocateBuffers() { mReqFormat, mReqUsage); } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) +status_t Surface::allowAllocation(bool allowAllocation) { + return mGraphicBufferProducer->allowAllocation(allowAllocation); +} +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + status_t Surface::setGenerationNumber(uint32_t generation) { status_t result = mGraphicBufferProducer->setGenerationNumber(generation); if (result == NO_ERROR) { @@ -695,6 +726,51 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { return OK; } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + +status_t Surface::dequeueBuffer(sp* buffer, sp* outFence) { + if (buffer == nullptr || outFence == nullptr) { + return BAD_VALUE; + } + + android_native_buffer_t* anb; + int fd = -1; + status_t res = dequeueBuffer(&anb, &fd); + *buffer = GraphicBuffer::from(anb); + *outFence = sp::make(fd); + return res; +} + +status_t Surface::queueBuffer(const sp& buffer, const sp& fd, + SurfaceQueueBufferOutput* output) { + if (buffer == nullptr) { + return BAD_VALUE; + } + return queueBuffer(buffer.get(), fd ? fd->get() : -1, output); +} + +status_t Surface::detachBuffer(const sp& buffer) { + if (nullptr == buffer) { + return BAD_VALUE; + } + + Mutex::Autolock lock(mMutex); + + uint64_t bufferId = buffer->getId(); + for (int slot = 0; slot < Surface::NUM_BUFFER_SLOTS; ++slot) { + auto& bufferSlot = mSlots[slot]; + if (bufferSlot.buffer != nullptr && bufferSlot.buffer->getId() == bufferId) { + bufferSlot.buffer = nullptr; + bufferSlot.dirtyRegion = Region::INVALID_REGION; + return mGraphicBufferProducer->detachBuffer(slot); + } + } + + return BAD_VALUE; +} + +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + int Surface::dequeueBuffers(std::vector* buffers) { using DequeueBufferInput = IGraphicBufferProducer::DequeueBufferInput; using DequeueBufferOutput = IGraphicBufferProducer::DequeueBufferOutput; @@ -1118,6 +1194,140 @@ void Surface::onBufferQueuedLocked(int slot, sp fence, } } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + +int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd, + SurfaceQueueBufferOutput* surfaceOutput) { + ATRACE_CALL(); + ALOGV("Surface::queueBuffer"); + + IGraphicBufferProducer::QueueBufferOutput output; + IGraphicBufferProducer::QueueBufferInput input; + int slot; + sp fence; + { + Mutex::Autolock lock(mMutex); + + slot = getSlotFromBufferLocked(buffer); + if (slot < 0) { + if (fenceFd >= 0) { + close(fenceFd); + } + return slot; + } + if (mSharedBufferSlot == slot && mSharedBufferHasBeenQueued) { + if (fenceFd >= 0) { + close(fenceFd); + } + return OK; + } + + getQueueBufferInputLocked(buffer, fenceFd, mTimestamp, &input); + applyGrallocMetadataLocked(buffer, input); + fence = input.fence; + } + nsecs_t now = systemTime(); + // Drop the lock temporarily while we touch the underlying producer. In the case of a local + // BufferQueue, the following should be allowable: + // + // Surface::queueBuffer + // -> IConsumerListener::onFrameAvailable callback triggers automatically + // -> implementation calls IGraphicBufferConsumer::acquire/release immediately + // -> SurfaceListener::onBufferRelesed callback triggers automatically + // -> implementation calls Surface::dequeueBuffer + status_t err = mGraphicBufferProducer->queueBuffer(slot, input, &output); + { + Mutex::Autolock lock(mMutex); + + mLastQueueDuration = systemTime() - now; + if (err != OK) { + ALOGE("queueBuffer: error queuing buffer, %d", err); + } + + onBufferQueuedLocked(slot, fence, output); + } + + if (surfaceOutput != nullptr) { + *surfaceOutput = {.bufferReplaced = output.bufferReplaced}; + } + + return err; +} + +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) +int Surface::queueBuffers(const std::vector& buffers, + std::vector* queueBufferOutputs) +#else +int Surface::queueBuffers(const std::vector& buffers) +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) +{ + ATRACE_CALL(); + ALOGV("Surface::queueBuffers"); + + size_t numBuffers = buffers.size(); + std::vector igbpQueueBufferInputs(numBuffers); + std::vector igbpQueueBufferOutputs; + std::vector bufferSlots(numBuffers, -1); + std::vector> bufferFences(numBuffers); + + int err; + { + Mutex::Autolock lock(mMutex); + + if (mSharedBufferMode) { + ALOGE("%s: batched operation is not supported in shared buffer mode", __FUNCTION__); + return INVALID_OPERATION; + } + + for (size_t batchIdx = 0; batchIdx < numBuffers; batchIdx++) { + int i = getSlotFromBufferLocked(buffers[batchIdx].buffer); + if (i < 0) { + if (buffers[batchIdx].fenceFd >= 0) { + close(buffers[batchIdx].fenceFd); + } + return i; + } + bufferSlots[batchIdx] = i; + + IGraphicBufferProducer::QueueBufferInput input; + getQueueBufferInputLocked(buffers[batchIdx].buffer, buffers[batchIdx].fenceFd, + buffers[batchIdx].timestamp, &input); + input.slot = i; + bufferFences[batchIdx] = input.fence; + igbpQueueBufferInputs[batchIdx] = input; + } + } + nsecs_t now = systemTime(); + err = mGraphicBufferProducer->queueBuffers(igbpQueueBufferInputs, &igbpQueueBufferOutputs); + { + Mutex::Autolock lock(mMutex); + mLastQueueDuration = systemTime() - now; + if (err != OK) { + ALOGE("%s: error queuing buffer, %d", __FUNCTION__, err); + } + + for (size_t batchIdx = 0; batchIdx < numBuffers; batchIdx++) { + onBufferQueuedLocked(bufferSlots[batchIdx], bufferFences[batchIdx], + igbpQueueBufferOutputs[batchIdx]); + } + } + +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + if (queueBufferOutputs != nullptr) { + queueBufferOutputs->clear(); + queueBufferOutputs->resize(numBuffers); + for (size_t batchIdx = 0; batchIdx < numBuffers; batchIdx++) { + (*queueBufferOutputs)[batchIdx].bufferReplaced = + igbpQueueBufferOutputs[batchIdx].bufferReplaced; + } + } +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + + return err; +} + +#else + int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { ATRACE_CALL(); ALOGV("Surface::queueBuffer"); @@ -1205,6 +1415,8 @@ int Surface::queueBuffers(const std::vector& buffers) { return err; } +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + void Surface::querySupportedTimestampsLocked() const { // mMutex must be locked when calling this method. @@ -1860,30 +2072,23 @@ bool Surface::transformToDisplayInverse() const { } int Surface::connect(int api) { - static sp listener = new StubProducerListener(); + static sp listener = new StubSurfaceListener(); return connect(api, listener); } -int Surface::connect(int api, const sp& listener) { - return connect(api, listener, false); -} - -int Surface::connect( - int api, bool reportBufferRemoval, const sp& sListener) { - if (sListener != nullptr) { - mListenerProxy = new ProducerListenerProxy(this, sListener); - } - return connect(api, mListenerProxy, reportBufferRemoval); -} - -int Surface::connect( - int api, const sp& listener, bool reportBufferRemoval) { +int Surface::connect(int api, const sp& listener, bool reportBufferRemoval) { ATRACE_CALL(); ALOGV("Surface::connect"); Mutex::Autolock lock(mMutex); IGraphicBufferProducer::QueueBufferOutput output; mReportRemovedBuffers = reportBufferRemoval; - int err = mGraphicBufferProducer->connect(listener, api, mProducerControlledByApp, &output); + + if (listener != nullptr) { + mListenerProxy = new ProducerListenerProxy(this, listener); + } + + int err = + mGraphicBufferProducer->connect(mListenerProxy, api, mProducerControlledByApp, &output); if (err == NO_ERROR) { mDefaultWidth = output.width; mDefaultHeight = output.height; @@ -1898,6 +2103,13 @@ int Surface::connect( } mConsumerRunningBehind = (output.numPendingBuffers >= 2); + +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + if (listener && listener->needsDeathNotify()) { + mSurfaceDeathListener = sp::make(listener); + IInterface::asBinder(mGraphicBufferProducer)->linkToDeath(mSurfaceDeathListener); + } +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) } if (!err && api == NATIVE_WINDOW_API_CPU) { mConnectedToCpu = true; @@ -1911,7 +2123,6 @@ int Surface::connect( return err; } - int Surface::disconnect(int api, IGraphicBufferProducer::DisconnectMode mode) { ATRACE_CALL(); ALOGV("Surface::disconnect"); @@ -1939,6 +2150,14 @@ int Surface::disconnect(int api, IGraphicBufferProducer::DisconnectMode mode) { mConnectedToCpu = false; } } + +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + if (mSurfaceDeathListener != nullptr) { + IInterface::asBinder(mGraphicBufferProducer)->unlinkToDeath(mSurfaceDeathListener); + mSurfaceDeathListener = nullptr; + } +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + return err; } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 5db539497c3246d018ca513f9ca019ca053e3dc7..df58df43be75c026f2f0061189da4b3008ebd576 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -20,8 +20,11 @@ #include #include +#include + #include #include +#include #include #include #include @@ -40,7 +43,7 @@ #include -#include +#include #include #include #include @@ -86,7 +89,8 @@ int64_t generateId() { return (((int64_t)getpid()) << 32) | ++idCounter; } -void emptyCallback(nsecs_t, const sp&, const std::vector&) {} +constexpr int64_t INVALID_VSYNC = -1; + } // namespace const std::string SurfaceComposerClient::kEmpty{}; @@ -207,9 +211,168 @@ sp SurfaceComposerClient::getDefault() { return DefaultComposerClient::getComposerClient(); } +// --------------------------------------------------------------------------- + JankDataListener::~JankDataListener() { } +status_t JankDataListener::flushJankData() { + if (mLayerId == -1) { + return INVALID_OPERATION; + } + + binder::Status status = ComposerServiceAIDL::getComposerService()->flushJankData(mLayerId); + return statusTFromBinderStatus(status); +} + +std::mutex JankDataListenerFanOut::sFanoutInstanceMutex; +std::unordered_map> JankDataListenerFanOut::sFanoutInstances; + +binder::Status JankDataListenerFanOut::onJankData(const std::vector& jankData) { + // Find the highest VSync ID. + int64_t lastVsync = jankData.empty() + ? 0 + : std::max_element(jankData.begin(), jankData.end(), + [](const gui::JankData& jd1, const gui::JankData& jd2) { + return jd1.frameVsyncId < jd2.frameVsyncId; + }) + ->frameVsyncId; + + // Fan out the jank data callback. + std::vector> listenersToRemove; + for (auto listener : getActiveListeners()) { + if (!listener->onJankDataAvailable(jankData) || + (listener->mRemoveAfter >= 0 && listener->mRemoveAfter <= lastVsync)) { + listenersToRemove.push_back(listener); + } + } + + return removeListeners(listenersToRemove) + ? binder::Status::ok() + : binder::Status::fromExceptionCode(binder::Status::EX_NULL_POINTER); +} + +status_t JankDataListenerFanOut::addListener(sp sc, sp listener) { + sp layer = sc->getHandle(); + if (layer == nullptr) { + return UNEXPECTED_NULL; + } + int32_t layerId = sc->getLayerId(); + + sFanoutInstanceMutex.lock(); + auto it = sFanoutInstances.find(layerId); + bool registerNeeded = it == sFanoutInstances.end(); + sp fanout; + if (registerNeeded) { + fanout = sp::make(layerId); + sFanoutInstances.insert({layerId, fanout}); + } else { + fanout = it->second; + } + + fanout->mMutex.lock(); + fanout->mListeners.insert(listener); + fanout->mMutex.unlock(); + + sFanoutInstanceMutex.unlock(); + + if (registerNeeded) { + binder::Status status = + ComposerServiceAIDL::getComposerService()->addJankListener(layer, fanout); + return statusTFromBinderStatus(status); + } + return OK; +} + +status_t JankDataListenerFanOut::removeListener(sp listener) { + int32_t layerId = listener->mLayerId; + if (layerId == -1) { + return INVALID_OPERATION; + } + + int64_t removeAfter = INVALID_VSYNC; + sp fanout; + + sFanoutInstanceMutex.lock(); + auto it = sFanoutInstances.find(layerId); + if (it != sFanoutInstances.end()) { + fanout = it->second; + removeAfter = fanout->updateAndGetRemovalVSync(); + } + + if (removeAfter != INVALID_VSYNC) { + // Remove this instance from the map, so that no new listeners are added + // while we're scheduled to be removed. + sFanoutInstances.erase(layerId); + } + sFanoutInstanceMutex.unlock(); + + if (removeAfter < 0) { + return OK; + } + + binder::Status status = + ComposerServiceAIDL::getComposerService()->removeJankListener(layerId, fanout, + removeAfter); + return statusTFromBinderStatus(status); +} + +std::vector> JankDataListenerFanOut::getActiveListeners() { + std::scoped_lock lock(mMutex); + + std::vector> listeners; + for (auto it = mListeners.begin(); it != mListeners.end();) { + auto listener = it->promote(); + if (!listener) { + it = mListeners.erase(it); + } else { + listeners.push_back(std::move(listener)); + it++; + } + } + return listeners; +} + +bool JankDataListenerFanOut::removeListeners(const std::vector>& listeners) { + std::scoped_lock fanoutLock(sFanoutInstanceMutex); + std::scoped_lock listenersLock(mMutex); + + for (auto listener : listeners) { + mListeners.erase(listener); + } + + if (mListeners.empty()) { + sFanoutInstances.erase(mLayerId); + return false; + } + return true; +} + +int64_t JankDataListenerFanOut::updateAndGetRemovalVSync() { + std::scoped_lock lock(mMutex); + if (mRemoveAfter >= 0) { + // We've already been scheduled to be removed. Don't schedule again. + return INVALID_VSYNC; + } + + int64_t removeAfter = 0; + for (auto it = mListeners.begin(); it != mListeners.end();) { + auto listener = it->promote(); + if (!listener) { + it = mListeners.erase(it); + } else if (listener->mRemoveAfter < 0) { + // We have at least one listener that's still interested. Don't remove. + return INVALID_VSYNC; + } else { + removeAfter = std::max(removeAfter, listener->mRemoveAfter); + it++; + } + } + + mRemoveAfter = removeAfter; + return removeAfter; +} + // --------------------------------------------------------------------------- // TransactionCompletedListener does not use ANDROID_SINGLETON_STATIC_INSTANCE because it needs @@ -256,14 +419,6 @@ CallbackId TransactionCompletedListener::addCallbackFunction( surfaceControls, CallbackId::Type callbackType) { std::lock_guard lock(mMutex); - return addCallbackFunctionLocked(callbackFunction, surfaceControls, callbackType); -} - -CallbackId TransactionCompletedListener::addCallbackFunctionLocked( - const TransactionCompletedCallback& callbackFunction, - const std::unordered_set, SurfaceComposerClient::SCHash>& - surfaceControls, - CallbackId::Type callbackType) { startListeningLocked(); CallbackId callbackId(getNextIdLocked(), callbackType); @@ -272,33 +427,11 @@ CallbackId TransactionCompletedListener::addCallbackFunctionLocked( for (const auto& surfaceControl : surfaceControls) { callbackSurfaceControls[surfaceControl->getHandle()] = surfaceControl; - - if (callbackType == CallbackId::Type::ON_COMPLETE && - mJankListeners.count(surfaceControl->getLayerId()) != 0) { - callbackId.includeJankData = true; - } } return callbackId; } -void TransactionCompletedListener::addJankListener(const sp& listener, - sp surfaceControl) { - std::lock_guard lock(mMutex); - mJankListeners.insert({surfaceControl->getLayerId(), listener}); -} - -void TransactionCompletedListener::removeJankListener(const sp& listener) { - std::lock_guard lock(mMutex); - for (auto it = mJankListeners.begin(); it != mJankListeners.end();) { - if (it->second == listener) { - it = mJankListeners.erase(it); - } else { - it++; - } - } -} - void TransactionCompletedListener::setReleaseBufferCallback(const ReleaseCallbackId& callbackId, ReleaseBufferCallback listener) { std::scoped_lock lock(mMutex); @@ -325,32 +458,20 @@ void TransactionCompletedListener::removeSurfaceStatsListener(void* context, voi } void TransactionCompletedListener::addSurfaceControlToCallbacks( - SurfaceComposerClient::CallbackInfo& callbackInfo, - const sp& surfaceControl) { + const sp& surfaceControl, + const std::unordered_set& callbackIds) { std::lock_guard lock(mMutex); - bool includingJankData = false; - for (auto callbackId : callbackInfo.callbackIds) { + for (auto callbackId : callbackIds) { mCallbacks[callbackId].surfaceControls.emplace(std::piecewise_construct, std::forward_as_tuple( surfaceControl->getHandle()), std::forward_as_tuple(surfaceControl)); - includingJankData = includingJankData || callbackId.includeJankData; - } - - // If no registered callback is requesting jank data, but there is a jank listener registered - // on the new surface control, add a synthetic callback that requests the jank data. - if (!includingJankData && mJankListeners.count(surfaceControl->getLayerId()) != 0) { - CallbackId callbackId = - addCallbackFunctionLocked(&emptyCallback, callbackInfo.surfaceControls, - CallbackId::Type::ON_COMPLETE); - callbackInfo.callbackIds.emplace(callbackId); } } void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) { std::unordered_map callbacksMap; - std::multimap> jankListenersMap; { std::lock_guard lock(mMutex); @@ -366,7 +487,6 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener * sp that could possibly exist for the callbacks. */ callbacksMap = mCallbacks; - jankListenersMap = mJankListeners; for (const auto& transactionStats : listenerStats.transactionStats) { for (auto& callbackId : transactionStats.callbackIds) { mCallbacks.erase(callbackId); @@ -486,12 +606,6 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener transactionStats.presentFence, surfaceStats); } } - - if (surfaceStats.jankData.empty()) continue; - auto jankRange = jankListenersMap.equal_range(layerId); - for (auto it = jankRange.first; it != jankRange.second; it++) { - it->second->onJankDataAvailable(surfaceStats.jankData); - } } } } @@ -713,7 +827,6 @@ SurfaceComposerClient::Transaction::Transaction() { SurfaceComposerClient::Transaction::Transaction(const Transaction& other) : mId(other.mId), - mTransactionNestCount(other.mTransactionNestCount), mAnimation(other.mAnimation), mEarlyWakeupStart(other.mEarlyWakeupStart), mEarlyWakeupEnd(other.mEarlyWakeupEnd), @@ -753,7 +866,6 @@ SurfaceComposerClient::Transaction::createFromParcel(const Parcel* parcel) { status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel) { const uint64_t transactionId = parcel->readUint64(); - const uint32_t transactionNestCount = parcel->readUint32(); const bool animation = parcel->readBool(); const bool earlyWakeupStart = parcel->readBool(); const bool earlyWakeupEnd = parcel->readBool(); @@ -850,7 +962,6 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel // Parsing was successful. Update the object. mId = transactionId; - mTransactionNestCount = transactionNestCount; mAnimation = animation; mEarlyWakeupStart = earlyWakeupStart; mEarlyWakeupEnd = earlyWakeupEnd; @@ -882,7 +993,6 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const const_cast(this)->cacheBuffers(); parcel->writeUint64(mId); - parcel->writeUint32(mTransactionNestCount); parcel->writeBool(mAnimation); parcel->writeBool(mEarlyWakeupStart); parcel->writeBool(mEarlyWakeupEnd); @@ -1004,8 +1114,9 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr // register all surface controls for all callbackIds for this listener that is merging for (const auto& surfaceControl : currentProcessCallbackInfo.surfaceControls) { - mTransactionCompletedListener->addSurfaceControlToCallbacks(currentProcessCallbackInfo, - surfaceControl); + mTransactionCompletedListener + ->addSurfaceControlToCallbacks(surfaceControl, + currentProcessCallbackInfo.callbackIds); } } @@ -1033,7 +1144,6 @@ void SurfaceComposerClient::Transaction::clear() { mInputWindowCommands.clear(); mUncacheBuffers.clear(); mMayContainBuffer = false; - mTransactionNestCount = 0; mAnimation = false; mEarlyWakeupStart = false; mEarlyWakeupEnd = false; @@ -1362,7 +1472,7 @@ void SurfaceComposerClient::Transaction::registerSurfaceControlForCallback( auto& callbackInfo = mListenerCallbacks[TransactionCompletedListener::getIInstance()]; callbackInfo.surfaceControls.insert(sc); - mTransactionCompletedListener->addSurfaceControlToCallbacks(callbackInfo, sc); + mTransactionCompletedListener->addSurfaceControlToCallbacks(sc, callbackInfo.callbackIds); } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setPosition( @@ -1941,8 +2051,9 @@ SurfaceComposerClient::Transaction::setFrameRateSelectionPriority(const sp& sc, const gui::EdgeExtensionParameters& effect) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + + s->what |= layer_state_t::eEdgeExtensionChanged; + s->edgeExtensionParameters = effect; + return *this; +} + SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBufferCrop( const sp& sc, const Rect& bufferCrop) { layer_state_t* s = getLayerState(sc); @@ -2263,6 +2393,22 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDropI return *this; } +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBufferReleaseChannel( + const sp& sc, + const std::shared_ptr& channel) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + + s->what |= layer_state_t::eBufferReleaseChannelChanged; + s->bufferReleaseChannel = channel; + + registerSurfaceControlForCallback(sc); + return *this; +} + // --------------------------------------------------------------------------- DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp& token) { diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index c5f9c38ca3b276b73e634137a54c65d7976b8f5f..f126c0be2fb7e3cecd85b701798e11a2b71f69a6 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -139,9 +139,9 @@ sp SurfaceControl::generateSurfaceLocked() uint32_t ignore; auto flags = mCreateFlags & (ISurfaceComposerClient::eCursorWindow | ISurfaceComposerClient::eOpaque); - mBbqChild = mClient->createSurface(String8("bbq-wrapper"), 0, 0, mFormat, + mBbqChild = mClient->createSurface(String8::format("[BBQ] %s", mName.c_str()), 0, 0, mFormat, flags, mHandle, {}, &ignore); - mBbq = sp::make("bbq-adapter", mBbqChild, mWidth, mHeight, mFormat); + mBbq = sp::make("[BBQ]" + mName, mBbqChild, mWidth, mHeight, mFormat); // This surface is always consumed by SurfaceFlinger, so the // producerControlledByApp value doesn't matter; using false. diff --git a/libs/gui/WindowInfosListenerReporter.cpp b/libs/gui/WindowInfosListenerReporter.cpp index 0929b8e1202a16e40d60fc2eb2eff4a25ea22350..91c9a85149e9eefba12a508bba25cfe239a77194 100644 --- a/libs/gui/WindowInfosListenerReporter.cpp +++ b/libs/gui/WindowInfosListenerReporter.cpp @@ -15,7 +15,7 @@ */ #include -#include +#include #include #include "gui/WindowInfosUpdate.h" diff --git a/libs/gui/aidl/Android.bp b/libs/gui/aidl/Android.bp index 8ed08c2644b7189ef4426dd55a9ee90cbef73696..fd035f60f55593022caf3215607a7d810562a1ec 100644 --- a/libs/gui/aidl/Android.bp +++ b/libs/gui/aidl/Android.bp @@ -28,9 +28,6 @@ filegroup { ":libgui_extra_unstructured_aidl_files", "android/gui/BitTube.aidl", - "android/gui/CaptureArgs.aidl", - "android/gui/DisplayCaptureArgs.aidl", - "android/gui/LayerCaptureArgs.aidl", "android/gui/LayerMetadata.aidl", "android/gui/ParcelableVsyncEventData.aidl", "android/gui/ScreenCaptureResults.aidl", diff --git a/libs/gui/aidl/android/gui/CaptureArgs.aidl b/libs/gui/aidl/android/gui/CaptureArgs.aidl index 9f198cae104acbd87bf02f5a5c6946b935dc2238..4920344e0ea753ccd7c44b5328d549238dbfd21b 100644 --- a/libs/gui/aidl/android/gui/CaptureArgs.aidl +++ b/libs/gui/aidl/android/gui/CaptureArgs.aidl @@ -16,4 +16,63 @@ package android.gui; -parcelable CaptureArgs cpp_header "gui/DisplayCaptureArgs.h" rust_type "gui_aidl_types_rs::CaptureArgs"; +import android.gui.ARect; + +// Common arguments for capturing content on-screen +parcelable CaptureArgs { + const int UNSET_UID = -1; + + // Desired pixel format of the final screenshotted buffer + int /*ui::PixelFormat*/ pixelFormat = 1; + + // Crop in layer space: all content outside of the crop will not be captured. + ARect sourceCrop; + + // Scale in the x-direction for the screenshotted result. + float frameScaleX = 1.0f; + + // Scale in the y-direction for the screenshotted result. + float frameScaleY = 1.0f; + + // True if capturing secure layers is permitted + boolean captureSecureLayers = false; + + // UID whose content we want to screenshot + int uid = UNSET_UID; + + // Force capture to be in a color space. If the value is ui::Dataspace::UNKNOWN, the captured + // result will be in a colorspace appropriate for capturing the display contents + // The display may use non-RGB dataspace (ex. displayP3) that could cause pixel data could be + // different from SRGB (byte per color), and failed when checking colors in tests. + // NOTE: In normal cases, we want the screen to be captured in display's colorspace. + int /*ui::Dataspace*/ dataspace = 0; + + // The receiver of the capture can handle protected buffer. A protected buffer has + // GRALLOC_USAGE_PROTECTED usage bit and must not be accessed unprotected behaviour. + // Any read/write access from unprotected context will result in undefined behaviour. + // Protected contents are typically DRM contents. This has no direct implication to the + // secure property of the surface, which is specified by the application explicitly to avoid + // the contents being accessed/captured by screenshot or unsecure display. + boolean allowProtected = false; + + // True if the content should be captured in grayscale + boolean grayscale = false; + + // List of layers to exclude capturing from + IBinder[] excludeHandles; + + // Hint that the caller will use the screenshot animation as part of a transition animation. + // The canonical example would be screen rotation - in such a case any color shift in the + // screenshot is a detractor so composition in the display's colorspace is required. + // Otherwise, the system may choose a colorspace that is more appropriate for use-cases + // such as file encoding or for blending HDR content into an ap's UI, where the display's + // exact colorspace is not an appropriate intermediate result. + // Note that if the caller is requesting a specific dataspace, this hint does nothing. + boolean hintForSeamlessTransition = false; + + // Allows the screenshot to attach a gainmap, which allows for a per-pixel + // transformation of the screenshot to another luminance range, typically + // mapping an SDR base image into HDR. + boolean attachGainmap = false; +} + diff --git a/libs/gui/aidl/android/gui/DisplayCaptureArgs.aidl b/libs/gui/aidl/android/gui/DisplayCaptureArgs.aidl index fc97dbf03d966e25ff365a2c85c2b9e0972af200..e00a2dfa82ecb806f3fa52327a10ede30d47ae77 100644 --- a/libs/gui/aidl/android/gui/DisplayCaptureArgs.aidl +++ b/libs/gui/aidl/android/gui/DisplayCaptureArgs.aidl @@ -16,5 +16,18 @@ package android.gui; -parcelable DisplayCaptureArgs cpp_header "gui/DisplayCaptureArgs.h" rust_type "gui_aidl_types_rs::DisplayCaptureArgs"; +import android.gui.CaptureArgs; + +// Arguments for screenshotting an entire display +parcelable DisplayCaptureArgs { + CaptureArgs captureArgs; + + // The display that we want to screenshot + IBinder displayToken; + + // The width of the render area when we screenshot + int width = 0; + // The length of the render area when we screenshot + int height = 0; +} diff --git a/libs/gui/aidl/android/gui/EdgeExtensionParameters.aidl b/libs/gui/aidl/android/gui/EdgeExtensionParameters.aidl new file mode 100644 index 0000000000000000000000000000000000000000..44f4259f746e518b47923d1608a1d18a620b34ce --- /dev/null +++ b/libs/gui/aidl/android/gui/EdgeExtensionParameters.aidl @@ -0,0 +1,27 @@ +/* + * Copyright 2024 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 */ +parcelable EdgeExtensionParameters { + // These represent the translation of the window as requested by the animation + boolean extendRight; + boolean extendLeft; + boolean extendTop; + boolean extendBottom; +} \ No newline at end of file diff --git a/libs/gui/aidl/android/gui/IJankListener.aidl b/libs/gui/aidl/android/gui/IJankListener.aidl new file mode 100644 index 0000000000000000000000000000000000000000..2bfd1af69da3be2c953979b0dda2c12f540b520c --- /dev/null +++ b/libs/gui/aidl/android/gui/IJankListener.aidl @@ -0,0 +1,29 @@ +/* + * Copyright 2024 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; + +import android.gui.JankData; + +/** @hide */ +interface IJankListener { + + /** + * Callback reporting jank data of the most recent frames. + * @See {@link ISurfaceComposer#addJankListener(IBinder, IJankListener)} + */ + void onJankData(in JankData[] data); +} diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl index 6d018ea7ef666c77e36e3f0db98528fa9a289453..ac14138e8c1addf6c2b16d799e562b267b4b07a1 100644 --- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl +++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl @@ -42,6 +42,7 @@ import android.gui.ISurfaceComposerClient; import android.gui.ITunnelModeEnabledListener; import android.gui.IWindowInfosListener; import android.gui.IWindowInfosPublisher; +import android.gui.IJankListener; import android.gui.LayerCaptureArgs; import android.gui.OverlayProperties; import android.gui.PullAtomData; @@ -580,4 +581,22 @@ interface ISurfaceComposer { * This method should not block the ShutdownThread therefore it's handled asynchronously. */ oneway void notifyShutdown(); + + /** + * Registers the jank listener on the given layer to receive jank data of future frames. + */ + void addJankListener(IBinder layer, IJankListener listener); + + /** + * Flushes any pending jank data on the given layer to any registered listeners on that layer. + */ + oneway void flushJankData(int layerId); + + /** + * Schedules the removal of the jank listener from the given layer after the VSync with the + * specified ID. Use a value <= 0 for afterVsync to remove the listener immediately. The given + * listener will not be removed before the given VSync, but may still receive data for frames + * past the provided VSync. + */ + oneway void removeJankListener(int layerId, IJankListener listener, long afterVsync); } diff --git a/libs/gui/aidl/android/gui/JankData.aidl b/libs/gui/aidl/android/gui/JankData.aidl new file mode 100644 index 0000000000000000000000000000000000000000..ec13681182d6a05fbe9b5f6fb7bd8302c8be4235 --- /dev/null +++ b/libs/gui/aidl/android/gui/JankData.aidl @@ -0,0 +1,45 @@ +/* + * Copyright 2024 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 */ +parcelable JankData { + /** + * Identifier for the frame submitted with Transaction.setFrameTimelineVsyncId + */ + long frameVsyncId; + + /** + * Bitmask of jank types that occurred. + */ + int jankType; + + /** + * Time between frames in nanoseconds. + */ + long frameIntervalNs; + + /** + * Time allocated to the application to render this frame. + */ + long scheduledAppFrameTimeNs; + + /** + * Time taken by the application to render this frame. + */ + long actualAppFrameTimeNs; +} diff --git a/libs/gui/aidl/android/gui/LayerCaptureArgs.aidl b/libs/gui/aidl/android/gui/LayerCaptureArgs.aidl index 18d293f2118fc67a36bae0b46d92425bb1088c6c..004c35a5ce99b456580d07855326fccc77434f45 100644 --- a/libs/gui/aidl/android/gui/LayerCaptureArgs.aidl +++ b/libs/gui/aidl/android/gui/LayerCaptureArgs.aidl @@ -16,4 +16,15 @@ package android.gui; -parcelable LayerCaptureArgs cpp_header "gui/LayerCaptureArgs.h" rust_type "gui_aidl_types_rs::LayerCaptureArgs"; +import android.gui.CaptureArgs; + +// Arguments for capturing a layer and/or its children +parcelable LayerCaptureArgs { + CaptureArgs captureArgs; + + // The Layer that we may want to capture. We would also capture its children + IBinder layerHandle; + // True if we don't actually want to capture the layer and want to capture + // its children instead. + boolean childrenOnly = false; +} diff --git a/libs/gui/aidl/android/gui/ScreenCaptureResults.aidl b/libs/gui/aidl/android/gui/ScreenCaptureResults.aidl index 97a903515bf4c548c8a9ab8c861c74b3020e6ebf..f4ef16dc714f6b47a58b6b93c5760a921c1a6288 100644 --- a/libs/gui/aidl/android/gui/ScreenCaptureResults.aidl +++ b/libs/gui/aidl/android/gui/ScreenCaptureResults.aidl @@ -16,4 +16,4 @@ package android.gui; -parcelable ScreenCaptureResults cpp_header "gui/ScreenCaptureResults.h" rust_type "gui_aidl_types_rs::ScreenCaptureResults"; \ No newline at end of file +parcelable ScreenCaptureResults cpp_header "gui/ScreenCaptureResults.h" rust_type "gui_aidl_types_rs::ScreenCaptureResults"; diff --git a/libs/gui/include/gui/AidlStatusUtil.h b/libs/gui/include/gui/AidlUtil.h similarity index 85% rename from libs/gui/include/gui/AidlStatusUtil.h rename to libs/gui/include/gui/AidlUtil.h index 55be27bf3547d59f7d7b5cf9dc0a0210b472db74..a3ecd84ba1365d30e980831efafce9cd7a4508d5 100644 --- a/libs/gui/include/gui/AidlStatusUtil.h +++ b/libs/gui/include/gui/AidlUtil.h @@ -16,9 +16,11 @@ #pragma once +#include #include +#include -// Extracted from frameworks/av/media/libaudioclient/include/media/AidlConversionUtil.h +// Originally extracted from frameworks/av/media/libaudioclient/include/media/AidlConversionUtil.h namespace android::gui::aidl_utils { /** @@ -68,7 +70,7 @@ static inline status_t statusTFromExceptionCode(int32_t exceptionCode) { * * return_type method(type0 param0, ...) */ -static inline status_t statusTFromBinderStatus(const ::android::binder::Status &status) { +static inline status_t statusTFromBinderStatus(const ::android::binder::Status& status) { return status.isOk() ? OK // check OK, : status.serviceSpecificErrorCode() // service-side error, not standard Java exception // (fromServiceSpecificError) @@ -84,8 +86,8 @@ static inline status_t statusTFromBinderStatus(const ::android::binder::Status & * where Java callers expect an exception, not an integer return value. */ static inline ::android::binder::Status binderStatusFromStatusT( - status_t status, const char *optionalMessage = nullptr) { - const char *const emptyIfNull = optionalMessage == nullptr ? "" : optionalMessage; + status_t status, const char* optionalMessage = nullptr) { + const char* const emptyIfNull = optionalMessage == nullptr ? "" : optionalMessage; // From binder::Status instructions: // Prefer a generic exception code when possible, then a service specific // code, and finally a status_t for low level failures or legacy support. @@ -111,4 +113,26 @@ static inline ::android::binder::Status binderStatusFromStatusT( return Status::fromServiceSpecificError(status, emptyIfNull); } +static inline Rect fromARect(ARect rect) { + return Rect(rect.left, rect.top, rect.right, rect.bottom); +} + +static inline ARect toARect(Rect rect) { + ARect aRect; + + aRect.left = rect.left; + aRect.top = rect.top; + aRect.right = rect.right; + aRect.bottom = rect.bottom; + return aRect; +} + +static inline ARect toARect(int32_t left, int32_t top, int32_t right, int32_t bottom) { + return toARect(Rect(left, top, right, bottom)); +} + +static inline ARect toARect(int32_t width, int32_t height) { + return toARect(Rect(width, height)); +} + } // namespace android::gui::aidl_utils diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 0e1a505c69c724122b40b4f44b8fa517410810b2..8592cffd156c4a053e0806c2fad7978ad8a6a6b4 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -17,9 +17,10 @@ #ifndef ANDROID_GUI_BLAST_BUFFER_QUEUE_H #define ANDROID_GUI_BLAST_BUFFER_QUEUE_H +#include #include #include - +#include #include #include @@ -28,7 +29,6 @@ #include #include -#include #include #include @@ -40,12 +40,20 @@ class BufferItemConsumer; class BLASTBufferItemConsumer : public BufferItemConsumer { public: +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + BLASTBufferItemConsumer(const sp& producer, + const sp& consumer, uint64_t consumerUsage, + int bufferCount, bool controlledByApp, wp bbq) + : BufferItemConsumer(producer, consumer, consumerUsage, bufferCount, controlledByApp), +#else BLASTBufferItemConsumer(const sp& consumer, uint64_t consumerUsage, int bufferCount, bool controlledByApp, wp bbq) : BufferItemConsumer(consumer, consumerUsage, bufferCount, controlledByApp), +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) mBLASTBufferQueue(std::move(bbq)), mCurrentlyConnected(false), - mPreviouslyConnected(false) {} + mPreviouslyConnected(false) { + } void onDisconnect() override EXCLUDES(mMutex); void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps, @@ -95,15 +103,21 @@ public: void onFrameDequeued(const uint64_t) override; void onFrameCancelled(const uint64_t) override; + TransactionCompletedCallbackTakesContext makeTransactionCommittedCallbackThunk(); void transactionCommittedCallback(nsecs_t latchTime, const sp& presentFence, const std::vector& stats); + + TransactionCompletedCallbackTakesContext makeTransactionCallbackThunk(); virtual void transactionCallback(nsecs_t latchTime, const sp& presentFence, const std::vector& stats); + + ReleaseBufferCallback makeReleaseBufferCallbackThunk(); void releaseBufferCallback(const ReleaseCallbackId& id, const sp& releaseFence, std::optional currentMaxAcquiredBufferCount); void releaseBufferCallbackLocked(const ReleaseCallbackId& id, const sp& releaseFence, std::optional currentMaxAcquiredBufferCount, bool fakeRelease) REQUIRES(mMutex); + bool syncNextTransaction(std::function callback, bool acquireSingleBuffer = true); void stopContinuousSyncTransaction(); @@ -128,9 +142,11 @@ public: * indicates the reason for the hang. */ void setTransactionHangCallback(std::function callback); - + void setApplyToken(sp); virtual ~BLASTBufferQueue(); + void onFirstRef() override; + private: friend class BLASTBufferQueueHelper; friend class BBQBufferQueueProducer; @@ -170,8 +186,7 @@ private: // BufferQueue internally allows 1 more than // the max to be acquired - int32_t mMaxAcquiredBuffers = 1; - + int32_t mMaxAcquiredBuffers GUARDED_BY(mMutex) = 1; int32_t mNumFrameAvailable GUARDED_BY(mMutex) = 0; int32_t mNumAcquired GUARDED_BY(mMutex) = 0; @@ -256,7 +271,7 @@ private: // Queues up transactions using this token in SurfaceFlinger. This prevents queued up // transactions from other parts of the client from blocking this transaction. - const sp mApplyToken GUARDED_BY(mMutex) = sp::make(); + sp mApplyToken GUARDED_BY(mMutex) = sp::make(); // Guards access to mDequeueTimestamps since we cannot hold to mMutex in onFrameDequeued or // we will deadlock. @@ -300,6 +315,51 @@ private: std::function mTransactionHangCallback; std::unordered_set mSyncedFrameNumbers GUARDED_BY(mMutex); + +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) + class BufferReleaseReader { + public: + BufferReleaseReader() = default; + BufferReleaseReader(std::unique_ptr); + BufferReleaseReader& operator=(BufferReleaseReader&&); + + // Block until we can read a buffer release message. + // + // Returns: + // * OK if a ReleaseCallbackId and Fence were successfully read. + // * WOULD_BLOCK if the blocking read was interrupted by interruptBlockingRead. + // * UNKNOWN_ERROR if something went wrong. + status_t readBlocking(ReleaseCallbackId& outId, sp& outReleaseFence, + uint32_t& outMaxAcquiredBufferCount); + + // Signals the reader's eventfd to wake up any threads waiting on readBlocking. + void interruptBlockingRead(); + + private: + std::mutex mMutex; + std::unique_ptr mEndpoint GUARDED_BY(mMutex); + android::base::unique_fd mEpollFd; + android::base::unique_fd mEventFd; + }; + + // BufferReleaseChannel is used to communicate buffer releases from SurfaceFlinger to + // the client. See BBQBufferQueueProducer::dequeueBuffer for details. + std::shared_ptr mBufferReleaseReader; + std::shared_ptr mBufferReleaseProducer; + + class BufferReleaseThread { + public: + BufferReleaseThread() = default; + ~BufferReleaseThread(); + void start(const sp&); + + private: + std::shared_ptr mRunning; + std::shared_ptr mReader; + }; + + BufferReleaseThread mBufferReleaseThread; +#endif }; } // namespace android diff --git a/libs/gui/include/gui/BufferItemConsumer.h b/libs/gui/include/gui/BufferItemConsumer.h index a905610ee25ff0a1bf0bbae304d4dde595748dd1..6810edaf7c016312911b949d8b61e0534bb63a71 100644 --- a/libs/gui/include/gui/BufferItemConsumer.h +++ b/libs/gui/include/gui/BufferItemConsumer.h @@ -17,13 +17,15 @@ #ifndef ANDROID_GUI_BUFFERITEMCONSUMER_H #define ANDROID_GUI_BUFFERITEMCONSUMER_H -#include +#include #include +#include #define ANDROID_GRAPHICS_BUFFERITEMCONSUMER_JNI_ID "mBufferItemConsumer" namespace android { +class GraphicBuffer; class String8; /** @@ -51,9 +53,17 @@ class BufferItemConsumer: public ConsumerBase // access at the same time. // controlledByApp tells whether this consumer is controlled by the // application. +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + BufferItemConsumer(uint64_t consumerUsage, int bufferCount = DEFAULT_MAX_BUFFERS, + bool controlledByApp = false, bool isConsumerSurfaceFlinger = false); + BufferItemConsumer(const sp& consumer, uint64_t consumerUsage, + int bufferCount = DEFAULT_MAX_BUFFERS, bool controlledByApp = false) + __attribute((deprecated("Prefer ctors that create their own surface and consumer."))); +#else BufferItemConsumer(const sp& consumer, uint64_t consumerUsage, int bufferCount = DEFAULT_MAX_BUFFERS, bool controlledByApp = false); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) ~BufferItemConsumer() override; @@ -85,7 +95,25 @@ class BufferItemConsumer: public ConsumerBase status_t releaseBuffer(const BufferItem &item, const sp& releaseFence = Fence::NO_FENCE); - private: +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + status_t releaseBuffer(const sp& buffer, + const sp& releaseFence = Fence::NO_FENCE); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + +protected: +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + // This should only be used by BLASTBufferQueue: + BufferItemConsumer(const sp& producer, + const sp& consumer, uint64_t consumerUsage, + int bufferCount = DEFAULT_MAX_BUFFERS, bool controlledByApp = false); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + +private: + void initialize(uint64_t consumerUsage, int bufferCount); + + status_t releaseBufferSlotLocked(int slotIndex, const sp& buffer, + const sp& releaseFence); + void freeBufferLocked(int slotIndex) override; // mBufferFreedListener is the listener object that will be called when diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h index bb52c8ec883bd7ec9e6d764ca000f34b39d28d1a..d5dd7c897cf6f2ca415e661864714e22b3f0549b 100644 --- a/libs/gui/include/gui/BufferQueueCore.h +++ b/libs/gui/include/gui/BufferQueueCore.h @@ -192,6 +192,10 @@ private: // callback is registered by the listener. When set to false, // mConnectedProducerListener will not trigger onBufferReleased() callback. bool mBufferReleasedCbEnabled; + // mBufferAttachedCbEnabled is used to indicate whether onBufferAttached() + // callback is registered by the listener. When set to false, + // mConnectedProducerListener will not trigger onBufferAttached() callback. + bool mBufferAttachedCbEnabled; // mSlots is an array of buffer slots that must be mirrored on the producer // side. This allows buffer ownership to be transferred between the producer diff --git a/libs/gui/include/gui/BufferReleaseChannel.h b/libs/gui/include/gui/BufferReleaseChannel.h new file mode 100644 index 0000000000000000000000000000000000000000..51fe0b6fab780f97062242069722244f256d119d --- /dev/null +++ b/libs/gui/include/gui/BufferReleaseChannel.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2024 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 +#include + +#include + +#include +#include +#include +#include + +namespace android::gui { + +/** + * IPC wrapper to pass release fences from SurfaceFlinger to apps via a local unix domain socket. + */ +class BufferReleaseChannel { +private: + class Endpoint { + public: + Endpoint(std::string name, android::base::unique_fd fd) + : mName(std::move(name)), mFd(std::move(fd)) {} + Endpoint() {} + + Endpoint(Endpoint&&) noexcept = default; + Endpoint& operator=(Endpoint&&) noexcept = default; + + Endpoint(const Endpoint&) = delete; + void operator=(const Endpoint&) = delete; + + const android::base::unique_fd& getFd() const { return mFd; } + + protected: + std::string mName; + android::base::unique_fd mFd; + }; + +public: + class ConsumerEndpoint : public Endpoint { + public: + ConsumerEndpoint(std::string name, android::base::unique_fd fd) + : Endpoint(std::move(name), std::move(fd)) {} + + /** + * Reads a release fence from the BufferReleaseChannel. + * + * Returns OK on success. + * Returns WOULD_BLOCK if there is no fence present. + * Other errors probably indicate that the channel is broken. + */ + status_t readReleaseFence(ReleaseCallbackId& outReleaseCallbackId, + sp& outReleaseFence, uint32_t& maxAcquiredBufferCount); + + private: + std::vector mFlattenedBuffer; + }; + + class ProducerEndpoint : public Endpoint, public Parcelable { + public: + ProducerEndpoint(std::string name, android::base::unique_fd fd) + : Endpoint(std::move(name), std::move(fd)) {} + ProducerEndpoint() {} + + status_t readFromParcel(const android::Parcel* parcel) override; + status_t writeToParcel(android::Parcel* parcel) const override; + + status_t writeReleaseFence(const ReleaseCallbackId&, const sp& releaseFence, + uint32_t maxAcquiredBufferCount); + + private: + std::vector mFlattenedBuffer; + }; + + /** + * Create two endpoints that make up the BufferReleaseChannel. + * + * Return OK on success. + */ + static status_t open(const std::string name, std::unique_ptr& outConsumer, + std::shared_ptr& outProducer); + + struct Message : public Flattenable { + ReleaseCallbackId releaseCallbackId; + sp releaseFence = Fence::NO_FENCE; + uint32_t maxAcquiredBufferCount; + + Message() = default; + Message(ReleaseCallbackId releaseCallbackId, sp releaseFence, + uint32_t maxAcquiredBufferCount) + : releaseCallbackId{releaseCallbackId}, + releaseFence{std::move(releaseFence)}, + maxAcquiredBufferCount{maxAcquiredBufferCount} {} + + // Flattenable protocol + size_t getFlattenedSize() const; + + size_t getFdCount() const { return releaseFence->getFdCount(); } + + status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const; + + status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count); + + private: + size_t getPodSize() const; + }; +}; + +} // namespace android::gui diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h index 8ff0cd0f6e2dc26f8d09dd6487876e746e55ec2c..e976aa48be10957ef74dc2e28e5b9e6200987371 100644 --- a/libs/gui/include/gui/ConsumerBase.h +++ b/libs/gui/include/gui/ConsumerBase.h @@ -17,18 +17,17 @@ #ifndef ANDROID_GUI_CONSUMERBASE_H #define ANDROID_GUI_CONSUMERBASE_H +#include #include #include #include +#include #include - #include - #include #include #include - namespace android { // ---------------------------------------------------------------------------- @@ -76,12 +75,28 @@ public: void dumpState(String8& result) const; void dumpState(String8& result, const char* prefix) const; +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + // Returns a Surface that can be used as the producer for this consumer. + sp getSurface() const; + + // DEPRECATED, DO NOT USE. Returns the underlying IGraphicBufferConsumer + // that backs this ConsumerBase. + sp getIGraphicBufferConsumer() const + __attribute((deprecated("DO NOT USE: Temporary hack for refactoring"))); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + // setFrameAvailableListener sets the listener object that will be notified // when a new frame becomes available. void setFrameAvailableListener(const wp& listener); // See IGraphicBufferConsumer::detachBuffer - status_t detachBuffer(int slot); + status_t detachBuffer(int slot) __attribute(( + deprecated("Please use the GraphicBuffer variant--slots are deprecated."))); + +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + // See IGraphicBufferConsumer::detachBuffer + status_t detachBuffer(const sp& buffer); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) // See IGraphicBufferConsumer::setDefaultBufferSize status_t setDefaultBufferSize(uint32_t width, uint32_t height); @@ -98,9 +113,18 @@ public: // See IGraphicBufferConsumer::setTransformHint status_t setTransformHint(uint32_t hint); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + // See IGraphicBufferConsumer::setMaxBufferCount + status_t setMaxBufferCount(int bufferCount); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + // See IGraphicBufferConsumer::setMaxAcquiredBufferCount status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + status_t setConsumerIsProtected(bool isProtected); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + // See IGraphicBufferConsumer::getSidebandStream sp getSidebandStream() const; @@ -115,12 +139,24 @@ private: ConsumerBase(const ConsumerBase&); void operator=(const ConsumerBase&); + void initialize(bool controlledByApp); + protected: // ConsumerBase constructs a new ConsumerBase object to consume image // buffers from the given IGraphicBufferConsumer. // The controlledByApp flag indicates that this consumer is under the application's // control. +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + explicit ConsumerBase(bool controlledByApp = false, bool consumerIsSurfaceFlinger = false); + explicit ConsumerBase(const sp& producer, + const sp& consumer, bool controlledByApp = false); + + explicit ConsumerBase(const sp& consumer, bool controlledByApp = false) + __attribute((deprecated("ConsumerBase should own its own producer, and constructing it " + "without one is fragile! This method is going away soon."))); +#else explicit ConsumerBase(const sp& consumer, bool controlledByApp = false); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) // onLastStrongRef gets called by RefBase just before the dtor of the most // derived class. It is used to clean up the buffers so that ConsumerBase @@ -150,6 +186,10 @@ protected: virtual void onBuffersReleased() override; virtual void onSidebandStreamChanged() override; + virtual int getSlotForBufferLocked(const sp& buffer); + + virtual status_t detachBufferLocked(int slotIndex); + // freeBufferLocked frees up the given buffer slot. If the slot has been // initialized this will release the reference to the GraphicBuffer in that // slot. Otherwise it has no effect. @@ -264,10 +304,16 @@ protected: Mutex mFrameAvailableMutex; wp mFrameAvailableListener; - // The ConsumerBase has-a BufferQueue and is responsible for creating this object - // if none is supplied + // The ConsumerBase has-a BufferQueue and is responsible for creating these + // objects if not supplied. sp mConsumer; +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + // This Surface wraps the IGraphicBufferConsumer created for this + // ConsumerBase. + sp mSurface; +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + // The final release fence of the most recent buffer released by // releaseBufferLocked. sp mPrevFinalReleaseFence; diff --git a/libs/gui/include/gui/CpuConsumer.h b/libs/gui/include/gui/CpuConsumer.h index 806fbe8aa0f020e653a5189f76d9d95736e311c8..2bba61bbe84193931d057cd3a2803e1f07b5b1db 100644 --- a/libs/gui/include/gui/CpuConsumer.h +++ b/libs/gui/include/gui/CpuConsumer.h @@ -19,8 +19,9 @@ #include -#include +#include #include +#include #include @@ -91,8 +92,17 @@ class CpuConsumer : public ConsumerBase // Create a new CPU consumer. The maxLockedBuffers parameter specifies // how many buffers can be locked for user access at the same time. +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + CpuConsumer(size_t maxLockedBuffers, bool controlledByApp = false, + bool isConsumerSurfaceFlinger = false); + + CpuConsumer(const sp& bq, size_t maxLockedBuffers, + bool controlledByApp = false) + __attribute((deprecated("Prefer ctors that create their own surface and consumer."))); +#else CpuConsumer(const sp& bq, size_t maxLockedBuffers, bool controlledByApp = false); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) // Gets the next graphics buffer from the producer and locks it for CPU use, // filling out the passed-in locked buffer structure with the native pointer diff --git a/libs/gui/include/gui/DisplayCaptureArgs.h b/libs/gui/include/gui/DisplayCaptureArgs.h deleted file mode 100644 index e29ce41bd5c45de8cd67d9446eb56d1e37b89904..0000000000000000000000000000000000000000 --- a/libs/gui/include/gui/DisplayCaptureArgs.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2022 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 -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace android::gui { - -struct CaptureArgs : public Parcelable { - const static int32_t UNSET_UID = -1; - virtual ~CaptureArgs() = default; - - ui::PixelFormat pixelFormat{ui::PixelFormat::RGBA_8888}; - Rect sourceCrop; - float frameScaleX{1}; - float frameScaleY{1}; - bool captureSecureLayers{false}; - int32_t uid{UNSET_UID}; - // Force capture to be in a color space. If the value is ui::Dataspace::UNKNOWN, the captured - // result will be in a colorspace appropriate for capturing the display contents - // The display may use non-RGB dataspace (ex. displayP3) that could cause pixel data could be - // different from SRGB (byte per color), and failed when checking colors in tests. - // NOTE: In normal cases, we want the screen to be captured in display's colorspace. - ui::Dataspace dataspace = ui::Dataspace::UNKNOWN; - - // The receiver of the capture can handle protected buffer. A protected buffer has - // GRALLOC_USAGE_PROTECTED usage bit and must not be accessed unprotected behaviour. - // Any read/write access from unprotected context will result in undefined behaviour. - // Protected contents are typically DRM contents. This has no direct implication to the - // secure property of the surface, which is specified by the application explicitly to avoid - // the contents being accessed/captured by screenshot or unsecure display. - bool allowProtected = false; - - bool grayscale = false; - - std::unordered_set, SpHash> excludeHandles; - - // Hint that the caller will use the screenshot animation as part of a transition animation. - // The canonical example would be screen rotation - in such a case any color shift in the - // screenshot is a detractor so composition in the display's colorspace is required. - // Otherwise, the system may choose a colorspace that is more appropriate for use-cases - // such as file encoding or for blending HDR content into an ap's UI, where the display's - // exact colorspace is not an appropriate intermediate result. - // Note that if the caller is requesting a specific dataspace, this hint does nothing. - bool hintForSeamlessTransition = false; - - virtual status_t writeToParcel(Parcel* output) const; - virtual status_t readFromParcel(const Parcel* input); -}; - -struct DisplayCaptureArgs : CaptureArgs { - sp displayToken; - uint32_t width{0}; - uint32_t height{0}; - - status_t writeToParcel(Parcel* output) const override; - status_t readFromParcel(const Parcel* input) override; -}; - -}; // namespace android::gui diff --git a/libs/gui/include/gui/Flags.h b/libs/gui/include/gui/Flags.h new file mode 100644 index 0000000000000000000000000000000000000000..735375a1e71d30e9711cbf3e75f9c6ec1a1c26d1 --- /dev/null +++ b/libs/gui/include/gui/Flags.h @@ -0,0 +1,24 @@ +/* + * Copyright 2024 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 + +#define WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES \ + (COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CAMERA3_AND_PROCESSORS) && \ + COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) && \ + COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)) \ No newline at end of file diff --git a/libs/gui/include/gui/FrameTimestamps.h b/libs/gui/include/gui/FrameTimestamps.h index 3d1be4d2ebc20918209b1cc3d38a10708ea5d39b..462081bfd27fa2dfa477f093979c38c29a18c245 100644 --- a/libs/gui/include/gui/FrameTimestamps.h +++ b/libs/gui/include/gui/FrameTimestamps.h @@ -116,7 +116,7 @@ public: // Public for testing. static nsecs_t snapToNextTick( nsecs_t timestamp, nsecs_t tickPhase, nsecs_t tickInterval); - nsecs_t getReportedCompositeDeadline() const { return mCompositorTiming.deadline; }; + nsecs_t getReportedCompositeDeadline() const { return mCompositorTiming.deadline; } nsecs_t getNextCompositeDeadline(const nsecs_t now) const; nsecs_t getCompositeInterval() const { return mCompositorTiming.interval; } diff --git a/libs/gui/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h index ba268ab17a39b01c1d8b774f0cf60abb97a1847c..bfe3eb31e8d3fc58b9877d2e1326e9603cfe1fe7 100644 --- a/libs/gui/include/gui/GLConsumer.h +++ b/libs/gui/include/gui/GLConsumer.h @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -82,12 +83,25 @@ public: // If the constructor without the tex parameter is used, the GLConsumer is // created in a detached state, and attachToContext must be called before // calls to updateTexImage. - GLConsumer(const sp& bq, - uint32_t tex, uint32_t texureTarget, bool useFenceSync, - bool isControlledByApp); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + GLConsumer(uint32_t tex, uint32_t textureTarget, bool useFenceSync, bool isControlledByApp); - GLConsumer(const sp& bq, uint32_t texureTarget, - bool useFenceSync, bool isControlledByApp); + GLConsumer(uint32_t textureTarget, bool useFenceSync, bool isControlledByApp); + + GLConsumer(const sp& bq, uint32_t tex, uint32_t textureTarget, + bool useFenceSync, bool isControlledByApp) + __attribute((deprecated("Prefer ctors that create their own surface and consumer."))); + + GLConsumer(const sp& bq, uint32_t textureTarget, bool useFenceSync, + bool isControlledByApp) + __attribute((deprecated("Prefer ctors that create their own surface and consumer."))); +#else + GLConsumer(const sp& bq, uint32_t tex, uint32_t textureTarget, + bool useFenceSync, bool isControlledByApp); + + GLConsumer(const sp& bq, uint32_t textureTarget, bool useFenceSync, + bool isControlledByApp); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) // updateTexImage acquires the most recently queued buffer, and sets the // image contents of the target texture to it. diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index 8fca9460aa8c55f6fd30ddb2c7c616ed92961e7e..3aac457a09209b1b46c2e8452e747a66a64b3759 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -867,6 +867,6 @@ class BnGraphicBufferProducer : public IGraphicBufferProducer { #endif // ---------------------------------------------------------------------------- -}; // namespace android +} // namespace android #endif // ANDROID_GUI_IGRAPHICBUFFERPRODUCER_H diff --git a/libs/gui/include/gui/IProducerListener.h b/libs/gui/include/gui/IProducerListener.h index b15f501518f401abb58408ef70912c93b92c800b..43bf6a7d4b3043022d8c4facbbb9b8b7aa80544f 100644 --- a/libs/gui/include/gui/IProducerListener.h +++ b/libs/gui/include/gui/IProducerListener.h @@ -25,6 +25,8 @@ #include #include +#include + namespace android { // ProducerListener is the interface through which the BufferQueue notifies the @@ -55,6 +57,16 @@ public: // This is called without any lock held and can be called concurrently by // multiple threads. virtual void onBufferDetached(int /*slot*/) {} // Asynchronous +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK) + // onBufferAttached is called from IGraphicBufferConsumer::attachBuffer to + // notify the producer that a buffer is attached. + // + // This is called without any lock held and can be called concurrently by + // multiple threads. This callback is enabled only when needsAttachNotify() + // returns {@code true}. + virtual void onBufferAttached() {} // Asynchronous + virtual bool needsAttachNotify() { return false; } +#endif }; #ifndef NO_BINDER @@ -78,6 +90,9 @@ public: Parcel* reply, uint32_t flags = 0); virtual bool needsReleaseNotify(); virtual void onBuffersDiscarded(const std::vector& slots); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK) + virtual bool needsAttachNotify(); +#endif }; #else @@ -91,6 +106,9 @@ public: virtual ~StubProducerListener(); virtual void onBufferReleased() {} virtual bool needsReleaseNotify() { return false; } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK) + virtual bool needsAttachNotify() { return false; } +#endif }; } // namespace android diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 1ecc216dff2b4c83eb73813f54c1fdf0acc63abb..9a422fd808b1b33e0425da2a09f78a294216f2c2 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -27,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -70,13 +72,6 @@ using gui::IRegionSamplingListener; using gui::IScreenCaptureListener; using gui::SpHash; -namespace gui { - -struct DisplayCaptureArgs; -struct LayerCaptureArgs; - -} // namespace gui - namespace ui { struct DisplayMode; diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h index bc97cd08280e0808dc9ce6a291fd13bc51b62700..014029b25714ab11c8a042e1154a3e80a8f9eafc 100644 --- a/libs/gui/include/gui/ITransactionCompletedListener.h +++ b/libs/gui/include/gui/ITransactionCompletedListener.h @@ -16,8 +16,6 @@ #pragma once -#include "JankInfo.h" - #include #include #include @@ -40,15 +38,10 @@ class ListenerCallbacks; class CallbackId : public Parcelable { public: int64_t id; - enum class Type : int32_t { - ON_COMPLETE = 0, - ON_COMMIT = 1, - /*reserved for serialization = 2*/ - } type; - bool includeJankData; // Only respected for ON_COMPLETE callbacks. + enum class Type : int32_t { ON_COMPLETE = 0, ON_COMMIT = 1 } type; CallbackId() {} - CallbackId(int64_t id, Type type) : id(id), type(type), includeJankData(false) {} + CallbackId(int64_t id, Type type) : id(id), type(type) {} status_t writeToParcel(Parcel* output) const override; status_t readFromParcel(const Parcel* input) override; @@ -113,29 +106,6 @@ public: nsecs_t dequeueReadyTime; }; -/** - * Jank information representing SurfaceFlinger's jank classification about frames for a specific - * surface. - */ -class JankData : public Parcelable { -public: - status_t writeToParcel(Parcel* output) const override; - status_t readFromParcel(const Parcel* input) override; - - JankData(); - JankData(int64_t frameVsyncId, int32_t jankType, nsecs_t frameIntervalNs) - : frameVsyncId(frameVsyncId), jankType(jankType), frameIntervalNs(frameIntervalNs) {} - - // Identifier for the frame submitted with Transaction.setFrameTimelineVsyncId - int64_t frameVsyncId; - - // Bitmask of janks that occurred - int32_t jankType; - - // Expected duration of the frame - nsecs_t frameIntervalNs; -}; - class SurfaceStats : public Parcelable { public: status_t writeToParcel(Parcel* output) const override; @@ -145,14 +115,13 @@ public: SurfaceStats(const sp& sc, std::variant> acquireTimeOrFence, const sp& prevReleaseFence, std::optional hint, uint32_t currentMaxAcquiredBuffersCount, FrameEventHistoryStats frameEventStats, - std::vector jankData, ReleaseCallbackId previousReleaseCallbackId) + ReleaseCallbackId previousReleaseCallbackId) : surfaceControl(sc), acquireTimeOrFence(std::move(acquireTimeOrFence)), previousReleaseFence(prevReleaseFence), transformHint(hint), currentMaxAcquiredBufferCount(currentMaxAcquiredBuffersCount), eventStats(frameEventStats), - jankData(std::move(jankData)), previousReleaseCallbackId(previousReleaseCallbackId) {} sp surfaceControl; @@ -161,7 +130,6 @@ public: std::optional transformHint = 0; uint32_t currentMaxAcquiredBufferCount = 0; FrameEventHistoryStats eventStats; - std::vector jankData; ReleaseCallbackId previousReleaseCallbackId; }; diff --git a/libs/gui/include/gui/LayerMetadata.h b/libs/gui/include/gui/LayerMetadata.h index 9cf62bc7d6b2fb8e574c4c33867bd772d08b90cd..7ee291df4c67e0077f02a0bf0ecbc137bdec6a85 100644 --- a/libs/gui/include/gui/LayerMetadata.h +++ b/libs/gui/include/gui/LayerMetadata.h @@ -74,6 +74,7 @@ enum class GameMode : int32_t { } // namespace android::gui using android::gui::METADATA_ACCESSIBILITY_ID; +using android::gui::METADATA_CALLING_UID; using android::gui::METADATA_DEQUEUE_TIME; using android::gui::METADATA_GAME_MODE; using android::gui::METADATA_MOUSE_CURSOR; diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 5f2f8dc01329e2822de5de05426e589e57ec8e6f..2cdde3255e012c5dd65e4c15e9ac191e947cf359 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -21,7 +21,9 @@ #include #include +#include #include +#include #include #include #include @@ -29,13 +31,13 @@ #include #include +#include #include #include #include -#include +#include #include -#include #include #include #include @@ -218,6 +220,8 @@ struct layer_state_t { eTrustedOverlayChanged = 0x4000'00000000, eDropInputModeChanged = 0x8000'00000000, eExtendedRangeBrightnessChanged = 0x10000'00000000, + eEdgeExtensionChanged = 0x20000'00000000, + eBufferReleaseChannelChanged = 0x40000'00000000, }; layer_state_t(); @@ -241,7 +245,7 @@ struct layer_state_t { layer_state_t::eCropChanged | layer_state_t::eDestinationFrameChanged | layer_state_t::eMatrixChanged | layer_state_t::ePositionChanged | layer_state_t::eTransformToDisplayInverseChanged | - layer_state_t::eTransparentRegionChanged; + layer_state_t::eTransparentRegionChanged | layer_state_t::eEdgeExtensionChanged; // Buffer and related updates. static constexpr uint64_t BUFFER_CHANGES = layer_state_t::eApiChanged | @@ -393,6 +397,9 @@ struct layer_state_t { // Stretch effect to be applied to this layer StretchEffect stretchEffect; + // Edge extension effect to be applied to this layer + gui::EdgeExtensionParameters edgeExtensionParameters; + Rect bufferCrop; Rect destinationFrame; @@ -407,6 +414,8 @@ struct layer_state_t { TrustedPresentationThresholds trustedPresentationThresholds; TrustedPresentationListener trustedPresentationListener; + + std::shared_ptr bufferReleaseChannel; }; class ComposerState { diff --git a/libs/gui/include/gui/ScreenCaptureResults.h b/libs/gui/include/gui/ScreenCaptureResults.h index 6e17791a29f138f20a194a5458eca2d3de3352d8..f176f48fb463177b304f920de4d73769b4222a4d 100644 --- a/libs/gui/include/gui/ScreenCaptureResults.h +++ b/libs/gui/include/gui/ScreenCaptureResults.h @@ -36,6 +36,11 @@ public: bool capturedSecureLayers{false}; bool capturedHdrLayers{false}; ui::Dataspace capturedDataspace{ui::Dataspace::V0_SRGB}; + // A gainmap that can be used to "lift" the screenshot into HDR + sp optionalGainMap; + // HDR/SDR ratio value that fully applies the gainmap. + // Note that we use 1/64 epsilon offsets to eliminate precision issues + float hdrSdrRatio{1.0f}; }; } // namespace android::gui diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index bdcaaf2866902883f9fed13f3898ff7e67259c40..14a351316d8ad2a02d56c9c9bb9dee7a4437bb6f 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -18,6 +18,7 @@ #define ANDROID_GUI_SURFACE_H #include +#include #include #include #include @@ -35,6 +36,8 @@ namespace android { +class GraphicBuffer; + namespace gui { class ISurfaceComposer; } // namespace gui @@ -56,8 +59,41 @@ public: virtual bool needsReleaseNotify() = 0; virtual void onBuffersDiscarded(const std::vector>& buffers) = 0; + virtual void onBufferDetached(int slot) = 0; +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK) + virtual void onBufferAttached() {} + virtual bool needsAttachNotify() { return false; } +#endif + +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + // Called if this Surface is connected to a remote implementation and it + // dies or becomes unavailable. + virtual void onRemoteDied() {} + + // Clients will overwrite this if they want to receive a notification + // via onRemoteDied. This should return a constant value. + virtual bool needsDeathNotify() { return false; } +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) }; +class StubSurfaceListener : public SurfaceListener { +public: + virtual ~StubSurfaceListener() {} + virtual void onBufferReleased() override {} + virtual bool needsReleaseNotify() { return false; } + virtual void onBuffersDiscarded(const std::vector>& /*buffers*/) override {} + virtual void onBufferDetached(int /*slot*/) override {} +}; + +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) +// Contains additional data from the queueBuffer operation. +struct SurfaceQueueBufferOutput { + // True if this queueBuffer caused a buffer to be replaced in the queue + // (and therefore not will not be acquired) + bool bufferReplaced = false; +}; +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + /* * An implementation of ANativeWindow that feeds graphics buffers into a * BufferQueue. @@ -154,6 +190,11 @@ public: */ virtual void allocateBuffers(); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + // See IGraphicBufferProducer::allowAllocation + status_t allowAllocation(bool allowAllocation); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + /* Sets the generation number on the IGraphicBufferProducer and updates the * generation number on any buffers attached to the Surface after this call. * See IGBP::setGenerationNumber for more information. */ @@ -170,6 +211,14 @@ public: * in . */ int setScalingMode(int mode); + virtual int setBuffersTimestamp(int64_t timestamp); + virtual int setBuffersDataSpace(ui::Dataspace dataSpace); + virtual int setCrop(Rect const* rect); + virtual int setBuffersTransform(uint32_t transform); + virtual int setBuffersStickyTransform(uint32_t transform); + virtual int setBuffersFormat(PixelFormat format); + virtual int setUsage(uint64_t reqUsage); + // See IGraphicBufferProducer::setDequeueTimeout status_t setDequeueTimeout(nsecs_t timeout); @@ -321,7 +370,12 @@ private: protected: virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd); virtual int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + virtual int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd, + SurfaceQueueBufferOutput* surfaceOutput = nullptr); +#else virtual int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) virtual int perform(int operation, va_list args); virtual int setSwapInterval(int interval); @@ -330,16 +384,9 @@ protected: virtual int connect(int api); virtual int setBufferCount(int bufferCount); virtual int setBuffersUserDimensions(uint32_t width, uint32_t height); - virtual int setBuffersFormat(PixelFormat format); - virtual int setBuffersTransform(uint32_t transform); - virtual int setBuffersStickyTransform(uint32_t transform); - virtual int setBuffersTimestamp(int64_t timestamp); - virtual int setBuffersDataSpace(ui::Dataspace dataSpace); virtual int setBuffersSmpte2086Metadata(const android_smpte2086_metadata* metadata); virtual int setBuffersCta8613Metadata(const android_cta861_3_metadata* metadata); virtual int setBuffersHdr10PlusMetadata(const size_t size, const uint8_t* metadata); - virtual int setCrop(Rect const* rect); - virtual int setUsage(uint64_t reqUsage); virtual void setSurfaceDamage(android_native_rect_t* rects, size_t numRects); public: @@ -357,22 +404,15 @@ public: virtual int unlockAndPost(); virtual int query(int what, int* value) const; - virtual int connect(int api, const sp& listener); - // When reportBufferRemoval is true, clients must call getAndFlushRemovedBuffers to fetch // GraphicBuffers removed from this surface after a dequeueBuffer, detachNextBuffer or // attachBuffer call. This allows clients with their own buffer caches to free up buffers no // longer in use by this surface. - virtual int connect( - int api, const sp& listener, - bool reportBufferRemoval); - virtual int detachNextBuffer(sp* outBuffer, - sp* outFence); + virtual int connect(int api, const sp& listener, + bool reportBufferRemoval = false); + virtual int detachNextBuffer(sp* outBuffer, sp* outFence); virtual int attachBuffer(ANativeWindowBuffer*); - virtual int connect( - int api, bool reportBufferRemoval, - const sp& sListener); virtual void destroy(); // When client connects to Surface with reportBufferRemoval set to true, any buffers removed @@ -387,6 +427,21 @@ public: static status_t attachAndQueueBufferWithDataspace(Surface* surface, sp buffer, ui::Dataspace dataspace); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + // Dequeues a buffer and its outFence, which must be signalled before the buffer can be used. + status_t dequeueBuffer(sp* buffer, sp* outFence); + + // Queues a buffer, with an optional fd fence that captures pending work on the buffer. This + // buffer must have been returned by dequeueBuffer or associated with this Surface via an + // attachBuffer operation. + status_t queueBuffer(const sp& buffer, const sp& fd = Fence::NO_FENCE, + SurfaceQueueBufferOutput* output = nullptr); + + // Detaches this buffer, dissociating it from this Surface. This buffer must have been returned + // by queueBuffer or associated with this Surface via an attachBuffer operation. + status_t detachBuffer(const sp& buffer); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + // Batch version of dequeueBuffer, cancelBuffer and queueBuffer // Note that these batched operations are not supported when shared buffer mode is being used. struct BatchBuffer { @@ -401,8 +456,13 @@ public: int fenceFd = -1; nsecs_t timestamp = NATIVE_WINDOW_TIMESTAMP_AUTO; }; +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + virtual int queueBuffers(const std::vector& buffers, + std::vector* queueBufferOutputs = nullptr); +#else virtual int queueBuffers( const std::vector& buffers); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) protected: enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS }; @@ -422,12 +482,38 @@ protected: return mSurfaceListener->needsReleaseNotify(); } + virtual void onBufferDetached(int slot) { mSurfaceListener->onBufferDetached(slot); } + virtual void onBuffersDiscarded(const std::vector& slots); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK) + virtual void onBufferAttached() { + mSurfaceListener->onBufferAttached(); + } + + virtual bool needsAttachNotify() { + return mSurfaceListener->needsAttachNotify(); + } +#endif private: wp mParent; sp mSurfaceListener; }; +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + class ProducerDeathListenerProxy : public IBinder::DeathRecipient { + public: + ProducerDeathListenerProxy(wp surfaceListener); + ProducerDeathListenerProxy(ProducerDeathListenerProxy&) = delete; + + // IBinder::DeathRecipient + virtual void binderDied(const wp&) override; + + private: + wp mSurfaceListener; + }; + friend class ProducerDeathListenerProxy; +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + void querySupportedTimestampsLocked() const; void freeAllBuffers(); @@ -459,6 +545,13 @@ protected: // TODO: rename to mBufferProducer sp mGraphicBufferProducer; +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + // mSurfaceDeathListener gets registered as mGraphicBufferProducer's + // DeathRecipient when SurfaceListener::needsDeathNotify returns true and + // gets notified when it dies. + sp mSurfaceDeathListener; +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + // mSlots stores the buffers that have been allocated for each buffer slot. // It is initialized to null pointers, and gets filled in with the result of // IGraphicBufferProducer::requestBuffer when the client dequeues a buffer from a diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 0862e03c44c4b56568eebe16aba2bdf6af5ef919..4f9af1682630c8a155d75de1b7a1642a95c9c53c 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -35,14 +35,17 @@ #include #include #include +#include #include #include #include #include #include +#include #include +#include #include #include #include @@ -337,6 +340,8 @@ public: static std::optional getDisplayDecorationSupport(const sp& displayToken); + static bool flagEdgeExtensionEffectUseShader(); + // ------------------------------------------------------------------------ // surface creation / destruction @@ -447,7 +452,6 @@ public: uint64_t mId; - uint32_t mTransactionNestCount = 0; bool mAnimation = false; bool mEarlyWakeupStart = false; bool mEarlyWakeupEnd = false; @@ -743,11 +747,26 @@ public: Transaction& setStretchEffect(const sp& sc, const StretchEffect& stretchEffect); + /** + * Provides the edge extension effect configured on a container that the + * surface is rendered within. + * @param sc target surface the edge extension should be applied to + * @param effect the corresponding EdgeExtensionParameters to be applied + * to the surface. + * @return The transaction being constructed + */ + Transaction& setEdgeExtensionEffect(const sp& sc, + const gui::EdgeExtensionParameters& effect); + Transaction& setBufferCrop(const sp& sc, const Rect& bufferCrop); Transaction& setDestinationFrame(const sp& sc, const Rect& destinationFrame); Transaction& setDropInputMode(const sp& sc, gui::DropInputMode mode); + Transaction& setBufferReleaseChannel( + const sp& sc, + const std::shared_ptr& channel); + status_t setDisplaySurface(const sp& token, const sp& bufferProducer); @@ -864,12 +883,82 @@ public: // --------------------------------------------------------------------------- -class JankDataListener : public VirtualLightRefBase { +class JankDataListener; + +// Acts as a representative listener to the composer for a single layer and +// forwards any received jank data to multiple listeners. Will remove itself +// from the composer only once the last listener is removed. +class JankDataListenerFanOut : public gui::BnJankListener { +public: + JankDataListenerFanOut(int32_t layerId) : mLayerId(layerId) {} + + binder::Status onJankData(const std::vector& jankData) override; + + static status_t addListener(sp sc, sp listener); + static status_t removeListener(sp listener); + +private: + std::vector> getActiveListeners(); + bool removeListeners(const std::vector>& listeners); + int64_t updateAndGetRemovalVSync(); + + struct WpJDLHash { + std::size_t operator()(const wp& listener) const { + return std::hash{}(listener.unsafe_get()); + } + }; + + std::mutex mMutex; + std::unordered_set, WpJDLHash> mListeners GUARDED_BY(mMutex); + int32_t mLayerId; + int64_t mRemoveAfter = -1; + + static std::mutex sFanoutInstanceMutex; + static std::unordered_map> sFanoutInstances; +}; + +// Base class for client listeners interested in jank classification data from +// the composer. Subclasses should override onJankDataAvailable and call the add +// and removal methods to receive jank data. +class JankDataListener : public virtual RefBase { public: - virtual ~JankDataListener() = 0; - virtual void onJankDataAvailable(const std::vector& jankData) = 0; + JankDataListener() {} + virtual ~JankDataListener(); + + virtual bool onJankDataAvailable(const std::vector& jankData) = 0; + + status_t addListener(sp sc) { + if (mLayerId != -1) { + removeListener(0); + mLayerId = -1; + } + + int32_t layerId = sc->getLayerId(); + status_t status = + JankDataListenerFanOut::addListener(std::move(sc), + sp::fromExisting(this)); + if (status == OK) { + mLayerId = layerId; + } + return status; + } + + status_t removeListener(int64_t afterVsync) { + mRemoveAfter = std::max(static_cast(0), afterVsync); + return JankDataListenerFanOut::removeListener(sp::fromExisting(this)); + } + + status_t flushJankData(); + + friend class JankDataListenerFanOut; + +private: + int32_t mLayerId = -1; + int64_t mRemoveAfter = -1; }; +// --------------------------------------------------------------------------- + class TransactionCompletedListener : public BnTransactionCompletedListener { public: TransactionCompletedListener(); @@ -904,7 +993,6 @@ protected: std::unordered_map mCallbacks GUARDED_BY(mMutex); - std::multimap> mJankListeners GUARDED_BY(mMutex); std::unordered_map mReleaseBufferCallbacks GUARDED_BY(mMutex); @@ -927,14 +1015,10 @@ public: const std::unordered_set, SurfaceComposerClient::SCHash>& surfaceControls, CallbackId::Type callbackType); - CallbackId addCallbackFunctionLocked( - const TransactionCompletedCallback& callbackFunction, - const std::unordered_set, SurfaceComposerClient::SCHash>& - surfaceControls, - CallbackId::Type callbackType) REQUIRES(mMutex); - void addSurfaceControlToCallbacks(SurfaceComposerClient::CallbackInfo& callbackInfo, - const sp& surfaceControl); + void addSurfaceControlToCallbacks( + const sp& surfaceControl, + const std::unordered_set& callbackIds); void addQueueStallListener(std::function stallListener, void* id); void removeQueueStallListener(void *id); @@ -943,18 +1027,6 @@ public: TrustedPresentationCallback tpc, int id, void* context); void clearTrustedPresentationCallback(int id); - /* - * Adds a jank listener to be informed about SurfaceFlinger's jank classification for a specific - * surface. Jank classifications arrive as part of the transaction callbacks about previous - * frames submitted to this Surface. - */ - void addJankListener(const sp& listener, sp surfaceControl); - - /** - * Removes a jank listener previously added to addJankCallback. - */ - void removeJankListener(const sp& listener); - void addSurfaceStatsListener(void* context, void* cookie, sp surfaceControl, SurfaceStatsCallback listener); void removeSurfaceStatsListener(void* context, void* cookie); diff --git a/libs/gui/include/gui/view/Surface.h b/libs/gui/include/gui/view/Surface.h index b7aba2b9dcfb7d03b9fd57cbd87db58f4e6a8f7c..7ddac8139ad5cea10e4d94aee0bd5633b43af571 100644 --- a/libs/gui/include/gui/view/Surface.h +++ b/libs/gui/include/gui/view/Surface.h @@ -59,8 +59,9 @@ class Surface : public Parcelable { // of the full parceling to happen on its native side. status_t readFromParcel(const Parcel* parcel, bool nameAlreadyRead); - private: + std::string toString() const; +private: static String16 readMaybeEmptyString16(const Parcel* parcel); }; diff --git a/libs/gui/libgui_flags.aconfig b/libs/gui/libgui_flags.aconfig index 792966fd5eebfc06a7dbafea33a2ca1f4ca8a0ac..d3f2899ba3b6c67b6304a20e7629797ec2ac280e 100644 --- a/libs/gui/libgui_flags.aconfig +++ b/libs/gui/libgui_flags.aconfig @@ -9,6 +9,14 @@ flag { is_fixed_read_only: true } # bq_setframerate +flag { + name: "bq_consumer_attach_callback" + namespace: "core_graphics" + description: "Controls IProducerListener to have consumer side attach callback" + bug: "353202582" + is_fixed_read_only: true +} # bq_consumer_attach_callback + flag { name: "frametimestamps_previousrelease" namespace: "core_graphics" @@ -35,3 +43,75 @@ flag { purpose: PURPOSE_BUGFIX } } # trace_frame_rate_override + +flag { + name: "wb_consumer_base_owns_bq" + namespace: "core_graphics" + description: "ConsumerBase-based classes now own their own bufferqueue" + bug: "340933754" + is_fixed_read_only: true +} # wb_consumer_base_owns_bq + +flag { + name: "wb_platform_api_improvements" + namespace: "core_graphics" + description: "Simple improvements to Surface and ConsumerBase classes" + bug: "340933794" + is_fixed_read_only: true +} # wb_platform_api_improvements + +flag { + name: "wb_stream_splitter" + namespace: "core_graphics" + description: "Removes IGBP/IGBCs from Camera3StreamSplitter as part of BufferQueue refactors" + bug: "340933206" + is_fixed_read_only: true +} # wb_stream_splitter + +flag { + name: "edge_extension_shader" + namespace: "windowing_frontend" + description: "Enable edge extension via shader" + bug: "322036393" + is_fixed_read_only: true +} # edge_extension_shader + +flag { + name: "buffer_release_channel" + namespace: "window_surfaces" + description: "Enable BufferReleaseChannel to optimize buffer releases" + bug: "294133380" + is_fixed_read_only: true +} # buffer_release_channel + +flag { + name: "wb_ring_buffer" + namespace: "core_graphics" + description: "Remove slot dependency in the Ring Buffer Consumer." + bug: "342197847" + is_fixed_read_only: true +} # wb_ring_buffer + +flag { + name: "wb_camera3_and_processors" + namespace: "core_graphics" + description: "Remove usage of IGBPs in the *Processor and Camera3*" + bug: "342199002" + is_fixed_read_only: true +} # wb_camera3_and_processors + +flag { + name: "wb_libcameraservice" + namespace: "core_graphics" + description: "Remove usage of IGBPs in the libcameraservice." + bug: "342197849" + is_fixed_read_only: true +} # wb_libcameraservice + +flag { + name: "bq_producer_throttles_only_async_mode" + namespace: "core_graphics" + description: "BufferQueueProducer only CPU throttle on queueBuffer() in async mode." + bug: "359252619" + is_fixed_read_only: true +} # bq_producer_throttles_only_async_mode diff --git a/libs/gui/rust/aidl_types/src/lib.rs b/libs/gui/rust/aidl_types/src/lib.rs index fead018bbf189b4df479a60eef20e70bef6bdaa5..2351df0318b54908e8e7a6461b6eb417334eecfb 100644 --- a/libs/gui/rust/aidl_types/src/lib.rs +++ b/libs/gui/rust/aidl_types/src/lib.rs @@ -42,10 +42,7 @@ macro_rules! stub_unstructured_parcelable { } stub_unstructured_parcelable!(BitTube); -stub_unstructured_parcelable!(CaptureArgs); -stub_unstructured_parcelable!(DisplayCaptureArgs); stub_unstructured_parcelable!(DisplayInfo); -stub_unstructured_parcelable!(LayerCaptureArgs); stub_unstructured_parcelable!(LayerDebugInfo); stub_unstructured_parcelable!(LayerMetadata); stub_unstructured_parcelable!(ParcelableVsyncEventData); diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp index ea8acbbb7298c915f4978284163dbb5e8890763f..f07747f32f3831b436be1940609aedb668742d74 100644 --- a/libs/gui/tests/Android.bp +++ b/libs/gui/tests/Android.bp @@ -12,6 +12,34 @@ package { default_applicable_licenses: ["frameworks_native_license"], } +aidl_interface { + name: "libgui_test_server_aidl", + unstable: true, + srcs: ["testserver/aidl/**/*.aidl"], + local_include_dir: "testserver/aidl", + include_dirs: [ + "frameworks/native/aidl/gui", + ], + backend: { + cpp: { + enabled: true, + additional_shared_libraries: [ + "libgui", + "libui", + ], + }, + java: { + enabled: false, + }, + ndk: { + enabled: false, + }, + rust: { + enabled: false, + }, + }, +} + cc_test { name: "libgui_test", test_suites: ["device-tests"], @@ -25,34 +53,41 @@ cc_test { "-Wthread-safety", "-DCOM_ANDROID_GRAPHICS_LIBGUI_FLAGS_BQ_SETFRAMERATE=true", "-DCOM_ANDROID_GRAPHICS_LIBGUI_FLAGS_BQ_EXTENDEDALLOCATE=true", + "-DCOM_ANDROID_GRAPHICS_LIBGUI_FLAGS_WB_CONSUMER_BASE_OWNS_BQ=true", + "-DCOM_ANDROID_GRAPHICS_LIBGUI_FLAGS_WB_PLATFORM_API_IMPROVEMENTS=true", ], srcs: [ - "LibGuiMain.cpp", // Custom gtest entrypoint "BLASTBufferQueue_test.cpp", "BufferItemConsumer_test.cpp", "BufferQueue_test.cpp", + "BufferReleaseChannel_test.cpp", "Choreographer_test.cpp", "CompositorTiming_test.cpp", "CpuConsumer_test.cpp", - "EndToEndNativeInputTest.cpp", - "FrameRateUtilsTest.cpp", - "DisplayInfo_test.cpp", "DisplayedContentSampling_test.cpp", + "DisplayInfo_test.cpp", + "EndToEndNativeInputTest.cpp", "FillBuffer.cpp", + "FrameRateUtilsTest.cpp", "GLTest.cpp", "IGraphicBufferProducer_test.cpp", + "LibGuiMain.cpp", // Custom gtest entrypoint "Malicious.cpp", "MultiTextureConsumer_test.cpp", "RegionSampling_test.cpp", "StreamSplitter_test.cpp", + "Surface_test.cpp", "SurfaceTextureClient_test.cpp", "SurfaceTextureFBO_test.cpp", + "SurfaceTextureGL_test.cpp", "SurfaceTextureGLThreadToGL_test.cpp", "SurfaceTextureGLToGL_test.cpp", - "SurfaceTextureGL_test.cpp", "SurfaceTextureMultiContextGL_test.cpp", - "Surface_test.cpp", + "TestServer_test.cpp", + "testserver/TestServer.cpp", + "testserver/TestServerClient.cpp", + "testserver/TestServerHost.cpp", "TextureRenderer.cpp", "VsyncEventData_test.cpp", "WindowInfo_test.cpp", @@ -63,10 +98,17 @@ cc_test { "android.hardware.configstore-utils", "libSurfaceFlingerProp", "libGLESv1_CM", + "libgui_test_server_aidl-cpp", "libinput", "libnativedisplay", ], + // This needs to get copied over for the test since it's not part of the + // platform. + data_libs: [ + "libgui_test_server_aidl-cpp", + ], + static_libs: [ "libgmock", ], diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 946ff058cff3e65856e52139a2a43c3f37945fee..53f4a36c42868dd6223e75a0d2185e4e0020b00e 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include #include @@ -186,6 +186,10 @@ public: mBlastBufferQueueAdapter->mergeWithNextTransaction(merge, frameNumber); } + void setApplyToken(sp applyToken) { + mBlastBufferQueueAdapter->setApplyToken(std::move(applyToken)); + } + private: sp mBlastBufferQueueAdapter; }; @@ -229,7 +233,8 @@ protected: ISurfaceComposerClient::eFXSurfaceBufferState, /*parent*/ mRootSurfaceControl->getHandle()); - mCaptureArgs.sourceCrop = Rect(ui::Size(mDisplayWidth, mDisplayHeight)); + mCaptureArgs.captureArgs.sourceCrop = + gui::aidl_utils::toARect(mDisplayWidth, mDisplayHeight); mCaptureArgs.layerHandle = mRootSurfaceControl->getHandle(); } @@ -510,6 +515,69 @@ TEST_F(BLASTBufferQueueTest, TripleBuffering) { adapter.waitForCallbacks(); } +class WaitForCommittedCallback { +public: + WaitForCommittedCallback() = default; + ~WaitForCommittedCallback() = default; + + void wait() { + std::unique_lock lock(mMutex); + cv.wait(lock, [this] { return mCallbackReceived; }); + } + + void notify() { + std::unique_lock lock(mMutex); + mCallbackReceived = true; + cv.notify_one(); + mCallbackReceivedTimeStamp = std::chrono::system_clock::now(); + } + auto getCallback() { + return [this](void* /* unused context */, nsecs_t /* latchTime */, + const sp& /* presentFence */, + const std::vector& /* stats */) { notify(); }; + } + std::chrono::time_point mCallbackReceivedTimeStamp; + +private: + std::mutex mMutex; + std::condition_variable cv; + bool mCallbackReceived = false; +}; + +TEST_F(BLASTBufferQueueTest, setApplyToken) { + sp applyToken = sp::make(); + WaitForCommittedCallback firstTransaction; + WaitForCommittedCallback secondTransaction; + { + BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); + adapter.setApplyToken(applyToken); + sp igbProducer; + setUpProducer(adapter, igbProducer); + + Transaction t; + t.addTransactionCommittedCallback(firstTransaction.getCallback(), nullptr); + adapter.mergeWithNextTransaction(&t, 1); + queueBuffer(igbProducer, 127, 127, 127, + /*presentTimeDelay*/ std::chrono::nanoseconds(500ms).count()); + } + { + BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); + adapter.setApplyToken(applyToken); + sp igbProducer; + setUpProducer(adapter, igbProducer); + + Transaction t; + t.addTransactionCommittedCallback(secondTransaction.getCallback(), nullptr); + adapter.mergeWithNextTransaction(&t, 1); + queueBuffer(igbProducer, 127, 127, 127, /*presentTimeDelay*/ 0); + } + + firstTransaction.wait(); + secondTransaction.wait(); + EXPECT_GT(secondTransaction.mCallbackReceivedTimeStamp, + firstTransaction.mCallbackReceivedTimeStamp); +} + TEST_F(BLASTBufferQueueTest, SetCrop_Item) { uint8_t r = 255; uint8_t g = 0; @@ -1269,6 +1337,20 @@ public: } }; +class TestSurfaceListener : public SurfaceListener { +public: + sp mIgbp; + TestSurfaceListener(const sp& igbp) : mIgbp(igbp) {} + void onBufferReleased() override { + sp buffer; + sp fence; + mIgbp->detachNextBuffer(&buffer, &fence); + } + bool needsReleaseNotify() override { return true; } + void onBuffersDiscarded(const std::vector>& /*buffers*/) override {} + void onBufferDetached(int /*slot*/) {} +}; + TEST_F(BLASTBufferQueueTest, CustomProducerListener) { BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); sp igbProducer = adapter.getIGraphicBufferProducer(); @@ -1327,7 +1409,7 @@ TEST_F(BLASTBufferQueueTest, TransformHint) { ASSERT_EQ(ui::Transform::ROT_0, static_cast(transformHint)); ASSERT_EQ(NO_ERROR, - surface->connect(NATIVE_WINDOW_API_CPU, new TestProducerListener(igbProducer))); + surface->connect(NATIVE_WINDOW_API_CPU, new TestSurfaceListener(igbProducer))); // After connecting to the surface, we should get the correct hint. surface->query(NATIVE_WINDOW_TRANSFORM_HINT, &transformHint); diff --git a/libs/gui/tests/BufferItemConsumer_test.cpp b/libs/gui/tests/BufferItemConsumer_test.cpp index 6880678050ddb7520815b53564b193d2580d21fb..845a1caf21d7e7cd9eee1ce60be50bd3364c2629 100644 --- a/libs/gui/tests/BufferItemConsumer_test.cpp +++ b/libs/gui/tests/BufferItemConsumer_test.cpp @@ -17,10 +17,12 @@ #define LOG_TAG "BufferItemConsumer_test" //#define LOG_NDEBUG 0 +#include #include #include #include #include +#include namespace android { @@ -42,16 +44,26 @@ class BufferItemConsumerTest : public ::testing::Test { BufferItemConsumerTest* mTest; }; + struct TrackingProducerListener : public BnProducerListener { + TrackingProducerListener(BufferItemConsumerTest* test) : mTest(test) {} + + virtual void onBufferReleased() override {} + virtual bool needsReleaseNotify() override { return true; } + virtual void onBuffersDiscarded(const std::vector&) override {} + virtual void onBufferDetached(int slot) override { mTest->HandleBufferDetached(slot); } + + BufferItemConsumerTest* mTest; + }; + void SetUp() override { - BufferQueue::createBufferQueue(&mProducer, &mConsumer); - mBIC = - new BufferItemConsumer(mConsumer, kFormat, kMaxLockedBuffers, true); + mBIC = new BufferItemConsumer(kFormat, kMaxLockedBuffers, true); String8 name("BufferItemConsumer_Under_Test"); mBIC->setName(name); mBFL = new BufferFreedListener(this); mBIC->setBufferFreedListener(mBFL); - sp producerListener = new StubProducerListener(); + sp producerListener = new TrackingProducerListener(this); + mProducer = mBIC->getSurface()->getIGraphicBufferProducer(); IGraphicBufferProducer::QueueBufferOutput bufferOutput; ASSERT_EQ(NO_ERROR, mProducer->connect(producerListener, NATIVE_WINDOW_API_CPU, @@ -71,6 +83,13 @@ class BufferItemConsumerTest : public ::testing::Test { ALOGD("HandleBufferFreed, mFreedBufferCount=%d", mFreedBufferCount); } + void HandleBufferDetached(int slot) { + std::lock_guard lock(mMutex); + mDetachedBufferSlots.push_back(slot); + ALOGD("HandleBufferDetached, slot=%d mDetachedBufferSlots-count=%zu", slot, + mDetachedBufferSlots.size()); + } + void DequeueBuffer(int* outSlot) { ASSERT_NE(outSlot, nullptr); @@ -120,6 +139,7 @@ class BufferItemConsumerTest : public ::testing::Test { std::mutex mMutex; int mFreedBufferCount{0}; + std::vector mDetachedBufferSlots = {}; sp mBIC; sp mBFL; @@ -203,4 +223,19 @@ TEST_F(BufferItemConsumerTest, TriggerBufferFreed_DeleteBufferItemConsumer) { ASSERT_EQ(1, GetFreedBufferCount()); } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) +// Test that delete BufferItemConsumer triggers onBufferFreed. +TEST_F(BufferItemConsumerTest, DetachBufferWithBuffer) { + int slot; + // Let buffer go through the cycle at least once. + DequeueBuffer(&slot); + QueueBuffer(slot); + AcquireBuffer(&slot); + + sp buffer = mBuffers[slot]; + EXPECT_EQ(OK, mBIC->detachBuffer(buffer)); + EXPECT_THAT(mDetachedBufferSlots, testing::ElementsAre(slot)); +} +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + } // namespace android diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 272c5ed2b4a00e49fcf9d2b95a1846320a058482..2e6ffcb57fd186cff4fbd29e45fb0e80a977bde2 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -1262,6 +1262,91 @@ TEST_F(BufferQueueTest, TestConsumerDetachProducerListener) { ASSERT_TRUE(result == WOULD_BLOCK || result == TIMED_OUT || result == INVALID_OPERATION); } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK) +struct BufferAttachedListener : public BnProducerListener { +public: + BufferAttachedListener(bool enable) : mEnabled(enable), mAttached(0) {} + virtual ~BufferAttachedListener() = default; + + virtual void onBufferReleased() {} + virtual bool needsReleaseNotify() { return true; } + virtual void onBufferAttached() { + ++mAttached; + } + virtual bool needsAttachNotify() { return mEnabled; } + + int getNumAttached() const { return mAttached; } +private: + const bool mEnabled; + int mAttached; +}; + +TEST_F(BufferQueueTest, TestConsumerAttachProducerListener) { + createBufferQueue(); + sp mc1(new MockConsumer); + ASSERT_EQ(OK, mConsumer->consumerConnect(mc1, true)); + IGraphicBufferProducer::QueueBufferOutput output; + // Do not enable attach callback. + sp pl1(new BufferAttachedListener(false)); + ASSERT_EQ(OK, mProducer->connect(pl1, NATIVE_WINDOW_API_CPU, true, &output)); + ASSERT_EQ(OK, mProducer->setDequeueTimeout(0)); + ASSERT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(1)); + + sp fence = Fence::NO_FENCE; + sp buffer = nullptr; + + int slot; + status_t result = OK; + + ASSERT_EQ(OK, mProducer->setMaxDequeuedBufferCount(1)); + + result = mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, + GRALLOC_USAGE_SW_READ_RARELY, nullptr, nullptr); + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result); + ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); + ASSERT_EQ(OK, mProducer->detachBuffer(slot)); + + // Check # of attach is zero. + ASSERT_EQ(0, pl1->getNumAttached()); + + // Attach a buffer and check the callback was not called. + ASSERT_EQ(OK, mConsumer->attachBuffer(&slot, buffer)); + ASSERT_EQ(0, pl1->getNumAttached()); + + mProducer = nullptr; + mConsumer = nullptr; + createBufferQueue(); + + sp mc2(new MockConsumer); + ASSERT_EQ(OK, mConsumer->consumerConnect(mc2, true)); + // Enable attach callback. + sp pl2(new BufferAttachedListener(true)); + ASSERT_EQ(OK, mProducer->connect(pl2, NATIVE_WINDOW_API_CPU, true, &output)); + ASSERT_EQ(OK, mProducer->setDequeueTimeout(0)); + ASSERT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(1)); + + fence = Fence::NO_FENCE; + buffer = nullptr; + + result = OK; + + ASSERT_EQ(OK, mProducer->setMaxDequeuedBufferCount(1)); + + result = mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, + GRALLOC_USAGE_SW_READ_RARELY, nullptr, nullptr); + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result); + ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); + ASSERT_EQ(OK, mProducer->detachBuffer(slot)); + + // Check # of attach is zero. + ASSERT_EQ(0, pl2->getNumAttached()); + + // Attach a buffer and check the callback was called. + ASSERT_EQ(OK, mConsumer->attachBuffer(&slot, buffer)); + ASSERT_EQ(1, pl2->getNumAttached()); +} +#endif + TEST_F(BufferQueueTest, TestStaleBufferHandleSentAfterDisconnect) { createBufferQueue(); sp mc(new MockConsumer); @@ -1345,19 +1430,15 @@ TEST_F(BufferQueueTest, TestBqSetFrameRateFlagBuildTimeIsSet) { } struct BufferItemConsumerSetFrameRateListener : public BufferItemConsumer { - BufferItemConsumerSetFrameRateListener(const sp& consumer) - : BufferItemConsumer(consumer, GRALLOC_USAGE_SW_READ_OFTEN, 1) {} + BufferItemConsumerSetFrameRateListener() : BufferItemConsumer(GRALLOC_USAGE_SW_READ_OFTEN, 1) {} MOCK_METHOD(void, onSetFrameRate, (float, int8_t, int8_t), (override)); }; TEST_F(BufferQueueTest, TestSetFrameRate) { - sp producer; - sp consumer; - BufferQueue::createBufferQueue(&producer, &consumer); - sp bufferConsumer = - sp::make(consumer); + sp::make(); + sp producer = bufferConsumer->getSurface()->getIGraphicBufferProducer(); EXPECT_CALL(*bufferConsumer, onSetFrameRate(12.34f, 1, 0)).Times(1); producer->setFrameRate(12.34f, 1, 0); @@ -1408,14 +1489,10 @@ struct OneshotOnDequeuedListener final : public BufferItemConsumer::FrameAvailab // See b/270004534 TEST(BufferQueueThreading, TestProducerDequeueConsumerDestroy) { - sp producer; - sp consumer; - BufferQueue::createBufferQueue(&producer, &consumer); - sp bufferConsumer = - sp::make(consumer, GRALLOC_USAGE_SW_READ_OFTEN, 2); + sp::make(GRALLOC_USAGE_SW_READ_OFTEN, 2); ASSERT_NE(nullptr, bufferConsumer.get()); - sp surface = sp::make(producer); + sp surface = bufferConsumer->getSurface(); native_window_set_buffers_format(surface.get(), PIXEL_FORMAT_RGBA_8888); native_window_set_buffers_dimensions(surface.get(), 100, 100); @@ -1446,14 +1523,10 @@ TEST(BufferQueueThreading, TestProducerDequeueConsumerDestroy) { } TEST_F(BufferQueueTest, TestAdditionalOptions) { - sp producer; - sp consumer; - BufferQueue::createBufferQueue(&producer, &consumer); - sp bufferConsumer = - sp::make(consumer, GRALLOC_USAGE_SW_READ_OFTEN, 2); + sp::make(GRALLOC_USAGE_SW_READ_OFTEN, 2); ASSERT_NE(nullptr, bufferConsumer.get()); - sp surface = sp::make(producer); + sp surface = bufferConsumer->getSurface(); native_window_set_buffers_format(surface.get(), PIXEL_FORMAT_RGBA_8888); native_window_set_buffers_dimensions(surface.get(), 100, 100); diff --git a/libs/gui/tests/BufferReleaseChannel_test.cpp b/libs/gui/tests/BufferReleaseChannel_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..11d122b525898e339a66a153ff01920fe46d91dc --- /dev/null +++ b/libs/gui/tests/BufferReleaseChannel_test.cpp @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2024 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 +#include + +#include +#include + +using namespace std::string_literals; +using android::gui::BufferReleaseChannel; + +namespace android { + +namespace { + +// Helper function to check if two file descriptors point to the same file. +bool is_same_file(int fd1, int fd2) { + struct stat stat1; + if (fstat(fd1, &stat1) != 0) { + return false; + } + struct stat stat2; + if (fstat(fd2, &stat2) != 0) { + return false; + } + return (stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino); +} + +} // namespace + +TEST(BufferReleaseChannelTest, MessageFlattenable) { + ReleaseCallbackId releaseCallbackId{1, 2}; + sp releaseFence = sp::make(memfd_create("fake-fence-fd", 0)); + uint32_t maxAcquiredBufferCount = 5; + + std::vector dataBuffer; + std::vector fdBuffer; + + // Verify that we can flatten a message + { + BufferReleaseChannel::Message message{releaseCallbackId, releaseFence, + maxAcquiredBufferCount}; + + dataBuffer.resize(message.getFlattenedSize()); + void* dataPtr = dataBuffer.data(); + size_t dataSize = dataBuffer.size(); + + fdBuffer.resize(message.getFdCount()); + int* fdPtr = fdBuffer.data(); + size_t fdSize = fdBuffer.size(); + + ASSERT_EQ(OK, message.flatten(dataPtr, dataSize, fdPtr, fdSize)); + + // Fence's unique_fd uses fdsan to check ownership of the file descriptor. Normally the file + // descriptor is passed through the Unix socket and duplicated (and sent to another process) + // so there's no problem with duplicate file descriptor ownership. For this unit test, we + // need to set up a duplicate file descriptor to avoid crashing due to duplicate ownership. + ASSERT_EQ(releaseFence->get(), fdBuffer[0]); + fdBuffer[0] = message.releaseFence->dup(); + } + + // Verify that we can unflatten a message + { + BufferReleaseChannel::Message message; + + const void* dataPtr = dataBuffer.data(); + size_t dataSize = dataBuffer.size(); + + const int* fdPtr = fdBuffer.data(); + size_t fdSize = fdBuffer.size(); + + ASSERT_EQ(OK, message.unflatten(dataPtr, dataSize, fdPtr, fdSize)); + ASSERT_EQ(releaseCallbackId, message.releaseCallbackId); + ASSERT_TRUE(is_same_file(releaseFence->get(), message.releaseFence->get())); + ASSERT_EQ(maxAcquiredBufferCount, message.maxAcquiredBufferCount); + } +} + +// Verify that the BufferReleaseChannel consume returns WOULD_BLOCK when there's no message +// available. +TEST(BufferReleaseChannelTest, ConsumerEndpointIsNonBlocking) { + std::unique_ptr consumer; + std::shared_ptr producer; + ASSERT_EQ(OK, BufferReleaseChannel::open("test-channel"s, consumer, producer)); + + ReleaseCallbackId releaseCallbackId; + sp releaseFence; + uint32_t maxAcquiredBufferCount; + ASSERT_EQ(WOULD_BLOCK, + consumer->readReleaseFence(releaseCallbackId, releaseFence, maxAcquiredBufferCount)); +} + +// Verify that we can write a message to the BufferReleaseChannel producer and read that message +// using the BufferReleaseChannel consumer. +TEST(BufferReleaseChannelTest, ProduceAndConsume) { + std::unique_ptr consumer; + std::shared_ptr producer; + ASSERT_EQ(OK, BufferReleaseChannel::open("test-channel"s, consumer, producer)); + + sp fence = sp::make(memfd_create("fake-fence-fd", 0)); + + for (uint64_t i = 0; i < 64; i++) { + ReleaseCallbackId producerId{i, i + 1}; + uint32_t maxAcquiredBufferCount = i + 2; + ASSERT_EQ(OK, producer->writeReleaseFence(producerId, fence, maxAcquiredBufferCount)); + } + + for (uint64_t i = 0; i < 64; i++) { + ReleaseCallbackId expectedId{i, i + 1}; + uint32_t expectedMaxAcquiredBufferCount = i + 2; + + ReleaseCallbackId consumerId; + sp consumerFence; + uint32_t maxAcquiredBufferCount; + ASSERT_EQ(OK, + consumer->readReleaseFence(consumerId, consumerFence, maxAcquiredBufferCount)); + + ASSERT_EQ(expectedId, consumerId); + ASSERT_TRUE(is_same_file(fence->get(), consumerFence->get())); + ASSERT_EQ(expectedMaxAcquiredBufferCount, maxAcquiredBufferCount); + } +} + +} // namespace android \ No newline at end of file diff --git a/libs/gui/tests/Choreographer_test.cpp b/libs/gui/tests/Choreographer_test.cpp index 2ac2550f07200e54a68065bbeafe15e0a4c40117..8db48d2eb01a24426da766a3573845a0b752e94a 100644 --- a/libs/gui/tests/Choreographer_test.cpp +++ b/libs/gui/tests/Choreographer_test.cpp @@ -52,25 +52,23 @@ TEST_F(ChoreographerTest, InputCallbackBeforeAnimation) { sp looper = Looper::prepare(0); Choreographer* choreographer = Choreographer::getForThread(); VsyncCallback animationCb; - VsyncCallback inputCb; - choreographer->postFrameCallbackDelayed(nullptr, nullptr, vsyncCallback, &animationCb, 0, CALLBACK_ANIMATION); + VsyncCallback inputCb; choreographer->postFrameCallbackDelayed(nullptr, nullptr, vsyncCallback, &inputCb, 0, CALLBACK_INPUT); - - nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); - nsecs_t currTime; - int pollResult; + auto startTime = std::chrono::system_clock::now(); do { - pollResult = looper->pollOnce(16); - currTime = systemTime(SYSTEM_TIME_MONOTONIC); - } while (!(inputCb.callbackReceived() && animationCb.callbackReceived()) && - (pollResult != Looper::POLL_TIMEOUT && pollResult != Looper::POLL_ERROR) && - (currTime - startTime < 3000)); - - ASSERT_TRUE(inputCb.callbackReceived()) << "did not receive input callback"; - ASSERT_TRUE(animationCb.callbackReceived()) << "did not receive animation callback"; + static constexpr int32_t timeoutMs = 1000; + int pollResult = looper->pollOnce(timeoutMs); + ASSERT_TRUE((pollResult != Looper::POLL_TIMEOUT) && (pollResult != Looper::POLL_ERROR)) + << "Failed to poll looper. Poll result = " << pollResult; + auto elapsedMs = std::chrono::duration_cast( + std::chrono::system_clock::now() - startTime); + ASSERT_LE(elapsedMs.count(), timeoutMs) + << "Timed out waiting for callbacks. inputCb=" << inputCb.callbackReceived() + << " animationCb=" << animationCb.callbackReceived(); + } while (!(inputCb.callbackReceived() && animationCb.callbackReceived())); ASSERT_EQ(inputCb.frameTime, animationCb.frameTime) << android::base::StringPrintf("input and animation callback frame times don't match. " diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp index d80bd9c62aee86abadd6437c7d127b60e0271875..f4239cb69e75c6e3243a36a10318186028f58de5 100644 --- a/libs/gui/tests/CpuConsumer_test.cpp +++ b/libs/gui/tests/CpuConsumer_test.cpp @@ -66,13 +66,10 @@ protected: test_info->name(), params.width, params.height, params.maxLockedBuffers, params.format); - sp producer; - sp consumer; - BufferQueue::createBufferQueue(&producer, &consumer); - mCC = new CpuConsumer(consumer, params.maxLockedBuffers); + mCC = new CpuConsumer(params.maxLockedBuffers); String8 name("CpuConsumer_Under_Test"); mCC->setName(name); - mSTC = new Surface(producer); + mSTC = mCC->getSurface(); mANW = mSTC; } diff --git a/libs/gui/tests/LibGuiMain.cpp b/libs/gui/tests/LibGuiMain.cpp index 10f7207588a2d377570f4d06bdeae8c50563672b..7c7c2cc30f8ba3dcf49d1945176abaf6de5af01c 100644 --- a/libs/gui/tests/LibGuiMain.cpp +++ b/libs/gui/tests/LibGuiMain.cpp @@ -14,8 +14,15 @@ * limitations under the License. */ -#include "gtest/gtest.h" -#include "log/log.h" +#include +#include +#include + +#include "testserver/TestServer.h" +#include "testserver/TestServerClient.h" +#include "testserver/TestServerHost.h" + +using namespace android; namespace { @@ -32,7 +39,34 @@ class TestCaseLogger : public ::testing::EmptyTestEventListener { } // namespace int main(int argc, char** argv) { + // There are three modes that we can run in to support the libgui TestServer: + // + // - libgui_test : normal mode, runs tests and fork/execs the testserver host process + // - libgui_test --test-server-host $recvPipeFd $sendPipeFd : TestServerHost mode, listens on + // $recvPipeFd for commands and sends responses over $sendPipeFd + // - libgui_test --test-server $name : TestServer mode, starts a ITestService binder service + // under $name + for (int i = 1; i < argc; i++) { + std::string arg = argv[i]; + if (arg == "--test-server-host") { + LOG_ALWAYS_FATAL_IF(argc < (i + 2), "--test-server-host requires two pipe fds"); + // Note that the send/recv are from our perspective. + base::unique_fd recvPipeFd = base::unique_fd(atoi(argv[i + 1])); + base::unique_fd sendPipeFd = base::unique_fd(atoi(argv[i + 2])); + return TestServerHostMain(argv[0], std::move(sendPipeFd), std::move(recvPipeFd)); + } + if (arg == "--test-server") { + LOG_ALWAYS_FATAL_IF(argc < (i + 1), "--test-server requires a name"); + return TestServerMain(argv[i + 1]); + } + } testing::InitGoogleTest(&argc, argv); testing::UnitTest::GetInstance()->listeners().Append(new TestCaseLogger()); + + // This has to be run *before* any test initialization, because it fork/execs a TestServerHost, + // which will later create new binder service. You can't do that in a forked thread after you've + // initialized any binder stuff, which some tests do. + TestServerClient::InitializeOrDie(argv[0]); + return RUN_ALL_TESTS(); } \ No newline at end of file diff --git a/libs/gui/tests/MultiTextureConsumer_test.cpp b/libs/gui/tests/MultiTextureConsumer_test.cpp index 7d3d4aa412e895ee452b6181b481e8a7b2328a32..2428bb311023865c71a47fb338811075ed99f554 100644 --- a/libs/gui/tests/MultiTextureConsumer_test.cpp +++ b/libs/gui/tests/MultiTextureConsumer_test.cpp @@ -34,12 +34,8 @@ protected: virtual void SetUp() { GLTest::SetUp(); - sp producer; - sp consumer; - BufferQueue::createBufferQueue(&producer, &consumer); - mGlConsumer = new GLConsumer(consumer, TEX_ID, - GLConsumer::TEXTURE_EXTERNAL, true, false); - mSurface = new Surface(producer); + mGlConsumer = new GLConsumer(TEX_ID, GLConsumer::TEXTURE_EXTERNAL, true, false); + mSurface = mGlConsumer->getSurface(); mANW = mSurface.get(); } diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp index 223e4b6cbda7500f6290913883f47117ed80ceee..a0d8c533854b87cf1a1d35ee9c07885a40753e87 100644 --- a/libs/gui/tests/RegionSampling_test.cpp +++ b/libs/gui/tests/RegionSampling_test.cpp @@ -19,7 +19,7 @@ #include #include -#include +#include #include #include #include diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp index b28dca8ab418aaacd0e96a783c7a8389aadb43f2..59d05b673c44be80cb4df82e46a4346e532d5f0e 100644 --- a/libs/gui/tests/SurfaceTextureClient_test.cpp +++ b/libs/gui/tests/SurfaceTextureClient_test.cpp @@ -40,12 +40,8 @@ protected: } virtual void SetUp() { - sp producer; - sp consumer; - BufferQueue::createBufferQueue(&producer, &consumer); - mST = new GLConsumer(consumer, 123, GLConsumer::TEXTURE_EXTERNAL, true, - false); - mSTC = new Surface(producer); + mST = new GLConsumer(123, GLConsumer::TEXTURE_EXTERNAL, true, false); + mSTC = mST->getSurface(); mANW = mSTC; // We need a valid GL context so we can test updateTexImage() @@ -731,12 +727,8 @@ protected: ASSERT_NE(EGL_NO_CONTEXT, mEglContext); for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) { - sp producer; - sp consumer; - BufferQueue::createBufferQueue(&producer, &consumer); - sp st(new GLConsumer(consumer, i, - GLConsumer::TEXTURE_EXTERNAL, true, false)); - sp stc(new Surface(producer)); + sp st(new GLConsumer(i, GLConsumer::TEXTURE_EXTERNAL, true, false)); + sp stc = st->getSurface(); mEglSurfaces[i] = eglCreateWindowSurface(mEglDisplay, myConfig, static_cast(stc.get()), nullptr); ASSERT_EQ(EGL_SUCCESS, eglGetError()); diff --git a/libs/gui/tests/SurfaceTextureGL.h b/libs/gui/tests/SurfaceTextureGL.h index 9d8af5d0f57628e1e9e656a6f84e00e5f4cff968..1309635afd9cd5fa7518904564910caf53d6b8ae 100644 --- a/libs/gui/tests/SurfaceTextureGL.h +++ b/libs/gui/tests/SurfaceTextureGL.h @@ -38,11 +38,8 @@ protected: void SetUp() { GLTest::SetUp(); - sp producer; - BufferQueue::createBufferQueue(&producer, &mConsumer); - mST = new GLConsumer(mConsumer, TEX_ID, GLConsumer::TEXTURE_EXTERNAL, - true, false); - mSTC = new Surface(producer); + mST = new GLConsumer(TEX_ID, GLConsumer::TEXTURE_EXTERNAL, true, false); + mSTC = mST->getSurface(); mANW = mSTC; ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), TEST_PRODUCER_USAGE_BITS)); mTextureRenderer = new TextureRenderer(TEX_ID, mST); @@ -63,7 +60,6 @@ protected: mTextureRenderer->drawTexture(); } - sp mConsumer; sp mST; sp mSTC; sp mANW; diff --git a/libs/gui/tests/SurfaceTextureGL_test.cpp b/libs/gui/tests/SurfaceTextureGL_test.cpp index f76c0be265bc6846bcba5767c24122ae16d7cd7a..449533aa57b46d44831904fb46bc61bc6b280271 100644 --- a/libs/gui/tests/SurfaceTextureGL_test.cpp +++ b/libs/gui/tests/SurfaceTextureGL_test.cpp @@ -480,8 +480,8 @@ TEST_F(SurfaceTextureGLTest, DisconnectStressTest) { }; sp dw(new DisconnectWaiter()); - mConsumer->consumerConnect(dw, false); - + sp consumer = mST->getIGraphicBufferConsumer(); + consumer->consumerConnect(dw, false); sp pt(new ProducerThread(mANW)); pt->run("ProducerThread"); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 5e910883780919aa54b82e6cc7bc103246efe6c1..88893b64baaa605975cab9192c4eef4768477f3d 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include "gui/view/Surface.h" #include "Constants.h" #include "MockConsumer.h" @@ -23,28 +24,41 @@ #include #include #include +#include #include +#include #include -#include +#include #include -#include +#include +#include +#include +#include +#include #include #include #include #include -#include #include #include #include +#include #include #include +#include #include #include #include +#include +#include +#include +#include #include #include +#include "testserver/TestServerClient.h" + namespace android { using namespace std::chrono_literals; @@ -82,7 +96,7 @@ public: virtual void onBuffersDiscarded(const std::vector>& buffers) { mDiscardedBuffers.insert(mDiscardedBuffers.end(), buffers.begin(), buffers.end()); } - + virtual void onBufferDetached(int /*slot*/) {} int getReleaseNotifyCount() const { return mBuffersReleased; } @@ -97,6 +111,18 @@ private: std::vector> mDiscardedBuffers; }; +class DeathWatcherListener : public StubSurfaceListener { +public: + virtual void onRemoteDied() { mDiedPromise.set_value(true); } + + virtual bool needsDeathNotify() { return true; } + + std::future getDiedFuture() { return mDiedPromise.get_future(); } + +private: + std::promise mDiedPromise; +}; + class SurfaceTest : public ::testing::Test { protected: SurfaceTest() { @@ -143,10 +169,10 @@ protected: if (hasSurfaceListener) { listener = new FakeSurfaceListener(enableReleasedCb); } - ASSERT_EQ(OK, surface->connect( - NATIVE_WINDOW_API_CPU, - /*reportBufferRemoval*/true, - /*listener*/listener)); + ASSERT_EQ(OK, + surface->connect(NATIVE_WINDOW_API_CPU, + /*listener*/ listener, + /*reportBufferRemoval*/ true)); const int BUFFER_COUNT = 4 + extraDiscardedBuffers; ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(window.get(), BUFFER_COUNT)); ASSERT_EQ(NO_ERROR, native_window_set_usage(window.get(), TEST_PRODUCER_USAGE_BITS)); @@ -264,13 +290,9 @@ TEST_F(SurfaceTest, LayerCountIsOne) { TEST_F(SurfaceTest, QueryConsumerUsage) { const int TEST_USAGE_FLAGS = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER; - sp producer; - sp consumer; - BufferQueue::createBufferQueue(&producer, &consumer); - sp c = new BufferItemConsumer(consumer, - TEST_USAGE_FLAGS); - sp s = new Surface(producer); + sp c = new BufferItemConsumer(TEST_USAGE_FLAGS); + sp s = c->getSurface(); sp anw(s); int flags = -1; @@ -282,15 +304,11 @@ TEST_F(SurfaceTest, QueryConsumerUsage) { TEST_F(SurfaceTest, QueryDefaultBuffersDataSpace) { const android_dataspace TEST_DATASPACE = HAL_DATASPACE_V0_SRGB; - sp producer; - sp consumer; - BufferQueue::createBufferQueue(&producer, &consumer); - sp cpuConsumer = new CpuConsumer(consumer, 1); + sp cpuConsumer = new CpuConsumer(1); cpuConsumer->setDefaultBufferDataSpace(TEST_DATASPACE); - sp s = new Surface(producer); - + sp s = cpuConsumer->getSurface(); sp anw(s); android_dataspace dataSpace; @@ -303,11 +321,8 @@ TEST_F(SurfaceTest, QueryDefaultBuffersDataSpace) { } TEST_F(SurfaceTest, SettingGenerationNumber) { - sp producer; - sp consumer; - BufferQueue::createBufferQueue(&producer, &consumer); - sp cpuConsumer = new CpuConsumer(consumer, 1); - sp surface = new Surface(producer); + sp cpuConsumer = new CpuConsumer(1); + sp surface = cpuConsumer->getSurface(); sp window(surface); // Allocate a buffer with a generation number of 0 @@ -491,11 +506,11 @@ TEST_F(SurfaceTest, GetAndFlushRemovedBuffers) { sp surface = new Surface(producer); sp window(surface); - sp listener = new StubProducerListener(); - ASSERT_EQ(OK, surface->connect( - NATIVE_WINDOW_API_CPU, - /*listener*/listener, - /*reportBufferRemoval*/true)); + sp listener = new StubSurfaceListener(); + ASSERT_EQ(OK, + surface->connect(NATIVE_WINDOW_API_CPU, + /*listener*/ listener, + /*reportBufferRemoval*/ true)); const int BUFFER_COUNT = 4; ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(window.get(), BUFFER_COUNT)); ASSERT_EQ(NO_ERROR, native_window_set_usage(window.get(), TEST_PRODUCER_USAGE_BITS)); @@ -987,6 +1002,19 @@ public: binder::Status notifyShutdown() override { return binder::Status::ok(); } + binder::Status addJankListener(const sp& /*layer*/, + const sp& /*listener*/) override { + return binder::Status::ok(); + } + + binder::Status flushJankData(int32_t /*layerId*/) override { return binder::Status::ok(); } + + binder::Status removeJankListener(int32_t /*layerId*/, + const sp& /*listener*/, + int64_t /*afterVsync*/) override { + return binder::Status::ok(); + } + protected: IBinder* onAsBinder() override { return nullptr; } @@ -2134,14 +2162,11 @@ TEST_F(SurfaceTest, DefaultMaxBufferCountSetAndUpdated) { TEST_F(SurfaceTest, BatchOperations) { const int BUFFER_COUNT = 16; const int BATCH_SIZE = 8; - sp producer; - sp consumer; - BufferQueue::createBufferQueue(&producer, &consumer); - sp cpuConsumer = new CpuConsumer(consumer, 1); - sp surface = new Surface(producer); + sp cpuConsumer = new CpuConsumer(1); + sp surface = cpuConsumer->getSurface(); sp window(surface); - sp listener = new StubProducerListener(); + sp listener = new StubSurfaceListener(); ASSERT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, /*listener*/listener, /*reportBufferRemoval*/false)); @@ -2186,14 +2211,11 @@ TEST_F(SurfaceTest, BatchOperations) { TEST_F(SurfaceTest, BatchIllegalOperations) { const int BUFFER_COUNT = 16; const int BATCH_SIZE = 8; - sp producer; - sp consumer; - BufferQueue::createBufferQueue(&producer, &consumer); - sp cpuConsumer = new CpuConsumer(consumer, 1); - sp surface = new Surface(producer); + sp cpuConsumer = new CpuConsumer(1); + sp surface = cpuConsumer->getSurface(); sp window(surface); - sp listener = new StubProducerListener(); + sp listener = new StubSurfaceListener(); ASSERT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, /*listener*/listener, /*reportBufferRemoval*/false)); @@ -2213,4 +2235,288 @@ TEST_F(SurfaceTest, BatchIllegalOperations) { ASSERT_EQ(NO_ERROR, surface->disconnect(NATIVE_WINDOW_API_CPU)); } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + +TEST_F(SurfaceTest, PlatformBufferMethods) { + sp cpuConsumer = sp::make(1); + sp surface = cpuConsumer->getSurface(); + sp listener = sp::make(); + sp buffer; + sp fence; + + EXPECT_EQ(OK, + surface->connect(NATIVE_WINDOW_API_CPU, listener, /* reportBufferRemoval */ false)); + + // + // Verify nullptrs are handled safely: + // + + EXPECT_EQ(BAD_VALUE, surface->dequeueBuffer((sp*)nullptr, nullptr)); + EXPECT_EQ(BAD_VALUE, surface->dequeueBuffer((sp*)nullptr, &fence)); + EXPECT_EQ(BAD_VALUE, surface->dequeueBuffer(&buffer, nullptr)); + EXPECT_EQ(BAD_VALUE, surface->queueBuffer(nullptr, nullptr)); + EXPECT_EQ(BAD_VALUE, surface->detachBuffer(nullptr)); + + // + // Verify dequeue/queue: + // + + EXPECT_EQ(OK, surface->dequeueBuffer(&buffer, &fence)); + EXPECT_NE(nullptr, buffer); + EXPECT_EQ(OK, surface->queueBuffer(buffer, fence)); + + // + // Verify dequeue/detach: + // + + wp weakBuffer; + { + EXPECT_EQ(OK, surface->dequeueBuffer(&buffer, &fence)); + + EXPECT_EQ(OK, surface->detachBuffer(buffer)); + + weakBuffer = buffer; + buffer = nullptr; + } + EXPECT_EQ(nullptr, weakBuffer.promote()) << "Weak buffer still held by Surface."; + + // + // Verify detach without borrowing the buffer does not work: + // + + sp heldTooLongBuffer; + EXPECT_EQ(OK, surface->dequeueBuffer(&heldTooLongBuffer, &fence)); + EXPECT_EQ(OK, surface->queueBuffer(heldTooLongBuffer)); + EXPECT_EQ(BAD_VALUE, surface->detachBuffer(heldTooLongBuffer)); +} + +TEST_F(SurfaceTest, AllowAllocation) { + // controlledByApp must be true to disable blocking + sp cpuConsumer = sp::make(1, /*controlledByApp*/ true); + sp surface = cpuConsumer->getSurface(); + sp listener = sp::make(); + sp buffer; + sp fence; + + EXPECT_EQ(OK, + surface->connect(NATIVE_WINDOW_API_CPU, listener, /* reportBufferRemoval */ false)); + EXPECT_EQ(OK, surface->allowAllocation(false)); + + EXPECT_EQ(OK, surface->setDequeueTimeout(-1)); + EXPECT_EQ(WOULD_BLOCK, surface->dequeueBuffer(&buffer, &fence)); + + EXPECT_EQ(OK, surface->setDequeueTimeout(10)); + EXPECT_EQ(TIMED_OUT, surface->dequeueBuffer(&buffer, &fence)); + + EXPECT_EQ(OK, surface->allowAllocation(true)); + EXPECT_EQ(OK, surface->dequeueBuffer(&buffer, &fence)); +} + +TEST_F(SurfaceTest, QueueAcquireReleaseDequeue_CalledInStack_DoesNotDeadlock) { + class DequeuingSurfaceListener : public SurfaceListener { + public: + DequeuingSurfaceListener(const wp& surface) : mSurface(surface) {} + + virtual void onBufferReleased() override { + sp surface = mSurface.promote(); + ASSERT_NE(nullptr, surface); + EXPECT_EQ(OK, surface->dequeueBuffer(&mBuffer, &mFence)); + } + + virtual bool needsReleaseNotify() override { return true; } + virtual void onBuffersDiscarded(const std::vector>&) override {} + virtual void onBufferDetached(int) override {} + + sp mBuffer; + sp mFence; + + private: + wp mSurface; + }; + + class ImmediateReleaseConsumerListener : public BufferItemConsumer::FrameAvailableListener { + public: + ImmediateReleaseConsumerListener(const wp& consumer) + : mConsumer(consumer) {} + + virtual void onFrameAvailable(const BufferItem&) override { + sp consumer = mConsumer.promote(); + ASSERT_NE(nullptr, consumer); + + mCalls += 1; + + BufferItem buffer; + EXPECT_EQ(OK, consumer->acquireBuffer(&buffer, 0)); + EXPECT_EQ(OK, consumer->releaseBuffer(buffer)); + } + + size_t mCalls = 0; + + private: + wp mConsumer; + }; + + sp bqProducer; + sp bqConsumer; + BufferQueue::createBufferQueue(&bqProducer, &bqConsumer); + + sp consumer = sp::make(bqConsumer, 3); + sp surface = sp::make(bqProducer); + sp consumerListener = + sp::make(consumer); + consumer->setFrameAvailableListener(consumerListener); + + sp surfaceListener = sp::make(surface); + EXPECT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, surfaceListener, false)); + + EXPECT_EQ(OK, surface->setMaxDequeuedBufferCount(2)); + + sp buffer; + sp fence; + EXPECT_EQ(OK, surface->dequeueBuffer(&buffer, &fence)); + EXPECT_EQ(OK, surface->queueBuffer(buffer, fence)); + + EXPECT_EQ(1u, consumerListener->mCalls); + EXPECT_NE(nullptr, surfaceListener->mBuffer); + + EXPECT_EQ(OK, surface->disconnect(NATIVE_WINDOW_API_CPU)); +} + +TEST_F(SurfaceTest, ViewSurface_toString) { + view::Surface surface{}; + EXPECT_EQ("", surface.toString()); + + surface.name = String16("name"); + EXPECT_EQ("name", surface.toString()); +} + +TEST_F(SurfaceTest, TestRemoteSurfaceDied_CallbackCalled) { + sp testServer = TestServerClient::Create(); + sp producer = testServer->CreateProducer(); + EXPECT_NE(nullptr, producer); + + sp surface = sp::make(producer); + sp deathWatcher = sp::make(); + EXPECT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, deathWatcher)); + + auto diedFuture = deathWatcher->getDiedFuture(); + EXPECT_EQ(OK, testServer->Kill()); + + diedFuture.wait(); + EXPECT_TRUE(diedFuture.get()); +} + +TEST_F(SurfaceTest, TestRemoteSurfaceDied_Disconnect_CallbackNotCalled) { + sp testServer = TestServerClient::Create(); + sp producer = testServer->CreateProducer(); + EXPECT_NE(nullptr, producer); + + sp surface = sp::make(producer); + sp deathWatcher = sp::make(); + EXPECT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, deathWatcher)); + EXPECT_EQ(OK, surface->disconnect(NATIVE_WINDOW_API_CPU)); + + auto watcherDiedFuture = deathWatcher->getDiedFuture(); + EXPECT_EQ(OK, testServer->Kill()); + + std::future_status status = watcherDiedFuture.wait_for(std::chrono::seconds(1)); + EXPECT_EQ(std::future_status::timeout, status); +} + +TEST_F(SurfaceTest, QueueBufferOutput_TracksReplacements) { + sp consumer = sp::make(GRALLOC_USAGE_SW_READ_OFTEN); + ASSERT_EQ(OK, consumer->setMaxBufferCount(3)); + ASSERT_EQ(OK, consumer->setMaxAcquiredBufferCount(1)); + + sp surface = consumer->getSurface(); + sp listener = sp::make(); + + // Async mode sets up an extra buffer so the surface can queue it without waiting. + ASSERT_EQ(OK, surface->setMaxDequeuedBufferCount(1)); + ASSERT_EQ(OK, surface->setAsyncMode(true)); + ASSERT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, listener)); + + sp buffer; + sp fence; + SurfaceQueueBufferOutput output; + BufferItem item; + + // We can queue directly, without an output arg. + EXPECT_EQ(OK, surface->dequeueBuffer(&buffer, &fence)); + EXPECT_EQ(OK, surface->queueBuffer(buffer, fence)); + EXPECT_EQ(OK, consumer->acquireBuffer(&item, 0)); + EXPECT_EQ(OK, consumer->releaseBuffer(item)); + + // We can queue with an output arg, and that we don't expect to see a replacement. + EXPECT_EQ(OK, surface->dequeueBuffer(&buffer, &fence)); + EXPECT_EQ(OK, surface->queueBuffer(buffer, fence, &output)); + EXPECT_FALSE(output.bufferReplaced); + + // We expect see a replacement when we queue a second buffer in async mode, and the consumer + // hasn't acquired the first one yet. + EXPECT_EQ(OK, surface->dequeueBuffer(&buffer, &fence)); + EXPECT_EQ(OK, surface->queueBuffer(buffer, fence, &output)); + EXPECT_TRUE(output.bufferReplaced); +} + +TEST_F(SurfaceTest, QueueBufferOutput_TracksReplacements_Plural) { + sp consumer = sp::make(GRALLOC_USAGE_SW_READ_OFTEN); + ASSERT_EQ(OK, consumer->setMaxBufferCount(4)); + ASSERT_EQ(OK, consumer->setMaxAcquiredBufferCount(1)); + + sp surface = consumer->getSurface(); + consumer->setName(String8("TRPTest")); + sp listener = sp::make(); + + // Async mode sets up an extra buffer so the surface can queue it without waiting. + ASSERT_EQ(OK, surface->setMaxDequeuedBufferCount(2)); + ASSERT_EQ(OK, surface->setAsyncMode(true)); + ASSERT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, listener)); + + // dequeueBuffers requires a vector of a certain size: + std::vector buffers(2); + std::vector queuedBuffers; + std::vector outputs; + BufferItem item; + + auto moveBuffersToQueuedBuffers = [&]() { + EXPECT_EQ(2u, buffers.size()); + EXPECT_NE(nullptr, buffers[0].buffer); + EXPECT_NE(nullptr, buffers[1].buffer); + + queuedBuffers.clear(); + for (auto& buffer : buffers) { + auto& queuedBuffer = queuedBuffers.emplace_back(); + queuedBuffer.buffer = buffer.buffer; + queuedBuffer.fenceFd = buffer.fenceFd; + queuedBuffer.timestamp = NATIVE_WINDOW_TIMESTAMP_AUTO; + } + buffers = {{}, {}}; + }; + + // We can queue directly, without an output arg. + EXPECT_EQ(OK, surface->dequeueBuffers(&buffers)); + moveBuffersToQueuedBuffers(); + EXPECT_EQ(OK, surface->queueBuffers(queuedBuffers)); + EXPECT_EQ(OK, consumer->acquireBuffer(&item, 0)); + EXPECT_EQ(OK, consumer->releaseBuffer(item)); + + // We can queue with an output arg. Only the second one should be replaced. + EXPECT_EQ(OK, surface->dequeueBuffers(&buffers)); + moveBuffersToQueuedBuffers(); + EXPECT_EQ(OK, surface->queueBuffers(queuedBuffers, &outputs)); + EXPECT_EQ(2u, outputs.size()); + EXPECT_FALSE(outputs[0].bufferReplaced); + EXPECT_TRUE(outputs[1].bufferReplaced); + + // Since we haven't acquired anything, both queued buffers will replace the original one. + EXPECT_EQ(OK, surface->dequeueBuffers(&buffers)); + moveBuffersToQueuedBuffers(); + EXPECT_EQ(OK, surface->queueBuffers(queuedBuffers, &outputs)); + EXPECT_EQ(2u, outputs.size()); + EXPECT_TRUE(outputs[0].bufferReplaced); + EXPECT_TRUE(outputs[1].bufferReplaced); +} +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + } // namespace android diff --git a/libs/gui/tests/TestServer_test.cpp b/libs/gui/tests/TestServer_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d6407820ffc8abee49e9bef4646b46c6f3af98fe --- /dev/null +++ b/libs/gui/tests/TestServer_test.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2024 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "binder/IInterface.h" +#include "testserver/TestServerClient.h" + +namespace android { + +namespace { + +class TestServerTest : public ::testing::Test { +protected: + TestServerTest() { ProcessState::self()->startThreadPool(); } +}; + +} // namespace + +TEST_F(TestServerTest, Create) { + EXPECT_NE(nullptr, TestServerClient::Create()); +} + +TEST_F(TestServerTest, CreateProducer) { + sp client = TestServerClient::Create(); + EXPECT_NE(nullptr, client->CreateProducer()); +} + +TEST_F(TestServerTest, KillServer) { + class DeathWaiter : public IBinder::DeathRecipient { + public: + virtual void binderDied(const wp&) override { mPromise.set_value(true); } + std::future getFuture() { return mPromise.get_future(); } + + std::promise mPromise; + }; + + sp client = TestServerClient::Create(); + sp producer = client->CreateProducer(); + EXPECT_NE(nullptr, producer); + + sp deathWaiter = sp::make(); + EXPECT_EQ(OK, IInterface::asBinder(producer)->linkToDeath(deathWaiter)); + + auto deathWaiterFuture = deathWaiter->getFuture(); + EXPECT_EQ(OK, client->Kill()); + EXPECT_EQ(nullptr, client->CreateProducer()); + + EXPECT_TRUE(deathWaiterFuture.get()); +} + +} // namespace android diff --git a/libs/gui/tests/testserver/TestServer.cpp b/libs/gui/tests/testserver/TestServer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cd8824e35538d40ec51df2d0dd8c747249129387 --- /dev/null +++ b/libs/gui/tests/testserver/TestServer.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2024 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 "TestServer" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "TestServer.h" + +namespace android { + +namespace { +class TestConsumerListener : public BnConsumerListener { + virtual void onFrameAvailable(const BufferItem&) override {} + virtual void onBuffersReleased() override {} + virtual void onSidebandStreamChanged() override {} +}; + +class TestServiceImpl : public libgui_test_server::BnTestServer { +public: + TestServiceImpl(const char* name) : mName(name) {} + + virtual binder::Status createProducer(view::Surface* out) override { + std::lock_guard lock(mMutex); + + BufferQueueHolder bq; + BufferQueue::createBufferQueue(&bq.producer, &bq.consumer); + sp listener = sp::make(); + bq.consumer->consumerConnect(listener, /*controlledByApp*/ true); + + uint64_t id = 0; + bq.producer->getUniqueId(&id); + std::string name = base::StringPrintf("%s-%" PRIu64, mName, id); + + out->name = String16(name.c_str()); + out->graphicBufferProducer = bq.producer; + mBqs.push_back(std::move(bq)); + + return binder::Status::ok(); + } + + virtual binder::Status killNow() override { + ALOGE("LibGUI Test Service %s dying in response to killNow", mName); + _exit(0); + // Not reached: + return binder::Status::ok(); + } + +private: + std::mutex mMutex; + const char* mName; + + struct BufferQueueHolder { + sp producer; + sp consumer; + }; + + std::vector mBqs; +}; +} // namespace + +int TestServerMain(const char* name) { + ProcessState::self()->startThreadPool(); + + sp testService = sp::make(name); + ALOGE("service"); + sp serviceManager(defaultServiceManager()); + LOG_ALWAYS_FATAL_IF(OK != serviceManager->addService(String16(name), testService)); + + ALOGD("LibGUI Test Service %s STARTED", name); + + IPCThreadState::self()->joinThreadPool(); + + ALOGW("LibGUI Test Service %s DIED", name); + + return 0; +} + +} // namespace android \ No newline at end of file diff --git a/libs/gui/tests/testserver/TestServer.h b/libs/gui/tests/testserver/TestServer.h new file mode 100644 index 0000000000000000000000000000000000000000..4226f1bb0932b9d3d620fe3c3d4072caec72b270 --- /dev/null +++ b/libs/gui/tests/testserver/TestServer.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 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 + +namespace android { + +/* + * Main method for a libgui ITestServer server. + * + * This must be called without any binder setup having been done, because you can't fork and do + * binder things once ProcessState is set up. + * @param name The service name of the test server to start. + * @return retcode + */ +int TestServerMain(const char* name); + +} // namespace android diff --git a/libs/gui/tests/testserver/TestServerClient.cpp b/libs/gui/tests/testserver/TestServerClient.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e388074675cde2a8ee85980aa1c363bf006fe690 --- /dev/null +++ b/libs/gui/tests/testserver/TestServerClient.cpp @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2024 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 +#include +#define LOG_TAG "TestServerClient" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "TestServerClient.h" +#include "TestServerCommon.h" + +namespace android { + +namespace { + +std::string GetUniqueServiceName() { + static std::atomic uniqueId = 1; + + pid_t pid = getpid(); + int id = uniqueId++; + return base::StringPrintf("Libgui-TestServer-%d-%d", pid, id); +} + +struct RemoteTestServerHostHolder { + RemoteTestServerHostHolder(pid_t pid, int sendFd, int recvFd) + : mPid(pid), mSendFd(sendFd), mRecvFd(recvFd) {} + ~RemoteTestServerHostHolder() { + std::lock_guard lock(mMutex); + + kill(mPid, SIGKILL); + close(mSendFd); + close(mRecvFd); + } + + pid_t CreateTestServerOrDie(std::string name) { + std::lock_guard lock(mMutex); + + CreateServerRequest request; + strlcpy(request.name, name.c_str(), sizeof(request.name) / sizeof(request.name[0])); + + ssize_t bytes = write(mSendFd, &request, sizeof(request)); + LOG_ALWAYS_FATAL_IF(bytes != sizeof(request)); + + CreateServerResponse response; + bytes = read(mRecvFd, &response, sizeof(response)); + LOG_ALWAYS_FATAL_IF(bytes != sizeof(response)); + + return response.pid; + } + +private: + std::mutex mMutex; + + pid_t mPid; + int mSendFd; + int mRecvFd; +}; + +std::unique_ptr g_remoteTestServerHostHolder = nullptr; + +} // namespace + +void TestServerClient::InitializeOrDie(const char* filename) { + int sendPipeFds[2]; + int ret = pipe(sendPipeFds); + LOG_ALWAYS_FATAL_IF(ret, "Unable to create subprocess send pipe"); + + int recvPipeFds[2]; + ret = pipe(recvPipeFds); + LOG_ALWAYS_FATAL_IF(ret, "Unable to create subprocess recv pipe"); + + pid_t childPid = fork(); + LOG_ALWAYS_FATAL_IF(childPid < 0, "Unable to fork child process"); + + if (childPid == 0) { + // We forked! + close(sendPipeFds[1]); + close(recvPipeFds[0]); + + // We'll be reading from the parent's "send" and writing to the parent's "recv". + std::string sendPipe = std::to_string(sendPipeFds[0]); + std::string recvPipe = std::to_string(recvPipeFds[1]); + char* args[] = { + const_cast(filename), + const_cast("--test-server-host"), + const_cast(sendPipe.c_str()), + const_cast(recvPipe.c_str()), + nullptr, + }; + + ret = execv(filename, args); + ALOGE("Failed to exec libguiTestServer. ret=%d errno=%d (%s)", ret, errno, strerror(errno)); + status_t status = -errno; + write(recvPipeFds[1], &status, sizeof(status)); + _exit(EXIT_FAILURE); + } + + close(sendPipeFds[0]); + close(recvPipeFds[1]); + + // Check for an OK status that the host started. If so, we're good to go. + status_t status; + ret = read(recvPipeFds[0], &status, sizeof(status)); + LOG_ALWAYS_FATAL_IF(ret != sizeof(status), "Unable to read from pipe: %d", ret); + LOG_ALWAYS_FATAL_IF(OK != status, "Pipe returned failed status: %d", status); + + g_remoteTestServerHostHolder = + std::make_unique(childPid, sendPipeFds[1], recvPipeFds[0]); +} + +sp TestServerClient::Create() { + std::string serviceName = GetUniqueServiceName(); + + pid_t childPid = g_remoteTestServerHostHolder->CreateTestServerOrDie(serviceName); + ALOGD("Created child server %s with pid %d", serviceName.c_str(), childPid); + + sp server = + waitForService(String16(serviceName.c_str())); + LOG_ALWAYS_FATAL_IF(server == nullptr); + ALOGD("Created connected to child server %s", serviceName.c_str()); + + return sp::make(server); +} + +TestServerClient::TestServerClient(const sp& server) + : mServer(server) {} + +TestServerClient::~TestServerClient() { + Kill(); +} + +sp TestServerClient::CreateProducer() { + std::lock_guard lock(mMutex); + + if (!mIsAlive) { + return nullptr; + } + + view::Surface surface; + binder::Status status = mServer->createProducer(&surface); + + if (!status.isOk()) { + ALOGE("Failed to create remote producer. Error: %s", status.exceptionMessage().c_str()); + return nullptr; + } + + if (!surface.graphicBufferProducer) { + ALOGE("Remote producer returned no IGBP."); + return nullptr; + } + + return surface.graphicBufferProducer; +} + +status_t TestServerClient::Kill() { + std::lock_guard lock(mMutex); + if (!mIsAlive) { + return DEAD_OBJECT; + } + + mServer->killNow(); + mServer = nullptr; + mIsAlive = false; + + return OK; +} + +} // namespace android diff --git a/libs/gui/tests/testserver/TestServerClient.h b/libs/gui/tests/testserver/TestServerClient.h new file mode 100644 index 0000000000000000000000000000000000000000..53296344a3507f0c83f2344497dc7ac55acd9477 --- /dev/null +++ b/libs/gui/tests/testserver/TestServerClient.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2024 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 +#include + +namespace android { + +class TestServerClient : public RefBase { +public: + static void InitializeOrDie(const char* filename); + static sp Create(); + + TestServerClient(const sp& server); + virtual ~TestServerClient() override; + + sp CreateProducer(); + status_t Kill(); + +private: + std::mutex mMutex; + + sp mServer; + bool mIsAlive = true; +}; + +} // namespace android diff --git a/libs/gui/tests/testserver/TestServerCommon.h b/libs/gui/tests/testserver/TestServerCommon.h new file mode 100644 index 0000000000000000000000000000000000000000..7370f20ef820931694d79edbca3eea62edc34250 --- /dev/null +++ b/libs/gui/tests/testserver/TestServerCommon.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2024 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 + +namespace android { + +/* + * Test -> TestServerHost Request to create a new ITestServer fork. + */ +struct CreateServerRequest { + /* + * Service name for new ITestServer. + */ + char name[128]; +}; + +/* + * TestServerHost -> Test Response for creating an ITestServer fork. + */ +struct CreateServerResponse { + /* + * pid of new ITestServer. + */ + pid_t pid; +}; + +} // namespace android \ No newline at end of file diff --git a/libs/gui/tests/testserver/TestServerHost.cpp b/libs/gui/tests/testserver/TestServerHost.cpp new file mode 100644 index 0000000000000000000000000000000000000000..696c3b9817a5935ba2b7c34d928fcd16805bb1c4 --- /dev/null +++ b/libs/gui/tests/testserver/TestServerHost.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2024 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 "TestServerHost" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "TestServerCommon.h" +#include "TestServerHost.h" + +namespace android { + +namespace { + +pid_t ForkTestServer(const char* filename, char* name) { + pid_t childPid = fork(); + LOG_ALWAYS_FATAL_IF(childPid == -1); + + if (childPid != 0) { + return childPid; + } + + // We forked! + const char* test_server_flag = "--test-server"; + char* args[] = { + const_cast(filename), + const_cast(test_server_flag), + name, + nullptr, + }; + + int ret = execv(filename, args); + ALOGE("Failed to exec libgui_test as a TestServer. ret=%d errno=%d (%s)", ret, errno, + strerror(errno)); + _exit(EXIT_FAILURE); +} + +} // namespace + +int TestServerHostMain(const char* filename, base::unique_fd sendPipeFd, + base::unique_fd recvPipeFd) { + status_t status = OK; + LOG_ALWAYS_FATAL_IF(sizeof(status) != write(sendPipeFd.get(), &status, sizeof(status))); + + ALOGE("Launched TestServerHost"); + + while (true) { + CreateServerRequest request = {}; + ssize_t bytes = read(recvPipeFd.get(), &request, sizeof(request)); + LOG_ALWAYS_FATAL_IF(bytes != sizeof(request)); + pid_t childPid = ForkTestServer(filename, request.name); + + CreateServerResponse response = {}; + response.pid = childPid; + bytes = write(sendPipeFd.get(), &response, sizeof(response)); + LOG_ALWAYS_FATAL_IF(bytes != sizeof(response)); + } + + return 0; +} + +} // namespace android \ No newline at end of file diff --git a/libs/gui/tests/testserver/TestServerHost.h b/libs/gui/tests/testserver/TestServerHost.h new file mode 100644 index 0000000000000000000000000000000000000000..df22c0c3fe721e3f2bc935876723e10283064682 --- /dev/null +++ b/libs/gui/tests/testserver/TestServerHost.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2024 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 + +#include + +namespace android { + +/* + * Main method for a host process for TestServers. + * + * This must be called without any binder setup having been done, because you can't fork and do + * binder things once ProcessState is set up. + * @param filename File name of this binary / the binary to execve into + * @param sendPipeFd Pipe FD to send data to. + * @param recvPipeFd Pipe FD to receive data from. + * @return retcode + */ +int TestServerHostMain(const char* filename, base::unique_fd sendPipeFd, + base::unique_fd recvPipeFd); + +} // namespace android diff --git a/libs/gui/tests/testserver/aidl/libgui_test_server/ITestServer.aidl b/libs/gui/tests/testserver/aidl/libgui_test_server/ITestServer.aidl new file mode 100644 index 0000000000000000000000000000000000000000..c939ea00c1df7f4756978c2f544306ec8276ea64 --- /dev/null +++ b/libs/gui/tests/testserver/aidl/libgui_test_server/ITestServer.aidl @@ -0,0 +1,12 @@ +package libgui_test_server; + +import android.view.Surface; + +// Test server for libgui_test +interface ITestServer { + // Create a new producer. The server will have connected to the consumer. + Surface createProducer(); + + // Kills the server immediately. + void killNow(); +} diff --git a/libs/gui/view/Surface.cpp b/libs/gui/view/Surface.cpp index 7c15e7cf92075c85d529022237b6a32161e38b79..84c2a6ac71869048d244564b71684500fdf00daf 100644 --- a/libs/gui/view/Surface.cpp +++ b/libs/gui/view/Surface.cpp @@ -121,5 +121,11 @@ String16 Surface::readMaybeEmptyString16(const Parcel* parcel) { return str.value_or(String16()); } +std::string Surface::toString() const { + std::stringstream out; + out << name; + return out.str(); +} + } // namespace view } // namespace android diff --git a/libs/input/Android.bp b/libs/input/Android.bp index d782f42071a87fe6f5edd1c15e31175817df89d8..e4e81adf58a1e2cc0bf5e1f1a144872b4699cc09 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -30,6 +30,7 @@ filegroup { "android/os/InputEventInjectionResult.aidl", "android/os/InputEventInjectionSync.aidl", "android/os/InputConfig.aidl", + "android/os/MotionEventFlag.aidl", "android/os/PointerIconType.aidl", ], } @@ -231,6 +232,7 @@ cc_library { "MotionPredictorMetricsManager.cpp", "PrintTools.cpp", "PropertyMap.cpp", + "Resampler.cpp", "TfLiteMotionPredictor.cpp", "TouchVideoFrame.cpp", "VelocityControl.cpp", @@ -257,6 +259,7 @@ cc_library { ], shared_libs: [ + "android.companion.virtualdevice.flags-aconfig-cc", "libbase", "libbinder", "libbinder_ndk", diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp index b09814797fc904d4855e5ba1e444ef825c594d39..a2bb3453fe132dbad8ee8937499d4263af418db5 100644 --- a/libs/input/Input.cpp +++ b/libs/input/Input.cpp @@ -580,7 +580,7 @@ void MotionEvent::initialize(int32_t id, int32_t deviceId, uint32_t source, &pointerProperties[pointerCount]); mSampleEventTimes.clear(); mSamplePointerCoords.clear(); - addSample(eventTime, pointerCoords); + addSample(eventTime, pointerCoords, mId); } void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) { @@ -640,9 +640,9 @@ void MotionEvent::splitFrom(const android::MotionEvent& other, mSampleEventTimes = other.mSampleEventTimes; } -void MotionEvent::addSample( - int64_t eventTime, - const PointerCoords* pointerCoords) { +void MotionEvent::addSample(int64_t eventTime, const PointerCoords* pointerCoords, + int32_t eventId) { + mId = eventId; mSampleEventTimes.push_back(eventTime); mSamplePointerCoords.insert(mSamplePointerCoords.end(), &pointerCoords[0], &pointerCoords[getPointerCount()]); diff --git a/libs/input/InputConsumer.cpp b/libs/input/InputConsumer.cpp index fcf490d5f9650d9a417874c5b42a4dd932672fa6..1eeb4e678cac936c140c383733eb7b3fe0fb36bf 100644 --- a/libs/input/InputConsumer.cpp +++ b/libs/input/InputConsumer.cpp @@ -135,7 +135,7 @@ void addSample(MotionEvent& event, const InputMessage& msg) { } event.setMetaState(event.getMetaState() | msg.body.motion.metaState); - event.addSample(msg.body.motion.eventTime, pointerCoords); + event.addSample(msg.body.motion.eventTime, pointerCoords, msg.body.motion.eventId); } void initializeTouchModeEvent(TouchModeEvent& event, const InputMessage& msg) { @@ -235,8 +235,9 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consum mMsgDeferred = false; } else { // Receive a fresh message. - status_t result = mChannel->receiveMessage(&mMsg); - if (result == OK) { + android::base::Result result = mChannel->receiveMessage(); + if (result.ok()) { + mMsg = std::move(result.value()); const auto [_, inserted] = mConsumeTimes.emplace(mMsg.header.seq, systemTime(SYSTEM_TIME_MONOTONIC)); LOG_ALWAYS_FATAL_IF(!inserted, "Already have a consume time for seq=%" PRIu32, @@ -244,11 +245,11 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consum // Trace the event processing timeline - event was just read from the socket ATRACE_ASYNC_BEGIN(mProcessingTraceTag.c_str(), /*cookie=*/mMsg.header.seq); - } - if (result) { + } else { // Consume the next batched event unless batches are being held for later. - if (consumeBatches || result != WOULD_BLOCK) { - result = consumeBatch(factory, frameTime, outSeq, outEvent); + if (consumeBatches || result.error().code() != WOULD_BLOCK) { + result = android::base::Error( + consumeBatch(factory, frameTime, outSeq, outEvent)); if (*outEvent) { ALOGD_IF(DEBUG_TRANSPORT_CONSUMER, "channel '%s' consumer ~ consumed batch event, seq=%u", @@ -256,7 +257,7 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consum break; } } - return result; + return result.error().code(); } } @@ -696,7 +697,7 @@ void InputConsumer::resampleTouchState(nsecs_t sampleTime, MotionEvent* event, currentCoords.getY(), otherCoords.getX(), otherCoords.getY(), alpha); } - event->addSample(sampleTime, touchState.lastResample.pointers); + event->addSample(sampleTime, touchState.lastResample.pointers, event->getId()); } status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) { diff --git a/libs/input/InputConsumerNoResampling.cpp b/libs/input/InputConsumerNoResampling.cpp index 15d992f9f3b752488c612125d8e914935665a9e7..cdbc1869c3bce46458be0ccc44ae864f8d59da12 100644 --- a/libs/input/InputConsumerNoResampling.cpp +++ b/libs/input/InputConsumerNoResampling.cpp @@ -14,9 +14,11 @@ * limitations under the License. */ -#define LOG_TAG "InputTransport" +#define LOG_TAG "InputConsumerNoResampling" #define ATRACE_TAG ATRACE_TAG_INPUT +#include + #include #include @@ -31,12 +33,12 @@ #include ::type, U>::type; - using U2 = - typename std::conditional::value, - typename std::add_volatile::type, U1>::type; - using U3 = - typename std::conditional::value, - typename std::add_lvalue_reference::type, - U2>::type; - using U4 = - typename std::conditional::value, - typename std::add_rvalue_reference::type, - U3>::type; - - public: - using Type = U4; -}; - -template -using CopyCVReferenceType = typename CopyCVReference::Type; - -} // namespace rpc -} // namespace pdx -} // namespace android - -#endif // ANDROID_PDX_RPC_COPY_CV_REFERENCE_H_ diff --git a/libs/vr/libpdx/private/pdx/rpc/default_initialization_allocator.h b/libs/vr/libpdx/private/pdx/rpc/default_initialization_allocator.h deleted file mode 100644 index b6e298084e4542fe6dcc1aa978fdea64bc2e0d43..0000000000000000000000000000000000000000 --- a/libs/vr/libpdx/private/pdx/rpc/default_initialization_allocator.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef ANDROID_PDX_RPC_DEFAULT_INITIALIZATION_ALLOCATOR_H_ -#define ANDROID_PDX_RPC_DEFAULT_INITIALIZATION_ALLOCATOR_H_ - -#include - -namespace android { -namespace pdx { -namespace rpc { - -// Allocator adaptor that interposes construct() calls to convert value -// initialization into default initialization. All standard containers -// value-initialize their elements when constructed with a single size_type -// argument or when grown by a call to resize. This allocator avoids potentially -// costly value-initialization in these situations for value types that are -// default constructible. As a consequence, elements of non-class types are left -// uninitialized; this is desirable when using std::vector as a resizable -// buffer, for example. -template > -class DefaultInitializationAllocator : public Allocator { - typedef std::allocator_traits AllocatorTraits; - - public: - template - struct rebind { - using other = DefaultInitializationAllocator< - U, typename AllocatorTraits::template rebind_alloc>; - }; - - using Allocator::Allocator; - - template - void construct(U* pointer) noexcept( - std::is_nothrow_default_constructible::value) { - ::new (static_cast(pointer)) U; - } - template - void construct(U* pointer, Args&&... args) { - AllocatorTraits::construct(static_cast(*this), pointer, - std::forward(args)...); - } -}; - -} // namespace rpc -} // namespace pdx -} // namespace android - -#endif // ANDROID_PDX_RPC_DEFAULT_INITIALIZATION_ALLOCATOR_H_ diff --git a/libs/vr/libpdx/private/pdx/rpc/encoding.h b/libs/vr/libpdx/private/pdx/rpc/encoding.h deleted file mode 100644 index f51d807f5bf5d23a9f9cf0dad38e117ad1a93c71..0000000000000000000000000000000000000000 --- a/libs/vr/libpdx/private/pdx/rpc/encoding.h +++ /dev/null @@ -1,616 +0,0 @@ -#ifndef ANDROID_PDX_RPC_ENCODING_H_ -#define ANDROID_PDX_RPC_ENCODING_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "array_wrapper.h" -#include "buffer_wrapper.h" -#include "string_wrapper.h" -#include "variant.h" - -namespace android { -namespace pdx { -namespace rpc { - -// This library uses a subset, or profile, of MessagePack (http://msgpack.org) -// to encode supported data types during serialization and to verify the -// expected data types during deserialization. One notable deviation from the -// MessagePack specification is that little-endian byte order is used for -// multi-byte numeric types to avoid unnecessary conversion on nearly all -// relevant architectures. -// -// Some data types, integers for example, support multiple encoding strategies. -// This library attempts to optimize for space based on the value of such types. -// However, during decode all valid encodings for a given type are accepted. - -// Prefix byte for type encodings. This is the complete list of prefix bytes -// from the MessagePack specification, even though not all types are used by -// this library. -enum EncodingPrefix { - ENCODING_TYPE_POSITIVE_FIXINT = 0x00, - ENCODING_TYPE_POSITIVE_FIXINT_MIN = 0x00, - ENCODING_TYPE_POSITIVE_FIXINT_MAX = 0x7f, - ENCODING_TYPE_POSITIVE_FIXINT_MASK = 0x7f, - ENCODING_TYPE_FIXMAP = 0x80, - ENCODING_TYPE_FIXMAP_MIN = 0x80, - ENCODING_TYPE_FIXMAP_MAX = 0x8f, - ENCODING_TYPE_FIXMAP_MASK = 0x0f, - ENCODING_TYPE_FIXARRAY = 0x90, - ENCODING_TYPE_FIXARRAY_MIN = 0x90, - ENCODING_TYPE_FIXARRAY_MAX = 0x9f, - ENCODING_TYPE_FIXARRAY_MASK = 0x0f, - ENCODING_TYPE_FIXSTR = 0xa0, - ENCODING_TYPE_FIXSTR_MIN = 0xa0, - ENCODING_TYPE_FIXSTR_MAX = 0xbf, - ENCODING_TYPE_FIXSTR_MASK = 0x1f, - ENCODING_TYPE_NIL = 0xc0, - ENCODING_TYPE_RESERVED = 0xc1, - ENCODING_TYPE_FALSE = 0xc2, - ENCODING_TYPE_TRUE = 0xc3, - ENCODING_TYPE_BIN8 = 0xc4, - ENCODING_TYPE_BIN16 = 0xc5, - ENCODING_TYPE_BIN32 = 0xc6, - ENCODING_TYPE_EXT8 = 0xc7, - ENCODING_TYPE_EXT16 = 0xc8, - ENCODING_TYPE_EXT32 = 0xc9, - ENCODING_TYPE_FLOAT32 = 0xca, - ENCODING_TYPE_FLOAT64 = 0xcb, - ENCODING_TYPE_UINT8 = 0xcc, - ENCODING_TYPE_UINT16 = 0xcd, - ENCODING_TYPE_UINT32 = 0xce, - ENCODING_TYPE_UINT64 = 0xcf, - ENCODING_TYPE_INT8 = 0xd0, - ENCODING_TYPE_INT16 = 0xd1, - ENCODING_TYPE_INT32 = 0xd2, - ENCODING_TYPE_INT64 = 0xd3, - ENCODING_TYPE_FIXEXT1 = 0xd4, - ENCODING_TYPE_FIXEXT2 = 0xd5, - ENCODING_TYPE_FIXEXT4 = 0xd6, - ENCODING_TYPE_FIXEXT8 = 0xd7, - ENCODING_TYPE_FIXEXT16 = 0xd8, - ENCODING_TYPE_STR8 = 0xd9, - ENCODING_TYPE_STR16 = 0xda, - ENCODING_TYPE_STR32 = 0xdb, - ENCODING_TYPE_ARRAY16 = 0xdc, - ENCODING_TYPE_ARRAY32 = 0xdd, - ENCODING_TYPE_MAP16 = 0xde, - ENCODING_TYPE_MAP32 = 0xdf, - ENCODING_TYPE_NEGATIVE_FIXINT = 0xe0, - ENCODING_TYPE_NEGATIVE_FIXINT_MIN = 0xe0, - ENCODING_TYPE_NEGATIVE_FIXINT_MAX = 0xff, -}; - -// Base encoding classes grouping multi-strategy encodings. -enum EncodingClass { - ENCODING_CLASS_BOOL, - ENCODING_CLASS_NIL, - ENCODING_CLASS_INT, - ENCODING_CLASS_UINT, - ENCODING_CLASS_FLOAT, - ENCODING_CLASS_ARRAY, - ENCODING_CLASS_MAP, - ENCODING_CLASS_STRING, - ENCODING_CLASS_BINARY, - ENCODING_CLASS_EXTENSION, -}; - -// Encoding prefixes are unsigned bytes. -typedef std::uint8_t EncodingType; - -// Extension encoding types defined by this library. -enum EncodingExtType : int8_t { - ENCODING_EXT_TYPE_FILE_DESCRIPTOR, - ENCODING_EXT_TYPE_CHANNEL_HANDLE, -}; - -// Encoding predicates. Determines whether the given encoding is of a specific -// type. -inline constexpr bool IsFixintEncoding(EncodingType encoding) { - switch (encoding) { - case ENCODING_TYPE_POSITIVE_FIXINT_MIN ... ENCODING_TYPE_POSITIVE_FIXINT_MAX: - case ENCODING_TYPE_NEGATIVE_FIXINT_MIN ... ENCODING_TYPE_NEGATIVE_FIXINT_MAX: - return true; - default: - return false; - } -} - -inline constexpr bool IsUnsignedFixintEncoding(EncodingType encoding) { - switch (encoding) { - case ENCODING_TYPE_POSITIVE_FIXINT_MIN ... ENCODING_TYPE_POSITIVE_FIXINT_MAX: - return true; - default: - return false; - } -} - -inline constexpr bool IsInt8Encoding(EncodingType encoding) { - switch (encoding) { - case ENCODING_TYPE_POSITIVE_FIXINT_MIN ... ENCODING_TYPE_POSITIVE_FIXINT_MAX: - case ENCODING_TYPE_NEGATIVE_FIXINT_MIN ... ENCODING_TYPE_NEGATIVE_FIXINT_MAX: - case ENCODING_TYPE_INT8: - return true; - default: - return false; - } -} - -inline constexpr bool IsUInt8Encoding(EncodingType encoding) { - switch (encoding) { - case ENCODING_TYPE_POSITIVE_FIXINT_MIN ... ENCODING_TYPE_POSITIVE_FIXINT_MAX: - case ENCODING_TYPE_UINT8: - return true; - default: - return false; - } -} - -inline constexpr bool IsInt16Encoding(EncodingType encoding) { - switch (encoding) { - case ENCODING_TYPE_POSITIVE_FIXINT_MIN ... ENCODING_TYPE_POSITIVE_FIXINT_MAX: - case ENCODING_TYPE_NEGATIVE_FIXINT_MIN ... ENCODING_TYPE_NEGATIVE_FIXINT_MAX: - case ENCODING_TYPE_INT8: - case ENCODING_TYPE_INT16: - return true; - default: - return false; - } -} - -inline constexpr bool IsUInt16Encoding(EncodingType encoding) { - switch (encoding) { - case ENCODING_TYPE_POSITIVE_FIXINT_MIN ... ENCODING_TYPE_POSITIVE_FIXINT_MAX: - case ENCODING_TYPE_UINT8: - case ENCODING_TYPE_UINT16: - return true; - default: - return false; - } -} - -inline constexpr bool IsInt32Encoding(EncodingType encoding) { - switch (encoding) { - case ENCODING_TYPE_POSITIVE_FIXINT_MIN ... ENCODING_TYPE_POSITIVE_FIXINT_MAX: - case ENCODING_TYPE_NEGATIVE_FIXINT_MIN ... ENCODING_TYPE_NEGATIVE_FIXINT_MAX: - case ENCODING_TYPE_INT8: - case ENCODING_TYPE_INT16: - case ENCODING_TYPE_INT32: - return true; - default: - return false; - } -} - -inline constexpr bool IsUInt32Encoding(EncodingType encoding) { - switch (encoding) { - case ENCODING_TYPE_POSITIVE_FIXINT_MIN ... ENCODING_TYPE_POSITIVE_FIXINT_MAX: - case ENCODING_TYPE_UINT8: - case ENCODING_TYPE_UINT16: - case ENCODING_TYPE_UINT32: - return true; - default: - return false; - } -} - -inline constexpr bool IsInt64Encoding(EncodingType encoding) { - switch (encoding) { - case ENCODING_TYPE_POSITIVE_FIXINT_MIN ... ENCODING_TYPE_POSITIVE_FIXINT_MAX: - case ENCODING_TYPE_NEGATIVE_FIXINT_MIN ... ENCODING_TYPE_NEGATIVE_FIXINT_MAX: - case ENCODING_TYPE_INT8: - case ENCODING_TYPE_INT16: - case ENCODING_TYPE_INT32: - case ENCODING_TYPE_INT64: - return true; - default: - return false; - } -} - -inline constexpr bool IsUInt64Encoding(EncodingType encoding) { - switch (encoding) { - case ENCODING_TYPE_POSITIVE_FIXINT_MIN ... ENCODING_TYPE_POSITIVE_FIXINT_MAX: - case ENCODING_TYPE_UINT8: - case ENCODING_TYPE_UINT16: - case ENCODING_TYPE_UINT32: - case ENCODING_TYPE_UINT64: - return true; - default: - return false; - } -} - -inline constexpr bool IsFixmapEncoding(EncodingType encoding) { - switch (encoding) { - case ENCODING_TYPE_FIXMAP_MIN ... ENCODING_TYPE_FIXMAP_MAX: - return true; - default: - return false; - } -} - -inline constexpr bool IsFixarrayEncoding(EncodingType encoding) { - switch (encoding) { - case ENCODING_TYPE_FIXARRAY_MIN ... ENCODING_TYPE_FIXARRAY_MAX: - return true; - default: - return false; - } -} - -inline constexpr bool IsFixstrEncoding(EncodingType encoding) { - switch (encoding) { - case ENCODING_TYPE_FIXSTR_MIN ... ENCODING_TYPE_FIXSTR_MAX: - return true; - default: - return false; - } -} - -inline constexpr bool IsFixextEncoding(EncodingType encoding) { - switch (encoding) { - case ENCODING_TYPE_FIXEXT1: - case ENCODING_TYPE_FIXEXT2: - case ENCODING_TYPE_FIXEXT4: - case ENCODING_TYPE_FIXEXT8: - case ENCODING_TYPE_FIXEXT16: - return true; - default: - return false; - } -} - -inline constexpr bool IsFloat32Encoding(EncodingType encoding) { - switch (encoding) { - case ENCODING_TYPE_FLOAT32: - return true; - default: - return false; - } -} - -inline constexpr bool IsFloat64Encoding(EncodingType encoding) { - switch (encoding) { - case ENCODING_TYPE_FLOAT32: - case ENCODING_TYPE_FLOAT64: - return true; - default: - return false; - } -} - -inline constexpr bool IsBoolEncoding(EncodingType encoding) { - switch (encoding) { - case ENCODING_TYPE_FALSE: - case ENCODING_TYPE_TRUE: - return true; - default: - return false; - } -} - -inline constexpr std::size_t GetFixstrSize(EncodingType encoding) { - return encoding & ENCODING_TYPE_FIXSTR_MASK; -} - -inline constexpr std::size_t GetFixarraySize(EncodingType encoding) { - return encoding & ENCODING_TYPE_FIXARRAY_MASK; -} - -inline constexpr std::size_t GetFixmapSize(EncodingType encoding) { - return encoding & ENCODING_TYPE_FIXMAP_MASK; -} - -inline constexpr std::size_t GetFixextSize(EncodingType encoding) { - switch (encoding) { - case ENCODING_TYPE_FIXEXT1: - return 1; - case ENCODING_TYPE_FIXEXT2: - return 2; - case ENCODING_TYPE_FIXEXT4: - return 4; - case ENCODING_TYPE_FIXEXT8: - return 8; - case ENCODING_TYPE_FIXEXT16: - return 16; - default: - return 0; // Invalid fixext size. - } -} - -// Gets the size of the encoding in bytes, not including external payload data. -inline constexpr std::size_t GetEncodingSize(EncodingType encoding) { - switch (encoding) { - // Encoding is fully contained within the type value. - case ENCODING_TYPE_POSITIVE_FIXINT_MIN ... ENCODING_TYPE_POSITIVE_FIXINT_MAX: - case ENCODING_TYPE_NEGATIVE_FIXINT_MIN ... ENCODING_TYPE_NEGATIVE_FIXINT_MAX: - case ENCODING_TYPE_FIXMAP_MIN ... ENCODING_TYPE_FIXMAP_MAX: - case ENCODING_TYPE_FIXARRAY_MIN ... ENCODING_TYPE_FIXARRAY_MAX: - case ENCODING_TYPE_FIXSTR_MIN ... ENCODING_TYPE_FIXSTR_MAX: - case ENCODING_TYPE_NIL: - case ENCODING_TYPE_RESERVED: - case ENCODING_TYPE_FALSE: - case ENCODING_TYPE_TRUE: - return 1; - - // Encoding type followed by one-byte size or immediate value. - case ENCODING_TYPE_BIN8: - case ENCODING_TYPE_EXT8: - case ENCODING_TYPE_UINT8: - case ENCODING_TYPE_INT8: - case ENCODING_TYPE_STR8: - // Encoding type followed by one-byte extension type. - case ENCODING_TYPE_FIXEXT1: - case ENCODING_TYPE_FIXEXT2: - case ENCODING_TYPE_FIXEXT4: - case ENCODING_TYPE_FIXEXT8: - case ENCODING_TYPE_FIXEXT16: - return 2; - - // Encoding type followed by two-byte size or immediate value. - case ENCODING_TYPE_BIN16: - case ENCODING_TYPE_EXT16: - case ENCODING_TYPE_UINT16: - case ENCODING_TYPE_INT16: - case ENCODING_TYPE_STR16: - case ENCODING_TYPE_ARRAY16: - case ENCODING_TYPE_MAP16: - return 3; - - // Encoding type followed by four-byte size or immediate value. - case ENCODING_TYPE_BIN32: - case ENCODING_TYPE_EXT32: - case ENCODING_TYPE_FLOAT32: - case ENCODING_TYPE_UINT32: - case ENCODING_TYPE_INT32: - case ENCODING_TYPE_STR32: - case ENCODING_TYPE_ARRAY32: - case ENCODING_TYPE_MAP32: - return 5; - - // Encoding type followed by eight-byte immediate value. - case ENCODING_TYPE_FLOAT64: - case ENCODING_TYPE_UINT64: - case ENCODING_TYPE_INT64: - return 9; - - default: - return 0; - } -} - -// Encoding for standard types. Each supported data type has an associated -// encoding or set of encodings. These functions determine the MessagePack -// encoding based on the data type, value, and size of their arguments. - -inline constexpr EncodingType EncodeArrayType(std::size_t size) { - if (size < (1U << 4)) - return ENCODING_TYPE_FIXARRAY | (size & ENCODING_TYPE_FIXARRAY_MASK); - else if (size < (1U << 16)) - return ENCODING_TYPE_ARRAY16; - else - return ENCODING_TYPE_ARRAY32; -} - -inline constexpr EncodingType EncodeMapType(std::size_t size) { - if (size < (1U << 4)) - return ENCODING_TYPE_FIXMAP | (size & ENCODING_TYPE_FIXMAP_MASK); - else if (size < (1U << 16)) - return ENCODING_TYPE_MAP16; - else - return ENCODING_TYPE_MAP32; -} - -inline constexpr EncodingType EncodeStringType(std::size_t size) { - if (size < (1U << 5)) - return ENCODING_TYPE_FIXSTR | (size & ENCODING_TYPE_FIXSTR_MASK); - else if (size < (1U << 8)) - return ENCODING_TYPE_STR8; - else if (size < (1U << 16)) - return ENCODING_TYPE_STR16; - else - return ENCODING_TYPE_STR32; -} - -inline constexpr EncodingType EncodeBinType(std::size_t size) { - if (size < (1U << 8)) - return ENCODING_TYPE_BIN8; - else if (size < (1U << 16)) - return ENCODING_TYPE_BIN16; - else - return ENCODING_TYPE_BIN32; -} - -inline EncodingType EncodeType(const EmptyVariant& /*empty*/) { - return ENCODING_TYPE_NIL; -} - -// Variant is encoded as a single-element map, with the type index as the key. -template -inline EncodingType EncodeType(const Variant& /*variant*/) { - return EncodeMapType(1); -} - -template -inline constexpr EncodingType EncodeType(const StringWrapper& value) { - return EncodeStringType(value.length()); -} - -inline constexpr EncodingType EncodeType(const std::string& value) { - return EncodeStringType(value.length()); -} - -template -inline constexpr EncodingType EncodeType(const std::array& /*value*/) { - return EncodeArrayType(Size); -} - -template -inline constexpr EncodingType EncodeType(const ArrayWrapper& value) { - return EncodeArrayType(value.size()); -} - -template -inline constexpr EncodingType EncodeType( - const std::vector& value) { - return EncodeArrayType(value.size()); -} - -template -inline constexpr EncodingType EncodeType( - const std::map& value) { - return EncodeMapType(value.size()); -} - -template -inline constexpr EncodingType EncodeType( - const std::unordered_map& value) { - return EncodeMapType(value.size()); -} - -template -inline constexpr EncodingType EncodeType(const BufferWrapper& value) { - // BIN size is in bytes. - return EncodeBinType(value.size() * - sizeof(typename BufferWrapper::value_type)); -} - -template -inline constexpr EncodingType EncodeType(const std::pair& /*value*/) { - return EncodeArrayType(2); -} - -template -inline constexpr EncodingType EncodeType(const std::tuple& /*value*/) { - return EncodeArrayType(sizeof...(T)); -} - -// FileHandle is encoded as a FIXEXT2 with a type code for "FileDescriptor" -// and a signed 16-bit index into the pushed fd array. Empty file descriptor -// have an array index of -1. -template -inline constexpr EncodingType EncodeType(const FileHandle& /*fd*/) { - return ENCODING_TYPE_FIXEXT2; -} - -// ChannelHandle is encoded as a FIXEXT4 with a type of -// ENCODING_EXT_TYPE_CHANNEL_HANDLE and a signed 32-bit value representing -// a client channel in a remote process. Empty handle has a value of -1. -template -inline constexpr EncodingType EncodeType( - const ChannelHandle& /*handle*/) { - return ENCODING_TYPE_FIXEXT4; -} - -inline constexpr EncodingType EncodeType(const bool& value) { - return value ? ENCODING_TYPE_TRUE : ENCODING_TYPE_FALSE; -} - -// Type 'char' is a little bit special in that it is distinct from 'signed char' -// and 'unsigned char'. Treating it as an unsigned 8-bit value is safe for -// encoding purposes and nicely handles 7-bit ASCII encodings as FIXINT. -inline constexpr EncodingType EncodeType(const char& value) { - if (value < static_cast(1 << 7)) - return value; - else - return ENCODING_TYPE_UINT8; -} - -inline constexpr EncodingType EncodeType(const uint8_t& value) { - if (value < (1U << 7)) - return value; - else - return ENCODING_TYPE_UINT8; -} -inline constexpr EncodingType EncodeType(const int8_t& value) { - if (value >= -32) - return value; - else - return ENCODING_TYPE_INT8; -} -inline constexpr EncodingType EncodeType(const uint16_t& value) { - if (value < (1U << 7)) - return static_cast(value); - else if (value < (1U << 8)) - return ENCODING_TYPE_UINT8; - else - return ENCODING_TYPE_UINT16; -} -inline constexpr EncodingType EncodeType(const int16_t& value) { - if (value >= -32 && value <= 127) - return static_cast(value); - else if (value >= -128 && value <= 127) - return ENCODING_TYPE_INT8; - else - return ENCODING_TYPE_INT16; -} -inline constexpr EncodingType EncodeType(const uint32_t& value) { - if (value < (1U << 7)) - return static_cast(value); - else if (value < (1U << 8)) - return ENCODING_TYPE_UINT8; - else if (value < (1U << 16)) - return ENCODING_TYPE_UINT16; - else - return ENCODING_TYPE_UINT32; -} -inline constexpr EncodingType EncodeType(const int32_t& value) { - if (value >= -32 && value <= 127) - return static_cast(value); - else if (value >= -128 && value <= 127) - return ENCODING_TYPE_INT8; - else if (value >= -32768 && value <= 32767) - return ENCODING_TYPE_INT16; - else - return ENCODING_TYPE_INT32; -} -inline constexpr EncodingType EncodeType(const uint64_t& value) { - if (value < (1ULL << 7)) - return static_cast(value); - else if (value < (1ULL << 8)) - return ENCODING_TYPE_UINT8; - else if (value < (1ULL << 16)) - return ENCODING_TYPE_UINT16; - else if (value < (1ULL << 32)) - return ENCODING_TYPE_UINT32; - else - return ENCODING_TYPE_UINT64; -} -inline constexpr EncodingType EncodeType(const int64_t& value) { - if (value >= -32 && value <= 127) - return static_cast(value); - else if (value >= -128 && value <= 127) // Effectively [-128, -32). - return ENCODING_TYPE_INT8; - else if (value >= -32768 && value <= 32767) - return ENCODING_TYPE_INT16; - else if (value >= -2147483648 && value <= 2147483647) - return ENCODING_TYPE_INT32; - else - return ENCODING_TYPE_INT64; -} - -inline constexpr EncodingType EncodeType(const float& /*value*/) { - return ENCODING_TYPE_FLOAT32; -} - -inline constexpr EncodingType EncodeType(const double& /*value*/) { - return ENCODING_TYPE_FLOAT64; -} - -} // namespace rpc -} // namespace pdx -} // namespace android - -#endif // ANDROID_PDX_RPC_ENCODING_H_ diff --git a/libs/vr/libpdx/private/pdx/rpc/enumeration.h b/libs/vr/libpdx/private/pdx/rpc/enumeration.h deleted file mode 100644 index 7a35d31b229271e144edb6df26089b055b97d924..0000000000000000000000000000000000000000 --- a/libs/vr/libpdx/private/pdx/rpc/enumeration.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef ANDROID_PDX_RPC_ENUMERATION_H_ -#define ANDROID_PDX_RPC_ENUMERATION_H_ - -#include - -namespace android { -namespace pdx { -namespace rpc { - -// Utility for manipulating lists of types. Provides operations to lookup an -// element by type or index. - -namespace detail { - -// Helper type that captures type and index for each element of a type -// enumeration. -template -struct IndexedElement { - using Type = T; - static constexpr std::size_t Index = I; -}; - -// Helper type that captures an IndexSequence and corresponding list of types. -template -struct ElementIndexer; - -// Partial specialization that generates an instantiation of IndexElement -// for each element of a type enumeration using inheritance. Once a type -// enumeration is instantiated this way the compiler is able to deduce either I -// or T from the other using the method below. -template -struct ElementIndexer, Ts...> : IndexedElement... { -}; - -// Helper function that causes the compiler to deduce an IndexedElement -// given T. -template -static IndexedElement SelectElementByType(IndexedElement); - -// Helper function that causes the compiler to deduce an IndexedElement -// given I. -template -static IndexedElement SelectElementByIndex(IndexedElement); - -} // namespace detail - -// Deduces the IndexedElement given T and a type sequence Ts. This may be -// used to determine the index of T within Ts at compile time. -template -using ElementForType = decltype(detail::SelectElementByType( - detail::ElementIndexer::type, Ts...>{})); - -// Deduces the IndexedElement given I and a type sequence Ts. This may be -// used to determine the type of the element at index I within Ts at compile -// time. Tuple operations may also be used to accomplish the same task, however -// this implementation is provided here for symmetry. -template -using ElementForIndex = decltype(detail::SelectElementByIndex( - detail::ElementIndexer::type, Ts...>{})); - -} // namespace rpc -} // namespace pdx -} // namespace android - -#endif // ANDROID_PDX_RPC_ENUMERATION_H_ diff --git a/libs/vr/libpdx/private/pdx/rpc/find_replace.h b/libs/vr/libpdx/private/pdx/rpc/find_replace.h deleted file mode 100644 index b4b086bd05c85e7a94916f7ed424846f267cc90a..0000000000000000000000000000000000000000 --- a/libs/vr/libpdx/private/pdx/rpc/find_replace.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef ANDROID_PDX_RPC_FIND_REPLACE_H_ -#define ANDROID_PDX_RPC_FIND_REPLACE_H_ - -#include - -#include - -namespace android { -namespace pdx { -namespace rpc { - -// Utility class to capture types to find and replace. -template -struct FindReplace; - -template -using IsSameBaseType = typename std::is_same::type, - typename std::decay::type>; - -// Replaces the type Subject with type Replace if type Subject is the same type -// as type Find, excluding cv-reference qualifiers in the match. -template -using ReplaceType = - typename std::conditional::value, - CopyCVReferenceType, - Subject>::type; - -// Determines whether the type Find (excluding cv-reference qualifiers) is in -// the given parameter pack. -template -struct ContainsType : std::true_type {}; - -template -struct ContainsType - : std::conditional::value, std::true_type, - ContainsType>::type {}; - -template -struct ContainsType : std::false_type {}; - -} // namespace rpc -} // namespace pdx -} // namespace android - -#endif // ANDROID_PDX_RPC_FIND_REPLACE_H_ diff --git a/libs/vr/libpdx/private/pdx/rpc/function_traits.h b/libs/vr/libpdx/private/pdx/rpc/function_traits.h deleted file mode 100644 index 7641b0a7c1d23de339298ac4576a1667b97b2ef1..0000000000000000000000000000000000000000 --- a/libs/vr/libpdx/private/pdx/rpc/function_traits.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef ANDROID_PDX_RPC_FUNCTION_TRAITS_H_ -#define ANDROID_PDX_RPC_FUNCTION_TRAITS_H_ - -#include - -#include - -namespace android { -namespace pdx { -namespace rpc { - -// Utility type to capture return and argument types of a function signature. -// Examples: -// typedef SignatureType SignatureType; -// using SignatureType = SignatureType; -template -using SignatureType = T; - -// Utility class to extract return and argument types from function types. -// Provides nested types for return value, arguments, and full signature. Also -// provides accessor types for individual arguments, argument-arity, and type -// substitution. -template -struct FunctionTraits; - -template -struct FunctionTraits { - using Return = Return_; - using Args = std::tuple; - using Signature = SignatureType; - - enum : std::size_t { Arity = sizeof...(Args_) }; - - template - using Arg = typename std::tuple_element::type; - - template - using RewriteArgs = - SignatureType...)>; - - template - using RewriteSignature = - SignatureType( - ConditionalRewrite...)>; - - template